summaryrefslogtreecommitdiffstats
path: root/writerfilter
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /writerfilter
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'writerfilter')
-rw-r--r--writerfilter/CppunitTest_writerfilter_dmapper.mk57
-rw-r--r--writerfilter/CppunitTest_writerfilter_filters_test.mk61
-rw-r--r--writerfilter/CppunitTest_writerfilter_misc.mk43
-rw-r--r--writerfilter/CppunitTest_writerfilter_rtftok.mk55
-rw-r--r--writerfilter/CustomTarget_source.mk111
-rw-r--r--writerfilter/IwyuFilter_writerfilter.yaml66
-rw-r--r--writerfilter/Library_writerfilter.mk138
-rw-r--r--writerfilter/Makefile7
-rw-r--r--writerfilter/Module_writerfilter.mk24
-rw-r--r--writerfilter/README.md22
-rw-r--r--writerfilter/documentation/KnownIssues.txt27
-rw-r--r--writerfilter/documentation/TODO13
-rw-r--r--writerfilter/documentation/doxygen/Doxyfile1254
-rw-r--r--writerfilter/documentation/doxygen/images/doctok.pngbin0 -> 7291 bytes
-rw-r--r--writerfilter/documentation/doxygen/images/ooxmlimportchain.pngbin0 -> 22605 bytes
-rw-r--r--writerfilter/documentation/ooxml/model.rng436
-rw-r--r--writerfilter/documentation/sprms.txt7
-rw-r--r--writerfilter/documentation/tablesInDoc.txt153
-rw-r--r--writerfilter/inc/dmapper/CommentProperties.hxx29
-rw-r--r--writerfilter/inc/dmapper/DomainMapperFactory.hxx48
-rw-r--r--writerfilter/inc/dmapper/GraphicZOrderHelper.hxx30
-rw-r--r--writerfilter/inc/dmapper/resourcemodel.hxx419
-rw-r--r--writerfilter/inc/ooxml/OOXMLDocument.hxx256
-rw-r--r--writerfilter/inc/ooxml/QNameToString.hxx31
-rw-r--r--writerfilter/inc/pch/precompiled_writerfilter.cxx12
-rw-r--r--writerfilter/inc/pch/precompiled_writerfilter.hxx123
-rw-r--r--writerfilter/inc/rtftok/RTFDocument.hxx46
-rw-r--r--writerfilter/qa/cppunittests/dmapper/CellColorHandler.cxx70
-rw-r--r--writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx134
-rw-r--r--writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx87
-rw-r--r--writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx323
-rw-r--r--writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx411
-rw-r--r--writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx173
-rw-r--r--writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx219
-rw-r--r--writerfilter/qa/cppunittests/dmapper/TextEffectsHandler.cxx74
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/1cell-insidev-rightborder.docxbin0 -> 13204 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docxbin0 -> 22007 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/chart-zorder.docxbin0 -> 21206 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/clearing-break.docxbin0 -> 15739 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/create-date-preserve.docxbin0 -> 13310 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docxbin0 -> 16534 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/field-if-inside-if.docxbin0 -> 12874 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docxbin0 -> 15046 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/follow-page-top-margin.docxbin0 -> 23144 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/frame-direction.docxbin0 -> 28204 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docxbin0 -> 24177 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docxbin0 -> 16684 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docxbin0 -> 17243 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docxbin0 -> 23126 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-2.docxbin0 -> 66189 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docxbin0 -> 12900 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docxbin0 -> 12206 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docxbin0 -> 12124 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/nested-floating-table.docxbin0 -> 12915 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docxbin0 -> 12336 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docxbin0 -> 15416 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf30
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/ptab.docxbin0 -> 15861 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docxbin0 -> 16119 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docxbin0 -> 11858 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-checkbox.docxbin0 -> 4244 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-dropdown.docxbin0 -> 4323 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docxbin0 -> 11987 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docxbin0 -> 13686 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docxbin0 -> 4356 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docxbin0 -> 12738 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docxbin0 -> 12648 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf129205.docxbin0 -> 13237 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf141540ChildRotation.docxbin0 -> 15385 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupLinePosSize.docxbin0 -> 19457 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupRotation.docxbin0 -> 18803 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docxbin0 -> 20932 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docxbin0 -> 23700 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docxbin0 -> 74805 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf143208_wrapTight.docxbin0 -> 20136 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf143455_SmartArtPosition.docxbin0 -> 24753 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/textbox-textline-top.docxbin0 -> 12637 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/textbox-textline.docxbin0 -> 12934 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docxbin0 -> 15018 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/README7
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2005-2971-1.rtfbin0 -> 10867 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2010-3451-1.rtfbin0 -> 4091 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/EDB-18749-1.rtfbin0 -> 3287 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/LIBREOFFICE-N4LA0OHZ.rtf403
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtfbin0 -> 196 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtfbin0 -> 155 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtfbin0 -> 99 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtfbin0 -> 198 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/popstate-2.rtf1
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/propheight-1.rtfbin0 -> 1560 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/sf_edeb1eb341ad4c8608af9396952724a0-128299-minimized.rtf57
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-5.rtfbin0 -> 1941 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtfbin0 -> 2417 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtfbin0 -> 1333 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtfbin0 -> 458 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtfbin0 -> 1300 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-3.rtf28
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/indeterminate/.gitignore0
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2964-1.rtfbin0 -> 10869 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-1.rtfbin0 -> 4055 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-2.rtfbin0 -> 4055 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2007-0245-1.rtfbin0 -> 11167 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3333-1.rtfbin0 -> 11289 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3452-1.rtf1
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-1.rtfbin0 -> 27562 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-2.rtfbin0 -> 27564 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/CVE-pseudo-2009-0238-1.rtfbin0 -> 11289 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18754-1.rtfbin0 -> 93727 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18940-1.rtfbin0 -> 14334 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/TCI-TN65GP-DDRHDLL-partial.rtf1719
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/abi3623.rtf7
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/abi4817.rtf6
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/fdo49666.rtf13
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/fdo64656.rtf10
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/i74153.rtf8
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/i84172.rtf11
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/parser-state-1.rtfbin0 -> 1546 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/rhbz960019.rtf12
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-101375-minimized.rtf62
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-108116-minimized.rtf62
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/sf_edeb1eb341ad4c8608af9396952724a0-41170.rtfbin0 -> 4055 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtfbin0 -> 106 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtfbin0 -> 121 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtfbin0 -> 54 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtfbin0 -> 324 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtfbin0 -> 1408 bytes
-rw-r--r--writerfilter/qa/cppunittests/filters-test/filters-test.cxx79
-rw-r--r--writerfilter/qa/cppunittests/misc/misc.cxx175
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/char-hidden-intbl.rtf6
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/duplicated-image.rtf41
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/follow-style.rtf7
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/invalid-hex.rtf3
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/left-margin-dedup.rtf26
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/negative-page-border.rtf7
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/old-para-num-left-margin.rtf14
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/page.rtf6
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/picture-in-textframe.rtf29
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/picw-pich.rtf6
-rw-r--r--writerfilter/qa/cppunittests/rtftok/data/watermark.rtf47
-rw-r--r--writerfilter/qa/cppunittests/rtftok/rtfdispatchsymbol.cxx72
-rw-r--r--writerfilter/qa/cppunittests/rtftok/rtfdispatchvalue.cxx107
-rw-r--r--writerfilter/qa/cppunittests/rtftok/rtfdocumentimpl.cxx149
-rw-r--r--writerfilter/qa/cppunittests/rtftok/rtfsdrimport.cxx94
-rw-r--r--writerfilter/qa/cppunittests/rtftok/rtfsprm.cxx83
-rw-r--r--writerfilter/qa/cppunittests/rtftok/rtftokenizer.cxx63
-rwxr-xr-xwriterfilter/qa/ooxml/watch-generated-code.sh50
-rw-r--r--writerfilter/source/dmapper/BorderHandler.cxx213
-rw-r--r--writerfilter/source/dmapper/BorderHandler.hxx78
-rw-r--r--writerfilter/source/dmapper/CellColorHandler.cxx331
-rw-r--r--writerfilter/source/dmapper/CellColorHandler.hxx66
-rw-r--r--writerfilter/source/dmapper/CellMarginHandler.cxx177
-rw-r--r--writerfilter/source/dmapper/CellMarginHandler.hxx64
-rw-r--r--writerfilter/source/dmapper/ConversionHelper.cxx691
-rw-r--r--writerfilter/source/dmapper/ConversionHelper.hxx60
-rw-r--r--writerfilter/source/dmapper/DocumentProtection.cxx239
-rw-r--r--writerfilter/source/dmapper/DocumentProtection.hxx88
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx4510
-rw-r--r--writerfilter/source/dmapper/DomainMapper.hxx195
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableHandler.cxx1700
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableHandler.hxx126
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableManager.cxx859
-rw-r--r--writerfilter/source/dmapper/DomainMapperTableManager.hxx172
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx8792
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.hxx1235
-rw-r--r--writerfilter/source/dmapper/FFDataHandler.cxx190
-rw-r--r--writerfilter/source/dmapper/FFDataHandler.hxx99
-rw-r--r--writerfilter/source/dmapper/FieldTypes.hxx305
-rw-r--r--writerfilter/source/dmapper/FontTable.cxx299
-rw-r--r--writerfilter/source/dmapper/FontTable.hxx106
-rw-r--r--writerfilter/source/dmapper/FormControlHelper.cxx378
-rw-r--r--writerfilter/source/dmapper/FormControlHelper.hxx52
-rw-r--r--writerfilter/source/dmapper/GraphicHelpers.cxx348
-rw-r--r--writerfilter/source/dmapper/GraphicHelpers.hxx79
-rw-r--r--writerfilter/source/dmapper/GraphicImport.cxx2029
-rw-r--r--writerfilter/source/dmapper/GraphicImport.hxx140
-rw-r--r--writerfilter/source/dmapper/LatentStyleHandler.cxx71
-rw-r--r--writerfilter/source/dmapper/LatentStyleHandler.hxx35
-rw-r--r--writerfilter/source/dmapper/LoggedResources.cxx400
-rw-r--r--writerfilter/source/dmapper/LoggedResources.hxx144
-rw-r--r--writerfilter/source/dmapper/MeasureHandler.cxx136
-rw-r--r--writerfilter/source/dmapper/MeasureHandler.hxx60
-rw-r--r--writerfilter/source/dmapper/ModelEventListener.cxx117
-rw-r--r--writerfilter/source/dmapper/ModelEventListener.hxx40
-rw-r--r--writerfilter/source/dmapper/NumberingManager.cxx1210
-rw-r--r--writerfilter/source/dmapper/NumberingManager.hxx250
-rw-r--r--writerfilter/source/dmapper/OLEHandler.cxx331
-rw-r--r--writerfilter/source/dmapper/OLEHandler.hxx94
-rw-r--r--writerfilter/source/dmapper/PageBordersHandler.cxx145
-rw-r--r--writerfilter/source/dmapper/PageBordersHandler.hxx62
-rw-r--r--writerfilter/source/dmapper/PropertyIds.cxx386
-rw-r--r--writerfilter/source/dmapper/PropertyIds.hxx377
-rw-r--r--writerfilter/source/dmapper/PropertyMap.cxx2219
-rw-r--r--writerfilter/source/dmapper/PropertyMap.hxx614
-rw-r--r--writerfilter/source/dmapper/PropertyMapHelper.cxx98
-rw-r--r--writerfilter/source/dmapper/PropertyMapHelper.hxx34
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx513
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx208
-rw-r--r--writerfilter/source/dmapper/SectionColumnHandler.cxx90
-rw-r--r--writerfilter/source/dmapper/SectionColumnHandler.hxx62
-rw-r--r--writerfilter/source/dmapper/SettingsTable.cxx692
-rw-r--r--writerfilter/source/dmapper/SettingsTable.hxx111
-rw-r--r--writerfilter/source/dmapper/SmartTagHandler.cxx127
-rw-r--r--writerfilter/source/dmapper/SmartTagHandler.hxx60
-rw-r--r--writerfilter/source/dmapper/StyleSheetTable.cxx1707
-rw-r--r--writerfilter/source/dmapper/StyleSheetTable.hxx150
-rw-r--r--writerfilter/source/dmapper/TDefTableHandler.cxx458
-rw-r--r--writerfilter/source/dmapper/TDefTableHandler.hxx72
-rw-r--r--writerfilter/source/dmapper/TableData.hxx390
-rw-r--r--writerfilter/source/dmapper/TableManager.cxx609
-rw-r--r--writerfilter/source/dmapper/TableManager.hxx530
-rw-r--r--writerfilter/source/dmapper/TablePositionHandler.cxx154
-rw-r--r--writerfilter/source/dmapper/TablePositionHandler.hxx68
-rw-r--r--writerfilter/source/dmapper/TablePropertiesHandler.cxx398
-rw-r--r--writerfilter/source/dmapper/TablePropertiesHandler.hxx94
-rw-r--r--writerfilter/source/dmapper/TagLogger.cxx230
-rw-r--r--writerfilter/source/dmapper/TagLogger.hxx65
-rw-r--r--writerfilter/source/dmapper/TblStylePrHandler.cxx259
-rw-r--r--writerfilter/source/dmapper/TblStylePrHandler.hxx82
-rw-r--r--writerfilter/source/dmapper/TextEffectsHandler.cxx804
-rw-r--r--writerfilter/source/dmapper/TextEffectsHandler.hxx69
-rw-r--r--writerfilter/source/dmapper/ThemeTable.cxx563
-rw-r--r--writerfilter/source/dmapper/ThemeTable.hxx58
-rw-r--r--writerfilter/source/dmapper/TrackChangesHandler.cxx95
-rw-r--r--writerfilter/source/dmapper/TrackChangesHandler.hxx40
-rw-r--r--writerfilter/source/dmapper/WrapPolygonHandler.cxx214
-rw-r--r--writerfilter/source/dmapper/WrapPolygonHandler.hxx82
-rw-r--r--writerfilter/source/dmapper/WriteProtection.cxx140
-rw-r--r--writerfilter/source/dmapper/WriteProtection.hxx58
-rw-r--r--writerfilter/source/dmapper/domainmapperfactory.cxx39
-rw-r--r--writerfilter/source/dmapper/util.cxx70
-rw-r--r--writerfilter/source/dmapper/util.hxx32
-rw-r--r--writerfilter/source/filter/RtfFilter.cxx220
-rw-r--r--writerfilter/source/filter/WriterFilter.cxx368
-rw-r--r--writerfilter/source/ooxml/Handler.cxx435
-rw-r--r--writerfilter/source/ooxml/Handler.hxx179
-rw-r--r--writerfilter/source/ooxml/OOXMLBinaryObjectReference.cxx71
-rw-r--r--writerfilter/source/ooxml/OOXMLBinaryObjectReference.hxx43
-rw-r--r--writerfilter/source/ooxml/OOXMLDocumentImpl.cxx898
-rw-r--r--writerfilter/source/ooxml/OOXMLDocumentImpl.hxx166
-rw-r--r--writerfilter/source/ooxml/OOXMLFactory.cxx179
-rw-r--r--writerfilter/source/ooxml/OOXMLFactory.hxx106
-rw-r--r--writerfilter/source/ooxml/OOXMLFastContextHandler.cxx2307
-rw-r--r--writerfilter/source/ooxml/OOXMLFastContextHandler.hxx632
-rw-r--r--writerfilter/source/ooxml/OOXMLFastDocumentHandler.cxx146
-rw-r--r--writerfilter/source/ooxml/OOXMLFastDocumentHandler.hxx90
-rw-r--r--writerfilter/source/ooxml/OOXMLFastHelper.hxx61
-rw-r--r--writerfilter/source/ooxml/OOXMLParserState.cxx286
-rw-r--r--writerfilter/source/ooxml/OOXMLParserState.hxx121
-rw-r--r--writerfilter/source/ooxml/OOXMLPropertySet.cxx857
-rw-r--r--writerfilter/source/ooxml/OOXMLPropertySet.hxx413
-rw-r--r--writerfilter/source/ooxml/OOXMLStreamImpl.cxx448
-rw-r--r--writerfilter/source/ooxml/OOXMLStreamImpl.hxx83
-rw-r--r--writerfilter/source/ooxml/README13
-rw-r--r--writerfilter/source/ooxml/factory_ns.py76
-rw-r--r--writerfilter/source/ooxml/factoryimpl.py214
-rw-r--r--writerfilter/source/ooxml/factoryimpl_ns.py767
-rw-r--r--writerfilter/source/ooxml/factoryinc.py49
-rw-r--r--writerfilter/source/ooxml/model.xml19297
-rw-r--r--writerfilter/source/ooxml/modelpreprocess.py90
-rw-r--r--writerfilter/source/ooxml/qnametostr.py64
-rw-r--r--writerfilter/source/ooxml/resourceids.py60
-rw-r--r--writerfilter/source/ooxml/tox.ini2
-rw-r--r--writerfilter/source/rtftok/README12
-rw-r--r--writerfilter/source/rtftok/rtfcharsets.cxx64
-rw-r--r--writerfilter/source/rtftok/rtfcharsets.hxx37
-rw-r--r--writerfilter/source/rtftok/rtfcontrolwords.cxx1900
-rw-r--r--writerfilter/source/rtftok/rtfcontrolwords.hxx2049
-rw-r--r--writerfilter/source/rtftok/rtfdispatchdestination.cxx684
-rw-r--r--writerfilter/source/rtftok/rtfdispatchflag.cxx1258
-rw-r--r--writerfilter/source/rtftok/rtfdispatchsymbol.cxx442
-rw-r--r--writerfilter/source/rtftok/rtfdispatchvalue.cxx1832
-rw-r--r--writerfilter/source/rtftok/rtfdocumentfactory.cxx28
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.cxx3992
-rw-r--r--writerfilter/source/rtftok/rtfdocumentimpl.hxx994
-rw-r--r--writerfilter/source/rtftok/rtffly.hxx138
-rw-r--r--writerfilter/source/rtftok/rtflistener.hxx69
-rw-r--r--writerfilter/source/rtftok/rtflookahead.cxx101
-rw-r--r--writerfilter/source/rtftok/rtflookahead.hxx57
-rw-r--r--writerfilter/source/rtftok/rtfreferenceproperties.cxx40
-rw-r--r--writerfilter/source/rtftok/rtfreferenceproperties.hxx33
-rw-r--r--writerfilter/source/rtftok/rtfreferencetable.cxx29
-rw-r--r--writerfilter/source/rtftok/rtfreferencetable.hxx32
-rw-r--r--writerfilter/source/rtftok/rtfsdrimport.cxx1182
-rw-r--r--writerfilter/source/rtftok/rtfsdrimport.hxx103
-rw-r--r--writerfilter/source/rtftok/rtfskipdestination.cxx42
-rw-r--r--writerfilter/source/rtftok/rtfskipdestination.hxx33
-rw-r--r--writerfilter/source/rtftok/rtfsprm.cxx476
-rw-r--r--writerfilter/source/rtftok/rtfsprm.hxx101
-rw-r--r--writerfilter/source/rtftok/rtftokenizer.cxx329
-rw-r--r--writerfilter/source/rtftok/rtftokenizer.hxx72
-rw-r--r--writerfilter/source/rtftok/rtfvalue.cxx222
-rw-r--r--writerfilter/source/rtftok/rtfvalue.hxx85
-rw-r--r--writerfilter/util/writerfilter.component32
293 files changed, 93506 insertions, 0 deletions
diff --git a/writerfilter/CppunitTest_writerfilter_dmapper.mk b/writerfilter/CppunitTest_writerfilter_dmapper.mk
new file mode 100644
index 000000000..de1a8cea9
--- /dev/null
+++ b/writerfilter/CppunitTest_writerfilter_dmapper.mk
@@ -0,0 +1,57 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# 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/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,writerfilter_dmapper))
+
+$(eval $(call gb_CppunitTest_use_externals,writerfilter_dmapper,\
+ boost_headers \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,writerfilter_dmapper, \
+ writerfilter/qa/cppunittests/dmapper/CellColorHandler \
+ writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler \
+ writerfilter/qa/cppunittests/dmapper/DomainMapper \
+ writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl \
+ writerfilter/qa/cppunittests/dmapper/GraphicImport \
+ writerfilter/qa/cppunittests/dmapper/TextEffectsHandler \
+ writerfilter/qa/cppunittests/dmapper/PropertyMap \
+ writerfilter/qa/cppunittests/dmapper/SdtHelper \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,writerfilter_dmapper, \
+ basegfx \
+ comphelper \
+ cppu \
+ oox \
+ sal \
+ test \
+ unotest \
+ vcl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,writerfilter_dmapper))
+
+$(eval $(call gb_CppunitTest_use_ure,writerfilter_dmapper))
+$(eval $(call gb_CppunitTest_use_vcl,writerfilter_dmapper))
+
+$(eval $(call gb_CppunitTest_use_rdb,writerfilter_dmapper,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,writerfilter_dmapper,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,writerfilter_dmapper))
+
+# we need to explicitly depend on library writerfilter because it is not implied
+# by a link relation
+$(call gb_CppunitTest_get_target,writerfilter_dmapper) : $(call gb_Library_get_target,writerfilter)
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/CppunitTest_writerfilter_filters_test.mk b/writerfilter/CppunitTest_writerfilter_filters_test.mk
new file mode 100644
index 000000000..a08c66675
--- /dev/null
+++ b/writerfilter/CppunitTest_writerfilter_filters_test.mk
@@ -0,0 +1,61 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# 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/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,writerfilter_filters_test))
+
+$(eval $(call gb_CppunitTest_use_external,writerfilter_filters_test,boost_headers))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,writerfilter_filters_test, \
+ writerfilter/qa/cppunittests/filters-test/filters-test \
+))
+
+ifeq ($(DISABLE_CVE_TESTS),TRUE)
+$(eval $(call gb_CppunitTest_add_defs,writerfilter_filters_test,\
+ -DDISABLE_CVE_TESTS \
+))
+endif
+
+$(eval $(call gb_CppunitTest_use_libraries,writerfilter_filters_test, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ sal \
+ test \
+ unotest \
+ vcl \
+ writerfilter \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,writerfilter_filters_test))
+
+$(eval $(call gb_CppunitTest_use_ure,writerfilter_filters_test))
+$(eval $(call gb_CppunitTest_use_vcl,writerfilter_filters_test))
+
+$(eval $(call gb_CppunitTest_use_components,writerfilter_filters_test,\
+ configmgr/source/configmgr \
+ framework/util/fwk \
+ i18npool/util/i18npool \
+ svtools/util/svt \
+ ucb/source/core/ucb1 \
+ ucb/source/ucp/file/ucpfile1 \
+ writerfilter/util/writerfilter \
+ vcl/vcl.common \
+))
+
+
+
+$(eval $(call gb_CppunitTest_use_configuration,writerfilter_filters_test))
+
+# we need to explicitly depend on library writerfilter because it is not implied
+# by a link relation
+$(call gb_CppunitTest_get_target,writerfilter_filters_test) : $(call gb_Library_get_target,writerfilter)
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/CppunitTest_writerfilter_misc.mk b/writerfilter/CppunitTest_writerfilter_misc.mk
new file mode 100644
index 000000000..1b45ec716
--- /dev/null
+++ b/writerfilter/CppunitTest_writerfilter_misc.mk
@@ -0,0 +1,43 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,writerfilter_misc))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,writerfilter_misc))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,writerfilter_misc,\
+ writerfilter/source \
+))
+
+$(eval $(call gb_CppunitTest_set_include,writerfilter_misc,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/writerfilter/inc \
+ -I$(SRCDIR)/writerfilter/source \
+ -I$(SRCDIR)/writerfilter/source/dmapper \
+))
+
+$(eval $(call gb_CppunitTest_use_external,writerfilter_misc,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_libraries,writerfilter_misc, \
+ writerfilter \
+ cppu \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,writerfilter_misc,\
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,writerfilter_misc, \
+ writerfilter/qa/cppunittests/misc/misc \
+))
+
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/CppunitTest_writerfilter_rtftok.mk b/writerfilter/CppunitTest_writerfilter_rtftok.mk
new file mode 100644
index 000000000..614f032c3
--- /dev/null
+++ b/writerfilter/CppunitTest_writerfilter_rtftok.mk
@@ -0,0 +1,55 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# 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/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,writerfilter_rtftok))
+
+$(eval $(call gb_CppunitTest_use_externals,writerfilter_rtftok,\
+ boost_headers \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,writerfilter_rtftok, \
+ writerfilter/qa/cppunittests/rtftok/rtfdispatchsymbol \
+ writerfilter/qa/cppunittests/rtftok/rtfdispatchvalue \
+ writerfilter/qa/cppunittests/rtftok/rtfdocumentimpl \
+ writerfilter/qa/cppunittests/rtftok/rtfsdrimport \
+ writerfilter/qa/cppunittests/rtftok/rtfsprm \
+ writerfilter/qa/cppunittests/rtftok/rtftokenizer \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,writerfilter_rtftok, \
+ basegfx \
+ comphelper \
+ cppu \
+ oox \
+ sal \
+ test \
+ unotest \
+ vcl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,writerfilter_rtftok))
+
+$(eval $(call gb_CppunitTest_use_ure,writerfilter_rtftok))
+$(eval $(call gb_CppunitTest_use_vcl,writerfilter_rtftok))
+
+$(eval $(call gb_CppunitTest_use_rdb,writerfilter_rtftok,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,writerfilter_rtftok,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,writerfilter_rtftok))
+
+# we need to explicitly depend on library writerfilter because it is not implied
+# by a link relation
+$(call gb_CppunitTest_get_target,writerfilter_rtftok) : $(call gb_Library_get_target,writerfilter)
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/CustomTarget_source.mk b/writerfilter/CustomTarget_source.mk
new file mode 100644
index 000000000..d0085654a
--- /dev/null
+++ b/writerfilter/CustomTarget_source.mk
@@ -0,0 +1,111 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,writerfilter/source))
+
+writerfilter_WORK := $(call gb_CustomTarget_get_workdir,writerfilter/source)
+writerfilter_SRC := $(SRCDIR)/writerfilter/source
+
+writerfilter_PYTHONCOMMAND := $(call gb_ExternalExecutable_get_command,python)
+writerfilter_XMLLINTCOMMAND := $(call gb_ExternalExecutable_get_command,xmllint)
+
+writerfilter_OOXMLNAMESPACES= \
+ dml-baseStylesheet \
+ dml-baseTypes \
+ dml-chartDrawing \
+ dml-documentProperties \
+ dml-graphicalObject \
+ dml-shape3DCamera \
+ dml-shape3DLighting \
+ dml-shape3DScene \
+ dml-shape3DStyles \
+ dml-shapeEffects \
+ dml-shapeGeometry \
+ dml-shapeLineProperties \
+ dml-shapeProperties \
+ dml-styleDefaults \
+ dml-stylesheet \
+ dml-textCharacter \
+ dml-wordprocessingDrawing \
+ shared-math \
+ shared-relationshipReference \
+ sml-customXmlMappings \
+ vml-main \
+ vml-officeDrawing \
+ vml-wordprocessingDrawing \
+ wp14 \
+ w14 \
+ w15 \
+ a14 \
+ wml
+
+writerfilter_ALL = \
+ $(writerfilter_GEN_ooxml_Factory_cxx) \
+ $(writerfilter_GEN_ooxml_Factory_hxx) \
+ $(writerfilter_GEN_ooxml_FactoryValues_hxx) \
+ $(writerfilter_GEN_ooxml_QNameToStr_cxx) \
+ $(writerfilter_GEN_ooxml_ResourceIds_hxx) \
+ $(writerfilter_GEN_ooxml_Model_validated) \
+ $(writerfilter_GEN_ooxml_Model_processed) \
+ $(patsubst %,$(writerfilter_WORK)/ooxml/OOXMLFactory_%.hxx,$(writerfilter_OOXMLNAMESPACES)) \
+ $(patsubst %,$(writerfilter_WORK)/ooxml/OOXMLFactory_%.cxx,$(writerfilter_OOXMLNAMESPACES)) \
+
+writerfilter_DEP_ooxml_Namespaces_txt=$(call gb_CustomTarget_get_workdir,oox/generated)/misc/namespaces.txt
+writerfilter_GEN_ooxml_FactoryValues_hxx=$(writerfilter_WORK)/ooxml/OOXMLFactory_values.hxx
+writerfilter_GEN_ooxml_Factory_cxx=$(writerfilter_WORK)/ooxml/OOXMLFactory_generated.cxx
+writerfilter_GEN_ooxml_Factory_hxx=$(writerfilter_WORK)/ooxml/OOXMLFactory_generated.hxx
+writerfilter_GEN_ooxml_Model_validated=$(writerfilter_WORK)/ooxml/model.validated
+writerfilter_GEN_ooxml_Model_processed=$(writerfilter_WORK)/ooxml/model_preprocessed.xml
+writerfilter_GEN_ooxml_QNameToStr_cxx=$(writerfilter_WORK)/ooxml/qnametostr.cxx
+writerfilter_GEN_ooxml_ResourceIds_hxx=$(writerfilter_WORK)/ooxml/resourceids.hxx
+writerfilter_SRC_ooxml_Model=$(writerfilter_SRC)/ooxml/model.xml
+writerfilter_SRC_ooxml_Preprocess_py=$(writerfilter_SRC)/ooxml/modelpreprocess.py
+writerfilter_SRC_ooxml_QNameToStr_py=$(writerfilter_SRC)/ooxml/qnametostr.py
+writerfilter_SRC_ooxml_ResourceIds_py=$(writerfilter_SRC)/ooxml/resourceids.py
+
+$(writerfilter_GEN_ooxml_Factory_cxx) : $(writerfilter_SRC)/ooxml/factoryimpl.py $(writerfilter_DEP_ooxml_Namespaces_txt) $(writerfilter_GEN_ooxml_Model_processed)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $< $(writerfilter_DEP_ooxml_Namespaces_txt) $(writerfilter_GEN_ooxml_Model_processed)) > $@
+
+$(writerfilter_GEN_ooxml_Factory_hxx) : $(writerfilter_SRC)/ooxml/factoryinc.py $(writerfilter_GEN_ooxml_Model_processed)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $< $(writerfilter_GEN_ooxml_Model_processed)) > $@
+
+$(writerfilter_GEN_ooxml_Model_validated) : $(writerfilter_SRC)/../documentation/ooxml/model.rng $(writerfilter_SRC_ooxml_Model)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,VAL,1)
+ $(call gb_Helper_abbreviate_dirs,\
+ $(writerfilter_XMLLINTCOMMAND) --noout --relaxng $(writerfilter_SRC)/../documentation/ooxml/model.rng $(writerfilter_SRC_ooxml_Model) > $@ 2>&1 \
+ || (cat $@; false))
+
+$(writerfilter_GEN_ooxml_Model_processed) : $(writerfilter_SRC_ooxml_Preprocess_py) $(writerfilter_DEP_ooxml_Namespaces_txt) $(writerfilter_GEN_ooxml_Model_validated)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $(writerfilter_SRC_ooxml_Preprocess_py) $(writerfilter_DEP_ooxml_Namespaces_txt) $(writerfilter_SRC_ooxml_Model)) > $@
+
+$(writerfilter_GEN_ooxml_QNameToStr_cxx): $(writerfilter_SRC_ooxml_QNameToStr_py) $(writerfilter_GEN_ooxml_Model_processed)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $(writerfilter_SRC_ooxml_QNameToStr_py) $(writerfilter_GEN_ooxml_Model_processed)) > $@
+
+$(writerfilter_GEN_ooxml_ResourceIds_hxx) : $(writerfilter_SRC_ooxml_ResourceIds_py) $(writerfilter_GEN_ooxml_Model_processed) | $(writerfilter_WORK)/ooxml/.dir
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $(writerfilter_SRC_ooxml_ResourceIds_py) $(writerfilter_GEN_ooxml_Model_processed)) > $@
+
+$(writerfilter_WORK)/ooxml/OOXMLFactory%.cxx : $(writerfilter_SRC)/ooxml/factoryimpl_ns.py $(writerfilter_GEN_ooxml_Model_processed)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $< $(writerfilter_GEN_ooxml_Model_processed) $@) > $@
+
+$(writerfilter_WORK)/ooxml/OOXMLFactory%.hxx : $(writerfilter_SRC)/ooxml/factory_ns.py $(writerfilter_GEN_ooxml_Model_processed)
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),build,PY ,1)
+ $(call gb_Helper_abbreviate_dirs, $(writerfilter_PYTHONCOMMAND) $< $(writerfilter_GEN_ooxml_Model_processed) $@) > $@
+
+
+$(call gb_CustomTarget_get_target,writerfilter/source) : $(writerfilter_ALL)
+
+$(writerfilter_ALL) :| $(call gb_ExternalExecutable_get_dependencies,python) $(call gb_ExternalExecutable_get_dependencies,xmllint) $(writerfilter_WORK)/ooxml/.dir
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/IwyuFilter_writerfilter.yaml b/writerfilter/IwyuFilter_writerfilter.yaml
new file mode 100644
index 000000000..50a4c8893
--- /dev/null
+++ b/writerfilter/IwyuFilter_writerfilter.yaml
@@ -0,0 +1,66 @@
+---
+assumeFilename: writerfilter/source/filter/WriterFilter.cxx
+excludelist:
+ writerfilter/source/dmapper/BorderHandler.cxx:
+ # Needed for method parameter type
+ - tools/color.hxx
+ writerfilter/source/dmapper/ConversionHelper.cxx:
+ # Actually used
+ - com/sun/star/table/BorderLine2.hpp
+ - com/sun/star/lang/Locale.hpp
+ writerfilter/source/dmapper/DomainMapperTableManager.cxx:
+ # Needed for rtl::math::round
+ - rtl/math.hxx
+ writerfilter/source/dmapper/GraphicImport.cxx:
+ # Actually used
+ - com/sun/star/drawing/XShape.hpp
+ - com/sun/star/graphic/XGraphic.hpp
+ - com/sun/star/lang/XMultiServiceFactory.hpp
+ - com/sun/star/uno/XComponentContext.hpp
+ # Needed for rtl::math::round
+ - rtl/math.hxx
+ writerfilter/source/dmapper/NumberingManager.cxx:
+ # Actually used
+ - com/sun/star/lang/XMultiServiceFactory.hpp
+ - com/sun/star/container/XNameContainer.hpp
+ writerfilter/source/dmapper/DomainMapper_Impl.cxx:
+ # Actually used
+ - com/sun/star/uno/XComponentContext.hpp
+ writerfilter/source/dmapper/OLEHandler.cxx:
+ # Actually used
+ - com/sun/star/drawing/XShape.hpp
+ - com/sun/star/graphic/XGraphic.hpp
+ - com/sun/star/text/XTextDocument.hpp
+ - com/sun/star/text/WrapTextMode.hpp
+ - com/sun/star/uno/XComponentContext.hpp
+ writerfilter/source/dmapper/TDefTableHandler.cxx:
+ # Needed for method parameter type
+ - tools/color.hxx
+ writerfilter/source/dmapper/TablePositionHandler.cxx:
+ # Actually used
+ - com/sun/star/beans/PropertyValue.hpp
+ writerfilter/source/dmapper/PropertyMap.cxx:
+ # Actually used
+ - com/sun/star/beans/PropertyValue.hpp
+ - com/sun/star/text/XTextColumns.hpp
+ writerfilter/source/dmapper/StyleSheetTable.cxx:
+ # Actually used
+ - com/sun/star/text/XTextDocument.hpp
+ writerfilter/source/ooxml/OOXMLPropertySet.cxx:
+ # Actually used
+ - com/sun/star/drawing/XShape.hpp
+ writerfilter/source/rtftok/rtfsdrimport.hxx:
+ # IWYU assumes std::stack<IncompleteType> in a header is OK, but that's not
+ # the case for all of LO's supported platforms.
+ # See <https://github.com/include-what-you-use/include-what-you-use/issues/175>.
+ - dmapper/GraphicZOrderHelper.hxx
+ writerfilter/source/rtftok/rtfvalue.cxx:
+ # complete type is needed
+ - com/sun/star/embed/XEmbeddedObject.hpp
+ writerfilter/source/rtftok/rtftokenizer.cxx:
+ # Actually used
+ - com/sun/star/task/XStatusIndicator.hpp
+ writerfilter/source/filter/RtfFilter.cxx:
+ - comphelper/scopeguard.hxx
+ writerfilter/source/filter/WriterFilter.cxx:
+ - comphelper/scopeguard.hxx
diff --git a/writerfilter/Library_writerfilter.mk b/writerfilter/Library_writerfilter.mk
new file mode 100644
index 000000000..4648ca942
--- /dev/null
+++ b/writerfilter/Library_writerfilter.mk
@@ -0,0 +1,138 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Library_Library,writerfilter))
+
+$(eval $(call gb_Library_use_custom_headers,writerfilter,\
+ officecfg/registry \
+ oox/generated \
+ writerfilter/source \
+))
+
+$(eval $(call gb_Library_set_precompiled_header,writerfilter,writerfilter/inc/pch/precompiled_writerfilter))
+
+$(eval $(call gb_Library_set_include,writerfilter,\
+ $$(INCLUDE) \
+ -I$(SRCDIR)/writerfilter/inc \
+ -I$(SRCDIR)/writerfilter/source \
+))
+
+$(eval $(call gb_Library_use_sdk_api,writerfilter))
+
+$(eval $(call gb_Library_set_componentfile,writerfilter,writerfilter/util/writerfilter,services))
+
+$(eval $(call gb_Library_use_libraries,writerfilter,\
+ basegfx \
+ comphelper \
+ cppu \
+ cppuhelper \
+ editeng \
+ i18nlangtag \
+ i18nutil \
+ msfilter \
+ oox \
+ sal \
+ salhelper \
+ sax \
+ sfx \
+ sot \
+ svt \
+ svxcore \
+ tl \
+ utl \
+ vcl \
+))
+
+$(eval $(call gb_Library_use_externals,writerfilter,\
+ boost_headers \
+ icui18n \
+ icuuc \
+ icu_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_Library_add_exception_objects,writerfilter,\
+ writerfilter/source/rtftok/rtfcharsets \
+ writerfilter/source/rtftok/rtfcontrolwords \
+ writerfilter/source/rtftok/rtfdispatchdestination \
+ writerfilter/source/rtftok/rtfdispatchflag \
+ writerfilter/source/rtftok/rtfdispatchsymbol \
+ writerfilter/source/rtftok/rtfdispatchvalue \
+ writerfilter/source/rtftok/rtfdocumentfactory \
+ writerfilter/source/rtftok/rtfdocumentimpl \
+ writerfilter/source/rtftok/rtflookahead \
+ writerfilter/source/rtftok/rtfreferenceproperties \
+ writerfilter/source/rtftok/rtfreferencetable \
+ writerfilter/source/rtftok/rtfsdrimport \
+ writerfilter/source/rtftok/rtfskipdestination \
+ writerfilter/source/rtftok/rtfsprm \
+ writerfilter/source/rtftok/rtftokenizer \
+ writerfilter/source/rtftok/rtfvalue \
+ writerfilter/source/dmapper/BorderHandler \
+ writerfilter/source/dmapper/CellColorHandler \
+ writerfilter/source/dmapper/CellMarginHandler \
+ writerfilter/source/dmapper/ConversionHelper \
+ writerfilter/source/dmapper/DocumentProtection \
+ writerfilter/source/dmapper/DomainMapper \
+ writerfilter/source/dmapper/DomainMapperTableHandler \
+ writerfilter/source/dmapper/DomainMapperTableManager \
+ writerfilter/source/dmapper/DomainMapper_Impl \
+ writerfilter/source/dmapper/domainmapperfactory \
+ writerfilter/source/dmapper/FFDataHandler \
+ writerfilter/source/dmapper/FontTable \
+ writerfilter/source/dmapper/FormControlHelper \
+ writerfilter/source/dmapper/GraphicHelpers \
+ writerfilter/source/dmapper/GraphicImport \
+ writerfilter/source/dmapper/LatentStyleHandler \
+ writerfilter/source/dmapper/LoggedResources \
+ writerfilter/source/dmapper/MeasureHandler \
+ writerfilter/source/dmapper/TrackChangesHandler \
+ writerfilter/source/dmapper/ModelEventListener \
+ writerfilter/source/dmapper/NumberingManager \
+ writerfilter/source/dmapper/OLEHandler \
+ writerfilter/source/dmapper/PageBordersHandler \
+ writerfilter/source/dmapper/PropertyIds \
+ writerfilter/source/dmapper/PropertyMap \
+ writerfilter/source/dmapper/PropertyMapHelper \
+ writerfilter/source/dmapper/SdtHelper \
+ writerfilter/source/dmapper/SectionColumnHandler \
+ writerfilter/source/dmapper/SettingsTable \
+ writerfilter/source/dmapper/SmartTagHandler \
+ writerfilter/source/dmapper/StyleSheetTable \
+ writerfilter/source/dmapper/TDefTableHandler \
+ writerfilter/source/dmapper/TableManager \
+ writerfilter/source/dmapper/TablePositionHandler \
+ writerfilter/source/dmapper/TablePropertiesHandler \
+ writerfilter/source/dmapper/TagLogger \
+ writerfilter/source/dmapper/TextEffectsHandler \
+ writerfilter/source/dmapper/TblStylePrHandler \
+ writerfilter/source/dmapper/ThemeTable \
+ writerfilter/source/dmapper/WrapPolygonHandler \
+ writerfilter/source/dmapper/WriteProtection \
+ writerfilter/source/dmapper/util \
+ writerfilter/source/filter/RtfFilter \
+ writerfilter/source/filter/WriterFilter \
+ writerfilter/source/ooxml/Handler \
+ writerfilter/source/ooxml/OOXMLBinaryObjectReference \
+ writerfilter/source/ooxml/OOXMLDocumentImpl \
+ writerfilter/source/ooxml/OOXMLFactory \
+ writerfilter/source/ooxml/OOXMLFastContextHandler \
+ writerfilter/source/ooxml/OOXMLFastDocumentHandler \
+ writerfilter/source/ooxml/OOXMLParserState \
+ writerfilter/source/ooxml/OOXMLPropertySet \
+ writerfilter/source/ooxml/OOXMLStreamImpl \
+))
+
+$(eval $(call gb_Library_add_generated_exception_objects,writerfilter,\
+ $(patsubst %,CustomTarget/writerfilter/source/ooxml/OOXMLFactory_%,$(writerfilter_OOXMLNAMESPACES)) \
+ CustomTarget/writerfilter/source/ooxml/OOXMLFactory_generated \
+ CustomTarget/writerfilter/source/ooxml/qnametostr \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/Makefile b/writerfilter/Makefile
new file mode 100644
index 000000000..ccb1c85a0
--- /dev/null
+++ b/writerfilter/Makefile
@@ -0,0 +1,7 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/Module_writerfilter.mk b/writerfilter/Module_writerfilter.mk
new file mode 100644
index 000000000..46d7af0ff
--- /dev/null
+++ b/writerfilter/Module_writerfilter.mk
@@ -0,0 +1,24 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Module_Module,writerfilter))
+
+$(eval $(call gb_Module_add_targets,writerfilter,\
+ CustomTarget_source \
+ Library_writerfilter \
+))
+
+$(eval $(call gb_Module_add_slowcheck_targets,writerfilter,\
+ CppunitTest_writerfilter_filters_test \
+ CppunitTest_writerfilter_misc \
+ CppunitTest_writerfilter_dmapper \
+ CppunitTest_writerfilter_rtftok \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/writerfilter/README.md b/writerfilter/README.md
new file mode 100644
index 000000000..0c027bf42
--- /dev/null
+++ b/writerfilter/README.md
@@ -0,0 +1,22 @@
+# Import Filters for LibreOffice Writer
+
+The writerfilter module contains import filters for Writer, using its UNO API.
+
+Import filter for DOCX and RTF.
+
+* Module contents
+ * `documentation`: RNG schema for the OOXML tokenizer, etc.
+ * `inc`: module-global headers (can be included by any files under source)
+ * `qa`: `cppunit` tests
+ * `source`: the filters themselves
+ * `util`: UNO passive registration config
+
+* Source contents
+ * `dmapper`: the domain mapper, hiding UNO from the tokenizers, used by DOCX and RTF import
+ * The incoming traffic of `dmapper` can be dumped into an XML file in `/tmp` in
+ `dbgutil` builds, start soffice with the `SW_DEBUG_WRITERFILTER=1`
+ environment variable if you want that.
+ * `filter`: the UNO filter service implementations, invoked by UNO and calling
+ the dmapper + one of the tokenizers
+ * `ooxml`: the docx tokenizer
+ * `rtftok`: the rtf tokenizer
diff --git a/writerfilter/documentation/KnownIssues.txt b/writerfilter/documentation/KnownIssues.txt
new file mode 100644
index 000000000..6c84daf0f
--- /dev/null
+++ b/writerfilter/documentation/KnownIssues.txt
@@ -0,0 +1,27 @@
+#
+# 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/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+- footnotes/endnotes: font index cannot be applied to Writer's footnote symbol
+in the footnote area
+- border types: width of border lines are changed to fit Writer's defaults,
+triple borders unsupported
+- there are no unlocked (writeable) sections within a read only document in
+Writer
+- multiple fields are either unsupported or drastically converted (see
+DomainMapper_Impl.cxx)
+- borders cannot be applied to whole document (from sections)
diff --git a/writerfilter/documentation/TODO b/writerfilter/documentation/TODO
new file mode 100644
index 000000000..2f85ab6a2
--- /dev/null
+++ b/writerfilter/documentation/TODO
@@ -0,0 +1,13 @@
+Import
+
+- Change Tracking
+- Tables
+ - attributes
+ - merged cells
+- Shapes
+ - Shapes generated by Word
+ - Shapes generated by PowerPoint and imported via clipboard
+- Pictures
+- OLE objects
+- Sections
+- Fields
diff --git a/writerfilter/documentation/doxygen/Doxyfile b/writerfilter/documentation/doxygen/Doxyfile
new file mode 100644
index 000000000..15414b828
--- /dev/null
+++ b/writerfilter/documentation/doxygen/Doxyfile
@@ -0,0 +1,1254 @@
+# Doxyfile 1.4.6
+#
+# 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/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = writerfilter
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = $(WORKSTAMP)
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../../inc ../../source
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS = *.cxx *.hxx *.java
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = CVS
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = images
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = $(SOLARINC)
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate an inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 512
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 4
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/writerfilter/documentation/doxygen/images/doctok.png b/writerfilter/documentation/doxygen/images/doctok.png
new file mode 100644
index 000000000..15adb9670
--- /dev/null
+++ b/writerfilter/documentation/doxygen/images/doctok.png
Binary files differ
diff --git a/writerfilter/documentation/doxygen/images/ooxmlimportchain.png b/writerfilter/documentation/doxygen/images/ooxmlimportchain.png
new file mode 100644
index 000000000..509f1cab5
--- /dev/null
+++ b/writerfilter/documentation/doxygen/images/ooxmlimportchain.png
Binary files differ
diff --git a/writerfilter/documentation/ooxml/model.rng b/writerfilter/documentation/ooxml/model.rng
new file mode 100644
index 000000000..a7d298991
--- /dev/null
+++ b/writerfilter/documentation/ooxml/model.rng
@@ -0,0 +1,436 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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/.
+ *
+-->
+<!--
+This file is both a relax-ng schema for writerfilter/source/ooxml/model.xml and
+documentation for that file. The schema has two parts:
+
+- first part: a subset of the relax-ng grammar to define *what* we expect as
+ the input in a DOCX file
+- second part: additional annotation on top of that to define *how* to handle
+ that expected input
+-->
+<grammar xmlns="http://relaxng.org/ns/structure/1.0">
+ <!--
+ First part: a subset of the relax-ng XML markup.
+
+ The order of elements in this part follow a bottom-up approach.
+ -->
+
+ <!-- Basic building blocks: element, attribute and their contents. -->
+
+ <!--
+ Describes an XML element.
+
+ Example:
+
+ <element name="charset">
+ <ref name="CT_Charset"/>
+ </element>
+ -->
+ <define name="element-element">
+ <element name="element" ns="http://relaxng.org/ns/structure/1.0">
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <oneOrMore>
+ <choice>
+ <ref name="attribute-element"/>
+ <ref name="data-element"/>
+ <ref name="ref-element"/>
+ </choice>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ Describes an attribute.
+
+ Example:
+
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ -->
+ <define name="attribute-element">
+ <element name="attribute" ns="http://relaxng.org/ns/structure/1.0">
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <zeroOrMore>
+ <choice>
+ <ref name="data-element"/>
+ <ref name="ref-element"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ Describes the type of the data contained in an attribute. Possible values:
+ boolean, integer or string. See also <text>.
+ -->
+ <define name="data-element">
+ <element name="data" ns="http://relaxng.org/ns/structure/1.0">
+ <attribute name="type"/>
+ </element>
+ </define>
+
+ <!--
+ Describes an enumeration element: a possible value for an attribute.
+ -->
+ <define name="value-element">
+ <element name="value" ns="http://relaxng.org/ns/structure/1.0">
+ <text/>
+ </element>
+ </define>
+
+ <!--
+ This element is ignored during parsing, it just helps readability.
+
+ Example:
+
+ <choice>
+ <value>true</value>
+ <value>false</value>
+ </choice>
+ -->
+ <define name="choice-element">
+ <element name="choice" ns="http://relaxng.org/ns/structure/1.0">
+ <oneOrMore>
+ <choice>
+ <ref name="data-element"/>
+ <ref name="element-element"/>
+ <ref name="ref-element"/>
+ <ref name="value-element"/>
+ </choice>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!-- Grouping elements: define and grammar. -->
+
+ <!--
+ A define is named definition of its contents, so that multiple <ref> elements
+ can refer to it, to avoid copy&paste. OOXML named (complex and simple) types
+ are described using defines.
+ -->
+ <define name="define-element">
+ <element name="define" ns="http://relaxng.org/ns/structure/1.0">
+ <attribute name="name"/>
+ <oneOrMore>
+ <choice>
+ <ref name="choice-element"/>
+ <ref name="attribute-element"/>
+ <ref name="element-element"/>
+ <ref name="data-element"/>
+ <ref name="ref-element"/>
+ <empty/>
+ </choice>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ A reference to a define.
+ -->
+ <define name="ref-element">
+ <element name="ref" ns="http://relaxng.org/ns/structure/1.0">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+ <!--
+ A grammar is a set of defines, one grammar is equivalent to one .xsd file
+ from the OOXML spec.
+ -->
+ <define name="grammar-element">
+ <element name="grammar" ns="http://relaxng.org/ns/structure/1.0">
+ <attribute name="ns"/>
+ <optional>
+ <attribute name="attributeFormDefault"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="include-element"/>
+ </zeroOrMore>
+ <oneOrMore>
+ <ref name="define-element"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ Controls the resolution of <ref> elements. The order is:
+
+ - the current grammar
+ - included grammars, if there are any
+ - the first define in the whole model
+ -->
+ <define name="include-element">
+ <element name="include" ns="http://relaxng.org/ns/structure/1.0">
+ <attribute name="href"/>
+ </element>
+ </define>
+
+ <!--
+ Second part: custom markup, building on top of the first one.
+
+ The order of elements in this part follow a top-down approach.
+
+ The output of the code generated from these elements is a token stream. There
+ are two types of tokens: SPRM tokens and attribute ones. SPRM refers to
+ Single PRoperty Modifier, in this context it means a token that contains other
+ tokens. It's used to represent an XML element. That means that SPRM tokens
+ can contain other SPRM tokens, and also attribute tokens, while attribute
+ tokens only contain simple types (boolean, integer, string).
+
+ More terminology: the types in the OOXML schema have two typical prefixes:
+
+ - CT_something: complex type, used to describe an XML element
+ - ST_something: simple type, used to describe the contents of an attribute
+
+ For tokens the following abbreviations are used:
+
+ - NS_something: namespace
+ - LN_something: local name
+ -->
+
+ <!--
+ The model element is the toplevel container for the XML element /
+ attribute mapping definition. It contains namespace aliases, direct token
+ definitions and mapping definitions for each namespace.
+ -->
+ <define name="model-element">
+ <element name="model">
+ <oneOrMore>
+ <ref name="token-element"/>
+ </oneOrMore>
+ <oneOrMore>
+ <ref name="namespace-element"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ A token element can explicitly define a token. This allows generating
+ such a token in the tokenizers and handling it in the domain mapper. Ideally
+ tokens are *not* defined this way, they are mapped to an XML element or
+ attribute from the OOXML specification.
+ -->
+ <define name="token-element">
+ <element name="token">
+ <!--
+ The token name must be ooxml:something, then in C++ it'll be the
+ NS_ooxml::LN_something ("OOXML namespace, something local name")
+ constant.
+ -->
+ <attribute name="tokenid"/>
+ </element>
+ </define>
+
+ <!--
+ A namespace element is a container for a subset of the relax-ng grammar
+ of a part of the OOXML specification. It also contains the resource
+ definitions, which specify how XML elements and attributes are mapped to
+ tokens.
+ -->
+ <define name="namespace-element">
+ <element name="namespace">
+ <attribute name="name"/>
+ <zeroOrMore>
+ <ref name="start-element"/>
+ </zeroOrMore>
+ <ref name="grammar-element"/>
+ <zeroOrMore>
+ <ref name="resource-element"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ A start element is similar to the relax-ng start element, but this one has a
+ name attribute to refer to a define, while the relax-ng one has a ref child
+ element to do the same.
+ -->
+ <define name="start-element">
+ <element name="start">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+ <!--
+ A resource element always matches (by its name attribute) a define from the
+ grammar of the namespace. It describes how that (simple or complex) type is
+ parsed during import.
+
+ Example:
+
+ <resource name="CT_Font" resource="Properties">
+ ...
+ </resource>
+
+ or
+
+ <resource name="CT_OMathPara" resource="Stream"/>
+ -->
+ <define name="resource-element">
+ <element name="resource">
+ <!-- There should be a define element with the same name attribute. -->
+ <attribute name="name"/>
+ <!--
+ This means the resource element will be handled by the
+ OOXMLFastContextHandler<resource> class.
+
+ The two most important resources:
+
+ - Properties: this maps elements/attributes to SPRM/attribute tokens
+ - Stream: If the element itself does not require any special handling,
+ but the subelements are interesting, use this resource. If no
+ explicit resource element is available, then a null context will be
+ created and the element and all its subelements will be ignored.
+ -->
+ <attribute name="resource"/>
+ <optional>
+ <attribute name="tokenid"/>
+ </optional>
+ <zeroOrMore>
+ <choice>
+ <ref name="resource-element-element"/>
+ <ref name="resource-attribute-element"/>
+ <ref name="resource-value-element"/>
+ <ref name="resource-action-element"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ The <element> child of a <resource> defines what element name will be handled
+ via what token.
+
+ Example:
+
+ <element name="charset" tokenid="ooxml:CT_Font_charset"/>
+
+ Means the <charset> element will be handled in the sprm() function of the handler
+ class as a NS_ooxml::LN_CT_Font_charset case. (sprm() is a logging wrapper
+ around lcl_sprm(), which is the real implementation.)
+ -->
+ <define name="resource-element-element">
+ <element name="element">
+ <attribute name="name"/>
+ <attribute name="tokenid"/>
+ </element>
+ </define>
+
+ <!--
+ The <attribute> child of a <resource> defines what attribute name will be
+ handled via what token.
+
+ Example:
+
+ <attribute name="name" tokenid="ooxml:CT_Font_name"/>
+
+ Means the <name> attribute will be handled in the attribute() (real
+ implementation in lcl_attribute()) function of the handler class as a
+ NS_ooxml::LN_CT_Font_name case.
+ -->
+ <define name="resource-attribute-element">
+ <element name="attribute">
+ <attribute name="name"/>
+ <optional>
+ <attribute name="tokenid"/>
+ </optional>
+ <optional>
+ <attribute name="action"/>
+ </optional>
+ </element>
+ </define>
+
+ <!--
+ A <value> inside a <resource> defines how to map the string data of a value
+ to a token. The tokenid attribute defines the token name, the text of the
+ element defines the string. This is useful in case the value of an attribute
+ is a choice from a predefined list.
+ -->
+ <define name="resource-value-element">
+ <element name="value">
+ <attribute name="tokenid"/>
+ <text/>
+ </element>
+ </define>
+
+ <!--
+ An <action> inside a <resource> can perform additional actions in the
+ following situations:
+
+ - start of the element
+ - end of the element
+ - character data of the element
+
+ The tokenid attribute restricts the action to a particular element.
+
+ Example:
+
+ <resource name="CT_TxbxContent" resource="Stream">
+ <action name="start" action="startTxbxContent"/>
+ <action name="end" action="endTxbxContent"/>
+ </resource>
+
+ That means that when:
+
+ - <txbxContent> starts, OOXMLFastContextHandler::startTxbxContent() will be called
+ - <txbxContent> ends, OOXMLFastContextHandler::endTxbxContent() will be called
+ -->
+ <define name="resource-action-element">
+ <element name="action">
+ <attribute name="name"/>
+ <attribute name="action"/>
+ <optional>
+ <attribute name="tokenid"/>
+ </optional>
+ <optional>
+ <attribute name="sendtokenid"/>
+ </optional>
+ <optional>
+ <ref name="resource-action-cond-element"/>
+ </optional>
+ </element>
+ </define>
+
+ <!--
+ Some actions take parameters, which can be defined by the <cond> element.
+
+ Example:
+
+ <resource name="CT_FldChar" resource="Stream">
+ <action name="start" action="fieldstart">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_begin"/>
+ </action>
+ </resource>
+
+ That means:
+
+ - if the <fldChar> starts with an fldCharType attribute being "begin"
+ - then perform the "fieldstart" action.
+ -->
+ <define name="resource-action-cond-element">
+ <element name="cond">
+ <attribute name="tokenid"/>
+ <attribute name="value"/>
+ </element>
+ </define>
+
+ <!-- The entry point of the schema. -->
+ <start>
+ <ref name="model-element"/>
+ </start>
+</grammar>
+<!-- vim: ft=xml shiftwidth=2 softtabstop=2 expandtab:
+-->
diff --git a/writerfilter/documentation/sprms.txt b/writerfilter/documentation/sprms.txt
new file mode 100644
index 000000000..6250de9e4
--- /dev/null
+++ b/writerfilter/documentation/sprms.txt
@@ -0,0 +1,7 @@
+0x2461: extra alignment:
+
+ 4: distributed
+ 8: justify low
+ 5: justify middle
+ 7: justify high
+ 9: Thai Distribute
diff --git a/writerfilter/documentation/tablesInDoc.txt b/writerfilter/documentation/tablesInDoc.txt
new file mode 100644
index 000000000..50c58a4e2
--- /dev/null
+++ b/writerfilter/documentation/tablesInDoc.txt
@@ -0,0 +1,153 @@
+#
+# 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/.
+#
+# This file incorporates work covered by the following license notice:
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed
+# with this work for additional information regarding copyright
+# ownership. The ASF licenses this file to you under the Apache
+# License, Version 2.0 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.apache.org/licenses/LICENSE-2.0 .
+#
+
+All paragraphs in tables:
+
+ sprms:
+ 0x2416 (sprmPFInTable) indicates a paragraph is in a table
+ 0x6649 (sprmPTableDepth) demarks the nesting depth of the paragraph
+
+paragraph at nesting depth 1:
+
+ end of cell: 0x7
+ end of row: 0x7 + sprm 0x2417(sprmFTtp)
+
+ the end of a row has its own 0x7
+
+paragraphs at nesting depth > 1;
+
+ end of cell: 0xd + sprm 0x244b(sprmPCell)
+ end of row 0xd + sprm 0x244b(sprmPCell) + sprm 0x244c(sprmPRow)
+
+ the end of a row has its own 0xd
+
+Algorithm to detect table structure:
+
+Datastructures:
+
+RowData<Handle>:
+ int getCellCount()
+ // return number of cells in row
+ Handle getStart(i)
+ // get handle for start of cell i
+ Handle getEnd(i)
+ // get handle for end off cell i
+ Properties getProperties()
+ // return properties of row
+
+TableData<Handle>:
+ void addCell(Handle start, Handle end)
+ // insert cell starting at start and ending at end into the
+ // current row
+ void endRow(properties)
+ // end current row and save properties for that row, begin new row
+ int getRowCount
+ // return number of rows in table
+ RowData<Handle> getRow(i)
+ // get data for row i
+
+prevTableDepth
+ depth in table hierarchy of previous paragraph
+
+curTableDepth
+ depth in table hierarchy of current paragraph
+
+bInCell
+ true if current paragraph is in a cell
+
+bEndCell
+ true if current paragraph if the last paragraph of a cell
+
+bEndRow
+ true if current paragraph is the end of a row
+
+paragraphHandle
+ handle for current paragraph
+
+initial:
+ create stack of TableData<Handle>
+
+final:
+ handle remaining TableData<Handle> on stack
+
+creating StreamHandler:
+ push new TableData<Handle> on stack
+
+destroying StreamHandler:
+ handle TableData<Handle> on top of stack
+ pop TableData<Handle> from stack
+
+StreamHandler::substream:
+ push new TableData<Handle> on stack
+ handle TableData<Handle> on top of stack
+ pop TableData<Handle> from stack
+
+starting paragraph group:
+ paragraphHandle = currentHandle;
+ bInCell = false;
+ bCellEnd = false;
+ bRowEnd = false;
+
+ending paragraph group:
+ difference = curTableDepth - prevTableDepth
+
+ if (difference > 0)
+ push difference new TableData<Handle> onto stack
+ else if (difference < 0)
+ {
+ repeat difference times
+ {
+ handle top of stack
+ pop stack
+ }
+ }
+ precTableDepth = curTableDepth
+
+ if (bInCell)
+ {
+ if (handleStart is null)
+ handleStart = paragraphHandle;
+
+ if (bCellEnd)
+ {
+ stack.top().addCell(handleStart, paragraphHandle);
+ clear handleStart
+ }
+
+ if (bRowEnd)
+ {
+ stack.top().endRow(properties)
+ }
+
+
+in StreamHandler::props:
+ save properties
+
+PropertiesHandler::sprm:
+ sprm 0x6649:
+ save value in curTableDepth
+ sprm 0x2416:
+ bInCell = true
+ sprm 0x244b:
+ bCellEnd = true
+ sprm 0x2417:
+ bRowEnd = true
+
+text:
+ 0x7:
+ bCellEnd = true
diff --git a/writerfilter/inc/dmapper/CommentProperties.hxx b/writerfilter/inc/dmapper/CommentProperties.hxx
new file mode 100644
index 000000000..d22a2f726
--- /dev/null
+++ b/writerfilter/inc/dmapper/CommentProperties.hxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#pragma once
+
+namespace writerfilter
+{
+/**
+ A container for the extended comment properties linked to the last paragraph of a comment
+
+ Corresponds to the data available in w15:commentEx elements from commentsExtended stream
+ ([MS-DOCX]): resolved state and parent (referring to comment that this one answers to; TODO).
+
+ @since 7.2
+*/
+struct CommentProperties
+{
+ bool bDone;
+ // TODO: a reference to a parent comment (paraIdParent: [MS-DOCX] sect. 2.5.3.1 CT_CommentEx)
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/writerfilter/inc/dmapper/DomainMapperFactory.hxx b/writerfilter/inc/dmapper/DomainMapperFactory.hxx
new file mode 100644
index 000000000..944ec1aee
--- /dev/null
+++ b/writerfilter/inc/dmapper/DomainMapperFactory.hxx
@@ -0,0 +1,48 @@
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <dmapper/resourcemodel.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace utl
+{
+class MediaDescriptor;
+}
+
+namespace writerfilter::dmapper
+{
+enum class SourceDocumentType
+{
+ OOXML,
+ RTF
+};
+
+/// Interface to create a DomainMapper instance.
+class DomainMapperFactory
+{
+public:
+ static Stream::Pointer_t
+ createMapper(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xModel, bool bRepairStorage,
+ SourceDocumentType eDocumentType, utl::MediaDescriptor const& rMediaDesc);
+};
+
+// export just for test
+SAL_DLLPUBLIC_EXPORT std::tuple<OUString, std::vector<OUString>, std::vector<OUString>>
+splitFieldCommand(const OUString& rCommand);
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx b/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
new file mode 100644
index 000000000..a6458333b
--- /dev/null
+++ b/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
@@ -0,0 +1,30 @@
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <map>
+
+namespace writerfilter::dmapper
+{
+class GraphicZOrderHelper
+{
+public:
+ void addItem(css::uno::Reference<css::beans::XPropertySet> const& props,
+ sal_Int32 relativeHeight);
+ sal_Int32 findZOrder(sal_Int32 relativeHeight, bool bOldStyle = false);
+
+private:
+ using Items = std::map<sal_Int32, css::uno::Reference<css::beans::XPropertySet>>;
+ Items items;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/dmapper/resourcemodel.hxx b/writerfilter/inc/dmapper/resourcemodel.hxx
new file mode 100644
index 000000000..e277ed675
--- /dev/null
+++ b/writerfilter/inc/dmapper/resourcemodel.hxx
@@ -0,0 +1,419 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <string>
+#include <sal/types.h>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <tools/ref.hxx>
+
+/**
+ @file resourcemodel.hxx
+
+ The classes in this file define the interfaces for the resource
+ model of the DocTokenizer:
+
+ @image html doctok.png
+
+ A resource is a set of events that describe an object. A resource
+ is only an abstract concept. It is not instantiated to a class.
+
+ A reference to a resource represents the object that the resource
+ describes. The reference can be resolved thereby generating the
+ events of the resource.
+
+ A handler receives the events generated by resolving a
+ reference. There are several types of handlers each accepting their
+ specific set of events.
+
+ References always have a parameter determining the kind of handler
+ they send the events they generate to. The set of events generated
+ by resolving the reference is a subset of the events received by
+ the handler.
+*/
+
+typedef sal_uInt32 Id;
+
+namespace writerfilter
+{
+struct CommentProperties;
+
+/**
+ Reference to a resource that generates events and sends them to a
+ handler.
+
+ The reference can be resolved, i.e. the resource generates its
+ events. The events must be suitable for the handler type given by
+ the template parameter.
+
+ @attention The parameter of the template does not determine the
+ type of the reference's target. It determines the type of the handler!
+
+ Example:
+
+ A Word document can be represented as a stream of events. Event
+ types in a Word document are text, properties, tables, starts and
+ ends of groups. These can be handled by a stream handler (@see
+ Stream). Thus a reference to a Word document is resolved by
+ sending these events to a stream handler.
+*/
+
+template <class T> class SAL_DLLPUBLIC_TEMPLATE Reference : public virtual SvRefBase
+{
+public:
+ /**
+ Pointer to reference
+
+ @attention The ownership of a reference is transferred when
+ the reference is passed.
+ */
+ typedef tools::SvRef<Reference<T>> Pointer_t;
+
+ /**
+ Resolves the reference.
+
+ The events of the references target resource are generated and
+ send to a handler.
+
+ @param rHandler handler which receives the events
+ */
+ virtual void resolve(T& rHandler) = 0;
+
+ Reference() = default;
+ Reference(Reference const&) = default;
+ Reference(Reference&&) = default;
+ Reference& operator=(Reference const&) = default;
+ Reference& operator=(Reference&&) = default;
+
+protected:
+ ~Reference() override {}
+};
+
+class Value;
+class Sprm;
+
+/**
+ Handler for properties.
+ */
+class Properties : public virtual SvRefBase
+{
+public:
+ /**
+ Receives an attribute.
+
+ @param name name of the attribute
+ @param val value of the attribute
+ */
+ virtual void attribute(Id name, Value& val) = 0;
+
+ /**
+ Receives a SPRM.
+
+ @param sprm the SPRM received
+ */
+ virtual void sprm(Sprm& sprm) = 0;
+
+protected:
+ ~Properties() override {}
+};
+
+/**
+ Handler for tables.
+ */
+class Table : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<Table> Pointer_t;
+
+ /**
+ Receives an entry of the table.
+
+ @param pos position of the entry in the table
+ @param ref reference to properties of the entry
+ */
+ virtual void entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref) = 0;
+
+protected:
+ ~Table() override {}
+};
+
+/**
+ Handler for binary objects.
+ */
+class BinaryObj
+{
+public:
+ /**
+ Receives binary data of the object.
+
+ @param buf pointer to buffer containing the data
+ @param len size of buffer
+ */
+ virtual void data(const sal_uInt8* buf, size_t len) = 0;
+
+protected:
+ ~BinaryObj() {}
+};
+
+const sal_uInt8 cFieldLock = 0x8;
+const sal_uInt8 cFieldStart = 0x13;
+const sal_uInt8 cFieldSep = 0x14;
+const sal_uInt8 cFieldEnd = 0x15;
+
+namespace ooxml
+{
+class OOXMLDocument;
+}
+
+/**
+ Handler for a stream.
+ */
+class Stream : public virtual SvRefBase
+{
+public:
+ /**
+ Pointer to this stream.
+ */
+ typedef tools::SvRef<Stream> Pointer_t;
+
+ /**
+ Receives start mark for group with the same section properties.
+ */
+ virtual void startSectionGroup() = 0;
+
+ /**
+ Receives end mark for group with the same section properties.
+ */
+ virtual void endSectionGroup() = 0;
+
+ /// The current section is the last one in this body text.
+ virtual void markLastSectionGroup(){};
+
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) = 0;
+
+ /**
+ Receives start mark for group with the same paragraph properties.
+ */
+ virtual void startParagraphGroup() = 0;
+
+ /**
+ Receives end mark for group with the same paragraph properties.
+ */
+ virtual void endParagraphGroup() = 0;
+
+ virtual void markLastParagraphInSection(){};
+
+ /**
+ Receives start mark for group with the same character properties.
+ */
+ virtual void startCharacterGroup() = 0;
+
+ /**
+ Receives end mark for group with the same character properties.
+ */
+ virtual void endCharacterGroup() = 0;
+
+ /**
+ Receives a shape.
+ */
+ virtual void startShape(css::uno::Reference<css::drawing::XShape> const& xShape) = 0;
+
+ virtual void endShape() = 0;
+
+ /**
+ Receives a text-box-content.
+ */
+ virtual void startTextBoxContent() = 0;
+
+ virtual void endTextBoxContent() = 0;
+
+ /**
+ Receives 8-bit per character text.
+
+ @param data buffer containing the text
+ @param len number of characters in the text
+ */
+ virtual void text(const sal_uInt8* data, size_t len) = 0;
+
+ /**
+ Receives 16-bit per character text.
+
+ @param data buffer containing the text
+ @param len number of characters in the text.
+ */
+ virtual void utext(const sal_uInt8* data, size_t len) = 0;
+
+ /**
+ * Offset in EMUs for a shape.
+ *
+ * Call *before* an ooxml::CT_PosH/V_posOffset sprm is sent.
+ */
+ virtual void positionOffset(const OUString& rText, bool bVertical) = 0;
+ /// Returns the last set offsets of a shape in HMM.
+ virtual css::awt::Point getPositionOffset() = 0;
+ /**
+ * Horizontal and vertical alignment for a shape.
+ *
+ * Call *before* an ooxml:CT_PosH/V_align sprm is sent.
+ */
+ virtual void align(const OUString& rText, bool bVertical) = 0;
+ virtual void positivePercentage(const OUString& rText) = 0;
+
+ /**
+ Receives properties of the current run of text.
+
+ @param ref reference to the properties
+ */
+ virtual void props(writerfilter::Reference<Properties>::Pointer_t ref) = 0;
+
+ /**
+ Receives table.
+
+ @param name name of the table
+ @param ref reference to the table
+ */
+ virtual void table(Id name, writerfilter::Reference<Table>::Pointer_t ref) = 0;
+
+ /**
+ Receives a substream.
+
+ @param name name of the substream
+ @param ref reference to the substream
+ */
+ virtual void substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref) = 0;
+
+ /**
+ Debugging: Receives information about current point in stream.
+
+ @param info the information
+ */
+ virtual void info(const std::string& info) = 0;
+
+ /// Receives start mark for glossary document entry.
+ virtual void startGlossaryEntry() = 0;
+
+ /// Receives end mark for glossary document entry.
+ virtual void endGlossaryEntry() = 0;
+
+ /// Receives identifier for node entry.
+ virtual void checkId(const sal_Int32 nId) = 0;
+
+ virtual void commentProps(const OUString& /*sId*/, const CommentProperties& /*rProps*/) {}
+
+protected:
+ ~Stream() override {}
+};
+
+/**
+ A value.
+
+ The methods of this class may throw exceptions if a certain aspect
+ makes no sense for a certain value, e.g. the integer value of a
+ string.
+ */
+class Value : public virtual SvRefBase
+{
+public:
+ /**
+ Pointer to a value.
+ */
+ typedef tools::SvRef<Value> Pointer_t;
+
+ /**
+ Returns integer representation of the value.
+ */
+ virtual int getInt() const = 0;
+
+ /**
+ Returns string representation of the value.
+ */
+ virtual OUString getString() const = 0;
+
+ /**
+ Returns representation of the value as uno::Any.
+ */
+ virtual css::uno::Any getAny() const = 0;
+
+ /**
+ Returns properties of this value.
+ */
+ virtual writerfilter::Reference<Properties>::Pointer_t getProperties() = 0;
+
+ /**
+ Returns binary object of this value.
+ */
+ virtual writerfilter::Reference<BinaryObj>::Pointer_t getBinary() = 0;
+
+ /**
+ Returns string representation of this value.
+ */
+#ifdef DBG_UTIL
+ virtual std::string toString() const = 0;
+#endif
+};
+
+/**
+ An SPRM: Section, Paragraph and Run Modifier
+
+ */
+class Sprm : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<Sprm> Pointer_t;
+
+ /**
+ Returns id of the SPRM.
+ */
+ virtual sal_uInt32 getId() const = 0;
+
+ /**
+ Returns value of the SPRM.
+ */
+ virtual Value::Pointer_t getValue() = 0;
+
+ /**
+ Returns reference to properties contained in the SPRM.
+
+ */
+ virtual writerfilter::Reference<Properties>::Pointer_t getProps() = 0;
+
+ /**
+ Returns name of sprm.
+ */
+#ifdef DBG_UTIL
+ virtual std::string getName() const = 0;
+#endif
+
+ /**
+ Returns string representation of sprm.
+ */
+#ifdef DBG_UTIL
+ virtual std::string toString() const = 0;
+#endif
+
+protected:
+ ~Sprm() override {}
+};
+
+typedef sal_Int32 Token_t;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/ooxml/OOXMLDocument.hxx b/writerfilter/inc/ooxml/OOXMLDocument.hxx
new file mode 100644
index 000000000..1179be43c
--- /dev/null
+++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx
@@ -0,0 +1,256 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <dmapper/resourcemodel.hxx>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <oox/shape/ShapeContextHandler.hxx>
+
+/**
+ @file OOXMLDocument.hxx
+
+ <h1>Import of OOXML WordprocessingML Documents</h1>
+
+ The following picture shows the classes involved in importing OOXML
+ WordprocessingML documents.
+
+ @image html ooxmlimportchain.png
+
+ The DOCX consists of parts. Each part is an XML document. The
+ OOXMLDocument opens the DOCX and creates a SAX parser for the part
+ containing the main document content. The OOXMLDocument creates a
+ SAX handler, too. This handler is set as the handler for the events
+ created by the parser. Finally the OOXMLDocument initiates the
+ parsing process.
+
+ The SAX handler hosts a stack of contexts. Each context is an
+ instance of a class derived from OOXMLContext. There is a context
+ class for each <define> in the model.xml.
+
+ For a detailed information about how the contexts are handled see
+ the documentation for OOXMLContext.
+
+ The contexts know how to convert an element in OOXML to the
+ intermediate format that the domain mapper understands. They
+ enumerate the according entity in OOXML by sending the according
+ events to the domain mapper.
+
+ The domain mapper knows how to convert the intermediate format to
+ API calls. It takes the events sent by the contexts and uses the
+ core API to insert the according elements to the core.
+ */
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLStream : public virtual SvRefBase
+{
+public:
+ enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING,
+ FOOTNOTES, ENDNOTES, COMMENTS, COMMENTS_EXTENDED, THEME, CUSTOMXML, CUSTOMXMLPROPS, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, VBADATA };
+ typedef tools::SvRef<OOXMLStream> Pointer_t;
+
+ /**
+ Returns fast parser for this stream.
+ */
+ virtual css::uno::Reference<css::xml::sax::XFastParser> getFastParser() = 0;
+
+ virtual css::uno::Reference<css::io::XInputStream> getDocumentStream() = 0;
+
+ /**
+ Returns component context for this stream.
+ */
+ virtual css::uno::Reference<css::uno::XComponentContext> getContext() = 0;
+
+ /**
+ Returns target URL from relationships for a given id.
+
+ @param rId the id to look for
+
+ @return the URL found or an empty string
+ */
+ virtual OUString getTargetForId(const OUString & rId) = 0;
+
+ virtual const OUString & getTarget() const = 0;
+
+ virtual css::uno::Reference<css::xml::sax::XFastTokenHandler>
+ getFastTokenHandler() = 0;
+
+};
+
+class OOXMLDocument : public writerfilter::Reference<Stream>
+{
+public:
+ /**
+ Pointer to this stream.
+ */
+ typedef tools::SvRef<OOXMLDocument> Pointer_t;
+
+ /**
+ Resolves this document to a stream handler.
+
+ @param rStream stream handler to resolve this document to
+ */
+ virtual void resolve(Stream & rStream) override = 0;
+
+ /**
+ Resolves a footnote to a stream handler.
+
+ A footnote is resolved if either the note type or
+ note id matches.
+
+ @param rStream stream handler to resolve to
+ @param rNoteType type of footnote to resolve
+ @param rNoteId id of the footnote to resolve
+ */
+ virtual void resolveFootnote(Stream & rStream,
+ Id aNoteType,
+ const sal_Int32 nNoteId) = 0;
+ /**
+ Resolves an endnote to a stream handler.
+
+ An endnote is resolved if either the note type or
+ note id matches.
+
+ @param rStream stream handler to resolve to
+ @param rNoteType type of footnote to resolve
+ @param rNoteId id of the endnote to resolve
+ */
+ virtual void resolveEndnote(Stream & rStream,
+ Id aNoteType,
+ const sal_Int32 NoteId) = 0;
+
+ /**
+ Resolves a comment to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param rComment id of the comment to resolve
+ */
+ virtual void resolveComment(Stream & rStream,
+ const sal_Int32 nCommentId) = 0;
+
+ /**
+ Resolves a picture to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param rPictureId id of the picture to resolve
+ */
+ virtual void resolvePicture(Stream & rStream,
+ const OUString & rPictureId) = 0;
+
+ /**
+ Resolves a header to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param type type of header to resolve:
+ NS_ooxml::LN_Value_ST_HrdFtr_even header on even page
+ NS_ooxml::LN_Value_ST_HrdFtr_default header on right page
+ NS_ooxml::LN_Value_ST_HrdFtr_first header on first page
+
+ @param rId id of the header
+ */
+ virtual void resolveHeader(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) = 0;
+
+ /**
+ Resolves a footer to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param type type of footer to resolve:
+ NS_ooxml::LN_Value_ST_HrdFtr_even header on even page
+ NS_ooxml::LN_Value_ST_HrdFtr_default header on right page
+ NS_ooxml::LN_Value_ST_HrdFtr_first header on first page
+
+ @param rId id of the header
+ */
+ virtual void resolveFooter(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) = 0;
+
+
+ /**
+ Returns target URL from relationships for a given id.
+
+ @param rId the id to look for
+
+ @return the URL found or an empty string
+ */
+ virtual OUString getTargetForId(const OUString & rId) = 0;
+
+ virtual void setModel(css::uno::Reference<css::frame::XModel> xModel) = 0;
+ virtual css::uno::Reference<css::frame::XModel> getModel() = 0;
+ virtual void setDrawPage(css::uno::Reference<css::drawing::XDrawPage> xDrawPage) = 0;
+ virtual css::uno::Reference<css::drawing::XDrawPage> getDrawPage() = 0;
+ virtual css::uno::Reference<css::io::XInputStream> getInputStreamForId(const OUString & rId) = 0;
+ virtual void setXNoteId(const sal_Int32 nId) = 0;
+ virtual sal_Int32 getXNoteId() const = 0;
+ virtual const OUString & getTarget() const = 0;
+ virtual rtl::Reference<oox::shape::ShapeContextHandler> getShapeContext( ) = 0;
+ virtual void setShapeContext( rtl::Reference<oox::shape::ShapeContextHandler> xContext ) = 0;
+ /// Push context of drawingML shapes, so nested shapes are handled separately.
+ virtual void pushShapeContext() = 0;
+ /// Pop context of a previously pushed drawingML shape.
+ virtual void popShapeContext() = 0;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getThemeDom( ) = 0;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom( ) = 0;
+ virtual css::uno::Sequence<css::uno::Sequence< css::beans::NamedValue> > getGlossaryDomList() = 0;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomList( ) = 0;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomPropsList( ) = 0;
+ virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() = 0;
+};
+
+
+class OOXMLDocumentFactory
+{
+public:
+ static OOXMLStream::Pointer_t
+ createStream(const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ const css::uno::Reference<css::io::XInputStream>& rStream,
+ bool bRepairStorage);
+
+ static OOXMLStream::Pointer_t
+ createStream(const OOXMLStream::Pointer_t& pStream,
+ OOXMLStream::StreamType_t nStreamType);
+
+ static OOXMLStream::Pointer_t
+ createStream(const OOXMLStream::Pointer_t& pStream, const OUString & rId);
+
+ static OOXMLDocument *
+ createDocument(const OOXMLStream::Pointer_t& pStream,
+ const css::uno::Reference<css::task::XStatusIndicator>& xStatusIndicator,
+ bool bSkipImage, const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor);
+
+};
+
+std::string fastTokenToId(sal_uInt32 nToken);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/ooxml/QNameToString.hxx b/writerfilter/inc/ooxml/QNameToString.hxx
new file mode 100644
index 000000000..d7d27d302
--- /dev/null
+++ b/writerfilter/inc/ooxml/QNameToString.hxx
@@ -0,0 +1,31 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <string>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter
+{
+#ifdef DBG_UTIL
+std::string QNameToString(Id);
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/pch/precompiled_writerfilter.cxx b/writerfilter/inc/pch/precompiled_writerfilter.cxx
new file mode 100644
index 000000000..135ea5e8c
--- /dev/null
+++ b/writerfilter/inc/pch/precompiled_writerfilter.cxx
@@ -0,0 +1,12 @@
+/* -*- 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 "precompiled_writerfilter.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/pch/precompiled_writerfilter.hxx b/writerfilter/inc/pch/precompiled_writerfilter.hxx
new file mode 100644
index 000000000..65289d9c1
--- /dev/null
+++ b/writerfilter/inc/pch/precompiled_writerfilter.hxx
@@ -0,0 +1,123 @@
+/* -*- 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/.
+ */
+
+/*
+ This file has been autogenerated by update_pch.sh. It is possible to edit it
+ manually (such as when an include file has been moved/renamed/removed). All such
+ manual changes will be rewritten by the next run of update_pch.sh (which presumably
+ also fixes all possible problems, so it's usually better to use it).
+
+ Generated on 2021-08-22 14:50:51 using:
+ ./bin/update_pch writerfilter writerfilter --cutoff=5 --exclude:system --exclude:module --exclude:local
+
+ If after updating build fails, use the following command to locate conflicting headers:
+ ./bin/update_pch_bisect ./writerfilter/inc/pch/precompiled_writerfilter.hxx "make writerfilter.build" --find-conflicts
+*/
+
+#include <sal/config.h>
+#if PCH_LEVEL >= 1
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <iomanip>
+#include <limits>
+#include <math.h>
+#include <memory>
+#include <ostream>
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include <vector>
+#include <boost/lexical_cast.hpp>
+#endif // PCH_LEVEL >= 1
+#if PCH_LEVEL >= 2
+#include <osl/diagnose.h>
+#include <osl/diagnose.hxx>
+#include <osl/file.hxx>
+#include <osl/mutex.hxx>
+#include <osl/thread.h>
+#include <rtl/character.hxx>
+#include <rtl/instance.hxx>
+#include <rtl/locale.h>
+#include <rtl/math.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/string.hxx>
+#include <rtl/tencinfo.h>
+#include <rtl/textenc.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/macros.h>
+#include <sal/types.h>
+#include <vcl/dllapi.h>
+#endif // PCH_LEVEL >= 2
+#if PCH_LEVEL >= 3
+#include <basegfx/basegfxdllapi.h>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/tuple/b2dtuple.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uno/Type.h>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/genfunc.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/string.hxx>
+#include <cppu/cppudllapi.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/implbase_ex.hxx>
+#include <cppuhelper/weak.hxx>
+#include <editeng/editengdllapi.h>
+#include <filter/msfilter/util.hxx>
+#include <o3tl/cow_wrapper.hxx>
+#include <o3tl/typed_flags_set.hxx>
+#include <oox/dllapi.h>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <oox/token/tokens.hxx>
+#include <ooxml/resourceids.hxx>
+#include <sfx2/dllapi.h>
+#include <svx/svxdllapi.h>
+#include <tools/UnitConversion.hxx>
+#include <tools/color.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/gen.hxx>
+#include <tools/long.hxx>
+#include <tools/ref.hxx>
+#include <tools/solar.h>
+#include <uno/data.h>
+#include <uno/sequence2.h>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/unotoolsdllapi.h>
+#endif // PCH_LEVEL >= 3
+#if PCH_LEVEL >= 4
+#endif // PCH_LEVEL >= 4
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/inc/rtftok/RTFDocument.hxx b/writerfilter/inc/rtftok/RTFDocument.hxx
new file mode 100644
index 000000000..44d0173a6
--- /dev/null
+++ b/writerfilter/inc/rtftok/RTFDocument.hxx
@@ -0,0 +1,46 @@
+/*
+ * 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/.
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <unotools/mediadescriptor.hxx>
+
+namespace writerfilter::rtftok
+{
+/// The RTFDocument opens and resolves the RTF document.
+class RTFDocument : public writerfilter::Reference<Stream>
+{
+public:
+ /// Pointer to this stream.
+ using Pointer_t = tools::SvRef<RTFDocument>;
+
+ /// Resolves this document to a stream handler.
+ void resolve(Stream& rHandler) override = 0;
+};
+
+/// Interface to create an RTFDocument instance.
+class RTFDocumentFactory
+{
+public:
+ static RTFDocument::Pointer_t
+ createDocument(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor);
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/CellColorHandler.cxx b/writerfilter/qa/cppunittests/dmapper/CellColorHandler.cxx
new file mode 100644
index 000000000..4449e9a20
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/CellColorHandler.cxx
@@ -0,0 +1,70 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/CellColorHandler.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, test129205)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf129205.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ drawing::FillStyle eFillStyle = drawing::FillStyle::FillStyle_NONE;
+ xPara->getPropertyValue("FillStyle") >>= eFillStyle;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: drawing::FillStyle_NONE
+ // - Actual : FillStyle_SOLID
+ // i.e. the paragraph had a solid fill, making the header image invisible.
+ CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_NONE, eFillStyle);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
new file mode 100644
index 000000000..639c8e9e0
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx
@@ -0,0 +1,134 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+
+#include <tools/UnitConversion.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/DomainMapper.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testLargeParaTopMargin)
+{
+ // Given a document with a paragraph with a large "before" spacing.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "large-para-top-margin.docx";
+ getComponent() = loadFromDesktop(aURL);
+
+ // When checking the first paragraph.
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+
+ // Then assert its top margin.
+ sal_Int32 nParaTopMargin{};
+ xPara->getPropertyValue("ParaTopMargin") >>= nParaTopMargin;
+ // <w:spacing w:before="37050"/> in the document.
+ sal_Int32 nExpected = convertTwipToMm100(37050);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 65352
+ // - Actual : 0
+ // i.e. the paragraph margin was lost, which shifted the paragraph to the right (no top margin
+ // -> wrap around a TextBox), which shifted the triangle shape out of the page frame.
+ CPPUNIT_ASSERT_EQUAL(nExpected, nParaTopMargin);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunInPara)
+{
+ // Given a document with a block SDT, and inside that some content + a run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-in-para.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the content inside the block SDT but outside the run SDT is not lost:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: first-second
+ // - Actual : second
+ // i.e. the block-SDT-only string was lost.
+ CPPUNIT_ASSERT_EQUAL(OUString("first-second"), xPara->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtDropdownNoDisplayText)
+{
+ // Given a document with <w:listItem w:value="..."/> (no display text):
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-dropdown-no-display-text.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure we create a dropdown content control, not a rich text one:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParagraphsAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xParagraphsAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), uno::UNO_QUERY);
+ OUString aPortionType;
+ xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+ CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType);
+ uno::Reference<text::XTextContent> xContentControl;
+ xTextPortion->getPropertyValue("ContentControl") >>= xContentControl;
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValues> aListItems;
+ xContentControlProps->getPropertyValue("ListItems") >>= aListItems;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the list item was lost on import.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aListItems.getLength());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.cxx
new file mode 100644
index 000000000..1accc77a1
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/DomainMapperTableHandler.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, test1cellInsidevRightborder)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "1cell-insidev-rightborder.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<text::XTextTablesSupplier> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xTables(xTextDocument->getTextTables(), uno::UNO_QUERY);
+ uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
+ table::BorderLine2 aBorder;
+ xCell->getPropertyValue("RightBorder") >>= aBorder;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 18
+ // i.e. the request to have no table-level right border was lost on import.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(0), aBorder.LineWidth);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testNestedFloatingTable)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "nested-floating-table.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xFrame(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ bool bIsFollowingTextFlow = false;
+ xFrame->getPropertyValue("IsFollowingTextFlow") >>= bIsFollowingTextFlow;
+ // Without the accompanying fix in place, this test would have failed, the nested floating table
+ // was partly positioned outside the table cell, leading to overlapping text.
+ CPPUNIT_ASSERT(bIsFollowingTextFlow);
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
new file mode 100644
index 000000000..16039f983
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
@@ -0,0 +1,323 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/style/BreakType.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/document/XDocumentInsertable.hpp>
+
+#include <vcl/scheduler.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/DomainMapper_Impl.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testPageBreakFooterTable)
+{
+ // Load a document which refers to a footer which ends with a table, and there is a page break
+ // in the body text right after the footer reference.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "page-break-footer-table.docx";
+ getComponent() = loadFromDesktop(aURL);
+
+ // Check the last paragraph.
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPara;
+ while (xParaEnum->hasMoreElements())
+ {
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ }
+ style::BreakType eType = style::BreakType_NONE;
+ xPara->getPropertyValue("BreakType") >>= eType;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 4
+ // - Actual : 0
+ // i.e. there was no page break before the last paragraph.
+ CPPUNIT_ASSERT_EQUAL(style::BreakType_PAGE_BEFORE, eType);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testNumberingRestartStyleParent)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "num-restart-style-parent.docx";
+ getComponent() = loadFromDesktop(aURL);
+
+ // The paragraphs are A 1 2 B 1 2.
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPara;
+ static OUStringLiteral aProp(u"ListLabelString");
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("A."), xPara->getPropertyValue(aProp).get<OUString>());
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("1."), xPara->getPropertyValue(aProp).get<OUString>());
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("2."), xPara->getPropertyValue(aProp).get<OUString>());
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("B."), xPara->getPropertyValue(aProp).get<OUString>());
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1.
+ // - Actual : 3.
+ // i.e. the numbering was not restarted after B.
+ CPPUNIT_ASSERT_EQUAL(OUString("1."), xPara->getPropertyValue(aProp).get<OUString>());
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("2."), xPara->getPropertyValue(aProp).get<OUString>());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testFrameDirection)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "frame-direction.docx";
+ getComponent() = loadFromDesktop(aURL);
+
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xFrame0(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xFrame1(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xFrame2(xDrawPage->getByIndex(2), uno::UNO_QUERY);
+ // Without the accompanying fix in place, all of the following values would be text::WritingMode2::CONTEXT
+ CPPUNIT_ASSERT_EQUAL(text::WritingMode2::CONTEXT,
+ xFrame0->getPropertyValue("WritingMode").get<sal_Int16>());
+ CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR,
+ xFrame1->getPropertyValue("WritingMode").get<sal_Int16>());
+ CPPUNIT_ASSERT_EQUAL(text::WritingMode2::TB_RL,
+ xFrame2->getPropertyValue("WritingMode").get<sal_Int16>());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testAltChunk)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "alt-chunk.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<text::XTextRange> xPara;
+ uno::Reference<beans::XPropertySet> xParaProps;
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ xParaProps.set(xPara, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("outer, before sect break"), xPara->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("Standard"),
+ xParaProps->getPropertyValue("PageStyleName").get<OUString>());
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ xParaProps.set(xPara, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("outer, after sect break"), xPara->getString());
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Converted1
+ // - Actual : Standard
+ // i.e. the page break between the first and the second paragraph was missing.
+ CPPUNIT_ASSERT_EQUAL(OUString("Converted1"),
+ xParaProps->getPropertyValue("PageStyleName").get<OUString>());
+
+ // Without the accompanying fix in place, this test would have failed with a
+ // container.NoSuchElementException, as the document had only 2 paragraphs, all the "inner"
+ // content was lost.
+ xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("inner doc, first para"), xPara->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testFieldIfInsideIf)
+{
+ // Load a document with a field in a table cell: it contains an IF field with various nested
+ // fields.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "field-if-inside-if.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<text::XTextTablesSupplier> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xTables(xTextDocument->getTextTables(), uno::UNO_QUERY);
+ uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
+
+ // Get the result of the topmost field.
+ uno::Reference<text::XTextRange> xCell(xTable->getCellByName("A1"), uno::UNO_QUERY);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 0** Expression is faulty **2
+ // i.e. some of the inner fields escaped outside the outer field.
+ CPPUNIT_ASSERT_EQUAL(OUString("2"), xCell->getString());
+
+ // Test the second cell: it contains "IF ", not the usual " IF ".
+ xCell.set(xTable->getCellByName("A2"), uno::UNO_QUERY);
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 25
+ // - Actual : 025
+ // i.e. some of the inner fields escaped outside the outer field.
+ CPPUNIT_ASSERT_EQUAL(OUString("25"), xCell->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testCreateDatePreserve)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "create-date-preserve.docx";
+ getComponent() = loadFromDesktop(aURL);
+ // Trigger idle layout.
+ Scheduler::ProcessEventsToIdle();
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xPortionEnumAccess(xParaEnum->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortionEnum = xPortionEnumAccess->createEnumeration();
+ uno::Reference<text::XTextRange> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 7/7/2020 10:11:00 AM
+ // - Actual : 07/07/2020
+ // i.e. the formatting of the create date field was lost.
+ CPPUNIT_ASSERT_EQUAL(OUString("7/7/2020 10:11:00 AM"), xPortion->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testChartZOrder)
+{
+ // Given a document with a chart and a shape on it:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "chart-zorder.docx";
+
+ // When loading the document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the shape is on top of the chart:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<lang::XServiceInfo> xChart(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed, as the chart was on top
+ // of the shape.
+ CPPUNIT_ASSERT(xChart->supportsService("com.sun.star.text.TextEmbeddedObject"));
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testPTab)
+{
+ // Given a document that has a <w:ptab> to render a linebreak:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "ptab.docx";
+
+ // When opening that file:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the Writer doc model contains that linebreak:
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY);
+ auto xFooter = xStyle->getPropertyValue("FooterText").get<uno::Reference<text::XTextRange>>();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: <space><newline>1\n
+ // - Actual: <space><tab>1\n
+ // i.e. the layout height of the footer text was incorrect, the page number field was not
+ // visually inside the background shape.
+ CPPUNIT_ASSERT_EQUAL(OUString(" \n1" SAL_NEWLINE_STRING), xFooter->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testPasteOle)
+{
+ // Given an empty document:
+ getComponent() = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+
+ // When pasting RTF into that document:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<document::XDocumentInsertable> xCursor(
+ xText->createTextCursorByRange(xText->getStart()), uno::UNO_QUERY);
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "paste-ole.rtf";
+ xCursor->insertDocumentFromURL(aURL, {});
+
+ // Then make sure that all the 3 paragraphs of the paste data (empty para, OLE obj, text) are
+ // inserted to the document:
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ xParaEnum->nextElement();
+ // Without the accompanying fix in place, this test would have failed, as the paste result was a
+ // single paragraph, containing the OLE object, and the content after the OLE object was lost.
+ CPPUNIT_ASSERT(xParaEnum->hasMoreElements());
+ xParaEnum->nextElement();
+ CPPUNIT_ASSERT(xParaEnum->hasMoreElements());
+ uno::Reference<text::XTextRange> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("hello"), xPara->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testClearingBreak)
+{
+ // Given a document with a clearing break:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "clearing-break.docx";
+
+ // When loading that file:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the clear property of the break is not ignored:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ xPortions->nextElement();
+ xPortions->nextElement();
+ // Without the accompanying fix in place, this test would have failed with:
+ // An uncaught exception of type com.sun.star.container.NoSuchElementException
+ // i.e. the first para was just a fly + text portion, the clearing break was lost.
+ uno::Reference<beans::XPropertySet> xPortion(xPortions->nextElement(), uno::UNO_QUERY);
+ OUString aPortionType;
+ xPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+ CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aPortionType);
+ uno::Reference<text::XTextContent> xLineBreak;
+ xPortion->getPropertyValue("LineBreak") >>= xLineBreak;
+ sal_Int16 eClear{};
+ uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
+ xLineBreakProps->getPropertyValue("Clear") >>= eClear;
+ // SwLineBreakClear::ALL
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(3), eClear);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
new file mode 100644
index 000000000..a20c84905
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
@@ -0,0 +1,411 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/view/XViewCursor.hpp>
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/GraphicImport.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf143455SmartArtPosition)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf143455_SmartArtPosition.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ // Without fix in place the group, which represents the SmartArt, was placed at the initializing
+ // position 0|0.
+ sal_Int32 nHoriPosition = 0;
+ xShape->getPropertyValue("HoriOrientPosition") >>= nHoriPosition;
+ // The test would have failed with Expected: 2858, Actual: 0
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2858), nHoriPosition);
+ sal_Int32 nVertPosition = 0;
+ xShape->getPropertyValue("VertOrientPosition") >>= nVertPosition;
+ // The test would have failed with Expected: 1588, Actual: 0
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1588), nVertPosition);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf143208wrapTight)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf143208_wrapTight.docx";
+ // The document has a shape with indentation and contour wrap "wrapTight". Error was, that
+ // the corresponding shape property 'ContourOutside=true' was not set.
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ bool bContourOutside = false;
+ xShape->getPropertyValue("ContourOutside") >>= bContourOutside;
+ CPPUNIT_ASSERT(bContourOutside);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf142305StrokeGlowMargin)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142305StrokeGlowMargin.docx";
+ // The document has an arc with fat stroke and glow. Its bounding rectangle differs much
+ // from the snap rectangle. Error was, that the margins were not set in a way, that the shape
+ // would render similar to Word.
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nTopMargin = 0;
+ xShape->getPropertyValue("TopMargin") >>= nTopMargin;
+ // Without fix in place top margin was 0, so that the text comes near to the shape.
+ // The test would have failed with Expected: 838, Actual: 0
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(838), nTopMargin);
+ sal_Int32 nBottomMargin = 0;
+ // Without fix in place bottom margin was >0, so that the text was far from to the shape.
+ // The test would have failed with Expected: 0, Actual: 637
+ xShape->getPropertyValue("BottomMargin") >>= nBottomMargin;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nBottomMargin);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf142305SquareWrapMargin)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142305SquareWrapMargin.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<frame::XModel> xModel(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
+ xModel->getCurrentController(), uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextViewCursor> xViewCursor(xTextViewCursorSupplier->getViewCursor());
+ xViewCursor->gotoStart(/*bExpand=*/false);
+ uno::Reference<view::XViewCursor> xCursor(xViewCursor, uno::UNO_QUERY);
+ xCursor->goDown(/*nCount=*/10, /*bExpand=*/false);
+ xViewCursor->goRight(/*nCount=*/1, /*bExpand=*/true);
+ OUString sText = xViewCursor->getString();
+ // Without fix in place, wrap was tight to the bounding box and not around the full shape as in
+ // Word. That results in different text at start of line, here "u" instead of expected "m".
+ CPPUNIT_ASSERT(sText.startsWith("m"));
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf142304GroupPosition)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142304GroupPosition.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nVertPosition = 0;
+ xShape->getPropertyValue("VertOrientPosition") >>= nVertPosition;
+ // Without fix in place the group was shifted left and down
+ // The test would have failed with Expected: 2178, Actual: 2521
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2178), nVertPosition);
+ sal_Int32 nHoriPosition = 0;
+ // The test would have failed with Expected: 4304, Actual: 3874
+ xShape->getPropertyValue("HoriOrientPosition") >>= nHoriPosition;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4304), nHoriPosition);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf141540ChildRotation)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf141540ChildRotation.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<container::XIndexAccess> xGroup(xDrawPage->getByIndex(0), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xRotatedShape(xGroup->getByIndex(1), uno::UNO_QUERY);
+ sal_Int32 nShearAngle = 9000; // initialize with invalid value
+ xRotatedShape->getPropertyValue("ShearAngle") >>= nShearAngle;
+ // Without fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 2494
+ // i.e. the rotated rectangle in the group was sheared, although the group itself is not rotated
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nShearAngle);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf141540GroupRotation)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf141540GroupRotation.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nShearAngle = 9000; // init with invalid value
+ xShape->getPropertyValue("ShearAngle") >>= nShearAngle;
+ // Without fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : -3190
+ // i.e. the group has got a shearing although MSO does not know shearing at all.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nShearAngle);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf141540GroupLinePosSize)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf141540GroupLinePosSize.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+
+ // Test line
+ uno::Reference<drawing::XShape> xLineShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ awt::Point aPosition = xLineShape->getPosition();
+ awt::Size aSize = xLineShape->getSize();
+ // Without fix in place, you had got Position = (19|6498), Size = 5001 x 2
+ // i.e. the line was nearly horizontal instead of vertical
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5022), aPosition.X);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2963), aPosition.Y);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aSize.Width);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7073), aSize.Height);
+
+ // Test group
+ uno::Reference<drawing::XShape> xGroupShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ aPosition = xGroupShape->getPosition();
+ aSize = xGroupShape->getSize();
+ // Without fix in place, you had got Position = (11511|3480), Size = 4022 x 4022
+ // i.e. the group was erroneously downscaled to unrotated size
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(10679), aPosition.X);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2648), aPosition.Y);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5687), aSize.Width);
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5687), aSize.Height);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testGroupShapeRotation)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "group-shape-rotation.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nVertPosition = 0;
+ xShape->getPropertyValue("VertOrientPosition") >>= nVertPosition;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1221
+ // - Actual : -2048
+ // i.e. the group shape had a so low vertical position that the line shape did not point into
+ // it.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1221), nVertPosition);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDrawShapeInlineEffect)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "draw-shape-inline-effect.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nBottomMargin = 0;
+ xShape->getPropertyValue("BottomMargin") >>= nBottomMargin;
+ // 273 in mm100 is 98425 EMUs from the file.
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 273
+ // - Actual : 0
+ // i.e. the layout result had less pages than expected (compared to Word).
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(273), nBottomMargin);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInlineAnchoredZOrder)
+{
+ // Load a document which has two shapes: an inline one and an anchored one. The inline has no
+ // explicit ZOrder, the anchored one has, and it's set to a value so it's visible.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "inline-anchored-zorder.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<container::XNamed> xOval(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Oval 2
+ // - Actual :
+ // i.e. the rectangle (with no name) was on top of the oval one, not the other way around.
+ CPPUNIT_ASSERT_EQUAL(OUString("Oval 2"), xOval->getName());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInlineInShapeAnchoredZOrder)
+{
+ // This document has a textbox shape and then an inline shape inside that.
+ // The ZOrder of the inline shape is larger than the hosting textbox, so the image is visible.
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "inline-inshape-anchored-zorder.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<container::XNamed> xOval(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Picture 1
+ // - Actual : Text Box 2
+ // i.e. the image was behind the textbox that was hosting it.
+ CPPUNIT_ASSERT_EQUAL(OUString("Picture 1"), xOval->getName());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testRelfromhInsidemargin)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "relfromh-insidemargin.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int16 nRelation = 0;
+ xShape->getPropertyValue("HoriOrientRelation") >>= nRelation;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 7 (PAGE_FRAME)
+ // - Actual : 0 (FRAME)
+ // i.e. the horizontal position was relative to the paragraph area, not to the entire page.
+ CPPUNIT_ASSERT_EQUAL(text::RelOrientation::PAGE_FRAME, nRelation);
+ bool bPageToggle = false;
+ xShape->getPropertyValue("PageToggle") >>= bPageToggle;
+ CPPUNIT_ASSERT(bPageToggle);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testWrapPolyCrop)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "wrap-poly-crop.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ drawing::PointSequenceSequence aContour;
+ xShape->getPropertyValue("ContourPolyPolygon") >>= aContour;
+ auto aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(aContour);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(1), aPolyPolygon.count());
+ auto aPolygon = aPolyPolygon.getB2DPolygon(0);
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(4), aPolygon.count());
+
+ // Ideally this would be 2352, because the graphic size in mm100, using the graphic's DPI is
+ // 10582, the lower 33% of the graphic is cropped, and the wrap polygon covers the middle third
+ // of the area vertically. Which means 10582*2/3 = 7054.67 is the cropped height, and the top of
+ // the middle third is 2351.55.
+ // Then there is a 15 twips shift from the origo, so it's 2351.55 + 26.46 = 2378.01 in mm100.
+ //
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2368
+ // - Actual : 3542
+ // i.e. the wrap polygon covered a larger-than-correct area, which end the end means 3 lines
+ // were wrapping around the image, not only 2 as Word does it.
+ CPPUNIT_ASSERT_EQUAL(2368., aPolygon.getB2DPoint(0).getY());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTextboxTextline)
+{
+ // Load a document with a shape with a textbox.
+ // The shape's vertical relation is <wp:positionV relativeFrom="line">.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "textbox-textline.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int16 nActualRelation{};
+ CPPUNIT_ASSERT(xShape->getPropertyValue("VertOrientRelation") >>= nActualRelation);
+ sal_Int32 nActualPosition{};
+ CPPUNIT_ASSERT(xShape->getPropertyValue("VertOrientPosition") >>= nActualPosition);
+
+ sal_Int16 nExpectedRelation = text::RelOrientation::TEXT_LINE;
+ CPPUNIT_ASSERT_EQUAL(nExpectedRelation, nActualRelation);
+ sal_Int32 nExpectedPosition = -2;
+ CPPUNIT_ASSERT_EQUAL(nExpectedPosition, nActualPosition);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTextboxTextlineTop)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "textbox-textline-top.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int16 nActualRelation{};
+ CPPUNIT_ASSERT(xShape->getPropertyValue("VertOrientRelation") >>= nActualRelation);
+ sal_Int16 nExpectedRelation = text::RelOrientation::TEXT_LINE;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 9 (TEXT_LINE)
+ // - Actual : 0 (FRAME)
+ // i.e. the anchor point for the positioning was wrong, resulting in overlapping textboxes.
+ CPPUNIT_ASSERT_EQUAL(nExpectedRelation, nActualRelation);
+
+ sal_Int16 nActualOrient{};
+ CPPUNIT_ASSERT(xShape->getPropertyValue("VertOrient") >>= nActualOrient);
+ sal_Int16 nExpectedOrient = text::VertOrientation::BOTTOM;
+ CPPUNIT_ASSERT_EQUAL(nExpectedOrient, nActualOrient);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testLayoutInCellWrapnoneColumn)
+{
+ // Given a file with a table, then a shape anchored inside the cell:
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "layout-in-cell-wrapnone-column.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the shape can leave the cell:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xNamedShape(xShape, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("Text Box 1"), xNamedShape->getName());
+ bool bFollowingTextFlow = true;
+ // Without the accompanying fix in place, this test would have failed, the shape was not allowed
+ // to leave the cell, leading to incorrect layout.
+ CPPUNIT_ASSERT(xShape->getPropertyValue("IsFollowingTextFlow") >>= bFollowingTextFlow);
+ CPPUNIT_ASSERT(!bFollowingTextFlow);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testLayoutInCellOfHraphics)
+{
+ // Given a file with a table, then a shape anchored inside the cell:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "layout-in-cell-2.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the cell obeys the layoutInCell:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xNamedShape(xShape, uno::UNO_QUERY);
+ bool bFollowingTextFlow = false;
+ CPPUNIT_ASSERT(xShape->getPropertyValue("IsFollowingTextFlow") >>= bFollowingTextFlow);
+ CPPUNIT_ASSERT(bFollowingTextFlow);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx
new file mode 100644
index 000000000..cc651d224
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx
@@ -0,0 +1,173 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XPageCursor.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/PropertyMap.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testFloatingTableHeader)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "floating-table-header.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<frame::XModel> xModel(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
+ xModel->getCurrentController(), uno::UNO_QUERY);
+ uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
+ uno::UNO_QUERY);
+ xCursor->jumpToLastPage();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 3
+ // i.e. a document which is 1 page in Word was imported as a 3 page one.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), xCursor->getPage());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testFollowPageTopMargin)
+{
+ // Load a document with 2 pages: first page has larger top margin, second page has smaller top
+ // margin.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "follow-page-top-margin.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY);
+ auto nTopMargin = xStyle->getPropertyValue("TopMargin").get<sal_Int32>();
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 250
+ // - Actual : 1249
+ // i.e. the top margin on page 2 was too large.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(250), nTopMargin);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTableNegativeVerticalPos)
+{
+ // Given a document with a table which has a negative vertical position (moves up to overlap
+ // with the header):
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "table-negative-vertical-pos.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure we don't import that as a plain table, which can't have a negative top margin:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. this was imported as a plain table, resulting in a 0 top margin (y pos too large).
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xDrawPage->getCount());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorder)
+{
+ // Given a document with a top margin and a border which has more spacing than the margin:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "negative-page-border.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the border distance is negative, so it can appear at the correct
+ // position:
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY);
+ auto nTopMargin = xStyle->getPropertyValue("TopMargin").get<sal_Int32>();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(501), nTopMargin);
+ auto aTopBorder = xStyle->getPropertyValue("TopBorder").get<table::BorderLine2>();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(159), aTopBorder.LineWidth);
+ auto nTopBorderDistance = xStyle->getPropertyValue("TopBorderDistance").get<sal_Int32>();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: -646
+ // - Actual : 0
+ // i.e. the border negative distance was lost.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-646), nTopBorderDistance);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorderNoMargin)
+{
+ // Given a document with no top margin and a border which has spacing:
+ OUString aURL
+ = m_directories.getURLFromSrc(DATA_DIRECTORY) + "negative-page-border-no-margin.docx";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the border distance is negative, so it can appear at the correct
+ // position:
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY);
+ auto nTopMargin = xStyle->getPropertyValue("TopMargin").get<sal_Int32>();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nTopMargin);
+ auto aTopBorder = xStyle->getPropertyValue("TopBorder").get<table::BorderLine2>();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(159), aTopBorder.LineWidth);
+ auto nTopBorderDistance = xStyle->getPropertyValue("TopBorderDistance").get<sal_Int32>();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: -1147
+ // - Actual : 0
+ // i.e. the border negative distance was lost.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1147), nTopBorderDistance);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
new file mode 100644
index 000000000..b2e7f1058
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
@@ -0,0 +1,219 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <comphelper/sequenceashashmap.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+using namespace com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/SdtHelper.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunRichText)
+{
+ // Given a document with a rich text inline/run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-rich-text.docx";
+
+ // When loading the document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that formatting of the text inside the SDT is not lost:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortionEnum = xPara->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY);
+ OUString aTextPortionType;
+ xPortion->getPropertyValue("TextPortionType") >>= aTextPortionType;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: ContentControl
+ // - Actual : TextField
+ // i.e. the SDT was imported as a text field, and the whole SDT had 12pt font size.
+ CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aTextPortionType);
+ uno::Reference<text::XTextContent> xContentControl;
+ xPortion->getPropertyValue("ContentControl") >>= xContentControl;
+ uno::Reference<text::XTextRange> xContentControlRange(xContentControl, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xContentControlRange->getText();
+ uno::Reference<container::XEnumerationAccess> xContentEnumAccess(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xContentEnum = xContentEnumAccess->createEnumeration();
+ uno::Reference<beans::XPropertySet> xContent(xContentEnum->nextElement(), uno::UNO_QUERY);
+ float fCharheight{};
+ xContent->getPropertyValue("CharHeight") >>= fCharheight;
+ CPPUNIT_ASSERT_EQUAL(12.f, fCharheight);
+ xContent.set(xContentEnum->nextElement(), uno::UNO_QUERY);
+ xContent->getPropertyValue("CharHeight") >>= fCharheight;
+ CPPUNIT_ASSERT_EQUAL(24.f, fCharheight);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunCheckbox)
+{
+ // Given a document with a checkbox inline/run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-checkbox.docx";
+
+ // When loading the document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the doc model has a clickable checkbox content control:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortionEnum = xPara->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY);
+ OUString aTextPortionType;
+ xPortion->getPropertyValue("TextPortionType") >>= aTextPortionType;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: ContentControl
+ // - Actual : Text
+ // i.e. the SDT was imported as plain text, making it hard to fill in checkboxes.
+ CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aTextPortionType);
+ uno::Reference<text::XTextContent> xContentControl;
+ xPortion->getPropertyValue("ContentControl") >>= xContentControl;
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ bool bCheckbox{};
+ xContentControlProps->getPropertyValue("Checkbox") >>= bCheckbox;
+ CPPUNIT_ASSERT(bCheckbox);
+ bool bChecked{};
+ xContentControlProps->getPropertyValue("Checked") >>= bChecked;
+ CPPUNIT_ASSERT(bChecked);
+ OUString aCheckedState;
+ xContentControlProps->getPropertyValue("CheckedState") >>= aCheckedState;
+ CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), aCheckedState);
+ OUString aUncheckedState;
+ xContentControlProps->getPropertyValue("UncheckedState") >>= aUncheckedState;
+ CPPUNIT_ASSERT_EQUAL(OUString(u"â˜"), aUncheckedState);
+ uno::Reference<text::XTextRange> xContentControlRange(xContentControl, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xContentControlRange->getText();
+ uno::Reference<container::XEnumerationAccess> xContentEnumAccess(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xContentEnum = xContentEnumAccess->createEnumeration();
+ uno::Reference<text::XTextRange> xContent(xContentEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), xContent->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunDropdown)
+{
+ // Given a document with a dropdown inline/run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-dropdown.docx";
+
+ // When loading the document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the doc model has a clickable dropdown content control:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParagraphsAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xParagraphsAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), uno::UNO_QUERY);
+ OUString aPortionType;
+ xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+ // Without the accompanying fix in place, this failed with:
+ // - Expected: ContentControl
+ // - Actual : TextField
+ // i.e. the SDT was imported as a dropdown field, which does not support display-text + value
+ // pairs.
+ CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType);
+ uno::Reference<text::XTextContent> xContentControl;
+ xTextPortion->getPropertyValue("ContentControl") >>= xContentControl;
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValues> aListItems;
+ xContentControlProps->getPropertyValue("ListItems") >>= aListItems;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(3), aListItems.getLength());
+ comphelper::SequenceAsHashMap aMap0(aListItems[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString("red"), aMap0["DisplayText"].get<OUString>());
+ CPPUNIT_ASSERT_EQUAL(OUString("R"), aMap0["Value"].get<OUString>());
+ comphelper::SequenceAsHashMap aMap1(aListItems[1]);
+ CPPUNIT_ASSERT_EQUAL(OUString("green"), aMap1["DisplayText"].get<OUString>());
+ CPPUNIT_ASSERT_EQUAL(OUString("G"), aMap1["Value"].get<OUString>());
+ comphelper::SequenceAsHashMap aMap2(aListItems[2]);
+ CPPUNIT_ASSERT_EQUAL(OUString("blue"), aMap2["DisplayText"].get<OUString>());
+ CPPUNIT_ASSERT_EQUAL(OUString("B"), aMap2["Value"].get<OUString>());
+ uno::Reference<text::XTextRange> xContentControlRange(xContentControl, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xContentControlRange->getText();
+ uno::Reference<container::XEnumerationAccess> xContentEnumAccess(xText, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xContentEnum = xContentEnumAccess->createEnumeration();
+ uno::Reference<text::XTextRange> xContent(xContentEnum->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("choose a color"), xContent->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtRunPicture)
+{
+ // Given a document with a dropdown inline/run SDT:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-run-picture.docx";
+
+ // When loading the document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the doc model has a clickable picture content control:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParagraphsAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xParagraphsAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ uno::Reference<beans::XPropertySet> xTextPortion(xPortions->nextElement(), uno::UNO_QUERY);
+ OUString aPortionType;
+ xTextPortion->getPropertyValue("TextPortionType") >>= aPortionType;
+ // Without the accompanying fix in place, this failed with:
+ // - Expected: ContentControl
+ // - Actual : Frame
+ // i.e. the SDT was imported as a plain image, not as a clickable placeholder in a content
+ // control.
+ CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType);
+ uno::Reference<text::XTextContent> xContentControl;
+ xTextPortion->getPropertyValue("ContentControl") >>= xContentControl;
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ bool bPicture{};
+ xContentControlProps->getPropertyValue("Picture") >>= bPicture;
+ CPPUNIT_ASSERT(bPicture);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/TextEffectsHandler.cxx b/writerfilter/qa/cppunittests/dmapper/TextEffectsHandler.cxx
new file mode 100644
index 000000000..45a689b6b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/TextEffectsHandler.cxx
@@ -0,0 +1,74 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/dmapper/TextEffectsHandler.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testSemiTransparentText)
+{
+ // Load a document with a single paragraph: second text portion has semi-transparent text.
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "semi-transparent-text.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xPara(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortionEnum = xPara->createEnumeration();
+ xPortionEnum->nextElement();
+ uno::Reference<beans::XPropertySet> xPortion(xPortionEnum->nextElement(), uno::UNO_QUERY);
+ sal_Int16 nCharTransparence = 0;
+ xPortion->getPropertyValue("CharTransparence") >>= nCharTransparence;
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 74
+ // - Actual : 0
+ // i.e. text was imported as regular text with solid color only.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(74), nCharTransparence);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/data/1cell-insidev-rightborder.docx b/writerfilter/qa/cppunittests/dmapper/data/1cell-insidev-rightborder.docx
new file mode 100644
index 000000000..d0bc40e23
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/1cell-insidev-rightborder.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx b/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx
new file mode 100644
index 000000000..40d071ff4
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/alt-chunk.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/chart-zorder.docx b/writerfilter/qa/cppunittests/dmapper/data/chart-zorder.docx
new file mode 100644
index 000000000..e022a3bde
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/chart-zorder.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx b/writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx
new file mode 100644
index 000000000..453a4c2b8
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/clearing-break.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/create-date-preserve.docx b/writerfilter/qa/cppunittests/dmapper/data/create-date-preserve.docx
new file mode 100644
index 000000000..4a587ce0d
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/create-date-preserve.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docx b/writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docx
new file mode 100644
index 000000000..3eb5b0e2f
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/field-if-inside-if.docx b/writerfilter/qa/cppunittests/dmapper/data/field-if-inside-if.docx
new file mode 100644
index 000000000..65e238869
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/field-if-inside-if.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docx b/writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docx
new file mode 100644
index 000000000..3840b2550
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/follow-page-top-margin.docx b/writerfilter/qa/cppunittests/dmapper/data/follow-page-top-margin.docx
new file mode 100644
index 000000000..ceae0b784
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/follow-page-top-margin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/frame-direction.docx b/writerfilter/qa/cppunittests/dmapper/data/frame-direction.docx
new file mode 100644
index 000000000..33f191e80
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/frame-direction.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docx b/writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docx
new file mode 100644
index 000000000..c9fee726b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docx b/writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docx
new file mode 100644
index 000000000..93932c470
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docx b/writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docx
new file mode 100644
index 000000000..3792285f4
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docx b/writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docx
new file mode 100644
index 000000000..34f24a3e2
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-2.docx b/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-2.docx
new file mode 100644
index 000000000..5b6926460
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-2.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docx b/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docx
new file mode 100644
index 000000000..d88761421
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/layout-in-cell-wrapnone-column.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx
new file mode 100644
index 000000000..8bd464a9e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border-no-margin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx
new file mode 100644
index 000000000..878ba1e78
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/negative-page-border.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/nested-floating-table.docx b/writerfilter/qa/cppunittests/dmapper/data/nested-floating-table.docx
new file mode 100644
index 000000000..73fd922fc
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/nested-floating-table.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docx b/writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docx
new file mode 100644
index 000000000..f908d94b5
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docx b/writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docx
new file mode 100644
index 000000000..376a1fb1e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf b/writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf
new file mode 100644
index 000000000..27ce59baa
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/paste-ole.rtf
@@ -0,0 +1,30 @@
+{\rtf1
+\pard\plain\par
+\pard\plain
+{\object\objemb\objw1287\objh832\objscalex100\objscaley99
+{\*\objclass Package}
+{\*\objdata 0105000002000000080000005061636b616765000000000000000000eb010000
+020030322e73766700443a5c446e445c54657374646174656e5c416c6c654461746569547970656e5c30322e737667000000030036000000443a5c54454d505c7b42433241443335362d363732422d344345302d394136342d3033373544464134324334377d5c30322e73766700ab0000003c7376672076657273696f6e
+3d22312e31222076696577426f783d223020302034342032362220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f737667223e0a203c7265637420783d222e352220793d222e35222077696474683d22343322206865696768743d223235222072783d2232222072793d2232222066696c6c3d
+222366666622207374726f6b653d2223303037616666222f3e0a3c2f7376673e0a3500000044003a005c00540045004d0050005c007b00420043003200410044003300350036002d0036003700320042002d0034004300450030002d0039004100360034002d003000330037003500440046004100340032004300340037
+007d005c00300032002e0073007600670006000000300032002e007300760067002600000044003a005c0044006e0044005c00540065007300740064006100740065006e005c0041006c006c0065004400610074006500690054007900700065006e005c00300032002e007300760067000105000000000000}
+{\result
+{\*\shppict
+{\pict
+\picscalex100\picscaley99\picw2270\pich1468\picwgoal1287\pichgoal832\emfblip
+010000006c00000000000000000000009500000095000000000000000000
+0000670f0000630f000020454d4600000100280100000700000002000000
+00000000000000000000000038070000bd030000e9010000fd0000000000
+00000000000000000000f675070016dd0300210000000800000062000000
+0c0000000100000027000000180000000100000000000000ff0000000000
+000047000000700000000000000000000000950000009500000050000000
+010000002000000001000000030000003000000000000000000000009600
+000096000000320000000000000064000000320000000000000032000000
+960000006400000032000000640000006400000096000000220000000c00
+0000ffffffff0e00000014000000000000001000000014000000}
+}
+}
+}
+\pard\plain\par
+\pard\plain hello\par
+}
diff --git a/writerfilter/qa/cppunittests/dmapper/data/ptab.docx b/writerfilter/qa/cppunittests/dmapper/data/ptab.docx
new file mode 100644
index 000000000..d1ae18a27
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/ptab.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docx b/writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docx
new file mode 100644
index 000000000..1f7a281e8
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx
new file mode 100644
index 000000000..ed6d7ac54
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-dropdown-no-display-text.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-checkbox.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-checkbox.docx
new file mode 100644
index 000000000..c6718b97c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-checkbox.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-dropdown.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-dropdown.docx
new file mode 100644
index 000000000..7718c0b04
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-dropdown.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx
new file mode 100644
index 000000000..863bc9213
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-in-para.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx
new file mode 100644
index 000000000..25fcc7f6f
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-picture.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx
new file mode 100644
index 000000000..b945d0bb3
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docx b/writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docx
new file mode 100644
index 000000000..6c0f8a79c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docx b/writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docx
new file mode 100644
index 000000000..2031f4769
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/table-negative-vertical-pos.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf129205.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf129205.docx
new file mode 100644
index 000000000..4289254d0
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf129205.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf141540ChildRotation.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf141540ChildRotation.docx
new file mode 100644
index 000000000..902bb6192
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf141540ChildRotation.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupLinePosSize.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupLinePosSize.docx
new file mode 100644
index 000000000..d0ceff118
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupLinePosSize.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupRotation.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupRotation.docx
new file mode 100644
index 000000000..13e65c1d1
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf141540GroupRotation.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docx
new file mode 100644
index 000000000..681a6e3b7
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docx
new file mode 100644
index 000000000..9a0fc8a2b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docx
new file mode 100644
index 000000000..3adc2d91b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf143208_wrapTight.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf143208_wrapTight.docx
new file mode 100644
index 000000000..fab911ad9
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf143208_wrapTight.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf143455_SmartArtPosition.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf143455_SmartArtPosition.docx
new file mode 100644
index 000000000..1b1881b1e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf143455_SmartArtPosition.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/textbox-textline-top.docx b/writerfilter/qa/cppunittests/dmapper/data/textbox-textline-top.docx
new file mode 100644
index 000000000..dbd750092
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/textbox-textline-top.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/textbox-textline.docx b/writerfilter/qa/cppunittests/dmapper/data/textbox-textline.docx
new file mode 100644
index 000000000..493604d77
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/textbox-textline.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docx b/writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docx
new file mode 100644
index 000000000..1835a130d
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/README b/writerfilter/qa/cppunittests/filters-test/README
new file mode 100644
index 000000000..2cc9fb3cb
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/README
@@ -0,0 +1,7 @@
+Files with the string 'CVE' in their name are encrypted to avoid
+problems with virus checkers on source code download.; use:
+
+mdecrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to unencrypt
+mcrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to create new tests
+
+to get access to the plain files for manual testing.
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2005-2971-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2005-2971-1.rtf
new file mode 100644
index 000000000..5cd42052c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2005-2971-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2010-3451-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2010-3451-1.rtf
new file mode 100644
index 000000000..0c639810d
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2010-3451-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/EDB-18749-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/EDB-18749-1.rtf
new file mode 100644
index 000000000..18795f5be
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/EDB-18749-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/LIBREOFFICE-N4LA0OHZ.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/LIBREOFFICE-N4LA0OHZ.rtf
new file mode 100644
index 000000000..6257e1071
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/LIBREOFFICE-N4LA0OHZ.rtf
@@ -0,0 +1,403 @@
+{\rtf1\ânsi\ansicpg1252\deflang3081\ftnbj\uc1\deff0
+{\fonttbl{\f0 \fswiss \f charset0 Times New Roman;}{\f4 \fswiss 3\fcharset2 Symbol;}{\f5 \froman \fchraph Font;}{\cs2\f6\fs16\b\protect\cf1\cb3\chcbpat3\expnd0\expndtw0\charscalex100\dn0 SSBookmark;}{\s3\snext0\outlinelevel0\f0\fs32\b\cf1\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel0 Heading 1;}{\s4\snext0\outlinelevel1\f0\fs24\b\cf1\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel1 Heading 2;}{\s5\snext0\outlinelevel2\f0\fs24\b\cf1\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel2 Heading 3
+;}{\s6\snext0\outlinelevel3\f0\fs24\b\cf1\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel3 Heading 4;}{\s7\snext0\outlinelevel4\f0\fs24\b\i\cf1\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel4 Heading 5;}{\s8\snext0\outlinelevel5\f0\fs20\b\cf1\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel5 Heading 6;}{\s9\snext0\outlinelevel6\f0\fs24\cf4\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel6 Heading 7;}{\s10\snext0\outlinelevel7\f0\fs24\i\cf4\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel7 Heading 8
+;}{\s11\snext0\outlinelevel8\f0\fs22\cf4\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0\outlinelevel8 Heading 9;}{\s12\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 TOC 1;}{\s13\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li180\ri0\sb0\sa0\sl0\shading0 TOC 2;}{\s14\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li360\ri0\sb0\sa0\sl0\shading0 TOC 3;}{\s15\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li540\ri0\sb0\sa0\sl0\shading0 TOC 4;}{\s16\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li360\ri0\sb0\sa0\sl0\shading0 TOC 3;}{\s15\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li540\ri0\sb0\sa0\sl0\shading0 TOC 4;}{\s16\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li720\ri0\sb0\sa0\sl0\shading0 TOC 5
+;}{\s17\snext0\f0\fs24\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li900\ri0\sb0\sa0\sl0\shading0 TOC 6;}{\s18\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li1080\ri0\sb0\sa0\sl0\shading0 TOC 7;}{\s19\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li1260\ri0\sb0\sa0\sl0\shading0 TOC 8;}{\s20\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li1440\ri0\sb0\sa0\sl0\shading0 TOC 9;}{\s21\snext0\f0\fs32\b\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb240\sa60\sl0\shading0\qc Title;}{\s22\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi-360\li360\ri0\sb0\sa0\sl0\shading0 Numbered List
+;}{\s23\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi-360\li360\ri0\sb0\sa0\sl0\shading0 Bulleted List;}{\s24\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa120\sl0\shading0 Body Text;}{\s25\snext0\f0\fs18\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa120\sl0\sl480\slmult1\shading0 Body Text 2;}{\s26\snext0\f0\fs16\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa120\sl0\shading0 Body Text 3;}{\s27\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Note Heading;}{\s28\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Plain Text
+;}{\s29\snext0\f0\fs20\b\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li;}{\s29\snext0\f0\fs20\b\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li;}{\s29\snext0\f0\fs20\b\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Strong;}{\s30\snext0\f0\fs20\i\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Emphasis;}{\s31\snext0\f0\fs20\ul\cf5\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Hyperlink;}{\s32\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Footer;}{\s33\snext0\f0\fs20\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Header;}{\s34\snext0\f0\fs18\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 Code
+;}{\cs35\f0\fs20\i\cf4\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0 Field Label;}{\cs36\f0\fs22\b\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0 Table Heading;}{\cs37\f0\fs20\b\ul\cf0\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0 Object type;}{\s38\snext0\f0\fs20\b\i\cf6\cb2\chcbpat2\expnd0\expndtw0\charscalex100\dn0\fi0\li0\ri0\sb0\sa0\sl0\shading0 List Header;}{\s39\snext24\f0\fs20\i\cf5\fi0\li0\ri0\sb0\sa120\sl240 InfoBlue;}}
+{\*\revtbl{Unknown;}}
+{\*\listtable
+{\list\listtemplateid1
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'00.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List1;}\listid1
+}
+{\list\listtemplateid2
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List2;}\listid2
+}
+{\list\listtemplateid3
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f1\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List3;}\listid3
+}
+{\list\listtemplateid4
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f1\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List4;}\listid4
+}
+{\list\listtemplateid5
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f2\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List5;}\listid5
+}
+{\list\listtemplateid6
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f2\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List6;}\listid6
+}
+{\list\listtemplateid7
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'00.}{\levelnumbers \'01}\f3\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List7;}\listid7
+}
+{\list\listtemplateid8
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f2\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List8;}\listid8
+}
+{\list\listtemplateid9
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f2\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List9;}\listid9
+}
+{\list\listtemplateid10
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f2\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List10;}\listid10
+}
+{\list\listtemplateid11
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f2\fs24}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'01.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'02.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'03.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'04.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{-\leveltext \'02\'05.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'06.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'07.}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'08.}{\levelnumbers \'01}}
+{\listname List11;}\listid11
+}
+{\list\listtemplateid12
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01. \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List735674015_1;}\listid735674015
+}
+{\list\listtemplateid16
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List366130062_1;}\listid735674016
+}
+{\list\listtemplateid17
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List366148531_1;}\listid735674017
+}
+{\list\listtemplateid18
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List366155203_1;}\listid735674018
+}
+{\list\listtemplateid19
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname ;}\listid735674019
+}
+{\list\listtemplateid20
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'02\'00.}{\levelnumbers \'01}\b}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List434687953_1;}\listid735674020
+}
+{\list\listtemplateid21
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List435828312_1;}\listid735674021
+}
+{\list\listtemplateid22
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}ô {\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List435835406_1;}\listid735674022
+}
+{\list\listtemplateid23
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List435856328_1;}\listid735674023
+}
+{\list\listtemplateid24
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname ;}\listid735674024
+}
+{\list\listtemplateid25
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List437350656_1;}\listid735674025
+}
+{\list\listtemplateid26
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List437406078_1;}\listid735674026
+}
+{\list\listtemplateid27
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List36741109_1;}\listid735674027
+}
+{\list\listtemplateid28
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List-1965950843_1;}\listid735674030
+}
+{\list\listtemplateid31
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'01\'00}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00stlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'03\'00.\'01}{\levelnumbers \'01\'03}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'05\'00.\'01.\'02}{\levelnumbers \'01\'03\'05}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'07\'00.\'01.\'02.\'03}{\levelnumbers \'01\'03\'05\'07}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'09\'00.\'01.\'02.\'03.\'04}{\levelnumbers \'01\'03\'05\'07\'09}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'b\'00.\'01.\'02.\'03.\'04.\'05}{\levelnumbers \'01\'03\'05\'07\'09\'b}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'d\'00.\'01.\'02.\'03.\'04.\'05.\'06}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f}}
+{\listlevel\levelnfc0\levelfollow0\levelstartat1{\leveltext \'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08}{\levelnumbers \'01\'03\'05\'07\'09\'b\'d\'f\'11}}
+{\listname List-1965798031_1;}\listid735674031
+}
+}
+{\*\listoverridetable
+{\listoverride\listid735674026\listoverridecount9
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+{\lfolevel\listoverrideformat\listoverridestartat
+{\listlevel\levelnfc23\levelfollow0\levelstartat1{\leveltext \'01\'b7}{\levelnumbers}\f4\fcs1\f4\af4\fcs0\rtlch\f4\af4\ltrch}
+}
+\ls1}
+}
+\paperw11908\paperh16833\margl1440\margr1440\margt1440\margb1440\headery720\footery720\nogrowautofit\deftab720\formshade\fet4\aenddoc\aftnnrlc\pgbrdrhead\pgbrdrfoot
+\sectd\pgwsxn12240\pghsxn15840\titlepg\marglsxn1440\margrsxn1440\margtsxn1440\margbsxn1440\headery720\footery720\sbkpage\pgnstarts1\pgnrestart\pgndec
+\plain\plain\f0\fs20
+{\footer\pard\plain\f0\fs20\plain\f0\fs20\loch \par
+\plain\f0\fs20}
+{\header\pard\plain\f0\fs20\plain\f0\fs20\loch \par
+\plain\f0\fs20}
+{\headerf\pard\plain\f0\fs20\plain\f0\fs20\loch \par
+\plain\f0\fs20}
+\li108\qc\plain\f0\fs20\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\fs20\par
+\par
+\par
+\par
+\li0\ql\plain\f0\fs20{\*\bkmkstart BKM_33fd3768_22f8_4de1_91d2_533133defa34}{\*\bkmkend BKM_33fd3768_22f8_4de1_91d2_533133defa34}{\*\bkmkstart Test1}{\*\bkmkend Test1}{\*\bkmkstart BKM_AB2df357_B3ca_4a2b_86fb_B32f0a1ff7fe}{\*\bkmkend BKM_AB2df357_B3ca_4a2b_86fb_B32f0a1ff7fe}\plain\f3\fs20\lang4105\hich\f3\dbch\f3\loch\f3\cf1\fs20\par
+\trowd\trgaph60\trleft0\trrh288\trkeep
+\clvertalc\clbrdrt\brdrs\brdrw10\clbrdrb\brdrs\brdrw10\clshdng1000\cellx9360
+\pard\intbl\ssparaaux0\s0\ql\plain\f0\fs20\plain\f5\fs20\lang1033\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\loch Scenario\cell
+\plain\f5\fs20\lang1033\hich\f5\dbch\f5\loch\f5\cf1\fs20\intbl\row
+\trowd\trgaph60\trleft0\trrh676
+\clvertalt\clvmgf\cellx630
+\clvertalt\cellx9360
+\pard\intbl\ssparaaux0\s0\li360\ri90\sb40\qr\plain\f0\fs20\plain\f7\fs20\cell
+\pard\intbl\ssparaaux0\s0\sb40\ql\plain\f0\fs20\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\par
+\pard\intbl\itap2\ssparaaux0\s0\sb40\sa40\ql\plain\f0\fs20\plain\f5\fs20\lang3081\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\protect\loch Basic Path\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\loch \plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\loch (\plain\f5\fs20\lang3081\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\i\protect\loch Basic Path\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\loch )\nestcell{\nonesttables\par}
+\intbl\itap2
+{{\*\nesttableprops\trowd\trgaph60\trleft0
+\clvertalt\clbrdrt\brdrs\brdrw1\clbrdrb\brdrs\brdrw1\clshdng1000\clcbpat2\cellx8610
+\nestrow}{\nonesttables\par}}
+\trowd\trgaph60\trleft0\trrh676
+\clvertalt\clvmgf\cellx630
+\clvertalt\cellx9360
+\pard\intbl\ssparaaux0\s0\ql\plain\f0\fs20\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\par
+\cell
+\intbl\row
+\trowd\trgaph60\trleft0\trrh676
+\clvertalt\clvmrg\cellx630
+\clvertalt\clvmgf\cellx9360
+\pard\intbl\ssparaaux0\s0{\pntext\pard\plain\f4\fs20 \'b7\tab}{\*\pn\pnlvlblt\ls1\ilvl0\pnhang\pnf0{\pntxtb \'b7}}\ls1\ilvl0\fi-180\li360\sb40\qr\plain\f0\fs20\plain\f7\fs20\lang4105\hich\f7\dbch\f7\loch\f7\cf1\ulc1\fs20\cell
+\pard\intbl\itap2\ssparaaux0\s0{\pntext\pard\plain\f4\fs20 \'b7\tab}{\*\pn\pnlvlblt\ls1\ilvl0\pnhang\pnf0{\pntxtb \'b7}}\ls1\ilvl0\fi-180\li360\sb40\qr\plain\f0\fs20\plain\f7\fs20\lang4105\hich\f7\dbch\f7\loch\f7\cf1\ulc1\fs20\nestcell{\nonesttables\par}
+\pard\intbl\itap2\ssparaaux0\s0\ql\plain\f0\fs20{\*\bkmkstart Pkg_Element_ElemScenario_Scenario_Structured_Begin}{\*\bkmkend Pkg_Element_ElemScenario_Scenario_Structured_Begin}\plain\f6\fs16\cs2\lang4105\hich\f6\dbch\f6\loch\f6\cf1\highlight3\cb3\chcbpat3\ulc1\fs16\b\protect\loch structured scenarios {\*\bkmkstart Pkg_Element_ElemScenario_Scenario_Structured_Begin_Inner}{\*\bkmkend Pkg_Element_ElemScenario_Scenario_Structured_Begin_Inner}\loch >\plain\f7\fs20\lang4105\hich\f7\dbch\f7\loch\f7\cf1\ulc1\fs20\par
+\par
+\plain\f5\fs20\lang3081\hich\f5\dbch\f5\loch\f5\cf1\ulc1\fs20\b\protect\loch 1\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\ulc1\fs20\b\loch .\plain\f7\fs20\lang4105\hich\f7\dbch\f7\loch\f7\cf1\ulc1\fs20\loch \plain\f5\fs20\lang3081\hich\f5\dbch\f5\loch\f5\cf1\ulc1\fs20\protect\loch user enter data\plain\f7\fs20\lang4105\hich\f7\dbch\f7\loch\f7\cf1\ulc1\fs20\par
+\pard\intbl\itap2\ssparaaux0\s0\tx720\ql\plain\f0\fs20\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\i\par
+\pard\intbl\itap3\ssparaaux0\s0\tx720\ql\plain\f0\fs20\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\ul\i\loch Rules \loch Referenced:\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\i\nestcell{\nonesttables\par}
+\pard\intbl\itap3\ssparaaux0\s0\ql\plain\f0\fs20\plain\f5\fs20\lang4105\hich\f5\dbch\f5\loch\f5\cf1\fs20\b\i\nestcell{\nonesttables\par}
+\intbl\itap3
+{{\*\nesttableprops\trowd\trgaph60\trleft0
+\clvertalt\clvmgf\clcbpat2\cellx7910
+\nestrow}{\nonesttables\par}}
+\pard\intbl\itap-88\ssparaaux0\s0\tx720\ql\plain\f0\fs20\plain\f5\fs20\lang4•105\hich\f5\dbch\f5\dbch\f5\loch\frd\intbl\itap-88\ssparaaux0\s0\tx720\ql\plain\f0\fs20\plain\f5\fs20\lang4•105\hich\f5\dbch\f5\dbch\f5\loch\frd\intbl\itap-88\ssparaaux0\s0\tx720\ql\plain\f0\fs20\plain\f5\fs20\lang4•105\hich\f5\dbch\f5\dbch\f5\loch\f5\cf1\fs20\cell
+\intbl\row
+\pard\ssparaaux0\s0\ql\plain\f0\fs20\plain\f3\fs20\lang3081\hich\f3\dbch\f3\loch\f3\cf1\fs20\par
+\plain\f7\fs20\lang4105\hich\f7\dbch\f7\loch\f7\cf1\ulc1 \ No newline at end of file
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtf
new file mode 100644
index 000000000..63465b073
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtf
new file mode 100644
index 000000000..f0152b0fa
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtf
new file mode 100644
index 000000000..59c3630a7
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtf
new file mode 100644
index 000000000..041891713
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-2.rtf
new file mode 100644
index 000000000..273bb135c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-2.rtf
@@ -0,0 +1 @@
+\\rttt\noTidqtpúúúúúúëúúúúúúúúúúúúúúúúdôp{\"pb18}\€p{\"ptxtbr }
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/propheight-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/propheight-1.rtf
new file mode 100644
index 000000000..130ff3f23
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/propheight-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/sf_edeb1eb341ad4c8608af9396952724a0-128299-minimized.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/sf_edeb1eb341ad4c8608af9396952724a0-128299-minimized.rtf
new file mode 100644
index 000000000..45597c085
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/sf_edeb1eb341ad4c8608af9396952724a0-128299-minimized.rtf
@@ -0,0 +1,57 @@
+{\rtf1\ansi\ansicpg1252\deff0
+{\fonttbl
+{\f0\fnil\fcharset0\fprq0\fttruetype Times New Roman;}
+{\f1\fnil\fcharset0\fprq0\fttruetype Nimbus Sans L;}
+{\f2\fnil\fcharset0\fprq0\fttruetype Dingbats;}
+{\f3\fnil\fcharset0\fprq0\fttruetype Symbol;}
+{\f4\fnil\fcharset0\fprq0\fttruetype Courier New;}}
+{\colortbl
+\red0\green0\blue0;
+\red255\green255\blue255;}
+{\stylesheet
+{\s1\fi-431\li720\sbasedon28\snext28 Contents 1;}
+{\s2\fi-431\li1440\sbasedon28\snext28 Contents 2;}
+{\s3\fi-431\li2160\sbasedon28\snext28 Contents 3;}
+{\s8\fi-431\li720\sbasedon28 Lower Roman List;}
+{\s5\tx431\sbasedon24\snext28 Numbered Heading 1;}
+{\s6\tx431\sbasedon25\snext28 Numbered Heading 2;}
+{\s7\fi-431\li720 Square List;}
+{\*\cs11\sbasedon28 Endnote Text;}
+{\s4\fi-431\li2880\sbasedon28\snext28 Contents 4;}
+{\s9\fi-431\li720 Diamond List;}
+{\s10\fi-431\li720 Numbered List;}
+{\*\cs12\fs20\super Endnote Reference;}
+{\s13\fi-431\li720 Triangle List;}
+{\s14\tx431\sbasedon26\snext28 Numbered Heading 3;}
+{\s15\fi-431\li720 Dashed List;}
+{\s16\fi-431\li720\sbasedon10 Upper Roman List;}
+{\s17\sb440\sa60\f1\fs24\b\sbasedon28\snext28 Heading 4;}
+{\s18\fi-431\li720 Heart List;}
+{\s34\fi-431\li720 Box List;}
+{\s20\fi-431\li720\sbasedon10 Upper Case List;}
+{\s21\fi-431\li720 Bullet List;}
+{\s22\fi-431\li720 Hand List;}
+{\*\cs23\fs20\sbasedon28 Footnote Text;}
+{\s24\sb440\sa60\f1\fs34\b\sbasedon28\snext28 Heading 1;}
+{\s25\sb440\sa60\f1\fs28\b\sbasedon28\snext28 Heading 2;}
+{\s19\qc\sb240\sa120\f1\fs32\b\sbasedon28\snext28 Contents Header;}
+{\s27\fi-431\li720 Tick List;}
+{\s26\sb440\sa60\f1\fs24\b\sbasedon28\snext28 Heading 3;}
+{\s29\fi-431\li720\sbasedon10 Lower Case List;}
+{\s30\li1440\ri1440\sa120\sbasedon28 Block Text;}
+{\s36\f4\sbasedon28 Plain Text;}
+{\s32\tx1584\sbasedon5\snext28 Section Heading;}
+{\s33\fi-431\li720 Implies List;}
+{\s28\f0\fs24\lang1033 Normal;}
+{\s35\fi-431\li720 Star List;}
+{\*\cs31\fs20\super Footnote Reference;}
+{\s37\tx1584\sbasedon5\snext28 Chapter Heading;}}
+{\*\listtable
+{\list\listtemplateid1002\listsimple{\listlevel\levelnfc0\levelstartat1\levelspAce0\levelfollow0\fi-431\li720{\leveltext\'02\'00.{}{\levelnumbers\'01;}}\listid1000}}
+{\*\listoverridetable
+{\listoverride\listoverridecount0\listid1000\levelnfc0\levelstartat1\levelspace0\levelfollow0\fi-431\li720{\leveltext\'02\'00.;}{\levelnumbers\'01;}\ls1}}
+
+\kerning0\cf0\ftnbj\fet2\ftnstart1\ftnnar\aftnnar\ftnstart1\aftnstart1\aenddoc\facingp\titlepg\revprop3{\info}\deftab720\viewkind1\paperw12240\paperh15840\margl1440\margr1440\widowctl
+\sectd\sbknone\colsx360\pgncont\ltrsect
+{\listtext\pard\fi-431\li720 1. }\pard\plain{\ltrpar\ql\fi-431\li720\s28{\*\abilist\abilistid1000\abilistparentid0\abilistlevel1\abistartat1{\abifieldfont NULL}{\abilistdecimal .}{\abilistdelim %L.}{\abiliststyle Numbered List}}{\*\pn\pnql\pnstart1\pnlvlbody\pndec{\pntxtb AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA}{\pntxta .}}\fn-431\li720\ls1\ilvl0\itap0{\s28\f0\fs24\lang1033{\*\listtag0}\abinodiroverride\ltrch test}{\s28\f0\fs24\lang1033{\*\listtag1001}\par}
+}\pard\plain\ltrpar\ql\s28\itap0{\s28\f0\fs24\lang1033{\*\listtag0}\par}}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-5.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-5.rtf
new file mode 100644
index 000000000..a03be130d
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-5.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtf
new file mode 100644
index 000000000..67a0ea175
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtf
new file mode 100644
index 000000000..df41b1f88
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtf
new file mode 100644
index 000000000..7cdb94ab2
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtf
new file mode 100644
index 000000000..c0bd2691c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-3.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-3.rtf
new file mode 100644
index 000000000..112162397
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-3.rtf
@@ -0,0 +1,28 @@
+{\ul\001ll\fJ
+ {Ystylesheet;{;}}
+{bbbbbbbbbbbbbbbbb{O\00\80\00\tc\DD\00\FFDD\BED@DDD\F7bTr\00\00*i\\FF\FB\FB\FB\FB\FB\FB\FB\FB\FB\FB\FB\FB\FB\FB\FB\FF\
+\\\BD\EB||){Tb\FD\00\00\00p\FFA\00\00\00r \00\00\00\BB
+\88\83AA4A\FC\E5C\E5\F5\E5\E5\FF\80\E5\E5\E5\D3O<BZ\
+\D\00
+\EA\00\00\00\FFbT\9B\85\00{rbNNNNNNNNNNNNNNNNN\E5\E5\E5\E5\E5\E5\E5\E5\E5IA\00\FFiH\\
+\T\\ \E7\00\ED(\\92\DEs\\F0 \82\AA\AA =\00V  n\E7\00\ect\00\00\00\B1\B1\B1w^w\AAuu\00\00
+\d\00\00\00\00\00\00\FFbTUUQVUߘ\98U\00DF\F6\F63#\99\00\00\98\AC\98\98\00\00 x\95es\E4\B7\D3\\00\80w\80\FF\00\AAd\FF\00*\00è‹\8B\8BM`I\00 \00\80\v\U\i\F8\F8\AB\98\D8\\91\sect\\F0\F0\F0\F0\F0\F0\F0ec\F0\F0\F0 \8B\00\8B\8B\8BOOOMII\C2\C2\EC\FEw{O\00\80\00d<tR}\\iL@\A4u{\E8A\00剉\89\89\89\89\89\89\{O\86]UvII<OOOOOOOOOOMI:\C2\C2\00\00\00\00\EC\F1w{O\00\80\00d\t\B5}\\iL\\00\89k \FF\DF\DF\DF\DF\DD\DF\DF\DF\DF\00 \8EiE \E5\q\FA{P\00zri\A2\00\DD\00\AAe{\00\C0DDDD\8FDD\BED\00\E8\f\\i\\FF\E9\FF\9Bc\F1[\8\00\EB{\98
+\DFh\FF\\00\\\BD\E1||||Z|||||\A1\FD\98\98\98\98\98\98\8F\90\98\98\D8\tc}ww\00\tc}\\i\FE\\00/k շ\D3\\FF\FF}wX\EB\tc}\\iL\\9F\00/k \F6\FF\FE\FFE\FF\FF\FE\E8KK\00\00\00 \00\E6ii{ۜ\80\85
+\80\q\FA\00\00\FA\F8\E5 ÞŽ|^
+\E5\E5\E5\E5C\E5\E5\E5\E5\FF\80\E5\E5\E5\D3\E5
+BZ\
+\t\00
+\E5\FF\FFi\00
+\ \FA>\006\FA\00\00\EB\F8\E5 \00\00\\98\00xtesÕ·\D3^t000c\00\00\00\00ppu\00\00\00\00\00\E5\D1\E5\80\00\00\00\FA\F8\E5'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb{O\00\80\00\tc\A5\\iL\\00\E5\F2\E5\E5\E5\80\E8\E5\E5\E5\FF\FFbTUEQU\00\00\00\00\80\00\00\AD\E5\E5\E5\E5C\00\00\00\E5\E5\E5\E5\E5\E5I \00\{P\FFig\\
+{O\00\80\00d<tR\T\ect\00\00\ .AK\EF
+\F\80\FF
+\\\E5\FF\FF\i"\00\FFw\F4\F2\D9\00\89\89\89s\89\89k\89\8AigQ\hhhhhhhA\\00Ad\00\FFiI \00iI d\00\00\009\FFH\E2\F8\006\FA\00\00 \00NNNNNNNNNNNNNNNNNNNNN\00\B6\FA\E5[\
+\Z\
+6\006\D3\00\80\E5\FF\ig\FB~\9Fo
+^
+\E5\E5\E4\E5C\E5\E5\E5\E5\E5\E5\E5\E5\E5\E5IA\00\FFiH\\
+\T\\ EAd\00\FF\iI \00\E8\00\\\
+\R\xKKKKKKKKKKKKKKKKKKKKKKKKK\FF\\\F8\FF\FA\00\82\00\00\00rd\00\00ppp\FF\i\\FF\FF\A0\00\00\00%C
+\FF\FF\00}g ~\80\00\80xxxxxxxxxxig\\
+\\%\E5\E5\E5\E5\E5\E5\E5\C6\E5\E5tes\E4\B7\D3\\00\80}\E5\E5,TgU\\00~
+\\006\00
diff --git a/writerfilter/qa/cppunittests/filters-test/data/indeterminate/.gitignore b/writerfilter/qa/cppunittests/filters-test/data/indeterminate/.gitignore
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/indeterminate/.gitignore
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2964-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2964-1.rtf
new file mode 100644
index 000000000..da97fba57
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2964-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-1.rtf
new file mode 100644
index 000000000..70321707f
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-2.rtf
new file mode 100644
index 000000000..c5ea695bc
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-2.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2007-0245-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2007-0245-1.rtf
new file mode 100644
index 000000000..757cfe62e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2007-0245-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3333-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3333-1.rtf
new file mode 100644
index 000000000..4dac58c0c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3333-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3452-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3452-1.rtf
new file mode 100644
index 000000000..da5d0f39b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3452-1.rtf
@@ -0,0 +1 @@
+2  ØHv$Èsù£Á …A«óu4”j \ No newline at end of file
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-1.rtf
new file mode 100644
index 000000000..44d28adcb
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-2.rtf
new file mode 100644
index 000000000..64109fbe2
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-2.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-pseudo-2009-0238-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-pseudo-2009-0238-1.rtf
new file mode 100644
index 000000000..44ed96982
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-pseudo-2009-0238-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18754-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18754-1.rtf
new file mode 100644
index 000000000..f4a736920
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18754-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18940-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18940-1.rtf
new file mode 100644
index 000000000..794f325c5
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18940-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/TCI-TN65GP-DDRHDLL-partial.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/TCI-TN65GP-DDRHDLL-partial.rtf
new file mode 100644
index 000000000..7cdb1e15c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/TCI-TN65GP-DDRHDLL-partial.rtf
@@ -0,0 +1,1719 @@
+{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff1\deff1\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f4\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Helvetica;}
+{\f10\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}{\f46\froman\fcharset2\fprq2{\*\panose 05030102010509060703}Webdings;}{\f273\froman\fcharset238\fprq2 Times New Roman CE;}{\f274\froman\fcharset204\fprq2 Times New Roman Cyr;}
+{\f276\froman\fcharset161\fprq2 Times New Roman Greek;}{\f277\froman\fcharset162\fprq2 Times New Roman Tur;}{\f278\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f279\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
+{\f280\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f281\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f283\fswiss\fcharset238\fprq2 Arial CE;}{\f284\fswiss\fcharset204\fprq2 Arial Cyr;}{\f286\fswiss\fcharset161\fprq2 Arial Greek;}
+{\f287\fswiss\fcharset162\fprq2 Arial Tur;}{\f288\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f289\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}{\f290\fswiss\fcharset186\fprq2 Arial Baltic;}{\f291\fswiss\fcharset163\fprq2 Arial (Vietnamese);}
+{\f293\fmodern\fcharset238\fprq1 Courier New CE;}{\f294\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f296\fmodern\fcharset161\fprq1 Courier New Greek;}{\f297\fmodern\fcharset162\fprq1 Courier New Tur;}
+{\f298\fbidi \fmodern\fcharset177\fprq1 Courier New (Hebrew);}{\f299\fbidi \fmodern\fcharset178\fprq1 Courier New (Arabic);}{\f300\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f301\fmodern\fcharset163\fprq1 Courier New (Vietnamese);}
+{\f313\fswiss\fcharset238\fprq2 Helvetica CE;}{\f314\fswiss\fcharset204\fprq2 Helvetica Cyr;}{\f316\fswiss\fcharset161\fprq2 Helvetica Greek;}{\f317\fswiss\fcharset162\fprq2 Helvetica Tur;}{\f318\fbidi \fswiss\fcharset177\fprq2 Helvetica (Hebrew);}
+{\f319\fbidi \fswiss\fcharset178\fprq2 Helvetica (Arabic);}{\f320\fswiss\fcharset186\fprq2 Helvetica Baltic;}{\f321\fswiss\fcharset163\fprq2 Helvetica (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;
+\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;
+\red128\green128\blue128;\red192\green192\blue192;\red255\green153\blue0;}{\stylesheet{\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch
+\f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 \sautoupd Normal;}{\s1\qr \li0\ri0\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 \rtlch \ab\af1\afs28\alang1025 \ltrch
+\b\caps\f1\fs28\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 1,Title Data;}{\s2\qr \li0\ri0\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch
+\f1\fs16\cf8\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 2;}{\s3\qr \li0\ri0\sb240\sa60\keepn\widctlpar\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin0\itap0 \rtlch \ab\af4\afs26\alang1025 \ltrch
+\b\f4\fs26\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\*
+\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv
+\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af0\afs20 \ltrch \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}{
+\s15\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs20\alang1025 \ltrch \f1\fs20\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \snext0 Body Spec;}{\*\cs16 \additive \rtlch \ab\af0\afs22 \ltrch
+\b\scaps\fs22\expnd3\expndtw18\lang1024\langfe1024\noproof \sbasedon10 Header Spec;}{\s17\ql \fi-72\li72\ri0\sb240\widctlpar\tx72\aspalpha\aspnum\faauto\adjustright\rin0\lin72\itap0 \rtlch \af1\afs13\alang1025 \ltrch
+\f1\fs13\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \snext17 \sautoupd mouse print;}{\s18\ql \li29\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin29\itap0 \rtlch \ab\af1\afs26\alang1025 \ltrch
+\b\scaps\f1\fs26\expnd4\expndtw24\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \snext18 Datasheet Title;}{\s19\ql \li0\ri0\sl-210\slmult0\widctlpar\tx180\tx3780\tx4050\tx9180\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch
+\af1\afs16\alang1025 \ltrch \f1\fs16\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \snext19 \sautoupd Bullet Spec;}{\s20\qr \li0\ri0\widctlpar\tqc\tx4320\tqr\tx8640\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch
+\af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext20 header;}{\s21\ql \li50\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin50\itap0 \rtlch \ab\af1\afs22\alang1025 \ltrch
+\b\scaps\f1\fs22\expnd3\expndtw17\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \snext21 \sautoupd Sub Header;}{\s22\ql \fi-216\li216\ri0\widctlpar\tqr\tx216\aspalpha\aspnum\faauto\ls38\adjustright\rin0\lin216\itap0 \rtlch
+\af1\afs19\alang1025 \ltrch \f1\fs19\cf17\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \snext22 \sautoupd copper bullet text;}{\s23\ql \fi-216\li216\ri0\widctlpar\tqr\tx216\aspalpha\aspnum\faauto\ls39\adjustright\rin0\lin216\itap0 \rtlch
+\af1\afs19\alang1025 \ltrch \f1\fs19\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \sbasedon22 \snext23 white bullet black text;}{\s24\ql \li0\ri0\sb40\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch
+\af1\afs17\alang1025 \ltrch \f1\fs17\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 \sbasedon0 \snext24 Part No.;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\listtable
+{\list\listtemplateid-1695512888{\listlevel\levelnfc23\levelnfcn23
+\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-4044 ?;}{\levelnumbers;}\b0\i0\strike0\outl0\shad0\embo0\impr0\caps0\v0\f46\fs18\ulnone\cf17\nosupersub\striked0\fbias0 \s22\fi-216\li216\jclisttab\tx360\lin216 }
+{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0
+\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0
+{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\loch\af3\hich\af3\dbch\af0\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers
+;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }
+{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\loch\af3\hich\af3\dbch\af0\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23
+\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1
+\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid265384847}
+{\list\listtemplateid422860360{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0
+\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-4044 ?;}{\levelnumbers;}\b0\i0\strike0\outl0\shad0\embo0\impr0\caps0\v0\f46\fs18\ulnone\cf8\nosupersub\striked0\fbias0 \s23\fi-216\li216\jclisttab\tx360\lin216 }{\listlevel\levelnfc23\levelnfcn23
+\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0
+\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li2160\jclisttab\tx2160\lin2160 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}
+\loch\af3\hich\af3\dbch\af0\fbias0 \fi-360\li2880\jclisttab\tx2880\lin2880 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600
+\jclisttab\tx3600\lin3600 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li4320\jclisttab\tx4320\lin4320 }{\listlevel\levelnfc23
+\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\loch\af3\hich\af3\dbch\af0\fbias0 \fi-360\li5040\jclisttab\tx5040\lin5040 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0
+\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760\lin5760 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext
+\'01\u-3929 ?;}{\levelnumbers;}\f10\fbias0 \fi-360\li6480\jclisttab\tx6480\lin6480 }{\listname ;}\listid678429498}
+}{\*\listoverridetable{\listoverride\listid1665083218\listoverridecount0\ls1}{\listoverride\listid1904289489\listoverridecount0\ls2}
+{\listoverride\listid1272055411\listoverridecount0\ls3}{\listoverride\listid1786775403\listoverridecount0\ls4}{\listoverride\listid95443872\listoverridecount0\ls5}{\listoverride\listid610892914\listoverridecount0\ls6}{\listoverride\listid1358891263
+\listoverridecount0\ls7}{\listoverride\listid406534060\listoverridecount0\ls8}{\listoverride\listid1411807819\listoverridecount0\ls9}{\listoverride\listid1946690268\listoverridecount0\ls10}{\listoverride\listid1825658399\listoverridecount0\ls11}
+{\listoverride\listid646323806\listoverridecount0\ls12}{\listoverride\listid1445687661\listoverridecount0\ls13}{\listoverride\listid379482012\listoverridecount0\ls14}{\listoverride\listid1058817243\listoverridecount0\ls15}{\listoverride\listid1246576990
+\listoverridecount0\ls16}{\listoverride\listid1776748315\listoverridecount0\ls17}{\listoverride\listid778525720\listoverridecount0\ls18}{\listoverride\listid1312296586\listoverridecount0\ls19}{\listoverride\listid1358582950\listoverridecount0\ls20}
+{\listoverride\listid455831286\listoverridecount0\ls21}{\listoverride\listid673074249\listoverridecount0\ls22}{\listoverride\listid2094740677\listoverridecount0\ls23}{\listoverride\listid-129\listoverridecount0\ls24}{\listoverride\listid275143120
+\listoverridecount0\ls25}{\listoverride\listid1245842577\listoverridecount0\ls26}{\listoverride\listid804469837\listoverridecount0\ls27}{\listoverride\listid568426430\listoverridecount0\ls28}{\listoverride\listid942303892\listoverridecount0\ls29}
+{\listoverride\listid1117597776\listoverridecount0\ls30}{\listoverride\listid1117597776\listoverridecount0\ls31}{\listoverride\listid1117597776\listoverridecount0\ls32}{\listoverride\listid1117597776\listoverridecount0\ls33}{\listoverride\listid1995066837
+\listoverridecount0\ls34}{\listoverride\listid529074992\listoverridecount0\ls35}{\listoverride\listid524364841\listoverridecount0\ls36}{\listoverride\listid1529562644\listoverridecount0\ls37}{\listoverride\listid265384847\listoverridecount0\ls38}
+{\listoverride\listid678429498\listoverridecount0\ls39}}{\*\rsidtbl \rsid7564464\rsid8398352\rsid9049968}{\*\generator Microsoft Word 11.0.5604;}\margl0\margr0\margt0\margb0\ltrsect
+\deftab14\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin0\dgvorigin0\dghshow0\dgvshow0
+\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\rsidroot9049968 \fet0\ltrpar \sectd \ltrsect
+\linex0\headery0\footery0\sectdefaultcl\sectrsid7564464\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}
+{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang
+{\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar
+\s20\qr \li0\ri0\sb240\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \lang1024\langfe1024\noproof\insrsid7564464
+{\shp{\*\shpinst\shpleft1281\shptop9231\shpright4476\shpbottom11909\shpfhdr0\shpbxcolumn\shpbxignore\shpbypara\shpbyignore\shpwr3\shpwrk0\shpfblwtxt0\shpz5\shplid1027{\sp{\sn shapeType}{\sv 202}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lTxid}{\sv 131072}}{\sp{\sn dxTextLeft}{\sv 64008}}{\sp{\sn dyTextTop}{\sv 0}}{\sp{\sn dxTextRight}{\sv 137160}}{\sp{\sn dyTextBottom}{\sv 0}}{\sp{\sn hspNext}{\sv 1027}}
+{\sp{\sn fFitShapeToText}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn lidRegroup}{\sv 1}}{\sp{\sn posrelh}{\sv 0}}{\sp{\sn posrelv}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}{\shptxt \ltrpar
+\pard\plain \ltrpar\s21\ql \li50\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin50\itap0 \rtlch \ab\af1\afs22\alang1025 \ltrch \b\scaps\f1\fs22\expnd3\expndtw17\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch
+\cf8\insrsid7564464 Deliverables
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s23 \rtlch \af46\afs18 \ltrch \f46\fs18\cf8\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard\plain \ltrpar\s23\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls39\adjustright\rin0\lin216\itap0 \rtlch \af1\afs19\alang1025 \ltrch \f1\fs19\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 GDSII and LVS Spice netlist, behavioral, synthesis, and \line LEF models, and extensive user documentation.
+\par }\pard \ltrpar\s23\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s23 \rtlch \af46\afs18 \ltrch \f46\fs18\cf8\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard \ltrpar\s23\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls39\adjustright\rin0\lin216\itap0 {\rtlch \af1 \ltrch \insrsid7564464 Integration support to ensure \line a successful tape out (included \line in standard design license fee).
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par
+\par }}}}
+{\shp{\*\shpinst\shpleft1282\shptop2362\shpright10462\shpbottom2765\shpfhdr0\shpbxcolumn\shpbxignore\shpbypara\shpbyignore\shpwr3\shpwrk0\shpfblwtxt0\shpz4\shplid1028{\sp{\sn shapeType}{\sv 202}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lTxid}{\sv 196608}}{\sp{\sn dxTextLeft}{\sv 45720}}{\sp{\sn dyTextTop}{\sv 0}}{\sp{\sn dxTextRight}{\sv 0}}{\sp{\sn dyTextBottom}{\sv 0}}{\sp{\sn hspNext}{\sv 1028}}{\sp{\sn fFitShapeToText}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}
+{\sp{\sn lidRegroup}{\sv 1}}{\sp{\sn posrelh}{\sv 0}}{\sp{\sn posrelv}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}{\shptxt \ltrpar \pard\plain \ltrpar
+\s18\ql \li29\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin29\itap0 \rtlch \ab\af1\afs26\alang1025 \ltrch \b\scaps\f1\fs26\expnd4\expndtw24\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+DDR DLL
+\par }}}}
+{\shp{\*\shpinst\shpleft5674\shptop12370\shpright11068\shpbottom14170\shpfhdr0\shpbxcolumn\shpbxignore\shpbypara\shpbyignore\shpwr3\shpwrk0\shpfblwtxt0\shpz3\shplid1029{\sp{\sn shapeType}{\sv 202}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lTxid}{\sv 196608}}{\sp{\sn hspNext}{\sv 1029}}{\sp{\sn fFitShapeToText}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn lidRegroup}{\sv 4}}{\sp{\sn fLayoutInCell}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 0}}{\shptxt \ltrpar
+\pard\plain \ltrpar\qc \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\pard\plain \ltrpar
+\qc \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1\afs24 \ltrch \fs24\insrsid5645506 {\pict\wmetafile8\picw8995\pich2892
+\picwgoal5105\pichgoal1655
+0100090000034612000004006e0000000000050000000b0200000000050000000c024c01fe030500000004010d000000050000002e01180000000500000002010100000005000000090200000000050000000102ffffff00030000001e0008000000fa02060004000000daa12900040000002d010000050000001402400038
+03050000001302400029010500000014024000db010500000013026f00db0107000000fc020000daa129000000040000002d01010008000000fa0205000100000000000000040000002d01020004000000f00100000c00000024030400cf016a00db017e00e6016a00cf016a0008000000fa02060004000000daa129000400
+00002d010000050000001402400038030500000013026f003803040000002d01020004000000f00100000c000000240304002c036a0038037e0044036a002c036a0008000000fa0206000200000000000000040000002d0100000500000014024801fa03050000001302480103000500000014024801030005000000130203
+000300050000001402030003000500000013020300fa030500000014020300fa030500000013024801fa03050000001402a5002601050000001302a5009a00050000001402a5009a0005000000130221009a0005000000140221009a000500000013022100260105000000140221002601050000001302a500260107000000
+fc020000000000000000040000002d01030004000000f0010100040000002d01020004000000f00100006600000024033100c1004a00c1004a00bd004900b9004800bb004400bb004400be004500c1004600c1004600c3004500c4004400c4004400c3004300c2004200bf004200bf004200bd004100bc004000bb003e00ba
+003c00ba003c00bb003900bd003700bf003600c2003500c2003500c6003600c9003700c7003b00c7003b00c5003a00c2003900c2003900c1003a00c0003b00c0003b00c1003c00c2003d00c4003d00c4003d00c8003f00c9004000ca004300ca004300c9004600c7004800c4004900c1004a00c1004a003000000024031600
+d2004a00d2004a00d0004a00ce004900ce004700ce004500ce003b00ce003b00ce003500d3003400d3003400d3003800d3004300d3004300d3004600d4004700d4004700d5004600d5004a00d5004a00d2004a00d2004a006e00000024033500e1004900e1004900df004a00dd004a00dd004a00db004a00d9004900d80047
+00d8004500d8004500d8004300da004200dc004100df004000df004000df004000df003f00df003f00df003e00de003e00de003e00dc003e00da004000d8003d00d8003d00db003b00df003a00df003a00e2003b00e4003d00e4003d00e4003f00e4004500e4004500e5004600e5004700e3004a00e3004a00e1004900e100
+4900e1004900dd004500dd004500dd004600de004700de004700df004600df004300df004300dd004400dd004500dd004500e10049001e00000024030d00f1004a00ed004a00e7003b00ec003b00ee003f00ee003f00ef004300ef004300ef004300f0003f00f1003b00f6003b00f1004a005800000024032a00ff004600ff
+0046000101460003014500050148000501480002014a00ff004a00ff004a00fc004900fa004800f8004600f8004200f8004200f8003f00f9003d00fc003b00fe003a00fe003a0001013b0004013d0005013f00050143000501430005014400fd004400fd004400fd004500fe004600ff004600ff004600ff004600ff003e00
+ff003e00fd003e00fd004100000141000001410000013f00ff003e00ff003e00ff0046005400000024032800b6006d00b6006d00b2006d00af006b00af006b00ad006700ad006300ad006300ad006000ae005d00ae005d00b0005b00b2005a00b4005900b6005900b6005900b9005900bb005a00b9005e00b9005e00b6005d
+00b6005d00b4005e00b4005e00b3005f00b3006200b3006200b3006600b4006800b4006800b5006900b6006900b6006900b8006900ba006800bc006b00bc006b00b9006d00b6006d00b6006d005400000024032800cc006500cc006500cb006900ca006b00c7006d00c5006d00c5006d00c2006d00c0006b00be006900be00
+6600be006600be006200c0006000c2005e00c5005e00c5005e00c8005e00ca006000cb006200cc006500cc006500cc006500c3006600c3006600c4006900c4006a00c5006a00c5006a00c6006a00c6006900c7006500c7006500c6006200c5006100c5006100c4006200c3006600c3006600cc0065003400000024031800d8
+006d00d8006400d8006400d7006200d7006200d7006200d5006300d5006d00d0006d00d0006400d0006400cf005f00d4005e00d4005e00d4005f00d4005f00d6005e00d9005e00d9005e00db005e00dc005f00dd006200dd006d00d8006d003a00000024031b00e7005e00ea005e00e9006100e7006100e7006700e7006700
+e7006900e9006a00e9006a00ea006a00ea006d00ea006d00e7006d00e7006d00e3006d00e2006c00e2006a00e2006100e1006100e1005e00e2005e00e2005e00e2005a00e7005a00e7005a00e7005e00e7005e002c00000024031400f7006200f7006200f5006200f5006200f4006200f3006300f3006d00ee006d00ee0064
+00ee006400ee005f00f2005e00f2005e00f3006000f3006000f4005e00f6005e00f6005e00f8005e00f7006200540000002403280007016500070165000601690005016b0003016d0000016d0000016d00fd006d00fb006b00fa006900f9006600f9006600fa006200fb006000fd005e0000015e0000015e0003015e000501
+600007016200070165000701650007016500ff006600ff006600ff006900ff006a0000016a0000016a0001016a00010169000201650002016500010162000001610000016100ff006200ff006600ff0066000701650030000000240316000f016d000f016d000d016d000c016c000b016a000b0168000b015e000b015e000b
+015900100158001001580010015c0010016700100167001001690011016a0011016a0012016a0013016d0013016d000f016d000f016d001200000024030700cc009000c1009000c1007c00c6007c00c6008c00cd008c00cc0090005400000024032800dd008900dd008900dc008c00db008f00d9009000d6009100d6009100
+d3009000d1008f00d0008c00cf008900cf008900d0008600d1008300d3008200d6008100d6008100d9008200db008300dc008500dd008900dd008900dd008900d4008900d4008900d5008c00d5008d00d6008d00d6008d00d7008d00d7008c00d8008800d8008800d7008500d6008500d6008500d5008500d4008900d40089
+00dd0089005400000024032800ee008900ee008900ed008c00ec008f00e9009000e7009100e7009100e4009000e2008f00e0008c00e0008900e0008900e0008600e2008300e4008200e7008100e7008100ea008200ec008300ed008500ee008900ee008900ee008900e5008900e5008900e6008c00e6008d00e7008d00e700
+8d00e8008d00e8008c00e8008800e8008800e8008500e7008500e7008500e6008500e5008900e5008900ee0089005800000024032a00f9008100f9008100fd008200fe008400ff008600ff008800ff008800ff008c00fe008f00fc009000f9009100f9009100f7009000f7009000f7009300f7009600f2009700f2008700f2
+008700f1008200f6008100f6008100f6008300f6008300f7008200f9008100f9008100f9008100f7008600f7008c00f7008c00f8008d00f8008d00f9008c00fa008900fa008900fa008600f8008500f8008500f7008600f7008600f900810008000000fa0206000200000000000000040000002d0100000500000014026400
+6c0005000000130264008900040000002d01020004000000f00100000c0000002403040087006f009a0064008700590087006f004c0000002403240026006e002400680024006800230066002200650022006e001c006e001c0058002400580024005800280059002a005a002c005c002c005e002c005e002c0061002b0063
+002900640027006400270064002a0067002a0067002d006e0026006e0026006e0022005d002200610023006100230061002500610026005f0026005f0025005d0023005d0022005d0026006e00540000002403280039006e0039006e0036006d0032006b0032006b003000680030006300300063003000600031005d003100
+5d0033005b0035005900370058003a0058003a0058003d005800400059003d005d003d005d003a005c003a005c0038005d0038005d0036005f003600620036006200360066003700680037006800380069003a006a003a006a003c0069003e00680040006c0040006c003d006e0039006e0039006e00120000002403070050
+006e0044006e00440058004a0058004a0069005100690050006e002000000024030e0055006e00550058005b0058005b006e0055006e0055006e006100620067006e0060006e005b0062005f005800660058006100620055006e001e00000024030d00e4012c01e4013801e6013801e6013b01dd013b01dd013801e0013801
+e0013001e0013001dd013201dc013001e2012c01e4012c011600000024030900eb011d01eb013301ee013301ee013601e7013601e7011a01ee011a01ee011d01eb011d011600000024030900fb013301fb011d01f8011d01f8011a01ff011a01ff013601f8013601f8013301fb01330108000000fa02060002000000000000
+00040000002d010000050000001402b0006f01050000001302b0008d01040000002d01020004000000f00100000c000000240304008a01bc009d01b1008a01a5008a01bc000e000000240305004e01a5004e01ba004a01ba004a01a5004e01a5002a000000240313005801a5005c01ad005c01ad005e01b3005e01b3005e01
+ad005e01a5006201a5006201ba005d01ba005a01b2005a01b2005701ab005701ab005701b1005701ba005301ba005301a5005801a5001e00000024030d006c01b5006c01c1006e01c1006e01c4006501c4006501c1006801c1006801ba006801ba006501bb006401b9006901b5006c01b50008000000fa0206000200000000
+000000040000002d010000050000001402b0001602050000001302b0003002040000002d01020004000000f00100000c000000240304002d02bc004002b1002d02a5002d02bc006e000000240335005602af005602af005602b3005502b6005302b8005102ba005102ba004f02ba004d02bb004d02bb004902ba004602b700
+4602b7004402b4004302b0004302b0004402ac004502a9004602a7004802a5004802a5004d02a4004d02a4005102a5005402a7005502ab005602af005602af005602af004902aa004902aa004902ac004802b0004802b0004902b4004a02b6004a02b6004d02b7004d02b7004f02b7005002b5005102b3005102af005102af
+005102aa005102aa004f02a9004d02a8004d02a8004b02a8004902aa004902aa005602af004000000024031e005d02a5005d02b3005d02b3005d02b5005d02b5005f02b6006002b7006002b7006302b6006402b4006402b4006402b2006402a5006802a5006802b3006802b3006802b7006802b7006702b8006602b9006402
+ba006102bb006102bb005c02ba005a02b8005a02b8005902b6005902b4005902a5005d02a50016000000240309007a02a5007902a8007402a8007402ba007002ba007002a8006a02a8006a02a5007a02a5001e00000024030d008202b5008202c1008402c1008402c4007b02c4007b02c1007e02c1007e02ba007e02ba007a
+02bb007902b9007f02b5008202b50008000000fa0206000200000000000000040000002d010000050000001402e3001602050000001302e3009e01050000001402e3009e010500000013027f009e010500000014027f009e010500000013027f0016020500000014027f001602050000001302e3001602040000002d010200
+04000000f00100006600000024033100bb01a900bb01a900b701a900b301a700b501a300b501a300b801a500bb01a500bb01a500bd01a500be01a300be01a300bd01a200bb01a200b901a100b901a100b701a000b6019f00b5019d00b4019b00b4019b00b5019800b6019600b9019500bc019500bc019500c0019500c30197
+00c1019a00c1019a00be019900bc019900bc019900bb019900ba019a00ba019a00bb019b00bc019c00be019c00be019c00c2019e00c3019f00c301a200c301a200c301a500c101a700be01a900bb01a900bb01a9003000000024031600cc01a900cc01a900ca01a900c801a800c801a600c801a400c8019a00c8019a00c801
+9500cd019400cd019400cd019800cd01a300cd01a300cd01a500ce01a600ce01a600ce01a600cf01a900cf01a900cc01a900cc01a9006e00000024033500db01a800db01a800d901a900d701a900d701a900d501a900d301a800d201a600d201a400d201a400d201a300d401a100d601a000d801a000d801a000d901a000d9
+019f00d9019f00d9019e00d8019d00d8019d00d6019e00d4019f00d2019c00d2019c00d5019a00d9019a00d9019a00dc019a00de019c00de019c00de019f00de01a400de01a400de01a600df01a700dc01aa00dc01aa00db01a800db01a800db01a800d701a400d701a400d701a500d801a600d801a600d901a500d901a300
+d901a300d701a300d701a400d701a400db01a8001e00000024030d00ea01a900e601a900e1019a00e6019a00e7019e00e7019e00e801a300e901a300e901a300e9019e00eb019a00f0019a00ea01a9005800000024032a00f901a600f901a600fb01a500fd01a400ff01a700ff01a700fc01a900f901a900f901a900f601a9
+00f301a700f201a500f101a200f101a200f2019e00f3019c00f5019a00f8019a00f8019a00fb019a00fd019c00ff019e00ff01a200ff01a200ff01a300f701a300f701a300f701a500f801a600f901a600f901a600f901a600f8019d00f8019d00f7019e00f701a000fa01a000fa01a000fa019e00f8019d00f8019d00f901
+a6004800000024032200c101ca00c101ca00bf01cc00bb01cc00b401cc00b401b800bb01b800bb01b800bd01b800c001ba00c001ba00c101bb00c201bd00c301c200c301c200c301c600c101ca00c101ca00c101ca00bb01bd00b901bd00b901c800bb01c800bb01c800bc01c800bd01c700bd01c200bd01c200bd01bf00bd
+01bd00bc01bd00bb01bd00bb01bd00c101ca005800000024032a00ce01c900ce01c900d001c900d201c800d401cb00d401cb00d101cc00ce01cd00ce01cd00ca01cc00c801cb00c701c800c601c500c601c500c701c200c801bf00ca01be00cd01bd00cd01bd00d001be00d201bf00d301c200d401c500d401c500d401c600
+cb01c600cb01c600cc01c800cc01c900ce01c900ce01c900ce01c900cd01c100cd01c100cc01c100cb01c300cf01c300cf01c300ce01c100cd01c100cd01c100ce01c9003000000024031600dc01cd00dc01cd00d901cc00d801cb00d801ca00d801c800d801bd00d801bd00d701b800dc01b700dc01b700dd01bb00dd01c6
+00dd01c600dd01c900de01c900de01c900de01c900df01cc00df01cc00dc01cd00dc01cd006e00000024033500ea01cb00ea01cb00e901cc00e701cd00e701cd00e401cc00e301cb00e201ca00e201c800e201c800e201c600e301c400e501c300e801c300e801c300e901c300e901c200e901c200e901c100e801c100e801
+c100e601c100e401c200e201bf00e201bf00e501be00e801bd00e801bd00ec01be00ee01c000ee01c000ee01c200ee01c700ee01c700ee01c900ef01ca00ec01cd00ec01cd00ea01cb00ea01cb00ea01cb00e601c800e601c800e701c900e801c900e801c900e901c900e901c600e901c600e701c700e601c800e601c800ea
+01cb003400000024031800fb01cc00fb01cc00fa01cf00f901d100f701d300f401d300f201d000f201d000f501cf00f701cc00f601cc00f601cc00f501c900f101be00f601bd00f801c500f801c500f901c800f901c800f901c800fa01c300fc01bd000102bd00fb01cc0008000000fa020600020000000000000004000000
+2d010000050000001402e300da010500000013021801da010500000014020801cf01050000001302f200e501040000002d01020004000000f0010000480000002403220045033b0139033b0139033701390337013c0336013c033601400333014103310141033101400330013e032f013e032f013d0330013a03310138032f
+0138032f013b032c013f032c013f032c0142032c0143032d0145032f0145033001450330014403330142033501420335013e0337013e0337013e0338013e033801400338014603380145033b0116000000240309004a031d014a0333014d0333014d0336014703360147031a014d031a014d031d014a031d01160000002403
+09005a0333015a031d0158031d0158031a015e031a015e03360158033601580333015a03330108000000fa0206000200000000000000040000002d010000050000001402b000cd02050000001302b000ea02040000002d01020004000000f00100000c00000024030400e702bc00fa02b100e702a500e702bc000e00000024
+030500a802a500a802ba00a402ba00a402a500a802a5002a00000024031300b102a500b502ad00b502ad00b802b300b802b300b702ad00b702a500bb02a500bb02ba00b702ba00b302b200b302b200b002ab00b002ab00b102b100b102ba00ad02ba00ad02a500b102a5004800000024032200cb02c400bf02c400bf02c100
+bf02c100c202bf00c202bf00c602bc00c702ba00c702ba00c602b900c402b800c402b800c302b900c102ba00be02b800be02b800c202b600c602b500c602b500c802b500ca02b600cb02b800cb02ba00cb02ba00ca02bc00c802be00c802be00c402c100c402c100c402c100c402c100c702c100cc02c100cb02c400080000
+00fa0206000200000000000000040000002d010000050000001402b0007403050000001302b0008d03040000002d01020004000000f00100000c000000240304008a03bc009d03b1008a03a5008a03bc006e00000024033500b303af00b303af00b303b300b203b600b103b800af03ba00af03ba00ad03ba00aa03bb00aa03
+bb00a603ba00a303b700a303b700a103b400a103b000a103b000a103ac00a203a900a403a700a603a500a603a500aa03a400aa03a400ae03a500b103a700b303ab00b303af00b303af00b303af00a703aa00a703aa00a603ac00a603b000a603b000a603b400a803b600a803b600aa03b700aa03b700ac03b700ad03b500ae
+03b300ae03af00ae03af00ae03aa00ae03aa00ad03a900aa03a800aa03a800a803a800a703aa00a703aa00b303af004000000024031e00ba03a500ba03b300ba03b300bb03b500bb03b500bc03b600be03b700be03b700c003b600c103b400c103b400c103b200c103a500c603a500c603b300c603b300c503b700c503b700
+c403b800c303b900c103ba00be03bb00be03bb00ba03ba00b703b800b703b800b603b600b603b400b603a500ba03a5001600000024030900d703a500d603a800d103a800d103ba00cd03ba00cd03a800c803a800c803a500d703a5004800000024032200e403c400d803c400d803c100d803c100db03bf00db03bf00df03bc
+00e003ba00e003ba00df03b900de03b800de03b800dc03b900da03ba00d703b800d703b800db03b600df03b500df03b500e103b500e303b600e403b800e403ba00e403ba00e303bc00e203be00e203be00de03c100de03c100dd03c100dd03c100e003c100e503c100e403c40008000000fa02060002000000000000000400
+00002d010000050000001402e3007303050000001302e300fb02050000001402e300fb020500000013027f00fb020500000014027f00fb020500000013027f0073030500000014027f007303050000001302e3007303040000002d01020004000000f001000066000000240331001803a9001803a9001403a9001103a70012
+03a3001203a3001503a5001803a5001803a5001a03a5001b03a3001b03a3001a03a2001903a2001603a1001603a1001403a00013039f0012039d0012039b0012039b0012039800140396001603950019039500190395001d039500210397001e039a001e039a001c0399001a0399001a0399001803990017039a0017039a00
+18039b0019039c001b039c001b039c001f039e0020039f002103a2002103a2002003a5001e03a7001c03a9001803a9001803a90030000000240316002903a9002903a9002703a9002603a8002503a6002503a40025039a0025039a00250395002a0394002a0394002a0398002a03a3002a03a3002a03a5002b03a6002b03a6
+002c03a6002d03a9002d03a9002903a9002903a9006e000000240335003803a8003803a8003603a9003403a9003403a9003203a9003003a8002f03a6002f03a4002f03a4003003a3003103a1003303a0003603a0003603a0003703a00037039f0037039f0036039e0035039d0035039d0033039e0031039f002f039c002f03
+9c0032039a0036039a0036039a003a039a003b039c003b039c003c039f003c03a4003c03a4003c03a6003d03a7003a03aa003a03aa003803a8003803a8003803a8003403a4003403a4003403a5003503a6003503a6003703a5003703a3003703a3003403a3003403a4003403a4003803a8001e00000024030d004803a90044
+03a9003e039a0043039a0045039e0045039e004603a3004603a3004603a30047039e0048039a004d039a004803a9005800000024032a005603a6005603a6005803a5005a03a4005c03a7005c03a7005903a9005603a9005603a9005303a9005103a7004f03a5004f03a2004f03a2004f039e0051039c0053039a0056039a00
+56039a0059039a005b039c005c039e005c03a2005c03a2005c03a3005403a3005403a3005403a5005503a6005603a6005603a6005603a60056039d0056039d0054039e005403a0005703a0005703a00057039e0056039d0056039d005603a60048000000240322001e03ca001e03ca001c03cc001903cc001103cc001103b8
+001803b8001803b8001b03b8001d03ba001d03ba001f03bb002003bd002003c2002003c2002003c6001e03ca001e03ca001e03ca001803bd001603bd001603c8001803c8001803c8001903c8001a03c7001b03c2001b03c2001b03bf001a03bd001903bd001803bd001803bd001e03ca005800000024032a002b03c9002b03
+c9002d03c9002f03c8003103cb003103cb002e03cc002b03cd002b03cd002803cc002503cb002403c8002403c5002403c5002403c2002503bf002703be002a03bd002a03bd002d03be002f03bf003103c2003103c5003103c5003103c6002903c6002903c6002903c8002a03c9002b03c9002b03c9002b03c9002a03c1002a
+03c1002903c1002903c3002c03c3002c03c3002c03c1002a03c1002a03c1002b03c90030000000240316003903cd003903cd003703cc003503cb003503ca003503c8003503bd003503bd003503b8003a03b7003a03b7003a03bb003a03c6003a03c6003a03c9003b03c9003b03c9003c03c9003c03cc003c03cc003903cd00
+3903cd006e000000240335004803cb004803cb004603cc004403cd004403cd004203cc004003cb003f03ca003f03c8003f03c8003f03c6004103c4004303c3004603c3004603c3004603c3004603c2004603c2004603c1004503c1004503c1004303c1004103c2003f03bf003f03bf004203be004603bd004603bd004903be
+004b03c0004b03c0004b03c2004b03c7004b03c7004c03c9004c03ca004a03cd004a03cd004803cb004803cb004803cb004403c8004403c8004403c9004503c9004503c9004603c9004603c6004603c6004403c7004403c8004403c8004803cb0034000000240318005903cc005903cc005803cf005603d1005403d3005103
+d3004f03d0004f03d0005303cf005403cc005303cc005303cc005203c9004e03be005303bd005603c5005603c5005603c8005603c8005603c8005703c3005903bd005e03bd005903cc0008000000fa0206000200000000000000040000002d010000050000001402e30037030500000013021801370305000000140208012c
+03050000001302f2004203040000002d01020004000000f00100002a000000240313001803310118032d0113032d01120331010d03310113031e0118031e011e0331011803310118033101160326011603260115032401150324011503270114032a0117032a01160326011803310144000000240320002b032f012b032f01
+29033001260331011f0331011f031e0126031e0126031e0128031f012a031f012a031f012d0322012d0327012d0327012d032b012b032f012b032f012b032f01260322012403220124032d0126032d0126032d0127032d0127032c012803270128032701270323012703220126032201260322012b032f011c00000024030c
+0035033001350330013503320133033401300336012e0334012e0334013003310130032e0130031e0135031e01350330012a00000024031300bc013101bb012d01b6012d01b5013101b0013101b6011e01bb011e01c1013101bc013101bc013101b9012601b9012601b9012401b9012401b8012701b7012a01ba012a01b901
+2601bc0131014400000024032000ce012f01ce012f01cc013001c9013101c3013101c3011e01c9011e01c9011e01cb011f01cd011f01cd011f01d0012201d1012701d1012701d0012b01ce012f01ce012f01ce012f01c9012201c7012201c7012d01c9012d01c9012d01ca012d01cb012c01cb012701cb012701cb012301ca
+012201c9012201c9012201ce012f011c00000024030c00d8013001d8013001d8013201d7013401d3013601d1013401d1013401d3013101d3012e01d3011e01d8011e01d8013001040000002701ffff030000000000}}}{\rtlch \af1 \ltrch \insrsid5645506
+\par }}}}
+{\shp{\*\shpinst\shpleft1281\shptop3312\shpright4428\shpbottom9000\shpfhdr0\shpbxcolumn\shpbxignore\shpbypara\shpbyignore\shpwr3\shpwrk0\shpfblwtxt0\shpz2\shplid1030{\sp{\sn shapeType}{\sv 202}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lTxid}{\sv 327680}}{\sp{\sn dxTextLeft}{\sv 64008}}{\sp{\sn dyTextTop}{\sv 182880}}{\sp{\sn dxTextRight}{\sv 137160}}{\sp{\sn dyTextBottom}{\sv 0}}{\sp{\sn hspNext}{\sv 1030}}
+{\sp{\sn fFitShapeToText}{\sv 0}}{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn lidRegroup}{\sv 1}}{\sp{\sn posrelh}{\sv 0}}{\sp{\sn posrelv}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}{\shptxt \ltrpar
+\pard\plain \ltrpar\s21\ql \li50\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin50\itap0 \rtlch \ab\af1\afs22\alang1025 \ltrch \b\scaps\f1\fs22\expnd3\expndtw17\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch
+\insrsid7564464 Features
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s22 \rtlch \af46\afs18 \ltrch \f46\fs18\cf17\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard\plain \ltrpar\s22\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls38\adjustright\rin0\lin216\itap0 \rtlch \af1\afs19\alang1025 \ltrch \f1\fs19\cf17\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 Designed for high-speed DDR style interface applications.
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s22 \rtlch \af46\afs18 \ltrch \f46\fs18\cf17\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard\plain \ltrpar\s22\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls38\adjustright\rin0\lin216\itap0 \rtlch \af1\afs19\alang1025 \ltrch \f1\fs19\cf17\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 Generates precise delays that can be programmed from 0 to 360 degrees of the reference period.
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s22 \rtlch \af46\afs18 \ltrch \f46\fs18\cf17\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard\plain \ltrpar\s22\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls38\adjustright\rin0\lin216\itap0 \rtlch \af1\afs19\alang1025 \ltrch \f1\fs19\cf17\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 Delays multiple periodic or aperiodic signals independent of voltage and temperature.
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s22 \rtlch \af46\afs18 \ltrch \f46\fs18\cf17\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard\plain \ltrpar\s22\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls38\adjustright\rin0\lin216\itap0 \rtlch \af1\afs19\alang1025 \ltrch \f1\fs19\cf17\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 Delivers optimal jitter \line performance over a wide \line frequency range.
+\par }\pard\plain \ltrpar\qr \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par {\listtext\pard\plain\ltrpar \s22 \rtlch \af46\afs18 \ltrch \f46\fs18\cf17\lang1024\langfe1024\noproof \loch\af46\dbch\af0\hich\f46 \'34\tab}}\pard\plain \ltrpar\s22\ql \fi-216\li216\ri0\widctlpar
+\tqr\tx216\aspalpha\aspnum\faauto\ls38\adjustright\rin0\lin216\itap0 \rtlch \af1\afs19\alang1025 \ltrch \f1\fs19\cf17\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 Available in flexible form factors for easier integration.
+\par }}}}
+{\shp{\*\shpinst\shpleft5061\shptop3312\shpright11541\shpbottom11952\shpfhdr0\shpbxcolumn\shpbxignore\shpbypara\shpbyignore\shpwr3\shpwrk0\shpfblwtxt0\shpz1\shplid1031{\sp{\sn shapeType}{\sv 202}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn lTxid}{\sv 393216}}{\sp{\sn dxTextLeft}{\sv 274320}}{\sp{\sn dyTextTop}{\sv 182880}}{\sp{\sn dxTextRight}{\sv 137160}}{\sp{\sn dyTextBottom}{\sv 0}}{\sp{\sn hspNext}{\sv 1031}}
+{\sp{\sn fFilled}{\sv 0}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn lidRegroup}{\sv 1}}{\sp{\sn posrelh}{\sv 0}}{\sp{\sn posrelv}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}{\shptxt \ltrpar \pard\plain \ltrpar
+\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs16\alang1025 \ltrch \f1\fs16\cf1\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch \ab\af1\afs22 \ltrch
+\cs16\b\scaps\fs22\expnd3\expndtw18\lang1024\langfe1024\noproof\insrsid7564464 Specifications
+\par }\pard\plain \ltrpar\s24\ql \li0\ri0\sb40\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs17\alang1025 \ltrch \f1\fs17\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+Part No. TCI-TN65GP-DDRHDLL
+\par }\pard\plain \ltrpar\s15\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch \af1\afs20\alang1025 \ltrch \f1\fs20\cf1\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+\par }\pard\plain \ltrpar\s19\ql \fi-3780\li3780\ri0\sl-210\slmult0\widctlpar\tx180\tx3780\tx4050\tx9180\aspalpha\aspnum\faauto\adjustright\rin0\lin3780\itap0 \rtlch \af1\afs16\alang1025 \ltrch
+\f1\fs16\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464 - Reference input frequency range\tab 220MHz - 1.1GHz
+\par - Slave delay adjustment range\tab 0% - 50% of reference cycle
+\par - Slave delay adjustment resolution\tab 0.83% of reference cycle
+\par - Specified master adjustment setting (MADJ)\tab 120
+\par - Allowed master adjustment range (MADJ)\tab 76 - 256
+\par - Specified slave adjustment range (ADJ)\tab 0 - 60
+\par - Slave delay equation\tab ADJ[7:0]/MADJ[7:0]*Tref
+\par - Number of slaves in cluster\tab 2
+\par - Pulse-width distortion (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Slave delay DNL (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Slave delay INL (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Slave delay jitter (P-P) (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Total slave timing uncertainty (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par
+\par - Power dissipation (nom)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Reset pulse width (min)\tab 1\'b5s
+\par - Lock time (min allowed)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Area (master + 2 slaves, isolation) (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par
+\par - Added core supply package pins\tab 1 VDD and 1 VSS
+\par - Low freq. supply noise est. (P-P) (max)\tab 10% VDD
+\par - Low freq. sub. noise est. (P-P) (max)\tab 10% VDD
+\par - Reference input jitter (period, P-P) (max)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Reference input duty-cycle range\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - High/low slave input pulse width (min)\tab }{\rtlch \af1 \ltrch \i\cf17\insrsid3022649\charrsid3022649 NDA Required}{\rtlch \af1 \ltrch \insrsid3022649
+\par - Slave inputs need not be periodic
+\par - Reference input 10%-90% edge time (max)\tab 150ps
+\par - Slave input 10%-90% edge time (max)\tab 150ps
+\par - Slave output loading (max)\tab 200fF
+\par
+\par - Process technology\tab TSMC CLN65GP 65nm
+\par - Supply voltage (nom, tol)\tab 1.0V, +/-10%
+\par - Junction temperature (nom, min, max)\tab 70C, -40C, 125C
+\par }\pard\plain \ltrpar\s17\ql \fi-72\li72\ri0\sb240\widctlpar\tx72\aspalpha\aspnum\faauto\adjustright\rin0\lin72\itap0 \rtlch \af1\afs13\alang1025 \ltrch \f1\fs13\lang1024\langfe1024\cgrid\noproof\langnp1033\langfenp1033 {\rtlch \af1 \ltrch \insrsid7564464
+*\tab Jitter numbers are worst-case estimates with 10% VDD supply and \line substrate noise\emdash actual results will be better.
+\par }}}}
+{\shp{\*\shpinst\shpleft0\shptop0\shpright11784\shpbottom15364\shpfhdr0\shpbxmargin\shpbxignore\shpbymargin\shpbyignore\shpwr3\shpwrk0\shpfblwtxt0\shpz0\shplid1032{\sp{\sn shapeType}{\sv 75}}{\sp{\sn fFlipH}{\sv 0}}{\sp{\sn fFlipV}{\sv 0}}
+{\sp{\sn pib}{\sv {\pict\picscalex33\picscaley33\piccropl0\piccropr0\piccropt0\piccropb0\picw62336\pich81306\picwgoal35340\pichgoal46095\wmetafile8\bliptag463789102{\*\blipuid 1ba4dc2e9856bff4bcf39ce845fe6d2b}
+010009000003d7b900000400e09e000000000400000003010800050000000b0230002e00050000000c02010c3409040000000601010007000000fc020000cccc
+cc000000040000002d01000008000000fa0205000000000000000000040000002d0101000f00000038050100050082002801f2002801f2003601820036018200
+2801040000000601010007000000fc020000000000000000040000002d01020004000000f00100000f000000380501000500f2002801cf012801cf013601f200
+3601f2002801040000000601020007000000fc020000efa000000000040000002d01000004000000f001020017000000380501000900fe00e100f900e100f900
+f100f400f100f400e100ef00e100ef00dd00ff00dd00fe00e10004000000060102004c0000003805020018000b000d01f1000d01f1000b01ed000b01ed000901
+ea000801e9000701e9000701f1000301f1000301dd000a01dd000a01dd000d01dd001001df001001df001101e1001201e3001201e3001101e5001001e7000e01
+e8000e01e8001301f1000d01f1000901e1000701e1000701e5000901e5000901e5000c01e5000c01e3000c01e3000c01e1000901e1000901e100040000000601
+020041000000380501001e002401ef002401ef002201f0001e01f1001e01f1001a01f0001701ef001701ef001601ed001601ea001601dd001b01dd001b01ea00
+1b01ea001b01ec001b01ec001c01ed001e01ed001e01ed002001ec002001ec002101eb002101e9002101dd002601dd002601ea002601ea002501ed002401ef00
+2401ef0004000000060102001f000000380501000d002b01f1002b01dd003801dd003701e1003001e1003001e4003601e4003601e8003001e8003001ed003801
+ed003801f1002b01f1001c000000fb02dcff000000000000900100000000000002224d657461506c7573426f6c644361707300f4cd0c00000000312027403120
+2700040000002d010200040000000601020007000000fc020000000000000000040000002d01030004000000f0010000550000003805010028004d01f1004d01
+f1004a01f0004701ef004701ef004501eb004401e7004401e7004401e4004601e1004601e1004901de004b01dd004d01dd004d01dd005001dd005301df005101
+e1005101e1004e01e0004e01e0004b01e0004901e2004901e2004801e4004801e7004801e7004801ea004901ec004901ec004b01ee004e01ee004e01ee005001
+ee005201ed005301ef005301ef005101f0004d01f1004d01f10004000000060102000f0000003805010005005701f1005701dd005b01dd005b01f1005701f100
+04000000060102005c000000380502001d000e006c01f1006c01f1006a01ee006a01ee006601e9006601e9006501e8006501f1006101f1006101dd006701dd00
+6701dd006a01de006d01df006d01df006e01e0006f01e3006f01e3006e01e5006d01e7006c01e8006901e8006901e8006a01e9006a01e9006d01ed006d01ed00
+7001f1006c01f1006501e0006501e6006701e6006701e6006a01e5006a01e5006b01e4006b01e3006b01e3006b01e1006901e0006901e0006701e0006501e000
+0400000006010200550000003805010028007d01f1007d01f1007901f0007601ef007601ef007401eb007301e7007301e7007401e4007501e1007501e1007801
+de007a01dd007d01dd007d01dd008001dd008201df008001e1008001e1007d01e0007d01e0007a01e0007801e2007801e2007701e4007701e7007701e7007701
+ea007901ec007901ec007a01ee007d01ee007d01ee007f01ee008101ed008301ef008301ef008001f0007d01f1007d01f1000400000006010200430000003805
+01001f009301ef009301ef009101f1008e01f1008e01f1008901f0008701ee008701ee008601ec008601ea008601dd008a01dd008a01e9008a01e9008a01ec00
+8a01ec008b01ee008e01ee008e01ee009001ee009101ed009101ed009201ec009201ea009201dd009501dd009501ea009501ea009501ed009301ef009301ef00
+04000000060102000f0000003805010005009c01f1009c01dd009f01dd009f01f1009c01f100040000000601020017000000380501000900b201e000ad01e000
+ad01f100a901f100a901e000a401e000a401dd00b301dd00b201e000040000000601020071000000380501003600c101f000c101f000be01f100bc01f100bc01
+f100b801f100b501ef00b601ed00b601ed00b901ee00bc01ee00bc01ee00bf01ee00bf01ee00c001ed00c001eb00c001eb00bf01ea00bd01e900ba01e800ba01
+e800b801e700b601e500b601e500b501e300b501e300b601e000b701de00ba01dd00bd01dd00bd01dd00c001dd00c401df00c201e100c201e100bf01e000bd01
+e000bd01e000ba01e000b901e200b901e200ba01e400bc01e500bf01e500bf01e500c101e600c301e700c301e700c401e900c401eb00c401eb00c301ee00c101
+f000c101f00004000000060102000f000000380501000500cf01f100cf01dd00d201dd00d201f100cf01f10004000000060102002b000000380501001300e401
+f100df01e700df01e700dc01e200dc01e200dc01e700dc01f100d901f100d901dd00dd01dd00e201e700e201e700e501ec00e501ec00e401e600e401dd00e801
+dd00e801f100e401f100040000000601020055000000380501002800f601f100f601f100f201f000ef01ef00ef01ef00ed01eb00ed01e700ed01e700ed01e400
+ee01e100ee01e100f201de00f401dd00f601dd00f601dd00f901dd00fb01df00fa01e100fa01e100f601e000f601e000f301e000f101e200f101e200f101e400
+f001e700f001e700f101ea00f201ec00f201ec00f401ee00f601ee00f601ee00f801ee00fa01ed00fc01ef00fc01ef00f901f000f601f100f601f10004000000
+0601020007000000fc020000efa000000000040000002d01000004000000f001030008000000fa0205000000000000000000040000002d01030004000000f001
+010007000000fc020000efa000000000040000002d01010004000000f00100000d0000003805010004006a007f007e0089006a0094006a007f0008000000fa02
+05000000000000000000040000002d01000004000000f001030007000000fc020100000000000000040000002d01030004000000f00101000c00000025030400
+6a007f007e0089006a0094006a007f00040000000601020007000000fc020000000000000000040000002d01010004000000f001030008000000fa0205000000
+000000000000040000002d01030004000000f001000007000000fc020000000000000000040000002d01000004000000f00101001b000000380501000b008200
+ca00820074009000740090008300e5008300e5009100900091009000bc00e400bc00e400ca008200ca0008000000fa0205000000000000000000040000002d01
+010004000000f001030007000000fc020100000000000000040000002d01030004000000f00100001a00000025030b008200ca00820074009000740090008300
+e5008300e5009100900091009000bc00e400bc00e400ca008200ca00040000000601020007000000fc020000000000000000040000002d01000004000000f001
+030008000000fa0205000000000000000000040000002d01030004000000f001010007000000fc020000000000000000040000002d01010004000000f0010000
+170000003805010009005601ca00f300ca00f30083005601830056019100010191000101bc005601bc005601ca0008000000fa02050000000000000000000400
+00002d01000004000000f001030007000000fc020100000000000000040000002d01030004000000f001010016000000250309005601ca00f300ca00f3008300
+5601830056019100010191000101bc005601bc005601ca00040000000601020007000000fc020000000000000000040000002d01010004000000f00103000800
+0000fa0205000000000000000000040000002d01030004000000f001000007000000fc020000000000000000040000002d01000004000000f00101000f000000
+3805010005007301ca006401ca0064018300730183007301ca0008000000fa0205000000000000000000040000002d01010004000000f001030007000000fc02
+0100000000000000040000002d01030004000000f00100000e000000250305007301ca006401ca0064018300730183007301ca00040000000601020007000000
+fc020000000000000000040000002d01000004000000f001030008000000fa0205000000000000000000040000002d01030004000000f001010007000000fc02
+0000000000000000040000002d01010004000000f00100003a000000380502000a0010000002ed000002f200ff01f200ff01ed00fd01ed00fd01ec000202ec00
+0202ed000002ed000002ed000902f2000902ed000902ed000702f2000602f2000502ed000402ed000402f2000302f2000302ec000502ec000702f0000802ec00
+0a02ec000a02f2000902f20008000000fa0205000000000000000000040000002d01000004000000f001030007000000fc020100000000000000040000002d01
+030004000000f00101001800000025030a000002ed000002f200ff01f200ff01ed00fd01ed00fd01ec000202ec000202ed000002ed000002ed00240000002503
+10000902f2000902ed000902ed000702f2000602f2000502ed000402ed000402f2000302f2000302ec000502ec000702f0000802ec000a02ec000a02f2000902
+f200040000000601010007000000fc020000efa000000000040000002d01010004000000f00103000f000000380501000500cf0128010c0928010c093601cf01
+3601cf012801e09e0000430f2000cc0000002700b6020000000075002208bc01ee0028000000b60200002700000001001800000000007c3d0100130b0000130b
+00000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef
+02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00a
+a4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7
+f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf1
+1dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126
+aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1
+f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f2
+38b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341
+b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bb
+f449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef4
+51bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55a
+c1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5
+f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f6
+6bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674
+cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bce
+f77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f7
+85d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88c
+d4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7
+f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf9
+9cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4
+ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0
+faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fa
+b4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbc
+e6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8
+fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfc
+caebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1
+eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1
+fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fd
+e0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6
+f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8
+feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafe
+f3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8
+fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefe
+fffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06
+a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6
+f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f0
+18a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120
+acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229af
+f22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f2
+32b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33b
+b6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9
+f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf4
+4dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455
+c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3
+f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f5
+67c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66e
+c9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677cc
+f677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff7
+7fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888
+d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6
+f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f8
+98d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99f
+dbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7de
+f9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1fa
+afe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7
+e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7
+fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafb
+c6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcce
+edfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4ef
+fcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fd
+dcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2
+f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7
+fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9fe
+eff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5
+fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfe
+fffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00
+a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3
+f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f0
+12a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11c
+aaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125ae
+f125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f2
+2eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237
+b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7
+f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf3
+48bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450
+bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1
+f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f5
+61c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66a
+c8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cb
+f673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf7
+7bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782
+d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4
+f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f8
+93d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99b
+daf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3dd
+f9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0fa
+abe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3
+e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5
+fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fb
+c3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9
+ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0ee
+fcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fd
+d8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddf
+f3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6
+fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8fe
+ecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2
+fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fc
+fff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfeff
+fdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2
+ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f0
+0ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017
+a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11fac
+f120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff2
+28aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231
+b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6
+f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f3
+43b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44c
+bcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bf
+f454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f5
+5dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565
+c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9
+f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf6
+76ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77e
+cff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2
+f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f8
+8fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897
+d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edb
+f99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9
+a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faae
+e1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4
+fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fb
+bee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5
+eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdec
+fccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effc
+d4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fdda
+f1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4
+fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fe
+e8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feef
+f9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fb
+fef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdff
+fafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffff
+ffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f0
+08a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011
+a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaa
+f11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf1
+23adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22c
+b1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4
+f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f3
+3eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346
+baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbd
+f450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f4
+58c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560
+c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7
+f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf6
+72caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77a
+cdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0
+f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f8
+8ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892
+d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9
+f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9
+a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaa
+dffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2
+fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fb
+bae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1
+e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8eb
+fcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfc
+d0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7
+f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3
+fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fd
+e5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feeb
+f8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fa
+fef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfe
+f7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffc
+fefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef
+03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00d
+a5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8
+f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf1
+1facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127
+aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2
+f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f3
+39b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342
+b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbc
+f44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff4
+53bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55c
+c2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5
+f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f6
+6cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675
+cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcf
+f77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f7
+86d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88e
+d5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8
+f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf9
+9edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5
+def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1
+faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fa
+b5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbd
+e6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9
+fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfc
+ccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3
+effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1
+fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fd
+e1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7
+f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9
+feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfe
+f4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffa
+fdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffff
+ffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07
+a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6
+f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f1
+19a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122
+adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0
+f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f2
+34b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33d
+b7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345ba
+f346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf4
+4ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457
+c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3
+f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f6
+68c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670
+caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cd
+f779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f7
+81d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889
+d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6
+f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f9
+99d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1
+dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9df
+faa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fa
+b1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9
+e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7
+fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafc
+c7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccf
+edfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0
+fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fd
+ddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4
+f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7
+feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fe
+f1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6
+fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfe
+fffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02
+a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4
+f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f0
+15a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11e
+abf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126ae
+f127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f2
+2fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238
+b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8
+f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf4
+49bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452
+bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1
+f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f5
+64c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66b
+c8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cb
+f674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef7
+7ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785
+d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4
+f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f8
+95d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99d
+dbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4dd
+f9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0fa
+ace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4
+e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6
+fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fb
+c3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccb
+ecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1ee
+fcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fd
+daf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0
+f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6
+fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8fe
+edf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3
+fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fd
+fff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefeff
+fefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2
+ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f0
+0fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118
+a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121ac
+f121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f2
+2ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233
+b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6
+f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f3
+45baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44d
+bdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0
+f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f5
+5ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567
+c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fca
+f66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf6
+78cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780
+d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3
+f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f8
+90d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998
+d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dc
+f9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffa
+a8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0
+e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4
+fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fb
+c0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6
+eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceed
+fcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effc
+d5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddc
+f2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5
+fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7fe
+eaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0
+f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fb
+fef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfeff
+fbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0
+ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f0
+0aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014
+a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caa
+f11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef1
+26aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22e
+b1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4
+f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f3
+3fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448
+bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451be
+f451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f5
+5ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561
+c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8
+f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf6
+73cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77b
+cef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1
+f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f8
+8cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894
+d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bda
+f99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9
+a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faab
+e0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3
+fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fb
+bbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3
+e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaeb
+fccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefc
+d1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8
+f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3
+fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fd
+e6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feec
+f8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fa
+fef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdff
+f8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffe
+fefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef
+06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00e
+a5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9
+f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf1
+20acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229
+aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3
+f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f3
+3bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343
+b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbc
+f44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff4
+54bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55d
+c3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6
+f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f6
+6ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677
+ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecf
+f77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f7
+88d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88f
+d5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8
+f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf9
+9fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7
+def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1
+faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fa
+b7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbe
+e7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5ea
+fbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfc
+cdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4
+effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2
+fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fd
+e2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9
+f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9
+feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfe
+f5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffa
+fdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb
+00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009
+a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7
+f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf1
+1caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123
+adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1
+f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f2
+35b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33e
+b7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bb
+f347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef4
+50bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459
+c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4
+f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f6
+69c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672
+caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acd
+f77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f7
+82d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88b
+d4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7
+f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f9
+9bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2
+dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadf
+faabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fa
+b2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbba
+e5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8
+fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfc
+c9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0
+eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0
+fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fd
+def3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5
+f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8
+feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafe
+f2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8
+fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfe
+fffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03
+a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5
+f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f0
+16a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11f
+acf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128af
+f228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f2
+31b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33a
+b6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8
+f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf4
+4bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453
+bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2
+f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f5
+65c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66d
+c9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676cc
+f676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff7
+7ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786
+d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5
+f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f8
+96d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99e
+dbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6de
+f9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1fa
+aee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6
+e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6
+fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fb
+c4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfccc
+ecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3ef
+fcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fd
+daf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1
+f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6
+fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9fe
+eff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4
+fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafd
+fffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff
+acb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3
+f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f0
+11a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11a
+aaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122ad
+f123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f2
+2bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234
+b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7
+f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf3
+46baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44f
+bdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1
+f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f5
+60c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668
+c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670ca
+f670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf7
+79cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781
+d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3
+f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f8
+92d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99a
+d9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dc
+f9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffa
+a9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1
+e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5
+fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fb
+c1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8
+ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0ed
+fcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fc
+d7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fddd
+f2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5
+fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7fe
+ebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1
+fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fc
+fef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfeff
+fcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1
+ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f0
+0ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015
+a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eab
+f11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef1
+27aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230
+b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5
+f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f3
+42b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449
+bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bf
+f452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f5
+5bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564
+c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8
+f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf6
+75cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77d
+cff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1
+f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f8
+8dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895
+d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddb
+f99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9
+a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faad
+e1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3
+fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fb
+bde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3
+e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbec
+fccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefc
+d2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fdda
+f1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4
+fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fd
+e7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feee
+f9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fb
+fef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdff
+f9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffe
+ffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef
+07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010
+a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9
+f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf1
+22adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22a
+b0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3
+f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f3
+3cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345
+baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebd
+f44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f4
+57c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55f
+c3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6
+f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf6
+6fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778
+cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0
+f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f8
+89d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891
+d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9
+f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9
+a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8
+dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2
+fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fb
+b8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0
+e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7ea
+fcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfc
+cfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6
+f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2
+fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fd
+e3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feea
+f7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9
+fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfe
+f6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffc
+fefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef
+02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00a
+a4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7
+f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf1
+1dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126
+aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1
+f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f2
+38b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341
+b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bb
+f449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef4
+51bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55a
+c1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5
+f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f6
+6bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674
+cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bce
+f77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f7
+85d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88c
+d4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7
+f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf9
+9cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4
+ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0
+faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fa
+b4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbc
+e6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8
+fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfc
+caebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1
+eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1
+fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fd
+e0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6
+f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8
+feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafe
+f3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8
+fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefe
+fffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06
+a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6
+f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f0
+18a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120
+acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229af
+f22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f2
+32b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33b
+b6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9
+f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf4
+4dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455
+c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3
+f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f5
+67c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66e
+c9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677cc
+f677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff7
+7fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888
+d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6
+f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f8
+98d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99f
+dbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7de
+f9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1fa
+afe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7
+e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7
+fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafb
+c6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcce
+edfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4ef
+fcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fd
+dcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2
+f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7
+fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9fe
+eff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5
+fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfe
+fffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00
+a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3
+f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f0
+12a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11c
+aaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125ae
+f125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f2
+2eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237
+b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7
+f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf3
+48bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450
+bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1
+f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f5
+61c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66a
+c8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cb
+f673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf7
+7bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782
+d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4
+f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f8
+93d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99b
+daf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3dd
+f9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0fa
+abe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3
+e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5
+fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fb
+c3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9
+ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0ee
+fcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fd
+d8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddf
+f3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6
+fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8fe
+ecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2
+fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fc
+fff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfeff
+fdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2
+ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f0
+0ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017
+a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11fac
+f120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff2
+28aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231
+b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6
+f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f3
+43b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44c
+bcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bf
+f454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f5
+5dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565
+c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9
+f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf6
+76ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77e
+cff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2
+f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f8
+8fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897
+d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edb
+f99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9
+a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faae
+e1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4
+fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fb
+bee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5
+eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdec
+fccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effc
+d4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fdda
+f1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4
+fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fe
+e8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feef
+f9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fb
+fef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdff
+fafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffff
+ffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f0
+08a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011
+a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaa
+f11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf1
+23adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22c
+b1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4
+f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f3
+3eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346
+baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbd
+f450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f4
+58c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560
+c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7
+f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf6
+72caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77a
+cdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0
+f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f8
+8ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892
+d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9
+f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9
+a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaa
+dffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2
+fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fb
+bae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1
+e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8eb
+fcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfc
+d0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7
+f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3
+fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fd
+e5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feeb
+f8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fa
+fef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfe
+f7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffc
+fefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef
+03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00d
+a5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8
+f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf1
+1facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127
+aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2
+f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f3
+39b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342
+b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbc
+f44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff4
+53bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55c
+c2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5
+f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f6
+6cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675
+cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcf
+f77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f7
+86d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88e
+d5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8
+f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf9
+9edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5
+def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1
+faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fa
+b5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbd
+e6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9
+fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfc
+ccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3
+effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1
+fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fd
+e1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7
+f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9
+feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfe
+f4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffa
+fdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffff
+ffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07
+a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6
+f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f1
+19a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122
+adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0
+f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f2
+34b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33d
+b7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345ba
+f346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf4
+4ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457
+c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3
+f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f6
+68c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670
+caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cd
+f779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f7
+81d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889
+d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6
+f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f9
+99d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1
+dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9df
+faa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fa
+b1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9
+e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7
+fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafc
+c7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccf
+edfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0
+fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fd
+ddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4
+f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7
+feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fe
+f1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6
+fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfe
+fffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02
+a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4
+f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f0
+15a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11e
+abf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126ae
+f127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f2
+2fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238
+b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8
+f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf4
+49bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452
+bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1
+f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f5
+64c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66b
+c8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cb
+f674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef7
+7ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785
+d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4
+f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f8
+95d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99d
+dbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4dd
+f9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0fa
+ace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4
+e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6
+fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fb
+c3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccb
+ecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1ee
+fcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fd
+daf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0
+f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6
+fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8fe
+edf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3
+fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fd
+fff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefeff
+fefffffeffffffffffffffffacb0ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2
+ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f0
+0fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118
+a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121ac
+f121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f2
+2ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233
+b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6
+f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f3
+45baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44d
+bdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0
+f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f5
+5ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567
+c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fca
+f66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf6
+78cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780
+d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3
+f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f8
+90d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998
+d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dc
+f9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffa
+a8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0
+e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4
+fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fb
+c0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6
+eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceed
+fcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effc
+d5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddc
+f2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5
+fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7fe
+eaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0
+f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fb
+fef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfeff
+fbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0
+ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f0
+0aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014
+a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caa
+f11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef1
+26aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22e
+b1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4
+f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f3
+3fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448
+bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451be
+f451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f5
+5ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561
+c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8
+f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf6
+73cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77b
+cef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1
+f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f8
+8cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894
+d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bda
+f99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9
+a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faab
+e0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3
+fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fb
+bbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3
+e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaeb
+fccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefc
+d1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8
+f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3
+fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fd
+e6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feec
+f8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fa
+fef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdff
+f8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffe
+fefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef
+06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00e
+a5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9
+f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf1
+20acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229
+aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3
+f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f3
+3bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343
+b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbc
+f44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff4
+54bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55d
+c3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6
+f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f6
+6ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677
+ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecf
+f77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f7
+88d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88f
+d5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8
+f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf9
+9fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7
+def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1
+faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fa
+b7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbe
+e7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5ea
+fbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfc
+cdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4
+effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2
+fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fd
+e2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9
+f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9
+feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfe
+f5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffa
+fdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb
+00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009
+a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7
+f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf1
+1caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123
+adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1
+f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f2
+35b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33e
+b7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bb
+f347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef4
+50bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459
+c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4
+f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f6
+69c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672
+caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acd
+f77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f7
+82d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88b
+d4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7
+f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f9
+9bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2
+dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadf
+faabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fa
+b2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbba
+e5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8
+fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfc
+c9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0
+eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0
+fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fd
+def3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5
+f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8
+feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafe
+f2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8
+fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfe
+fffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03
+a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5
+f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f0
+16a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11f
+acf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128af
+f228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f2
+31b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33a
+b6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8
+f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf4
+4bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453
+bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2
+f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f5
+65c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66d
+c9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676cc
+f676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff7
+7ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786
+d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5
+f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f8
+96d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99e
+dbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6de
+f9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1fa
+aee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6
+e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6
+fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fb
+c4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfccc
+ecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3ef
+fcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fd
+daf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1
+f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6
+fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9fe
+eff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4
+fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafd
+fffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff
+2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3
+f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f0
+11a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11a
+aaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122ad
+f123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f2
+2bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234
+b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7
+f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf3
+46baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44f
+bdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1
+f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f5
+60c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668
+c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670ca
+f670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf7
+79cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781
+d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3
+f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f8
+92d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99a
+d9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dc
+f9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffa
+a9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1
+e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5
+fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fb
+c1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8
+ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0ed
+fcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fc
+d7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fddd
+f2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5
+fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7fe
+ebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1
+fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fc
+fef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfeff
+fcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1
+ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f0
+0ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015
+a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eab
+f11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef1
+27aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230
+b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5
+f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f3
+42b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449
+bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bf
+f452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f5
+5bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564
+c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8
+f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf6
+75cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77d
+cff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1
+f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f8
+8dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895
+d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddb
+f99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9
+a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faad
+e1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3
+fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fb
+bde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3
+e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbec
+fccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefc
+d2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fdda
+f1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4
+fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fd
+e7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feee
+f9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fb
+fef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdff
+f9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffe
+ffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef
+07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010
+a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9
+f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf1
+22adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22a
+b0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3
+f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f3
+3cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345
+baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebd
+f44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f4
+57c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55f
+c3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6
+f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf6
+6fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778
+cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0
+f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f8
+89d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891
+d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9
+f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9
+a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8
+dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2
+fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fb
+b8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0
+e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7ea
+fcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfc
+cfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6
+f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2
+fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fd
+e3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feea
+f7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9
+fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfe
+f6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffc
+fefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef
+02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00a
+a4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7
+f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf1
+1dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126
+aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1
+f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f2
+38b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341
+b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bb
+f449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef4
+51bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55a
+c1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5
+f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f6
+6bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674
+cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bce
+f77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f7
+85d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88c
+d4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7
+f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf9
+9cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4
+ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0
+faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fa
+b4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbc
+e6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8
+fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfc
+caebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1
+eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1
+fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fd
+e0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6
+f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8
+feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafe
+f3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8
+fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefe
+fffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06
+a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6
+f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f0
+18a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120
+acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229af
+f22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f2
+32b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33b
+b6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9
+f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf4
+4dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455
+c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3
+f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f5
+67c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66e
+c9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677cc
+f677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff7
+7fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888
+d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6
+f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f8
+98d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99f
+dbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7de
+f9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1fa
+afe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7
+e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7
+fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafb
+c6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcce
+edfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4ef
+fcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fd
+dcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2
+f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7
+fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9fe
+eff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5
+fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfe
+fffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00
+a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3
+f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f00ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f0
+12a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11c
+aaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11facf120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125ae
+f125aef126aef126aef126aef127aef127aef127aef128aff228aff228aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f2
+2eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237
+b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7
+f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f343b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf3
+48bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44cbcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450
+bef451bef451bef451bef452bff452bff452bff453bff453bff454bff454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1
+f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f55dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f5
+61c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66a
+c8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cb
+f673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf676ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf7
+7bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77ecff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782
+d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4
+f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f88fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f8
+93d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99b
+daf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edbf99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3dd
+f9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0fa
+abe0faabe0faace0faace0faace0faade1faade1faade1faaee1faaee1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3
+e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5
+fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fbbee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fb
+c3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9
+ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdecfccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0ee
+fcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effcd4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fd
+d8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddf
+f3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6
+fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fee8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8fe
+ecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2
+fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fc
+fff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfeff
+fdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffffffbfe7fb00a0ef00a0ef01a0ef01a0ef02a1ef02a1ef02a1ef03a1ef03a1ef03a1ef05a2
+ef05a2ef06a2ef06a2ef06a2ef07a3ef07a3ef07a3ef08a3f008a3f008a3f009a3f009a3f00aa4f00aa4f00aa4f00ca4f00ca4f00ca4f00da5f00da5f00ea5f0
+0ea5f00ea5f00fa6f00fa6f00fa6f010a6f010a6f010a6f011a6f011a6f012a7f012a7f012a7f014a7f014a7f014a7f015a8f015a8f016a8f016a8f016a8f017
+a9f017a9f017a9f018a9f118a9f118a9f119a9f119a9f11aaaf11aaaf11aaaf11caaf11caaf11caaf11dabf11dabf11eabf11eabf11eabf11facf11facf11fac
+f120acf120acf120acf121acf121acf122adf122adf122adf123adf123adf123adf125aef125aef126aef126aef126aef127aef127aef127aef128aff228aff2
+28aff229aff229aff22ab0f22ab0f22ab0f22bb0f22bb0f22bb0f22cb1f22cb1f22eb1f22eb1f22eb1f22fb1f22fb1f22fb1f230b2f230b2f230b2f231b2f231
+b2f232b3f232b3f232b3f233b3f233b3f233b3f234b3f234b3f235b4f235b4f235b4f237b4f237b4f237b4f238b5f238b5f238b5f239b5f339b5f33ab6f33ab6
+f33ab6f33bb6f33bb6f33bb6f33cb6f33cb6f33db7f33db7f33db7f33eb7f33eb7f33eb7f33fb8f33fb8f341b8f341b8f341b8f342b8f342b8f342b8f343b9f3
+43b9f343b9f344b9f344b9f345baf345baf345baf346baf346baf346baf347bbf347bbf348bbf448bbf448bbf449bbf449bbf449bbf44bbcf44bbcf44bbcf44c
+bcf44cbcf44dbdf44dbdf44dbdf44ebdf44ebdf44ebdf44fbdf44fbdf450bef450bef450bef451bef451bef451bef452bff452bff452bff453bff453bff454bf
+f454bff454bff455c0f455c0f455c0f457c0f457c0f458c1f458c1f458c1f459c1f559c1f559c1f55ac1f55ac1f55ac1f55bc2f55bc2f55cc2f55cc2f55cc2f5
+5dc3f55dc3f55dc3f55ec3f55ec3f55fc3f55fc3f55fc3f560c4f560c4f560c4f561c4f561c4f561c4f563c5f563c5f564c5f564c5f564c5f565c6f565c6f565
+c6f566c6f566c6f567c6f567c6f567c6f568c7f668c7f668c7f669c7f669c7f669c7f66ac8f66ac8f66bc8f66bc8f66bc8f66cc8f66cc8f66cc8f66dc9f66dc9
+f66ec9f66ec9f66ec9f66fcaf66fcaf66fcaf670caf670caf670caf672caf672caf673cbf673cbf673cbf674cbf674cbf674cbf675cbf675cbf676ccf676ccf6
+76ccf677ccf677ccf677ccf678cdf778cdf778cdf779cdf779cdf77acdf77acdf77acdf77bcef77bcef77bcef77ccef77ccef77dcff77dcff77dcff77ecff77e
+cff77ecff77fcff77fcff780d0f780d0f780d0f781d0f781d0f781d0f782d1f782d1f782d1f783d1f783d1f785d1f785d1f785d1f786d2f786d2f786d2f787d2
+f787d2f788d3f888d3f888d3f889d3f889d3f889d3f88ad3f88ad3f88ad3f88bd4f88bd4f88cd4f88cd4f88cd4f88dd4f88dd4f88dd4f88ed5f88ed5f88fd5f8
+8fd5f88fd5f890d6f890d6f890d6f891d6f891d6f891d6f892d6f892d6f893d7f893d7f893d7f894d7f894d7f894d7f895d8f895d8f896d8f896d8f896d8f897
+d8f897d8f897d8f898d9f998d9f998d9f999d9f999d9f99ad9f99ad9f99ad9f99bdaf99bdaf99bdaf99cdaf99cdaf99ddbf99ddbf99ddbf99edbf99edbf99edb
+f99fdbf99fdbf99fdbf9a0dcf9a0dcf9a1dcf9a1dcf9a1dcf9a2dcf9a2dcf9a2dcf9a3ddf9a3ddf9a4ddf9a4ddf9a4ddf9a5def9a5def9a5def9a6def9a6def9
+a6def9a7def9a7def9a8dffaa8dffaa8dffaa9dffaa9dffaa9dffaaadffaaadffaabe0faabe0faabe0faace0faace0faace0faade1faade1faade1faaee1faae
+e1faafe1faafe1faafe1fab0e2fab0e2fab0e2fab1e2fab1e2fab2e2fab2e2fab2e2fab3e3fab3e3fab3e3fab4e3fab4e3fab5e3fab5e3fab5e3fab6e4fab6e4
+fab6e4fab7e4fab7e4fab7e4fab8e5fbb8e5fbb9e5fbb9e5fbb9e5fbbae5fbbae5fbbae5fbbbe6fbbbe6fbbce6fbbce6fbbce6fbbde6fbbde6fbbde6fbbee7fb
+bee7fbbee7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc4e9fbc4e9fbc4e9fbc5
+eafbc5eafbc6eafbc6eafbc6eafbc7eafcc7eafcc7eafcc8ebfcc8ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccbecfccbecfccbecfcccecfcccecfccdec
+fccdecfccdecfcceedfcceedfcceedfccfedfccfedfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1eefcd2eefcd2eefcd3effcd3effcd3effc
+d4effcd4effcd4effcd5effcd5effcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd8f0fdd8f0fdd8f0fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fdda
+f1fddbf2fddbf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fddef3fddef3fddef3fddff3fddff3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4
+fde2f4fde2f4fde2f4fde3f5fde3f5fde3f5fde4f5fde4f5fde5f5fde5f5fde5f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fee7f6fee8f6fee8f6fe
+e8f6fee9f7fee9f7fee9f7feeaf7feeaf7feebf7feebf7feebf7feebf8feebf8feebf8feecf8feecf8feecf8feedf8feedf8feeef9feeef9feeef9feeff9feef
+f9feeff9feeff9feeff9fef0f9fef0f9fef0f9fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef5fb
+fef5fbfef5fbfef5fbfef5fbfef6fcfef6fcfef6fcfef7fcfef7fcfef7fcfef8fcfff8fcfff8fdfff8fdfff8fdfff9fdfff9fdfff9fdfffafdfffafdfffafdff
+fafdfffafdfffbfefffbfefffbfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffefefffefefffefefffefffffeffffffffffffffff2e60ffff
+ffeff9febfe7fbbfe7fbbfe7fbbfe7fbc0e7fbc0e7fbc0e7fbc0e7fbc0e7fbc0e7fbc0e8fbc0e8fbc1e8fbc1e8fbc1e8fbc1e8fbc1e8fbc1e8fbc1e8fbc1e8fb
+c1e8fbc1e8fbc1e8fbc2e8fbc2e8fbc2e8fbc2e8fbc2e8fbc2e8fbc2e8fbc2e8fbc3e8fbc3e8fbc3e8fbc3e9fbc3e9fbc3e9fbc3e9fbc3e9fbc3e9fbc3e9fbc3
+e9fbc4e9fbc4e9fbc4e9fbc4e9fbc4e9fbc4e9fbc4e9fbc4e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc5e9fbc6eafbc6ea
+fbc6eafbc6eafbc6eafbc6eafbc6eafbc6eafbc7eafbc7eafbc7eafbc7eafbc7eafbc7eafbc7eafbc7eafbc7eafbc7eafbc7eafbc8eafbc8eafbc8eafbc8eafb
+c8eafbc8eafbc8ebfbc8ebfbc9ebfbc9ebfbc9ebfbc9ebfbc9ebfbc9ebfbc9ebfcc9ebfcc9ebfcc9ebfcc9ebfccaebfccaebfccaebfccaebfccaebfccaebfcca
+ebfccaebfccbebfccbebfccbebfccbebfccbebfccbebfccbecfccbecfccbecfccbecfccbecfcccecfcccecfcccecfcccecfcccecfcccecfcccecfcccecfcccec
+fcccecfcccecfccdecfccdecfccdecfccdecfccdecfccdecfccdecfccdecfcceedfcceedfcceedfcceedfcceedfcceedfcceedfcceedfcceedfcceedfcceedfc
+cfedfccfedfccfedfccfedfccfedfccfedfccfedfccfedfcd0edfcd0edfcd0edfcd0edfcd0edfcd0edfcd0edfcd0edfcd0eefcd0eefcd0eefcd1eefcd1eefcd1
+eefcd1eefcd1eefcd1eefcd1eefcd1eefcd1eefcd1eefcd1eefcd2eefcd2eefcd2eefcd2eefcd2eefcd2eefcd2eefcd2eefcd3eefcd3eefcd3eefcd3eefcd3ee
+fcd3effcd3effcd3effcd3effcd3effcd3effcd4effcd4effcd4effcd4effcd4effcd4effcd4effcd4effcd4effcd4effcd4effcd5effcd5effcd5effcd5effc
+d5effcd5effcd5effcd5effcd6effcd6effcd6effcd6f0fcd6f0fcd6f0fcd6f0fcd6f0fcd6f0fcd6f0fcd6f0fcd7f0fcd7f0fcd7f0fcd7f0fcd7f0fcd7f0fcd7
+f0fcd7f0fcd7f0fcd7f0fcd7f0fcd8f0fcd8f0fcd8f0fcd8f0fcd8f0fcd8f1fcd8f1fcd8f1fcd9f1fcd9f1fcd9f1fcd9f1fcd9f1fcd9f1fdd9f1fdd9f1fdd9f1
+fdd9f1fdd9f1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddaf1fddbf1fddbf1fddbf1fddbf2fddbf2fddbf2fddbf2fddbf2fddbf2fd
+dcf2fddcf2fddcf2fddcf2fddcf2fddcf2fddcf2fddcf2fddcf2fddcf2fdddf2fdddf2fdddf2fdddf2fdddf2fdddf2fdddf2fdddf2fdddf2fdddf2fdddf2fdde
+f2fddef2fddef2fddef3fddef3fddef3fddef3fddef3fddef3fddef3fddef3fddff3fddff3fddff3fddff3fddff3fddff3fddff3fddff3fddff3fddff3fddff3
+fde0f3fde0f3fde0f3fde0f3fde0f3fde0f3fde0f3fde0f3fde1f4fde1f4fde1f4fde1f4fde1f4fde1f4fde1f4fde1f4fde1f4fde1f4fde1f4fde2f4fde2f4fd
+e2f4fde2f4fde2f4fde2f4fde2f4fde2f4fde2f4fde2f4fde2f4fde3f4fde3f4fde3f4fde3f4fde3f4fde3f5fde3f5fde3f5fde3f5fde3f5fde3f5fde4f5fde4
+f5fde4f5fde4f5fde4f5fde4f5fde4f5fde4f5fde4f5fde4f5fde5f5fde5f5fde5f5fde5f5fde5f5fde5f5fde5f5fde5f5fde5f5fde5f5fde5f5fde6f5fde6f5
+fde6f5fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde6f6fde7f6fde7f6fde7f6fde7f6fde7f6fde7f6fde7f6fde7f6fde7f6fde7f6fde7f6fde8f6fd
+e8f6fde8f6fde8f6fde8f6fde8f6fde8f6fde8f6fde8f7fde8f7fde8f7fde9f7fde9f7fde9f7fde9f7fde9f7fde9f7fee9f7fee9f7fee9f7fee9f7fee9f7feea
+f7feeaf7feeaf7feeaf7feeaf7feeaf7feeaf7feeaf7feeaf7feeaf7feeaf7feebf7feebf7feebf7feebf7feebf7feebf8feebf8feebf8feebf8feebf8feecf8
+feecf8feecf8feecf8feecf8feecf8feecf8feecf8feecf8feecf8feecf8feedf8feedf8feedf8feedf8feedf8feedf8feedf8feedf8feedf8feedf8feedf8fe
+eef8feeef8feeef8feeef9feeef9feeef9feeef9feeef9feeef9feeef9feeef9feeff9feeff9feeff9feeff9feeff9feeff9feeff9feeff9feeff9feeff9feef
+f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0f9fef0fafef0fafef1fafef1fafef1fafef1fafef1fafef1fafef1fafef1fa
+fef1fafef1fafef1fafef2fafef2fafef2fafef2fafef2fafef2fafef2fafef2fafef2fafef2fafef2fafef3fafef3fafef3fafef3fafef3fafef3fafef3fafe
+f3fafef3fbfef3fbfef3fbfef3fbfef3fbfef3fbfef4fbfef4fbfef4fbfef4fbfef4fbfef4fbfef4fbfef4fbfef4fbfef4fbfef5fbfef5fbfef5fbfef5fbfef5
+fbfef5fbfef5fbfef5fbfef5fbfef5fbfef5fbfef6fbfef6fbfef6fbfef6fbfef6fbfef6fbfef6fcfef6fcfef6fcfef6fcfef6fcfef6fcfef6fcfef6fcfef7fc
+fef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef7fcfef8fcfef8fcfef8fcfef8fcfef8fcfef8fcfef8fcfef8fcfef8fcfe
+f8fcfef8fcfef9fdfef9fdfef9fdfef9fdfef9fdfef9fdfef9fdfff9fdfff9fdfff9fdfff9fdfff9fdfff9fdfff9fdfffafdfffafdfffafdfffafdfffafdfffa
+fdfffafdfffafdfffafdfffafdfffafdfffafdfffafdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfdfffbfefffbfefffbfe
+fffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffcfefffdfefffdfefffdfefffdfefffdfeff
+fdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffdfefffefefffefefffefefffefefffefefffefffffefffffefffffefffffefffffefffffefffffe
+fffffefffffefffffeffffffffffffffffffffffffffffffffffffffffffffff2e60ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffff2e60040000000601020008000000fa0205000000000000000000040000002d01030004000000f001000007000000fc020000efa00000000004000000
+2d01000004000000f00101000d0000003805010004008200e10182000f02a300f7018200e10108000000fa0205000000000000000000040000002d0101000400
+0000f001030007000000fc020100000000000000040000002d01030004000000f00100000c000000250304008200e10182000f02a300f7018200e10104000000
+0601010007000000fc020000efa000000000040000002d01000004000000f00103000f000000380501000500f20017077603170776034b09f2004b09f2001707
+07000000fc020100000000000000040000002d01030004000000f001000008000000fa02000008000800efa00000040000002d01000004000000f00101009700
+00003805010049000909ff080909ff080809060907090e090609140903091b0900092109fc082709f8082d09f4083209ef083709e9083b09e3083e09dd084109
+d6084409cf084609c8084709c1084709410447094104470939044709320446092b044409250441091f043e0919043b09130437090e04320909042d0905042709
+02042109fe031b09fc031409fa030e09f9030609f903ff08f903d702f903d702f903d002fa03c802fc03c202fe03bb020204b5020504af020904a9020e04a402
+13049f0219049b021f049802250495022b0492023204900239048f0241048f02c1088f02c1088f02c8088f02cf089002d6089202dd089502e3089802e9089b02
+ef089f02f408a402f808a902fc08af020009b5020309bb020609c2020709c8020809d0020909d7020909ff08040000000601020007000000fc02000000000000
+0000040000002d01010004000000f001030008000000fa0205000000000000000000040000002d01030004000000f00100003f000000380501001d00c2058a0b
+be058a0bbc05800bbc05800bbb057a0bbb057a0bbb057a0bba05800bb7058a0bb4058a0baf05760bb205760bb405800bb405800bb505870bb605870bb605870b
+b705810bb905760bbc05760bbf05810bbf05810bc005870bc005870bc005870bc105800bc305760bc605760bc2058a0b04000000060102003f00000038050100
+1d00e0058a0bdc058a0bda05800bda05800bd9057a0bd9057a0bd9057a0bd705800bd5058a0bd2058a0bcd05760bd005760bd205800bd205800bd305870bd305
+870bd305870bd505810bd705760bda05760bdd05810bdd05810bde05870bde05870bde05870bdf05800be105760be405760be0058a0b04000000060102003f00
+0000380501001d00fd058a0bfa058a0bf805800bf805800bf7057a0bf6057a0bf6057a0bf505800bf3058a0bf0058a0beb05760bee05760bf005800bf005800b
+f105870bf105870bf105870bf305810bf505760bf805760bfb05810bfb05810bfc05870bfc05870bfc05870bfd05800bff05760b0206760bfd058a0b04000000
+0601020021000000380501000e000d06880b0d06880b0c068a0b0b068b0b0b068b0b09068a0b0806880b0806880b0906870b0b06860b0b06860b0c06870b0d06
+880b0d06880b0400000006010200170000003805010009002206780b1c06780b1c068a0b1a068a0b1a06780b1406780b1406760b2206760b2206780b04000000
+0601020060000000380502001d00100034068a0b34068a0b3306870b3306870b2f06820b2f06820b2d06810b2d068a0b2a068a0b2a06760b3006760b3006760b
+3306760b3506770b3506770b3606790b37067b0b37067b0b36067e0b35067f0b3306810b3106810b3106810b3306830b3306830b3506850b3506850b38068a0b
+34068a0b3206780b3206780b2f06780b2d06780b2d067f0b2f067f0b2f067f0b31067f0b33067e0b33067e0b33067d0b34067b0b34067b0b3306790b3206780b
+3206780b040000000601020041000000380501001e004d06880b4d06880b4b068a0b47068b0b47068b0b43068a0b4106880b4106880b4006840b4006760b4306
+760b4306830b4306830b4306850b4406870b4406870b4506880b4706880b4706880b4906880b4b06870b4b06870b4b06830b4b06760b4e06760b4e06840b4e06
+840b4e06870b4d06880b4d06880b04000000060102001f000000380501000d0059068a0b5906760b6406760b6306780b5c06780b5c067e0b62067e0b6206810b
+5c06810b5c06880b6406880b64068a0b59068a0b04000000060102005700000038050100290074068b0b74068b0b71068a0b6e06870b6e06870b6c06840b6c06
+800b6c06800b6c067d0b6d067a0b6d067a0b6e06780b7006760b7206760b7506750b7506750b7706760b7a06770b7806790b7806790b7606780b7506780b7506
+780b7206780b70067a0b70067a0b6f067d0b6f06800b6f06800b7006850b7006850b7206870b7506880b7506880b7706880b7906870b7a06890b7a06890b7706
+8a0b74068b0b74068b0b04000000060102000f00000038050100050085068a0b8506760b8206760b82068a0b85068a0b04000000060102006000000038050200
+1d0010009a068a0b9a068a0b9906870b9906870b9506820b9506820b9306810b93068a0b90068a0b9006760b9606760b9606760b9906760b9b06770b9b06770b
+9c06790b9d067b0b9d067b0b9d067e0b9c067f0b9a06810b9706810b9706810b9906830b9906830b9b06850b9b06850b9e068a0b9a068a0b9806780b9806780b
+9606780b9306780b93067f0b95067f0b95067f0b98067f0b99067e0b99067e0b9a067d0b9a067b0b9a067b0b9906790b9806780b9806780b0400000006010200
+57000000380501002900ae068b0bae068b0bab068a0ba806870ba806870ba606840ba606800ba606800ba6067d0ba7067a0ba7067a0ba806780baa06760bac06
+760bae06750bae06750bb106760bb306770bb206790bb206790bb006780bae06780bae06780bac06780baa067a0baa067a0ba9067d0ba906800ba906800ba906
+850ba906850bac06870baf06880baf06880bb106880bb206870bb406890bb406890bb1068a0bae068b0bae068b0b040000000601020041000000380501001e00
+c906880bc906880bc7068a0bc3068b0bc3068b0bbf068a0bbd06880bbd06880bbc06840bbc06760bbf06760bbf06830bbf06830bbf06850bc006870bc006870b
+c106880bc306880bc306880bc506880bc606870bc606870bc706830bc706760bca06760bca06840bca06840bca06870bc906880bc906880b0400000006010200
+0f000000380501000500d5068a0bd506760bd806760bd8068a0bd5068a0b040000000601020017000000380501000900ee06780be806780be8068a0be5068a0b
+e506780be006780be006760bee06760bee06780b040000000601020067000000380501003100fb068b0bfb068b0bf7068a0bf406890bf506870bf506870bf806
+880bfb06880bfb06880bfe06870bff06860bff06850bff06850bfe06830bfc06810bfa06810bfa06810bf6067f0bf5067d0bf5067b0bf5067b0bf506790bf706
+770bf906760bfc06750bfc06750bff06760b0207770b0107790b0107790bfe06780bfc06780bfc06780bf906780bf8067b0bf8067b0bf9067d0bfb067e0bfe06
+7e0bfe067e0b0107800b0207820b0307840b0307840b0207860b0107890bfe068a0bfb068b0bfb068b0b040000000601020021000000380501000e000d07860b
+0d07860b0c07870b0b07880b0b07880b0c078a0b0d078b0b0d078b0b0f078a0b0f07880b0f07880b0f07870b0d07860b0d07860b040000000601020057000000
+3805010029002607890b2407870b2407870b2307880b2007880b2007880b1d07870b1b07850b1b07850b1b07800b1b07800b1b077d0b1c077a0b1c077a0b1d07
+780b2007780b2007780b2207780b2407790b2507770b2507770b2307760b2007750b2007750b1e07760b1c07760b1a07780b19077a0b19077a0b18077d0b1707
+800b1707800b1807840b1a07870b1a07870b1c078a0b20078b0b20078b0b23078a0b2607890b2607890b04000000060102005e00000038050200160016003507
+8b0b35078b0b31078a0b2f07880b2d07840b2c07800b2c07800b2d077b0b2f07780b3107760b3507750b3507750b3907760b3b07780b3d077c0b3d07800b3d07
+800b3d07840b3b07880b38078a0b35078b0b35078b0b3507770b3507770b3207780b31077a0b30077c0b3007800b3007800b3007830b3107860b3207880b3507
+880b3507880b3707880b3907870b3a07840b3a07800b3a07800b3a077d0b39077a0b3707780b3507770b3507770b04000000060102003f000000380501001d00
+57078a0b56077c0b56077c0b5607790b5607790b5607790b55077c0b51078a0b4f078a0b4b077d0b4b077d0b4a07790b4a07790b4a07790b4a077d0b49078a0b
+46078a0b4807760b4c07760b4f07820b4f07820b5007860b5007860b5007860b5107820b5507760b5907760b5a078a0b57078a0b04000000060102000f000000
+38050100050065078f0b63078f0b6b07730b6d07730b65078f0b04000000060102004c00000038050200130010008107810b8107810b8007820b7d07820b7a07
+820b7a078a0b77078a0b7707760b7c07760b7c07760b7f07760b8107770b8107770b8307790b84077c0b84077c0b83077f0b8107810b8107810b8007790b8007
+790b7e07780b7c07780b7a07780b7a07800b7d07800b7d07800b7f07800b80077f0b80077f0b81077c0b81077c0b80077a0b8007790b8007790b040000000601
+020060000000380502001d00100096078a0b96078a0b9407870b9407870b9107820b9107820b8f07810b8f078a0b8c078a0b8c07760b9207760b9207760b9507
+760b9707770b9707770b9807790b99077b0b99077b0b98077e0b97077f0b9507810b9307810b9307810b9507830b9507830b9707850b9707850b9a078a0b9607
+8a0b9407780b9407780b9107780b8f07780b8f077f0b91077f0b91077f0b93077f0b95077e0b95077e0b95077d0b96077b0b96077b0b9507790b9407780b9407
+780b04000000060102005e0000003805020016001600aa078b0baa078b0ba6078a0ba307880ba207840ba107800ba107800ba2077b0ba307780ba607760ba907
+750ba907750bad07760bb007780bb1077c0bb207800bb207800bb107840bb007880bad078a0baa078b0baa078b0ba907770ba907770ba707780ba5077a0ba507
+7c0ba407800ba407800ba507830ba507860ba707880baa07880baa07880bac07880bad07870bae07840baf07800baf07800bae077d0bad077a0bac07780ba907
+770ba907770b04000000060102004a0000003805020011001100c707870bc707870bc5078a0bc1078a0bbb078a0bbb07760bc007760bc007760bc507760bc807
+790bc807790bc9077c0bca07800bca07800bc907840bc707870bc707870bc5077a0bc5077a0bc307780bc107780bbe07780bbe07880bc107880bc107880bc407
+870bc507860bc507860bc607830bc707800bc707800bc6077d0bc5077a0bc5077a0b040000000601020041000000380501001e00e007880be007880bde078a0b
+da078b0bda078b0bd6078a0bd407880bd407880bd307840bd307760bd607760bd607830bd607830bd607850bd707870bd707870bd807880bda07880bda07880b
+dc07880bde07870bde07870bde07830bde07760be107760be107840be107840be107870be007880be007880b040000000601020057000000380501002900f307
+8b0bf3078b0bef078a0bed07870bed07870beb07840bea07800bea07800beb077d0bec077a0bec077a0bed07780bef07760bf107760bf307750bf307750bf607
+760bf807770bf707790bf707790bf507780bf307780bf307780bf107780bef077a0bef077a0bee077d0bee07800bee07800bee07850bee07850bf007870bf307
+880bf307880bf607880bf707870bf907890bf907890bf6078a0bf3078b0bf3078b0b0400000006010200170000003805010009000d08760bff07760bff07780b
+0408780b04088a0b07088a0b0708780b0d08780b0d08760b04000000060102000f00000038050100050012088e0b12088d0b21088d0b21088e0b12088e0b0400
+0000060102003f000000380501001d003a088a0b39087c0b39087c0b3908790b3808790b3808790b38087c0b34088a0b31088a0b2d087d0b2d087d0b2c08790b
+2c08790b2c08790b2c087d0b2b088a0b28088a0b2a08760b2e08760b3208820b3208820b3208860b3208860b3208860b3308820b3708760b3b08760b3d088a0b
+3a088a0b040000000601020028000000380502000900080052088a0b5008840b4908840b47088a0b44088a0b4a08760b4e08760b55088a0b52088a0b4c08780b
+4c08780b4c08780b4908820b4f08820b4f08820b4c08780b4c08780b0400000006010200170000003805010009006708780b6108780b61088a0b5f088a0b5f08
+780b5908780b5908760b6708760b6708780b040000000601020060000000380502001d00100079088a0b79088a0b7808870b7808870b7408820b7408820b7208
+810b72088a0b6f088a0b6f08760b7508760b7508760b7808760b7a08770b7a08770b7b08790b7c087b0b7c087b0b7b087e0b7a087f0b7908810b7608810b7608
+810b7808830b7808830b7a08850b7a08850b7d088a0b79088a0b7708780b7708780b7408780b7208780b72087f0b74087f0b74087f0b76087f0b78087e0b7808
+7e0b78087d0b79087b0b79087b0b7808790b7708780b7708780b04000000060102000f00000038050100050086088a0b8608760b8908760b89088a0b86088a0b
+04000000060102001f000000380501000d009d088a0b9908810b94088a0b91088a0b97087f0b9108760b9508760b99087d0b9c08760ba008760b9a087f0ba108
+8a0b9d088a0b040000000601020021000000380501000e00aa08860baa08860ba808870ba808880ba808880ba8088a0baa088b0baa088b0bab088a0bac08880b
+ac08880bab08870baa08860baa08860b04000000060102001f000000380501000d00c0088a0bc008800bb808800bb8088a0bb6088a0bb608760bb808760bb808
+7e0bc0087e0bc008760bc308760bc3088a0bc0088a0b040000000601020017000000380501000900d908780bd408780bd4088a0bd1088a0bd108780bcc08780b
+cc08760bd908760bd908780b04000000060102003f000000380501001d00f2088a0bf1087c0bf1087c0bf008790bf008790bf008790bf0087c0bec088a0be908
+8a0be5087d0be5087d0be408790be408790be408790be4087d0be3088a0be0088a0be208760be608760bea08820bea08820bea08860bea08860bea08860beb08
+820bef08760bf308760bf5088a0bf2088a0b0400000006010200130000003805010007000909880b0109880b0109760bfe08760bfe088a0b09098a0b0909880b
+0400000006010200170000003805010009009000780b8b00780b8b008a0b88008a0b8800780b8300780b8300760b9000760b9000780b04000000060102006000
+0000380502001d001000a3008a0ba3008a0ba100870ba100870b9d00820b9d00820b9b00810b9b008a0b99008a0b9900760b9e00760b9e00760ba100760ba300
+770ba300770ba500790ba5007b0ba5007b0ba5007e0ba4007f0ba200810ba000810ba000810ba100830ba100830ba300850ba300850ba6008a0ba3008a0ba000
+780ba000780b9e00780b9b00780b9b007f0b9d007f0b9d007f0ba0007f0ba1007e0ba1007e0ba2007d0ba2007b0ba2007b0ba200790ba000780ba000780b0400
+00000601020041000000380501001e00bc00880bbc00880bb9008a0bb6008b0bb6008b0bb2008a0baf00880baf00880baf00840baf00760bb200760bb200830b
+b200830bb200850bb200870bb200870bb400880bb600880bb600880bb800880bb900870bb900870bba00830bba00760bbd00760bbd00840bbd00840bbd00870b
+bc00880bbc00880b04000000060102001f000000380501000d00c7008a0bc700760bd200760bd200780bca00780bca007e0bd1007e0bd100810bca00810bca00
+880bd300880bd3008a0bc7008a0b040000000601020057000000380501002900ef008b0bef008b0beb008a0be800870be800870be600840be600800be600800b
+e6007d0be7007a0be7007a0be900780bea00760bec00760bef00750bef00750bf100760bf400770bf200790bf200790bf100780bef00780bef00780bec00780b
+ea007a0bea007a0be9007d0be900800be900800bea00850bea00850bec00870bef00880bef00880bf100880bf300870bf400890bf400890bf1008a0bef008b0b
+ef008b0b04000000060102000f000000380501000500fd008a0bfd00760bff00760bff008a0bfd008a0b040000000601020060000000380502001d0010001501
+8a0b15018a0b1301870b1301870b0f01820b0f01820b0d01810b0d018a0b0b018a0b0b01760b1001760b1001760b1301760b1501770b1501770b1601790b1701
+7b0b17017b0b17017e0b16017f0b1401810b1201810b1201810b1301830b1301830b1501850b1501850b18018a0b15018a0b1201780b1201780b1001780b0d01
+780b0d017f0b0f017f0b0f017f0b12017f0b13017e0b13017e0b14017d0b14017b0b14017b0b1401790b1201780b1201780b0400000006010200570000003805
+0100290028018b0b28018b0b25018a0b2201870b2201870b2001840b2001800b2001800b20017d0b21017a0b21017a0b2201780b2401760b2601760b2801750b
+2801750b2b01760b2d01770b2c01790b2c01790b2a01780b2801780b2801780b2601780b24017a0b24017a0b23017d0b2301800b2301800b2401850b2401850b
+2601870b2901880b2901880b2b01880b2c01870b2e01890b2e01890b2b018a0b28018b0b28018b0b040000000601020041000000380501001e004301880b4301
+880b41018a0b3d018b0b3d018b0b39018a0b3701880b3701880b3601840b3601760b3901760b3901830b3901830b3901850b3a01870b3a01870b3b01880b3d01
+880b3d01880b3f01880b4001870b4001870b4101830b4101760b4401760b4401840b4401840b4401870b4301880b4301880b04000000060102000f0000003805
+010005004f018a0b4f01760b5201760b52018a0b4f018a0b0400000006010200170000003805010009006801780b6201780b62018a0b60018a0b6001780b5a01
+780b5a01760b6801760b6801780b04000000060102006700000038050100310075018b0b75018b0b71018a0b6e01890b6f01870b6f01870b7201880b7501880b
+7501880b7801870b7901860b7901850b7901850b7901830b7601810b7401810b7401810b70017f0b6f017d0b6f017b0b6f017b0b6f01790b7101770b7301760b
+7601750b7601750b7901760b7c01770b7b01790b7b01790b7801780b7601780b7601780b7301780b72017b0b72017b0b73017d0b75017e0b78017e0b78017e0b
+7b01800b7c01820b7d01840b7d01840b7c01860b7b01890b78018a0b75018b0b75018b0b04000000060102002d00000038050100140086018f0b85018d0b8501
+8d0b86018c0b87018b0b87018b0b86018a0b86018a0b85018a0b8501880b8501880b8501870b8701860b8701860b8901870b8901890b8901890b88018c0b8601
+8f0b86018f0b04000000060102000f0000003805010005009f018a0b9f01760ba101760ba1018a0b9f018a0b04000000060102002f000000380501001500b701
+8a0bb2017f0bb2017f0baf017a0baf017a0baf017a0baf017f0baf018a0bad018a0bad01760bb001760bb601810bb601810bb801860bb801860bb801860bb801
+800bb801760bba01760bba018a0bb7018a0b040000000601020057000000380501002900cc018b0bcc018b0bc8018a0bc601870bc601870bc401840bc301800b
+c301800bc4017d0bc5017a0bc5017a0bc601780bc801760bca01760bcc01750bcc01750bcf01760bd101770bd001790bd001790bce01780bcc01780bcc01780b
+c901780bc8017a0bc8017a0bc7017d0bc701800bc701800bc701850bc701850bc901870bcc01880bcc01880bce01880bd001870bd201890bd201890bcf018a0b
+cc018b0bcc018b0b040000000601020021000000380501000e00dd01880bdd01880bdd018a0bdb018b0bdb018b0bda018a0bd901880bd901880bda01870bdb01
+860bdb01860bdd01870bdd01880bdd01880b040000000601020057000000380501002900fa018b0bfa018b0bf6018a0bf401870bf401870bf201840bf101800b
+f101800bf2017d0bf3017a0bf3017a0bf401780bf601760bf801760bfa01750bfa01750bfd01760bff01770bfe01790bfe01790bfc01780bfa01780bfa01780b
+f701780bf6017a0bf6017a0bf5017d0bf501800bf501800bf501850bf501850bf701870bfa01880bfa01880bfd01880bfe01870b0002890b0002890bfd018a0b
+fa018b0bfa018b0b04000000060102005e00000038050200160016000f028b0b0f028b0b0b028a0b0902880b0702840b0602800b0602800b07027b0b0902780b
+0b02760b0f02750b0f02750b1302760b1502780b17027c0b1702800b1702800b1702840b1502880b12028a0b0f028b0b0f028b0b0f02770b0f02770b0c02780b
+0b027a0b0a027c0b0a02800b0a02800b0a02830b0b02860b0c02880b0f02880b0f02880b1102880b1302870b1402840b1402800b1402800b14027d0b13027a0b
+1102780b0f02770b0f02770b04000000060102002f0000003805010015002b028a0b26027f0b26027f0b23027a0b23027a0b23027a0b23027f0b23028a0b2102
+8a0b2102760b2402760b2a02810b2a02810b2c02860b2c02860b2c02860b2c02800b2c02760b2e02760b2e028a0b2b028a0b04000000060102001b0000003805
+01000b004402780b3c02780b3c027e0b42027e0b4202810b3c02810b3c028a0b39028a0b3902760b4402760b4402780b04000000060102000f00000038050100
+05004c028a0b4c02760b4f02760b4f028a0b4c028a0b04000000060102004c00000038050200120011006602870b6602870b64028a0b5f028a0b5a028a0b5a02
+760b5f02760b5f02760b6302760b6502770b6702790b6702790b68027c0b6902800b6902800b6802840b6602870b6602870b64027a0b64027a0b6202780b5f02
+780b5d02780b5d02880b5f02880b5f02880b6202870b6402860b6402860b6502830b6502800b6502800b65027d0b64027a0b64027a0b04000000060102001f00
+0000380501000d0072028a0b7202760b7d02760b7d02780b7502780b75027e0b7c027e0b7c02810b7502810b7502880b7e02880b7e028a0b72028a0b04000000
+060102002f00000038050100150092028a0b8c027f0b8c027f0b8a027a0b8a027a0b8a027a0b8a027f0b8a028a0b87028a0b8702760b8a02760b9002810b9002
+810b9202860b9202860b9202860b9202800b9202760b9502760b95028a0b92028a0b040000000601020017000000380501000900ab02780ba502780ba5028a0b
+a2028a0ba202780b9d02780b9d02760bab02760bab02780b04000000060102000f000000380501000500b3028a0bb302760bb602760bb6028a0bb3028a0b0400
+000006010200280000003805020009000800cc028a0bca02840bc302840bc1028a0bbe028a0bc502760bc802760bcf028a0bcc028a0bc602780bc602780bc602
+780bc302820bc902820bc902820bc602780bc602780b040000000601020013000000380501000700e1028a0bd7028a0bd702760bd902760bd902880be102880b
+e1028a0b04000000060102000f000000380501000500f5028a0bf502760bf802760bf8028a0bf5028a0b04000000060102002f0000003805010015000d038a0b
+08037f0b08037f0b05037a0b05037a0b05037a0b05037f0b05038a0b03038a0b0303760b0603760b0c03810b0c03810b0e03860b0e03860b0e03860b0e03800b
+0e03760b1003760b10038a0b0d038a0b04000000060102001b000000380501000b002603780b1e03780b1e037e0b24037e0b2403810b1e03810b1e038a0b1b03
+8a0b1b03760b2603760b2603780b04000000060102005e000000380502001600160035038b0b35038b0b31038a0b2f03880b2d03840b2d03800b2d03800b2d03
+7b0b2f03780b3203760b3503750b3503750b3903760b3c03780b3d037c0b3e03800b3e03800b3d03840b3b03880b39038a0b35038b0b35038b0b3503770b3503
+770b3303780b31037a0b30037c0b3003800b3003800b3003830b3103860b3303880b3503880b3503880b3703880b3903870b3a03840b3a03800b3a03800b3a03
+7d0b39037a0b3803780b3503770b3503770b040000000601020060000000380502001d00100051038a0b51038a0b4f03870b4f03870b4c03820b4c03820b4a03
+810b4a038a0b47038a0b4703760b4d03760b4d03760b5003760b5203770b5203770b5303790b54037b0b54037b0b53037e0b52037f0b5003810b4e03810b4e03
+810b5003830b5003830b5203850b5203850b55038a0b51038a0b4f03780b4f03780b4c03780b4a03780b4a037f0b4c037f0b4c037f0b4e037f0b50037e0b5003
+7e0b50037d0b51037b0b51037b0b5003790b4f03780b4f03780b04000000060102003f000000380501001d006e038a0b6d037c0b6d037c0b6d03790b6d03790b
+6d03790b6c037c0b68038a0b66038a0b62037d0b62037d0b6103790b6103790b6103790b61037d0b60038a0b5d038a0b5f03760b6303760b6603820b6603820b
+6703860b6703860b6703860b6803820b6b03760b6f03760b71038a0b6e038a0b040000000601020028000000380502000900080086038a0b8403840b7d03840b
+7b038a0b78038a0b7f03760b8303760b89038a0b86038a0b8103780b8103780b8103780b7e03820b8303820b8303820b8103780b8103780b0400000006010200
+170000003805010009009b03780b9603780b96038a0b93038a0b9303780b8e03780b8e03760b9c03760b9b03780b04000000060102000f000000380501000500
+a7038a0ba703760ba403760ba4038a0ba7038a0b04000000060102005e0000003805020016001600b9038b0bb9038b0bb5038a0bb203880bb103840bb003800b
+b003800bb1037b0bb203780bb503760bb803750bb803750bbc03760bbf03780bc0037c0bc103800bc103800bc003840bbf03880bbc038a0bb9038b0bb9038b0b
+b803770bb803770bb603780bb4037a0bb4037c0bb303800bb303800bb403830bb403860bb603880bb903880bb903880bbb03880bbc03870bbd03840bbe03800b
+be03800bbd037d0bbc037a0bbb03780bb803770bb803770b04000000060102002f000000380501001500d5038a0bcf037f0bcf037f0bcd037a0bcd037a0bcd03
+7a0bcd037f0bcd038a0bca038a0bca03760bce03760bd303810bd303810bd503860bd503860bd503860bd503800bd503760bd803760bd8038a0bd5038a0b0400
+00000601010007000000fc020000facf8a000000040000002d01000004000000f0010100f50000003805010078006009f90b6009ea0b0c09ea0b0c09a50baa08
+a50baa08ea0b6c08ea0b6c08a50b0b08a50b0b08ea0bcd07ea0bcd07a50b6c07a50b6c07ea0b2e07ea0b2e07a50bcd06a50bcd06ea0b8f06ea0b8f06a50b2d06
+a50b2d06ea0bf005ea0bf005a50b8e05a50b8e05ea0b5005ea0b5005a50bef04a50bef04ea0bb104ea0bb104a50b5004a50b5004ea0b1204ea0b1204a50bb103
+a50bb103ea0b7303ea0b7303a50b1103a50b1103ea0bc202ea0bc202ea0bc202a50b6002a50b6002ea0b2302ea0b2302a50bc101a50bc101ea0b8301ea0b8301
+a50b2201a50b2201ea0be400ea0be400a50b8300a50b8300ea0b3000ea0b3000f90b9500f90b9500b40bd200b40bd200f90b3401f90b3401b40b7201b40b7201
+b40b7201f90b7201f90bd301f90bd301b40b1102b40b1102f90b7202f90b7202b40bb002b40bb002f90b2303f90b2303b40b6103b40b6103f90bc203f90bc203
+b40b0004b40b0004f90b6204f90b6204b40b9f04b40b9f04f90b0105f90b0105b40b3f05b40b3f05f90ba005f90ba005b40bde05b40bde05f90b3f06f90b3f06
+b40b7d06b40b7d06f90bde06f90bde06b40b1c07b40b1c07f90b7e07f90b7e07b40bbb07b40bbb07f90b1d08f90b1d08b40b5b08b40b5b08f90bbc08f90bbc08b40bfa08b40bfa08f90b6009f90b04000000f001000004000000f001020004000000f00103000300000000000000}
+}}{\sp{\sn pibFlags}{\sv 2}}{\sp{\sn fLine}{\sv 0}}{\sp{\sn posh}{\sv 2}}{\sp{\sn posrelh}{\sv 0}}{\sp{\sn posv}{\sv 2}}{\sp{\sn posrelv}{\sv 0}}{\sp{\sn fLayoutInCell}{\sv 1}}{\sp{\sn fLayoutInCell}{\sv 1}}}{\shprslt\par\pard
+\ql \li0\ri0\widctlpar\phmrg\posxc\posyc\dxfrtext180\dfrmtxtx180\dfrmtxty0\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \par}}
+\par }}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/abi3623.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/abi3623.rtf
new file mode 100644
index 000000000..a47161a2f
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/abi3623.rtf
@@ -0,0 +1,7 @@
+{\rtf1
+{\stylesheet
+{\s2\ls1\sbasedon0 heading 2;}
+}
+\s2
+foo\par
+}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/abi4817.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/abi4817.rtf
new file mode 100644
index 000000000..58d88f5ff
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/abi4817.rtf
@@ -0,0 +1,6 @@
+{\rtf1
+\super
+{
+\par
+\par }
+}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/fdo49666.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/fdo49666.rtf
new file mode 100644
index 000000000..5a673ca04
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/fdo49666.rtf
@@ -0,0 +1,13 @@
+{\rtf1 \ansi \ansicpg1252 \uc1 \deff1 \deflang1033 \deflangfe1033
+{\shp
+{\*\shpinst \shpleft144 \shptop490 \shpright2049 \shpbottom1840 \shpfhdr1 \shpbxcolumn \shpbypara \shpwr4 \shpwrk2 \shpfblwtxt1 \shpz0 \shplid2053
+{\sp
+{\sn shapeType}
+{\sv 75}
+}
+{\shptxt foo
+}
+}
+}
+\par
+}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/fdo64656.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/fdo64656.rtf
new file mode 100644
index 000000000..1c815c4e7
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/fdo64656.rtf
@@ -0,0 +1,10 @@
+{\rtf
+{\*\listtable
+{\list \listtemplateid3794224 \listhybrid
+{\listlevel \levelnfc0 \levelnfcn0 \leveljc0 \leveljcn0 \levelstartat1 \levelfollow0 \levelspace0 \levelindent0 \levellegal0 \levelnorestart0
+{\levelnumbers ;}
+}
+{\listname ;}
+\listid258183 }
+}
+}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/i74153.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/i74153.rtf
new file mode 100644
index 000000000..7e81865ad
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/i74153.rtf
@@ -0,0 +1,8 @@
+{\rtf1
+{\*\revtbl
+{Unknown;}
+{TAMUS HSC Mac User;}
+}
+{\revised\super\revauth1\revdttm-1501115711 hello}
+\par
+}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/i84172.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/i84172.rtf
new file mode 100644
index 000000000..ce6616e5e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/i84172.rtf
@@ -0,0 +1,11 @@
+{\rtf1
+{\*\revtbl
+{Unknown;}
+}
+\par \pard\plain
+{
+{\revised\revauth1\revdttm-1497631607 foo
+{bar}
+}
+}
+}
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/parser-state-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/parser-state-1.rtf
new file mode 100644
index 000000000..3fe4b2876
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/parser-state-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/rhbz960019.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/rhbz960019.rtf
new file mode 100644
index 000000000..869aa339b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/rhbz960019.rtf
@@ -0,0 +1,12 @@
+{\rtf1
+{\*\listtable
+{\list\listtemplateid-723955400\listsimple{\listlevel\leveljc\levelfollow0\levelspace0\levelindent0\levelstartat1{\leveltext\'03\'00. ;}{\levelnumbers\'01;}\f0 }{\listname ;}\listid-1155484576}
+}
+{\*\listoverridetable
+{\*\listoverride{\listid-1155484576\listoverridecount0\ls1}}
+}
+\pard\plain \pvpg\phpg\posx1143\posy4743\absw9615\absh-2922\dfrmtxtx72\dfrmtxty72\nowrap
+Hello\par
+\pard\plain\par
+}
+
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-101375-minimized.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-101375-minimized.rtf
new file mode 100644
index 000000000..c3ffebc2b
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-101375-minimized.rtf
@@ -0,0 +1,62 @@
+{\rtf1\ansi\deff0\adeflang1025
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset128 Times New Roman;}{\f4\froman\fprq2\fcharset128 Arial Narrow;}{\f5\froman\fprq0\fcharset128 Arial Narrow;}{\f6\froman\fprq2\fcharset128 Symbol;}{\f7\froman\fprq0\fcharset128 Symbol;}{\f8\froman\fprq2\fcharset128 Wingdings;}{\f9\froman\fprq0\fcharset128 Wingdings;}{\f10\froman\fprq0\fcharset128 Times New Roman;}{\f11\fnil\fprq2\fcharset0 Microsoft YaHei;}{\f12\fnil\fprq2\fcharset128 SimSun;}{\f13\fnil\fprq2\fcharset128 Times New Roman (Arabic);}{\f14\fnil\fprq0\fcharset128 Times New Roman (Arabic);}{\f15\fnil\fprq2\fcharset128 Times New Roman;}{\f16\fnil\fprq0\fcharset128 Times New Roman;}{\f17\fnil\fprq2\fcharset0 Mangal;}{\f18\fnil\fprq0\fcharset128 Mangal;}{\f19\fnil\fprq2\fcharset128 Mangal;}{\f20\fnil\fprq2\fcharset128 Cambria Math;}{\f21\fnil\fprq0\fcharset128 Cambria Math;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red128\green128\blue128;}
+{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040 Predefinito;}
+{\s15\sbasedon0\snext16\sb240\sa120\keepn\hich\af11\dbch\af17\afs28\loch\f2\fs28 Intestazione;}
+{\s16\sbasedon0\snext16\sb0\sa120 Corpo testo;}
+{\s17\sbasedon16\snext17\sb0\sa120\dbch\af18 Elenco;}
+{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af18\afs24\ai\fs24 Didascalia;}
+{\s19\sbasedon0\snext19\noline\dbch\af18 Indice;}
+}{\info{\creatim\yr2011\mo9\dy28\hr16\min28}{\revtim\yr2011\mo9\dy28\hr16\min29}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3500}}\deftab720
+
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1417\margbsxn1134\pgdscnxt0 Predefinito;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1134\margr1134\margt1417\margb1134\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1417\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx9864\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\keepn{\scaps\b\hich\af14\langfe1040\dbch\af14\afs26\alang1025\ab\rtlch \ltrch\loch\fs26\lang1040\loch\f5
+SSSSSSS SSSSSSS curriculum vitae}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\langfe1040\dbch\af14\afs16\alang1025\rtlch \ltrch\loch\fs16\lang1040\loch\f5
+}\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\keepn{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+Informazioni personali}\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Nome}\cell\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSS SSSSSSS}\cell\cell\row\pard\trowd\trql\trleft-108\ltrrow\trrh876\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvert`lt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\h{phmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Indirizzo}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSS S. SSSSSSSS SSSS}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40[\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSS SSSSS SSSSSS}\cell\row\pard\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Telefono}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSSSSS}\cell\row\pard\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\langfe1040\dbch\af14\afs22\alang1025\rtlch \ltrch\loch\fs22\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+}\cell\row\pard\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+E-mail}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSSSSSSSSSSSSSSSSS}\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb120\sa0{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Nazionalit\'e0}\cell\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSSS}\cell\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Luogo e Data di nascita}\cell\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSS SSSSSSSSSS }\cell\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par } \ No newline at end of file
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-108116-minimized.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-108116-minimized.rtf
new file mode 100644
index 000000000..9576906da
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_2063317381c4a46d642c79a4b1817dc0-108116-minimized.rtf
@@ -0,0 +1,62 @@
+{\rtf1\ansi\deff0\adeflang1025
+{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset128 Times New Roman;}{\f4\froman\fprq2\fcharset128 Arial Narrow;}{\f5\froman\fprq0\fcharset128 Arial Narrow;}{\f6\froman\fprq2\fcharset128 Symbol;}{\f7\froman\fprq0\fcharset128 Symbol;}{\f8\froman\fprq2\fcharset128 Wingdings;}{\f9\froman\fprq0\fcharset128 Wingdings;}{\f10\froman\fprq0\fcharset128 Times New Roman;}{\f11\fnil\fprq2\fcharset0 Microsoft YaHei;}{\f12\fnil\fprq2\fcharset128 SimSun;}{\f13\fnil\fprq2\fcharset128 Times New Roman (Arabic);}{\f14\fnil\fprq0\fcharset128 Times New Roman (Arabic);}{\f15\fnil\fprq2\fcharset128 Times New Roman;}{\f16\fnil\fprq0\fcharset128 Times New Roman;}{\f17\fnil\fprq2\fcharset0 Mangal;}{\f18\fnil\fprq0\fcharset128 Mangal;}{\f19\fnil\fprq2\fcharset128 Mangal;}{\f20\fnil\fprq2\fcharset128 Cambria Math;}{\f21\fnil\fprq0\fcharset128 Cambria Math;}}
+{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red128\green128\blue128;}
+{\stylesheet{\s0\snext0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040 Predefinito;}
+{\s15\sbasedon0\snext16\sb240\sa120\keepn\hich\af11\dbch\af17\afs28\loch\f2\fs28 Intestazione;}
+{\s16\sbasedon0\snext16\sb0\sa120 Corpo testo;}
+{\s17\sbasedon16\snext17\sb0\sa120\dbch\af18 Elenco;}
+{\s18\sbasedon0\snext18\sb120\sa120\noline\i\dbch\af18\afs24\ai\fs24 Didascalia;}
+{\s19\sbasedon0\snext19\noline\dbch\af18 Indice;}
+}{\info{\creatim\yr2011\mo9\dy28\hr16\min28}{\revtim\yr2011\mo9\dy28\hr16\min29}{\printim\yr0\mo0\dy0\hr0\min0}{\comment LibreOffice}{\vern3500}}\deftab720
+
+{\*\pgdsctbl
+{\pgdsc0\pgdscuse195\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1417\margbsxn1134\pgdscnxt0 Predefinito;}}
+\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1134\margr1134\margt1417\margb1134\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1417\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
+\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx9864\pgndec\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\keepn{\scaps\b\hich\af14\langfe1040\dbch\af14\afs26\alang1025\ab\rtlch \ltrch\loch\fs26\lang1040\loch\f5
+SSSSSSS SSSSSSS curriculum vitae}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\langfe1040\dbch\af14\afs16\alang1025\rtlch \ltrch\loch\fs16\lang1040\loch\f5
+}\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\keepn{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+Informazioni personali}\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Nome}\cell\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSS SSSSSSS}\cell\cell\row\pard\trowd\trql\trleft-108\ltrrow\trrh876\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Indirizzo}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSS S. SSSSSSSS SSSS}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\scaps\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSS SSSSS SSSSSS}\cell\row\pard\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Telefono}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSSSSS}\cell\row\pard\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\langfe1040\dbch\af14\afs22\alang1025\rtlch \ltrch\loch\fs22\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+}\cell\row\pard\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2896\clvertalt\cellx9864\pard\plain \sp\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+E-mail}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSSSSSSSSSSSSSSSSS}\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb120\sa0{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Nazionalit\'e0}\cell\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSSSS}\cell\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20{\rtlch \ltrch\loch
+}
+\par \trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\qr\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20\keepn{\hich\af14\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+Luogo e Data di nascita}\cell\trowd\trql\trleft-108\ltrrow\trpaddft3\trpaddt0\trpaddfl3\trpaddl0\trpaddfb3\trpaddb0\trpaddfr3\trpaddr0\clvertalt\cellx2623\clvertalt\cellx2895\clvertalt\cellx9864\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb20\sa20{\langfe1040\dbch\af14\afs20\alang1025\rtlch \ltrch\loch\fs20\lang1040\loch\f5
+}\cell\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\intbl\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0\sb40\sa40{\b\hich\af14\langfe1040\dbch\af14\afs24\alang1025\ab\rtlch \ltrch\loch\fs24\lang1040\loch\f5
+SSSSSS SSSSSSSSSS }\cell\cell\row\pard\pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par \pard\plain \s0\nowidctlpar{\*\hyphen2\hyphlead2\hyphtrail2\hyphmax0}\cf0\kerning1\hich\af22\langfe2052\dbch\af17\afs24\alang1081\loch\f0\fs24\lang1040\ql\nowidctlpar\faauto\li0\ri0\lin0\rin0\fi0{\rtlch \ltrch\loch
+}
+\par } \ No newline at end of file
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/sf_edeb1eb341ad4c8608af9396952724a0-41170.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_edeb1eb341ad4c8608af9396952724a0-41170.rtf
new file mode 100644
index 000000000..0925203f8
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_edeb1eb341ad4c8608af9396952724a0-41170.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtf
new file mode 100644
index 000000000..5b34e7f61
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtf
new file mode 100644
index 000000000..58328edc9
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtf
new file mode 100644
index 000000000..9fd589214
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtf
new file mode 100644
index 000000000..28093f25a
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtf
new file mode 100644
index 000000000..847e165c5
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtf
Binary files differ
diff --git a/writerfilter/qa/cppunittests/filters-test/filters-test.cxx b/writerfilter/qa/cppunittests/filters-test/filters-test.cxx
new file mode 100644
index 000000000..36ebeee21
--- /dev/null
+++ b/writerfilter/qa/cppunittests/filters-test/filters-test.cxx
@@ -0,0 +1,79 @@
+/* -*- 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 <unotest/filters-test.hxx>
+#include <test/bootstrapfixture.hxx>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+using namespace ::com::sun::star;
+
+/**
+ * Unit test invoking writerfilter/ only.
+ *
+ * This does only minimal testing, checking if the filter crashes and returns
+ * the expected bool value for given inputs. More fine-grained tests can be
+ * found under sw/qa/extras/rtfimport/.
+ */
+class RtfTest : public test::FiltersTest, public test::BootstrapFixture
+{
+public:
+ virtual void setUp() override;
+
+ virtual bool load(const OUString&, const OUString& rURL, const OUString&, SfxFilterFlags,
+ SotClipboardFormatId, unsigned int) override;
+
+private:
+ uno::Reference<document::XFilter> m_xFilter;
+};
+
+void RtfTest::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ m_xFilter.set(m_xSFactory->createInstance("com.sun.star.comp.Writer.RtfFilter"),
+ uno::UNO_QUERY_THROW);
+}
+
+bool RtfTest::load(const OUString&, const OUString& rURL, const OUString&, SfxFilterFlags,
+ SotClipboardFormatId, unsigned int)
+{
+ uno::Sequence<beans::PropertyValue> aDescriptor = { beans::PropertyValue(
+ "URL", sal_Int32(0), uno::Any(rURL), beans::PropertyState_DIRECT_VALUE) };
+ try
+ {
+ return m_xFilter->filter(aDescriptor);
+ }
+ catch (const lang::WrappedTargetRuntimeException& rWrapped)
+ {
+ io::WrongFormatException e;
+ if (rWrapped.TargetException >>= e)
+ {
+ return false;
+ }
+ throw;
+ }
+ catch (const std::exception&)
+ {
+ return false;
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(RtfTest, testFilter)
+{
+#ifndef DISABLE_CVE_TESTS
+ testDir(OUString(),
+ m_directories.getURLFromSrc(u"/writerfilter/qa/cppunittests/filters-test/data/"));
+#endif
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/misc/misc.cxx b/writerfilter/qa/cppunittests/misc/misc.cxx
new file mode 100644
index 000000000..ce9e9ba28
--- /dev/null
+++ b/writerfilter/qa/cppunittests/misc/misc.cxx
@@ -0,0 +1,175 @@
+/* -*- 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 <tuple>
+#include <vector>
+
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <sal/types.h>
+
+#include <rtl/ustring.hxx>
+#include <dmapper/ConversionHelper.hxx>
+#include <dmapper/DomainMapperFactory.hxx>
+
+namespace
+{
+class WriterfilterMiscTest : public ::CppUnit::TestFixture
+{
+public:
+ void testTwipConversions();
+ void testFieldParameters();
+
+ CPPUNIT_TEST_SUITE(WriterfilterMiscTest);
+ CPPUNIT_TEST(testTwipConversions);
+ CPPUNIT_TEST(testFieldParameters);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+void WriterfilterMiscTest::testTwipConversions()
+{
+ using writerfilter::dmapper::ConversionHelper::convertTwipToMM100;
+ using writerfilter::dmapper::ConversionHelper::convertTwipToMM100Unsigned;
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-2), convertTwipToMM100(-1));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-17639), convertTwipToMM100(-10000));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(-70556), convertTwipToMM100(-40000));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), convertTwipToMM100(1));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(17639), convertTwipToMM100(10000));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), convertTwipToMM100(40000));
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), convertTwipToMM100Unsigned(-1));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), convertTwipToMM100Unsigned(-10000));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), convertTwipToMM100Unsigned(-40000));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(2), convertTwipToMM100Unsigned(1));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(17639), convertTwipToMM100Unsigned(10000));
+ CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), convertTwipToMM100Unsigned(40000));
+}
+
+void WriterfilterMiscTest::testFieldParameters()
+{
+ using writerfilter::dmapper::splitFieldCommand;
+ std::tuple<OUString, std::vector<OUString>, std::vector<OUString>> result;
+
+ result = splitFieldCommand("PAGEREF last_page");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand(" PAGEREF last_page ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+
+ result = splitFieldCommand("pageref last_page");
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("pageref \"last_page\"");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("\"PAGEREF\" \"last_page\" \"\" ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(2), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString(), std::get<1>(result)[1]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("\"PAGEREF\"\"last_page\" ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("PAGEREF\"last_page\" ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("\"PAGEREF\"last_page \"\"");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(2), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString(), std::get<1>(result)[1]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("\"PAGEREF\"last_page \"\"");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(2), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString(), std::get<1>(result)[1]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("pageref \"last\\\\pa\\\"ge\"");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last\\pa\"ge"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT(std::get<2>(result).empty());
+
+ result = splitFieldCommand("PAGEREF\"last_page\"\\*");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<2>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("\\*"), std::get<2>(result)[0]);
+
+ result = splitFieldCommand("PAGEREF last_page \\b foobar ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(size_t(1), std::get<1>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("last_page"), std::get<1>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), std::get<2>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("\\B"), std::get<2>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString("foobar"), std::get<2>(result)[1]);
+
+ result = splitFieldCommand("PAGEREF\\bfoobar\\A\"\"");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGEREF"), std::get<0>(result));
+ CPPUNIT_ASSERT(std::get<1>(result).empty());
+ CPPUNIT_ASSERT_EQUAL(size_t(4), std::get<2>(result).size());
+ CPPUNIT_ASSERT_EQUAL(OUString("\\B"), std::get<2>(result)[0]);
+ CPPUNIT_ASSERT_EQUAL(OUString("foobar"), std::get<2>(result)[1]);
+ CPPUNIT_ASSERT_EQUAL(OUString("\\A"), std::get<2>(result)[2]);
+ CPPUNIT_ASSERT_EQUAL(OUString(), std::get<2>(result)[3]);
+
+ for (auto prefix : { "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":",
+ ";", "<", ">", "?", "@", "[", "]", "^", "_", "`", "{", "|", "}", "~" })
+ {
+ OUString test(OUString::createFromAscii(prefix) + "PAGE");
+ result = splitFieldCommand(test + " ");
+ CPPUNIT_ASSERT_EQUAL(test, std::get<0>(result));
+ }
+ result = splitFieldCommand("\\PAGE ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGE"), std::get<0>(result));
+ result = splitFieldCommand("\\ PAGE ");
+ CPPUNIT_ASSERT_EQUAL(OUString("\\ "), std::get<0>(result));
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGE"), std::get<1>(result)[0]);
+ result = splitFieldCommand("\\\\PAGE ");
+ CPPUNIT_ASSERT_EQUAL(OUString("\\PAGE"), std::get<0>(result));
+ result = splitFieldCommand("\"PAGE\" ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGE"), std::get<0>(result));
+ result = splitFieldCommand("\"PAGE ");
+ CPPUNIT_ASSERT_EQUAL(OUString("PAGE "), std::get<0>(result));
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(WriterfilterMiscTest);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/rtftok/data/char-hidden-intbl.rtf b/writerfilter/qa/cppunittests/rtftok/data/char-hidden-intbl.rtf
new file mode 100644
index 000000000..76fea92fa
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/char-hidden-intbl.rtf
@@ -0,0 +1,6 @@
+{\rtf1
+\paperw11906\paperh16838\margl1440\margr1440\margt1440\margb1440\pard\plain before\par
+\trowd\cellx4475\cellx9058\pard\plain\intbl A1\cell
+\pard\intbl{\v \line}B1\cell\row
+\pard\plain after\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/duplicated-image.rtf b/writerfilter/qa/cppunittests/rtftok/data/duplicated-image.rtf
new file mode 100644
index 000000000..f225ff1f2
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/duplicated-image.rtf
@@ -0,0 +1,41 @@
+{\rtf1
+before table\par
+\trowd\cellx4819\cellx9638\pard\plain\intbl
+A1
+\cell\pard\plain
+{\shp
+{\*\shpinst\shpwr1\shpbypara\shpbyignore\shptop113\shpbottom1352\shpbxcolumn\shpbxignore\shpleft-22\shpright4733
+{\sp
+{\sn shapeType}
+{\sv 75}
+}
+{\sp
+{\sn pib}
+{\sv
+{\pict\picscalex92\picscaley92\piccropl0\piccropr0\piccropt0\piccropb0\picw341\pich89\picwgoal5115\pichgoal1335\pngblip
+89504e470d0a1a0a0000000d4948445200000010000000100403000000eddde25200000030504c54450000008000000080008080000000808000800080808080
+80c0c0c0ff000000ff00ffff000000ffff00ff00ffffffffff7b1fb1c40000005b49444154789c458db10ac03008445d33e5b71d04d764caef3808f99d0604ab
+b5a5b778dc933bf057f01bdd650ca98cf8d885ce240d0c3ecf40a41dc9097011f4d67a2ad18ac8f239af44f33255e19c1044ce42e39a60f9469fc06fa01a6b07
+bcd70bc70000000049454e44ae426082
+}
+}
+}
+}
+}
+\cell\row
+\pard\plain after table\par
+\pard\plain
+{\*\shppict
+{\pict
+{\*\picprop
+}
+\picscalex100\picscaley100\piccropl0\piccropr0\piccropt0\piccropb0\picw16\pich16\picwgoal240\pichgoal240\pngblip
+89504e470d0a1a0a0000000d4948445200000010000000100403000000eddde25200000030504c54450000008000000080008080000000808000800080808080
+80c0c0c0ff000000ff00ffff000000ffff00ff00ffffffffff7b1fb1c40000005b49444154789c458db10ac03008445d33e5b71d04d764caef3808f99d0604ab
+b5a5b778dc933bf057f01bdd650ca98cf8d885ce240d0c3ecf40a41dc9097011f4d67a2ad18ac8f239af44f33255e19c1044ce42e39a60f9469fc06fa01a6b07
+bcd70bc70000000049454e44ae426082
+}
+}
+end
+\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/follow-style.rtf b/writerfilter/qa/cppunittests/rtftok/data/follow-style.rtf
new file mode 100644
index 000000000..6e627c784
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/follow-style.rtf
@@ -0,0 +1,7 @@
+{\rtf1
+{\stylesheet
+{\s0\ql Normal;}
+{\s1\snext0 Heading 1;}
+}
+\pard\plain\s1 x\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/invalid-hex.rtf b/writerfilter/qa/cppunittests/rtftok/data/invalid-hex.rtf
new file mode 100644
index 000000000..8f9224c0e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/invalid-hex.rtf
@@ -0,0 +1,3 @@
+{\rtf1
+x\u345\'3?x
+\par}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/left-margin-dedup.rtf b/writerfilter/qa/cppunittests/rtftok/data/left-margin-dedup.rtf
new file mode 100644
index 000000000..8536694a2
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/left-margin-dedup.rtf
@@ -0,0 +1,26 @@
+{\rtf1
+{\fonttbl
+{\f0 Times New Roman;}
+{\f3\froman\fcharset2\fprq2 Symbol;}
+}
+{\stylesheet
+{\ql Normal;}
+{\s44\ql\fi-288\li360 Table Text Bullet;}
+{\s59\ql\li720 List Paragraph;}
+}
+{\*\listtable
+{\list
+{\listlevel\levelnfc23\leveljc0\leveljcn0\levelfollow0
+\levelstartat1\levelspace0\levelindent0
+{\leveltext\'01\u-3913 ?;}
+{\levelnumbers;}
+\f3\fbias0 \fi-360\li1305 }
+{\listname ;}
+\listid845246918}
+}
+{\*\listoverridetable
+{\listoverride\listid845246918\listoverridecount0\ls27}
+}
+\pard\plain\s44\ql\fi-360\li720\ls27 P1\par
+\pard\plain\s59\ql\fi-360\li720\ls27 P2\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/negative-page-border.rtf b/writerfilter/qa/cppunittests/rtftok/data/negative-page-border.rtf
new file mode 100644
index 000000000..e5bec712a
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/negative-page-border.rtf
@@ -0,0 +1,7 @@
+{\rtf1
+\paperw11906\paperh16838\margl1134\margr1134\margt284\margb1134
+\sectd\pgbrdropt32\pgbrdrt\brdrs\brdrw90\brsp560 \pgbrdrl\brdrs\brdrw90\brsp560 \pgbrdrb\brdrs\brdrw90\brsp560 \pgbrdrr\brdrs\brdrw90\brsp560
+\pard\plain
+In this example, the page top margin (0.5cm) is the same as the border top margin (0.5 cm).
+\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/old-para-num-left-margin.rtf b/writerfilter/qa/cppunittests/rtftok/data/old-para-num-left-margin.rtf
new file mode 100644
index 000000000..99825370e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/old-para-num-left-margin.rtf
@@ -0,0 +1,14 @@
+{\rtf1\ansi
+\margt1497\margb590\margl590\margr590\pgwsxn11906\pghsxn16838
+\pard\plain First\par
+\pard\plain
+{\*\pn \pnlvlbody
+{\pntxtb \'78}
+}
+{\b\f7\fs22 Second\par}
+\pard\plain\li1191
+{\*\pn \pnlvlbody
+{\pntxtb \'78}
+}
+{\f7\fs22 Third, with left indent\par}
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/page.rtf b/writerfilter/qa/cppunittests/rtftok/data/page.rtf
new file mode 100644
index 000000000..75e137638
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/page.rtf
@@ -0,0 +1,6 @@
+{\rtf1
+\pard\plain
+page 1\par
+\page
+page 2\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/picture-in-textframe.rtf b/writerfilter/qa/cppunittests/rtftok/data/picture-in-textframe.rtf
new file mode 100644
index 000000000..ec0a07690
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/picture-in-textframe.rtf
@@ -0,0 +1,29 @@
+{\rtf1
+\paperw10080\paperh12960\margl1066\margr1066\margt1642\margb1066
+\pard\plain
+{\shp
+{\*\shpinst\shpleft31\shptop105\shpright4108\shpbottom3887\shpfhdr0\shpwr2\shpwrk3\shpfblwtxt0
+{\sp
+{\sn shapeType}
+{\sv 202}
+}
+{\shptxt \pard\plain
+before
+{\*\shppict
+{\pict
+{\*\picprop\shplid1025
+{\sp
+{\sn shapeType}
+{\sv 75}
+}
+}
+\picscalex23\picscaley24\piccropl0\piccropr0\piccropt0\piccropb0\picw30372\pich22437\picwgoal17219\pichgoal12720\pngblip
+47494638396110001000d5ff00000000ffffffc0c0c0555f00ffffaafcfcfcf6f6f6eaeaeae6e6e6e4e4e4e3e3e3c2c2c2c1c1c1bcbcbcb5b5b5b3b3b3b0b0b0adadada5a5a5a2a2a2a1a1a19f9f9f9494948a8a8a8888888686867b7b7b6c6c6c5c5c5c4e4e4e4b4b4b4747474646463d3d3d3c3c3c2e2e2e2525251b1b1b18181810101009090906060603030300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021f90401000002002c0000000010001000000684408170482c0a06c8a4728924389f506833b281302a8e6b164b18103024c52111504cca67332102e0042e9a40d9319f8300a343c1200f54e47f7e2a00001e0b0a7d0d728a010d838400261a7c0d94947784252700127e9d159f6c8411140019080ea7a9a85f842122281612b1b3b25d6b1f29291d0fbbbdbc5d5e51c34e4cc64a46c94341003b
+}
+}
+after\par
+}
+}
+}
+\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/picw-pich.rtf b/writerfilter/qa/cppunittests/rtftok/data/picw-pich.rtf
new file mode 100644
index 000000000..56a2b0d1e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/picw-pich.rtf
@@ -0,0 +1,6 @@
+{\rtf1
+\pard\plain
+{\pict\wmetafile8\picwgoal2134\pichgoal2264\picscalex100\picscaley100\picw99\pich105
+010009000003d13d00000000a73d0000000005000000070103000000050000000102ffffff0005000000090200000000a73d0000410b2000cc006900630000000000690063000000000028000000630000006900000001001800000000000c7b000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafb9c8a3de3e0cbfefffdfffffffffdfffbfffbfffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ffffdcccafa2975bfffff9e1dee0b8b3b5aaacaccad2c8f5f5f5fffffffffffffdfdfdfffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffeffaa9e58fffdfdfefefefffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafdfbfffff7a19363d0ceabb6b2b17b777d7475798c9489d3d3d3fffffffcfcfcfefefefffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfdfffffffffffffcfcfcfdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfbfda79b55fffffffffffffffffffafffcfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffdfcd9d3c67d732d949484b6b2b8bcb9c29ba097828282a2a2a2edededfffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffaa9e58fffffffdfdfdfefcfcfafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9faf8a6a6ac85773cbbb483f7fcfdfffcfefcfcfccdcdcd898989979797e4e4e4fffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefefffffffefefefbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffefefffffffffffffafffcfffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffdfe7e7706a6bdfd7ca928539f2fae9fffffcfffafffffffffbfbfb909090979797f7f7f7fdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffdfdfdfdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffa99d57fffdfdfffffffffffff9fffbfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcf9fbbbc3c28c8a89ede5ecc2be8db3a874f5fffdfffdfffefefeffffffdddddd888888d0d0d0fffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfdfdfdf4f4f4f7f7f7fffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfcfea79b55fffffffffffffffefef7fef9fffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f6f7b7b5b4929897f5f0effcfcf6968449ebeed5fffffafffffffffffffefefea4a4a4a7a7a7fafafafefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefec2c2c2979797c5c5c5fbfbfbfffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffefefcfcfcfffffffafffcfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5f7f7b2adaf9da299edf5f4fffbffd3d1afae965afafffefefefefffffffdfdfda6a6a6a1a1a1fffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b9b9b898989b4b4b48e8e8e9a9a9af9f9f9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffeffa89c56e5e3e3cbcbcbdcdadaf3faf5fffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fcf7c9c6c88f8a89eeececfdf9fffeffef959853ebd5acf6f9fffffff8fafffea8a6a6aaa19efafdfffcfefefffffefcfcfcfffffffffffffdfdfdfefefefdfdfdfffffffefefefefefefffffffefefefefefefffffffdfdfdfdfdfdfefefec5c5c5838383d5d5d5ffffffd8d8d8767676cacacafcfcfcfefefefffffffefefefffffffffffffdfdfdfffffffdfdfdfffffffffffffefefefffffffcfcfcfffffffffffffefefeedededbebdbf8377318a88889292928c8a8aa7aea9fffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffe8e6e5736f6ed0d0d0fbfffffffffee5ddc6958b4ffff9f6f9fffafbfff7bdb3bf888385fdfffcfbfffffffcfdfffffffbfbfbfffffffdfdfdfffffffffffffafafafffffffffffffdfdfdfffffffefefefefefefffffffffffff0f0f0787878bfbfbffffffffefefeffffffcacaca7d7d7de6e6e6fffffffdfdfdfffffffefefefffffffffffffefefefffffffdfdfdfffffffffffffdfdfdfefefeffffffdfdfdfb5b5b59494948e8d8f867a34d6d4d4e7e7e7c2c0c07a817cfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfcfefcfaf9aeaaa9939296d1d9cef9f9f9fffbffa8a471d4c196fafffffafef2dfd7de7b7a83dddedaf8fefdfffdfefdfdfdfefefefffffffffffffdfdfdfcfcfcfffffffefefefffffffdfdfdfffffffffffffdfdfdffffffffffffd5d5d5767676e7e7e7fffffffdfdfdfffffff6f6f67f7f7fbcbcbcfbfbfbfffffffefefefffffffffffffdfdfdfffffffcfcfcfffffffafafafffffffcfcfcedededc6c6c68888887d7d7db9b9b9faf9fba89c56fffffffafafaa9a7a7a1a8a3fffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffdfc9c9ba46e7372c9cec5faf5f6f7efe291803dfdfaecfffdfffafff6adafb78d8a8cf1f5f0fffffffefefefffffffbfbfbfcfcfcfffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffcfcfcf6f6f6b0b0b0a2a2a2f1f1f1fcfcfcfffffffbfbfbffffffd7d7d7838383d8d8d8fffffffffffffcfcfcfdfdfdfffffffefefefffffffffffffcfcfcf8f8f8d2d2d2828282737373c1c1c1fffffffffffffffeffa49852fcfafad4d4d46e6c6cdce3defffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfbfdfffffbfefefef8f9fdc2c5ca757b76c7cbc0fff8ffcbbf8fbaad79fffbfff4fff5e1e0e47b787ac4c1bcf8fdfefdfdfdfdfdfdfffffffffffffffffffffffffdfdfdfefefefefefefffffffcfcfcfffffffffffffdfdfdececec898989c3c3c3f7f7f7fffffffefefefffffffdfdfdfdfdfd9090909d9d9dfffffffffffffffffffffffffefefefffffffefefefbfbfbcdcdcd7f7f7f777777bebebef2f2f2fffffffefefefefefefffeffa69a54efeded8c8c8cb2b0b0f5fcf7fff9feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffcfff5fefefefdfefcfbfdfeb3b2bc787c77e6e6e6fdf7ec93893bf0e8dbfbfffffefbfdcfceca797672bbc3c3fefefefffffffbfbfbfefefefffffffffffffdfdfdfffffffffffffffffffdfdfdfffffffdfdfdffffffe2e2e2757575e4e4e4fefefefffffffdfdfdfffffffefefeffffffe9e9e9838383979797f9f9f9fcfcfcfffffffdfdfdebebebb3b3b3868686848484b7b7b7e0e0e0f8f8f8fffffffcfcfcfffffffefefefffeffada15ba2a0a0858585f8f6f6fafffcfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffdfffefdfffffffffcfffffffaf6fca1a0a2979b95faf9fdd3cea1a29b6afffff9fffdfffdfdfdc6c4c3767b7aadadadf9f9f9fffffffcfcfcfffffffffffffefefefdfdfdfffffffefefefffffffffffffdfdfdffffffcdcdcd7e7e7ef5f5f5fffffffffffffffffffdfdfdfefefefdfdfdffffffdadada8f8f8f8585859f9f9f9e9e9e9393938383839a9a9ab9b9b9e0e0e0fffffffefefefdfdfdfefefefffffffefefefffffffefdff877b35838181dfdfdffffdfdf9fffbfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfff7fdfcfff9fbfbfffefffffefffffff7dfe0dc6c6e6ee4e9e7fdf9ffa09c4ee4d5bbfffbfffffcfffbfffcc4c7c58282829f9f9fcececef8f8f8fefefefffffffffffffffffffefefefffffffffffffefefefffffffbfbfbb8b8b8909090f8f8f8fefefefefefefefefefffffffffffffffffffefefeffffffefefefb1b1b19d9d9d999999a6a6a6cdcdcdf4f4f4fffffffffffffffffffcfcfcfffffffefefeffffffffffffffffffc0bfc17c702acdcbcbfffffffffffff9fffbfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffefefeffffffefefef9b9b9bc2babbf2faffd9ddb99b8a47fdfff5fffefefbfffffefdffeeeeee8e8e8e767676a5a5a5cacacadddddde6e6e6eeeeeef8f8f8ffffffffffffffffffffffffededed979797bfbfbffbfbfbfdfdfdfffffffffffffffffffffffffffffffffffffefefefffffffefefefffffffffffffffffffefefefffffffffffffcfcfcfffffffffffffffffffffffffdfdfdfbfbfbcdccc8747474938741fffefffbfafcfffefefafffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffffffffffffffbfbfbbebebe969192e6eee4fffff8a8a46fd6c69bf8fbfffffffffdfffffefefeffffffdfdfdf9d9d9d7878787272727d7d7d999999bfbfbfe8e8e8f6f6f6fdfdfdfbfbfbdddddd848484e3e3e3fcfcfcfefefefffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefefffffffffffffefefefefefefffffffefefefffffffffffffbfbfbfffffff5f5f5c2c2c2696864cacacaaa9e58fffcfefffefffffefefafffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefefefefefefefefefefefefed5d5d581837de6e4e3fffeffebedda9b883ff9faf0f9f8fcfdfffcfefefefffffffffffff9f9f9f3f3f3eaeaead0d0d0b3b3b38686867474748d8d8de4e4e4ffffffbfbfbf808080fbfbfbfefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffefefefbfbfbfffffffbfbfbfffffffffffffefefefffffffffffffbfbfbfffffff4f4f4acacac6f6f6fd5d4d0fefefea79b55fffcfefefdfffffffff7fef9fffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfdfefefeffffffffffffdfdfdf787e73e5dce9fffefdfffdffb9b07ebfb37dfbfefffffffcfffffffdfdfdfdfdfdfffffffefefefafafafefefefbfbfbebebebd8d8d8acacac7e7e7e9696967f7f7fb0b0b0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f9fffffffffffffffffffffffffefefefdfdfdfffffffffffffffffffefefececece838383909090e0e0e0f9f8f4f9f9f9aa9e58fffefffefdfffffffffafffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfdffffffffffffffffffe1e1e1737a77e5dee3fffefffdfbfaf8f5f096893bf2eedcfcfefffefefefffffffdfdfdfefefefffffffffffffffffffafafafdfdfdfffffff8f8f8cacaca7f7f7f979797f3f3f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfffffffefefefffffff9f9f9fffffffffffffbfbfbefefefcfcfcfaaaaaa909090888888abababe4e4e4fffffff6f5f1fefefeaa9e58fefbfdfffefffffdfdf9fffbfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffffffffdfdfdffffffdedede767981e8e3dafdfdfdfdfffffdfeffcdc59db0a46afffffefffffffdfdfdfdfdfdfffffffefefefcfcfcfffffffffffffffffffffffffefefefcfcfcf3f3f3edededfffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffefefeddddddb1b1b1929292858585929292b1b1b1ddddddfffffffffffffdfdfdf5f4f0ffffffab9f59fffcfefbfafcfffffffafffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefeffffffffffffffffffffffffcecece838089e8e9dffffff9f6f8fffffffefdf8f59f9359eae2c5fefefefffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffff8f8f8fcfcfcc6c6c6868686858585b7b7b7edededfdfdfdfafafafffffffffffffffffffffffff8f7f3ffffffa1954ffffefffffefffffdfdfafffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefefefefefefefefefefef5f5f5b1b1b1a89da5eef6effbfef5fbfffffaf9fffffffce3dac6ab9a5bfffffffdfdfdfefefefffffffffffffffffffffffffdfdfdfefefefffffffdfdfdfefefefffffffffffffefefefffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffcfcfcc6c6c6727272bebebefffffffffffffcfcfcfffffffffffffffffffffffffffffffffffff8f7f3fcfcfcab9f59fffcfefdfcfefffffff8fffafffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefefffffffffffffdfdfdfefefefffffffffffffdfdfdfffffffffffffefefefefefefffffffffffffdfdfdededed838383ccc8cefdfdfdfbfefcfdfffffffefffffdfcfffff1a4a182d8d499fffcfefffcfffffff9fffefffcfefff8fffbfffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffcfcfcffffffececec707070c6c6c6f8f8f8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfbfffffffdfdfdfdfdfdfffffffffffffefefefffffffdfdfdfffffffffffffbfbfbfffffffffffffefefefdfdfdfffffffefefeffffffffffffffffffc9c9c96f6f6fefeceefdfefcfdfffbfbfefcfcfbfffffefffffef5ece9d4988d53fbf5f6fdfff9fffdfffdfffefcfdf9fffefff8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffdfdfdfffffffbfbfbfffffffffffffefefeffffffffffffc8c8c8828282e5e5e5fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefefdfdfdfffffffefefefcfcfcfffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffefefefffffffffffffffffffdfdfdf0f0f0a1a1a1a8a8a8fffdfdfffffbfdfff9fbfffafdfefffdfbfffffdfdfffffbc3b591cac497f4f4fadadbd9bfbdbcb2b1adada2a4949da09090909393939494949191918e8e8e909090989898a0a0a0a8a8a8c0c0c0e9e9e9fffffffdfdfdfffffffffffffafafafffffffefefef5f5f5b6b6b6a1a1a1efefeffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffcfcfcfffffffffffffcfcfcfefefefffffffdfdfdfefefefffffffffffffdfdfdfffffffffffffcfcfcffffffffffffffffffd3d3d37e7e7ee9e9e9fffdfffffdfcfefffafbfffaf9fefdfdfefffffefffbfbfbfaeee8877d308a847d858d8c948f8c989394939595a3a3a3aeaeaeb0b0b0b2b2b2b3b3b3b1b1b1abababa4a4a49e9e9e9191918282828c8c8cb7b7b7f5f5f5fffffffbfbfbfffffffefefefffffff4f4f4b2b2b29f9f9ff1f1f1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffefefefcfcfcfffffffffffffdfdfdfdfdfdfefefefffffff4f4f4ebebebf0f0f0fdfdfdfffffffffffffffffffffffffffffffefefefffffffcfcfcffffffb7b7b77e7e7efffffffffcfffffdfffffffefdfffcfbfefcfdfffff9fbfcfafcfcbeb9ba7d6f45938e51e6e5eff8f6f5fffffbf6fffffffefbfffffffefefefdfdfdfefefefffffffffffffffffffdfdfdfffffff6f6f6bababa7b7b7bb1b1b1fffffffffffffffffffefefefffffffefefec9c9c9848484efefeffbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffcfcfcfffffffffffffcfcfcd1d1d19e9e9e989898a0a0a0bfbfbfe3e3e3f5f5f5fafafafdfdfdfffffffffffffefefeffffffffffffa7a7a7969696fefefefffdfffffefffcfbfdfcfcfcfffffefcfffdfdfffec0c3c17c7d7bd4cec9a1984feaddcffbfefffafff6fbfffffffffcfefefefffffffffffffffffffefefefdfdfdfefefefffffffffffffafafaffffffd4d4d47b7b7bd1d1d1fefefefcfcfcfffffffefefeffffffededed797979d4d4d4fffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffefefefdfdfdfffffffffffffefefefefefec0c0c07a7a7aa9a9a9b9b9b9aaaaaa8787877575757e7e7eb0b0b0eeeeeefdfdfdfffffffdfdfdfffffffdfdfda2a2a2a5a5a5fefefefffffefefefefffefffffefffffffffffffed8d9d7737472b6babbfdffffe0d2b6a59a68fffff9fafffffffffffffefdfefefefdfdfdfdfdfdfefefefffffffffffffffffffefefefffffffdfdfdfffffffafafac1c1c1747474edededfffffffefefefffffffdfdfdf8f8f8a2a2a2a2a2a2f6f6f6fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefefefefffffff3f3f3828282c0c0c0f1f1f1f8f8f8f4f4f4e9e9e9ddddddc2c2c29a9a9a7e7e7e8e8e8eb7b7b7e9e9e9fffffffbfbfba4a4a4a0a0a0fffffffdfff9fefffbfffffffffefffffdffedebeb767474b4b2b2f0fafafdfafcfffdffaaa168dbd8acf9fbfffefdfffffffbfefefefffffffffffffffffffefefefefefefffffffffffffdfdfdfffffffcfcfcffffffefefef9c9c9ca4a4a4f5f5f5fffffffffffffffffffdfdfdeeeeee747474bdbdbdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdffa89c56fffffffffffffffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffcfcfcfffffff8f8f8717171d9d9d9fffffffffffffffffffffffffcfcfcffffffecececcececeb0b0b0939393878787929292999999757575a9a9a9fffffffffffffffffffefefefffffff5f5f58c8c8c9c9c9cf7f7f7fffff9f9fefdf6fffff3e9d1a08f4cfcfff4fffff7fafffffefdfffffefffffcfffffbfffafefffafffbfdfefafffbfffffffffefefefdfdfdffffffffffffe3e3e3767676cececefffffffefefeffffffffffffffffffc8c8c87d7d7db7b7b7fffffffffffffffffffefefefdfdfdfffffffffffffdfdfdfefefefffeffa89c56fffffffffffffffffff6fdf8fffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefef6f6f6a5a5a5a7a7a7f7f7f7fffffffefefefefefefffffffffffffffffffefefeffffffefefefd0d0d0a5a5a59696969f9f9fd9d9d9fffffffefefefffffffffffff9f9f9b2b2b27d7d7df2f2f2fffffffffefdfdfffefbfefffffff0beb28acdbd8ffafcfffdfdfffcfefefffffbfffffcfffdfffbfefff9fffafefffbfffcfffffffffffffffffffffcfcfcfffffffefefeb3b3b39b9b9befefeffffffffdfdfdfdfdfdfffffffbfbfbbfbfbf818181a4a4a4dadadafafafafffffffffffffdfdfdfffffffffffffefefefffeffa59953fffefefdfdfdfffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefcfcfcfffffffdfdfdffffffe3e3e3818181cececefffffffffffffdfdfdfffffffcfcfcfffffffffffffffffffdfdfdfffffffffffffffffffdfdfdfffffffdfdfdfefefefffffffdfdfdcecece777777dededefffffffdfdfdfffefffdfffffefffdfbfff8f2f0e5ab8e55f6f3ebfefafffafffffdfffbfffff8fffffefffffffbfefcfdfffefffefffffffffffffffffffffffffffffffffffffff9f9f97c7c7ccdcdcdfffffffffffffffffffcfcfcfefefeffffffdfdfdf888888818181c5c5c5edededfffffffffffffffffffcfcfcfdfdfdfffeffa79b55fffffffefefefdfbfbfafffcfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfefefefffffffdfdfd9f9f9fa3a3a3f9f9f9fffffffefefefffffffffffffffffffcfcfcfffffffffffffbfbfbfefefefffffffefefefffffffffffffffffffdfdfdf4f4f4909090a2a2a2fffffffbfbfbfffffffffefffcfbfffbfffafffffbfaffffcebf9ebdaf7bfffffef9fdfff9fefcfffffbfefdf9fffffffffefffdfffefdfffefffffffefefefefefefffffffcfcfcfffffff7f7f77d7d7dcacacafdfdfdfcfcfcfefefefffffffdfdfdffffffffffffffffffc7c7c7707070999999e6e6e6fcfcfcfafafafffffffffffffffeffa59953fffefefffffffffffff9fffbfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefefffffffdfdfdffffffe9e9e98d8d8dc7c7c7fffffffdfdfdfefefefefefefffffffffffff8f8f8fffffffffffffffffffdfdfdfffffffdfdfdfefefefefefeffffffb0b0b0858585fbfbfbfcfcfcfffffff8f8f8fffffefcfbfffffffcfffbfefbfbfff6fbf2a59552ebe9c6fdfdfff9fafefffefffffffffffefffffefffcfefefbfffbfdfdfdfffffffefefefbfbfbfffffffbfbfbafafaf919191e7e7e7fffffffffffffbfbfbfefefefffffffdfdfdfffffffffffffafafaefefef9b9b9b777777d8d8d8fffffffffffffdfdfdfefdffaa9e58fffefefdfdfdfffffff7fef9fffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffcfcfcfefefeffffffa0a0a0999999fffffffffffffffffffdfdfdfffffffffffffffffffefefefbfbfbfffffffffffffffffffefefeffffffffffffe8e8e87f7f7fbdbdbdfffffffffffffcfcfcfffffffbfffffcfffdfffffefbfefffffdfff6fffed9d9b1ada465fffff8fffefffffcfffdfefffdfdfdfffefffffffffcfffbfffffffdfdfdfefefefffffffcfcfcdfdfdf6b6b6bcececefdfdfdfffffffcfcfcfffffffffffffffffffffffffffffffffffffdfdfdfefefef1f1f1b6b6b67b7b7bc3c3c3fafafafffffffbfafca89c56fffffffdfdfdfffffffafffcfffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffdfdfdfefefefefefefffffffffffffdfdfdcccccc8d8d8de6e6e6fefefefefefefefefefffffffefefefffffffdfdfdfffffffffffffffffffdfdfdffffffffffffffffff9b9b9b9b9b9bf8f8f8fffffffffffffdfdfdfffffffbfffffdfff9fffffffafffffef9fafefffbfdfefaa79c6adbd5b2fffff8fefbfffbfefffcfffdfffffffffefffbfdfdfffffffffffffdfdfdfefefeefefef8b8b8baaaaaaf7f7f7fdfdfdfffffffefefefffffffffffffefefefffffffffffffcfcfcfffffffffffffcfcfcfcfcfcbcbcbc7a7a7abbbbbbfbfbfbfffeffa59953fffffffffffffffefefafffcfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffcfcfcfffffffdfdfdfffffff1f1f1949494c2c2c2fefefefffffffffffffefefefefefefefefefffffffffffffcfcfcfffffffefefefefefeffffffededed767676cdcdcdfffffffcfcfcfffffffffffffefefefafefffffffcfafffffefffdfafffbfffdfffffbffebe3cc98915affffebfffdfffafdfffdfffbfffffefffdfffffefffefefefffffffefefef9f9f9b3b3b37c7c7cf3f3f3fffffffffffffdfdfdfffffffffffffffffffffffffefefefefefefffffffffffffdfdfdfffffffffffffefefec7c7c7787878b7b7b7f8f7f9aa9e58fffdfdfffffffffefefafffcfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffefefefefefefffffffffffffefefefefefefffffffffffffffffffdfdfdfffffffcfcfcfffffffdfdfdfffffff5f5f5979797bcbcbcfffffffffffffefefefffffffefefefffffffefefefffffffffffffefefefffffffffffffafafab4b4b49a9a9aebebebfffffffffffffdfdfdfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffbab17fcac89ffffdfef8fefdfafffff6f7fffdfffefffffbfcfcfcffffffffffffc3c3c37a7a7ae4e4e4fffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffdfdfdfffffffefefefffffffcfcfcd7d7d774736fbdbfbfaa9a55fcfefffffbfefdfffff9fffafffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffefefefefefefffffffffffffffffffffffffffffffcfcfcfffffffefefefffffffffffffffffffffffffdfdfdd5d5d5818181dadadafffffffefefefffffffffffffffffffffffffefefefffffffefefefdfdfdfffffffefefef6f6f6878787bebebefffffffffffffdfdfdfffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffff5f6dca59560fcf6e9fffbfef2fbfefffffffffefffefffdffffffffffffe0e0e08a8a8ab2b2b2fdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffdfdfdfdfdfdfffffffcfcfcd2d1cd777979958540fcfefffffdfffdfffffbfffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfbfbfbfffffffffffffefefeffffff9090908f8f8ffdfdfdfffffffdfdfdfffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffff6f6f67d7d7dc6c6c6fffffffefefefdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fff8d3c2a1c0bc89fffefffdfffefafffdfffffefbfcfffefefefefefe9797978a8a8af6f6f6fdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefefffffffffffffcfcfcfdfdfdfffffff6f5f1b2b4b483732ee4e6e7fffbfefafcfcfbfffcfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffefefefefefefefefefefefefcfcfcfffffffffffffafafafffffffcfcfc939393888888e2e2e2fffffffafafafffffffafafafffffffdfdfdfffffffefefefffffffefefefdfdfdfefefefefefefbfbfb9e9e9ea9a9a9f9f9f9fefefefffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffcfff9fea69a5af1f0d6fffcfefdfffefffffcfffdffffffffa6a6a6848484e8e8e8fffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefefdfdfdfffffffffffffdfdfdfefefefffffbf1f3f3887833909293fffdfffdfffffbfffcfffafcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffdfdfdffffffcbcbcb8d8d8d909090ddddddfffffffffffffffffffcfcfcfffffffefefefdfdfdfffffffefefefffffffffffffffffffffffffdfdfdfcfcfcd8d8d8888888ddddddfdfdfdfffffffcfcfcfffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffefdf9fafbffdcd5b4b7ab6bfcfefffffffbfdffffffffffc5c5c57a7a7ad4d4d4fffffffbfbfbfefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffefefefdfdfdfffffffffffffffffffffffcf9fbfba4944f868889beb7bafafcfcf9fffafffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffefefefefefeffffffdededeadadad878787a0a0a0f3f3f3fefefefffffff9f9f9fcfcfcfffffffcfcfcfefefefffffffffffffefefefefefeffffffffffffffffffffffffffffffffffff808080b5b5b5fffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffefff7fffefefcfbb4a66ce3dfc3fbfffffffdfecccdcb737373c7c7c7fcfcfcfffffffffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffefefefefefefefefefdfdfdfffffbfdffffa59550c7c9ca797275eceeeefbfffcfffcfeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffefefefcfcfcffffffeaeaeac4c4c4878787898989d7d7d7fcfcfcfffffffffffffbfbfbfffffffffffffffffffffffffffffff8f8f8f9f9f9fefefefffffffffffffdfdfdfefefeffffffffffffffffffaeaeae9a9a9af0f0f0fffffffcfcfcfffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffcfffbfffbfefefee8e3ceab9d6cf5f9edd0cbc879787abababafdfdfdfcfcfcfffffffdfdfdfbfbfbfffffffbfbfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfefefefffffffffffffffffffffffff6f5f1fbfdfdac9c57edeff09e979aabadadf5fbf6fffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffefefefffffffefefefbfbfbf7f7f7d2d2d28b8b8b717171c7c7c7fdfdfdfffffffffffffefefefefefefffffffdfdfdfffffffdfdfdf8f8f8e4e4e4c5c5c5bdbdbdd6d6d6f0f0f0fcfcfcfffffffffffffffffffdfdfdfefefef4f4f4858585bcbcbcfffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffdfefffffff8f8fef9fdfbfab1a87daca0786f7a78c0b9c0fffffffdfdfdfffffffcfcfcfffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffffffffefefefefefefefefefffffffdfdfdf7f6f2fdffffab9b56fcfeffdad3d6797b7bedf3eefffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fefefefffffffefefefffffffdfdfdffffffe0e0e0888888727272b4b4b4edededfdfdfdfdfdfdfffffffffffffffffffffffffffffffafafafffffff3f3f39a9a9a717171898989919191787878747474cdcdcdfffffffafafafffffffffffffffffffbfbfba7a7a7868686fdfdfdfffffffdfdfdfffffffffffffffffffffffffefefefdfdfdfffffffffffffffffff7fdf8efede5d7d0d79ea9b77b7a667d6e2fd6cec1f5faf8fffcfffffefefdfffff9fafefffffefffff9fdfefafdfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f6eefbfdfeac9956fdfffeeae5e4828387ccd1d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffdfdfdfcfcfcf4f4f49797977b7b7bb3b3b3ddddddf2f2f2fffffffffffffffffffffffffffffffdfdfdfefefefdfdfdffffffc8c8c8727272a1a1a1dededeeaeaeaececece1e1e1c0c0c0707070b2b2b2fffffffffffffefefefdfdfdffffffeeeeee959595848484b3b3b3bababab3b3b3b1b1b1afafafaaaaaaa6a6a6a4a4a49e9e9e9393938989897a7c7d84827a8b8a8c9d9fa7c9c6c1b8af8ac2bd8cfffffffffbfffffffcf8fbfffdfffefefffafefafffffefffafdfbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f6eefcfeffaf9c59fbfefcf7f2f1a8a9ada4a9a8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fefefeffffffffffffc8c8c8848484999999d0d0d0fcfcfcfffffffffffffffffffefefefdfdfdfefefeffffffffffffffffffffffffacacac797979bababaf6f6f6fbfbfbfefefefefefefffffffdfdfdd0d0d07d7d7dc4c4c4fefefefffffffffffffdfdfdfefefee7e7e7a5a5a59595959898989b9b9b9b9b9ba0a0a0a2a2a2a1a1a1a1a1a1a7a7a7b1b1b1b7b7b7c9c8cad2d3cfe2e7e5fdf4f7fffefef7f5eda39a61f1ead9fffbfffffffbf8fdfcfbfffefefffdfffcfffffefffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f6eefdffffae9b58fbfefcfffefdd0d1d57e8382ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffdfdfdb9b9b97b7b7bafafaffffffffefefefffffffffffffefefefffffffefefefefefefffffffffffffcfcfcdbdbdba0a0a0868686c9c9c9fdfdfdfffffffffffffefefefffffffdfdfdfcfcfcffffffb7b7b78a8a8aefefeffffffffafafafffffffdfdfdfffffffefefef7f7f7f7f7f7f6f6f6fafafafefefefffffffffffffefefefefefefffffffffffffefdfffbfdfefdfffbfffbfefdfdfdfdffffd2c7b1bcb381fffffbfffffefbfffbf9fdfefffcfffffffffefcfbfffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5edfdffffac9956fdfffefffffee5e6ea747978ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffcacaca6f6f6fd2d2d2fffffff6f6f6fffffffdfdfdfffffffdfdfdfdfdfdfffffff9f9f9ecececd7d7d7c2c2c2808080898989e3e3e3fffffffefefefafafafffffffdfdfdfffffffefefefffffffbfbfbf2f2f2959595b8b8b8fefefefffffffffffffffffffbfbfbfffffffffffffefefefefefefffffffffffffefefefefefefffffffffffffffffffefefefffefffbfffffffffbfefbfdfffcfffcfffdfdfbfba79a62e0e1bffffbfffdfffcfafffdfdfcfffffff9fffcfefffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f6eefdffffac9956fdfffefffffeecedf1767b7affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffff8a8a8ab8b8b8f3f3f3f7f7f7fefefef6f6f6f7f7f7f5f5f5f3f3f3efefefd9d9d9b2b2b28f8f8f8080807d7d7dcacacafffffffefefefffffffffffffffffffdfdfdfffffffdfdfdfffffffafafaffffffffffffbbbbbb838383fffffffefefefefefefdfdfdfffffffdfdfdfbfbfbfffffffffffffefefefffffffffffffffffffffffffefefefefefefefefefffcfffbfff9fffffcfdfffefef4fffffffcf8fff9f1e0c5a3a46cfff5fdfffefffdfffbfffffffffffcfffdfffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f7effcfeffae9b58fafdfbfffffef0f1f5727776ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fefefeb5b5b57b7b7b959595abababa9a9a9a9a9a99a9a9a8989898080807878787f7f7f959595b9b9b9dfdfdff7f7f7fbfbfbfefefefffffffdfdfdfffffffffffffcfcfcfffffffffffffdfdfdfffffffffffffefefec5c5c5868686f1f1f1fcfcfcfefefefffffffffffffdfdfdfffffffdfdfdfcfcfcfffffffffffffefefefefefefffffffffffffffffffffffffffefffafffbfbfcfafffffefffcfffdfffffbfff5fffeffb3ab7cd8d1b6fffffcfffefffffffefffffffefdfffdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f6eefcfeffae9b58fbfefcfffffeeeeff36e7372ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fefefef2f2f2cdcdcdb3b3b3a3a3a3a4a4a4a8a8a8b1b1b1bcbcbcccccccdcdcdce5e5e5efefeffafafafefefefcfcfcfffffffdfdfdfffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffefefefdfdfddbdbdb808080e8e8e8fefefefffffffefefefefefefffffffefefefcfcfcfffffffffffffefefefffffffffffffffffffffffffffffffffffffffffcfbfefffafffefffdfffdfff7fafffffffefff6fbffffecd3989a58fcf9ebfffafffdfcfefffffffffff8fdfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5edfdffffab9855fdfffefffdfce8e9ed6f7473ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fdfdfdfffffffffffffdfdfdf7f7f7f5f5f5f9f9f9fefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffffd5d5d5848484e8e8e8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6ffffcdbb92c8c295fffefef9fefdfffffefffefffbfefcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6f3eefdfeffae9a59fcfffdfffefdcecfd37e8382ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffefefefefefefefefefefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd0d0d0808080f0f0f0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefaf9eba39463f6f5e1fffefffbfcfffefdfffdfffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaf7f2fdfeffac9857fcfffdfffaf9acadb19ca1a0fffefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffcfcfcf7d7d7df6f6f6fefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefdfbffffcfc7aab7b079fffefffffdfffafdfffffffcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f5f0fcfdffaa9655fdfffee9e4e3818286ccd1d0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fefefefefefefefefefffffffffffffffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffcfcfcffffffd2d2d27d7d7df4f4f4fefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9fcfafafcfcad9f64ece5ccfdfbfffbfffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f6f1fdfeffaa9655fdfffed6d1d0727377ebf0efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfdffffffd3d3d3808080f1f1f1fdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefbfffffffdffe2dbc2b2a469fdfffff9fcfafffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafdfeffaf9b5af4f7f5b8b3b2929397eef3f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffefefefefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfefefeffffffffffffd6d6d6848484e7e7e7fcfcfcfefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfbfefffffdfffffdfeb0a972dbd3b6fbfffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaf7f2f8f9fdae9a59dde0de847f7ed3d4d8f8fdfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffefefefdfdfdfefefefffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefeffffffffffffdfdfdf8c8c8cd4d4d4fcfcfcfefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffefffefff9fafefffeffeeedd9a89968faf9ebfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f5f0fdfeffac9857b6b9b7847f7ef8f9fdfbfffffefcfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffebebeb949494c1c1c1fcfcfcfefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffefffdfffffffef8fdfcfffefebfb98cd6c49bf6fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f6f1fdfeffa692518b8e8cc2bdbcfdfefffbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefefdfdfdf7f7f7acacaca1a1a1f8f8f8fffffffffffffffffffdfdfdfffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfbfffffffcfffffffdfff7fffdfff7f4e698985cfff2dcfbfffffffdfffbfefffffff3fffcfff8fefffffcfffffffffffffffefefefdfdfdfffffffefefefffffffefefefffffff7f5edfdffff8d7938868987fffcfbfbfdfefbfffefffefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffefefebbbbbb878787f5f5f5fffffffcfcfcfefefefffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffefffdfffffcfefefefffdfffffffbcfcaabbdb488fffffbfafdfbfafbfffffefffffffffafcfdfbfff9fffdfffffffffefefefffffffcfcfcfffffffffffffffffffcfcfcfbf9f1e0e2e3836f2ebdc0befffffefdfffff7fcfafffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffdfdfdfffffffefefeffffffd1d1d1767676efefeffefefefffffffdfdfdfffffffefefefffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfefefefffffbfffcfffcfdfffffffffdf2f49fa165f2e4c8fdfefffffefffcfbfffefdf9fffffcf6fff5fffefffffffffffffffbfbfbfffffffefefefefefefffffffdfdfdf7f5ed8688898b7736f7faf8fffdfcfdfffffbfffefffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefefffffffcfcfcffffffe3e3e37b7b7be3e3e3fcfcfcfffffffefefefefefefffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffafffefffffffcfdfcfff9fefcfcfefefffbffd5d9afb4a86efffcfffafcfdfdfffffffefdfffffcfafffffffdfcfdfdfdfffffffdfdfdfffffffffffffffffff7f7f7ffffffc0beb6818384a4904ffdfffefffbfafcfefffafffdfffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffefefefefefeffffffeeeeee979797bcbcbcf9f9f9fbfbfbfffffffffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffdfffefffffdfdfffffffbfffbfbfffbfffefffffffab5a973d7d0b7fdfffffffffcfffdfcfbfffefffcfffffffffffffffffffffffffffffffffdfdfdfefefeffffffd4d4d4737169c6c8c9ac9857fdfffefffffefdfffffafffdfdfbfaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffefefefffffffffffff9f9f9c8c8c8828282efefeffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffefffcfef8fbfffbf9fff9fdfff7fff9ffefe4cea1a063fefbf3fffffefcfdf9fafffffff7fffdfffffffffffffffffdfdfdffffffffffffffffffdcdcdc7f7f7fb1afa7f8fafbad9958fdfffefffdfcfdfffffbfffefffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffefefefefefefdfdfdffffffefefef777777cececefffffffffffffefefefdfdfdfffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfefffffffefffffffefffbfdfffffbfffefffffbfff9fffffeffbcb885d1c6a6fffffbfafffffcfdfffffefffbfffafcfcfcfffffffffffffdfdfdffffffe2e2e28f8f8f969696f9f7effbfdfead9958fcfffdfffffefdfffff5faf8fffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffffffff8f8f89a9a9aa9a9a9f8f8f8fefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffcfffffcfffffffbfcfffdfdfffefcfcfffffefbfffffff2e6a4955df3f7e4f0fafffffcfffefffdfffff5fffffffefefefffffffefefeebebeb939393888888fffffff7f5edfdffffad9958fdfffefffcfbfdfffffbfffefffefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0e0e07d7d7ddadadafefefefffffffefefefffffffffffffffffffffffffffffffffffffffffffefefefefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffefefefffffffefefefffffffffffbfcfbffd0c7a2b8b382fffefffafffffffff9fffffffdfdfdfffefffffeffeeedf185868a919393f5f9f4f9fff9f7f5edfffffcaa9c54fffefffdfdfdfffffef8fff9fffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc8d8d8d9f9f9ffefefefffffffffffffdfdfdfdfdfdfcfcfcfffffffffffffdfdfdfffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfcfcfcfffffffffffffefefefffffffefefefffffffffff9fffdfffbf8f0a99e65f0ecd9fffafff8fff7fffefffffefffefdffdadada7c7b7da2a1a3edecf0fbfbfffdfcfff7f4f6fffeffa79951fffdfdfffefffffcfff7fffffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdddddd7d7d7dcacacafffffffcfcfcfffffffffffffdfdfdfffffffffffffffffffffffffefefefefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffefefefffffffffff8f8fbfffffeffd7d0afb1a771fffdfffafffefffefffefdffb3b4b27d7f79b1b4abf6f9f0fefef8fffffefffcfef7f5f4fffefeab9f59fffdfffaf8fefffefff6fff7fffff9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeb7b7b77c7c7cdededefffffffdfdfdfffffffffffffffffffdfdfdfffffffffffffffffffdfdfdfdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffffffffffffffffffffffef9fdfdfffefffbfffffbb3a76ddad6b9fffbffd7dad89a9c9c898a88babbb7fffffcfefdf9fffffefffdfcfffefff3f8e9fffffba49852fffdfffffefffffefffafffefffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefdfdfda2a2a28c8c8ce6e6e6fffffffcfcfcfdfdfdfefefefffffffffffffcfcfcfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefefefefffffffffffffefefefefefefefefefbfefffffefff8fffcfffdfcece5d2a79e5ec2bdbc8183838f908ee8e8e8fefdfffbf8fffffcfffef9fffffdfffffdfff7f8f4fbfafea8995bfffcfffffffffdfbfafafffffff8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefef0f0f0949494818181e6e6e6fefefefffffffdfdfdfefefefffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefdfdfdfffffffffffffbfefffffbfef9fdf7ebf5efe0d7e1897e4c767249cac7c9fffefffcfbfffffefffbfafcfffffefdfffcfbfff7fcfff7f1f8e9fdfffba79d57fffefffbfdfdfffffcf8fff6fffefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffcfcfcffffffecececa0a0a0717171cececefefefefffffffffffffbfbfbfefefefffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefefefefffffffefefefffffffffffffbfbfbfefcfcfdfeffd3d1c9788484817983b2aa999a9354faf5e6fffbfffffffffefffafdfff9f7fef7fafffefafdfff4f6fff3f2fbfbfdfea7a051fafbf7fdfefffffcfffafffefffefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfdf0f0f0bababa808080858585cdcdcdfffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffbfbfbe6e6e6b8b2b37b807e84898ab6b6b6dbe1e6fff9f5ccc594c5bd95fffffffffffcfdfff7fdfffcfbfbffe0d9febaacecb8a6f9956ee86b53a1a69564fffffbfdfffefdf9fffafffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffdfdfdfffffffcfcfcdadadaa9a9a98d8d8d8d8d8da6a6a6bdbdbdddddddf9f9f9fdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffff8f8f8e1e1e1c5c5c5a8a8a89292928989899c9b9fbdb9bededfddfcfffafbfefffffdfffffbe79d965fefebd8faf9fbf4ffffb2b6f08774e86a5aed8265ea6c52ec7d53d6ac97c8a6994ffdfffff9fdfefffffcfbfffbfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcffffffdededeb2b2b29595958a8a8a8b8b8b979797a4a4a4b1b1b1bcbcbcc5c5c5c6c6c6c7c7c7c8c8c8c3c3c3bababaaeaeaea8a8a89b9b9b8f8f8f8b8b8b959595b1b1b1d1d1d1f8fafafffefffffffffdfffefbfefffdfafffffff6dcd6b3afa67aa487fa6b3be7784fee9e93f3bfaeffc6c0f7e8edfffdfafffefbf6b0a456fafbfff9fefcfffffbfbfffbfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffbfbfbfffffffffffffffffffffffffffffffffffff7f7f7d7d7d7b0b0b09e9e9e8a8a8a8686868181817e7e7e7c7c7c7d7d7d8181818585859595959c9c9cb1b1b1d4d4d4f4f4f4fefefefdfdfdfffffffdfffcfffffffffdfffafafafdfefffefbfffffefffffef5a6a1628062b5c9c3f8f3f0ffeef2fffffffaf9fcfffffff8fdfff1fffff8a89659fdfcfffbfff9fffffefbfefffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffdfdfdfffffffffffffffffffffffffdfdfdfffffffefefefffffffffffffffffffefefefffffffffffffffffff9f9f9f2f2f2f1f1f1efefefedededf2f2f2fafafafefefefffffffffffffffffffffffffffffffffffffffffffafffaf9fbfbfffefffffdfffffffffffefffdfefffdfdffe1ddc5a19658f8ffeff9fefffffefffffffefdfcfffffffcfbfcfffffbffa9955efdfefff9fff7fffcfffbfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffcfcfcfefefefffffffefefefdfdfdfffffffffffffffffffffffffffffffffffffefefefffffffffffffffffffcfcfcfefefefffffffffffffdfdfdfdfffefcfffdfffefffffefefefdf9fffffbfbfffefafefffffeffb1a067d4cba5f7fff8fffefff8fff7fefff7fffefffbfffafffffba99a55fdfffff9fffafffdfffbfffffcfff5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefefffffffdfdfdfdfdfdfffffffefefefffffffffffffdfdfdfdfdfdfffffffffffffffffffefefefffffffffffffffffffffffffffffffefefefffffffffffffffffffffffffffffffffffffefefefdfdfdfefefefffffffefdfffdfffefdfffefffffffffefdfffff7fdfffbfafffffffeffeee4da978538fbf8eafafffff6fffcfdfafffbfffcfdfffbfffff7ab9c57fdfdfff7fdf8fffffcfafffdfffffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfefefefffffffffffffffffffffffffffffffcfcfcfffffffffffffefefefdfdfdfcfcfcfdfdfdfffffffffffffcfcfcfefefefffffffffffffdfdfdfcfcfcfffffffffffffefefefefefefffffffffffffffffffffffffffffffffbfffffffcfafffbfbfefffffdfffffffbfefffafdfffffefff2fffffbbfb17cbdb181fffff9f6fdfafbfffefffff9fdfcfffffbffa9975cfdfdfffbfffbfffefffbfefffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffffffffdfdfdfdfdfdfffffffffffffffffffffffffefefefffffffffffffefefefffffffffffffefefefefefefffffffffffffdfdfdfdfdfdfffffffffffffefefefefefefffffffffffffefefefdfdfdfefefefffffffefefefffbfffefffbf9fffaf9fdfffefafffffdfffffefffffefffbfffcfff7fff9f2ef96853cf9e6e3fdfffcf8fdfefffffcfcfffbfffffea99956fbfdfdfbfffefff9fffbfcfffdfefaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffbf4f8fdd6c39da89f5ffffffbfafefffdfefffffdfefffdffa89b57fffffefdfffffffcfffafffffffffaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfbfffefffffffcfceea29152dfd9bcfdfafffbfffefffffbfffeffa79b53fffffafcfffdfefafffafffffffefdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefef9fbfcfbfffbfbffffddd3bba4954dfffafcfbfffcfdfffcfdffffa79b53fffff9fffffcfffdfffafffffffdfeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffbfffffafff8fcfcfcfafcffad9b5adaca9cf9fdfefbfffffcfcffa69856fffffbfffffcfffcfef8ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfffffffffffdfafafffcf8fcfdebe1d79c8b3afcf8f3fdfcfefffbffa9995efffefffffffefffbfdf6fffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fffffff8fffffdfcfafff8fffffcfffcffb4aa7ac4b890fdf8effffbffa9975cfefafffffffffffefffafffefffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafffcfff8fffbfffefffff8fdfefffcfdf9f1f1eb938243efeacbfffdf4b09f5cfffcfefbfffffffefffafffefffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfff4fffefffefffffefefffdfff8fffffdfff6d6c58da6a170dfd8bfa9994cfffffefafffffefdfff9fffdfffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefe968b3bd6b89fa79d57fffff7fffff8fafffffffafffafffaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefefefefed6caa6958839b09a58fffffcfdfffef9fefdfffbfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ef90883b998832fffafffbfdfdfdfffbfffdfefffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9eae0c8837d30fffcfffffefffafef8fffbfffbfffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffcfffff2fdfff7fffafdfbfffefcfcfcf8fffcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafff5fffefafdfff8fdfffffff9f8fffcf9fefcfaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfff4faf9fefefefaf9fffffff5fafffbfffdfffdfcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfcfafffff7fffafffafefffffffefbfff8fffafffffdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000050000000701010000000500000001020100000005000000090201000000030000000000}
+\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/data/watermark.rtf b/writerfilter/qa/cppunittests/rtftok/data/watermark.rtf
new file mode 100644
index 000000000..552f93844
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/watermark.rtf
@@ -0,0 +1,47 @@
+{\rtf1
+{\header\pard\plain
+{\shp
+{\*\shpinst\shpleft0\shptop0\shpright9359\shpbottom9359\shpfhdr1\shpbxmargin\shpbxignore\shpbymargin\shpbyignore\shpwr3\shpwrk0\shpfblwtxt1\shpz1\shplid2050
+{\sp
+{\sn shapeType}
+{\sv 75}
+}
+{\sp
+{\sn pib}
+{\sv
+{\pict\picscalex914\picscaley914\piccropl0\piccropr0\piccropt0\piccropb0\picw1806\pich1806\picwgoal1024\pichgoal1024\pngblip\bliptag133373369
+89504e470d0a1a0a0000000d49484452000000400000004008040000000060b9550000000467414d410000b18f0bfc6105000000017352474200aece1ce90000
+00206348524d00007a26000080840000fa00000080e8000075300000ea6000003a98000017709cba513c00000002624b47440000aa8d2332000000096f464673
+0000000600000000000c7355d3000000097048597300000dd700000dd70142289b7800000009767041670000004c00000040009d31381b000001cd4944415468
+deedd93d4fc24018c0f17f89c6cdc44940e3e222be2c0e7e0417e3a8113571707632514012a320c6f84d34be2c2ec2b750f40be8e6e4a00113cfe14a5b69b108
+f4589ee71652eefafce0b9f42e3d7063822aaac3f641d173a75d3efee85b6582c0c8749c5eb7332cfb4e6f213d336ed29807304477b1c7a94db80ae9e9c934d0
+fcdd12e7ffcefcc9168f9a0059143b8cb0d2de581f609854073fbecc220f60b18722479d0d14abed8c8cb5d3293ce2949903b0d8a7047cb1c98541008cba840c
+a736e1d2200046b967567f740961d3b197008873cf74835002eaac7363100009ca0d4296121675d2dc1a0440d2256428625163ed2f42cf011e8245d621b42c44
+0400485261a699706d1000092fa100d4490713220240dc25e438b1090185880ca09f8ece5c28d9843b009e82471ca25069d5cb785529bd007fdbfb8541b65b2f
+531100947a51530d42c1d92f9829818e31ca4ce9421c70e427440e80712a7a89b7c8fb0906003046a5311df31cf501a01f4d0ee1b80f00bd4c398558ee0340ff
+0b939a30df17002459f05d330a080a0108400002108000042000010840000210800004200001f8ce0ddf798e30dd7b38e0ce7ea16d2abc25a819cbda225337c7
+f7ff69bf8eef7f0084e08d42bdf8a03e00000025744558746372656174652d6461746500323031302d31322d32305431373a30383a33362b30313a30307ae51b1c00000025744558746d6f646966792d6461746500323031302d31322d32305431373a30383a33372b30313a30308323669c0000000049454e44ae426082}
+}
+}
+{\sp
+{\sn pictureContrast}
+{\sv 19661}
+}
+{\sp
+{\sn pictureBrightness}
+{\sv 22938}
+}
+{\sp
+{\sn posh}
+{\sv 2}
+}
+{\sp
+{\sn posv}
+{\sv 2}
+}
+}
+}
+\par
+}
+\pard\plain\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/rtfdispatchsymbol.cxx b/writerfilter/qa/cppunittests/rtftok/rtfdispatchsymbol.cxx
new file mode 100644
index 000000000..5f4091688
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtfdispatchsymbol.cxx
@@ -0,0 +1,72 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtfdispatchsymbol.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/rtftok/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testPage)
+{
+ // Given a file with a \page and 2 \par tokens:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "page.rtf";
+
+ // When loading that file:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure we get exactly two paragraphs:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xText(xTextDocument->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration();
+ xParagraphs->nextElement();
+ xParagraphs->nextElement();
+ // Without the accompanying fix in place, this test would have failed, the document had 3
+ // paragraphs, not 2.
+ CPPUNIT_ASSERT(!xParagraphs->hasMoreElements());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/rtftok/rtfdispatchvalue.cxx b/writerfilter/qa/cppunittests/rtftok/rtfdispatchvalue.cxx
new file mode 100644
index 000000000..4479a0c3c
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtfdispatchvalue.cxx
@@ -0,0 +1,107 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtfdispatchvalue.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/rtftok/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testFollowStyle)
+{
+ // Given a file with \snext:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "follow-style.rtf";
+
+ // When loading that file:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure we set the follow of the para style correctly:
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(
+ xStyleFamilies->getByName("ParagraphStyles"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Heading 1"),
+ uno::UNO_QUERY);
+ OUString aFollowStyle;
+ xStyle->getPropertyValue("FollowStyle") >>= aFollowStyle;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Standard
+ // - Actual : Heading 1
+ // i.e. \snext was ignored.
+ CPPUNIT_ASSERT_EQUAL(OUString("Standard"), aFollowStyle);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorder)
+{
+ // Given a document with a top margin and a border which has more spacing than the margin:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "negative-page-border.rtf";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the border distance is negative, so it can appear at the correct
+ // position:
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(getComponent(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xStyle(xStyleFamily->getByName("Standard"), uno::UNO_QUERY);
+ auto nTopMargin = xStyle->getPropertyValue("TopMargin").get<sal_Int32>();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(501), nTopMargin);
+ auto aTopBorder = xStyle->getPropertyValue("TopBorder").get<table::BorderLine2>();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(159), aTopBorder.LineWidth);
+ auto nTopBorderDistance = xStyle->getPropertyValue("TopBorderDistance").get<sal_Int32>();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: -646
+ // - Actual : 342
+ // i.e. the border negative distance was lost.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-646), nTopBorderDistance);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/rtftok/rtfdocumentimpl.cxx b/writerfilter/qa/cppunittests/rtftok/rtfdocumentimpl.cxx
new file mode 100644
index 000000000..f33f0f0e5
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtfdocumentimpl.cxx
@@ -0,0 +1,149 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+#include <vcl/graph.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtfdocumentimpl.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/rtftok/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testPicwPich)
+{
+ // Given a document with a WMF file where picwgoal and picscalex is provided, so picw is not
+ // relevant:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "picw-pich.rtf";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the graphic's preferred size is correct:
+ uno::Reference<drawing::XDrawPageSupplier> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xTextDocument->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<graphic::XGraphic> xGraphic;
+ xShape->getPropertyValue("Graphic") >>= xGraphic;
+ Graphic aGraphic(xGraphic);
+ Size aPrefSize = aGraphic.GetPrefSize();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2619
+ // - Actual : 132
+ // i.e. the graphic width didn't match 2.62 cm from the Word UI.
+ CPPUNIT_ASSERT_EQUAL(static_cast<tools::Long>(2619), aPrefSize.Width());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testCharHiddenInTable)
+{
+ // Given a document with a table, and a hidden \line in it:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "char-hidden-intbl.rtf";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that line is indeed hidden:
+ uno::Reference<text::XTextTablesSupplier> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xTables(xTextDocument->getTextTables(), uno::UNO_QUERY);
+ uno::Reference<text::XTextTable> xTable(xTables->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xCell(xTable->getCellByName("B1"),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xCell->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ uno::Reference<beans::XPropertySet> xPortion(xPortions->nextElement(), uno::UNO_QUERY);
+ bool bCharHidden{};
+ xPortion->getPropertyValue("CharHidden") >>= bCharHidden;
+ // Without the accompanying fix in place, this test would have failed, the newline was not
+ // hidden.
+ CPPUNIT_ASSERT(bCharHidden);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDuplicatedImage)
+{
+ // Given a document with 2 images:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "duplicated-image.rtf";
+
+ // When importing that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure no duplicated images are created:
+ uno::Reference<drawing::XDrawPageSupplier> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xTextDocument->getDrawPage();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 3
+ // i.e. there was a 3rd, duplicated image.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xDrawPage->getCount());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testOldParaNumLeftMargin)
+{
+ // Given a document with 3 paragraphs, the third one with a left indent:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "old-para-num-left-margin.rtf";
+
+ // When importing that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure that the third paragraph has a left indent:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xText(xTextDocument->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration();
+ xParagraphs->nextElement();
+ xParagraphs->nextElement();
+ uno::Reference<beans::XPropertySet> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
+ sal_Int32 nParaLeftMargin{};
+ xParagraph->getPropertyValue("ParaLeftMargin") >>= nParaLeftMargin;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2101
+ // - Actual : 0
+ // i.e. the left indent was 0, not 1191 twips (from the file) in mm100.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2101), nParaLeftMargin);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/rtftok/rtfsdrimport.cxx b/writerfilter/qa/cppunittests/rtftok/rtfsdrimport.cxx
new file mode 100644
index 000000000..74af1dcf1
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtfsdrimport.cxx
@@ -0,0 +1,94 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtfsdrimport.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/rtftok/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testPictureInTextframe)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "picture-in-textframe.rtf";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xTextDocument->getDrawPage();
+ uno::Reference<beans::XPropertySet> xInnerShape(xDrawPage->getByIndex(1), uno::UNO_QUERY);
+ text::TextContentAnchorType eAnchorType = text::TextContentAnchorType_AT_PARAGRAPH;
+ xInnerShape->getPropertyValue("AnchorType") >>= eAnchorType;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 4
+ // i.e. the properties of the inner shape (including its anchor type and bitmap fill) were lost
+ // on import.
+ CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AS_CHARACTER, eAnchorType);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testWatermark)
+{
+ // Given a document with a picture watermark, and the "washout" checkbox is ticked on the Word
+ // UI:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "watermark.rtf";
+
+ // When loading that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the watermark effect is not lost on import:
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPagesSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPagesSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ drawing::ColorMode eMode{};
+ xShape->getPropertyValue("GraphicColorMode") >>= eMode;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 3
+ // - Actual : 0
+ // i.e. the color mode was STANDARD, not WATERMARK.
+ CPPUNIT_ASSERT_EQUAL(drawing::ColorMode_WATERMARK, eMode);
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/rtftok/rtfsprm.cxx b/writerfilter/qa/cppunittests/rtftok/rtfsprm.cxx
new file mode 100644
index 000000000..abb0a19f4
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtfsprm.cxx
@@ -0,0 +1,83 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtfsprm.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/rtftok/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testLeftMarginDedup)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "left-margin-dedup.rtf";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xText(xTextDocument->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration();
+ uno::Reference<beans::XPropertySet> xParagraph(xParagraphs->nextElement(), uno::UNO_QUERY);
+ sal_Int32 nLeftMargin = 0;
+ xParagraph->getPropertyValue("ParaLeftMargin") >>= nLeftMargin;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1270), nLeftMargin);
+
+ uno::Reference<beans::XPropertyState> xParagraphState(xParagraph, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DIRECT_VALUE,
+ xParagraphState->getPropertyState("ParaLeftMargin"));
+
+ xParagraph.set(xParagraphs->nextElement(), uno::UNO_QUERY);
+ nLeftMargin = 0;
+ xParagraph->getPropertyValue("ParaLeftMargin") >>= nLeftMargin;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1270), nLeftMargin);
+
+ xParagraphState.set(xParagraph, uno::UNO_QUERY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0 (DIRECT_VALUE)
+ // - Actual : 1 (DEFAULT_VALUE)
+ // i.e. the left margin was not a direct formatting, which means left margin from the numbering
+ // was used instead.
+ CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DIRECT_VALUE,
+ xParagraphState->getPropertyState("ParaLeftMargin"));
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/rtftok/rtftokenizer.cxx b/writerfilter/qa/cppunittests/rtftok/rtftokenizer.cxx
new file mode 100644
index 000000000..530e9bb72
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtftokenizer.cxx
@@ -0,0 +1,63 @@
+/* -*- 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 <test/bootstrapfixture.hxx>
+#include <unotest/macros_test.hxx>
+
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtftokenizer.cxx.
+class Test : public test::BootstrapFixture, public unotest::MacrosTest
+{
+private:
+ uno::Reference<lang::XComponent> mxComponent;
+
+public:
+ void setUp() override;
+ void tearDown() override;
+ uno::Reference<lang::XComponent>& getComponent() { return mxComponent; }
+};
+
+void Test::setUp()
+{
+ test::BootstrapFixture::setUp();
+
+ mxDesktop.set(frame::Desktop::create(mxComponentContext));
+}
+
+void Test::tearDown()
+{
+ if (mxComponent.is())
+ mxComponent->dispose();
+
+ test::BootstrapFixture::tearDown();
+}
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/rtftok/data/";
+
+CPPUNIT_TEST_FIXTURE(Test, testInvalidHex)
+{
+ // Given a document with a markup like "\'3?":
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "invalid-hex.rtf";
+
+ // When load that document:
+ getComponent() = loadFromDesktop(aURL);
+
+ // Then make sure the result matches Word, rather than just refusing to import the document:
+ uno::Reference<text::XTextDocument> xTextDocument(getComponent(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString::fromUtf8("xřx"), xTextDocument->getText()->getString());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/ooxml/watch-generated-code.sh b/writerfilter/qa/ooxml/watch-generated-code.sh
new file mode 100755
index 000000000..d7026be82
--- /dev/null
+++ b/writerfilter/qa/ooxml/watch-generated-code.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+if [ ! -e bin/get_config_variables ]; then
+ cd ../../..
+fi
+
+. bin/get_config_variables SRCDIR
+
+if [ "$PWD" != "$SRCDIR" ]; then
+ echo "error: not in the expected SRCDIR"
+ exit 1
+fi
+
+cd writerfilter
+echo 'include Makefile' > watch.mk
+echo 'watch:' >> watch.mk
+echo $'\techo $(writerfilter_ALL)' >> watch.mk
+mydir=workdir/CustomTarget/writerfilter
+writerfilter_ALL=$(make -sr -f watch.mk watch|sed "s|$SRCDIR/$mydir/||g")
+rm watch.mk
+cd - >/dev/null
+
+case $1 in
+reference)
+ rm -rf $mydir-reference
+ mkdir -p $mydir-reference/source/ooxml
+ for i in $writerfilter_ALL
+ do
+ cp $mydir/"$i" $mydir-reference/"$i"
+ done
+ ;;
+compare)
+ for i in $writerfilter_ALL
+ do
+ if [ "$(basename "$i")" == "model_preprocessed.xml" ]; then
+ continue
+ fi
+ diff -u $mydir-reference/"$i" $mydir/"$i"
+ done
+ ;;
+*)
+ echo "usage: $0 [ reference | compare ]"
+ echo
+ echo "$0 first saves a reference output of all generated files by writerfilter, then"
+ echo "allows comparing against it. This helps seeing the effect of changes made on"
+ echo "the code generator scripts."
+ ;;
+esac
+
+# vi:set shiftwidth=4 expandtab:
diff --git a/writerfilter/source/dmapper/BorderHandler.cxx b/writerfilter/source/dmapper/BorderHandler.cxx
new file mode 100644
index 000000000..cb8e38c75
--- /dev/null
+++ b/writerfilter/source/dmapper/BorderHandler.cxx
@@ -0,0 +1,213 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "BorderHandler.hxx"
+#include "TDefTableHandler.hxx"
+#include "PropertyMap.hxx"
+#include "ConversionHelper.hxx"
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <o3tl/enumarray.hxx>
+#include <o3tl/enumrange.hxx>
+#include <ooxml/resourceids.hxx>
+#include <filter/msfilter/util.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/color.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+BorderHandler::BorderHandler( bool bOOXML ) :
+LoggedProperties("BorderHandler"),
+m_nLineWidth(15), // Word default, in twips
+m_nLineType(0),
+m_nLineColor(0),
+m_nLineDistance(0),
+m_bShadow(false),
+m_bOOXML( bOOXML )
+{
+ m_aFilledLines.fill(false);
+ m_aBorderLines.fill(table::BorderLine2());
+}
+
+BorderHandler::~BorderHandler()
+{
+}
+
+void BorderHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_Border_sz:
+ // width of a single line in 1/8 pt, max of 32 pt -> twip * 5 / 2.
+ m_nLineWidth = nIntValue * 5 / 2;
+ appendGrabBag("sz", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ m_nLineType = nIntValue;
+ appendGrabBag("val", TDefTableHandler::getBorderTypeString(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_color:
+ m_nLineColor = nIntValue;
+ appendGrabBag("color", msfilter::util::ConvertColorOU(Color(ColorTransparency, nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Border_space: // border distance in points
+ m_nLineDistance = ConversionHelper::convertTwipToMM100( nIntValue * 20 );
+ appendGrabBag("space", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ m_bShadow = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Border_frame:
+ case NS_ooxml::LN_CT_Border_themeTint:
+ appendGrabBag("themeTint", OUString::number(nIntValue, 16));
+ break;
+ case NS_ooxml::LN_CT_Border_themeColor:
+ appendGrabBag("themeColor", TDefTableHandler::getThemeColorTypeString(nIntValue));
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+void BorderHandler::lcl_sprm(Sprm & rSprm)
+{
+ BorderPosition pos;
+ const bool rtl = false; // TODO detect
+ OUString aBorderPos;
+ switch( rSprm.getId())
+ {
+ case NS_ooxml::LN_CT_TblBorders_top:
+ pos = BorderPosition::Top;
+ aBorderPos = "top";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_start:
+ pos = rtl ? BorderPosition::Right : BorderPosition::Left;
+ aBorderPos = "start";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_left:
+ pos = BorderPosition::Left;
+ aBorderPos = "left";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_bottom:
+ pos = BorderPosition::Bottom;
+ aBorderPos = "bottom";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_end:
+ pos = rtl ? BorderPosition::Left : BorderPosition::Right;
+ aBorderPos = "end";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_right:
+ pos = BorderPosition::Right;
+ aBorderPos = "right";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_insideH:
+ pos = BorderPosition::Horizontal;
+ aBorderPos = "insideH";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_insideV:
+ pos = BorderPosition::Vertical;
+ aBorderPos = "insideV";
+ break;
+ default:
+ return;
+ }
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties)
+ {
+ std::vector<beans::PropertyValue> aSavedGrabBag;
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ aSavedGrabBag = m_aInteropGrabBag;
+ m_aInteropGrabBag.clear();
+ }
+ pProperties->resolve(*this);
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ aSavedGrabBag.push_back(getInteropGrabBag(aBorderPos));
+ m_aInteropGrabBag = aSavedGrabBag;
+ }
+ }
+ ConversionHelper::MakeBorderLine( m_nLineWidth, m_nLineType, m_nLineColor,
+ m_aBorderLines[ pos ], m_bOOXML );
+ m_aFilledLines[ pos ] = true;
+}
+
+PropertyMapPtr BorderHandler::getProperties()
+{
+ static const o3tl::enumarray<BorderPosition, PropertyIds> aPropNames =
+ {
+ PROP_TOP_BORDER,
+ PROP_LEFT_BORDER,
+ PROP_BOTTOM_BORDER,
+ PROP_RIGHT_BORDER,
+ META_PROP_HORIZONTAL_BORDER,
+ META_PROP_VERTICAL_BORDER
+ };
+ PropertyMapPtr pPropertyMap(new PropertyMap);
+ // don't fill in default properties
+ if( m_bOOXML )
+ {
+ for( auto nProp: o3tl::enumrange<BorderPosition>())
+ {
+ if ( m_aFilledLines[nProp] ) {
+ pPropertyMap->Insert( aPropNames[nProp], uno::Any( m_aBorderLines[nProp] ) );
+ }
+ }
+ }
+ return pPropertyMap;
+}
+
+table::BorderLine2 BorderHandler::getBorderLine()
+{
+ table::BorderLine2 aBorderLine;
+ ConversionHelper::MakeBorderLine( m_nLineWidth, m_nLineType, m_nLineColor, aBorderLine, m_bOOXML );
+ return aBorderLine;
+}
+
+
+void BorderHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue BorderHandler::getInteropGrabBag(const OUString& aName)
+{
+ beans::PropertyValue aRet;
+ if (aName.isEmpty())
+ aRet.Name = m_aInteropGrabBagName;
+ else
+ aRet.Name = aName;
+
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+void BorderHandler::appendGrabBag(const OUString& aKey, const OUString& aValue)
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ m_aInteropGrabBag.push_back(aProperty);
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/BorderHandler.hxx b/writerfilter/source/dmapper/BorderHandler.hxx
new file mode 100644
index 000000000..6c607ca5a
--- /dev/null
+++ b/writerfilter/source/dmapper/BorderHandler.hxx
@@ -0,0 +1,78 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+#include "LoggedResources.hxx"
+#include "PropertyMap.hxx"
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <o3tl/enumarray.hxx>
+
+namespace writerfilter::dmapper
+{
+class PropertyMap;
+class BorderHandler : public LoggedProperties
+{
+private:
+ //todo: order is a guess
+ enum class BorderPosition
+ {
+ Top,
+ Left,
+ Bottom,
+ Right,
+ Horizontal,
+ Vertical,
+ LAST = Vertical
+ };
+
+ //values of the current border
+ sal_Int32 m_nLineWidth;
+ sal_Int32 m_nLineType;
+ sal_Int32 m_nLineColor;
+ sal_Int32 m_nLineDistance;
+ bool m_bShadow;
+ bool m_bOOXML;
+
+ o3tl::enumarray<BorderPosition, bool> m_aFilledLines;
+ o3tl::enumarray<BorderPosition, css::table::BorderLine2> m_aBorderLines;
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+ void appendGrabBag(const OUString& aKey, const OUString& aValue);
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ explicit BorderHandler( bool bOOXML );
+ virtual ~BorderHandler() override;
+
+ PropertyMapPtr getProperties();
+ css::table::BorderLine2 getBorderLine();
+ sal_Int32 getLineDistance() const { return m_nLineDistance;}
+ sal_Int32 getLineType() const { return m_nLineType;}
+ bool getShadow() const { return m_bShadow;}
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag(const OUString& aName = OUString());
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/CellColorHandler.cxx b/writerfilter/source/dmapper/CellColorHandler.cxx
new file mode 100644
index 000000000..439806e20
--- /dev/null
+++ b/writerfilter/source/dmapper/CellColorHandler.cxx
@@ -0,0 +1,331 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "CellColorHandler.hxx"
+#include "PropertyMap.hxx"
+#include "TDefTableHandler.hxx"
+#include <ooxml/resourceids.hxx>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/ShadingPattern.hpp>
+#include <filter/msfilter/util.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/color.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+CellColorHandler::CellColorHandler() :
+LoggedProperties("CellColorHandler"),
+m_nShadingPattern( drawing::ShadingPattern::CLEAR ),
+m_nColor( 0xffffffff ),
+m_nFillColor( 0xffffffff ),
+m_bAutoFillColor( true ),
+m_bFillSpecified( false ),
+ m_OutputFormat( Form )
+{
+}
+
+CellColorHandler::~CellColorHandler()
+{
+}
+
+// ST_Shd strings are converted to integers by the tokenizer, store strings in
+// the InteropGrabBag
+static uno::Any lcl_ConvertShd(sal_Int32 nIntValue)
+{
+ OUString aRet;
+ // This should be in sync with the ST_Shd list in ooxml's model.xml.
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Shd_clear: aRet = "clear"; break;
+ case NS_ooxml::LN_Value_ST_Shd_solid: aRet = "solid"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct5: aRet = "pct5"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct10: aRet = "pct10"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct20: aRet = "pct20"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct25: aRet = "pct25"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct30: aRet = "pct30"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct40: aRet = "pct40"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct50: aRet = "pct50"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct60: aRet = "pct60"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct70: aRet = "pct70"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct75: aRet = "pct75"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct80: aRet = "pct80"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct90: aRet = "pct90"; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzStripe: aRet = "horzStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_vertStripe: aRet = "vertStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_reverseDiagStripe: aRet = "reverseDiagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagStripe: aRet = "diagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzCross: aRet = "horzCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagCross: aRet = "diagCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzStripe: aRet = "thinHorzStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinVertStripe: aRet = "thinVertStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinReverseDiagStripe: aRet = "thinReverseDiagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagStripe: aRet = "thinDiagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzCross: aRet = "thinHorzCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagCross: aRet = "thinDiagCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct12: aRet = "pct12"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct15: aRet = "pct15"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct35: aRet = "pct35"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct37: aRet = "pct37"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct45: aRet = "pct45"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct55: aRet = "pct55"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct62: aRet = "pct62"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct65: aRet = "pct65"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct85: aRet = "pct85"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct87: aRet = "pct87"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct95: aRet = "pct95"; break;
+ case NS_ooxml::LN_Value_ST_Shd_nil: aRet = "nil"; break;
+ }
+ return uno::Any(aRet);
+}
+
+void CellColorHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_Shd_val:
+ {
+ createGrabBag("val", lcl_ConvertShd(nIntValue));
+ m_nShadingPattern = nIntValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_Shd_fill:
+ createGrabBag("fill", uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, nIntValue))));
+ if( nIntValue == sal_Int32(COL_AUTO) )
+ nIntValue = 0xffffff; //fill color auto means white
+ else
+ m_bAutoFillColor = false;
+
+ m_nFillColor = nIntValue;
+ m_bFillSpecified = true;
+ break;
+ case NS_ooxml::LN_CT_Shd_color:
+ createGrabBag("color", uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, nIntValue))));
+ if( nIntValue == sal_Int32(COL_AUTO) )
+ nIntValue = 0; //shading color auto means black
+ //color of the shading
+ m_nColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Shd_themeFill:
+ createGrabBag("themeFill", uno::Any(TDefTableHandler::getThemeColorTypeString(nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeFillShade:
+ createGrabBag("themeFillShade", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeFillTint:
+ createGrabBag("themeFillTint", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeColor:
+ createGrabBag("themeColor", uno::Any(TDefTableHandler::getThemeColorTypeString(nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeShade:
+ createGrabBag("themeShade", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeTint:
+ createGrabBag("themeTint", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+void CellColorHandler::lcl_sprm(Sprm &) {}
+
+TablePropertyMapPtr CellColorHandler::getProperties()
+{
+ TablePropertyMapPtr pPropertyMap(new TablePropertyMap);
+
+ // Code from binary word filter (the values are out of 1000)
+ sal_Int32 nWW8BrushStyle = 0;
+ switch (m_nShadingPattern)
+ {
+ // Clear-Brush
+ case NS_ooxml::LN_Value_ST_Shd_clear: nWW8BrushStyle = 0; break;
+ // Solid-Brush
+ case NS_ooxml::LN_Value_ST_Shd_solid: nWW8BrushStyle = 1000; break;
+ // Percent values
+ case NS_ooxml::LN_Value_ST_Shd_pct5: nWW8BrushStyle = 50; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct10: nWW8BrushStyle = 100; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct20: nWW8BrushStyle = 200; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct25: nWW8BrushStyle = 250; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct30: nWW8BrushStyle = 300; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct40: nWW8BrushStyle = 400; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct50: nWW8BrushStyle = 500; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct60: nWW8BrushStyle = 600; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct70: nWW8BrushStyle = 700; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct75: nWW8BrushStyle = 750; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct80: nWW8BrushStyle = 800; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct90: nWW8BrushStyle = 900; break;
+ // Special cases
+ case NS_ooxml::LN_Value_ST_Shd_horzStripe: nWW8BrushStyle = 333; break; // Dark Horizontal
+ case NS_ooxml::LN_Value_ST_Shd_vertStripe: nWW8BrushStyle = 333; break; // Dark Vertical
+ case NS_ooxml::LN_Value_ST_Shd_reverseDiagStripe: nWW8BrushStyle = 333; break; // Dark Forward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_diagStripe: nWW8BrushStyle = 333; break; // Dark Backward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_horzCross: nWW8BrushStyle = 333; break; // Dark Cross
+ case NS_ooxml::LN_Value_ST_Shd_diagCross: nWW8BrushStyle = 333; break; // Dark Diagonal Cross
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzStripe: nWW8BrushStyle = 333; break; // Horizontal
+ case NS_ooxml::LN_Value_ST_Shd_thinVertStripe: nWW8BrushStyle = 333; break; // Vertical
+ case NS_ooxml::LN_Value_ST_Shd_thinReverseDiagStripe: nWW8BrushStyle = 333; break; // Forward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagStripe: nWW8BrushStyle = 333; break; // Backward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzCross: nWW8BrushStyle = 333; break; // Cross
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagCross: nWW8BrushStyle = 333; break; // 25 Diagonal Cross
+ // Different shading types
+ case NS_ooxml::LN_Value_ST_Shd_pct12: nWW8BrushStyle = 125; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct15: nWW8BrushStyle = 150; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct35: nWW8BrushStyle = 350; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct37: nWW8BrushStyle = 375; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct45: nWW8BrushStyle = 450; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct55: nWW8BrushStyle = 550; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct62: nWW8BrushStyle = 625; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct65: nWW8BrushStyle = 650; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct85: nWW8BrushStyle = 850; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct87: nWW8BrushStyle = 875; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct95: nWW8BrushStyle = 950; break;
+ }
+
+ sal_Int32 nApplyColor = 0;
+ if( !nWW8BrushStyle )
+ {
+ // Clear-Brush
+ if ( m_bFillSpecified && m_bAutoFillColor )
+ nApplyColor = sal_Int32(COL_AUTO);
+ else
+ nApplyColor = m_nFillColor;
+ }
+ else
+ {
+ sal_Int32 nFore = m_nColor;
+ sal_Int32 nBack = m_nFillColor;
+
+ sal_uInt32 nRed = ((nFore & 0xff0000)>>0x10) * nWW8BrushStyle;
+ sal_uInt32 nGreen = ((nFore & 0xff00)>>0x8) * nWW8BrushStyle;
+ sal_uInt32 nBlue = (nFore & 0xff) * nWW8BrushStyle;
+ nRed += ((nBack & 0xff0000)>>0x10) * (1000L - nWW8BrushStyle);
+ nGreen += ((nBack & 0xff00)>>0x8)* (1000L - nWW8BrushStyle);
+ nBlue += (nBack & 0xff) * (1000L - nWW8BrushStyle);
+
+ nApplyColor = ( (nRed/1000) << 0x10 ) + ((nGreen/1000) << 8) + nBlue/1000;
+ }
+
+ // Check if it is a 'Character'
+ if (m_OutputFormat == Character)
+ {
+ sal_Int32 nShadingPattern = drawing::ShadingPattern::CLEAR;
+ switch (m_nShadingPattern)
+ {
+ case NS_ooxml::LN_Value_ST_Shd_clear: nShadingPattern = drawing::ShadingPattern::CLEAR; break;
+ case NS_ooxml::LN_Value_ST_Shd_solid: nShadingPattern = drawing::ShadingPattern::SOLID; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct5: nShadingPattern = drawing::ShadingPattern::PCT5; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct10: nShadingPattern = drawing::ShadingPattern::PCT10; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct20: nShadingPattern = drawing::ShadingPattern::PCT20; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct25: nShadingPattern = drawing::ShadingPattern::PCT25; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct30: nShadingPattern = drawing::ShadingPattern::PCT30; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct40: nShadingPattern = drawing::ShadingPattern::PCT40; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct50: nShadingPattern = drawing::ShadingPattern::PCT50; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct60: nShadingPattern = drawing::ShadingPattern::PCT60; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct70: nShadingPattern = drawing::ShadingPattern::PCT70; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct75: nShadingPattern = drawing::ShadingPattern::PCT75; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct80: nShadingPattern = drawing::ShadingPattern::PCT80; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct90: nShadingPattern = drawing::ShadingPattern::PCT90; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzStripe: nShadingPattern = drawing::ShadingPattern::HORZ_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_vertStripe: nShadingPattern = drawing::ShadingPattern::VERT_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_reverseDiagStripe: nShadingPattern = drawing::ShadingPattern::REVERSE_DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagStripe: nShadingPattern = drawing::ShadingPattern::DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzCross: nShadingPattern = drawing::ShadingPattern::HORZ_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagCross: nShadingPattern = drawing::ShadingPattern::DIAG_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzStripe: nShadingPattern = drawing::ShadingPattern::THIN_HORZ_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinVertStripe: nShadingPattern = drawing::ShadingPattern::THIN_VERT_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinReverseDiagStripe: nShadingPattern = drawing::ShadingPattern::THIN_REVERSE_DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagStripe: nShadingPattern = drawing::ShadingPattern::THIN_DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzCross: nShadingPattern = drawing::ShadingPattern::THIN_HORZ_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagCross: nShadingPattern = drawing::ShadingPattern::THIN_DIAG_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct12: nShadingPattern = drawing::ShadingPattern::PCT12; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct15: nShadingPattern = drawing::ShadingPattern::PCT15; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct35: nShadingPattern = drawing::ShadingPattern::PCT35; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct37: nShadingPattern = drawing::ShadingPattern::PCT37; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct45: nShadingPattern = drawing::ShadingPattern::PCT45; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct55: nShadingPattern = drawing::ShadingPattern::PCT55; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct62: nShadingPattern = drawing::ShadingPattern::PCT62; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct65: nShadingPattern = drawing::ShadingPattern::PCT65; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct85: nShadingPattern = drawing::ShadingPattern::PCT85; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct87: nShadingPattern = drawing::ShadingPattern::PCT87; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct95: nShadingPattern = drawing::ShadingPattern::PCT95; break;
+ }
+
+ // Write the shading pattern property
+ pPropertyMap->Insert(PROP_CHAR_SHADING_VALUE, uno::Any( nShadingPattern ));
+ }
+
+ if (m_OutputFormat == Paragraph && m_nShadingPattern != NS_ooxml::LN_Value_ST_Shd_nil)
+ {
+ if (nWW8BrushStyle || !m_bAutoFillColor)
+ pPropertyMap->Insert(PROP_FILL_STYLE, uno::Any(drawing::FillStyle_SOLID));
+ else if (m_bFillSpecified) // m_bAutoFillColor == true
+ pPropertyMap->Insert(PROP_FILL_STYLE, uno::Any(drawing::FillStyle_NONE));
+
+ pPropertyMap->Insert(PROP_FILL_COLOR, uno::Any(nApplyColor));
+ }
+ else if ( nWW8BrushStyle || !m_bAutoFillColor || m_bFillSpecified )
+ pPropertyMap->Insert( m_OutputFormat == Form ? PROP_BACK_COLOR
+ : PROP_CHAR_BACK_COLOR, uno::Any( nApplyColor ));
+
+ createGrabBag("originalColor", uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, nApplyColor))));
+
+ return pPropertyMap;
+}
+
+void CellColorHandler::createGrabBag(const OUString& aName, const uno::Any& rAny)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+
+ beans::PropertyValue aValue;
+ aValue.Name = aName;
+ aValue.Value = rAny;
+ m_aInteropGrabBag.push_back(aValue);
+}
+
+void CellColorHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue CellColorHandler::getInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = m_aInteropGrabBagName;
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+void CellColorHandler::disableInteropGrabBag()
+{
+ m_aInteropGrabBagName.clear();
+ m_aInteropGrabBag.clear();
+}
+
+bool CellColorHandler::isInteropGrabBagEnabled() const
+{
+ return !(m_aInteropGrabBagName.isEmpty());
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/CellColorHandler.hxx b/writerfilter/source/dmapper/CellColorHandler.hxx
new file mode 100644
index 000000000..a011cd9fd
--- /dev/null
+++ b/writerfilter/source/dmapper/CellColorHandler.hxx
@@ -0,0 +1,66 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include "PropertyMap.hxx"
+#include <vector>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+class TablePropertyMap;
+class CellColorHandler : public LoggedProperties
+{
+public:
+ enum OutputFormat { Form, Paragraph, Character }; // for what part of the document
+private:
+ sal_Int32 m_nShadingPattern;
+ sal_Int32 m_nColor;
+ sal_Int32 m_nFillColor;
+ bool m_bAutoFillColor;
+ bool m_bFillSpecified;
+ OutputFormat m_OutputFormat;
+
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ void createGrabBag(const OUString& aName, const css::uno::Any& rValue);
+
+public:
+ CellColorHandler( );
+ virtual ~CellColorHandler() override;
+
+ TablePropertyMapPtr getProperties();
+
+ void setOutputFormat( OutputFormat format ) { m_OutputFormat = format; }
+
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag();
+ void disableInteropGrabBag();
+ bool isInteropGrabBagEnabled() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/CellMarginHandler.cxx b/writerfilter/source/dmapper/CellMarginHandler.cxx
new file mode 100644
index 000000000..8b7b5fa77
--- /dev/null
+++ b/writerfilter/source/dmapper/CellMarginHandler.cxx
@@ -0,0 +1,177 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "CellMarginHandler.hxx"
+#include "ConversionHelper.hxx"
+#include <ooxml/resourceids.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+using namespace ::writerfilter;
+
+CellMarginHandler::CellMarginHandler() :
+LoggedProperties("CellMarginHandler"),
+m_nValue( 0 ),
+m_nWidth( 0 ),
+m_nType( 0 ),
+m_nLeftMargin( 0 ),
+m_bLeftMarginValid( false ),
+m_nRightMargin( 0 ),
+m_bRightMarginValid( false ),
+m_nTopMargin( 0 ),
+m_bTopMarginValid( false ),
+m_nBottomMargin( 0 ),
+m_bBottomMarginValid( false )
+{
+}
+
+CellMarginHandler::~CellMarginHandler()
+{
+}
+
+void CellMarginHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_TblWidth_w:
+ m_nWidth = nIntValue;
+ m_nValue = ConversionHelper::convertTwipToMM100Unsigned( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_TblWidth_type:
+ SAL_WARN_IF(NS_ooxml::LN_Value_ST_TblWidth_dxa != sal::static_int_cast<Id>(nIntValue), "writerfilter", "CellMarginHandler: cell margins work for absolute values only");
+ m_nType = nIntValue;
+ break;
+ default:
+ SAL_WARN("writerfilter", "CellMarginHandler::lcl_attribute: unknown attribute");
+ }
+}
+
+void CellMarginHandler::createGrabBag(const OUString& aName)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+
+ beans::PropertyValue aRet;
+ aRet.Name = aName;
+
+ OUString sType;
+ switch (m_nType)
+ {
+ case NS_ooxml::LN_Value_ST_TblWidth_nil: sType = "nil"; break;
+ case NS_ooxml::LN_Value_ST_TblWidth_pct: sType = "pct"; break;
+ case NS_ooxml::LN_Value_ST_TblWidth_dxa: sType = "dxa"; break;
+ case NS_ooxml::LN_Value_ST_TblWidth_auto: sType = "auto"; break;
+ }
+ uno::Sequence<beans::PropertyValue> aSeq( comphelper::InitPropertySequence({
+ { "w", uno::Any(m_nWidth) },
+ { "type", uno::Any(sType) }
+ }));
+
+ aRet.Value <<= aSeq;
+ m_aInteropGrabBag.push_back(aRet);
+}
+
+void CellMarginHandler::lcl_sprm(Sprm & rSprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties)
+ {
+ pProperties->resolve( *this );
+ const bool rtl = false; // TODO
+ switch( rSprm.getId() )
+ {
+ case NS_ooxml::LN_CT_TblCellMar_top:
+ case NS_ooxml::LN_CT_TcMar_top:
+ m_nTopMargin = m_nValue;
+ m_bTopMarginValid = true;
+ createGrabBag("top");
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_start:
+ case NS_ooxml::LN_CT_TcMar_start:
+ if( rtl )
+ {
+ m_nRightMargin = m_nValue;
+ m_bRightMarginValid = true;
+ }
+ else
+ {
+ m_nLeftMargin = m_nValue;
+ m_bLeftMarginValid = true;
+ }
+ createGrabBag("start");
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_left:
+ case NS_ooxml::LN_CT_TcMar_left:
+ m_nLeftMargin = m_nValue;
+ m_bLeftMarginValid = true;
+ createGrabBag("left");
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_bottom:
+ case NS_ooxml::LN_CT_TcMar_bottom:
+ m_nBottomMargin = m_nValue;
+ m_bBottomMarginValid = true;
+ createGrabBag("bottom");
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_end:
+ case NS_ooxml::LN_CT_TcMar_end:
+ if( rtl )
+ {
+ m_nLeftMargin = m_nValue;
+ m_bLeftMarginValid = true;
+ }
+ else
+ {
+ m_nRightMargin = m_nValue;
+ m_bRightMarginValid = true;
+ }
+ createGrabBag("end");
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_right:
+ case NS_ooxml::LN_CT_TcMar_right:
+ m_nRightMargin = m_nValue;
+ m_bRightMarginValid = true;
+ createGrabBag("right");
+ break;
+ default:
+ SAL_WARN("writerfilter", "CellMarginHandler::lcl_sprm: unknown sprm");
+ }
+ }
+ m_nValue = 0;
+}
+
+void CellMarginHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue CellMarginHandler::getInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = m_aInteropGrabBagName;
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/CellMarginHandler.hxx b/writerfilter/source/dmapper/CellMarginHandler.hxx
new file mode 100644
index 000000000..8dcbf2dc5
--- /dev/null
+++ b/writerfilter/source/dmapper/CellMarginHandler.hxx
@@ -0,0 +1,64 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+class TablePropertyMap;
+class CellMarginHandler : public LoggedProperties
+{
+private:
+ sal_Int32 m_nValue; ///< Converted value.
+ sal_Int32 m_nWidth; ///< Original value.
+ sal_Int32 m_nType; ///< Unit of the value (dxa, etc).
+
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ void createGrabBag(const OUString& aName);
+
+public:
+ sal_Int32 m_nLeftMargin;
+ bool m_bLeftMarginValid;
+ sal_Int32 m_nRightMargin;
+ bool m_bRightMarginValid;
+ sal_Int32 m_nTopMargin;
+ bool m_bTopMarginValid;
+ sal_Int32 m_nBottomMargin;
+ bool m_bBottomMarginValid;
+
+public:
+ CellMarginHandler( );
+ virtual ~CellMarginHandler() override;
+
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag();
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ConversionHelper.cxx b/writerfilter/source/dmapper/ConversionHelper.cxx
new file mode 100644
index 000000000..5c3b0831f
--- /dev/null
+++ b/writerfilter/source/dmapper/ConversionHelper.cxx
@@ -0,0 +1,691 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "ConversionHelper.hxx"
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <editeng/borderline.hxx>
+#include <ooxml/resourceids.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/color.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper::ConversionHelper{
+
+/// Convert OOXML border style to WW8 that editeng can handle.
+static sal_Int32 lcl_convertBorderStyleFromToken(sal_Int32 nOOXMLType)
+{
+ switch (nOOXMLType)
+ {
+ case NS_ooxml::LN_Value_ST_Border_nil: return 255;
+ case NS_ooxml::LN_Value_ST_Border_none: return 0;
+ case NS_ooxml::LN_Value_ST_Border_single: return 1;
+ case NS_ooxml::LN_Value_ST_Border_thick: return 2;
+ case NS_ooxml::LN_Value_ST_Border_double: return 3;
+ case NS_ooxml::LN_Value_ST_Border_dotted: return 6;
+ case NS_ooxml::LN_Value_ST_Border_dashed: return 7;
+ case NS_ooxml::LN_Value_ST_Border_dotDash: return 8;
+ case NS_ooxml::LN_Value_ST_Border_dotDotDash: return 9;
+ case NS_ooxml::LN_Value_ST_Border_triple: return 10;
+ case NS_ooxml::LN_Value_ST_Border_thinThickSmallGap: return 11;
+ case NS_ooxml::LN_Value_ST_Border_thickThinSmallGap: return 12;
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinSmallGap: return 13;
+ case NS_ooxml::LN_Value_ST_Border_thinThickMediumGap: return 14;
+ case NS_ooxml::LN_Value_ST_Border_thickThinMediumGap: return 15;
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinMediumGap: return 16;
+ case NS_ooxml::LN_Value_ST_Border_thinThickLargeGap: return 17;
+ case NS_ooxml::LN_Value_ST_Border_thickThinLargeGap: return 18;
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinLargeGap: return 19;
+ case NS_ooxml::LN_Value_ST_Border_wave: return 20;
+ case NS_ooxml::LN_Value_ST_Border_doubleWave: return 21;
+ case NS_ooxml::LN_Value_ST_Border_dashSmallGap: return 22;
+ case NS_ooxml::LN_Value_ST_Border_dashDotStroked: return 23;
+ case NS_ooxml::LN_Value_ST_Border_threeDEmboss: return 24;
+ case NS_ooxml::LN_Value_ST_Border_threeDEngrave: return 25;
+ case NS_ooxml::LN_Value_ST_Border_outset: return 26;
+ case NS_ooxml::LN_Value_ST_Border_inset: return 27;
+ case NS_ooxml::LN_Value_ST_Border_apples: return 64;
+ case NS_ooxml::LN_Value_ST_Border_archedScallops: return 65;
+ case NS_ooxml::LN_Value_ST_Border_babyPacifier: return 66;
+ case NS_ooxml::LN_Value_ST_Border_babyRattle: return 67;
+ case NS_ooxml::LN_Value_ST_Border_balloons3Colors: return 68;
+ case NS_ooxml::LN_Value_ST_Border_balloonsHotAir: return 69;
+ case NS_ooxml::LN_Value_ST_Border_basicBlackDashes: return 70;
+ case NS_ooxml::LN_Value_ST_Border_basicBlackDots: return 71;
+ case NS_ooxml::LN_Value_ST_Border_basicBlackSquares: return 72;
+ case NS_ooxml::LN_Value_ST_Border_basicThinLines: return 73;
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteDashes: return 74;
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteDots: return 75;
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteSquares: return 76;
+ case NS_ooxml::LN_Value_ST_Border_basicWideInline: return 77;
+ case NS_ooxml::LN_Value_ST_Border_basicWideMidline: return 78;
+ case NS_ooxml::LN_Value_ST_Border_basicWideOutline: return 79;
+ case NS_ooxml::LN_Value_ST_Border_bats: return 80;
+ case NS_ooxml::LN_Value_ST_Border_birds: return 81;
+ case NS_ooxml::LN_Value_ST_Border_birdsFlight: return 82;
+ case NS_ooxml::LN_Value_ST_Border_cabins: return 83;
+ case NS_ooxml::LN_Value_ST_Border_cakeSlice: return 84;
+ case NS_ooxml::LN_Value_ST_Border_candyCorn: return 85;
+ case NS_ooxml::LN_Value_ST_Border_celticKnotwork: return 86;
+ case NS_ooxml::LN_Value_ST_Border_certificateBanner: return 87;
+ case NS_ooxml::LN_Value_ST_Border_chainLink: return 88;
+ case NS_ooxml::LN_Value_ST_Border_champagneBottle: return 89;
+ case NS_ooxml::LN_Value_ST_Border_checkedBarBlack: return 90;
+ case NS_ooxml::LN_Value_ST_Border_checkedBarColor: return 91;
+ case NS_ooxml::LN_Value_ST_Border_checkered: return 92;
+ case NS_ooxml::LN_Value_ST_Border_christmasTree: return 93;
+ case NS_ooxml::LN_Value_ST_Border_circlesLines: return 94;
+ case NS_ooxml::LN_Value_ST_Border_circlesRectangles: return 95;
+ case NS_ooxml::LN_Value_ST_Border_classicalWave: return 96;
+ case NS_ooxml::LN_Value_ST_Border_clocks: return 97;
+ case NS_ooxml::LN_Value_ST_Border_compass: return 98;
+ case NS_ooxml::LN_Value_ST_Border_confetti: return 99;
+ case NS_ooxml::LN_Value_ST_Border_confettiGrays: return 100;
+ case NS_ooxml::LN_Value_ST_Border_confettiOutline: return 101;
+ case NS_ooxml::LN_Value_ST_Border_confettiStreamers: return 102;
+ case NS_ooxml::LN_Value_ST_Border_confettiWhite: return 103;
+ case NS_ooxml::LN_Value_ST_Border_cornerTriangles: return 104;
+ case NS_ooxml::LN_Value_ST_Border_couponCutoutDashes: return 105;
+ case NS_ooxml::LN_Value_ST_Border_couponCutoutDots: return 106;
+ case NS_ooxml::LN_Value_ST_Border_crazyMaze: return 107;
+ case NS_ooxml::LN_Value_ST_Border_creaturesButterfly: return 108;
+ case NS_ooxml::LN_Value_ST_Border_creaturesFish: return 109;
+ case NS_ooxml::LN_Value_ST_Border_creaturesInsects: return 110;
+ case NS_ooxml::LN_Value_ST_Border_creaturesLadyBug: return 111;
+ case NS_ooxml::LN_Value_ST_Border_crossStitch: return 112;
+ case NS_ooxml::LN_Value_ST_Border_cup: return 113;
+ case NS_ooxml::LN_Value_ST_Border_decoArch: return 114;
+ case NS_ooxml::LN_Value_ST_Border_decoArchColor: return 115;
+ case NS_ooxml::LN_Value_ST_Border_decoBlocks: return 116;
+ case NS_ooxml::LN_Value_ST_Border_diamondsGray: return 117;
+ case NS_ooxml::LN_Value_ST_Border_doubleD: return 118;
+ case NS_ooxml::LN_Value_ST_Border_doubleDiamonds: return 119;
+ case NS_ooxml::LN_Value_ST_Border_earth1: return 120;
+ case NS_ooxml::LN_Value_ST_Border_earth2: return 121;
+ case NS_ooxml::LN_Value_ST_Border_eclipsingSquares1: return 122;
+ case NS_ooxml::LN_Value_ST_Border_eclipsingSquares2: return 123;
+ case NS_ooxml::LN_Value_ST_Border_eggsBlack: return 124;
+ case NS_ooxml::LN_Value_ST_Border_fans: return 125;
+ case NS_ooxml::LN_Value_ST_Border_film: return 126;
+ case NS_ooxml::LN_Value_ST_Border_firecrackers: return 127;
+ case NS_ooxml::LN_Value_ST_Border_flowersBlockPrint: return 128;
+ case NS_ooxml::LN_Value_ST_Border_flowersDaisies: return 129;
+ case NS_ooxml::LN_Value_ST_Border_flowersModern1: return 130;
+ case NS_ooxml::LN_Value_ST_Border_flowersModern2: return 131;
+ case NS_ooxml::LN_Value_ST_Border_flowersPansy: return 132;
+ case NS_ooxml::LN_Value_ST_Border_flowersRedRose: return 133;
+ case NS_ooxml::LN_Value_ST_Border_flowersRoses: return 134;
+ case NS_ooxml::LN_Value_ST_Border_flowersTeacup: return 135;
+ case NS_ooxml::LN_Value_ST_Border_flowersTiny: return 136;
+ case NS_ooxml::LN_Value_ST_Border_gems: return 137;
+ case NS_ooxml::LN_Value_ST_Border_gingerbreadMan: return 138;
+ case NS_ooxml::LN_Value_ST_Border_gradient: return 139;
+ case NS_ooxml::LN_Value_ST_Border_handmade1: return 140;
+ case NS_ooxml::LN_Value_ST_Border_handmade2: return 141;
+ case NS_ooxml::LN_Value_ST_Border_heartBalloon: return 142;
+ case NS_ooxml::LN_Value_ST_Border_heartGray: return 143;
+ case NS_ooxml::LN_Value_ST_Border_hearts: return 144;
+ case NS_ooxml::LN_Value_ST_Border_heebieJeebies: return 145;
+ case NS_ooxml::LN_Value_ST_Border_holly: return 146;
+ case NS_ooxml::LN_Value_ST_Border_houseFunky: return 147;
+ case NS_ooxml::LN_Value_ST_Border_hypnotic: return 148;
+ case NS_ooxml::LN_Value_ST_Border_iceCreamCones: return 149;
+ case NS_ooxml::LN_Value_ST_Border_lightBulb: return 150;
+ case NS_ooxml::LN_Value_ST_Border_lightning1: return 151;
+ case NS_ooxml::LN_Value_ST_Border_lightning2: return 152;
+ case NS_ooxml::LN_Value_ST_Border_mapPins: return 153;
+ case NS_ooxml::LN_Value_ST_Border_mapleLeaf: return 154;
+ case NS_ooxml::LN_Value_ST_Border_mapleMuffins: return 155;
+ case NS_ooxml::LN_Value_ST_Border_marquee: return 156;
+ case NS_ooxml::LN_Value_ST_Border_marqueeToothed: return 157;
+ case NS_ooxml::LN_Value_ST_Border_moons: return 158;
+ case NS_ooxml::LN_Value_ST_Border_mosaic: return 159;
+ case NS_ooxml::LN_Value_ST_Border_musicNotes: return 160;
+ case NS_ooxml::LN_Value_ST_Border_northwest: return 161;
+ case NS_ooxml::LN_Value_ST_Border_ovals: return 162;
+ case NS_ooxml::LN_Value_ST_Border_packages: return 163;
+ case NS_ooxml::LN_Value_ST_Border_palmsBlack: return 164;
+ case NS_ooxml::LN_Value_ST_Border_palmsColor: return 165;
+ case NS_ooxml::LN_Value_ST_Border_paperClips: return 166;
+ case NS_ooxml::LN_Value_ST_Border_papyrus: return 167;
+ case NS_ooxml::LN_Value_ST_Border_partyFavor: return 168;
+ case NS_ooxml::LN_Value_ST_Border_partyGlass: return 169;
+ case NS_ooxml::LN_Value_ST_Border_pencils: return 170;
+ case NS_ooxml::LN_Value_ST_Border_people: return 171;
+ case NS_ooxml::LN_Value_ST_Border_peopleWaving: return 172;
+ case NS_ooxml::LN_Value_ST_Border_peopleHats: return 173;
+ case NS_ooxml::LN_Value_ST_Border_poinsettias: return 174;
+ case NS_ooxml::LN_Value_ST_Border_postageStamp: return 175;
+ case NS_ooxml::LN_Value_ST_Border_pumpkin1: return 176;
+ case NS_ooxml::LN_Value_ST_Border_pushPinNote2: return 177;
+ case NS_ooxml::LN_Value_ST_Border_pushPinNote1: return 178;
+ case NS_ooxml::LN_Value_ST_Border_pyramids: return 179;
+ case NS_ooxml::LN_Value_ST_Border_pyramidsAbove: return 180;
+ case NS_ooxml::LN_Value_ST_Border_quadrants: return 181;
+ case NS_ooxml::LN_Value_ST_Border_rings: return 182;
+ case NS_ooxml::LN_Value_ST_Border_safari: return 183;
+ case NS_ooxml::LN_Value_ST_Border_sawtooth: return 184;
+ case NS_ooxml::LN_Value_ST_Border_sawtoothGray: return 185;
+ case NS_ooxml::LN_Value_ST_Border_scaredCat: return 186;
+ case NS_ooxml::LN_Value_ST_Border_seattle: return 187;
+ case NS_ooxml::LN_Value_ST_Border_shadowedSquares: return 188;
+ case NS_ooxml::LN_Value_ST_Border_sharksTeeth: return 189;
+ case NS_ooxml::LN_Value_ST_Border_shorebirdTracks: return 190;
+ case NS_ooxml::LN_Value_ST_Border_skyrocket: return 191;
+ case NS_ooxml::LN_Value_ST_Border_snowflakeFancy: return 192;
+ case NS_ooxml::LN_Value_ST_Border_snowflakes: return 193;
+ case NS_ooxml::LN_Value_ST_Border_sombrero: return 194;
+ case NS_ooxml::LN_Value_ST_Border_southwest: return 195;
+ case NS_ooxml::LN_Value_ST_Border_stars: return 196;
+ case NS_ooxml::LN_Value_ST_Border_starsTop: return 197;
+ case NS_ooxml::LN_Value_ST_Border_stars3d: return 198;
+ case NS_ooxml::LN_Value_ST_Border_starsBlack: return 199;
+ case NS_ooxml::LN_Value_ST_Border_starsShadowed: return 200;
+ case NS_ooxml::LN_Value_ST_Border_sun: return 201;
+ case NS_ooxml::LN_Value_ST_Border_swirligig: return 202;
+ case NS_ooxml::LN_Value_ST_Border_tornPaper: return 203;
+ case NS_ooxml::LN_Value_ST_Border_tornPaperBlack: return 204;
+ case NS_ooxml::LN_Value_ST_Border_trees: return 205;
+ case NS_ooxml::LN_Value_ST_Border_triangleParty: return 206;
+ case NS_ooxml::LN_Value_ST_Border_triangles: return 207;
+ case NS_ooxml::LN_Value_ST_Border_tribal1: return 208;
+ case NS_ooxml::LN_Value_ST_Border_tribal2: return 209;
+ case NS_ooxml::LN_Value_ST_Border_tribal3: return 210;
+ case NS_ooxml::LN_Value_ST_Border_tribal4: return 211;
+ case NS_ooxml::LN_Value_ST_Border_tribal5: return 212;
+ case NS_ooxml::LN_Value_ST_Border_tribal6: return 213;
+ case NS_ooxml::LN_Value_ST_Border_twistedLines1: return 214;
+ case NS_ooxml::LN_Value_ST_Border_twistedLines2: return 215;
+ case NS_ooxml::LN_Value_ST_Border_vine: return 216;
+ case NS_ooxml::LN_Value_ST_Border_waveline: return 217;
+ case NS_ooxml::LN_Value_ST_Border_weavingAngles: return 218;
+ case NS_ooxml::LN_Value_ST_Border_weavingBraid: return 219;
+ case NS_ooxml::LN_Value_ST_Border_weavingRibbon: return 220;
+ case NS_ooxml::LN_Value_ST_Border_weavingStrips: return 221;
+ case NS_ooxml::LN_Value_ST_Border_whiteFlowers: return 222;
+ case NS_ooxml::LN_Value_ST_Border_woodwork: return 223;
+ case NS_ooxml::LN_Value_ST_Border_xIllusions: return 224;
+ case NS_ooxml::LN_Value_ST_Border_zanyTriangles: return 225;
+ case NS_ooxml::LN_Value_ST_Border_zigZag: return 226;
+ case NS_ooxml::LN_Value_ST_Border_zigZagStitch: return 227;
+ default: break;
+ }
+ return 0;
+}
+
+void MakeBorderLine( sal_Int32 nLineThickness, sal_Int32 nLineToken,
+ sal_Int32 nLineColor,
+ table::BorderLine2& rToFill, bool bIsOOXML )
+{
+ static const Color aBorderDefColor[] =
+ {
+ // The first item means automatic color (COL_AUTO), but we
+ // do not use it anyway (see the next statement) .-)
+ // See also GetLineIndex in sw/source/filter/ww8/ww8par6.cxx
+ COL_AUTO, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
+ COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
+ COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
+ COL_LIGHTGRAY
+ };
+ if(!bIsOOXML && sal::static_int_cast<sal_uInt32>(nLineColor) < SAL_N_ELEMENTS(aBorderDefColor))
+ nLineColor = sal_Int32(aBorderDefColor[nLineColor]);
+ //no auto color for borders
+ if (nLineColor == sal_Int32(COL_AUTO))
+ nLineColor = sal_Int32(COL_BLACK);
+
+ sal_Int32 nLineType = lcl_convertBorderStyleFromToken(nLineToken);
+
+ // Map to our border types, we should use of one equal line
+ // thickness, or one of smaller thickness. If too small we
+ // can make the deficit up in additional white space or
+ // object size
+ SvxBorderLineStyle const nLineStyle(
+ ::editeng::ConvertBorderStyleFromWord(nLineType));
+ rToFill.LineStyle = static_cast<sal_Int16>(nLineStyle);
+ double const fConverted( (SvxBorderLineStyle::NONE == nLineStyle) ? 0.0 :
+ ::editeng::ConvertBorderWidthFromWord(nLineStyle, nLineThickness,
+ nLineType));
+ rToFill.LineWidth = convertTwipToMM100(fConverted);
+ rToFill.Color = nLineColor;
+}
+
+namespace {
+void lcl_SwapQuotesInField(OUString &rFmt)
+{
+ //Swap unescaped " and ' with ' and "
+ sal_Int32 nLen = rFmt.getLength();
+ OUStringBuffer aBuffer( rFmt );
+ const sal_Unicode* pFmt = rFmt.getStr();
+ for (sal_Int32 nI = 0; nI < nLen; ++nI)
+ {
+ if ((pFmt[nI] == '\"') && (!nI || pFmt[nI-1] != '\\'))
+ aBuffer[nI] = '\'';
+ else if ((pFmt[nI] == '\'') && (!nI || pFmt[nI-1] != '\\'))
+ aBuffer[nI] = '\"';
+ }
+ rFmt = aBuffer.makeStringAndClear();
+}
+bool lcl_IsNotAM(OUString const & rFmt, sal_Int32 nPos)
+{
+ return (
+ (nPos == rFmt.getLength() - 1) ||
+ (
+ (rFmt[nPos+1] != 'M') &&
+ (rFmt[nPos+1] != 'm')
+ )
+ );
+}
+bool IsPreviousAM(std::u16string_view rParams, sal_Int32 nPos)
+{
+ return nPos >= 2 && o3tl::matchIgnoreAsciiCase(rParams, u"am", nPos - 2);
+}
+bool IsNextPM(std::u16string_view rParams, sal_Int32 nPos)
+{
+ return o3tl::make_unsigned(nPos + 2) < rParams.size() && o3tl::matchIgnoreAsciiCase(rParams, u"pm", nPos + 1);
+}
+}
+
+// See also sw::ms::MSDateTimeFormatToSwFormat
+OUString ConvertMSFormatStringToSO(
+ const OUString& rFormat, lang::Locale& rLocale, bool bHijri)
+{
+ OUString sFormat(rFormat);
+ lcl_SwapQuotesInField(sFormat);
+
+ //#102782#, #102815#, #108341# & #111944# have to work at the same time :-)
+ bool bForceJapanese(false);
+ bool bForceNatNum(false);
+ const sal_Int32 nLen = sFormat.getLength();
+ sal_Int32 nI = 0;
+ sal_Int32 nAddedChars = 0;
+// const sal_Unicode* pFormat = sFormat.getStr();
+ OUStringBuffer aNewFormat( sFormat );
+ while (nI < nLen)
+ {
+ if (sFormat[nI] == '\\')
+ ++nI;
+ else if (sFormat[nI] == '\"')
+ {
+ ++nI;
+ //While not at the end and not at an unescaped end quote
+ while ((nI < nLen) && ((sFormat[nI] != '\"') && (sFormat[nI-1] != '\\')))
+ ++nI;
+ }
+ else //normal unquoted section
+ {
+ sal_Unicode nChar = sFormat[nI];
+ if (nChar == 'O')
+ {
+ aNewFormat[nI + nAddedChars] = 'M';
+ bForceNatNum = true;
+ }
+ else if (nChar == 'o')
+ {
+ aNewFormat[nI + nAddedChars] = 'm';
+ bForceNatNum = true;
+ }
+ else if ((nChar == 'A') && lcl_IsNotAM(sFormat, nI))
+ {
+ aNewFormat[nI + nAddedChars] = 'D';
+ bForceNatNum = true;
+ }
+ else if ((nChar == 'g') || (nChar == 'G'))
+ bForceJapanese = true;
+ else if ((nChar == 'a') && lcl_IsNotAM(sFormat, nI))
+ bForceJapanese = true;
+ else if (nChar == 'E')
+ {
+ if ((nI != nLen-1) && (sFormat[nI+1] == 'E'))
+ {
+ //todo: this cannot be the right way to replace a part of the string!
+ aNewFormat[nI + nAddedChars] = 'Y';
+ aNewFormat[nI + nAddedChars + 1] = 'Y';
+ aNewFormat.insert(nI + nAddedChars + 2, "YY");
+ nAddedChars += 2;
+ ++nI;
+ }
+ bForceJapanese = true;
+ }
+ else if (nChar == 'e')
+ {
+ if ((nI != nLen-1) && (sFormat[nI+1] == 'e'))
+ {
+ //todo: this cannot be the right way to replace a part of the string!
+ aNewFormat[nI + nAddedChars] = 'y';
+ aNewFormat[nI + nAddedChars + 1] = 'y';
+ aNewFormat.insert(nI + nAddedChars + 2, "yy");
+ nAddedChars += 2;
+ ++nI;
+ }
+ bForceJapanese = true;
+ }
+ else if (nChar == '/' && !(IsPreviousAM(sFormat, nI) && IsNextPM(sFormat, nI)))
+ {
+ // MM We have to escape '/' in case it's used as a char
+ //todo: this cannot be the right way to replace a part of the string!
+ aNewFormat[nI + nAddedChars] = '\\';
+ aNewFormat.insert(nI + nAddedChars + 1, "/");
+ ++nAddedChars;
+ ++nI;
+ }
+ }
+ ++nI;
+ }
+
+ if (bForceNatNum)
+ bForceJapanese = true;
+
+ if (bForceJapanese)
+ {
+ rLocale.Language = "ja";
+ rLocale.Country = "JP";
+ }
+
+ if (bForceNatNum)
+ {
+ aNewFormat.insert( 0, "[NatNum1][$-411]");
+ }
+
+ if (bHijri)
+ {
+ aNewFormat.insert( 0, "[~hijri]");
+ }
+ return aNewFormat.makeStringAndClear();
+
+}
+
+sal_Int32 convertTwipToMM100(sal_Int32 _t)
+{
+ // It appears that MSO handles large twip values specially, probably legacy 16bit handling,
+ // anything that's bigger than 32767 appears to be simply ignored.
+ if( _t >= 0x8000 )
+ return 0;
+ return ::convertTwipToMm100( _t );
+}
+
+sal_Int32 convertTwipToMM100WithoutLimit(sal_Int32 _t)
+{
+ return ::convertTwipToMm100(_t);
+}
+
+double convertTwipToMM100Double(sal_Int32 _t)
+{
+ // It appears that MSO handles large twip values specially, probably legacy 16bit handling,
+ // anything that's bigger than 32767 appears to be simply ignored.
+ if( _t >= 0x8000 )
+ return 0.0;
+ return o3tl::convert<double>(_t, o3tl::Length::twip, o3tl::Length::mm100);
+}
+
+sal_uInt32 convertTwipToMM100Unsigned(sal_Int32 _t)
+{
+ if( _t < 0 )
+ return 0;
+ return convertTwipToMM100( _t );
+}
+
+text::RubyAdjust convertRubyAlign( sal_Int32 nIntValue )
+{
+ text::RubyAdjust rubyAdjust = text::RubyAdjust_LEFT;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_RubyAlign_center:
+ case NS_ooxml::LN_Value_ST_RubyAlign_rightVertical:
+ rubyAdjust = text::RubyAdjust_CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_distributeLetter:
+ rubyAdjust = text::RubyAdjust_BLOCK;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_distributeSpace:
+ rubyAdjust = text::RubyAdjust_INDENT_BLOCK;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_left:
+ rubyAdjust = text::RubyAdjust_LEFT;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_right:
+ rubyAdjust = text::RubyAdjust_RIGHT;
+ break;
+ }
+ return rubyAdjust;
+}
+
+sal_Int16 convertTableJustification( sal_Int32 nIntValue )
+{
+ sal_Int16 nOrient = text::HoriOrientation::LEFT_AND_WIDTH;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_Jc_center:
+ nOrient = text::HoriOrientation::CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_right:
+ case NS_ooxml::LN_Value_ST_Jc_end:
+ nOrient = text::HoriOrientation::RIGHT;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_left:
+ case NS_ooxml::LN_Value_ST_Jc_start:
+ //no break
+ default:;
+
+ }
+ return nOrient;
+}
+
+// Return the suggested default if the given format has no known conversion
+sal_Int16 ConvertNumberingType(const sal_Int32 nFmt, const sal_Int16 nDefault)
+{
+ sal_Int16 nRet;
+ switch(nFmt)
+ {
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimal:
+ nRet = style::NumberingType::ARABIC;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_upperRoman:
+ nRet = style::NumberingType::ROMAN_UPPER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman:
+ nRet = style::NumberingType::ROMAN_LOWER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ordinal:
+ nRet = style::NumberingType::TEXT_NUMBER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_bullet:
+ nRet = style::NumberingType::CHAR_SPECIAL;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_none:
+ nRet = style::NumberingType::NUMBER_NONE;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_upperLetter:
+ nRet = style::NumberingType::CHARS_UPPER_LETTER_N;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter:
+ nRet = style::NumberingType::CHARS_LOWER_LETTER_N;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_iroha:
+ nRet = style::NumberingType::IROHA_HALFWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth:
+ nRet = style::NumberingType::IROHA_FULLWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_aiueo:
+ nRet = style::NumberingType::AIU_HALFWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth:
+ nRet = style::NumberingType::AIU_FULLWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_hebrew2:
+ nRet = style::NumberingType::CHARS_HEBREW;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_thaiLetters:
+ nRet = style::NumberingType::CHARS_THAI;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_russianLower:
+ nRet = style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_russianUpper:
+ nRet = style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese:
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircle:
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle:
+ nRet = style::NumberingType::CIRCLE_NUMBER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional:
+ nRet = style::NumberingType::TIAN_GAN_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac:
+ nRet = style::NumberingType::DI_ZI_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ganada:
+ nRet = style::NumberingType::HANGUL_SYLLABLE_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chosung:
+ nRet = style::NumberingType::HANGUL_JAMO_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal:
+ nRet = style::NumberingType::NUMBER_LEGAL_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital:
+ nRet = style::NumberingType::NUMBER_DIGITAL_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting:
+ nRet = style::NumberingType::NUMBER_HANGUL_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2:
+ nRet = style::NumberingType::NUMBER_DIGITAL2_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional:
+ nRet = style::NumberingType::NUMBER_UPPER_ZH_TW;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha:
+ nRet = style::NumberingType::CHARS_ARABIC;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad:
+ nRet = style::NumberingType::CHARS_ARABIC_ABJAD;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_hindiVowels:
+ nRet = style::NumberingType::CHARS_NEPALI;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal:
+ nRet = style::NumberingType::NUMBER_TRADITIONAL_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting:
+ case NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting:
+ case NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting:
+ case NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand:
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital:
+ case NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand:
+ nRet = style::NumberingType::NUMBER_LOWER_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified:
+ nRet = style::NumberingType::NUMBER_UPPER_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_hebrew1:
+ //91726
+ nRet = style::NumberingType::NUMBER_HEBREW;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth:
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2:
+ nRet = style::NumberingType::FULLWIDTH_ARABIC;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_cardinalText:
+ nRet = style::NumberingType::TEXT_CARDINAL;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ordinalText:
+ nRet = style::NumberingType::TEXT_ORDINAL;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chicago:
+ nRet = style::NumberingType::SYMBOL_CHICAGO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalZero:
+ nRet = style::NumberingType::ARABIC_ZERO;
+ break;
+ default: nRet = nDefault;
+ }
+/* TODO: Lots of additional values are available - some are supported in the I18 framework
+ NS_ooxml::LN_Value_ST_NumberFormat_hex = 91685;
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth = 91692;
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand = 91694;
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop = 91703;
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen = 91704;
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional = 91709;
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital = 91713;
+ NS_ooxml::LN_Value_ST_NumberFormat_vietnameseCounting = 91721;
+ NS_ooxml::LN_Value_ST_NumberFormat_numberInDash = 91725;
+ NS_ooxml::LN_Value_ST_NumberFormat_hindiConsonants = 91731;
+ NS_ooxml::LN_Value_ST_NumberFormat_hindiNumbers = 91732;
+ NS_ooxml::LN_Value_ST_NumberFormat_hindiCounting = 91733;
+ NS_ooxml::LN_Value_ST_NumberFormat_thaiNumbers = 91735;
+ NS_ooxml::LN_Value_ST_NumberFormat_thaiCounting = 91736;*/
+ return nRet;
+}
+
+sal_Int16 ConvertCustomNumberFormat(std::u16string_view rFormat)
+{
+ sal_Int16 nRet = -1;
+
+ if (rFormat == u"001, 002, 003, ...")
+ {
+ nRet = style::NumberingType::ARABIC_ZERO3;
+ }
+ else if (rFormat == u"0001, 0002, 0003, ...")
+ {
+ nRet = style::NumberingType::ARABIC_ZERO4;
+ }
+ else if (rFormat == u"00001, 00002, 00003, ...")
+ {
+ nRet = style::NumberingType::ARABIC_ZERO5;
+ }
+
+ return nRet;
+}
+
+util::DateTime ConvertDateStringToDateTime( std::u16string_view rDateTime )
+{
+ util::DateTime aDateTime;
+ //xsd::DateTime in the format [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] example: 2008-01-21T10:42:00Z
+ //OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const
+ sal_Int32 nIndex = 0;
+ std::u16string_view sDate = o3tl::getToken(rDateTime, 0, 'T', nIndex );
+ // HACK: this is broken according to the spec, but MSOffice always treats the time as local,
+ // and writes it as Z (=UTC+0)
+ std::u16string_view sTime = o3tl::getToken(rDateTime, 0, 'Z', nIndex );
+ nIndex = 0;
+ aDateTime.Year = sal_uInt16( o3tl::toInt32(o3tl::getToken(sDate, 0, '-', nIndex )) );
+ aDateTime.Month = sal_uInt16( o3tl::toInt32(o3tl::getToken(sDate, 0, '-', nIndex )) );
+ if (nIndex != -1)
+ aDateTime.Day = sal_uInt16( o3tl::toInt32(sDate.substr( nIndex )) );
+
+ nIndex = 0;
+ aDateTime.Hours = sal_uInt16( o3tl::toInt32(o3tl::getToken(sTime, 0, ':', nIndex )) );
+ aDateTime.Minutes = sal_uInt16( o3tl::toInt32(o3tl::getToken(sTime, 0, ':', nIndex )) );
+ if (nIndex != -1)
+ aDateTime.Seconds = sal_uInt16( o3tl::toInt32(sTime.substr( nIndex )) );
+
+ return aDateTime;
+}
+
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ConversionHelper.hxx b/writerfilter/source/dmapper/ConversionHelper.hxx
new file mode 100644
index 000000000..c14c8033e
--- /dev/null
+++ b/writerfilter/source/dmapper/ConversionHelper.hxx
@@ -0,0 +1,60 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/RubyAdjust.hpp>
+
+namespace com::sun::star{
+ namespace lang{
+ struct Locale;
+ }
+ namespace table{
+ struct BorderLine2;
+ }
+}
+
+namespace writerfilter::dmapper::ConversionHelper{
+
+ // create a border line and return the distance value
+ void MakeBorderLine(sal_Int32 nLineThickness,
+ sal_Int32 nLineType,
+ sal_Int32 nLineColor,
+ css::table::BorderLine2& rToFill,
+ bool bIsOOXML);
+ //convert the number format string form MS format to SO format
+ OUString ConvertMSFormatStringToSO(const OUString& rFormat, css::lang::Locale& rLocale, bool bHijri);
+ // export just for test
+ SAL_DLLPUBLIC_EXPORT sal_Int32 convertTwipToMM100(sal_Int32 _t);
+ sal_Int32 convertTwipToMM100WithoutLimit(sal_Int32 _t);
+ double convertTwipToMM100Double(sal_Int32 _t);
+ SAL_DLLPUBLIC_EXPORT sal_uInt32 convertTwipToMM100Unsigned(sal_Int32 _t);
+ sal_Int16 convertTableJustification( sal_Int32 nIntValue );
+ css::text::RubyAdjust convertRubyAlign( sal_Int32 nIntValue );
+ sal_Int16 ConvertNumberingType(const sal_Int32 nFmt, const sal_Int16 nDefault = css::style::NumberingType::ARABIC);
+ sal_Int16 ConvertCustomNumberFormat(std::u16string_view rFormat);
+
+ css::util::DateTime ConvertDateStringToDateTime(std::u16string_view rDateTime);
+} // namespace writerfilter::dmapper::ConversionHelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DocumentProtection.cxx b/writerfilter/source/dmapper/DocumentProtection.cxx
new file mode 100644
index 000000000..dddf964c4
--- /dev/null
+++ b/writerfilter/source/dmapper/DocumentProtection.cxx
@@ -0,0 +1,239 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DocumentProtection.hxx"
+#include "TagLogger.hxx"
+#include <vector>
+#include <comphelper/sequence.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+DocumentProtection::DocumentProtection()
+ : LoggedProperties("DocumentProtection")
+ , m_nEdit(
+ NS_ooxml::
+ LN_Value_doc_ST_DocProtect_none) // Specifies that no editing restrictions have been applied to the document
+ , m_bProtectForm(false)
+ , m_bRedlineProtection(false)
+ , m_bReadOnly(false)
+ , m_bEnforcement(false)
+ , m_bFormatting(false)
+ , m_nCryptProviderType(NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+ , m_sCryptAlgorithmClass("hash")
+ , m_sCryptAlgorithmType("typeAny")
+ , m_CryptSpinCount(0)
+{
+}
+
+DocumentProtection::~DocumentProtection() {}
+
+void DocumentProtection::lcl_attribute(Id nName, Value& val)
+{
+ int nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_DocProtect_edit: // 92037
+ m_nEdit = nIntValue;
+ // multiple DocProtect_edits should not exist. If they do, last one wins
+ m_bRedlineProtection = false;
+ m_bProtectForm = false;
+ m_bReadOnly = false;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges:
+ {
+ m_bRedlineProtection = true;
+ m_sRedlineProtectionKey = m_sHash;
+ break;
+ }
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_forms:
+ m_bProtectForm = true;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly:
+ m_bReadOnly = true;
+ break;
+ }
+ break;
+ case NS_ooxml::LN_CT_DocProtect_enforcement: // 92039
+ m_bEnforcement = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_DocProtect_formatting: // 92038
+ m_bFormatting = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_AG_Password_cryptProviderType: // 92025
+ m_nCryptProviderType = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmClass: // 92026
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgClass_hash) // 92023
+ m_sCryptAlgorithmClass = "hash";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmType: // 92027
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgType_typeAny) // 92024
+ m_sCryptAlgorithmType = "typeAny";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmSid: // 92028
+ m_sCryptAlgorithmSid = sStringValue;
+ break;
+ case NS_ooxml::LN_AG_Password_cryptSpinCount: // 92029
+ m_CryptSpinCount = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_hash: // 92035
+ m_sHash = sStringValue;
+ break;
+ case NS_ooxml::LN_AG_Password_salt: // 92036
+ m_sSalt = sStringValue;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void DocumentProtection::lcl_sprm(Sprm& /*rSprm*/) {}
+
+uno::Sequence<beans::PropertyValue> DocumentProtection::toSequence() const
+{
+ std::vector<beans::PropertyValue> documentProtection;
+
+ if (enabled())
+ {
+ // w:edit
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "edit";
+
+ switch (m_nEdit)
+ {
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_none:
+ aValue.Value <<= OUString("none");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly:
+ aValue.Value <<= OUString("readOnly");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_comments:
+ aValue.Value <<= OUString("comments");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges:
+ aValue.Value <<= OUString("trackedChanges");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_forms:
+ aValue.Value <<= OUString("forms");
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+
+ documentProtection.push_back(aValue);
+ }
+
+ // w:enforcement
+ if (m_bEnforcement)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "enforcement";
+ aValue.Value <<= OUString("1");
+ documentProtection.push_back(aValue);
+ }
+
+ // w:formatting
+ if (m_bFormatting)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "formatting";
+ aValue.Value <<= OUString("1");
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptProviderType
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptProviderType";
+ if (m_nCryptProviderType == NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+ aValue.Value <<= OUString("rsaAES");
+ else if (m_nCryptProviderType == NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull)
+ aValue.Value <<= OUString("rsaFull");
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptAlgorithmClass
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptAlgorithmClass";
+ aValue.Value <<= m_sCryptAlgorithmClass;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptAlgorithmType
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptAlgorithmType";
+ aValue.Value <<= m_sCryptAlgorithmType;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptAlgorithmSid
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptAlgorithmSid";
+ aValue.Value <<= m_sCryptAlgorithmSid;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptSpinCount
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptSpinCount";
+ aValue.Value <<= OUString::number(m_CryptSpinCount);
+ documentProtection.push_back(aValue);
+ }
+
+ // w:hash
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "hash";
+ aValue.Value <<= m_sHash;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:salt
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "salt";
+ aValue.Value <<= m_sSalt;
+ documentProtection.push_back(aValue);
+ }
+ }
+
+ return comphelper::containerToSequence(documentProtection);
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DocumentProtection.hxx b/writerfilter/source/dmapper/DocumentProtection.hxx
new file mode 100644
index 000000000..2ec0f3f21
--- /dev/null
+++ b/writerfilter/source/dmapper/DocumentProtection.hxx
@@ -0,0 +1,88 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper
+{
+/** Document protection restrictions
+ *
+ * This element specifies the set of document protection restrictions which have been applied to the contents of a
+ * WordprocessingML document.These restrictions should be enforced by applications editing this document
+ * when the enforcement attribute is turned on, and ignored(but persisted) otherwise.Document protection is a
+ * set of restrictions used to prevent unintentional changes to all or part of a WordprocessingML document.
+ */
+class DocumentProtection : public LoggedProperties
+{
+private:
+ /** Document Editing Restrictions
+ *
+ * Possible values:
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_none
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_comments
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_forms
+ */
+ sal_Int32 m_nEdit;
+ bool m_bProtectForm;
+ bool m_bRedlineProtection;
+ OUString m_sRedlineProtectionKey;
+ bool m_bReadOnly;
+ bool m_bEnforcement;
+ bool m_bFormatting;
+
+ /** Provider type
+ *
+ * Possible values:
+ * "rsaAES" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES
+ * "rsaFull" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull
+ */
+ sal_Int32 m_nCryptProviderType;
+ OUString m_sCryptAlgorithmClass;
+ OUString m_sCryptAlgorithmType;
+ OUString m_sCryptAlgorithmSid;
+ sal_Int32 m_CryptSpinCount;
+ OUString m_sHash;
+ OUString m_sSalt;
+
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+ bool enabled() const { return !isNone(); }
+ bool isNone() const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_none; };
+
+public:
+ DocumentProtection();
+ virtual ~DocumentProtection() override;
+
+ css::uno::Sequence<css::beans::PropertyValue> toSequence() const;
+
+ bool getProtectForm() const { return m_bProtectForm; }
+ bool getRedlineProtection() const { return m_bRedlineProtection; }
+ bool getReadOnly() const { return m_bReadOnly; }
+ bool getEnforcement() const { return m_bEnforcement; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
new file mode 100644
index 000000000..e4b507957
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -0,0 +1,4510 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "BorderHandler.hxx"
+#include "PageBordersHandler.hxx"
+
+#include "util.hxx"
+#include "SdtHelper.hxx"
+#include "TagLogger.hxx"
+#include "TDefTableHandler.hxx"
+#include "DomainMapper_Impl.hxx"
+#include "ConversionHelper.hxx"
+#include "ModelEventListener.hxx"
+#include "MeasureHandler.hxx"
+#include <i18nlangtag/languagetag.hxx>
+#include <i18nutil/paper.hxx>
+#include <ooxml/resourceids.hxx>
+#include <oox/token/tokens.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/table/BorderLineStyle.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/XEndnotesSupplier.hpp>
+#include <com/sun/star/text/XFootnotesSupplier.hpp>
+#include <com/sun/star/text/XLineNumberingProperties.hpp>
+#include <com/sun/star/awt/FontRelief.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/style/BreakType.hpp>
+#include <com/sun/star/style/CaseMap.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/text/FootnoteNumbering.hpp>
+#include <com/sun/star/text/TextGridMode.hpp>
+#include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XFootnote.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+#include <com/sun/star/text/RubyPosition.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/text/FontEmphasis.hpp>
+#include <com/sun/star/awt/CharSet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/types.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <editeng/escapementitem.hxx>
+#include <filter/msfilter/util.hxx>
+#include <sfx2/DocumentMetadataAccess.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include "TextEffectsHandler.hxx"
+#include "CellColorHandler.hxx"
+#include "SectionColumnHandler.hxx"
+#include "GraphicHelpers.hxx"
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <tools/UnitConversion.hxx>
+
+using namespace ::com::sun::star;
+using namespace oox;
+
+namespace writerfilter::dmapper{
+
+struct
+{
+ sal_Int32 h;
+ bool orient;
+ sal_Int32 w;
+} CT_PageSz;
+
+
+DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xContext,
+ uno::Reference<io::XInputStream> const& xInputStream,
+ uno::Reference<lang::XComponent> const& xModel,
+ bool bRepairStorage,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc) :
+ LoggedProperties("DomainMapper"),
+ LoggedTable("DomainMapper"),
+ LoggedStream("DomainMapper"),
+ m_pImpl(new DomainMapper_Impl(*this, xContext, xModel, eDocumentType, rMediaDesc)),
+ mbIsSplitPara(false),
+ mbHasControls(false),
+ mbWasShapeInPara(false)
+{
+ // #i24363# tab stops relative to indent
+ m_pImpl->SetDocumentSettingsProperty(
+ getPropertyName( PROP_TABS_RELATIVE_TO_INDENT ),
+ uno::Any( false ) );
+ m_pImpl->SetDocumentSettingsProperty(
+ getPropertyName( PROP_SURROUND_TEXT_WRAP_SMALL ),
+ uno::Any( true ) );
+ m_pImpl->SetDocumentSettingsProperty(
+ getPropertyName( PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING ),
+ uno::Any( true ) );
+
+ // Don't load the default style definitions to avoid weird mix
+ m_pImpl->SetDocumentSettingsProperty("StylesNoDefault", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("MsWordCompTrailingBlanks", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("HeaderSpacingBelowLastPara",
+ uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("FrameAutowidthWithMorePara", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("FootnoteInColumnToPageEnd", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("TabAtLeftIndentForParagraphsInList", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("NoNumberingShowFollowBy", uno::Any(true));
+
+ // Initialize RDF metadata, to be able to add statements during the import.
+ try
+ {
+ uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
+ uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ OUString aBaseURL = rMediaDesc.getUnpackedValueOrDefault("URL", OUString());
+ const uno::Reference<frame::XModel> xModel_(xModel,
+ uno::UNO_QUERY_THROW);
+ const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xContext, xModel_, aBaseURL, u""));
+ const uno::Reference<task::XInteractionHandler> xHandler;
+ xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "failed to initialize RDF metadata");
+ }
+
+ if (eDocumentType == SourceDocumentType::OOXML) {
+ // tdf#108350
+ // In Word since version 2007, the default document font is Calibri 11 pt.
+ // If a DOCX document doesn't contain font information, we should assume
+ // the intended font to provide best layout match.
+ try
+ {
+ uno::Reference< beans::XPropertySet > xDefProps(GetTextFactory()->createInstance("com.sun.star.text.Defaults"),
+ uno::UNO_QUERY_THROW);
+ xDefProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), css::uno::Any(OUString("Calibri")));
+ xDefProps->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT), css::uno::Any(double(11)));
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "failed to initialize default font");
+ }
+ }
+
+ //import document properties
+ try
+ {
+ m_pImpl->m_xDocumentStorage = comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
+ OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, bRepairStorage);
+
+ uno::Reference< uno::XInterface > xTemp = xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.OOXMLDocumentPropertiesImporter",
+ xContext);
+
+ uno::Reference< document::XOOXMLDocumentPropertiesImporter > xImporter( xTemp, uno::UNO_QUERY_THROW );
+ uno::Reference< document::XDocumentPropertiesSupplier > xPropSupplier( xModel, uno::UNO_QUERY_THROW);
+ xImporter->importProperties(m_pImpl->m_xDocumentStorage,
+ xPropSupplier->getDocumentProperties());
+ }
+ catch( const uno::Exception& ) {}
+}
+
+void DomainMapper::setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument)
+{
+ m_pImpl->setDocumentReference(pDocument);
+}
+
+DomainMapper::~DomainMapper()
+{
+ try
+ {
+ // Remove temporary footnotes and endnotes
+ m_pImpl->RemoveTemporaryFootOrEndnotes();
+
+ uno::Reference< text::XDocumentIndexesSupplier> xIndexesSupplier( m_pImpl->GetTextDocument(), uno::UNO_QUERY );
+ sal_Int32 nIndexes = 0;
+ if( xIndexesSupplier.is() )
+ {
+ uno::Reference< container::XIndexAccess > xIndexes = xIndexesSupplier->getDocumentIndexes();
+ nIndexes = xIndexes->getCount();
+ }
+ // If we have page references, those need updating as well, similar to the indexes.
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if(xTextFieldsSupplier.is())
+ {
+ uno::Reference<container::XEnumeration> xEnumeration = xTextFieldsSupplier->getTextFields()->createEnumeration();
+ while(xEnumeration->hasMoreElements())
+ {
+ ++nIndexes;
+ xEnumeration->nextElement();
+ }
+ }
+
+ mbHasControls |= m_pImpl->m_pSdtHelper->hasElements();
+ if ( nIndexes || mbHasControls )
+ {
+ //index update has to wait until first view is created
+ uno::Reference< document::XEventBroadcaster > xBroadcaster(xIndexesSupplier, uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addEventListener(uno::Reference< document::XEventListener >(new ModelEventListener(nIndexes, mbHasControls)));
+ }
+
+
+ // Apply the document settings for both DOCX and RTF after everything else
+ m_pImpl->GetSettingsTable()->ApplyProperties( m_pImpl->GetTextDocument( ) );
+
+ // now that importing is finished, re-enable default styles for any that were never defined/imported.
+ m_pImpl->SetDocumentSettingsProperty("StylesNoDefault", uno::Any(false));
+
+ // Grab-bag handling
+ comphelper::SequenceAsHashMap aProperties;
+
+ // Add the saved w:themeFontLang setting
+ aProperties["ThemeFontLangProps"] <<= m_pImpl->GetSettingsTable()->GetThemeFontLangProperties();
+
+ // Add the saved compat settings
+ aProperties["CompatSettings"] <<= m_pImpl->GetSettingsTable()->GetCompatSettings();
+
+ // Add the saved DocumentProtection settings
+ aProperties["DocumentProtection"] <<= m_pImpl->GetSettingsTable()->GetDocumentProtectionSettings();
+
+ // Add the saved w:doNotHyphenateCaps setting
+ aProperties["NoHyphenateCaps"] <<= m_pImpl->GetSettingsTable()->GetNoHyphenateCaps();
+
+ uno::Reference<beans::XPropertySet> xDocProps(m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if (xDocProps.is())
+ {
+ comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
+ aGrabBag.update(aProperties);
+ xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
+ }
+
+ // tdf#138782: for docs created in MS Word 2010 and older (compatibilityMode <= 14)
+ m_pImpl->SetDocumentSettingsProperty(
+ "AddFrameOffsets",
+ uno::Any(14 >= m_pImpl->GetSettingsTable()->GetWordCompatibilityMode()));
+ }
+ catch( const uno::Exception& ) {}
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endDocument();
+#endif
+}
+
+void DomainMapper::lcl_attribute(Id nName, Value & val)
+{
+ if (m_pImpl->hasTableManager() && m_pImpl->getTableManager().attribute(nName, val))
+ return;
+
+ static const int nSingleLineSpacing = 240;
+ sal_Int32 nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ SectionPropertyMap * pSectionContext = m_pImpl->GetSectionContext();
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_Lvl_start:
+ break;
+ case NS_ooxml::LN_CT_Lvl_numFmt:
+ break;
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ break;
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_nsid:
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ break;
+ case NS_ooxml::LN_CT_Border_sz:
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ break;
+ case NS_ooxml::LN_CT_Border_space:
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ break;
+ case NS_ooxml::LN_CT_Border_frame:
+ break;
+ case NS_ooxml::LN_headerr:
+ break;
+ case NS_ooxml::LN_footerr:
+ break;
+ case NS_ooxml::LN_endnote:
+ break;
+ case NS_ooxml::LN_CT_Bookmark_name:
+ m_pImpl->SetBookmarkName( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_MarkupRangeBookmark_id:
+ // add a bookmark range -- this remembers a bookmark starting here
+ // or, if the bookmark was already started or, if the bookmark was
+ // already started before, writes out the bookmark
+ m_pImpl->StartOrEndBookmark( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_MarkupRange_displacedByCustomXml:
+ break;
+ case NS_ooxml::LN_NUMBERING:
+ break;
+ case NS_ooxml::LN_FONTTABLE:
+ break;
+ case NS_ooxml::LN_STYLESHEET:
+ break;
+
+ case NS_ooxml::LN_CT_Sym_char:
+ m_pImpl->SetSymbolChar(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Sym_font:
+ m_pImpl->SetSymbolFont(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Underline_val:
+ if (m_pImpl->GetTopContext())
+ handleUnderlineType(nIntValue, m_pImpl->GetTopContext());
+ break;
+ case NS_ooxml::LN_CT_Color_val:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COLOR, uno::Any( nIntValue ) );
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "val", msfilter::util::ConvertColorOU(Color(ColorTransparency,nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Underline_color:
+ if (m_pImpl->GetTopContext())
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_HAS_COLOR, uno::Any( true ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_COLOR, uno::Any( nIntValue ) );
+ }
+ break;
+
+ case NS_ooxml::LN_CT_TabStop_val:
+ if (sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_TabJc_clear)
+ {
+ m_pImpl->m_aCurrentTabStop.bDeleted = true;
+ }
+ else
+ {
+ m_pImpl->m_aCurrentTabStop.bDeleted = false;
+ m_pImpl->m_aCurrentTabStop.Alignment = getTabAlignFromValue(nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_TabStop_leader:
+ m_pImpl->m_aCurrentTabStop.FillChar = getFillCharFromValue(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_TabStop_pos:
+ m_pImpl->m_aCurrentTabStop.Position = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+
+ case NS_ooxml::LN_CT_Fonts_ascii:
+ if (m_pImpl->GetTopContext())
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, uno::Any( sStringValue ));
+ }
+ break;
+ case NS_ooxml::LN_CT_Fonts_asciiTheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "asciiTheme", ThemeTable::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ // note: overwrite Fonts_ascii with Fonts_asciiTheme *even if*
+ // theme font is empty - this is apparently what Word 2013 does
+ uno::Any aPropValue( m_pImpl->GetThemeTable()->getFontNameForTheme( nIntValue ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, aPropValue );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_ASCII, aPropValue, true, CHAR_GRAB_BAG );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_ASCII, uno::Any( ThemeTable::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ }
+ break;
+ case NS_ooxml::LN_CT_Fonts_hAnsi:
+ break;//unsupported
+ case NS_ooxml::LN_CT_Fonts_hAnsiTheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "hAnsiTheme", ThemeTable::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_H_ANSI, uno::Any( ThemeTable::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ break;
+ case NS_ooxml::LN_CT_Fonts_eastAsia:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::Any( sStringValue ));
+ break;
+ case NS_ooxml::LN_CT_Fonts_eastAsiaTheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "eastAsiaTheme", ThemeTable::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ uno::Any aPropValue( m_pImpl->GetThemeTable()->getFontNameForTheme( nIntValue ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_ASIAN, aPropValue );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_EAST_ASIA, aPropValue, true, CHAR_GRAB_BAG );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_EAST_ASIA, uno::Any( ThemeTable::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ }
+ break;
+ case NS_ooxml::LN_CT_Fonts_cs:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_COMPLEX, uno::Any( sStringValue ));
+ break;
+ case NS_ooxml::LN_CT_Fonts_cstheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "cstheme", ThemeTable::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ uno::Any aPropValue( m_pImpl->GetThemeTable()->getFontNameForTheme( nIntValue ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_COMPLEX, aPropValue );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_CS, aPropValue, true, CHAR_GRAB_BAG );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_CS, uno::Any( ThemeTable::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ }
+ break;
+ case NS_ooxml::LN_CT_Spacing_before:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "before", OUString::number(nIntValue));
+ if (m_pImpl->GetTopContext())
+ // Don't overwrite NS_ooxml::LN_CT_Spacing_beforeAutospacing.
+ m_pImpl->GetTopContext()->Insert(
+ PROP_PARA_TOP_MARGIN,
+ uno::Any(static_cast<sal_Int32>(convertTwipToMm100(nIntValue))), false);
+ break;
+ case NS_ooxml::LN_CT_Spacing_beforeLines:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "beforeLines", OUString::number(nIntValue));
+ // We would need to make sure that this doesn't overwrite any
+ // NS_ooxml::LN_CT_Spacing_before in parent styles before style
+ // sheet support can be enabled.
+ if (m_pImpl->GetTopContext() && !IsStyleSheetImport())
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_TOP_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(nIntValue * nSingleLineSpacing / 100)), false);
+ break;
+ case NS_ooxml::LN_CT_Spacing_after:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "after", OUString::number(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ // Don't overwrite NS_ooxml::LN_CT_Spacing_afterAutospacing.
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any( ConversionHelper::convertTwipToMM100( nIntValue ) ), false);
+
+ uno::Any aContextualSpacingFromStyle = m_pImpl->GetPropertyFromParaStyleSheet(PROP_PARA_CONTEXT_MARGIN);
+ if (aContextualSpacingFromStyle.hasValue())
+ // Setting "after" spacing means Writer doesn't inherit
+ // contextual spacing anymore from style, but Word does.
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_CONTEXT_MARGIN, aContextualSpacingFromStyle);
+ }
+ break;
+ case NS_ooxml::LN_CT_Spacing_afterLines:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "afterLines", OUString::number(nIntValue));
+ // We would need to make sure that this doesn't overwrite any
+ // NS_ooxml::LN_CT_Spacing_after in parent styles before style
+ // sheet support can be enabled.
+ if (m_pImpl->GetTopContext() && !IsStyleSheetImport())
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(nIntValue * nSingleLineSpacing / 100)), false);
+ break;
+ case NS_ooxml::LN_CT_Spacing_line: //91434
+ case NS_ooxml::LN_CT_Spacing_lineRule: //91435
+ {
+ style::LineSpacing aSpacing;
+ PropertyMapPtr pTopContext = m_pImpl->GetTopContext();
+ std::optional<PropertyMap::Property> aLineSpacingVal;
+ if (pTopContext && (aLineSpacingVal = pTopContext->getProperty(PROP_PARA_LINE_SPACING)) )
+ {
+ aLineSpacingVal->second >>= aSpacing;
+ }
+ else
+ {
+ //default to single line spacing
+ aSpacing.Mode = style::LineSpacingMode::FIX;
+ aSpacing.Height = sal_Int16(ConversionHelper::convertTwipToMM100( nSingleLineSpacing ));
+ }
+ if( nName == NS_ooxml::LN_CT_Spacing_line )
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "line", OUString::number(nIntValue));
+ //now set the value depending on the Mode
+ if( aSpacing.Mode == style::LineSpacingMode::PROP )
+ aSpacing.Height = sal_Int16(nIntValue * 100 / nSingleLineSpacing );
+ else
+ aSpacing.Height = sal_Int16(ConversionHelper::convertTwipToMM100( nIntValue ));
+ }
+ else //NS_ooxml::LN_CT_Spacing_lineRule:
+ {
+ // exactly, atLeast, auto
+ if( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto)
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "lineRule", "auto");
+ if (aSpacing.Height >= 0)
+ {
+ aSpacing.Mode = style::LineSpacingMode::PROP;
+ //reinterpret the already set value
+ aSpacing.Height = sal_Int16( aSpacing.Height * 100 / ConversionHelper::convertTwipToMM100( nSingleLineSpacing ));
+ }
+ else
+ {
+ // Negative value still means a positive height,
+ // just the mode is "exact".
+ aSpacing.Mode = style::LineSpacingMode::FIX;
+ aSpacing.Height *= -1;
+ }
+ }
+ else if( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast)
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "lineRule", "atLeast");
+ aSpacing.Mode = style::LineSpacingMode::MINIMUM;
+ }
+ else // NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "lineRule", "exact");
+ aSpacing.Mode = style::LineSpacingMode::FIX;
+ }
+ }
+ if (pTopContext)
+ pTopContext->Insert(PROP_PARA_LINE_SPACING, uno::Any( aSpacing ));
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_start:
+ case NS_ooxml::LN_CT_Ind_left:
+ if (m_pImpl->GetTopContext())
+ {
+ // Word inherits FirstLineIndent property of the numbering, even if ParaLeftMargin is set, Writer does not.
+ // So copy it explicitly, if necessary.
+ sal_Int32 nFirstLineIndent = m_pImpl->getCurrentNumberingProperty("FirstLineIndent");
+ sal_Int32 nIndentAt = m_pImpl->getCurrentNumberingProperty("IndentAt");
+
+ sal_Int32 nParaLeftMargin = ConversionHelper::convertTwipToMM100(nIntValue);
+ if (nParaLeftMargin != 0 && nIndentAt == nParaLeftMargin)
+ // Avoid direct left margin when it's the same as from the
+ // numbering.
+ break;
+
+ if (nFirstLineIndent != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN,
+ uno::Any(nParaLeftMargin));
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_end:
+ case NS_ooxml::LN_CT_Ind_right:
+ if (m_pImpl->GetTopContext())
+ {
+ // Word inherits FirstLineIndent/ParaLeftMargin property of the numbering, even if ParaRightMargin is set, Writer does not.
+ // So copy it explicitly, if necessary.
+ sal_Int32 nFirstLineIndent = m_pImpl->getCurrentNumberingProperty("FirstLineIndent");
+ sal_Int32 nParaLeftMargin = m_pImpl->getCurrentNumberingProperty("IndentAt");
+
+ if (nFirstLineIndent != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+ if (nParaLeftMargin != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+
+ m_pImpl->GetTopContext()->Insert(
+ PROP_PARA_RIGHT_MARGIN, uno::Any( ConversionHelper::convertTwipToMM100(nIntValue ) ));
+ }
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "right", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Ind_hanging:
+ if (m_pImpl->GetTopContext())
+ {
+ sal_Int32 nValue = ConversionHelper::convertTwipToMM100( nIntValue );
+ m_pImpl->GetTopContext()->Insert(
+ PROP_PARA_FIRST_LINE_INDENT, uno::Any( - nValue ));
+
+ // See above, need to inherit left margin from list style when first is set.
+ sal_Int32 nParaLeftMargin = m_pImpl->getCurrentNumberingProperty("IndentAt");
+ if (nParaLeftMargin != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ if (m_pImpl->GetTopContext())
+ {
+ sal_Int32 nFirstLineIndent
+ = m_pImpl->getCurrentNumberingProperty("FirstLineIndent");
+ sal_Int32 nParaFirstLineIndent = ConversionHelper::convertTwipToMM100(nIntValue);
+ if (nParaFirstLineIndent != 0 && nFirstLineIndent == nParaFirstLineIndent)
+ // Avoid direct first margin when it's the same as from the
+ // numbering.
+ break;
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT,
+ uno::Any(nParaFirstLineIndent));
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_rightChars:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "rightChars", OUString::number(nIntValue));
+ break;
+
+ case NS_ooxml::LN_CT_EastAsianLayout_id:
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_combine:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_IS_ON, uno::Any ( nIntValue != 0 ));
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_combineBrackets:
+ if (m_pImpl->GetTopContext())
+ {
+ OUString sCombinePrefix = getBracketStringFromEnum(nIntValue);
+ OUString sCombineSuffix = getBracketStringFromEnum(nIntValue, false);
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_PREFIX, uno::Any ( sCombinePrefix ));
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_SUFFIX, uno::Any ( sCombineSuffix ));
+ }
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_vert:
+ if (m_pImpl->GetTopContext())
+ {
+ sal_Int16 nRotationAngle = (nIntValue ? 900 : 0);
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_ROTATION, uno::Any ( nRotationAngle ));
+ }
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_vertCompress:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_ROTATION_IS_FIT_TO_LINE, uno::Any ( nIntValue != 0 ));
+ break;
+
+ case NS_ooxml::LN_CT_PageSz_code:
+ break;
+ case NS_ooxml::LN_CT_PageSz_h:
+ {
+ sal_Int32 nHeight = ConversionHelper::convertTwipToMM100WithoutLimit(nIntValue);
+ CT_PageSz.h = PaperInfo::sloppyFitPageDimension(nHeight);
+ }
+ break;
+ case NS_ooxml::LN_CT_PageSz_orient:
+ CT_PageSz.orient = (nIntValue != NS_ooxml::LN_Value_ST_PageOrientation_portrait);
+ break;
+ case NS_ooxml::LN_CT_PageSz_w:
+ {
+ sal_Int32 nWidth = ConversionHelper::convertTwipToMM100WithoutLimit(nIntValue);
+ CT_PageSz.w = PaperInfo::sloppyFitPageDimension(nWidth);
+ }
+ break;
+
+ case NS_ooxml::LN_CT_PageMar_top:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_TOP, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_right:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_RIGHT, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_bottom:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_BOTTOM, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_left:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_LEFT, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_header:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_HEADER, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_footer:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_FOOTER, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_gutter:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_GUTTER, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_Language_val: //90314
+ case NS_ooxml::LN_CT_Language_eastAsia: //90315
+ case NS_ooxml::LN_CT_Language_bidi: //90316
+ {
+ // store decimal symbol associated to the language of the document
+ if ( m_pImpl->IsDocDefaultsImport() && ( nName == NS_ooxml::LN_CT_Language_val ) )
+ {
+ LanguageTag aLanguageTag( sStringValue );
+ LocaleDataWrapper aLocaleWrapper( std::move(aLanguageTag) );
+ if ( aLocaleWrapper.getNumDecimalSep() == "," )
+ m_pImpl->SetIsDecimalComma();
+
+ }
+ if (nName == NS_ooxml::LN_CT_Language_eastAsia)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "eastAsia", sStringValue);
+ else if (nName == NS_ooxml::LN_CT_Language_val)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "val", sStringValue);
+ else if (nName == NS_ooxml::LN_CT_Language_bidi)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "bidi", sStringValue);
+ lang::Locale aLocale;
+ if (sStringValue.getLength() <= 3 && sStringValue.getLength() >= 1)
+ {
+ // Cheesy Google Docs is known to tag language-only even for
+ // "en" or others that need some region to distinguish language
+ // variants for spell-checker and hyphenation. Obtain our known
+ // fallback to clarify and match. The original value/context is
+ // unknown anyway.
+ LanguageTag aLanguageTag( sStringValue);
+ aLanguageTag.makeFallback();
+ if (aLanguageTag.getLanguage() == sStringValue)
+ aLocale = aLanguageTag.getLocale();
+ else
+ {
+ // Do not fallback for an unknown language, which usually
+ // results in "en-US", or any other non-matching case.
+ aLocale = LanguageTag::convertToLocale( sStringValue);
+ }
+ }
+ else
+ {
+ aLocale = LanguageTag::convertToLocale( sStringValue);
+ }
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(NS_ooxml::LN_CT_Language_val== nName ? PROP_CHAR_LOCALE :
+ NS_ooxml::LN_CT_Language_eastAsia == nName ? PROP_CHAR_LOCALE_ASIAN : PROP_CHAR_LOCALE_COMPLEX,
+ uno::Any( aLocale ) );
+ }
+ break;
+ // See SwWW8ImplReader::GetParagraphAutoSpace() on why these are 100 and 280
+ case NS_ooxml::LN_CT_Spacing_beforeAutospacing:
+ {
+ sal_Int32 default_spacing = -1;
+ if (nIntValue)
+ {
+ m_pImpl->SetParaAutoBefore(true);
+
+ default_spacing = 100;
+ if (!m_pImpl->GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing())
+ {
+ // 49 is just the old value that should be removed, once the
+ // root cause in SwTabFrm::MakeAll() is fixed.
+ if (m_pImpl->GetSettingsTable()->GetView() == NS_ooxml::LN_Value_doc_ST_View_web)
+ default_spacing = 49;
+ else
+ default_spacing = 280;
+ }
+ // required at export (here mainly for StyleSheets) to determine if the setting has changed from grab_bag
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_TOP_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(default_spacing)));
+ }
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::Any( ConversionHelper::convertTwipToMM100(default_spacing) ),true, PARA_GRAB_BAG );
+ }
+ break;
+ case NS_ooxml::LN_CT_Spacing_afterAutospacing:
+ {
+ sal_Int32 default_spacing = -1;
+ if (nIntValue)
+ {
+ default_spacing = 100;
+ if (!m_pImpl->GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing())
+ {
+ if (m_pImpl->GetSettingsTable()->GetView() == NS_ooxml::LN_Value_doc_ST_View_web)
+ default_spacing = 49;
+ else
+ default_spacing = 280;
+ }
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(default_spacing)));
+ }
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, uno::Any( ConversionHelper::convertTwipToMM100(default_spacing) ),true, PARA_GRAB_BAG );
+ }
+ break;
+ case NS_ooxml::LN_CT_SmartTagRun_uri:
+ m_pImpl->getSmartTagHandler().setURI(val.getString());
+ break;
+ case NS_ooxml::LN_CT_SmartTagRun_element:
+ m_pImpl->getSmartTagHandler().setElement(val.getString());
+ break;
+ case NS_ooxml::LN_CT_Br_type:
+ // Handled in the OOXMLBreakHandler dtor.
+ break;
+ case NS_ooxml::LN_CT_Br_clear:
+ m_pImpl->HandleLineBreakClear(val.getInt());
+ break;
+ case NS_ooxml::LN_CT_Fonts_hint :
+ /* assigns script type to ambiguous characters, values can be:
+ NS_ooxml::LN_Value_ST_Hint_default
+ NS_ooxml::LN_Value_ST_Hint_eastAsia
+ NS_ooxml::LN_Value_ST_Hint_cs
+ */
+ //TODO: unsupported?
+ break;
+ case NS_ooxml::LN_CT_TblBorders_right:
+ case NS_ooxml::LN_CT_TblBorders_top:
+ case NS_ooxml::LN_CT_TblBorders_left:
+ case NS_ooxml::LN_CT_TblBorders_bottom:
+ //todo: handle cell mar
+ break;
+ case NS_ooxml::LN_blip: // contains the binary graphic
+ case NS_ooxml::LN_shape:
+ {
+ //looks a bit like a hack - and it is. The graphic import is split into the inline_inline part and
+ //afterwards the adding of the binary data.
+ m_pImpl->GetGraphicImport( IMPORT_AS_DETECTED_INLINE )->attribute(nName, val);
+ m_pImpl->ImportGraphic( val.getProperties(), IMPORT_AS_DETECTED_INLINE );
+ }
+ break;
+ case NS_ooxml::LN_Value_math_ST_Jc_centerGroup:
+ case NS_ooxml::LN_Value_math_ST_Jc_center:
+ m_pImpl->appendStarMath(val);
+ m_pImpl->adjustLastPara(sal_Int8(style::ParagraphAdjust::ParagraphAdjust_CENTER));
+ break;
+ case NS_ooxml::LN_Value_math_ST_Jc_left:
+ m_pImpl->appendStarMath(val);
+ m_pImpl->adjustLastPara(sal_Int8(style::ParagraphAdjust::ParagraphAdjust_LEFT));
+ break;
+ case NS_ooxml::LN_Value_math_ST_Jc_right:
+ m_pImpl->appendStarMath(val);
+ m_pImpl->adjustLastPara(sal_Int8(style::ParagraphAdjust::ParagraphAdjust_RIGHT));
+ break;
+ case NS_ooxml::LN_starmath:
+ m_pImpl->appendStarMath(val);
+ break;
+ case NS_ooxml::LN_CT_FramePr_dropCap:
+ case NS_ooxml::LN_CT_FramePr_lines:
+ case NS_ooxml::LN_CT_FramePr_hAnchor:
+ case NS_ooxml::LN_CT_FramePr_vAnchor:
+ case NS_ooxml::LN_CT_FramePr_x:
+ case NS_ooxml::LN_CT_FramePr_xAlign:
+ case NS_ooxml::LN_CT_FramePr_y:
+ case NS_ooxml::LN_CT_FramePr_yAlign:
+ case NS_ooxml::LN_CT_FramePr_hRule:
+ case NS_ooxml::LN_CT_FramePr_w:
+ case NS_ooxml::LN_CT_FramePr_h:
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ {
+ ParagraphProperties* pParaProperties = nullptr;
+ // handle frame properties at styles
+ if( m_pImpl->GetTopContextType() == CONTEXT_STYLESHEET )
+ pParaProperties = dynamic_cast< ParagraphProperties*>( m_pImpl->GetTopContextOfType( CONTEXT_STYLESHEET ).get() );
+ else
+ pParaProperties = dynamic_cast< ParagraphProperties*>( m_pImpl->GetTopContextOfType( CONTEXT_PARAGRAPH ).get() );
+
+ if( pParaProperties )
+ {
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_FramePr_dropCap:
+ pParaProperties->SetDropCap( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_lines:
+ pParaProperties->SetLines( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_hAnchor:
+ switch(nIntValue)
+ {
+ case NS_ooxml::LN_Value_doc_ST_HAnchor_text: //relative to column
+ nIntValue = text::RelOrientation::FRAME; break;
+ case NS_ooxml::LN_Value_doc_ST_HAnchor_margin: nIntValue = text::RelOrientation::PAGE_PRINT_AREA; break;
+ case NS_ooxml::LN_Value_doc_ST_HAnchor_page: nIntValue = text::RelOrientation::PAGE_FRAME; break;
+ default:;
+ }
+ pParaProperties->SethAnchor( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_vAnchor:
+ switch(nIntValue)
+ {
+ case NS_ooxml::LN_Value_doc_ST_VAnchor_text: //relative to paragraph
+ nIntValue = text::RelOrientation::FRAME; break;
+ case NS_ooxml::LN_Value_doc_ST_VAnchor_margin:nIntValue = text::RelOrientation::PAGE_PRINT_AREA ; break;
+ case NS_ooxml::LN_Value_doc_ST_VAnchor_page: nIntValue = text::RelOrientation::PAGE_FRAME; break;
+ default:;
+ }
+ pParaProperties->SetvAnchor( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_x:
+ pParaProperties->Setx( ConversionHelper::convertTwipToMM100(nIntValue ));
+ pParaProperties->SetxAlign( text::HoriOrientation::NONE );
+ break;
+ case NS_ooxml::LN_CT_FramePr_xAlign:
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_doc_ST_XAlign_center : nIntValue = text::HoriOrientation::CENTER; break;
+ case NS_ooxml::LN_Value_doc_ST_XAlign_right : nIntValue = text::HoriOrientation::RIGHT; break;
+ case NS_ooxml::LN_Value_doc_ST_XAlign_inside : nIntValue = text::HoriOrientation::INSIDE; break;
+ case NS_ooxml::LN_Value_doc_ST_XAlign_outside : nIntValue = text::HoriOrientation::OUTSIDE; break;
+ case NS_ooxml::LN_Value_doc_ST_XAlign_left : nIntValue = text::HoriOrientation::LEFT; break;
+ default: nIntValue = text::HoriOrientation::NONE;
+ }
+ pParaProperties->SetxAlign( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_y:
+ pParaProperties->Sety( ConversionHelper::convertTwipToMM100(nIntValue ));
+ pParaProperties->SetyAlign( text::VertOrientation::NONE );
+ break;
+ case NS_ooxml::LN_CT_FramePr_yAlign:
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_doc_ST_YAlign_top :
+ case NS_ooxml::LN_Value_doc_ST_YAlign_inside :nIntValue = text::VertOrientation::TOP; break;
+ case NS_ooxml::LN_Value_doc_ST_YAlign_center :nIntValue = text::VertOrientation::CENTER;break;
+ case NS_ooxml::LN_Value_doc_ST_YAlign_bottom :
+ case NS_ooxml::LN_Value_doc_ST_YAlign_outside :nIntValue = text::VertOrientation::BOTTOM;break;
+ case NS_ooxml::LN_Value_doc_ST_YAlign_inline :
+ {
+ // HACK: This is for bnc#780851, where a table has one cell that has w:framePr,
+ // which causes that paragraph to be converted to a text frame, and the original
+ // paragraph object no longer exists, which makes table creation fail and furthermore
+ // it would be missing in the table layout anyway. So actually no letting that paragraph
+ // be a text frame "fixes" it. I'm not sure what "inline" is supposed to mean in practice
+ // anyway, so as long as this doesn't cause trouble elsewhere ...
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if( pContext )
+ {
+ ParagraphPropertyMap* pParaContext = dynamic_cast< ParagraphPropertyMap* >( pContext.get() );
+ if (pParaContext)
+ pParaContext->SetFrameMode(false);
+ }
+ nIntValue = text::VertOrientation::NONE;
+ break;
+ }
+ default:
+ nIntValue = text::VertOrientation::NONE;
+ break;
+ }
+ pParaProperties->SetyAlign( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_hRule:
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_doc_ST_HeightRule_exact:
+ nIntValue = text::SizeType::FIX;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_HeightRule_atLeast:
+ nIntValue = text::SizeType::MIN;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_HeightRule_auto:
+ //no break;
+ default:;
+ nIntValue = text::SizeType::VARIABLE;
+ }
+ pParaProperties->SethRule( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ {
+ //should be either LN_Value_doc_ST_Wrap_notBeside or LN_Value_doc_ST_Wrap_around or LN_Value_doc_ST_Wrap_auto
+ OSL_ENSURE( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_around ||
+ sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_notBeside ||
+ sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_through ||
+ sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_none ||
+ sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_auto,
+ "wrap not around, not_Beside, through, none or auto?");
+ if( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_through ||
+ sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_auto )
+ pParaProperties->SetWrap ( text::WrapTextMode_DYNAMIC ) ;
+ else if (sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_around)
+ pParaProperties->SetWrap(text::WrapTextMode_PARALLEL);
+ else if (sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_none)
+ pParaProperties->SetWrap ( text::WrapTextMode_THROUGH ) ;
+ else
+ pParaProperties->SetWrap ( text::WrapTextMode_NONE ) ;
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_w:
+ pParaProperties->Setw(ConversionHelper::convertTwipToMM100(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ pParaProperties->Seth(ConversionHelper::convertTwipToMM100(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ pParaProperties->SethSpace( ConversionHelper::convertTwipToMM100(nIntValue ));
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ pParaProperties->SetvSpace( ConversionHelper::convertTwipToMM100(nIntValue ));
+ break;
+ default:;
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrackChange_author:
+ m_pImpl->SetCurrentRedlineAuthor( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_TrackChange_date:
+ m_pImpl->SetCurrentRedlineDate( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_Markup_id:
+ m_pImpl->SetCurrentRedlineId( nIntValue );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart:
+ m_pImpl->AddAnnotationPosition( true, nIntValue );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd:
+ m_pImpl->AddAnnotationPosition( false, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_Comment_initials:
+ m_pImpl->SetCurrentRedlineInitials(sStringValue);
+ break;
+ case NS_ooxml::LN_token:
+ m_pImpl->SetCurrentRedlineToken( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_start:
+ case NS_ooxml::LN_CT_LineNumber_distance:
+ case NS_ooxml::LN_CT_LineNumber_countBy:
+ case NS_ooxml::LN_CT_LineNumber_restart:
+ {
+ //line numbering in Writer is a global document setting
+ //in Word is a section setting
+ //if line numbering is switched on anywhere in the document it's set at the global settings
+ LineNumberSettings aSettings = m_pImpl->GetLineNumberSettings();
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_LineNumber_countBy:
+ aSettings.nInterval = nIntValue;
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetLnnMod( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_start:
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetLnnMin( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_distance:
+ aSettings.nDistance = ConversionHelper::convertTwipToMM100( nIntValue );
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetdxaLnn( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_restart:
+ aSettings.bRestartAtEachPage = nIntValue == NS_ooxml::LN_Value_ST_LineNumberRestart_newPage;
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetLnc( nIntValue );
+ break;
+ default:;
+ }
+ m_pImpl->SetLineNumberSettings( aSettings );
+ }
+ break;
+ case NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows:
+ m_pImpl->StartCustomFootnote(m_pImpl->GetTopContext());
+ break;
+ case NS_ooxml::LN_CT_FtnEdnRef_id:
+ // footnote or endnote reference id - not needed
+ break;
+ case NS_ooxml::LN_CT_Color_themeColor:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "themeColor", TDefTableHandler::getThemeColorTypeString(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Color_themeTint:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "themeTint", OUString::number(nIntValue, 16));
+ break;
+ case NS_ooxml::LN_CT_Color_themeShade:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "themeShade", OUString::number(nIntValue, 16));
+ break;
+ case NS_ooxml::LN_CT_DocGrid_linePitch:
+ {
+ //see SwWW8ImplReader::SetDocumentGrid
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ pSectionContext->SetGridLinePitch( ConversionHelper::convertTwipToMM100( nIntValue ) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_DocGrid_charSpace:
+ {
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ pSectionContext->SetDxtCharSpace( nIntValue );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_DocGrid_type:
+ {
+ if (pSectionContext != nullptr)
+ {
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_default:
+ pSectionContext->SetGridType(text::TextGridMode::NONE);
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_lines:
+ pSectionContext->SetGridType(text::TextGridMode::LINES);
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_linesAndChars:
+ pSectionContext->SetGridType(text::TextGridMode::LINES_AND_CHARS);
+ pSectionContext->SetGridSnapToChars( false );
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_snapToChars:
+ pSectionContext->SetGridType(text::TextGridMode::LINES_AND_CHARS);
+ pSectionContext->SetGridSnapToChars( true );
+ break;
+ default :
+ OSL_FAIL("unknown SwTextGrid value");
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtBlock_sdtContent:
+ case NS_ooxml::LN_CT_SdtRun_sdtContent:
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::unknown)
+ {
+ // Still not determined content type? and it is even not unsupported? Then it is plain text field
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ }
+ if (nName == NS_ooxml::LN_CT_SdtRun_sdtContent)
+ {
+ if (m_pImpl->GetSdtStarts().empty() && !m_pImpl->m_pSdtHelper->getSdtTexts().isEmpty())
+ {
+ // A non-inline SDT is already started, first convert that to a field and only
+ // then map the inline SDT to a content control.
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ }
+ }
+
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::richText);
+ m_pImpl->PushSdt();
+ break;
+ }
+ m_pImpl->SetSdt(true);
+ break;
+ case NS_ooxml::LN_CT_SdtBlock_sdtEndContent:
+ case NS_ooxml::LN_CT_SdtRun_sdtEndContent:
+ if (nName == NS_ooxml::LN_CT_SdtRun_sdtEndContent)
+ {
+ // Inline SDT.
+ switch (m_pImpl->m_pSdtHelper->getControlType())
+ {
+ case SdtControlType::richText:
+ case SdtControlType::checkBox:
+ case SdtControlType::dropDown:
+ case SdtControlType::picture:
+ case SdtControlType::datePicker:
+ m_pImpl->PopSdt();
+ break;
+ default:
+ break;
+ }
+ }
+
+ m_pImpl->SetSdt(false);
+
+ // It's not possible to insert the relevant property to the character context here:
+ // the previous, already sent character context may be still active, so the property would be lost.
+ if (m_pImpl->m_pSdtHelper->isOutsideAParagraph())
+ m_pImpl->setParaSdtEndDeferred(true);
+ else
+ m_pImpl->setSdtEndDeferred(true);
+
+ switch (m_pImpl->m_pSdtHelper->getControlType())
+ {
+ case SdtControlType::dropDown:
+ m_pImpl->m_pSdtHelper->createDropDownControl();
+ break;
+ case SdtControlType::plainText:
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ break;
+ case SdtControlType::datePicker:
+ m_pImpl->m_pSdtHelper->createDateContentControl();
+ break;
+ case SdtControlType::unknown:
+ default:;
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtListItem_displayText:
+ m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().push_back(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtListItem_value:
+ m_pImpl->m_pSdtHelper->getDropDownItems().push_back(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtDate_fullDate:
+ m_pImpl->m_pSdtHelper->getDate().append(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Background_color:
+ if (m_pImpl->GetSettingsTable()->GetDisplayBackgroundShape())
+ m_pImpl->m_oBackgroundColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_PageNumber_start:
+ if (pSectionContext != nullptr && !m_pImpl->IsAltChunk())
+ pSectionContext->SetPageNumber(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_PageNumber_fmt:
+ if (pSectionContext)
+ {
+ sal_Int16 nNumberType = ConversionHelper::ConvertNumberingType(nIntValue, -1);
+ if (nNumberType != -1)
+ pSectionContext->SetPageNumberType(nNumberType);
+ }
+ break;
+ case NS_ooxml::LN_CT_FtnEdn_type:
+ // This is the "separator" footnote, ignore its linebreaks/text.
+ if (static_cast<sal_uInt32>(nIntValue) == NS_ooxml::LN_Value_doc_ST_FtnEdn_separator)
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::ON );
+ else
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::OFF );
+ break;
+ case NS_ooxml::LN_CT_FtnEdn_id:
+ {
+ SkipFootnoteSeparator eSkip = m_pImpl->GetSkipFootnoteState();
+ if ( eSkip == SkipFootnoteSeparator::ON )
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::SKIPPING );
+ else if ( eSkip == SkipFootnoteSeparator::SKIPPING )
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::OFF );
+ }
+ break;
+ case NS_ooxml::LN_CT_DataBinding_prefixMappings:
+ m_pImpl->m_pSdtHelper->setDataBindingPrefixMapping(sStringValue);
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_prefixMappings", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_DataBinding_xpath:
+ m_pImpl->m_pSdtHelper->setDataBindingXPath(sStringValue);
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_xpath", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_DataBinding_storeItemID:
+ m_pImpl->m_pSdtHelper->setDataBindingStoreItemID(sStringValue);
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_storeItemID", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtPlaceholder_docPart_val", sStringValue);
+ m_pImpl->m_pSdtHelper->SetPlaceholderDocPart(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtColor_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtColor_val", sStringValue);
+ m_pImpl->m_pSdtHelper->SetColor(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtText_multiLine:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtText_multiLine", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_PTab_leader:
+ case NS_ooxml::LN_CT_PTab_relativeTo:
+ break;
+ case NS_ooxml::LN_CT_PTab_alignment:
+ m_pImpl->HandlePTab(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastRowLastColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastRowLastColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastRowFirstColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastRowFirstColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstRowLastColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstRowLastColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_oddHBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "oddHBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstRowFirstColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstRowFirstColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_evenVBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "evenVBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_evenHBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "evenHBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_oddVBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "oddVBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastRow:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastRow", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstRow:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstRow", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_DocPartName_val:
+ {
+ m_sGlossaryEntryName = sStringValue;
+ break;
+ }
+ case NS_ooxml::LN_CT_DocPartGallery_val:
+ {
+ const OUString& sGlossaryEntryGallery = sStringValue;
+ if(m_pImpl->GetTopContext())
+ {
+ OUString sName = sGlossaryEntryGallery + ":" + m_sGlossaryEntryName;
+ // Add glossary entry name as a first paragraph in section
+ m_pImpl->appendTextPortion(sName, m_pImpl->GetTopContext());
+ }
+ break;
+ }
+ case NS_ooxml::LN_CT_PermStart_ed:
+ {
+ m_pImpl->setPermissionRangeEd(sStringValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_PermStart_edGrp:
+ {
+ m_pImpl->setPermissionRangeEdGrp(sStringValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_PermStart_id:
+ {
+ m_pImpl->startOrEndPermissionRange(nIntValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_PermEnd_id:
+ {
+ m_pImpl->startOrEndPermissionRange(nIntValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_NumFmt_val:
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xFtnEdnSettings;
+ if (m_pImpl->IsInFootnoteProperties())
+ {
+ uno::Reference<text::XFootnotesSupplier> xFootnotesSupplier(
+ m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if (xFootnotesSupplier.is())
+ xFtnEdnSettings = xFootnotesSupplier->getFootnoteSettings();
+ }
+ else
+ {
+ uno::Reference<text::XEndnotesSupplier> xEndnotesSupplier(
+ m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if (xEndnotesSupplier.is())
+ xFtnEdnSettings = xEndnotesSupplier->getEndnoteSettings();
+ }
+ if (xFtnEdnSettings.is())
+ {
+ sal_Int16 nNumType = ConversionHelper::ConvertNumberingType(nIntValue);
+ xFtnEdnSettings->setPropertyValue(getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any(nNumType));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_AltChunk:
+ {
+ m_pImpl->HandleAltChunk(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_AG_Parids_paraId:
+ if (ParagraphPropertyMap* pParaContext
+ = dynamic_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContext().get()))
+ {
+ pParaContext->SetParaId(sStringValue);
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "DomainMapper::lcl_attribute: unhandled token: " << nName);
+ }
+}
+
+void DomainMapper::lcl_sprm(Sprm & rSprm)
+{
+ if (!m_pImpl->hasTableManager() || !m_pImpl->getTableManager().sprm(rSprm))
+ sprmWithProps(rSprm, m_pImpl->GetTopContext());
+}
+
+// In rtl-paragraphs the meaning of left/right are to be exchanged
+static bool ExchangeLeftRight(const PropertyMapPtr& rContext, DomainMapper_Impl& rImpl)
+{
+ bool bExchangeLeftRight = false;
+ sal_Int32 aAdjust;
+ uno::Any aPropPara = rImpl.GetAnyProperty(PROP_WRITING_MODE, rContext);
+ if( (aPropPara >>= aAdjust) && aAdjust == text::WritingMode2::RL_TB )
+ bExchangeLeftRight = true;
+ return bExchangeLeftRight;
+}
+
+void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
+{
+ // These SPRM's are not specific to any section, so it's expected that there is no context yet.
+ switch (rSprm.getId())
+ {
+ case NS_ooxml::LN_background_background:
+ return;
+ default:
+ break;
+ }
+
+ OSL_ENSURE(rContext, "PropertyMap has to be valid!");
+ if(!rContext)
+ return ;
+
+ sal_uInt32 nSprmId = rSprm.getId();
+ //needed for page properties
+ SectionPropertyMap * pSectionContext = m_pImpl->GetSectionContext();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = pValue->getInt();
+ const OUString sStringValue = pValue->getString();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_PPrBase_jc:
+ {
+ bool bExchangeLeftRight = !IsRTFImport() && ExchangeLeftRight(rContext, *m_pImpl);
+ handleParaJustification(nIntValue, rContext, bExchangeLeftRight);
+ break;
+ }
+ case NS_ooxml::LN_CT_PPrBase_keepLines:
+ rContext->Insert(PROP_PARA_SPLIT, uno::Any(nIntValue == 0));
+ break;
+ case NS_ooxml::LN_CT_PPrBase_keepNext:
+ rContext->Insert(PROP_PARA_KEEP_TOGETHER, uno::Any( nIntValue != 0 ) );
+ break;
+ case NS_ooxml::LN_CT_PPrBase_pageBreakBefore:
+ rContext->Insert(PROP_BREAK_TYPE, uno::Any(nIntValue ? style::BreakType_PAGE_BEFORE : style::BreakType_NONE), /*bOverwrite=*/bool(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_NumPr_ilvl:
+ if (nIntValue < 0 || 10 <= nIntValue)
+ {
+ SAL_INFO("writerfilter",
+ "unsupported numbering level " << nIntValue);
+ break;
+ }
+ if( IsStyleSheetImport() )
+ {
+ //style sheets cannot have a numbering rule attached
+ StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() );
+ if (pStyleSheetPropertyMap)
+ pStyleSheetPropertyMap->SetListLevel( static_cast<sal_Int16>(nIntValue) );
+ }
+ // 0-8 are the 9 levels that Microsoft supports. (LO supports 10 levels).
+ // 9 indicates "no numbering", for which LO has no corresponding concept,
+ // and so it will be treated as the 10th level.
+ // finishParagraph() will convert the 9 into "no numbering" for direct formatting.
+ // (Styles only use this PROP for round-tripping and UI, but cannot trust it for import)
+ if (!IsStyleSheetImport() || nIntValue != 9)
+ rContext->Insert(PROP_NUMBERING_LEVEL, uno::Any(static_cast<sal_Int16>(nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_NumPr_numId:
+ {
+ //convert the ListTable entry to a NumberingRules property and apply it
+ ListsManager::Pointer pListTable = m_pImpl->GetListTable();
+ ListDef::Pointer pList = pListTable->GetList( nIntValue );
+ if( IsStyleSheetImport() )
+ {
+ //style sheets cannot have a numbering rule attached
+ StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() );
+ if (pStyleSheetPropertyMap)
+ pStyleSheetPropertyMap->SetListId( nIntValue );
+ }
+ if( pList )
+ {
+ if( !IsStyleSheetImport() )
+ {
+ uno::Any aRules( pList->GetNumberingRules( ) );
+ rContext->Insert( PROP_NUMBERING_RULES, aRules );
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (pContext)
+ {
+ assert(dynamic_cast<ParagraphPropertyMap*>(pContext.get()));
+ static_cast<ParagraphPropertyMap*>(pContext.get())->SetListId(pList->GetId());
+ }
+
+ // Indentation can came from:
+ // 1) Paragraph style's numbering's indentation: the current non-style numId has priority over it.
+ // 2) Numbering's indentation: Writer handles that natively, so it should not be set on rContext.
+ // 3) Paragraph style's indentation: ditto.
+ // 4) Direct paragraph formatting: that will came later.
+ // So no situation where keeping indentation at this point would make sense -> erase.
+ rContext->Erase(PROP_PARA_FIRST_LINE_INDENT);
+ rContext->Erase(PROP_PARA_LEFT_MARGIN);
+ rContext->Erase(PROP_PARA_RIGHT_MARGIN);
+ }
+ }
+ else
+ {
+ if( !IsStyleSheetImport() )
+ {
+ // eg. disabled numbering using non-existent numId "0"
+ rContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::Any( OUString() ) );
+ // disable inheritance of indentation of parent styles
+ rContext->Insert( PROP_PARA_LEFT_MARGIN, uno::Any( sal_Int32(0) ), /*bOverwrite=*/false);
+ rContext->Insert( PROP_PARA_FIRST_LINE_INDENT,
+ uno::Any( sal_Int32(0) ), /*bOverwrite=*/false);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_suppressLineNumbers:
+ rContext->Insert(PROP_PARA_LINE_NUMBER_COUNT, uno::Any( nIntValue == 0 ) );
+ break;
+ case NS_ooxml::LN_inTbl:
+ break;
+ case NS_ooxml::LN_tblDepth:
+ //not handled via sprm but via text( 0x07 )
+ break;
+ case NS_ooxml::LN_CT_FramePr_w:
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ break;
+
+ case NS_ooxml::LN_CT_PrBase_pBdr: //paragraph border
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_CT_PBdr_top:
+ case NS_ooxml::LN_CT_PBdr_left:
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ case NS_ooxml::LN_CT_PBdr_right:
+ case NS_ooxml::LN_CT_PBdr_between:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>( true );
+ pProperties->resolve(*pBorderHandler);
+ PropertyIds eBorderId = PropertyIds( 0 );
+ PropertyIds eBorderDistId = PropertyIds( 0 );
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_PBdr_top:
+ eBorderId = PROP_TOP_BORDER;
+ eBorderDistId = PROP_TOP_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_left:
+ eBorderId = PROP_LEFT_BORDER;
+ eBorderDistId = PROP_LEFT_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ eBorderId = PROP_BOTTOM_BORDER ;
+ eBorderDistId = PROP_BOTTOM_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_right:
+ eBorderId = PROP_RIGHT_BORDER;
+ eBorderDistId = PROP_RIGHT_BORDER_DISTANCE ;
+ break;
+ case NS_ooxml::LN_CT_PBdr_between:
+ if (m_pImpl->handlePreviousParagraphBorderInBetween())
+ {
+ // If previous paragraph also had border in between property
+ // then it is possible to emulate this border as top border
+ // for current paragraph
+ eBorderId = PROP_TOP_BORDER;
+ eBorderDistId = PROP_TOP_BORDER_DISTANCE;
+ }
+ // Since there are borders in between, each paragraph will have own borders. No more joining
+ rContext->Insert(PROP_PARA_CONNECT_BORDERS, uno::Any(false));
+ break;
+ default:;
+ }
+ if( eBorderId )
+ rContext->Insert( eBorderId, uno::Any( pBorderHandler->getBorderLine()) );
+ if(eBorderDistId)
+ rContext->Insert(eBorderDistId, uno::Any( pBorderHandler->getLineDistance()));
+ if ( nSprmId == NS_ooxml::LN_CT_PBdr_right )
+ {
+ table::ShadowFormat aFormat;
+ // Word only allows shadows on visible borders
+ if ( pBorderHandler->getShadow() && pBorderHandler->getBorderLine().LineStyle != table::BorderLineStyle::NONE )
+ aFormat = writerfilter::dmapper::PropertyMap::getShadowFromBorder(pBorderHandler->getBorderLine());
+ rContext->Insert(PROP_PARA_SHADOW_FORMAT, uno::Any(aFormat));
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PBdr_bar:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens:
+ rContext->Insert(PROP_PARA_IS_HYPHENATION, uno::Any( nIntValue == 0 ));
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ break;
+ case NS_ooxml::LN_CT_PrBase_shd:
+ {
+ //contains fore color, back color and shadow percentage, results in a brush
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellColorHandler = std::make_shared<CellColorHandler>();
+ pCellColorHandler->setOutputFormat( CellColorHandler::Paragraph );
+ bool bEnableTempGrabBag = !pCellColorHandler->isInteropGrabBagEnabled();
+ if( bEnableTempGrabBag )
+ pCellColorHandler->enableInteropGrabBag( "TempShdPropsGrabBag" );
+
+ pProperties->resolve(*pCellColorHandler);
+ rContext->InsertProps(pCellColorHandler->getProperties().get());
+
+ rContext->Insert(PROP_CHAR_THEME_FILL, pCellColorHandler->getInteropGrabBag().Value, true, PARA_GRAB_BAG);
+ if(bEnableTempGrabBag)
+ pCellColorHandler->disableInteropGrabBag();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ break; // sprmPDyaFromText
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ break; // sprmPDxaFromText
+ case NS_ooxml::LN_CT_FramePr_anchorLock:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_widowControl:
+ {
+ uno::Any aVal( uno::Any( sal_Int8(nIntValue ? 2 : 0 )));
+ rContext->Insert( PROP_PARA_WIDOWS, aVal );
+ rContext->Insert( PROP_PARA_ORPHANS, aVal );
+ }
+ break; // sprmPFWidowControl
+ case NS_ooxml::LN_CT_PPrBase_overflowPunct:
+ rContext->Insert(PROP_PARA_IS_HANGING_PUNCTUATION, uno::Any( nIntValue == 0 ));
+ break;
+ case NS_ooxml::LN_CT_PPrBase_topLinePunct:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_autoSpaceDE:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_autoSpaceDN:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_textAlignment:
+ {
+ sal_Int16 nAlignment = 0;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_top:
+ nAlignment = 2;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_center:
+ nAlignment = 3;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline:
+ nAlignment = 1;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_bottom:
+ nAlignment = 4;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_auto:
+ default:
+ break;
+ }
+ rContext->Insert( PROP_PARA_VERT_ALIGNMENT, uno::Any( nAlignment) );
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_textDirection:
+ {
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr:
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::BT_LR);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::LR_TB);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
+ default:
+ SAL_WARN("writerfilter", "DomainMapper::sprmWithProps: unhandled textDirection");
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_outlineLvl:
+ {
+ if (nIntValue < WW_OUTLINE_MIN || nIntValue > WW_OUTLINE_MAX)
+ break; // invalid value is ignored by MS Word
+
+ if( IsStyleSheetImport() )
+ {
+ StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() );
+ if (pStyleSheetPropertyMap)
+ pStyleSheetPropertyMap->SetOutlineLevel(nIntValue);
+ }
+ else
+ {
+ // convert MS body level (9) to LO body level (0) and equivalent outline levels
+ sal_Int16 nLvl = nIntValue == WW_OUTLINE_MAX ? 0 : nIntValue + 1;
+ rContext->Insert(PROP_OUTLINE_LEVEL, uno::Any ( nLvl ));
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_bidi:
+ {
+ // Four situations to handle:
+ // 1.) bidi same as previous setting: no adjust change
+ // 2.) no previous adjust: set appropriate default for this bidi
+ // 3.) previous adjust and bidi different from previous: swap adjusts
+ // 4.) previous adjust and no previous bidi: RTL swaps adjust
+
+ const sal_Int16 nWritingMode = nIntValue ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB;
+ sal_Int16 nParentBidi = -1;
+ m_pImpl->GetPropertyFromParaStyleSheet(PROP_WRITING_MODE) >>= nParentBidi;
+ // Paragraph justification reverses its meaning in an RTL context.
+ // 1. Only make adjustments if the BiDi changes.
+ if ( nParentBidi != nWritingMode && !IsRTFImport() )
+ {
+ style::ParagraphAdjust eAdjust = style::ParagraphAdjust(-1);
+ // 2. no adjust property exists yet
+ if ( !(m_pImpl->GetAnyProperty(PROP_PARA_ADJUST, rContext) >>= eAdjust) )
+ {
+ // RTL defaults to right adjust
+ eAdjust = nIntValue ? style::ParagraphAdjust_RIGHT : style::ParagraphAdjust_LEFT;
+ rContext->Insert(PROP_PARA_ADJUST, uno::Any( eAdjust ), /*bOverwrite=*/false);
+ }
+ // 3,4. existing adjust: if RTL, then swap. If LTR, but previous was RTL, also swap.
+ else if ( nIntValue || nParentBidi == sal_Int16(text::WritingMode2::RL_TB) )
+ {
+ if ( eAdjust == style::ParagraphAdjust_RIGHT )
+ rContext->Insert(PROP_PARA_ADJUST, uno::Any( style::ParagraphAdjust_LEFT ));
+ else if ( eAdjust == style::ParagraphAdjust_LEFT )
+ rContext->Insert(PROP_PARA_ADJUST, uno::Any( style::ParagraphAdjust_RIGHT ));
+ }
+ }
+ rContext->Insert(PROP_WRITING_MODE, uno::Any( nWritingMode ));
+ }
+
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_bidi:
+ if (pSectionContext != nullptr)
+ {
+ const sal_Int16 writingMode = (nIntValue != 0) ? sal_Int16(text::WritingMode2::RL_TB) : sal_Int16(text::WritingMode2::LR_TB);
+ pSectionContext->Insert(PROP_WRITING_MODE, uno::Any(writingMode));
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_rtlGutter:
+ if (pSectionContext != nullptr)
+ {
+ bool bRtlGutter = nIntValue != 0;
+ pSectionContext->Insert(PROP_RTL_GUTTER, uno::Any(bRtlGutter));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_highlight:
+ {
+ // MS Word completely ignores character highlighting in character styles.
+ if ( IsStyleSheetImport() )
+ {
+ const StyleSheetEntryPtr pCurrStyle = GetStyleSheetTable()->GetCurrentEntry();
+ if ( pCurrStyle && pCurrStyle->nStyleTypeCode == STYLE_TYPE_CHAR )
+ break;
+ }
+
+ // OOXML import uses an ID
+ if( IsOOXMLImport() )
+ {
+ sal_Int32 nColor = 0;
+ if( getColorFromId(nIntValue, nColor) )
+ rContext->Insert(PROP_CHAR_HIGHLIGHT, uno::Any( nColor ));
+ }
+ // RTF import uses the actual color value
+ else if( IsRTFImport() )
+ {
+ rContext->Insert(PROP_CHAR_HIGHLIGHT, uno::Any( nIntValue ));
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_em:
+ rContext->Insert(PROP_CHAR_EMPHASIS, uno::Any ( getEmphasisValue (nIntValue)));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_emboss:
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_bCs:
+ case NS_ooxml::LN_EG_RPrBase_i:
+ case NS_ooxml::LN_EG_RPrBase_iCs:
+ case NS_ooxml::LN_EG_RPrBase_strike:
+ case NS_ooxml::LN_EG_RPrBase_dstrike:
+ case NS_ooxml::LN_EG_RPrBase_outline:
+ case NS_ooxml::LN_EG_RPrBase_shadow:
+ case NS_ooxml::LN_EG_RPrBase_caps:
+ case NS_ooxml::LN_EG_RPrBase_smallCaps:
+ case NS_ooxml::LN_EG_RPrBase_vanish:
+ case NS_ooxml::LN_EG_RPrBase_webHidden:
+ {
+ PropertyIds ePropertyId = PROP_CHAR_WEIGHT; //initialized to prevent warning!
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_bCs:
+ ePropertyId = nSprmId != NS_ooxml::LN_EG_RPrBase_bCs ? PROP_CHAR_WEIGHT : PROP_CHAR_WEIGHT_COMPLEX;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_i:
+ case NS_ooxml::LN_EG_RPrBase_iCs:
+ ePropertyId = nSprmId == NS_ooxml::LN_EG_RPrBase_i ? PROP_CHAR_POSTURE : PROP_CHAR_POSTURE_COMPLEX;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_strike:
+ case NS_ooxml::LN_EG_RPrBase_dstrike:
+ ePropertyId = PROP_CHAR_STRIKEOUT;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_outline:
+ ePropertyId = PROP_CHAR_CONTOURED;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_shadow:
+ ePropertyId = PROP_CHAR_SHADOWED;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_caps:
+ case NS_ooxml::LN_EG_RPrBase_smallCaps:
+ ePropertyId = PROP_CHAR_CASE_MAP;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_vanish:
+ case NS_ooxml::LN_EG_RPrBase_webHidden:
+ ePropertyId = PROP_CHAR_HIDDEN;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_emboss:
+ ePropertyId = PROP_CHAR_RELIEF;
+ break;
+ }
+ //expected: 0,1,128,129
+ if(nIntValue != 128) //inherited from paragraph - ignore
+ {
+ if( nIntValue == 129) //inverted style sheet value
+ {
+ //get value from style sheet and invert it
+ sal_Int16 nStyleValue = 0;
+ uno::Any aStyleVal = m_pImpl->GetPropertyFromParaStyleSheet(ePropertyId);
+ if( !aStyleVal.hasValue() )
+ {
+ nIntValue = NS_ooxml::LN_EG_RPrBase_smallCaps == nSprmId ?
+ 4 : 1;
+ }
+ else if(aStyleVal.getValueTypeClass() == uno::TypeClass_FLOAT )
+ {
+ double fDoubleValue = 0;
+ //only in case of awt::FontWeight
+ aStyleVal >>= fDoubleValue;
+ nIntValue = fDoubleValue > 100. ? 0 : 1;
+ }
+ else if((aStyleVal >>= nStyleValue) ||
+ (nStyleValue = static_cast<sal_Int16>(comphelper::getEnumAsINT32(aStyleVal))) >= 0 )
+ {
+ nIntValue = NS_ooxml::LN_EG_RPrBase_smallCaps == nSprmId ?
+ nStyleValue ? 0 : 4 :
+ nStyleValue ? 0 : 1;
+ }
+ else
+ {
+ OSL_FAIL( "what type was it");
+ }
+ }
+
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_bCs:
+ {
+ uno::Any aBold( uno::Any( nIntValue ? awt::FontWeight::BOLD : awt::FontWeight::NORMAL ) );
+
+ rContext->Insert(ePropertyId, aBold );
+ if( nSprmId != NS_ooxml::LN_EG_RPrBase_bCs )
+ rContext->Insert(PROP_CHAR_WEIGHT_ASIAN, aBold );
+
+ if (nSprmId == NS_ooxml::LN_EG_RPrBase_b)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "b", OUString::number(nIntValue));
+ else if (nSprmId == NS_ooxml::LN_EG_RPrBase_bCs)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "bCs", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_i:
+ case NS_ooxml::LN_EG_RPrBase_iCs:
+ {
+ uno::Any aPosture( uno::Any( nIntValue ? awt::FontSlant_ITALIC : awt::FontSlant_NONE ) );
+ rContext->Insert( ePropertyId, aPosture );
+ if (nSprmId != NS_ooxml::LN_EG_RPrBase_iCs)
+ rContext->Insert(PROP_CHAR_POSTURE_ASIAN, aPosture );
+ if (nSprmId == NS_ooxml::LN_EG_RPrBase_i)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "i", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_strike:
+ rContext->Insert(ePropertyId,
+ uno::Any( nIntValue ? awt::FontStrikeout::SINGLE : awt::FontStrikeout::NONE ) );
+ break;
+ case NS_ooxml::LN_EG_RPrBase_dstrike:
+ rContext->Insert(ePropertyId,
+ uno::Any( nIntValue ? awt::FontStrikeout::DOUBLE : awt::FontStrikeout::NONE ) );
+ break;
+ case NS_ooxml::LN_EG_RPrBase_outline:
+ case NS_ooxml::LN_EG_RPrBase_shadow:
+ case NS_ooxml::LN_EG_RPrBase_vanish:
+ case NS_ooxml::LN_EG_RPrBase_webHidden:
+ rContext->Insert(ePropertyId, uno::Any( nIntValue != 0 ));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_smallCaps:
+ // If smallcaps would be just disabled and another casemap is already inserted, don't do anything.
+ if (nIntValue || !rContext->isSet(ePropertyId) )
+ rContext->Insert(ePropertyId, uno::Any( nIntValue ? style::CaseMap::SMALLCAPS : style::CaseMap::NONE));
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "smallCaps", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_caps:
+ rContext->Insert(ePropertyId,
+ uno::Any( nIntValue ? style::CaseMap::UPPERCASE : style::CaseMap::NONE));
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "caps", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_emboss:
+ rContext->Insert(ePropertyId,
+ uno::Any( nIntValue ? awt::FontRelief::EMBOSSED : awt::FontRelief::NONE ));
+ break;
+
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ case NS_ooxml::LN_EG_RPrBase_szCs:
+ {
+ //multiples of half points (12pt == 24)
+ double fVal = double(nIntValue) / 2.;
+ uno::Any aVal( fVal );
+ if( NS_ooxml::LN_EG_RPrBase_szCs == nSprmId )
+ {
+ rContext->Insert( PROP_CHAR_HEIGHT_COMPLEX, aVal );
+ }
+ else
+ {
+ const RubyInfo &aInfo = m_pImpl->GetRubyInfo();
+ if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rt && aInfo.nHps > 0 )
+ {
+ fVal = double(aInfo.nHps) / 2.;
+ aVal <<= fVal;
+ }
+ else if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rubyBase && aInfo.nHpsBaseText > 0 )
+ {
+ fVal = double(aInfo.nHpsBaseText) / 2.;
+ aVal <<= fVal;
+ }
+ //Asian get the same value as Western
+ rContext->Insert( PROP_CHAR_HEIGHT, aVal );
+ rContext->Insert( PROP_CHAR_HEIGHT_ASIAN, aVal );
+ }
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, (nSprmId == NS_ooxml::LN_EG_RPrBase_sz ? OUString("sz") : OUString("szCs")), OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_position:
+ // The spec says 0 is the same as the lack of the value, so don't parse that.
+ if ( nIntValue )
+ {
+ if (!IsStyleSheetImport() && !IsNumberingImport())
+ m_pImpl->deferCharacterProperty( nSprmId, uno::Any( nIntValue ));
+ else if (!m_pImpl->IsDocDefaultsImport())
+ {
+ // For some undocumented reason, MS Word seems to ignore this in docDefaults
+
+ // DON'T FIXME: Truly calculating this for Character Styles will be tricky,
+ // because it depends on the final fontsize - regardless of
+ // where it is set. So at the style level,
+ // the escapement value would need to be grabbagged.
+ // At appendText time the final fontsize needs to be determined, and then
+ // the escapement can be calculated from the grabbag'd half-point value
+ // and directly applied. Yuck.
+ // It seems best to just treat charstyle escapement like
+ // pre-commit e70df84352d3670508a4666c97df44f82c1ce934
+ // which just assigned default values and ignored the actual/given escapement.
+ sal_Int16 nEscapement = nIntValue > 0 ? DFLT_ESC_AUTO_SUPER : DFLT_ESC_AUTO_SUB;
+ sal_Int8 nProp = DFLT_ESC_PROP;
+ rContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( nEscapement ) );
+ rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::Any( nProp ) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_spacing:
+ {
+ //Kerning half point values
+ //TODO: there are two kerning values -
+ // in ww8par6.cxx NS_sprm::LN_CHpsKern is used as boolean AutoKerning
+ sal_Int16 nResult = static_cast<sal_Int16>(ConversionHelper::convertTwipToMM100(nIntValue));
+ if (m_pImpl->IsInComments())
+ {
+ nResult = static_cast<sal_Int16>(nIntValue);
+ }
+ rContext->Insert(PROP_CHAR_CHAR_KERNING, uno::Any(nResult));
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "spacing", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_kern: // auto kerning is bound to a minimum font size in Word - but not in Writer :-(
+ rContext->Insert(PROP_CHAR_AUTO_KERNING, uno::Any( nIntValue != 0 ) );
+ break;
+ case NS_ooxml::LN_EG_RPrBase_w:
+ // ST_TextScale must fall between 1% and 600% according to spec, otherwise resets to 100% according to experience
+ if ((1 <= nIntValue) && (nIntValue <= 600))
+ {
+ rContext->Insert(PROP_CHAR_SCALE_WIDTH,
+ uno::Any( sal_Int16(nIntValue) ));
+ }
+ else
+ {
+ rContext->Insert(PROP_CHAR_SCALE_WIDTH,
+ uno::Any( sal_Int16(100) ));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_imprint:
+ // FontRelief: NONE, EMBOSSED, ENGRAVED
+ rContext->Insert(PROP_CHAR_RELIEF,
+ uno::Any( nIntValue ? awt::FontRelief::ENGRAVED : awt::FontRelief::NONE ));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_effect:
+ // The file-format has many character animations. We have only
+ // one, so we use it always. Suboptimal solution though.
+ if (nIntValue != NS_ooxml::LN_Value_ST_TextEffect_none)
+ rContext->Insert(PROP_CHAR_FLASH, uno::Any( true ));
+ else
+ rContext->Insert(PROP_CHAR_FLASH, uno::Any( false ));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_rtl:
+ break;
+ case NS_ooxml::LN_EG_RPrBase_shd:
+ {
+ //contains fore color, back color and shadow percentage, results in a brush
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellColorHandler = std::make_shared<CellColorHandler>();
+ pCellColorHandler->setOutputFormat( CellColorHandler::Character );
+ pProperties->resolve(*pCellColorHandler);
+ rContext->InsertProps(pCellColorHandler->getProperties().get());
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_SHADING_MARKER, uno::Any(true), true, CHAR_GRAB_BAG );
+ }
+ break;
+ }
+ case NS_ooxml::LN_EG_SectPrContents_type:
+ /* break type
+ 0 - No break
+ 1 - New Column
+ 2 - New page
+ 3 - Even page
+ 4 - odd page
+ */
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ //continuous break only allowed if it is not the only section break
+ SectionPropertyMap* pLastContext = m_pImpl->GetLastSectionContext();
+ if ( nIntValue != NS_ooxml::LN_Value_ST_SectionMark_continuous || pLastContext || m_pImpl->GetParaSectpr() )
+ pSectionContext->SetBreakType( nIntValue );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_titlePg:
+ {
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ pSectionContext->SetTitlePage( nIntValue > 0 );//section has title page
+ }
+ break;
+ case 165:
+ {
+ //page height, rounded to default values, default: 0x3dc0 twip
+ sal_Int32 nHeight = ConversionHelper::convertTwipToMM100( nIntValue );
+ rContext->Insert( PROP_HEIGHT, uno::Any( PaperInfo::sloppyFitPageDimension( nHeight ) ) );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_textDirection:
+ {
+ /* 0 HoriLR 1 Vert TR 2 Vert TR 3 Vert TT 4 HoriLT
+ only 0 and 1 can be imported correctly
+ */
+ text::WritingMode nDirection = text::WritingMode_LR_TB;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
+ nDirection = text::WritingMode_LR_TB;
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr:
+ nDirection = text::WritingMode_TB_RL;
+ break;
+ default:;
+ }
+
+ PropertyMap * pTargetContext = rContext.get();
+
+ if (pSectionContext)
+ {
+ pTargetContext = pSectionContext;
+ }
+
+ pTargetContext->Insert(PROP_WRITING_MODE, uno::Any( sal_Int16(nDirection) ) );
+ }
+ break; // sprmSTextFlow
+ // the following are not part of the official documentation
+ case NS_ooxml::LN_CT_Tabs_tab:
+ resolveSprmProps(*this, rSprm);
+ m_pImpl->IncorporateTabStop(m_pImpl->m_aCurrentTabStop);
+ m_pImpl->m_aCurrentTabStop = DeletableTabStop();
+ break;
+ case NS_ooxml::LN_CT_PPrBase_tabs:
+ {
+ // Initialize tab stop vector from style sheet
+ // fdo#81033: for RTF, a tab stop is inherited from the style if it
+ // is also applied to the paragraph directly, and cleared if it is
+ // not applied to the paragraph directly => don't InitTabStopFromStyle
+ if ( !IsRTFImport() )
+ {
+ uno::Any aValue = m_pImpl->GetPropertyFromParaStyleSheet(PROP_PARA_TAB_STOPS);
+ uno::Sequence< style::TabStop > aStyleTabStops;
+ if(aValue >>= aStyleTabStops)
+ {
+ m_pImpl->InitTabStopFromStyle( aStyleTabStops );
+ }
+ }
+ resolveSprmProps(*this, rSprm);
+ rContext->Insert(PROP_PARA_TAB_STOPS, uno::Any( m_pImpl->GetCurrentTabStopAndClear()));
+ }
+ break;
+
+ case NS_ooxml::LN_CT_DocDefaults_pPrDefault:
+ case NS_ooxml::LN_CT_DocDefaults_rPrDefault:
+ GetStyleSheetTable()->sprm( rSprm );
+ break;
+ case NS_ooxml::LN_EG_RPrBase_bdr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>( true );
+ pProperties->resolve(*pBorderHandler);
+
+ rContext->Insert( PROP_CHAR_TOP_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+ rContext->Insert( PROP_CHAR_BOTTOM_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+ rContext->Insert( PROP_CHAR_LEFT_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+ rContext->Insert( PROP_CHAR_RIGHT_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+
+ rContext->Insert( PROP_CHAR_TOP_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+ rContext->Insert( PROP_CHAR_BOTTOM_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+ rContext->Insert( PROP_CHAR_LEFT_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+ rContext->Insert( PROP_CHAR_RIGHT_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+
+ table::ShadowFormat aFormat;
+ // Word only allows shadows on visible borders
+ if ( pBorderHandler->getShadow() && pBorderHandler->getBorderLine().LineStyle != table::BorderLineStyle::NONE )
+ aFormat = writerfilter::dmapper::PropertyMap::getShadowFromBorder(pBorderHandler->getBorderLine());
+ rContext->Insert(PROP_CHAR_SHADOW_FORMAT, uno::Any(aFormat));
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPr_sectPr:
+ case NS_ooxml::LN_EG_RPrBase_color:
+ case NS_ooxml::LN_EG_RPrBase_rFonts:
+ case NS_ooxml::LN_EG_RPrBase_eastAsianLayout:
+ case NS_ooxml::LN_EG_RPrBase_u:
+ case NS_ooxml::LN_EG_RPrBase_lang:
+ case NS_ooxml::LN_CT_PPrBase_spacing:
+ case NS_ooxml::LN_CT_PPrBase_ind:
+ case NS_ooxml::LN_CT_RPrDefault_rPr:
+ case NS_ooxml::LN_CT_PPrDefault_pPr:
+ case NS_ooxml::LN_CT_Style_pPr:
+ case NS_ooxml::LN_CT_Style_rPr:
+ case NS_ooxml::LN_CT_PPr_rPr:
+ case NS_ooxml::LN_CT_PPrBase_numPr:
+ {
+ bool bTempGrabBag = !m_pImpl->isInteropGrabBagEnabled();
+ if (nSprmId == NS_ooxml::LN_CT_PPr_sectPr)
+ m_pImpl->SetParaSectpr(true);
+ else if (nSprmId == NS_ooxml::LN_EG_RPrBase_color && bTempGrabBag)
+ // if DomainMapper grab bag is not enabled, enable it temporarily
+ m_pImpl->enableInteropGrabBag("TempColorPropsGrabBag");
+ resolveSprmProps(*this, rSprm);
+ if (nSprmId == NS_ooxml::LN_CT_PPrBase_spacing)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "spacing", m_pImpl->m_aSubInteropGrabBag);
+ else if (nSprmId == NS_ooxml::LN_EG_RPrBase_rFonts)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "rFonts", m_pImpl->m_aSubInteropGrabBag);
+ else if (nSprmId == NS_ooxml::LN_EG_RPrBase_lang)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lang", m_pImpl->m_aSubInteropGrabBag);
+ else if (nSprmId == NS_ooxml::LN_EG_RPrBase_color)
+ {
+ for (const auto& rItem : m_pImpl->m_aSubInteropGrabBag)
+ {
+ if (rItem.Name == "val")
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_ORIGINAL_COLOR, rItem.Value, true, CHAR_GRAB_BAG);
+ else if (rItem.Name == "themeColor")
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_COLOR, rItem.Value, true, CHAR_GRAB_BAG);
+ else if (rItem.Name == "themeShade")
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_COLOR_SHADE, rItem.Value, true, CHAR_GRAB_BAG);
+ else if (rItem.Name == "themeTint")
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_COLOR_TINT, rItem.Value, true, CHAR_GRAB_BAG);
+ }
+ if (bTempGrabBag)
+ //disable and clear DomainMapper grab bag if it wasn't enabled before
+ m_pImpl->disableInteropGrabBag();
+
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "color", m_pImpl->m_aSubInteropGrabBag);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_PPrBase_ind)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ind", m_pImpl->m_aSubInteropGrabBag);
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_wordWrap:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "wordWrap", "");
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_footnotePr:
+ case NS_ooxml::LN_EG_SectPrContents_endnotePr:
+ m_pImpl->SetInFootnoteProperties( NS_ooxml::LN_EG_SectPrContents_footnotePr == nSprmId );
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_lnNumType:
+ {
+ resolveSprmProps(*this, rSprm);
+ LineNumberSettings aSettings = m_pImpl->GetLineNumberSettings();
+ m_pImpl->SetLineNumberSettings( aSettings );
+ //apply settings at XLineNumberingProperties
+ try
+ {
+ uno::Reference< text::XLineNumberingProperties > xLineNumberingProperties( m_pImpl->GetTextDocument(), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xLineNumberingPropSet = xLineNumberingProperties->getLineNumberingProperties();
+ if( aSettings.nInterval == 0 )
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_IS_ON ), uno::Any(false) );
+ else
+ {
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_IS_ON ), uno::Any(true) );
+ if( aSettings.nInterval )
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_INTERVAL ), uno::Any(static_cast<sal_Int16>(aSettings.nInterval)) );
+ if( aSettings.nDistance != -1 )
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_DISTANCE ), uno::Any(aSettings.nDistance) );
+ else
+ {
+ // set Auto value (0.5 cm)
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_DISTANCE ), uno::Any(static_cast<sal_Int32>(500)) );
+ if( pSectionContext )
+ pSectionContext->SetdxaLnn( static_cast<sal_Int32>(283) );
+ }
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::Any(aSettings.bRestartAtEachPage) );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_framePr:
+ // Avoid frames if we're inside a structured document tag, would just cause outer tables fail to create.
+ if (!m_pImpl->GetSdt())
+ {
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if( pContext )
+ {
+ // If there is a deferred page break applied to this framed paragraph,
+ // create a dummy paragraph without extra properties,
+ // so that the anchored frame will be on the correct page (similar to shapes).
+ if (pContext->isSet(PROP_BREAK_TYPE))
+ {
+ pContext->Erase(PROP_BREAK_TYPE);
+
+ lcl_startParagraphGroup();
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ lcl_startCharacterGroup();
+ sal_uInt8 const sBreak[] = { 0xd };
+ lcl_text(sBreak, 1);
+ lcl_endCharacterGroup();
+ lcl_endParagraphGroup();
+ }
+
+ ParagraphPropertyMap* pParaContext = dynamic_cast< ParagraphPropertyMap* >( pContext.get() );
+ if (pParaContext)
+ pParaContext->SetFrameMode();
+
+ if (!IsInHeaderFooter())
+ m_pImpl->m_bIsActualParagraphFramed = true;
+ }
+ else
+ {
+ //TODO: What about style sheet import of frame properties
+ }
+ m_pImpl->NewFrameDirection();
+ resolveSprmProps(*this, rSprm);
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_pgSz:
+ {
+ PaperInfo aLetter(PAPER_LETTER);
+ CT_PageSz.w = aLetter.getWidth();
+ CT_PageSz.h = aLetter.getHeight();
+ }
+ CT_PageSz.orient = false;
+ resolveSprmProps(*this, rSprm);
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ if (!m_pImpl->IsAltChunk())
+ {
+ pSectionContext->Insert(PROP_HEIGHT, uno::Any(CT_PageSz.h));
+ }
+ pSectionContext->Insert( PROP_IS_LANDSCAPE, uno::Any( CT_PageSz.orient ));
+ if (!m_pImpl->IsAltChunk())
+ {
+ pSectionContext->Insert(PROP_WIDTH, uno::Any(CT_PageSz.w));
+ }
+ }
+ break;
+
+ case NS_ooxml::LN_EG_SectPrContents_pgMar:
+ m_pImpl->InitPageMargins();
+ resolveSprmProps(*this, rSprm);
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ const PageMar& rPageMar = m_pImpl->GetPageMargins();
+ pSectionContext->SetTopMargin( rPageMar.top );
+ pSectionContext->SetRightMargin( rPageMar.right );
+ pSectionContext->SetBottomMargin( rPageMar.bottom );
+ pSectionContext->SetLeftMargin( rPageMar.left );
+ pSectionContext->SetHeaderTop( rPageMar.header );
+ pSectionContext->SetHeaderBottom( rPageMar.footer );
+ pSectionContext->SetGutterMargin(rPageMar.gutter);
+ }
+ break;
+
+ case NS_ooxml::LN_EG_SectPrContents_cols:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+
+ tools::SvRef< SectionColumnHandler > pSectHdl( new SectionColumnHandler );
+ pProperties->resolve(*pSectHdl);
+ if(pSectionContext && !m_pImpl->isInIndexContext())
+ {
+ sal_Int16 nColumnCount = pSectHdl->GetNum() == 1 ? 0 : pSectHdl->GetNum();
+ if( pSectHdl->IsEqualWidth() )
+ {
+ pSectionContext->SetEvenlySpaced( true );
+ pSectionContext->SetColumnCount( nColumnCount );
+ pSectionContext->SetColumnDistance( pSectHdl->GetSpace() );
+ pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() );
+ }
+ else if( !pSectHdl->GetColumns().empty() )
+ {
+ pSectionContext->SetEvenlySpaced( false );
+ pSectionContext->SetColumnDistance( pSectHdl->GetSpace() );
+ nColumnCount = pSectHdl->GetColumns().size();
+ pSectionContext->SetColumnCount( nColumnCount == 1 ? 0 : nColumnCount );
+ std::vector<Column_>::const_iterator tmpIter = pSectHdl->GetColumns().begin();
+ for (; tmpIter != pSectHdl->GetColumns().end(); ++tmpIter)
+ {
+ pSectionContext->AppendColumnWidth( tmpIter->nWidth );
+ if ((tmpIter != pSectHdl->GetColumns().end() - 1) || (tmpIter->nSpace > 0))
+ pSectionContext->AppendColumnSpacing( tmpIter->nSpace );
+ }
+ pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() );
+ }
+ else if( nColumnCount )
+ {
+ pSectionContext->SetColumnCount( nColumnCount );
+ pSectionContext->SetColumnDistance( pSectHdl->GetSpace() );
+ pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() );
+ }
+ }
+
+ else if ( pSectionContext )
+ {
+ FieldContextPtr pContext = m_pImpl->GetTopFieldContext();
+ uno::Reference< beans::XPropertySet > xTOC = pContext->GetTOC();
+ if( xTOC.is() )
+ {
+ uno::Reference<text::XTextColumns> xTextColumns;
+ xTOC->getPropertyValue(getPropertyName( PROP_TEXT_COLUMNS )) >>= xTextColumns;
+ if (xTextColumns.is())
+ {
+ uno::Reference< beans::XPropertySet > xColumnPropSet( xTextColumns, uno::UNO_QUERY_THROW );
+ xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::Any( pSectHdl->GetSpace() ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TEXT_COLUMNS ), uno::Any( xTextColumns ) );
+ }
+ }
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_docGrid:
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_pgBorders:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties && pSectionContext )
+ {
+ tools::SvRef< PageBordersHandler > pHandler( new PageBordersHandler );
+ pProperties->resolve( *pHandler );
+
+ // Set the borders to the context and apply them to the styles
+ pHandler->SetBorders( pSectionContext );
+ }
+ }
+ break;
+
+ case NS_ooxml::LN_CT_PPrBase_snapToGrid:
+ if (!IsStyleSheetImport()||!m_pImpl->isInteropGrabBagEnabled())
+ {
+ rContext->Insert( PROP_SNAP_TO_GRID, uno::Any(bool(nIntValue)));
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "snapToGrid", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_pStyle:
+ {
+ StyleSheetTablePtr pStyleTable = m_pImpl->GetStyleSheetTable();
+ const OUString sConvertedStyleName = pStyleTable->ConvertStyleName( sStringValue, true );
+ m_pImpl->SetCurrentParaStyleName( sConvertedStyleName );
+ if (m_pImpl->GetTopContext() && m_pImpl->GetTopContextType() != CONTEXT_SECTION)
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_STYLE_NAME, uno::Any( sConvertedStyleName ));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_rStyle:
+ {
+ OUString sConvertedName( m_pImpl->GetStyleSheetTable()->ConvertStyleName( sStringValue, true ) );
+ if (m_pImpl->CheckFootnoteStyle() && m_pImpl->GetFootnoteContext())
+ m_pImpl->SetHasFootnoteStyle(m_pImpl->GetFootnoteContext()->GetFootnoteStyle() == sConvertedName);
+
+ // First check if the style exists in the document.
+ StyleSheetEntryPtr pEntry = m_pImpl->GetStyleSheetTable( )->FindStyleSheetByConvertedStyleName( sConvertedName );
+ bool bExists = pEntry && ( pEntry->nStyleTypeCode == STYLE_TYPE_CHAR );
+ // Add the property if the style exists, but do not add it elements in TOC:
+ // they will receive later another style references from TOC
+ if ( bExists && m_pImpl->GetTopContext() && !m_pImpl->IsInTOC())
+ m_pImpl->GetTopContext()->Insert( PROP_CHAR_STYLE_NAME, uno::Any( sConvertedName ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar: //cell margins
+ {
+ resolveSprmProps(*this, rSprm);//contains LN_CT_TblCellMar_top, LN_CT_TblCellMar_left, LN_CT_TblCellMar_bottom, LN_CT_TblCellMar_right
+ }
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_top:
+ case NS_ooxml::LN_CT_TblCellMar_start:
+ case NS_ooxml::LN_CT_TblCellMar_left:
+ case NS_ooxml::LN_CT_TblCellMar_bottom:
+ case NS_ooxml::LN_CT_TblCellMar_end:
+ case NS_ooxml::LN_CT_TblCellMar_right:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ sal_Int32 nMeasureValue = pMeasureHandler->getMeasureValue();
+ PropertyIds eId = META_PROP_CELL_MAR_TOP;
+ bool rtl = false; // TODO
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_TblCellMar_top:
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_start:
+ eId = rtl ? META_PROP_CELL_MAR_RIGHT : META_PROP_CELL_MAR_LEFT;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_left:
+ eId = META_PROP_CELL_MAR_LEFT;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_bottom:
+ eId = META_PROP_CELL_MAR_BOTTOM;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_end:
+ eId = rtl ? META_PROP_CELL_MAR_LEFT : META_PROP_CELL_MAR_RIGHT;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_right:
+ eId = META_PROP_CELL_MAR_RIGHT;
+ break;
+ default:;
+ }
+ rContext->Insert( eId, uno::Any(nMeasureValue), false);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_noProof: // no grammar and spell checking, unsupported
+ break;
+ case NS_ooxml::LN_anchor_anchor: // at_character drawing
+ case NS_ooxml::LN_inline_inline: // as_character drawing
+ {
+ if ( m_pImpl->IsDiscardHeaderFooter() )
+ break;
+ //tdf112342: Break before images as well, if there are page break
+ if (m_pImpl->isBreakDeferred(BreakType::PAGE_BREAK))
+ {
+ m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)
+ ->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ m_pImpl->clearDeferredBreak(PAGE_BREAK);
+ }
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ GraphicImportType eGraphicType =
+ (NS_ooxml::LN_anchor_anchor ==
+ sal::static_int_cast<Id>(nSprmId)) ?
+ IMPORT_AS_DETECTED_ANCHOR :
+ IMPORT_AS_DETECTED_INLINE;
+ GraphicImportPtr pGraphicImport =
+ m_pImpl->GetGraphicImport(eGraphicType);
+ pProperties->resolve(*pGraphicImport);
+ m_pImpl->ImportGraphic(pProperties, eGraphicType);
+ if( !pGraphicImport->IsGraphic() )
+ {
+ m_pImpl->ResetGraphicImport();
+ // todo: It's a shape, now start shape import
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_vertAlign:
+ {
+ sal_Int16 nEscapement = 0;
+ sal_Int8 nProp = DFLT_ESC_PROP;
+ if ( sStringValue == "superscript" )
+ nEscapement = DFLT_ESC_AUTO_SUPER;
+ else if ( sStringValue == "subscript" )
+ nEscapement = DFLT_ESC_AUTO_SUB;
+ else
+ nProp = 100;
+
+ rContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( nEscapement ) );
+ rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::Any( nProp ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_FtnProps_pos:
+ //footnotes in word can be at page end or beneath text - writer supports only the first
+ //endnotes in word can be at section end or document end - writer supports only the latter
+ // -> so this property can be ignored
+ break;
+ case NS_ooxml::LN_CT_FtnProps_numFmt:
+ case NS_ooxml::LN_CT_EdnProps_numFmt:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_FtnEdnNumProps_numStart:
+ case NS_ooxml::LN_EG_FtnEdnNumProps_numRestart:
+ {
+ try
+ {
+ uno::Reference< beans::XPropertySet > xFtnEdnSettings;
+ if( m_pImpl->IsInFootnoteProperties() )
+ {
+ uno::Reference< text::XFootnotesSupplier> xFootnotesSupplier( m_pImpl->GetTextDocument(), uno::UNO_QUERY );
+ if (xFootnotesSupplier.is())
+ xFtnEdnSettings = xFootnotesSupplier->getFootnoteSettings();
+ }
+ else
+ {
+ uno::Reference< text::XEndnotesSupplier> xEndnotesSupplier( m_pImpl->GetTextDocument(), uno::UNO_QUERY );
+ if (xEndnotesSupplier.is())
+ xFtnEdnSettings = xEndnotesSupplier->getEndnoteSettings();
+ }
+ if( NS_ooxml::LN_EG_FtnEdnNumProps_numStart == nSprmId && xFtnEdnSettings.is())
+ {
+ xFtnEdnSettings->setPropertyValue(
+ getPropertyName( PROP_START_AT),
+ uno::Any( sal_Int16( nIntValue - 1 )));
+ }
+ else if( NS_ooxml::LN_EG_FtnEdnNumProps_numRestart == nSprmId && xFtnEdnSettings.is())
+ {
+ sal_Int16 nFootnoteCounting = 0;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_RestartNumber_continuous: nFootnoteCounting = text::FootnoteNumbering::PER_DOCUMENT; break;
+ case NS_ooxml::LN_Value_ST_RestartNumber_eachPage: nFootnoteCounting = text::FootnoteNumbering::PER_PAGE; break;
+ case NS_ooxml::LN_Value_ST_RestartNumber_eachSect: nFootnoteCounting = text::FootnoteNumbering::PER_CHAPTER; break;
+ default: break;
+ }
+ xFtnEdnSettings->setPropertyValue(
+ getPropertyName( PROP_FOOTNOTE_COUNTING ),
+ uno::Any( nFootnoteCounting ));
+ }
+ else if (xFtnEdnSettings.is())
+ {
+ sal_Int16 nNumType = ConversionHelper::ConvertNumberingType( nIntValue );
+ xFtnEdnSettings->setPropertyValue(
+ getPropertyName( PROP_NUMBERING_TYPE),
+ uno::Any( nNumType ));
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveFromRangeStart:
+ m_pImpl->SetMoveBookmark(/*bIsFrom=*/true);
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().setMoved( getPropertyName(PROP_TABLE_ROW_DELETE) );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveToRangeStart:
+ m_pImpl->SetMoveBookmark(/*bIsFrom=*/false);
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().setMoved( getPropertyName(PROP_TABLE_ROW_INSERT) );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveFromRangeEnd:
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveToRangeEnd:
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().setMoved( OUString() );
+ break;
+ case NS_ooxml::LN_CT_ParaRPr_moveFrom:
+ case NS_ooxml::LN_CT_ParaRPr_moveTo:
+ m_pImpl->StartParaMarkerMove( );
+ break;
+ case NS_ooxml::LN_paratrackchange:
+ m_pImpl->StartParaMarkerChange( );
+ [[fallthrough]];
+ case NS_ooxml::LN_CT_PPr_pPrChange:
+ case NS_ooxml::LN_CT_ParaRPr_rPrChange:
+ case NS_ooxml::LN_trackchange:
+ case NS_ooxml::LN_EG_RPrContent_rPrChange:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlDelRangeStart:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlDelRangeEnd:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveFromRangeStart:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveFromRangeEnd:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveToRangeStart:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveToRangeEnd:
+ {
+ HandleRedline( rSprm );
+ }
+ break;
+ case NS_ooxml::LN_endtrackchange:
+ m_pImpl->RemoveTopRedline();
+ break;
+ case NS_ooxml::LN_CT_RPrChange_rPr:
+ {
+ // Push all the current 'Character' properties to the stack, so that we don't store them
+ // as 'tracked changes' by mistake
+ m_pImpl->PushProperties(CONTEXT_CHARACTER);
+
+ // Resolve all the properties that are under the 'rPrChange'->'rPr' XML node
+ resolveSprmProps(*this, rSprm );
+
+ // Get all the properties that were processed in the 'rPrChange'->'rPr' XML node
+ uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
+
+ // Pop back out the character properties that were on the run
+ m_pImpl->PopProperties(CONTEXT_CHARACTER);
+
+ // Store these properties in the current redline object (do it after the PopProperties() above, since
+ // otherwise it'd be stored in the content dropped there).
+ m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrChange_pPr:
+ {
+ // Push all the current 'Paragraph' properties to the stack, so that we don't store them
+ // as 'tracked changes' by mistake
+ m_pImpl->PushProperties(CONTEXT_PARAGRAPH);
+
+ // Resolve all the properties that are under the 'pPrChange'->'pPr' XML node
+ resolveSprmProps(*this, rSprm );
+
+ // Get all the properties that were processed in the 'pPrChange'->'pPr' XML node
+ uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
+
+ // Pop back out the character properties that were on the run
+ m_pImpl->PopProperties(CONTEXT_PARAGRAPH);
+
+ // Store these properties in the current redline object (do it after the PopProperties() above, since
+ // otherwise it'd be stored in the content dropped there).
+ m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
+ }
+ break;
+ case NS_ooxml::LN_object:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pOLEHandler = std::make_shared<OLEHandler>(*this);
+ pProperties->resolve(*pOLEHandler);
+ if ( pOLEHandler->isOLEObject( ) )
+ {
+ OUString sStreamName = pOLEHandler->copyOLEOStream( m_pImpl->GetTextDocument() );
+ if( !sStreamName.isEmpty() )
+ {
+ m_pImpl->appendOLE( sStreamName, pOLEHandler );
+ }
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_HdrFtrReferences_headerReference: // header reference - not needed
+ case NS_ooxml::LN_EG_HdrFtrReferences_footerReference: // footer reference - not needed
+ break;
+ case NS_ooxml::LN_EG_RPrBase_snapToGrid: // "Use document grid settings for inter-paragraph spacing"
+ break;
+ case NS_ooxml::LN_CT_PPrBase_contextualSpacing:
+ rContext->Insert(PROP_PARA_CONTEXT_MARGIN, uno::Any( nIntValue != 0 ));
+ break;
+ case NS_ooxml::LN_CT_PPrBase_mirrorIndents: // mirrorIndents
+ rContext->Insert(PROP_MIRROR_INDENTS, uno::Any( nIntValue != 0 ), true, PARA_GRAB_BAG);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_formProt: //section protection
+ {
+ if( pSectionContext )
+ pSectionContext->Insert( PROP_IS_PROTECTED, uno::Any( bool(nIntValue) ) );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_vAlign:
+ {
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ {
+ drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_VerticalJc_center: //92367
+ nVA = drawing::TextVerticalAdjust_CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_both: //92368 - justify
+ nVA = drawing::TextVerticalAdjust_BLOCK;
+ break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_bottom: //92369
+ nVA = drawing::TextVerticalAdjust_BOTTOM;
+ break;
+ default:
+ break;
+ }
+ pSectionContext->Insert( PROP_TEXT_VERTICAL_ADJUST, uno::Any( nVA ), true, PARA_GRAB_BAG );
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_fitText:
+ break;
+ case NS_ooxml::LN_ffdata:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ FFDataHandler::Pointer_t pFFDataHandler(new FFDataHandler());
+
+ pProperties->resolve(*pFFDataHandler);
+ m_pImpl->SetFieldFFData(pFFDataHandler);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_dropDownList:
+ case NS_ooxml::LN_CT_SdtPr_comboBox:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::dropDown);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDropDownList_listItem:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+
+ size_t nDropDownDisplayTexts = m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().size();
+ size_t nDropDownItems = m_pImpl->m_pSdtHelper->getDropDownItems().size();
+
+ if (pProperties)
+ pProperties->resolve(*this);
+
+ if (m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().size() != nDropDownDisplayTexts + 1)
+ {
+ // w:displayText="..." is optional, add empty value if it was not provided.
+ m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().push_back(OUString());
+ }
+ if (m_pImpl->m_pSdtHelper->getDropDownItems().size() != nDropDownItems + 1)
+ {
+ // w:value="..." is optional, add empty value if it was not provided.
+ m_pImpl->m_pSdtHelper->getDropDownItems().push_back(OUString());
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_placeholder:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ break;
+ case NS_ooxml::LN_CT_SdtPr_date:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::datePicker);
+ resolveSprmProps(*this, rSprm);
+ m_pImpl->m_pSdtHelper->setDateFieldStartRange(GetCurrentTextRange()->getEnd());
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_dateFormat:
+ {
+ m_pImpl->m_pSdtHelper->getDateFormat().append(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_storeMappedDataAs:
+ {
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_calendar:
+ {
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_lid:
+ {
+ m_pImpl->m_pSdtHelper->getLocale().append(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_text:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ enableInteropGrabBag("ooxml:CT_SdtPr_text");
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_showingPlcHdr:
+ {
+ m_pImpl->m_pSdtHelper->SetShowingPlcHdr();
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_dataBinding:
+ case NS_ooxml::LN_CT_SdtPr_equation:
+ case NS_ooxml::LN_CT_SdtPr_checkbox:
+ case NS_ooxml::LN_CT_SdtPr_docPartObj:
+ case NS_ooxml::LN_CT_SdtPr_docPartList:
+ case NS_ooxml::LN_CT_SdtPr_picture:
+ case NS_ooxml::LN_CT_SdtPr_citation:
+ case NS_ooxml::LN_CT_SdtPr_group:
+ case NS_ooxml::LN_CT_SdtPr_id:
+ case NS_ooxml::LN_CT_SdtPr_alias:
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart:
+ case NS_ooxml::LN_CT_SdtPr_color:
+ {
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_color)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::checkBox);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_SdtPr_picture)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::picture);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_SdtPr_date)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::datePicker);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+ }
+
+ // this is an unsupported SDT property, create a grab bag for it
+ OUString sName;
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_SdtPr_dataBinding: sName = "ooxml:CT_SdtPr_dataBinding"; break;
+ case NS_ooxml::LN_CT_SdtPr_equation: sName = "ooxml:CT_SdtPr_equation"; break;
+ case NS_ooxml::LN_CT_SdtPr_checkbox: sName = "ooxml:CT_SdtPr_checkbox"; break;
+ case NS_ooxml::LN_CT_SdtPr_docPartObj: sName = "ooxml:CT_SdtPr_docPartObj"; break;
+ case NS_ooxml::LN_CT_SdtPr_docPartList: sName = "ooxml:CT_SdtPr_docPartList"; break;
+ case NS_ooxml::LN_CT_SdtPr_picture: sName = "ooxml:CT_SdtPr_picture"; break;
+ case NS_ooxml::LN_CT_SdtPr_citation: sName = "ooxml:CT_SdtPr_citation"; break;
+ case NS_ooxml::LN_CT_SdtPr_group: sName = "ooxml:CT_SdtPr_group"; break;
+ case NS_ooxml::LN_CT_SdtPr_id: sName = "ooxml:CT_SdtPr_id"; break;
+ case NS_ooxml::LN_CT_SdtPr_alias: sName = "ooxml:CT_SdtPr_alias"; break;
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart: sName = "ooxml:CT_SdtPlaceholder_docPart"; break;
+ case NS_ooxml::LN_CT_SdtPr_color: sName = "ooxml:CT_SdtPr_color"; break;
+ default: assert(false);
+ };
+ if (
+ nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartObj ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartList ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_picture ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_citation)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::unsupported);
+ }
+ enableInteropGrabBag(sName);
+
+ // process subitems
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_alias)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = sName;
+ aValue.Value <<= sStringValue;
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(aValue);
+ }
+ else
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
+ m_pImpl->m_pSdtHelper->setOutsideAParagraph(m_pImpl->IsOutsideAParagraph());
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtCheckbox_checked:
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ // nIntValue is not just 0 or 1, because we're in the w14 namespace's ST_OnOff.
+ if (nIntValue == NS_ooxml::LN_ST_OnOff_true || nIntValue == NS_ooxml::LN_ST_OnOff_1)
+ {
+ m_pImpl->m_pSdtHelper->SetChecked();
+ }
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtCheckbox_checked",
+ TextEffectsHandler::getOnOffString(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtCheckbox_checkedState:
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ m_pImpl->m_pSdtHelper->SetCheckedState(OUString(sal_Unicode(sStringValue.toInt32(16))));
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtCheckbox_checkedState",
+ sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtCheckbox_uncheckedState:
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ m_pImpl->m_pSdtHelper->SetUncheckedState(
+ OUString(sal_Unicode(sStringValue.toInt32(16))));
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag,
+ "ooxml:CT_SdtCheckbox_uncheckedState", sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDocPart_docPartGallery:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtDocPart_docPartGallery", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtDocPart_docPartCategory:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtDocPart_docPartCategory", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtDocPart_docPartUnique:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtDocPart_docPartUnique", sStringValue);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_pgNumType:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_tblStart:
+ {
+ if (m_pImpl->hasTableManager())
+ {
+ bool bTableStartsAtCellStart = m_pImpl->m_nTableDepth > 0 && m_pImpl->m_nTableCellDepth > m_pImpl->m_nLastTableCellParagraphDepth + 1;
+ m_pImpl->getTableManager().setTableStartsAtCellStart(bTableStartsAtCellStart);
+ }
+ /*
+ * Hack for Importing Section Properties
+ * LO is not able to import section properties if first element in the
+ * section is a table. So in case first element is a table add a dummy para
+ * and remove it again when lcl_endSectionGroup is called
+ */
+ if(m_pImpl->m_nTableDepth == 0 && m_pImpl->GetIsFirstParagraphInSection()
+ && !m_pImpl->GetIsDummyParaAddedForTableInSection() && !m_pImpl->GetIsTextFrameInserted()
+ && !IsInHeaderFooter())
+ {
+ m_pImpl->AddDummyParaForTableInSection();
+ }
+
+ // if first paragraph style in table has break-before-page, transfer that setting to the table itself.
+ if( m_pImpl->m_nTableDepth == 0 )
+ {
+ const uno::Any aBreakType(style::BreakType_PAGE_BEFORE);
+ const PropertyMapPtr pParagraphProps = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if( pParagraphProps && pParagraphProps->isSet(PROP_PARA_STYLE_NAME) )
+ {
+ StyleSheetEntryPtr pStyle;
+ OUString sStyleName;
+ pParagraphProps->getProperty(PROP_PARA_STYLE_NAME)->second >>= sStyleName;
+ if( !sStyleName.isEmpty() && GetStyleSheetTable() )
+ pStyle = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( sStyleName );
+
+ if( pStyle && pStyle->pProperties
+ && pStyle->pProperties->isSet(PROP_BREAK_TYPE)
+ && pStyle->pProperties->getProperty(PROP_BREAK_TYPE)->second == aBreakType )
+ {
+ pParagraphProps->Insert(PROP_BREAK_TYPE, aBreakType);
+ }
+ }
+ }
+
+ m_pImpl->m_nTableDepth++;
+ }
+ break;
+ case NS_ooxml::LN_tblEnd:
+ m_pImpl->m_nTableDepth--;
+ break;
+ case NS_ooxml::LN_tcStart:
+ m_pImpl->m_nTableCellDepth++;
+ break;
+ case NS_ooxml::LN_tcEnd:
+ m_pImpl->m_nTableCellDepth--;
+ m_pImpl->m_nLastTableCellParagraphDepth = 0;
+ break;
+ case NS_ooxml::LN_glow_glow:
+ case NS_ooxml::LN_shadow_shadow:
+ case NS_ooxml::LN_reflection_reflection:
+ case NS_ooxml::LN_textOutline_textOutline:
+ case NS_ooxml::LN_textFill_textFill:
+ case NS_ooxml::LN_scene3d_scene3d:
+ case NS_ooxml::LN_props3d_props3d:
+ case NS_ooxml::LN_ligatures_ligatures:
+ case NS_ooxml::LN_numForm_numForm:
+ case NS_ooxml::LN_numSpacing_numSpacing:
+ case NS_ooxml::LN_stylisticSets_stylisticSets:
+ case NS_ooxml::LN_cntxtAlts_cntxtAlts:
+ {
+ tools::SvRef<TextEffectsHandler> pTextEffectsHandlerPtr( new TextEffectsHandler(nSprmId) );
+ std::optional<PropertyIds> aPropertyId = pTextEffectsHandlerPtr->getGrabBagPropertyId();
+ if(aPropertyId)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*pTextEffectsHandlerPtr);
+
+ beans::PropertyValue aGrabBag = pTextEffectsHandlerPtr->getInteropGrabBag();
+ rContext->Insert(*aPropertyId, uno::Any(aGrabBag), true, CHAR_GRAB_BAG);
+
+ sal_Int16 nTransparency = TextEffectsHandler::GetTextFillSolidFillAlpha(aGrabBag);
+ if (nTransparency != 0)
+ {
+ rContext->Insert(PROP_CHAR_TRANSPARENCE, uno::Any(nTransparency));
+ }
+ }
+ else if (nSprmId == NS_ooxml::LN_cntxtAlts_cntxtAlts)
+ {
+ pTextEffectsHandlerPtr->lcl_sprm(rSprm);
+ beans::PropertyValue aGrabBag = pTextEffectsHandlerPtr->getInteropGrabBag();
+ rContext->Insert(*aPropertyId, uno::Any(aGrabBag), true, CHAR_GRAB_BAG);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_rPr:
+ {
+ // Make sure properties from a previous SDT are not merged with the current ones.
+ m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblLook:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ m_pImpl->getTableManager().finishTableLook();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_cnfStyle:
+ {
+ m_pImpl->enableInteropGrabBag("cnfStyle");
+ resolveSprmProps(*this, rSprm);
+
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_ROW_CNF_STYLE, uno::Any(comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag)), true, ROW_GRAB_BAG);
+ m_pImpl->getTableManager().insertRowProps(pPropMap);
+
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_cnfStyle:
+ {
+ m_pImpl->enableInteropGrabBag("cnfStyle");
+ resolveSprmProps(*this, rSprm);
+
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_CELL_CNF_STYLE, uno::Any(comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag)), true, CELL_GRAB_BAG);
+ m_pImpl->getTableManager().cellProps(pPropMap);
+
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_cnfStyle:
+ {
+ m_pImpl->enableInteropGrabBag("cnfStyle");
+ resolveSprmProps(*this, rSprm);
+ rContext->Insert(PROP_PARA_CNF_STYLE, uno::Any(comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag)), true, PARA_GRAB_BAG);
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_EG_RunInnerContent_sym:
+ {
+ resolveSprmProps(*this, rSprm);
+ SymbolData aSymbolData = m_pImpl->GetSymbolData();
+ uno::Any aVal( aSymbolData.sFont );
+ auto xFootnote = rContext->GetFootnote();
+ if (!xFootnote.is() && m_pImpl->IsInCustomFootnote())
+ xFootnote = m_pImpl->GetFootnoteContext()->GetFootnote();
+ if (xFootnote.is())
+ {
+ // DOCX can have different labels for the footnote reference and the footnote area.
+ // This skips the one from the footnote area and just uses the reference one.
+ if (!m_pImpl->IsInFootOrEndnote())
+ {
+ auto xAnchorRange = xFootnote->getAnchor();
+ auto xAnchorCursor(xAnchorRange->getText()->createTextCursorByRange(xAnchorRange));
+
+ // append a dummy character, so the following properties will be set as
+ // as SwpHints::SwTextAttr instead of the SwAttrSet of the paragraph,
+ // which would be removed by SwXText::Impl::finishOrAppendParagraph
+ xAnchorCursor->collapseToEnd();
+ uno::Reference<text::XTextRange> xHackRange(xAnchorCursor, uno::UNO_QUERY);
+ xHackRange->setString("x");
+
+ uno::Reference<beans::XPropertySet> xAnchorProps(xAnchorRange, uno::UNO_QUERY);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), aVal);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_ASIAN), aVal);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_COMPLEX), aVal);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_CHAR_SET), uno::Any(awt::CharSet::SYMBOL));
+
+ // remove the dummy char
+ xHackRange->setString("");
+
+ OUString sLabel = xFootnote->getLabel() + OUStringChar(aSymbolData.cSymbol);
+ xFootnote->setLabel(sLabel);
+ }
+ }
+ else //it's a _real_ symbol
+ {
+ rContext->Insert(PROP_CHAR_FONT_NAME, aVal);
+ rContext->Insert(PROP_CHAR_FONT_NAME_ASIAN, aVal);
+ rContext->Insert(PROP_CHAR_FONT_NAME_COMPLEX, aVal);
+ rContext->Insert(PROP_CHAR_FONT_CHAR_SET, uno::Any(awt::CharSet::SYMBOL));
+ utext( reinterpret_cast < const sal_uInt8 * >( &(aSymbolData.cSymbol) ), 1 );
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RunInnerContent_ruby:
+ {
+ RubyInfo aInfo ;
+ m_pImpl->SetRubyInfo(aInfo);
+ }
+ break;
+ case NS_ooxml::LN_CT_RubyPr:
+ case NS_ooxml::LN_CT_Ruby_rt:
+ case NS_ooxml::LN_CT_Ruby_rubyBase:
+ {
+ m_pImpl->SetRubySprmId(nSprmId);
+ if (nSprmId == NS_ooxml::LN_CT_RubyPr)
+ {
+ resolveSprmProps(*this, rSprm);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RubyContent_r:
+ {
+ const RubyInfo & aInfo = m_pImpl->GetRubyInfo();
+ if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rubyBase)
+ {
+ rContext->Insert(PROP_RUBY_TEXT, uno::Any(aInfo.sRubyText));
+ rContext->Insert(PROP_RUBY_STYLE, uno::Any(aInfo.sRubyStyle));
+ rContext->Insert(PROP_RUBY_ADJUST, uno::Any(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign))));
+ if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical )
+ rContext->Insert(PROP_RUBY_POSITION, uno::Any(css::text::RubyPosition::INTER_CHARACTER));
+
+ m_pImpl->SetRubySprmId(0);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_RubyPr_rubyAlign:
+ case NS_ooxml::LN_CT_RubyPr_hps:
+ case NS_ooxml::LN_CT_RubyPr_hpsBaseText:
+ {
+ RubyInfo aInfo = m_pImpl->GetRubyInfo();
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_RubyPr_rubyAlign:
+ aInfo.nRubyAlign = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_RubyPr_hps:
+ aInfo.nHps= nIntValue;
+ break;
+ case NS_ooxml::LN_CT_RubyPr_hpsBaseText:
+ aInfo.nHpsBaseText = nIntValue;
+ break;
+ }
+ m_pImpl->SetRubyInfo(aInfo);
+ }
+ break;
+ case NS_ooxml::LN_CT_SmartTagRun_smartTagPr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties && m_pImpl->GetTopContextType() == CONTEXT_PARAGRAPH)
+ pProperties->resolve(m_pImpl->getSmartTagHandler());
+ }
+ break;
+ case NS_ooxml::LN_CT_DocPartPr_name:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_DocPartPr_category:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_DocPartCategory_gallery:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("unhandled");
+ TagLogger::getInstance().attribute("id", nSprmId);
+ TagLogger::getInstance().attribute("name", rSprm.getName());
+ TagLogger::getInstance().endElement();
+#endif
+ }
+ }
+}
+
+void DomainMapper::processDeferredCharacterProperties( const std::map< sal_Int32, uno::Any >& deferredCharacterProperties )
+{
+ assert( m_pImpl->GetTopContextType() == CONTEXT_CHARACTER );
+ PropertyMapPtr rContext = m_pImpl->GetTopContext();
+ for( const auto& rProp : deferredCharacterProperties )
+ {
+ sal_Int32 Id = rProp.first;
+ sal_Int32 nIntValue = 0;
+ OUString sStringValue;
+ rProp.second >>= nIntValue;
+ rProp.second >>= sStringValue;
+ switch( Id )
+ {
+ case NS_ooxml::LN_EG_RPrBase_position:
+ {
+ double nEscapement = 0;
+ sal_Int8 nProp = 0;
+ if ( nIntValue )
+ {
+ nProp = 100;
+ double fFontSize = 0;
+ m_pImpl->GetAnyProperty(PROP_CHAR_HEIGHT, rContext) >>= fFontSize;
+ if ( fFontSize )
+ // nIntValue is in half-points, fontsize is in points, escapement is a percentage.
+ nEscapement = round( nIntValue/2.0 / fFontSize * 100 );
+ else
+ nEscapement = nIntValue > 0 ? DFLT_ESC_SUPER : DFLT_ESC_SUB;
+ }
+ if ( nEscapement > MAX_ESC_POS )
+ nEscapement = MAX_ESC_POS;
+ else if ( nEscapement < -MAX_ESC_POS )
+ nEscapement = -MAX_ESC_POS;
+
+ rContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( sal_Int16(nEscapement) ) );
+ rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::Any( nProp ) );
+ }
+ break;
+ default:
+ SAL_WARN( "writerfilter", "Unhandled property in processDeferredCharacterProperty()" );
+ break;
+ }
+ }
+}
+
+void DomainMapper::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+ ref->resolve(*this);
+}
+
+void DomainMapper::data(const sal_uInt8* /*buf*/, size_t /*len*/)
+{
+}
+
+void DomainMapper::lcl_startSectionGroup()
+{
+ if (!m_pImpl->isInIndexContext() && !m_pImpl->isInBibliographyContext())
+ {
+ m_pImpl->PushProperties(CONTEXT_SECTION);
+ }
+ m_pImpl->SetIsFirstParagraphInSection(true);
+ m_pImpl->SetIsFirstParagraphInSectionAfterRedline(true);
+}
+
+void DomainMapper::lcl_endSectionGroup()
+{
+ if (m_pImpl->isInIndexContext() || m_pImpl->isInBibliographyContext())
+ return;
+
+ m_pImpl->CheckUnregisteredFrameConversion();
+ m_pImpl->ExecuteFrameConversion();
+ // When pasting, it's fine to not have any paragraph inside the document at all.
+ if (m_pImpl->GetIsFirstParagraphInSection() && m_pImpl->IsNewDoc())
+ {
+ // This section has no paragraph at all (e.g. they are all actually in a frame).
+ // If this section has a page break, there would be nothing to apply to the page
+ // style, so force a dummy paragraph.
+ lcl_startParagraphGroup();
+ lcl_startCharacterGroup();
+ sal_uInt8 const sBreak[] = { 0xd };
+ lcl_text(sBreak, 1);
+ lcl_endCharacterGroup();
+ lcl_endParagraphGroup();
+ }
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_SECTION);
+ SectionPropertyMap* pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ pSectionContext->CloseSectionGroup( *m_pImpl );
+ // Remove the dummy paragraph if added for
+ // handling the section properties if section starts with a table
+ if (m_pImpl->GetIsDummyParaAddedForTableInSection())
+ m_pImpl->RemoveDummyParaForTableInSection();
+ }
+ m_pImpl->SetIsTextFrameInserted( false );
+ m_pImpl->PopProperties(CONTEXT_SECTION);
+}
+
+void DomainMapper::lcl_startParagraphGroup()
+{
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().startParagraphGroup();
+ /*
+ * Add new para properties only if paragraph is not split
+ * or the top context is not of paragraph properties
+ * Set mbIsSplitPara to false as it has been handled
+ */
+ if (!mbIsSplitPara)
+ m_pImpl->PushProperties(CONTEXT_PARAGRAPH);
+ mbIsSplitPara = false;
+ if (m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH) != m_pImpl->GetTopContext())
+ m_pImpl->PushProperties(CONTEXT_PARAGRAPH);
+
+ if (m_pImpl->GetTopContext())
+ {
+ if (!m_pImpl->IsInShape())
+ {
+ const OUString& sDefaultParaStyle = m_pImpl->GetDefaultParaStyleName();
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_STYLE_NAME, uno::Any( sDefaultParaStyle ) );
+ m_pImpl->SetCurrentParaStyleName( sDefaultParaStyle );
+
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ mbWasShapeInPara = false;
+ }
+
+ if (m_pImpl->isParaSdtEndDeferred())
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_SDT_END_BEFORE, uno::Any(true), true, PARA_GRAB_BAG);
+ }
+ m_pImpl->SetIsFirstRun(true);
+ m_pImpl->SetIsOutsideAParagraph(false);
+ if (!m_pImpl->IsInShape())
+ m_pImpl->clearDeferredBreaks();
+ m_pImpl->setParaSdtEndDeferred(false);
+}
+
+void DomainMapper::lcl_endParagraphGroup()
+{
+ if (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ if (m_pImpl->GetIsLastParagraphInSection())
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+ }
+
+ m_pImpl->PopProperties(CONTEXT_PARAGRAPH);
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().endParagraphGroup();
+ //frame conversion has to be executed after table conversion
+ m_pImpl->ExecuteFrameConversion();
+ m_pImpl->SetIsOutsideAParagraph(true);
+}
+
+void DomainMapper::markLastParagraphInSection( )
+{
+ m_pImpl->SetIsLastParagraphInSection( true );
+}
+
+void DomainMapper::markLastSectionGroup( )
+{
+ m_pImpl->SetIsLastSectionGroup( true );
+}
+
+void DomainMapper::lcl_startShape(uno::Reference<drawing::XShape> const& xShape)
+{
+ assert(xShape.is());
+
+ m_pImpl->AttachTextBoxContentToShape(xShape);
+ if (m_pImpl->GetTopContext())
+ {
+ // If there is a deferred page break, handle it now, so that the
+ // started shape will be on the correct page.
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(PAGE_BREAK);
+ lcl_startCharacterGroup();
+ sal_uInt8 const sBreak[] = { 0xd };
+ lcl_text(sBreak, 1);
+ lcl_endCharacterGroup();
+ lcl_endParagraphGroup();
+ lcl_startParagraphGroup();
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ }
+ m_pImpl->PushShapeContext( xShape );
+ lcl_startParagraphGroup();
+ }
+ else
+ {
+ // No context? Then this image should not appear directly inside the
+ // document, just save it for later usage.
+ m_pImpl->PushPendingShape(xShape);
+ }
+
+ m_pImpl->SetIsFirstParagraphInShape(true);
+ mbWasShapeInPara = true;
+}
+
+void DomainMapper::lcl_endShape( )
+{
+ if (!m_pImpl->GetTopContext())
+ return;
+
+ // End the current table, if there are any. Otherwise the unavoidable
+ // empty paragraph at the end of the shape text will cause problems: if
+ // the shape text ends with a table, the extra paragraph will be
+ // handled as an additional row of the ending table.
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().endTable();
+
+ lcl_endParagraphGroup();
+ m_pImpl->PopShapeContext( );
+ // A shape is always inside a paragraph (anchored or inline).
+ m_pImpl->SetIsOutsideAParagraph(false);
+}
+
+void DomainMapper::lcl_startTextBoxContent()
+{
+ m_pImpl->PushTextBoxContent();
+}
+
+void DomainMapper::lcl_endTextBoxContent()
+{
+ m_pImpl->PopTextBoxContent();
+}
+
+void DomainMapper::PushStyleSheetProperties( const PropertyMapPtr& pStyleProperties, bool bAffectTableMngr )
+{
+ m_pImpl->PushStyleProperties( pStyleProperties );
+ if ( bAffectTableMngr )
+ m_pImpl->getTableManager( ).SetStyleProperties( pStyleProperties );
+}
+
+void DomainMapper::PopStyleSheetProperties( bool bAffectTableMngr )
+{
+ m_pImpl->PopProperties( CONTEXT_STYLESHEET );
+ if ( bAffectTableMngr )
+ {
+ PropertyMapPtr emptyPtr;
+ m_pImpl->getTableManager( ).SetStyleProperties( emptyPtr );
+ }
+}
+
+void DomainMapper::PushListProperties( const ::tools::SvRef<PropertyMap>& pListProperties )
+{
+ m_pImpl->PushListProperties( pListProperties );
+}
+
+void DomainMapper::PopListProperties()
+{
+ m_pImpl->PopProperties( CONTEXT_LIST );
+}
+
+void DomainMapper::lcl_startCharacterGroup()
+{
+ m_pImpl->PushProperties(CONTEXT_CHARACTER);
+ if (m_pImpl->isSdtEndDeferred())
+ {
+ // Fields have an empty character group before the real one, so don't
+ // call setSdtEndDeferred(false) here, that will happen only in lcl_utext().
+ m_pImpl->GetTopContext()->Insert(PROP_SDT_END_BEFORE, uno::Any(true), true, CHAR_GRAB_BAG);
+ }
+}
+
+void DomainMapper::lcl_endCharacterGroup()
+{
+ if (m_pImpl->CheckFootnoteStyle())
+ {
+ m_pImpl->SetCheckFootnoteStyle(m_pImpl->IsInCustomFootnote());
+ m_pImpl->SetHasFootnoteStyle(false);
+ }
+ m_pImpl->PopProperties(CONTEXT_CHARACTER);
+}
+
+void DomainMapper::lcl_text(const sal_uInt8 * data_, size_t len)
+{
+ //TODO: Determine the right text encoding (FIB?)
+ OUString sText( reinterpret_cast<const char*>(data_), len, RTL_TEXTENCODING_MS_1252 );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("text");
+ TagLogger::getInstance().chars(sText);
+ TagLogger::getInstance().endElement();
+#endif
+
+ try
+ {
+ if(len == 1)
+ {
+ switch(*data_)
+ {
+ case 0x02: return; //footnote character
+ case 0x08: // Lock field if in field context
+ if (m_pImpl->IsOpenField())
+ m_pImpl->SetFieldLocked();
+ return;
+ case 0x0c: //page break
+ // page breaks aren't supported in footnotes and endnotes
+ if (!m_pImpl->IsInFootOrEndnote())
+ {
+ m_pImpl->deferBreak(PAGE_BREAK);
+ m_pImpl->SetIsDummyParaAddedForTableInSectionPage(false);
+ }
+ return;
+ case 0x0e: //column break
+ m_pImpl->deferBreak(COLUMN_BREAK);
+ return;
+ case 0x0a: //line break
+ if (m_pImpl->GetIsLastParagraphInSection())
+ {
+ m_pImpl->deferBreak(LINE_BREAK);
+ return;
+ }
+ break;
+ case 0x07:
+ m_pImpl->getTableManager().text(data_, len);
+ return;
+ case 0x0d:
+ {
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (pContext && m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ m_pImpl->clearDeferredBreak(COLUMN_BREAK);
+ }
+ finishParagraph();
+ return;
+ }
+ case cFieldStart:
+ m_pImpl->PushFieldContext();
+ return;
+ case cFieldSep:
+ // delimiter not necessarily available
+ // appears only if field contains further content
+ m_pImpl->CloseFieldCommand();
+ return;
+ case cFieldEnd:
+ m_pImpl->PopFieldContext();
+ return;
+ default:
+ break;
+ }
+ }
+
+ // GetTopContext() is changed by inserted breaks, but we want to keep the current context
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", pContext);
+ }
+
+ if (!m_pImpl->GetFootnoteContext())
+ {
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+
+ if (pContext && pContext->GetFootnote().is() && m_pImpl->IsInCustomFootnote())
+ {
+ pContext->GetFootnote()->setLabel(sText);
+ m_pImpl->EndCustomFootnote();
+ //otherwise ignore sText
+ }
+ else if (m_pImpl->IsOpenFieldCommand() && !m_pImpl->IsForceGenericFields())
+ {
+ m_pImpl->AppendFieldCommand(sText);
+ }
+ else if( m_pImpl->IsOpenField() && m_pImpl->IsFieldResultAsString())
+ /*depending on the success of the field insert operation this result will be
+ set at the field or directly inserted into the text*/
+ m_pImpl->AppendFieldResult(sText);
+ else
+ {
+ if (pContext == nullptr)
+ pContext = new PropertyMap();
+
+ if (sText == "\n")
+ {
+ m_pImpl->HandleLineBreak(pContext);
+ }
+ else
+ {
+ m_pImpl->appendTextPortion(sText, pContext);
+ }
+ }
+ }
+ catch( const uno::RuntimeException& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "");
+ }
+}
+
+void DomainMapper::lcl_positionOffset(const OUString& rText, bool bVertical)
+{
+ if (bVertical)
+ m_pImpl->m_aPositionOffsets.second = rText;
+ else
+ m_pImpl->m_aPositionOffsets.first = rText;
+}
+
+awt::Point DomainMapper::getPositionOffset()
+{
+ awt::Point aRet;
+ aRet.X = oox::drawingml::convertEmuToHmm(m_pImpl->m_aPositionOffsets.first.toInt32());
+ aRet.Y = oox::drawingml::convertEmuToHmm(m_pImpl->m_aPositionOffsets.second.toInt32());
+ return aRet;
+}
+
+void DomainMapper::lcl_align(const OUString& rText, bool bVertical)
+{
+ if (bVertical)
+ m_pImpl->m_aAligns.second = rText;
+ else
+ m_pImpl->m_aAligns.first = rText;
+}
+
+void DomainMapper::lcl_positivePercentage(const OUString& rText)
+{
+ m_pImpl->m_aPositivePercentages.push(rText);
+}
+
+void DomainMapper::lcl_checkId(const sal_Int32 nId)
+{
+ if (m_pImpl->IsInFootnote())
+ {
+ m_pImpl->m_aFootnoteIds.push_back(nId);
+ // keep only the first real footnote
+ if (m_pImpl->GetFootnoteCount() == -1 && m_pImpl->m_aFootnoteIds.size() == 2)
+ m_pImpl->m_aFootnoteIds.pop_front();
+ }
+ else
+ {
+ m_pImpl->m_aEndnoteIds.push_back(nId);
+ // keep only the first real endnote
+ if (m_pImpl->GetEndnoteCount() == -1 && m_pImpl->m_aEndnoteIds.size() == 2)
+ m_pImpl->m_aEndnoteIds.pop_front();
+ }
+}
+
+void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
+{
+ // All these fixed values are defined as static const sal_Unicode codepoints in the fast parser,
+ // like uFtnEdnRef = 0x2, uFtnEdnSep = 0x3, ... and have a len of 1, if they aren't valid unicode.
+
+ OUString sText(reinterpret_cast<const sal_Unicode *>(data_), len);
+ const RubyInfo & aInfo = m_pImpl->GetRubyInfo();
+ if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rt)
+ {
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+ PropertyValueVector_t aProps = comphelper::sequenceToContainer< PropertyValueVector_t >(pContext->GetPropertyValues());
+ OUString sStyle = getOrCreateCharStyle(aProps, /*bAlwaysCreate=*/false);
+ m_pImpl->SetRubyText(sText,sStyle);
+ return;
+ }
+
+ if (len == 1)
+ {
+ // preload all footnotes in separated footnotes
+ if (sText[0] == 0x5)
+ {
+ if (m_pImpl->IsInFootnote())
+ {
+ if (m_pImpl->GetFootnoteCount() > -1)
+ {
+ m_pImpl->PopFootOrEndnote();
+ m_pImpl->PushFootOrEndnote(/*bIsFootnote=*/true);
+ }
+ m_pImpl->IncrementFootnoteCount();
+ }
+ else
+ {
+ if (m_pImpl->GetEndnoteCount() > -1)
+ {
+ m_pImpl->PopFootOrEndnote();
+ m_pImpl->PushFootOrEndnote(/*bIsFootnote=*/false);
+ }
+ m_pImpl->IncrementEndnoteCount();
+ }
+ }
+
+ // If the footnote contains a Footnote Reference Mark, it can't be a custom footnote
+ // ******
+ // This code block is wrong, as it should also be in m_pImpl->IsInFootOrEndnote().
+ // The main problem is that
+ //
+ // assert(len != 1 || sText[0] != 0x2)
+ //
+ // is triggered by the unit test SwLayoutWriter::testForcepoint75, so all these pseudo
+ // value handling is broken.
+ // But this is just a symptom, as I guess it's possible to generate broken DOCX documents,
+ // which might be problematic, triggering *funny* code paths left and right.
+ // ******
+ if (sText[0] == 0x2)
+ {
+ m_pImpl->EndCustomFootnote();
+ return;
+ }
+
+ if (m_pImpl->IsInCustomFootnote())
+ {
+ if (sText[0] != 0xd && sText[0] != 0x3)
+ {
+ // DOCX can have different labels for the footnote reference and the footnote area.
+ // This skips the one from the footnote area and just uses the reference one.
+ if (!m_pImpl->IsInFootOrEndnote())
+ {
+ if (PropertyMapPtr pFootnoteContext = m_pImpl->GetFootnoteContext())
+ {
+ auto xFootnote = pFootnoteContext->GetFootnote();
+ xFootnote->setLabel(xFootnote->getLabel() + sText);
+ }
+ }
+ return;
+ }
+ else
+ m_pImpl->SetHasFootnoteStyle(true);
+ }
+ }
+
+ if (m_pImpl->isSdtEndDeferred())
+ {
+ // In case we have a field context, then save the property there, so
+ // SDT's ending right before a field start are handled as well.
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+ if (m_pImpl->IsOpenField())
+ pContext = m_pImpl->GetTopFieldContext()->getProperties();
+ pContext->Insert(PROP_SDT_END_BEFORE, uno::Any(true), true, CHAR_GRAB_BAG);
+ m_pImpl->setSdtEndDeferred(false);
+ }
+
+ bool bNewLine = len == 1 && (sText[0] == 0x0d || sText[0] == 0x07);
+ if (m_pImpl->GetSdtStarts().empty() && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::dropDown)
+ {
+ // Block, cell or row SDT.
+ if (bNewLine)
+ // Dropdown control has single-line texts, so in case of newline, create the control.
+ m_pImpl->m_pSdtHelper->createDropDownControl();
+ else
+ {
+ m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
+ return;
+ }
+ }
+ else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ {
+ if (IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter())
+ {
+ m_pImpl->m_pSdtHelper->getDateFormat().truncate();
+ m_pImpl->m_pSdtHelper->getLocale().truncate();
+ return;
+ }
+ }
+ else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
+ if (bNewLine)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ finishParagraph();
+ }
+ return;
+ }
+ else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty())
+ {
+ // there are unsupported SDT properties in the document
+ // save them in the paragraph interop grab bag
+ if (m_pImpl->IsDiscardHeaderFooter())
+ {
+ // Unless we're supposed to ignore this header/footer.
+ m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ return;
+ }
+ if((m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_checkbox") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_text") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_dataBinding") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_citation") ||
+ (m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_id") &&
+ m_pImpl->m_pSdtHelper->getInteropGrabBagSize() == 1)) && !m_pImpl->m_pSdtHelper->isOutsideAParagraph())
+ {
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_CHARACTER);
+
+ if (m_pImpl->IsOpenField())
+ // We have a field, insert the SDT properties to the field's grab-bag, so they won't be lost.
+ pContext = m_pImpl->GetTopFieldContext()->getProperties();
+
+ uno::Sequence<beans::PropertyValue> aGrabBag = m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ if (m_pImpl->GetSdtStarts().empty() || m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::dropDown)
+ {
+ pContext->Insert(PROP_SDTPR, uno::Any(aGrabBag), true, CHAR_GRAB_BAG);
+ }
+ }
+ else
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag = m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ if (m_pImpl->GetSdtStarts().empty()
+ || (m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::dropDown && m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::richText))
+ {
+ m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->Insert(PROP_SDTPR,
+ uno::Any(aGrabBag), true, PARA_GRAB_BAG);
+ }
+ }
+ }
+ else if (len == 1 && sText[0] == 0x03)
+ {
+ // This is the uFtnEdnSep, remember that the document has a separator.
+ m_pImpl->m_bHasFtnSep = true;
+ return;
+ }
+ else if (len == 1 && sText[0] == '\r')
+ {
+ // Clear "last" one linebreak at end of section
+ if (m_pImpl->GetIsLastParagraphInSection() && m_pImpl->isBreakDeferred(LINE_BREAK))
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ // And emit all other linebreaks
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+ }
+ else if (len == 1 && sText[0] == '\t' )
+ {
+ if ( m_pImpl->m_bCheckFirstFootnoteTab && m_pImpl->IsInFootOrEndnote() )
+ {
+ // Allow MSO to emulate LO footnote text starting at left margin - only meaningful with hanging indent
+ m_pImpl->m_bCheckFirstFootnoteTab = false;
+ sal_Int32 nFirstLineIndent = 0;
+ m_pImpl->GetAnyProperty(PROP_PARA_FIRST_LINE_INDENT, m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)) >>= nFirstLineIndent;
+ if ( nFirstLineIndent < 0 )
+ m_pImpl->m_bIgnoreNextTab = true;
+ }
+
+ if ( m_pImpl->m_bIgnoreNextTab )
+ {
+ m_pImpl->m_bIgnoreNextTab = false;
+ return;
+ }
+ }
+ if (!m_pImpl->hasTableManager())
+ return;
+
+ SkipFootnoteSeparator eSkip = m_pImpl->GetSkipFootnoteState();
+ if ( eSkip == SkipFootnoteSeparator::ON || eSkip == SkipFootnoteSeparator::SKIPPING )
+ {
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::SKIPPING );
+ return;
+ }
+
+ try
+ {
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+
+ m_pImpl->getTableManager().utext(data_, len);
+
+ if (bNewLine)
+ {
+ const bool bSingleParagraph = m_pImpl->GetIsFirstParagraphInSection() && m_pImpl->GetIsLastParagraphInSection();
+ const bool bSingleParagraphAfterRedline = m_pImpl->GetIsFirstParagraphInSection(/*bAfterRedline=*/true) &&
+ m_pImpl->GetIsLastParagraphInSection();
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (!m_pImpl->GetFootnoteContext())
+ {
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ if (m_pImpl->GetSettingsTable()->GetSplitPgBreakAndParaMark())
+ {
+ if ( m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() )
+ {
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+
+
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+ }
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ if ( m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() )
+ {
+ mbIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+ }
+
+ // If the paragraph contains only the section properties and it has
+ // no runs, we should not create a paragraph for it in Writer, unless that would remove the whole section.
+ // Also do not remove here column breaks: they are treated in a different way and place.
+ bool bIsColumnBreak = false;
+ if (pContext->isSet(PROP_BREAK_TYPE))
+ {
+ const uno::Any aBreakType = pContext->getProperty(PROP_BREAK_TYPE)->second;
+ bIsColumnBreak =
+ aBreakType == style::BreakType_COLUMN_BEFORE ||
+ aBreakType == style::BreakType_COLUMN_AFTER ||
+ aBreakType == style::BreakType_COLUMN_BOTH;
+ }
+
+ bool bRemove = (!m_pImpl->GetParaChanged() && m_pImpl->GetRemoveThisPara()) ||
+ (!m_pImpl->GetParaChanged() && m_pImpl->GetParaSectpr()
+ && !bSingleParagraphAfterRedline
+ && !bIsColumnBreak
+ && !m_pImpl->GetParaHadField()
+ && (!m_pImpl->GetIsDummyParaAddedForTableInSectionPage())
+ && !m_pImpl->GetIsPreviousParagraphFramed()
+ && !m_pImpl->HasTopAnchoredObjects()
+ && !m_pImpl->IsParaWithInlineObject());
+
+ const bool bNoNumbering = bRemove || (!m_pImpl->GetParaChanged() && m_pImpl->GetParaSectpr() && bSingleParagraph);
+ PropertyMapPtr xContext = bNoNumbering ? m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH) : PropertyMapPtr();
+ if (xContext)
+ {
+ // tdf#97417 delete numbering of the paragraph
+ // it will be deleted anyway, and the numbering would be copied
+ // to the next paragraph in sw SplitNode and then be applied to
+ // every following paragraph
+ xContext->Erase(PROP_NUMBERING_RULES);
+ static_cast<ParagraphPropertyMap*>(xContext.get())->SetListId(-1);;
+ xContext->Erase(PROP_NUMBERING_LEVEL);
+ }
+ finishParagraph(bRemove, bNoNumbering);
+ if (bRemove)
+ m_pImpl->RemoveLastParagraph();
+ m_pImpl->SetParaSectpr(false);
+ }
+ else
+ {
+ // GetTopContext() is changed by inserted breaks, but we want to keep the current context
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+ if (!m_pImpl->GetFootnoteContext())
+ {
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ /* If PAGEBREAK appears in first paragraph of the section or
+ * after first run of any paragraph then need to split paragraph
+ * to handle it properly.
+ */
+ if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun())
+ {
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ }
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() || mbWasShapeInPara)
+ {
+ mbWasShapeInPara = false;
+ mbIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ }
+ m_pImpl->clearDeferredBreaks();
+ }
+
+ if (pContext && pContext->GetFootnote().is())
+ {
+ pContext->GetFootnote()->setLabel( sText );
+ // tdf#141548 don't lose footnote/endnote text of the run with uFtnEdnRef
+ // (i.e. when footnoteRef/endnoteRef is followed by some text in the same run)
+ m_pImpl->appendTextPortion( sText, pContext );
+ }
+ else if (m_pImpl->IsOpenFieldCommand() && !m_pImpl->IsForceGenericFields())
+ {
+ m_pImpl->AppendFieldCommand(sText);
+ }
+ else if( m_pImpl->IsOpenField() && m_pImpl->IsFieldResultAsString())
+ /*depending on the success of the field insert operation this result will be
+ set at the field or directly inserted into the text*/
+ m_pImpl->AppendFieldResult(sText);
+ else
+ {
+ if (pContext == nullptr)
+ pContext = new PropertyMap();
+
+ m_pImpl->appendTextPortion( sText, pContext );
+ }
+
+ }
+ m_pImpl->SetIsFirstRun(false);
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+}
+
+void DomainMapper::lcl_props(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+ ref->resolve(*this);
+}
+
+void DomainMapper::lcl_table(Id name, writerfilter::Reference<Table>::Pointer_t ref)
+{
+ m_pImpl->SetAnyTableImport(true);
+ switch(name)
+ {
+ case NS_ooxml::LN_FONTTABLE:
+
+ // create a font table object that listens to the attributes
+ // each entry call inserts a new font entry
+ ref->resolve( *m_pImpl->GetFontTable() );
+ break;
+ case NS_ooxml::LN_STYLESHEET:
+ //same as above to import style sheets
+ m_pImpl->SetStyleSheetImport( true );
+ ref->resolve( *m_pImpl->GetStyleSheetTable() );
+ m_pImpl->GetStyleSheetTable()->ApplyStyleSheets(m_pImpl->GetFontTable());
+ m_pImpl->SetStyleSheetImport( false );
+ break;
+ case NS_ooxml::LN_NUMBERING:
+ {
+ m_pImpl->SetNumberingImport(true);
+ //the same for list tables
+ ref->resolve( *m_pImpl->GetListTable() );
+ m_pImpl->GetListTable( )->CreateNumberingRules( );
+ m_pImpl->SetNumberingImport(false);
+ }
+ break;
+ case NS_ooxml::LN_THEMETABLE:
+ m_pImpl->GetThemeTable()->setThemeFontLangProperties(
+ m_pImpl->GetSettingsTable()->GetThemeFontLangProperties() );
+ ref->resolve ( *m_pImpl->GetThemeTable() );
+ break;
+ case NS_ooxml::LN_settings_settings:
+ ref->resolve ( *m_pImpl->GetSettingsTable() );
+ m_pImpl->ApplySettingsTable();
+ break;
+ default:
+ OSL_FAIL( "which table is to be filled here?");
+ }
+ m_pImpl->SetAnyTableImport(false);
+}
+
+void DomainMapper::lcl_substream(Id rName, ::writerfilter::Reference<Stream>::Pointer_t ref)
+{
+ m_pImpl->substream(rName, ref);
+}
+
+void DomainMapper::lcl_startGlossaryEntry()
+{
+ uno::Reference< text::XTextRange > xTextRange = GetCurrentTextRange();
+ m_pImpl->setGlossaryEntryStart(xTextRange);
+}
+
+void DomainMapper::lcl_endGlossaryEntry()
+{
+ m_pImpl->appendGlossaryEntry();
+}
+
+void DomainMapper::handleUnderlineType(const Id nId, const ::tools::SvRef<PropertyMap>& rContext)
+{
+ sal_Int16 nUnderline = awt::FontUnderline::NONE;
+
+ switch (nId)
+ {
+ case NS_ooxml::LN_Value_ST_Underline_none:
+ nUnderline = awt::FontUnderline::NONE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_words:
+ rContext->Insert(PROP_CHAR_WORD_MODE, uno::Any(true));
+ [[fallthrough]];
+ case NS_ooxml::LN_Value_ST_Underline_single:
+ nUnderline = awt::FontUnderline::SINGLE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_double:
+ nUnderline = awt::FontUnderline::DOUBLE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dotted:
+ nUnderline = awt::FontUnderline::DOTTED;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dash:
+ nUnderline = awt::FontUnderline::DASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dotDash:
+ nUnderline = awt::FontUnderline::DASHDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dotDotDash:
+ nUnderline = awt::FontUnderline::DASHDOTDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_thick:
+ nUnderline = awt::FontUnderline::BOLD;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_wave:
+ nUnderline = awt::FontUnderline::WAVE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dottedHeavy:
+ nUnderline = awt::FontUnderline::BOLDDOTTED;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashedHeavy:
+ nUnderline = awt::FontUnderline::BOLDDASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashLong:
+ nUnderline = awt::FontUnderline::LONGDASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashLongHeavy:
+ nUnderline = awt::FontUnderline::BOLDLONGDASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashDotHeavy:
+ nUnderline = awt::FontUnderline::BOLDDASHDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy:
+ nUnderline = awt::FontUnderline::BOLDDASHDOTDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_wavyHeavy:
+ nUnderline = awt::FontUnderline::BOLDWAVE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_wavyDouble:
+ nUnderline = awt::FontUnderline::DOUBLEWAVE;
+ break;
+ }
+ rContext->Insert(PROP_CHAR_UNDERLINE, uno::Any(nUnderline));
+}
+
+void DomainMapper::handleParaJustification(const sal_Int32 nIntValue, const ::tools::SvRef<PropertyMap>& rContext, const bool bExchangeLeftRight)
+{
+ style::ParagraphAdjust nAdjust = style::ParagraphAdjust_LEFT;
+ style::ParagraphAdjust nLastLineAdjust = style::ParagraphAdjust_LEFT;
+ OUString aStringValue = "left";
+ switch(nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Jc_center:
+ nAdjust = style::ParagraphAdjust_CENTER;
+ aStringValue = "center";
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_right:
+ case NS_ooxml::LN_Value_ST_Jc_end:
+ nAdjust = bExchangeLeftRight ? style::ParagraphAdjust_LEFT : style::ParagraphAdjust_RIGHT;
+ aStringValue = "right";
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_distribute:
+ nLastLineAdjust = style::ParagraphAdjust_BLOCK;
+ [[fallthrough]];
+ case NS_ooxml::LN_Value_ST_Jc_both:
+ nAdjust = style::ParagraphAdjust_BLOCK;
+ aStringValue = "both";
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_left:
+ case NS_ooxml::LN_Value_ST_Jc_start:
+ default:
+ nAdjust = bExchangeLeftRight ? style::ParagraphAdjust_RIGHT : style::ParagraphAdjust_LEFT;
+ break;
+ }
+ rContext->Insert( PROP_PARA_ADJUST, uno::Any( nAdjust ) );
+ rContext->Insert( PROP_PARA_LAST_LINE_ADJUST, uno::Any( nLastLineAdjust ) );
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "jc", aStringValue);
+}
+
+bool DomainMapper::getColorFromId(const Id nId, sal_Int32 &nColor)
+{
+ nColor = 0;
+ if ((nId < NS_ooxml::LN_Value_ST_HighlightColor_black) || (nId > NS_ooxml::LN_Value_ST_HighlightColor_none))
+ return false;
+
+ switch (nId)
+ {
+ case NS_ooxml::LN_Value_ST_HighlightColor_black: nColor=0x000000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_blue: nColor=0x0000ff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_cyan: nColor=0x00ffff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_green: nColor=0x00ff00; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_magenta: nColor=0xff00ff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_red: nColor=0xff0000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_yellow: nColor=0xffff00; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_white: nColor=0xffffff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkBlue: nColor=0x000080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkCyan: nColor=0x008080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkGreen: nColor=0x008000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkMagenta: nColor=0x800080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkRed: nColor=0x800000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkYellow: nColor=0x808000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkGray: nColor=0x808080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_lightGray: nColor=0xC0C0C0; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_none: nColor=0xFFFFFFFF; break; //COL_AUTO
+ default:
+ return false;
+ }
+ return true;
+}
+
+sal_Int16 DomainMapper::getEmphasisValue(const sal_Int32 nIntValue)
+{
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Em_dot:
+ return text::FontEmphasis::DOT_ABOVE;
+ case NS_ooxml::LN_Value_ST_Em_comma:
+ return text::FontEmphasis::ACCENT_ABOVE;
+ case NS_ooxml::LN_Value_ST_Em_circle:
+ return text::FontEmphasis::CIRCLE_ABOVE;
+ case NS_ooxml::LN_Value_ST_Em_underDot:
+ return text::FontEmphasis::DOT_BELOW;
+ default:
+ return text::FontEmphasis::NONE;
+ }
+}
+
+OUString DomainMapper::getBracketStringFromEnum(const sal_Int32 nIntValue, const bool bIsPrefix)
+{
+ switch(nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_CombineBrackets_round:
+ if (bIsPrefix)
+ return "(";
+ return ")";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_square:
+ if (bIsPrefix)
+ return "[";
+ return "]";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_angle:
+ if (bIsPrefix)
+ return "<";
+ return ">";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_curly:
+ if (bIsPrefix)
+ return "{";
+ return "}";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_none:
+ default:
+ return OUString();
+ }
+}
+
+style::TabAlign DomainMapper::getTabAlignFromValue(const sal_Int32 nIntValue)
+{
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TabJc_start:
+ case NS_ooxml::LN_Value_ST_TabJc_left:
+ case NS_ooxml::LN_Value_ST_TabJc_bar: // bar not supported
+ case NS_ooxml::LN_Value_ST_TabJc_num: // num not supported
+ return style::TabAlign_LEFT;
+ case NS_ooxml::LN_Value_ST_TabJc_center:
+ return style::TabAlign_CENTER;
+ case NS_ooxml::LN_Value_ST_TabJc_end:
+ case NS_ooxml::LN_Value_ST_TabJc_right:
+ return style::TabAlign_RIGHT;
+ case NS_ooxml::LN_Value_ST_TabJc_decimal:
+ return style::TabAlign_DECIMAL;
+ }
+ return style::TabAlign_LEFT;
+}
+
+sal_Unicode DomainMapper::getFillCharFromValue(const sal_Int32 nIntValue)
+{
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TabTlc_dot:
+ return u'.';
+ case NS_ooxml::LN_Value_ST_TabTlc_hyphen:
+ return u'-';
+ case NS_ooxml::LN_Value_ST_TabTlc_underscore:
+ case NS_ooxml::LN_Value_ST_TabTlc_heavy: // FIXME ???
+ return u'_';
+ case NS_ooxml::LN_Value_ST_TabTlc_middleDot: // middleDot
+ return u'\x00b7';
+ case NS_ooxml::LN_Value_ST_TabTlc_none:
+ default:
+ return u' '; // blank space
+ }
+}
+
+bool DomainMapper::IsOOXMLImport() const
+{
+ return m_pImpl->IsOOXMLImport();
+}
+
+bool DomainMapper::IsRTFImport() const
+{
+ return m_pImpl->IsRTFImport();
+}
+
+uno::Reference < lang::XMultiServiceFactory > const & DomainMapper::GetTextFactory() const
+{
+ return m_pImpl->GetTextFactory();
+}
+
+uno::Reference< text::XTextRange > DomainMapper::GetCurrentTextRange()
+{
+ if (m_pImpl->HasTopText())
+ return m_pImpl->GetTopTextAppend()->getEnd();
+ return m_pImpl->m_xInsertTextRange;
+}
+
+OUString DomainMapper::getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate )
+{
+ StyleSheetTablePtr pStyleSheets = m_pImpl->GetStyleSheetTable();
+ return pStyleSheets->getOrCreateCharStyle( rCharProperties, bAlwaysCreate );
+}
+
+StyleSheetTablePtr const & DomainMapper::GetStyleSheetTable( )
+{
+ return m_pImpl->GetStyleSheetTable( );
+}
+
+SettingsTablePtr const & DomainMapper::GetSettingsTable()
+{
+ return m_pImpl->GetSettingsTable();
+}
+
+GraphicZOrderHelper* DomainMapper::graphicZOrderHelper()
+{
+ if (zOrderHelper == nullptr)
+ zOrderHelper.reset( new GraphicZOrderHelper );
+ return zOrderHelper.get();
+}
+
+GraphicNamingHelper& DomainMapper::GetGraphicNamingHelper()
+{
+ if (m_pGraphicNamingHelper == nullptr)
+ m_pGraphicNamingHelper.reset(new GraphicNamingHelper());
+ return *m_pGraphicNamingHelper;
+}
+
+uno::Reference<drawing::XShape> DomainMapper::PopPendingShape()
+{
+ return m_pImpl->PopPendingShape();
+}
+
+bool DomainMapper::IsInHeaderFooter() const
+{
+ return m_pImpl->IsInHeaderFooter();
+}
+
+bool DomainMapper::IsInShape() const { return m_pImpl->IsInShape(); }
+
+bool DomainMapper::IsInTable() const
+{
+ return m_pImpl->hasTableManager() && m_pImpl->getTableManager().isInCell();
+}
+
+OUString DomainMapper::GetListStyleName(sal_Int32 nListId) const
+{
+ return m_pImpl->GetListStyleName( nListId );
+}
+
+void DomainMapper::ValidateListLevel(const OUString& sStyleIdentifierD)
+{
+ m_pImpl->ValidateListLevel(sStyleIdentifierD);
+}
+
+void DomainMapper::SetDocDefaultsImport(bool bSet)
+{
+ m_pImpl->SetDocDefaultsImport(bSet);
+}
+
+bool DomainMapper::IsStyleSheetImport() const
+{
+ return m_pImpl->IsStyleSheetImport();
+}
+
+bool DomainMapper::IsNumberingImport() const
+{
+ return m_pImpl->IsNumberingImport();
+}
+
+void DomainMapper::enableInteropGrabBag(const OUString& aName)
+{
+ m_pImpl->m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue DomainMapper::getInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = m_pImpl->m_aInteropGrabBagName;
+ aRet.Value <<= comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag);
+
+ m_pImpl->m_aInteropGrabBag.clear();
+ m_pImpl->m_aInteropGrabBagName.clear();
+ return aRet;
+}
+
+void DomainMapper::HandleRedline( Sprm& rSprm )
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ m_pImpl->AddNewRedline( nSprmId );
+
+ if (nSprmId == NS_ooxml::LN_CT_PPr_pPrChange)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_ParagraphFormat);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TrPr_ins)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableRowInsert);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TrPr_del)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableRowDelete);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TcPrBase_cellIns)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableCellInsert);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TcPrBase_cellDel)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableCellDelete);
+ }
+
+ resolveSprmProps(*this, rSprm );
+ // now the properties author, date and id should be available
+ sal_Int32 nToken = m_pImpl->GetCurrentRedlineToken();
+ switch( nToken & 0xffff )
+ {
+ case XML_mod:
+ case XML_ins:
+ case XML_del:
+ case XML_moveTo:
+ case XML_moveFrom:
+ case XML_ParagraphFormat:
+ case XML_tableRowInsert:
+ case XML_tableRowDelete:
+ case XML_tableCellInsert:
+ case XML_tableCellDelete:
+ break;
+ default: OSL_FAIL( "redline token other than mod, ins, del, moveTo, moveFrom or table row" ); break;
+ }
+ m_pImpl->EndParaMarkerChange( );
+ m_pImpl->SetCurrentRedlineIsRead();
+}
+
+void DomainMapper::finishParagraph(const bool bRemove, const bool bNoNumbering)
+{
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ m_pImpl->m_pSdtHelper->createDateContentControl();
+ m_pImpl->finishParagraph(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH), bRemove, bNoNumbering);
+}
+
+void DomainMapper::commentProps(const OUString& sId, const CommentProperties& rProps)
+{
+ m_pImpl->commentProps(sId, rProps);
+}
+
+css::uno::Reference<css::container::XNameContainer> const & DomainMapper::GetCharacterStyles()
+{
+ return m_pImpl->GetCharacterStyles();
+}
+
+OUString DomainMapper::GetUnusedCharacterStyleName()
+{
+ return m_pImpl->GetUnusedCharacterStyleName();
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper.hxx b/writerfilter/source/dmapper/DomainMapper.hxx
new file mode 100644
index 000000000..4096b2b5d
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapper.hxx
@@ -0,0 +1,195 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include "LoggedResources.hxx"
+#include "PropertyMap.hxx"
+#include "SettingsTable.hxx"
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/style/TabAlign.hpp>
+
+#include <map>
+#include <vector>
+#include <memory>
+
+namespace com::sun::star{
+ namespace beans{
+ struct PropertyValue;
+ }
+ namespace io{
+ class XInputStream;
+ }
+ namespace uno{
+ class XComponentContext;
+ }
+ namespace lang{
+ class XMultiServiceFactory;
+ }
+ namespace text{
+ class XTextRange;
+ }
+}
+
+namespace utl
+{
+class MediaDescriptor;
+}
+
+typedef std::vector<css::beans::PropertyValue> PropertyValueVector_t;
+
+namespace writerfilter::dmapper
+{
+
+class PropertyMap;
+class DomainMapper_Impl;
+class ListsManager;
+class StyleSheetTable;
+class GraphicZOrderHelper;
+class GraphicNamingHelper;
+
+typedef tools::SvRef<StyleSheetTable> StyleSheetTablePtr;
+
+class DomainMapper : public LoggedProperties, public LoggedTable,
+ public BinaryObj, public LoggedStream
+{
+ std::unique_ptr<DomainMapper_Impl> m_pImpl;
+
+public:
+ DomainMapper(const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xModel,
+ bool bRepairStorage,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc);
+ virtual ~DomainMapper() override;
+
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) override;
+
+ // Stream
+ virtual void markLastParagraphInSection() override;
+ virtual void markLastSectionGroup() override;
+
+ // BinaryObj
+ virtual void data(const sal_uInt8* buf, size_t len) override;
+
+ void sprmWithProps( Sprm& sprm, const PropertyMapPtr& pContext );
+
+ void PushStyleSheetProperties( const PropertyMapPtr& pStyleProperties, bool bAffectTableMngr = false );
+ void PopStyleSheetProperties( bool bAffectTableMngr = false );
+
+ void PushListProperties( const ::tools::SvRef<PropertyMap>& pListProperties );
+ void PopListProperties();
+ OUString GetListStyleName(sal_Int32 nListId) const;
+ void ValidateListLevel(const OUString& sStyleIdentifierD);
+
+ bool IsOOXMLImport() const;
+ bool IsRTFImport() const;
+ css::uno::Reference<css::lang::XMultiServiceFactory> const & GetTextFactory() const;
+ css::uno::Reference<css::text::XTextRange> GetCurrentTextRange();
+
+ OUString getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate );
+ StyleSheetTablePtr const & GetStyleSheetTable( );
+ SettingsTablePtr const & GetSettingsTable();
+ GraphicZOrderHelper* graphicZOrderHelper();
+ GraphicNamingHelper& GetGraphicNamingHelper();
+
+ /// Return the first from the pending (not inserted to the document) shapes, if there are any.
+ css::uno::Reference<css::drawing::XShape> PopPendingShape();
+
+ bool IsInHeaderFooter() const;
+ bool IsInTable() const;
+ void SetDocDefaultsImport(bool bSet);
+ bool IsStyleSheetImport() const;
+ bool IsNumberingImport() const;
+ bool IsInShape() const;
+
+ void hasControls( const bool bSet ) { mbHasControls = bSet; }
+
+ /**
+ @see DomainMapper_Impl::processDeferredCharacterProperties()
+ */
+ void processDeferredCharacterProperties(const std::map<sal_Int32, css::uno::Any>& rDeferredCharacterProperties);
+
+ /// Enable storing of seen tokens in a named grab bag.
+ void enableInteropGrabBag(const OUString& aName);
+ /// Get the stored tokens and clear the internal storage.
+ css::beans::PropertyValue getInteropGrabBag();
+
+ void HandleRedline( Sprm& rSprm );
+
+ virtual void commentProps(const OUString& sId, const CommentProperties& rProps) override;
+
+ css::uno::Reference<css::container::XNameContainer> const & GetCharacterStyles();
+ OUString GetUnusedCharacterStyleName();
+
+private:
+ // Stream
+ virtual void lcl_startSectionGroup() override;
+ virtual void lcl_endSectionGroup() override;
+ virtual void lcl_startParagraphGroup() override;
+ virtual void lcl_endParagraphGroup() override;
+ virtual void lcl_startCharacterGroup() override;
+ virtual void lcl_endCharacterGroup() override;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ virtual void lcl_endShape( ) override;
+ virtual void lcl_startTextBoxContent() override;
+ virtual void lcl_endTextBoxContent() override;
+ virtual void lcl_text(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_utext(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_positionOffset(const OUString& rText, bool bVertical) override;
+ virtual css::awt::Point getPositionOffset() override;
+ virtual void lcl_align(const OUString& rText, bool bVertical) override;
+ virtual void lcl_positivePercentage(const OUString& rText) override;
+ virtual void lcl_props(writerfilter::Reference<Properties>::Pointer_t ref) override;
+ virtual void lcl_table(Id name,
+ writerfilter::Reference<Table>::Pointer_t ref) override;
+ virtual void lcl_substream(Id name,
+ ::writerfilter::Reference<Stream>::Pointer_t ref) override;
+ virtual void lcl_startGlossaryEntry() override;
+ virtual void lcl_endGlossaryEntry() override;
+ virtual void lcl_checkId(const sal_Int32 nId) override;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+ void finishParagraph(const bool bRemove = false, const bool bNoNumbering = false);
+
+ static void handleUnderlineType(const Id nId, const ::tools::SvRef<PropertyMap>& rContext);
+ void handleParaJustification(const sal_Int32 nIntValue, const ::tools::SvRef<PropertyMap>& rContext, const bool bExchangeLeftRight);
+ static bool getColorFromId(const Id, sal_Int32 &nColor);
+ static sal_Int16 getEmphasisValue(const sal_Int32 nIntValue);
+ static OUString getBracketStringFromEnum(const sal_Int32 nIntValue, const bool bIsPrefix = true);
+ static css::style::TabAlign getTabAlignFromValue(const sal_Int32 nIntValue);
+ static sal_Unicode getFillCharFromValue(const sal_Int32 nIntValue);
+ bool mbIsSplitPara;
+ bool mbHasControls;
+ bool mbWasShapeInPara;
+ std::unique_ptr< GraphicZOrderHelper > zOrderHelper;
+ std::unique_ptr<GraphicNamingHelper> m_pGraphicNamingHelper;
+ OUString m_sGlossaryEntryName;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
new file mode 100644
index 000000000..bf170d9cc
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -0,0 +1,1700 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "DomainMapperTableHandler.hxx"
+#include "DomainMapper_Impl.hxx"
+#include "StyleSheetTable.hxx"
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/table/TableBorderDistances.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/table/BorderLineStyle.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/XTextRangeCompare.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include "TablePositionHandler.hxx"
+#include "TagLogger.hxx"
+#include "util.hxx"
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <boost/lexical_cast.hpp>
+
+#ifdef DBG_UTIL
+#include "PropertyMapHelper.hxx"
+#include <rtl/ustring.hxx>
+#endif
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+using namespace ::std;
+
+#define DEF_BORDER_DIST 190 //0,19cm
+#define CNF_FIRST_ROW 0x800
+#define CNF_LAST_ROW 0x400
+#define CNF_FIRST_COLUMN 0x200
+#define CNF_LAST_COLUMN 0x100
+#define CNF_ODD_VBAND 0x080
+#define CNF_EVEN_VBAND 0x040
+#define CNF_ODD_HBAND 0x020
+#define CNF_EVEN_HBAND 0x010
+#define CNF_FIRST_ROW_LAST_COLUMN 0x008
+#define CNF_FIRST_ROW_FIRST_COLUMN 0x004
+#define CNF_LAST_ROW_LAST_COLUMN 0x002
+#define CNF_LAST_ROW_FIRST_COLUMN 0x001
+#define CNF_ALL 0xFFF
+
+// total number of table columns
+#define MAXTABLECELLS 63
+
+DomainMapperTableHandler::DomainMapperTableHandler(
+ css::uno::Reference<css::text::XTextAppendAndConvert> const& xText,
+ DomainMapper_Impl& rDMapper_Impl)
+ : m_xText(xText),
+ m_rDMapper_Impl( rDMapper_Impl ),
+ m_bHadFootOrEndnote(false)
+{
+}
+
+DomainMapperTableHandler::~DomainMapperTableHandler()
+{
+}
+
+void DomainMapperTableHandler::startTable(const TablePropertyMapPtr& pProps)
+{
+ m_aTableProperties = pProps;
+ m_aTableRanges.clear();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablehandler.table");
+
+ if (pProps)
+ pProps->dumpXml();
+#endif
+}
+
+static void lcl_mergeBorder( PropertyIds nId, const PropertyMapPtr& pOrig, const PropertyMapPtr& pDest )
+{
+ std::optional<PropertyMap::Property> pOrigVal = pOrig->getProperty(nId);
+
+ if ( pOrigVal )
+ {
+ pDest->Insert( nId, pOrigVal->second, false );
+ }
+}
+
+static void lcl_computeCellBorders( const PropertyMapPtr& pTableBorders, const PropertyMapPtr& pCellProps,
+ sal_uInt32 nCell, sal_uInt32 nFirstCell, sal_uInt32 nLastCell, sal_Int32 nRow, bool bIsEndRow, bool bMergedVertically )
+{
+ const bool bIsStartCol = nCell == nFirstCell;
+ const bool bIsEndCol = nCell == nLastCell;
+ std::optional<PropertyMap::Property> pVerticalVal = pCellProps->getProperty(META_PROP_VERTICAL_BORDER);
+ std::optional<PropertyMap::Property> pHorizontalVal = pCellProps->getProperty(META_PROP_HORIZONTAL_BORDER);
+
+ // Handle the vertical and horizontal borders
+ uno::Any aVertProp;
+ if ( !pVerticalVal)
+ {
+ pVerticalVal = pTableBorders->getProperty(META_PROP_VERTICAL_BORDER);
+ if ( pVerticalVal )
+ aVertProp = pVerticalVal->second;
+ }
+ else
+ {
+ aVertProp = pVerticalVal->second;
+ pCellProps->Erase( pVerticalVal->first );
+ }
+
+ uno::Any aHorizProp;
+ if ( !pHorizontalVal )
+ {
+ pHorizontalVal = pTableBorders->getProperty(META_PROP_HORIZONTAL_BORDER);
+ if ( pHorizontalVal )
+ aHorizProp = pHorizontalVal->second;
+ }
+ else
+ {
+ aHorizProp = pHorizontalVal->second;
+ pCellProps->Erase( pHorizontalVal->first );
+ }
+
+ if ( bIsStartCol )
+ lcl_mergeBorder( PROP_LEFT_BORDER, pTableBorders, pCellProps );
+
+ if ( bIsEndCol )
+ lcl_mergeBorder( PROP_RIGHT_BORDER, pTableBorders, pCellProps );
+
+ // <w:insideV> counts if there are multiple cells in this row.
+ if ( pVerticalVal )
+ {
+ if ( !bIsEndCol && nCell >= nFirstCell )
+ pCellProps->Insert( PROP_RIGHT_BORDER, aVertProp, false );
+ if ( !bIsStartCol && nCell <= nLastCell )
+ pCellProps->Insert( PROP_LEFT_BORDER, aVertProp, false );
+ }
+
+ if ( nRow == 0 )
+ {
+ lcl_mergeBorder( PROP_TOP_BORDER, pTableBorders, pCellProps );
+ if ( pHorizontalVal && !bMergedVertically )
+ pCellProps->Insert( PROP_BOTTOM_BORDER, aHorizProp, false );
+ }
+
+ if ( bMergedVertically )
+ lcl_mergeBorder( PROP_BOTTOM_BORDER, pTableBorders, pCellProps );
+
+ if ( bIsEndRow )
+ {
+ lcl_mergeBorder( PROP_BOTTOM_BORDER, pTableBorders, pCellProps );
+ if ( pHorizontalVal )
+ pCellProps->Insert( PROP_TOP_BORDER, aHorizProp, false );
+ }
+
+ if ( nRow > 0 && !bIsEndRow )
+ {
+ if ( pHorizontalVal )
+ {
+ pCellProps->Insert( PROP_TOP_BORDER, aHorizProp, false );
+ pCellProps->Insert( PROP_BOTTOM_BORDER, aHorizProp, false );
+ }
+ }
+}
+
+#ifdef DBG_UTIL
+
+static void lcl_debug_BorderLine(table::BorderLine const & rLine)
+{
+ TagLogger::getInstance().startElement("BorderLine");
+ TagLogger::getInstance().attribute("Color", rLine.Color);
+ TagLogger::getInstance().attribute("InnerLineWidth", rLine.InnerLineWidth);
+ TagLogger::getInstance().attribute("OuterLineWidth", rLine.OuterLineWidth);
+ TagLogger::getInstance().attribute("LineDistance", rLine.LineDistance);
+ TagLogger::getInstance().endElement();
+}
+
+static void lcl_debug_TableBorder(table::TableBorder const & rBorder)
+{
+ TagLogger::getInstance().startElement("TableBorder");
+ lcl_debug_BorderLine(rBorder.TopLine);
+ TagLogger::getInstance().attribute("IsTopLineValid", sal_uInt32(rBorder.IsTopLineValid));
+ lcl_debug_BorderLine(rBorder.BottomLine);
+ TagLogger::getInstance().attribute("IsBottomLineValid", sal_uInt32(rBorder.IsBottomLineValid));
+ lcl_debug_BorderLine(rBorder.LeftLine);
+ TagLogger::getInstance().attribute("IsLeftLineValid", sal_uInt32(rBorder.IsLeftLineValid));
+ lcl_debug_BorderLine(rBorder.RightLine);
+ TagLogger::getInstance().attribute("IsRightLineValid", sal_uInt32(rBorder.IsRightLineValid));
+ lcl_debug_BorderLine(rBorder.VerticalLine);
+ TagLogger::getInstance().attribute("IsVerticalLineValid", sal_uInt32(rBorder.IsVerticalLineValid));
+ lcl_debug_BorderLine(rBorder.HorizontalLine);
+ TagLogger::getInstance().attribute("IsHorizontalLineValid", sal_uInt32(rBorder.IsHorizontalLineValid));
+ TagLogger::getInstance().attribute("Distance", rBorder.Distance);
+ TagLogger::getInstance().attribute("IsDistanceValid", sal_uInt32(rBorder.IsDistanceValid));
+ TagLogger::getInstance().endElement();
+}
+#endif
+
+struct TableInfo
+{
+ sal_Int32 nLeftBorderDistance;
+ sal_Int32 nRightBorderDistance;
+ sal_Int32 nTopBorderDistance;
+ sal_Int32 nBottomBorderDistance;
+ sal_Int32 nTblLook;
+ sal_Int32 nNestLevel;
+ PropertyMapPtr pTableDefaults;
+ PropertyMapPtr pTableBorders;
+ TableStyleSheetEntry* pTableStyle;
+ css::beans::PropertyValues aTableProperties;
+ std::vector< PropertyIds > aTablePropertyIds;
+
+ TableInfo()
+ : nLeftBorderDistance(DEF_BORDER_DIST)
+ , nRightBorderDistance(DEF_BORDER_DIST)
+ , nTopBorderDistance(0)
+ , nBottomBorderDistance(0)
+ , nTblLook(0x4a0)
+ , nNestLevel(0)
+ , pTableDefaults(new PropertyMap)
+ , pTableBorders(new PropertyMap)
+ , pTableStyle(nullptr)
+ {
+ }
+
+};
+
+namespace
+{
+
+bool lcl_extractTableBorderProperty(const PropertyMapPtr& pTableProperties, const PropertyIds nId, TableInfo const & rInfo, table::BorderLine2& rLine)
+{
+ if (!pTableProperties)
+ return false;
+
+ const std::optional<PropertyMap::Property> aTblBorder = pTableProperties->getProperty(nId);
+ if( aTblBorder )
+ {
+ OSL_VERIFY(aTblBorder->second >>= rLine);
+
+ rInfo.pTableBorders->Insert( nId, uno::Any( rLine ) );
+ rInfo.pTableDefaults->Erase( nId );
+
+ return true;
+ }
+
+ return false;
+}
+
+void lcl_extractHoriOrient(std::vector<beans::PropertyValue>& rFrameProperties, sal_Int32& nHoriOrient)
+{
+ // Shifts the frame left by the given value.
+ for (const beans::PropertyValue & rFrameProperty : rFrameProperties)
+ {
+ if (rFrameProperty.Name == "HoriOrient")
+ {
+ sal_Int32 nValue = rFrameProperty.Value.get<sal_Int32>();
+ if (nValue != text::HoriOrientation::NONE)
+ nHoriOrient = nValue;
+ return;
+ }
+ }
+}
+
+void lcl_DecrementHoriOrientPosition(std::vector<beans::PropertyValue>& rFrameProperties, sal_Int32 nAmount)
+{
+ // Shifts the frame left by the given value.
+ for (beans::PropertyValue & rPropertyValue : rFrameProperties)
+ {
+ if (rPropertyValue.Name == "HoriOrientPosition")
+ {
+ sal_Int32 nValue = rPropertyValue.Value.get<sal_Int32>();
+ nValue -= nAmount;
+ rPropertyValue.Value <<= nValue;
+ return;
+ }
+ }
+}
+
+void lcl_adjustBorderDistance(TableInfo& rInfo, const table::BorderLine2& rLeftBorder,
+ const table::BorderLine2& rRightBorder)
+{
+ // MS Word appears to do these things to adjust the cell horizontal area:
+ //
+ // bll = left borderline width
+ // blr = right borderline width
+ // cea = cell's edit area rectangle
+ // cea_w = cea width
+ // cml = cell's left margin (padding) defined in cell settings
+ // cmr = cell's right margin (padding) defined in cell settings
+ // cw = cell width (distance between middles of left borderline and right borderline)
+ // pad_l = actual cea left padding = (its left pos relative to middle of bll)
+ // pad_r = actual cea right padding = abs (its right pos relative to middle of blr)
+ //
+ // pad_l = max(bll/2, cml) -> cea does not overlap left borderline
+ // cea_w = cw-max(pad_l+blr/2, cml+cmr) -> cea does not overlap right borderline
+ // pad_r = max(pad_l+blr/2, cml+cmr) - pad_l
+ //
+ // It means that e.g. for border widths of 6 pt (~2.12 mm), left margin 0 mm, and right margin
+ // 2 mm, actual left and right margins will (unexpectedly) coincide with inner edges of cell's
+ // borderlines - the right margin won't create spacing between right of edit rectangle and the
+ // inner edge of right borderline.
+
+ const sal_Int32 nActualL
+ = std::max<sal_Int32>(rLeftBorder.LineWidth / 2, rInfo.nLeftBorderDistance);
+ const sal_Int32 nActualR
+ = std::max<sal_Int32>(nActualL + rRightBorder.LineWidth / 2,
+ rInfo.nLeftBorderDistance + rInfo.nRightBorderDistance)
+ - nActualL;
+ rInfo.nLeftBorderDistance = nActualL;
+ rInfo.nRightBorderDistance = nActualR;
+}
+
+}
+
+TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo,
+ std::vector<beans::PropertyValue>& rFrameProperties,
+ bool bConvertToFloatingInFootnote)
+{
+ // will receive the table style if any
+ TableStyleSheetEntry* pTableStyle = nullptr;
+
+ if( m_aTableProperties )
+ {
+ //create properties from the table attributes
+ //...pPropMap->Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
+ //pPropMap->Insert( PROP_HORI_ORIENT, uno::makeAny( text::HoriOrientation::RIGHT ));
+ sal_Int32 nGapHalf = 0;
+ sal_Int32 nLeftMargin = 0;
+
+ comphelper::SequenceAsHashMap aGrabBag;
+
+ if (nullptr != m_rDMapper_Impl.getTableManager().getCurrentTableRealPosition())
+ {
+ TablePositionHandler *pTablePositions = m_rDMapper_Impl.getTableManager().getCurrentTableRealPosition();
+
+ uno::Sequence< beans::PropertyValue > aGrabBagTS{
+ comphelper::makePropertyValue("bottomFromText", pTablePositions->getBottomFromText()),
+ comphelper::makePropertyValue("horzAnchor", pTablePositions->getHorzAnchor()),
+ comphelper::makePropertyValue("leftFromText", pTablePositions->getLeftFromText()),
+ comphelper::makePropertyValue("rightFromText", pTablePositions->getRightFromText()),
+ comphelper::makePropertyValue("tblpX", pTablePositions->getX()),
+ comphelper::makePropertyValue("tblpXSpec", pTablePositions->getXSpec()),
+ comphelper::makePropertyValue("tblpY", pTablePositions->getY()),
+ comphelper::makePropertyValue("tblpYSpec", pTablePositions->getYSpec()),
+ comphelper::makePropertyValue("topFromText", pTablePositions->getTopFromText()),
+ comphelper::makePropertyValue("vertAnchor", pTablePositions->getVertAnchor())
+ };
+
+ aGrabBag["TablePosition"] <<= aGrabBagTS;
+ }
+ else if (bConvertToFloatingInFootnote)
+ {
+ // define empty "TablePosition" to avoid export temporary floating
+ aGrabBag["TablePosition"] = uno::Any();
+ }
+
+ std::optional<PropertyMap::Property> aTableStyleVal = m_aTableProperties->getProperty(META_PROP_TABLE_STYLE_NAME);
+ if(aTableStyleVal)
+ {
+ // Apply table style properties recursively
+ OUString sTableStyleName;
+ aTableStyleVal->second >>= sTableStyleName;
+ StyleSheetTablePtr pStyleSheetTable = m_rDMapper_Impl.GetStyleSheetTable();
+ const StyleSheetEntryPtr pStyleSheet = pStyleSheetTable->FindStyleSheetByISTD( sTableStyleName );
+ pTableStyle = dynamic_cast<TableStyleSheetEntry*>( pStyleSheet.get( ) );
+ m_aTableProperties->Erase( aTableStyleVal->first );
+
+ aGrabBag["TableStyleName"] <<= sTableStyleName;
+
+ if( pStyleSheet )
+ {
+ // First get the style properties, then the table ones
+ PropertyMapPtr pTableProps( m_aTableProperties.get() );
+ TablePropertyMapPtr pEmptyProps( new TablePropertyMap );
+
+ m_aTableProperties = pEmptyProps;
+
+ PropertyMapPtr pMergedProperties = pStyleSheet->GetMergedInheritedProperties(pStyleSheetTable);
+
+ table::BorderLine2 aBorderLine;
+ TableInfo rStyleInfo;
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_TOP_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleTopBorder"] <<= aBorderLine;
+ }
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_BOTTOM_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleBottomBorder"] <<= aBorderLine;
+ }
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_LEFT_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleLeftBorder"] <<= aBorderLine;
+ }
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_RIGHT_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleRightBorder"] <<= aBorderLine;
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("mergedProps");
+ if (pMergedProperties)
+ pMergedProperties->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ m_aTableProperties->InsertProps(pMergedProperties);
+ m_aTableProperties->InsertProps(pTableProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TableProperties");
+ m_aTableProperties->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+ if (pTableStyle)
+ {
+ // apply tblHeader setting of the table style
+ PropertyMapPtr pHeaderStyleProps = pTableStyle->GetProperties(CNF_FIRST_ROW);
+ if ( pHeaderStyleProps->getProperty(PROP_HEADER_ROW_COUNT) )
+ m_aTableProperties->Insert(PROP_HEADER_ROW_COUNT, uno::Any( sal_Int32(1)), false);
+ }
+ }
+ }
+
+ // This is the one preserving just all the table look attributes.
+ std::optional<PropertyMap::Property> oTableLook = m_aTableProperties->getProperty(META_PROP_TABLE_LOOK);
+ if (oTableLook)
+ {
+ aGrabBag["TableStyleLook"] = oTableLook->second;
+ m_aTableProperties->Erase(oTableLook->first);
+ }
+
+ // This is just the "val" attribute's numeric value.
+ const std::optional<PropertyMap::Property> aTblLook = m_aTableProperties->getProperty(PROP_TBL_LOOK);
+ if(aTblLook)
+ {
+ aTblLook->second >>= rInfo.nTblLook;
+ m_aTableProperties->Erase( aTblLook->first );
+ }
+
+ // apply cell margin settings of the table style
+ const std::optional<PropertyMap::Property> oLeftMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_LEFT);
+ if (oLeftMargin)
+ {
+ oLeftMargin->second >>= rInfo.nLeftBorderDistance;
+ m_aTableProperties->Erase(oLeftMargin->first);
+ }
+ const std::optional<PropertyMap::Property> oRightMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_RIGHT);
+ if (oRightMargin)
+ {
+ oRightMargin->second >>= rInfo.nRightBorderDistance;
+ m_aTableProperties->Erase(oRightMargin->first);
+ }
+ const std::optional<PropertyMap::Property> oTopMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_TOP);
+ if (oTopMargin)
+ {
+ oTopMargin->second >>= rInfo.nTopBorderDistance;
+ m_aTableProperties->Erase(oTopMargin->first);
+ }
+ const std::optional<PropertyMap::Property> oBottomMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_BOTTOM);
+ if (oBottomMargin)
+ {
+ oBottomMargin->second >>= rInfo.nBottomBorderDistance;
+ m_aTableProperties->Erase(oBottomMargin->first);
+ }
+
+ // Set the table default attributes for the cells
+ rInfo.pTableDefaults->InsertProps(m_aTableProperties.get());
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TableDefaults");
+ rInfo.pTableDefaults->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ if (!aGrabBag.empty())
+ {
+ m_aTableProperties->Insert( PROP_TABLE_INTEROP_GRAB_BAG, uno::Any( aGrabBag.getAsConstPropertyValueList() ) );
+ }
+
+ m_aTableProperties->getValue( TablePropertyMap::GAP_HALF, nGapHalf );
+
+ std::optional<PropertyMap::Property> oLeftMarginFromStyle = m_aTableProperties->getProperty(PROP_LEFT_MARGIN);
+ if (oLeftMarginFromStyle)
+ {
+ oLeftMarginFromStyle->second >>= nLeftMargin;
+ // don't need to erase, we will push back the adjusted value
+ // of this (or the direct formatting, if that exists) later
+ }
+ m_aTableProperties->getValue( TablePropertyMap::LEFT_MARGIN, nLeftMargin );
+
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_LEFT,
+ rInfo.nLeftBorderDistance );
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_RIGHT,
+ rInfo.nRightBorderDistance );
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_TOP,
+ rInfo.nTopBorderDistance );
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_BOTTOM,
+ rInfo.nBottomBorderDistance );
+
+ table::TableBorderDistances aDistances;
+ aDistances.IsTopDistanceValid =
+ aDistances.IsBottomDistanceValid =
+ aDistances.IsLeftDistanceValid =
+ aDistances.IsRightDistanceValid = true;
+ aDistances.TopDistance = static_cast<sal_Int16>( rInfo.nTopBorderDistance );
+ aDistances.BottomDistance = static_cast<sal_Int16>( rInfo.nBottomBorderDistance );
+ aDistances.LeftDistance = static_cast<sal_Int16>( rInfo.nLeftBorderDistance );
+ aDistances.RightDistance = static_cast<sal_Int16>( rInfo.nRightBorderDistance );
+
+ m_aTableProperties->Insert( PROP_TABLE_BORDER_DISTANCES, uno::Any( aDistances ) );
+
+ if (!rFrameProperties.empty())
+ lcl_DecrementHoriOrientPosition(rFrameProperties, rInfo.nLeftBorderDistance);
+
+ // Set table above/bottom spacing to 0.
+ m_aTableProperties->Insert( PROP_TOP_MARGIN, uno::Any( sal_Int32( 0 ) ) );
+ m_aTableProperties->Insert( PROP_BOTTOM_MARGIN, uno::Any( sal_Int32( 0 ) ) );
+
+ //table border settings
+ table::TableBorder aTableBorder;
+ table::BorderLine2 aBorderLine, aLeftBorder, aRightBorder;
+
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_TOP_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.TopLine = aBorderLine;
+ aTableBorder.IsTopLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_BOTTOM_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.BottomLine = aBorderLine;
+ aTableBorder.IsBottomLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_LEFT_BORDER, rInfo, aLeftBorder))
+ {
+ aTableBorder.LeftLine = aLeftBorder;
+ aTableBorder.IsLeftLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_RIGHT_BORDER, rInfo,
+ aRightBorder))
+ {
+ aTableBorder.RightLine = aRightBorder;
+ aTableBorder.IsRightLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), META_PROP_HORIZONTAL_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.HorizontalLine = aBorderLine;
+ aTableBorder.IsHorizontalLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), META_PROP_VERTICAL_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.VerticalLine = aBorderLine;
+ aTableBorder.IsVerticalLineValid = true;
+ }
+
+ aTableBorder.Distance = 0;
+ aTableBorder.IsDistanceValid = false;
+
+ m_aTableProperties->Insert( PROP_TABLE_BORDER, uno::Any( aTableBorder ) );
+
+#ifdef DBG_UTIL
+ lcl_debug_TableBorder(aTableBorder);
+#endif
+
+ // Table position in Office is computed in 2 different ways :
+ // - top level tables: the goal is to have in-cell text starting at table indent pos (tblInd),
+ // so table's position depends on table's cells margin
+ // - nested tables: the goal is to have left-most border starting at table_indent pos
+
+ // Only top level table position depends on border width of Column A.
+ if ( !m_aCellProperties.empty() && !m_aCellProperties[0].empty() )
+ {
+ // aLeftBorder already contains tblBorder; overwrite if cell is different.
+ std::optional<PropertyMap::Property> aCellBorder
+ = m_aCellProperties[0][0]->getProperty(PROP_LEFT_BORDER);
+ if ( aCellBorder )
+ aCellBorder->second >>= aLeftBorder;
+ aCellBorder = m_aCellProperties[0][0]->getProperty(PROP_RIGHT_BORDER);
+ if (aCellBorder)
+ aCellBorder->second >>= aRightBorder;
+ }
+ if (rInfo.nNestLevel == 1 && aLeftBorder.LineWidth && !rFrameProperties.empty())
+ {
+ lcl_DecrementHoriOrientPosition(rFrameProperties, aLeftBorder.LineWidth * 0.5);
+ }
+ lcl_adjustBorderDistance(rInfo, aLeftBorder, aRightBorder);
+
+ // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level tables are handled the same as nested tables;
+ // the default behavior when DOCX doesn't define "compatibilityMode" option is to add the cell spacing
+
+ // Undefined should not be possible any more for DOCX, but it is for RTF.
+ // In any case, continue to treat undefined as version 12 during import.
+ sal_Int32 nMode = m_rDMapper_Impl.GetSettingsTable()->GetWordCompatibilityMode();
+
+ if (((nMode < 0) || (0 < nMode && nMode <= 14)) && rInfo.nNestLevel == 1)
+ {
+ const sal_Int32 nAdjustedMargin = nLeftMargin - nGapHalf - rInfo.nLeftBorderDistance;
+ m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::Any( nAdjustedMargin ) );
+ }
+ else
+ {
+ // Writer starts a table in the middle of the border.
+ // Word starts a table at the left edge of the border,
+ // so emulate that by adding the half the width. (also see docxattributeoutput)
+ if ( rInfo.nNestLevel > 1 && nLeftMargin < 0 )
+ nLeftMargin = 0;
+ const sal_Int32 nAdjustedMargin = nLeftMargin - nGapHalf + (aLeftBorder.LineWidth / 2);
+ m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::Any( nAdjustedMargin ) );
+ }
+
+ sal_Int32 nTableWidth = 0;
+ sal_Int32 nTableWidthType = text::SizeType::FIX;
+ m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH, nTableWidth );
+ m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType );
+ if( nTableWidthType == text::SizeType::FIX )
+ {
+ if( nTableWidth > 0 )
+ m_aTableProperties->Insert( PROP_WIDTH, uno::Any( nTableWidth ));
+ else
+ {
+ // tdf#109524: If there is no width for the table, make it simply 100% by default.
+ // TODO: use cell contents to evaluate width (according to ECMA-376-1:2016 17.18.87)
+ nTableWidth = 100;
+ nTableWidthType = text::SizeType::VARIABLE;
+ }
+ }
+ if (nTableWidthType != text::SizeType::FIX)
+ {
+ m_aTableProperties->Insert( PROP_RELATIVE_WIDTH, uno::Any( sal_Int16( nTableWidth ) ) );
+ m_aTableProperties->Insert( PROP_IS_WIDTH_RELATIVE, uno::Any( true ) );
+ }
+
+ sal_Int32 nHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
+ // Fetch Horizontal Orientation in rFrameProperties if not set in m_aTableProperties
+ if ( !m_aTableProperties->getValue( TablePropertyMap::HORI_ORIENT, nHoriOrient ) )
+ lcl_extractHoriOrient( rFrameProperties, nHoriOrient );
+ m_aTableProperties->Insert( PROP_HORI_ORIENT, uno::Any( sal_Int16(nHoriOrient) ) );
+ //fill default value - if not available
+ m_aTableProperties->Insert( PROP_HEADER_ROW_COUNT, uno::Any( sal_Int32(0)), false);
+
+ // if table is only a single row, and row is set as don't split, set the same value for the whole table.
+ if( m_aRowProperties.size() == 1 && m_aRowProperties[0] )
+ {
+ std::optional<PropertyMap::Property> oSplitAllowed = m_aRowProperties[0]->getProperty(PROP_IS_SPLIT_ALLOWED);
+ if( oSplitAllowed )
+ {
+ bool bRowCanSplit = true;
+ oSplitAllowed->second >>= bRowCanSplit;
+ if( !bRowCanSplit )
+ m_aTableProperties->Insert( PROP_SPLIT, uno::Any(bRowCanSplit) );
+ }
+ }
+
+ rInfo.aTableProperties = m_aTableProperties->GetPropertyValues();
+ rInfo.aTablePropertyIds = m_aTableProperties->GetPropertyIds();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("debug.tableprops");
+ m_aTableProperties->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ }
+
+ return pTableStyle;
+}
+
+CellPropertyValuesSeq_t DomainMapperTableHandler::endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("getCellProperties");
+#endif
+
+ CellPropertyValuesSeq_t aCellProperties( m_aCellProperties.size() );
+
+ if ( m_aCellProperties.empty() )
+ {
+ #ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+ #endif
+ return aCellProperties;
+ }
+ // std::vector< std::vector<PropertyMapPtr> > m_aCellProperties
+ PropertyMapVector2::const_iterator aRowOfCellsIterator = m_aCellProperties.begin();
+ PropertyMapVector2::const_iterator aRowOfCellsIteratorEnd = m_aCellProperties.end();
+ PropertyMapVector2::const_iterator aLastRowIterator = m_aCellProperties.end() - 1;
+ sal_Int32 nRow = 0;
+
+ css::uno::Sequence<css::beans::PropertyValues>* pCellProperties = aCellProperties.getArray();
+ PropertyMapVector1::const_iterator aRowIter = m_aRowProperties.begin();
+ while( aRowOfCellsIterator != aRowOfCellsIteratorEnd )
+ {
+ //aRowOfCellsIterator points to a vector of PropertyMapPtr
+ PropertyMapVector1::const_iterator aCellIterator = aRowOfCellsIterator->begin();
+ PropertyMapVector1::const_iterator aCellIteratorEnd = aRowOfCellsIterator->end();
+
+ sal_Int32 nRowStyleMask = 0;
+
+ if (aRowOfCellsIterator==m_aCellProperties.begin())
+ {
+ if(rInfo.nTblLook&0x20)
+ nRowStyleMask |= CNF_FIRST_ROW; // first row style used
+ }
+ else if (aRowOfCellsIterator==aLastRowIterator)
+ {
+ if(rInfo.nTblLook&0x40)
+ nRowStyleMask |= CNF_LAST_ROW; // last row style used
+ }
+ else if (*aRowIter && (*aRowIter)->isSet(PROP_TBL_HEADER))
+ nRowStyleMask |= CNF_FIRST_ROW; // table header implies first row
+ if(!nRowStyleMask) // if no row style used yet
+ {
+ // banding used only if not first and or last row style used
+ if(!(rInfo.nTblLook&0x200))
+ { // hbanding used
+ int n = nRow + 1;
+ if(rInfo.nTblLook&0x20)
+ n++;
+ if(n & 1)
+ nRowStyleMask = CNF_ODD_HBAND;
+ else
+ nRowStyleMask = CNF_EVEN_HBAND;
+ }
+ }
+
+ // Note that this is intentionally called "cell" and not "column".
+ // Don't make the mistake that all cell x's will be in the same column.
+ // Merged cells (grid span) in a row will affect the actual column. (fake cells were added to handle gridBefore/After)
+ sal_Int32 nCell = 0;
+ pCellProperties[nRow].realloc( aRowOfCellsIterator->size() );
+ beans::PropertyValues* pSingleCellProperties = pCellProperties[nRow].getArray();
+
+ while( aCellIterator != aCellIteratorEnd )
+ {
+ PropertyMapPtr pAllCellProps( new PropertyMap );
+
+ PropertyMapVector1::const_iterator aLastCellIterator = aRowOfCellsIterator->end() - 1;
+ bool bIsEndCol = aCellIterator == aLastCellIterator;
+ bool bIsEndRow = aRowOfCellsIterator == aLastRowIterator;
+
+ //aCellIterator points to a PropertyMapPtr;
+ if( *aCellIterator )
+ {
+ // remove directly applied insideV/H borders since they are meaningless without a context (tdf#82177)
+ (*aCellIterator)->Erase(META_PROP_VERTICAL_BORDER);
+ (*aCellIterator)->Erase(META_PROP_HORIZONTAL_BORDER);
+
+ pAllCellProps->InsertProps(rInfo.pTableDefaults);
+
+ sal_Int32 nCellStyleMask = 0;
+ if (aCellIterator==aRowOfCellsIterator->begin())
+ {
+ if(rInfo.nTblLook&0x80)
+ nCellStyleMask = CNF_FIRST_COLUMN; // first col style used
+ }
+ else if (bIsEndCol)
+ {
+ if(rInfo.nTblLook&0x100)
+ nCellStyleMask = CNF_LAST_COLUMN; // last col style used
+ }
+ if(!nCellStyleMask) // if no cell style is used yet
+ {
+ if(!(rInfo.nTblLook&0x400))
+ { // vbanding used
+ int n = nCell + 1;
+ if(rInfo.nTblLook&0x80)
+ n++;
+ if(n & 1)
+ nCellStyleMask = CNF_ODD_VBAND;
+ else
+ nCellStyleMask = CNF_EVEN_VBAND;
+ }
+ }
+ sal_Int32 nCnfStyleMask = nCellStyleMask + nRowStyleMask;
+ if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_FIRST_ROW)
+ nCnfStyleMask |= CNF_FIRST_ROW_FIRST_COLUMN;
+ else if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_LAST_ROW)
+ nCnfStyleMask |= CNF_LAST_ROW_FIRST_COLUMN;
+ else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_FIRST_ROW)
+ nCnfStyleMask |= CNF_FIRST_ROW_LAST_COLUMN;
+ else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_LAST_ROW)
+ nCnfStyleMask |= CNF_LAST_ROW_LAST_COLUMN;
+
+ if ( rInfo.pTableStyle )
+ {
+ PropertyMapPtr pStyleProps = rInfo.pTableStyle->GetProperties( nCnfStyleMask );
+
+ // Check if we need to clean up some empty border definitions to match what Word does.
+ static const PropertyIds pBorders[] =
+ {
+ PROP_TOP_BORDER, PROP_LEFT_BORDER, PROP_BOTTOM_BORDER, PROP_RIGHT_BORDER
+ };
+ for (const PropertyIds& rBorder : pBorders)
+ {
+ std::optional<PropertyMap::Property> oStyleCellBorder = pStyleProps->getProperty(rBorder);
+ std::optional<PropertyMap::Property> oDirectCellBorder = (*aCellIterator)->getProperty(rBorder);
+ if (oStyleCellBorder && oDirectCellBorder)
+ {
+ // We have a cell border from the table style and as direct formatting as well.
+ table::BorderLine2 aStyleCellBorder = oStyleCellBorder->second.get<table::BorderLine2>();
+ table::BorderLine2 aDirectCellBorder = oDirectCellBorder->second.get<table::BorderLine2>();
+ if (aStyleCellBorder.LineStyle != table::BorderLineStyle::NONE && aDirectCellBorder.LineStyle == table::BorderLineStyle::NONE)
+ {
+ // The style one would be visible, but then cleared away as direct formatting.
+ // Delete both, so that table formatting can become visible.
+ pStyleProps->Erase(rBorder);
+ (*aCellIterator)->Erase(rBorder);
+ }
+ else
+ {
+ std::optional<PropertyMap::Property> oTableBorder = rInfo.pTableBorders->getProperty(rBorder);
+ if (oTableBorder)
+ {
+ table::BorderLine2 aTableBorder = oTableBorder->second.get<table::BorderLine2>();
+ // Both style and direct formatting says that the cell has no border.
+ bool bNoCellBorder = aStyleCellBorder.LineStyle == table::BorderLineStyle::NONE && aDirectCellBorder.LineStyle == table::BorderLineStyle::NONE;
+ if (aTableBorder.LineStyle != table::BorderLineStyle::NONE && bNoCellBorder)
+ {
+ // But at a table-level, there is a border, then again delete both cell properties.
+ pStyleProps->Erase(rBorder);
+ (*aCellIterator)->Erase(rBorder);
+ }
+ }
+ }
+ }
+ }
+
+ pAllCellProps->InsertProps( pStyleProps );
+ }
+
+ // Remove properties from style/row that aren't allowed in cells
+ pAllCellProps->Erase( PROP_HEADER_ROW_COUNT );
+ pAllCellProps->Erase( PROP_TBL_HEADER );
+
+ // Then add the cell properties
+ pAllCellProps->InsertProps(*aCellIterator);
+ std::swap(*(*aCellIterator), *pAllCellProps );
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("cell");
+ TagLogger::getInstance().attribute("cell", nCell);
+ TagLogger::getInstance().attribute("row", nRow);
+#endif
+
+ // Do not apply horizontal and vertical borders to a one cell table.
+ if (m_aCellProperties.size() <= 1 && aRowOfCellsIterator->size() <= 1)
+ {
+ rInfo.pTableBorders->Erase(META_PROP_HORIZONTAL_BORDER);
+ rInfo.pTableBorders->Erase(META_PROP_VERTICAL_BORDER);
+ }
+ // Do not apply vertical borders to a one column table.
+ else if (m_aCellProperties.size() > 1 && aRowOfCellsIterator->size() <= 1)
+ {
+ bool isOneCol = true;
+ for (size_t i = nRow; i < m_aCellProperties.size(); i++)
+ {
+ if (m_aCellProperties[i].size() > 1)
+ {
+ isOneCol = false;
+ break;
+ }
+ }
+ if (isOneCol)
+ rInfo.pTableBorders->Erase(META_PROP_VERTICAL_BORDER);
+ }
+ // Do not apply horizontal borders to a one row table.
+ else if (m_aCellProperties.size() == 1 && aRowOfCellsIterator->size() > 1)
+ {
+ rInfo.pTableBorders->Erase(META_PROP_HORIZONTAL_BORDER);
+ }
+
+ // tdf#129452 Checking if current cell is vertically merged with all the other cells below to the bottom.
+ // This must be done in order to apply the bottom border of the table to the first cell in a vertical merge.
+ std::optional<PropertyMap::Property> oProp = m_aCellProperties[nRow][nCell]->getProperty(PROP_VERTICAL_MERGE);
+ bool bMergedVertically = oProp && oProp->second.get<bool>(); // starting cell
+ if ( bMergedVertically )
+ {
+ const sal_uInt32 nColumn = m_rDMapper_Impl.getTableManager().findColumn(nRow, nCell);
+ sal_Int32 nLastMergedRow = 0;
+ for (size_t i = nRow + 1; bMergedVertically && i < m_aCellProperties.size(); i++)
+ {
+ const sal_uInt32 nColumnCell = m_rDMapper_Impl.getTableManager().findColumnCell(i, nColumn);
+ if ( m_aCellProperties[i].size() > sal::static_int_cast<std::size_t>(nColumnCell) )
+ {
+ oProp = m_aCellProperties[i][nColumnCell]->getProperty(PROP_VERTICAL_MERGE);
+ bMergedVertically = oProp && !oProp->second.get<bool>(); //continuing cell
+ if ( bMergedVertically )
+ nLastMergedRow = i;
+ }
+ else
+ bMergedVertically = false;
+ }
+
+ // Only consider the bottom border setting from the last merged cell.
+ // Note: in MSO, left/right apply per-unmerged-row. Can't do that in LO, so just using the top cell's borders should be fine.
+ if ( nRow < nLastMergedRow )
+ {
+ (*aCellIterator)->Erase(PROP_BOTTOM_BORDER);
+ const sal_uInt32 nColumnCell = m_rDMapper_Impl.getTableManager().findColumnCell(nLastMergedRow, nColumn);
+ lcl_mergeBorder( PROP_BOTTOM_BORDER, m_aCellProperties[nLastMergedRow][nColumnCell], *aCellIterator );
+ }
+ }
+
+ const sal_uInt32 nFirstCell = m_rDMapper_Impl.getTableManager().getGridBefore(nRow);
+ const sal_uInt32 nLastCell = m_aCellProperties[nRow].size() - m_rDMapper_Impl.getTableManager().getGridAfter(nRow) - 1;
+ lcl_computeCellBorders( rInfo.pTableBorders, *aCellIterator, nCell, nFirstCell, nLastCell, nRow, bIsEndRow, bMergedVertically );
+
+ //now set the default left+right border distance TODO: there's an sprm containing the default distance!
+ aCellIterator->get()->Insert( PROP_LEFT_BORDER_DISTANCE,
+ uno::Any(rInfo.nLeftBorderDistance ), false);
+ aCellIterator->get()->Insert( PROP_RIGHT_BORDER_DISTANCE,
+ uno::Any(rInfo.nRightBorderDistance ), false);
+ aCellIterator->get()->Insert( PROP_TOP_BORDER_DISTANCE,
+ uno::Any(rInfo.nTopBorderDistance ), false);
+ aCellIterator->get()->Insert( PROP_BOTTOM_BORDER_DISTANCE,
+ uno::Any(rInfo.nBottomBorderDistance ), false);
+
+ // Horizontal merge is not a UNO property, extract that info here to rMerges, and then remove it from the map.
+ const std::optional<PropertyMap::Property> aHorizontalMergeVal = (*aCellIterator)->getProperty(PROP_HORIZONTAL_MERGE);
+ if (aHorizontalMergeVal)
+ {
+ if (aHorizontalMergeVal->second.get<bool>())
+ {
+ // first cell in a merge
+ HorizontallyMergedCell aMerge(nRow, nCell);
+ rMerges.push_back(aMerge);
+ }
+ else if (!rMerges.empty())
+ {
+ // resuming an earlier merge
+ HorizontallyMergedCell& rMerge = rMerges.back();
+ rMerge.m_nLastRow = nRow;
+ rMerge.m_nLastCol = nCell;
+ }
+ (*aCellIterator)->Erase(PROP_HORIZONTAL_MERGE);
+ }
+ pSingleCellProperties[nCell] = (*aCellIterator)->GetPropertyValues();
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+ }
+ ++nCell;
+ ++aCellIterator;
+ }
+ ++nRow;
+ ++aRowOfCellsIterator;
+ ++aRowIter;
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+ return aCellProperties;
+}
+
+/// Do all cells in this row have a CellHideMark property?
+static bool lcl_hideMarks(PropertyMapVector1& rCellProperties)
+{
+ for (const PropertyMapPtr & p : rCellProperties)
+ {
+ // if anything is vertically merged, the row must not be set to fixed
+ // as Writer's layout doesn't handle that well
+ if (!p->isSet(PROP_CELL_HIDE_MARK) || p->isSet(PROP_VERTICAL_MERGE))
+ return false;
+ }
+ return true;
+}
+
+/// Are all cells in this row empty?
+static bool lcl_emptyRow(std::vector<RowSequence_t>& rTableRanges, sal_Int32 nRow)
+{
+ if (nRow >= static_cast<sal_Int32>(rTableRanges.size()))
+ {
+ SAL_WARN("writerfilter.dmapper", "m_aCellProperties not in sync with rTableRanges?");
+ return false;
+ }
+
+ const RowSequence_t rRowSeq = rTableRanges[nRow];
+ if (!rRowSeq.hasElements())
+ {
+ SAL_WARN("writerfilter.dmapper", "m_aCellProperties not in sync with rTableRanges?");
+ return false;
+ }
+
+ if (!rRowSeq[0][0].is())
+ {
+ // This can happen when we can't import the table, e.g. we're inside a
+ // comment.
+ SAL_WARN("writerfilter.dmapper", "rRowSeq[0][0] is an empty reference");
+ return false;
+ }
+
+ uno::Reference<text::XTextRangeCompare> xTextRangeCompare(rRowSeq[0][0]->getText(), uno::UNO_QUERY);
+ try
+ {
+ // See SwXText::Impl::ConvertCell(), we need to compare the start of
+ // the start and the end of the end. However for our text ranges, only
+ // the starts are set, so compareRegionStarts() does what we need.
+ bool bRangesAreNotEqual = std::any_of(rRowSeq.begin(), rRowSeq.end(),
+ [&xTextRangeCompare](const CellSequence_t& rCellSeq) {
+ return xTextRangeCompare->compareRegionStarts(rCellSeq[0], rCellSeq[1]) != 0; });
+ if (bRangesAreNotEqual)
+ return false;
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "compareRegionStarts() failed");
+ return false;
+ }
+ return true;
+}
+
+css::uno::Sequence<css::beans::PropertyValues> DomainMapperTableHandler::endTableGetRowProperties()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("getRowProperties");
+#endif
+
+ css::uno::Sequence<css::beans::PropertyValues> aRowProperties( m_aRowProperties.size() );
+ auto aRowPropertiesRange = asNonConstRange(aRowProperties);
+ sal_Int32 nRow = 0;
+ for( const auto& rRow : m_aRowProperties )
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("rowProps.row");
+#endif
+ if (rRow)
+ {
+ //set default to 'break across pages"
+ rRow->Insert( PROP_IS_SPLIT_ALLOWED, uno::Any(true ), false );
+ // tblHeader is only our property, remove before the property map hits UNO
+ rRow->Erase(PROP_TBL_HEADER);
+
+ if (lcl_hideMarks(m_aCellProperties[nRow]) && lcl_emptyRow(m_aTableRanges, nRow))
+ {
+ // We have CellHideMark on all cells, and also all cells are empty:
+ // Force the row height to be exactly as specified, and not just as the minimum suggestion.
+ rRow->Insert(PROP_SIZE_TYPE, uno::Any(text::SizeType::FIX));
+ }
+
+ aRowPropertiesRange[nRow] = rRow->GetPropertyValues();
+#ifdef DBG_UTIL
+ rRow->dumpXml();
+ lcl_DumpPropertyValues(aRowProperties[nRow]);
+#endif
+ }
+ ++nRow;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+ return aRowProperties;
+}
+
+// table style has got bigger precedence than docDefault style,
+// but lower precedence than the paragraph styles and direct paragraph formatting
+void DomainMapperTableHandler::ApplyParagraphPropertiesFromTableStyle(TableParagraph rParaProp, std::vector< PropertyIds > aAllTableParaProperties, const css::beans::PropertyValues rCellProperties)
+{
+ for( auto const& eId : aAllTableParaProperties )
+ {
+ // apply paragraph and character properties of the table style on table paragraphs
+ // if there is no direct paragraph formatting
+ bool bIsParaLevel = rParaProp.m_pPropertyMap->isSet(eId);
+ if ( !bIsParaLevel || isCharacterProperty(eId) )
+ {
+ if ( (eId == PROP_PARA_LEFT_MARGIN || eId == PROP_PARA_FIRST_LINE_INDENT) &&
+ rParaProp.m_pPropertyMap->isSet(PROP_NUMBERING_RULES) )
+ {
+ // indentation of direct numbering has bigger precedence, than table style
+ continue;
+ }
+
+ OUString sPropertyName = getPropertyName(eId);
+
+ auto pCellProp = std::find_if(rCellProperties.begin(), rCellProperties.end(),
+ [&](const beans::PropertyValue& rProp) { return rProp.Name == sPropertyName; });
+ // this cell applies the table style property
+ if (pCellProp != rCellProperties.end())
+ {
+ bool bDocDefault;
+ // handle paragraph background color defined in CellColorHandler
+ if (eId == PROP_FILL_COLOR)
+ {
+ // table style defines paragraph background color, use the correct property name
+ auto pFillStyleProp = std::find_if(rCellProperties.begin(), rCellProperties.end(),
+ [](const beans::PropertyValue& rProp) { return rProp.Name == "FillStyle"; });
+ if ( pFillStyleProp != rCellProperties.end() &&
+ pFillStyleProp->Value == uno::Any(drawing::FillStyle_SOLID) )
+ {
+ sPropertyName = "ParaBackColor";
+ }
+ else
+ {
+ // FillStyle_NONE, skip table style usage for paragraph background color
+ continue;
+ }
+ }
+ OUString sParaStyleName;
+ rParaProp.m_rPropertySet->getPropertyValue("ParaStyleName") >>= sParaStyleName;
+ StyleSheetEntryPtr pEntry = m_rDMapper_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(sParaStyleName);
+ uno::Any aParaStyle = m_rDMapper_Impl.GetPropertyFromStyleSheet(eId, pEntry, true, true, &bDocDefault);
+ // A very strange compatibility rule says that the DEFAULT style's specified fontsize of 11 or 12
+ // or a specified left justify will always be overridden by the table-style.
+ // Normally this rule is applied, so always do this unless a compatSetting indicates otherwise.
+ bool bCompatOverride = false;
+ if ( (eId == PROP_CHAR_HEIGHT || eId == PROP_PARA_ADJUST) && sParaStyleName == m_rDMapper_Impl.GetDefaultParaStyleName() )
+ {
+ if ( eId == PROP_CHAR_HEIGHT )
+ bCompatOverride = aParaStyle == uno::Any(double(11)) || aParaStyle == uno::Any(double(12));
+ else if ( eId == PROP_PARA_ADJUST )
+ {
+ style::ParagraphAdjust eAdjust(style::ParagraphAdjust_CENTER);
+ aParaStyle >>= eAdjust;
+ bCompatOverride = eAdjust == style::ParagraphAdjust_LEFT;
+ }
+
+ // The wording is confusing here. Normally, the paragraph style DOES override the table-style.
+ // But for these two special situations, do not override the table-style. So the default is false.
+ // If false, then "CompatOverride" the normal behaviour, and apply the table-style's value.
+ bCompatOverride &= !m_rDMapper_Impl.GetSettingsTable()->GetCompatSettingValue(u"overrideTableStyleFontSizeAndJustification");
+ }
+
+ // use table style when no paragraph style setting or a docDefault value is applied instead of it
+ if ( aParaStyle == uno::Any() || bDocDefault || bCompatOverride ) try
+ {
+ // check property state of paragraph
+ uno::Reference<text::XParagraphCursor> xParagraph(
+ rParaProp.m_rEndParagraph->getText()->createTextCursorByRange(rParaProp.m_rEndParagraph), uno::UNO_QUERY_THROW );
+ // select paragraph
+ xParagraph->gotoStartOfParagraph( true );
+ uno::Reference< beans::XPropertyState > xParaProperties( xParagraph, uno::UNO_QUERY_THROW );
+ if ( xParaProperties->getPropertyState(sPropertyName) == css::beans::PropertyState_DEFAULT_VALUE )
+ {
+ // don't overwrite empty paragraph with table style, if it has a direct paragraph formatting
+ if ( bIsParaLevel && xParagraph->getString().getLength() == 0 )
+ continue;
+
+ if ( eId != PROP_FILL_COLOR )
+ {
+ // apply style setting when the paragraph doesn't modify it
+ rParaProp.m_rPropertySet->setPropertyValue( sPropertyName, pCellProp->Value );
+ }
+ else
+ {
+ // we need this for complete import of table-style based paragraph background color
+ rParaProp.m_rPropertySet->setPropertyValue( "FillColor", pCellProp->Value );
+ rParaProp.m_rPropertySet->setPropertyValue( "FillStyle", uno::Any(drawing::FillStyle_SOLID) );
+ }
+ }
+ else
+ {
+ // apply style setting only on text portions without direct modification of it
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xParagraph, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ while ( xRunEnum->hasMoreElements() )
+ {
+ uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference< beans::XPropertyState > xRunProperties( xRun, uno::UNO_QUERY_THROW );
+ if ( xRunProperties->getPropertyState(sPropertyName) == css::beans::PropertyState_DEFAULT_VALUE )
+ {
+ uno::Reference< beans::XPropertySet > xRunPropertySet( xRun, uno::UNO_QUERY_THROW );
+ xRunPropertySet->setPropertyValue( sPropertyName, pCellProp->Value );
+ }
+ }
+ }
+ }
+ catch ( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.dmapper", "Exception during table style correction");
+ }
+ }
+ }
+ }
+}
+
+// convert formula range identifier ABOVE, BELOW, LEFT and RIGHT
+static void lcl_convertFormulaRanges(const uno::Reference<text::XTextTable> & xTable)
+{
+ uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xTableRows(xTable->getRows(), uno::UNO_QUERY_THROW);
+ sal_Int32 nRows = xTableRows->getCount();
+ for (sal_Int32 nRow = 0; nRow < nRows; ++nRow)
+ {
+ for (sal_Int16 nCol = 0; nCol < MAXTABLECELLS; ++nCol)
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xCellProperties(xCellRange->getCellByPosition(nCol, nRow), uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aCellGrabBag;
+ xCellProperties->getPropertyValue("CellInteropGrabBag") >>= aCellGrabBag;
+ OUString sFormula;
+ bool bReplace = false;
+ for (const auto& rProp : std::as_const(aCellGrabBag))
+ {
+ if ( rProp.Name == "CellFormulaConverted" )
+ {
+ rProp.Value >>= sFormula;
+ struct RangeDirection
+ {
+ OUString m_sName;
+ sal_Int16 m_nCol;
+ sal_Int16 m_nRow;
+ };
+ static const RangeDirection pDirections[] =
+ {
+ { OUString(" LEFT "), -1, 0},
+ { OUString(" RIGHT "), 1, 0},
+ { OUString(" ABOVE "), 0, -1},
+ { OUString(" BELOW "), 0, 1 }
+ };
+ for (const RangeDirection& rRange : pDirections)
+ {
+ if ( sFormula.indexOf(rRange.m_sName) > -1 )
+ {
+ // range starts at the first cell above/below/left/right, but ends at the
+ // table border or at the first non-value cell after a value cell
+ bool bFoundFirst = false;
+ OUString sNextCell;
+ OUString sLastCell;
+ OUString sLastValueCell;
+ // walk through the cells of the range
+ try
+ {
+ sal_Int32 nCell = 0;
+ while (++nCell)
+ {
+ uno::Reference<beans::XPropertySet> xCell(
+ xCellRange->getCellByPosition(nCol + nCell * rRange.m_nCol, nRow + nCell * rRange.m_nRow),
+ uno::UNO_QUERY_THROW);
+ // empty cell or cell with text content is end of the range
+ uno::Reference<text::XText> xText(xCell, uno::UNO_QUERY_THROW);
+ sLastCell = xCell->getPropertyValue("CellName").get<OUString>();
+ if (sNextCell.isEmpty())
+ sNextCell = sLastCell;
+ try
+ {
+ // accept numbers with comma and percent
+ OUString sCellText = xText->getString().replace(',', '.');
+ if (sCellText.endsWith("%"))
+ sCellText = sCellText.copy(0, sCellText.getLength()-1);
+ boost::lexical_cast<double>(sCellText);
+ }
+ catch( boost::bad_lexical_cast const& )
+ {
+ if ( !bFoundFirst )
+ {
+ // still search value cells
+ continue;
+ }
+ else
+ {
+ // end of range
+ break;
+ }
+ }
+ sLastValueCell = sLastCell;
+ bFoundFirst = true;
+ }
+ }
+ catch ( const lang::IndexOutOfBoundsException & )
+ {
+ }
+
+ if ( !sNextCell.isEmpty() )
+ {
+ OUString sRange = "<" + sNextCell + ":" +
+ ( sLastValueCell.isEmpty() ? sLastCell : sLastValueCell ) + ">";
+ sFormula = sFormula.replaceAll(rRange.m_sName, sRange);
+ bReplace = true;
+ }
+ }
+ }
+
+ // update formula field
+ if (bReplace)
+ {
+ uno::Reference<text::XText> xCell(xCellRange->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCell, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ while ( xRunEnum->hasMoreElements() )
+ {
+ uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xRunProperties( xRun, uno::UNO_QUERY_THROW );
+ if ( xRunProperties->getPropertyValue("TextPortionType") == uno::Any(OUString("TextField")) )
+ {
+ uno::Reference<text::XTextField> const xField(xRunProperties->getPropertyValue("TextField").get<uno::Reference<text::XTextField>>());
+ uno::Reference< beans::XPropertySet > xFieldProperties( xField, uno::UNO_QUERY_THROW );
+ // cell can contain multiple text fields, but only one is handled now (~formula cell)
+ if ( rProp.Value != xFieldProperties->getPropertyValue("Content") )
+ continue;
+ xFieldProperties->setPropertyValue("Content", uno::Any(sFormula));
+ // update grab bag
+ auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aCellGrabBag);
+ beans::PropertyValue aValue;
+ aValue.Name = "CellFormulaConverted";
+ aValue.Value <<= sFormula;
+ aGrabBag.push_back(aValue);
+ xCellProperties->setPropertyValue("CellInteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+ }
+ }
+ }
+ }
+ }
+ catch ( const lang::IndexOutOfBoundsException & )
+ {
+ // jump to next table row
+ break;
+ }
+ }
+ }
+}
+
+void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTableStartsAtCellStart)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablehandler.endTable");
+#endif
+
+ // If we want to make this table a floating one.
+ std::vector<beans::PropertyValue> aFrameProperties = comphelper::sequenceToContainer<std::vector<beans::PropertyValue> >
+ (m_rDMapper_Impl.getTableManager().getCurrentTablePosition());
+ TableInfo aTableInfo;
+ aTableInfo.nNestLevel = nestedTableLevel;
+
+ // non-floating tables need floating in footnotes and endnotes, because
+ // Writer core cannot handle (i.e. save in ODT, copy, edit etc.) them otherwise
+ bool bConvertToFloating = aFrameProperties.empty() &&
+ nestedTableLevel <= 1 &&
+ m_rDMapper_Impl.IsInFootOrEndnote();
+ bool bFloating = !aFrameProperties.empty() || bConvertToFloating;
+
+ aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties, bConvertToFloating);
+ // expands to uno::Sequence< Sequence< beans::PropertyValues > >
+
+ std::vector<HorizontallyMergedCell> aMerges;
+ CellPropertyValuesSeq_t aCellProperties = endTableGetCellProperties(aTableInfo, aMerges);
+
+ css::uno::Sequence<css::beans::PropertyValues> aRowProperties = endTableGetRowProperties();
+
+#ifdef DBG_UTIL
+ lcl_DumpPropertyValueSeq(aRowProperties);
+#endif
+
+ if (!m_aTableRanges.empty())
+ {
+ uno::Reference<text::XTextRange> xStart;
+ uno::Reference<text::XTextRange> xEnd;
+
+ // fill empty frame properties to create an invisible frame around the table:
+ // hide frame borders and zero inner and outer frame margins
+ if (bConvertToFloating)
+ DomainMapper_Impl::fillEmptyFrameProperties(aFrameProperties, true);
+
+ // OOXML table style may contain paragraph properties, apply these on cell paragraphs
+ if ( m_aTableRanges[0].hasElements() && m_aTableRanges[0][0].hasElements() )
+ {
+ // collect all paragraph properties used in table styles
+ PropertyMapPtr pAllTableProps( new PropertyMap );
+ pAllTableProps->InsertProps(aTableInfo.pTableDefaults);
+ if ( aTableInfo.pTableStyle )
+ pAllTableProps->InsertProps(aTableInfo.pTableStyle->GetProperties( CNF_ALL ));
+ for (const auto& eId : pAllTableProps->GetPropertyIds())
+ {
+ if ( !isParagraphProperty(eId) && !isCharacterProperty(eId) )
+ pAllTableProps->Erase(eId);
+ }
+ std::vector< PropertyIds > aAllTableParaProperties = pAllTableProps->GetPropertyIds();
+
+ if ( !aAllTableParaProperties.empty() )
+ {
+ TableParagraphVectorPtr pTableParagraphs = m_rDMapper_Impl.getTableManager().getCurrentParagraphs();
+ for (size_t nRow = 0; nRow < m_aTableRanges.size(); ++nRow)
+ {
+ // Note that this is "cell" since you must not treat it as "column".
+ for (size_t nCell = 0; nCell < m_aTableRanges[nRow].size(); ++nCell)
+ {
+ auto rStartPara = m_aTableRanges[nRow][nCell][0];
+ if (!rStartPara.is())
+ continue;
+ auto rEndPara = m_aTableRanges[nRow][nCell][1];
+ uno::Reference<text::XTextRangeCompare> xTextRangeCompare(rStartPara->getText(), uno::UNO_QUERY);
+ bool bApply = false;
+ // search paragraphs of the cell
+ std::vector<TableParagraph>::iterator aIt = pTableParagraphs->begin();
+ while ( aIt != pTableParagraphs->end() ) try
+ {
+ if (!bApply && xTextRangeCompare->compareRegionStarts(rStartPara, aIt->m_rStartParagraph) == 0)
+ bApply = true;
+ if (bApply)
+ {
+ bool bEndOfApply = (xTextRangeCompare->compareRegionEnds(rEndPara, aIt->m_rEndParagraph) == 0);
+ // tdf#153891 handle missing cell properties (exception in style handling?)
+ if ( nCell < sal::static_int_cast<std::size_t>(aCellProperties[nRow].getLength()) )
+ ApplyParagraphPropertiesFromTableStyle(*aIt, aAllTableParaProperties, aCellProperties[nRow][nCell]);
+ // erase processed paragraph from list of pending paragraphs
+ aIt = pTableParagraphs->erase(aIt);
+ if (bEndOfApply)
+ break;
+ }
+ else
+ ++aIt;
+ }
+ catch( const lang::IllegalArgumentException & )
+ {
+ // skip compareRegion with nested tables
+ ++aIt;
+ }
+ }
+ }
+ }
+ }
+
+ // Additional checks: if we can do this.
+ if (bFloating && m_aTableRanges[0].hasElements() && m_aTableRanges[0][0].hasElements())
+ {
+ xStart = m_aTableRanges[0][0][0];
+ uno::Sequence< uno::Sequence< uno::Reference<text::XTextRange> > >& rLastRow = m_aTableRanges[m_aTableRanges.size() - 1];
+ if (rLastRow.hasElements())
+ {
+ const uno::Sequence< uno::Reference<text::XTextRange> >& rLastCell = rLastRow[rLastRow.getLength() - 1];
+ xEnd = rLastCell[1];
+ }
+ }
+ uno::Reference<text::XTextTable> xTable;
+ try
+ {
+ if (m_xText.is())
+ {
+ xTable = m_xText->convertToTable(comphelper::containerToSequence(m_aTableRanges), aCellProperties, aRowProperties, aTableInfo.aTableProperties);
+
+ if (xTable.is())
+ {
+ if (!aMerges.empty())
+ {
+ static const std::vector<std::u16string_view> aBorderNames
+ = { u"TopBorder", u"LeftBorder", u"BottomBorder", u"RightBorder" };
+
+ // Perform horizontal merges in reverse order, so the fact that merging changes the position of cells won't cause a problem for us.
+ for (std::vector<HorizontallyMergedCell>::reverse_iterator it = aMerges.rbegin(); it != aMerges.rend(); ++it)
+ {
+ uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xFirstCell(
+ xCellRange->getCellByPosition(it->m_nFirstCol, it->m_nFirstRow),
+ uno::UNO_QUERY_THROW);
+ OUString aFirst
+ = xFirstCell->getPropertyValue("CellName").get<OUString>();
+ // tdf#105852: Only try to merge if m_nLastCol is set (i.e. there were some merge continuation cells)
+ if (it->m_nLastCol != -1)
+ {
+ // Save border properties of the first cell
+ // before merge.
+ table::BorderLine2 aBorderValues[4];
+ for (size_t i = 0; i < aBorderNames.size(); ++i)
+ xFirstCell->getPropertyValue(OUString(aBorderNames[i]))
+ >>= aBorderValues[i];
+
+ uno::Reference<beans::XPropertySet> xLastCell(
+ xCellRange->getCellByPosition(it->m_nLastCol, it->m_nLastRow),
+ uno::UNO_QUERY_THROW);
+ OUString aLast
+ = xLastCell->getPropertyValue("CellName").get<OUString>();
+
+ uno::Reference<text::XTextTableCursor> xCursor = xTable->createCursorByCellName(aFirst);
+ xCursor->gotoCellByName(aLast, true);
+
+ xCursor->mergeRange();
+
+ // Handle conflicting properties: mergeRange()
+ // takes the last cell, Word takes the first
+ // cell.
+ for (size_t i = 0; i < aBorderNames.size(); ++i)
+ {
+ if (aBorderValues[i].LineStyle != table::BorderLineStyle::NONE)
+ xFirstCell->setPropertyValue(
+ OUString(aBorderNames[i]), uno::Any(aBorderValues[i]));
+ }
+ }
+ }
+ }
+
+ // convert special range IDs ABOVE, BELOW, LEFT and RIGHT
+ lcl_convertFormulaRanges(xTable);
+ }
+ }
+ }
+ catch ( const lang::IllegalArgumentException & )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.dmapper", "Conversion to table error");
+#ifdef DBG_UTIL
+ TagLogger::getInstance().chars(std::string("failed to import table!"));
+#endif
+ }
+ catch ( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.dmapper", "Exception during table creation");
+ }
+
+ // If we have a table with a start and an end position, we should make it a floating one.
+ // Unless the table had a foot or endnote, as Writer doesn't support those in TextFrames.
+ if (xTable.is() && xStart.is() && xEnd.is() && !m_bHadFootOrEndnote)
+ {
+ uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
+ bool bIsRelative = false;
+ xTableProperties->getPropertyValue("IsWidthRelative") >>= bIsRelative;
+ if (!bIsRelative)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "Width";
+ aValue.Value = xTableProperties->getPropertyValue("Width");
+ aFrameProperties.push_back(aValue);
+ }
+ else
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "FrameWidthPercent";
+ aValue.Value = xTableProperties->getPropertyValue("RelativeWidth");
+ aFrameProperties.push_back(aValue);
+
+ // Applying the relative width to the frame, needs to have the table width to be 100% of the frame width
+ xTableProperties->setPropertyValue("RelativeWidth", uno::Any(sal_Int16(100)));
+ }
+
+ // A non-zero left margin would move the table out of the frame, move the frame itself instead.
+ xTableProperties->setPropertyValue("LeftMargin", uno::Any(sal_Int32(0)));
+
+ if (nestedTableLevel >= 2)
+ {
+ // Floating tables inside a table always stay inside the cell.
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue("IsFollowingTextFlow", true));
+ }
+
+ // In case the document ends with a table, we're called after
+ // SectionPropertyMap::CloseSectionGroup(), so we'll have no idea
+ // about the text area width, nor can fix this by delaying the text
+ // frame conversion: just do it here.
+ // Also, when the anchor is within a table, then do it here as well,
+ // as xStart/xEnd would not point to the start/end at conversion
+ // time anyway.
+ // Next exception: it's pointless to delay the conversion if the
+ // table is not in the body text.
+ sal_Int32 nTableWidth = 0;
+ m_aTableProperties->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
+ sal_Int32 nTableWidthType = text::SizeType::FIX;
+ m_aTableProperties->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType);
+ if (m_rDMapper_Impl.GetSectionContext() && nestedTableLevel <= 1 && !m_rDMapper_Impl.IsInHeaderFooter())
+ {
+ m_rDMapper_Impl.m_aPendingFloatingTables.emplace_back(xStart, xEnd,
+ comphelper::containerToSequence(aFrameProperties),
+ nTableWidth, nTableWidthType, bConvertToFloating);
+ }
+ else
+ {
+ // m_xText points to the body text, get the current xText from m_rDMapper_Impl, in case e.g. we would be in a header.
+ uno::Reference<text::XTextAppendAndConvert> xTextAppendAndConvert(m_rDMapper_Impl.GetTopTextAppend(), uno::UNO_QUERY);
+ // Only execute the conversion if the table is not anchored at
+ // the start of an outer table cell, that's not yet
+ // implemented.
+ if (xTextAppendAndConvert.is() && !bTableStartsAtCellStart)
+ xTextAppendAndConvert->convertToTextFrame(xStart, xEnd, comphelper::containerToSequence(aFrameProperties));
+ }
+ }
+
+ // We're right after a table conversion.
+ m_rDMapper_Impl.m_bConvertedTable = true;
+ }
+
+ m_aTableProperties.clear();
+ m_aCellProperties.clear();
+ m_aRowProperties.clear();
+ m_bHadFootOrEndnote = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void DomainMapperTableHandler::startRow(const TablePropertyMapPtr& pProps)
+{
+ m_aRowProperties.push_back( pProps.get() );
+ m_aCellProperties.emplace_back( );
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("table.row");
+ if (pProps != nullptr)
+ pProps->dumpXml();
+#endif
+
+ m_aRowRanges.clear();
+}
+
+void DomainMapperTableHandler::endRow()
+{
+ m_aTableRanges.push_back(comphelper::containerToSequence(m_aRowRanges));
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void DomainMapperTableHandler::startCell(const css::uno::Reference< css::text::XTextRange > & start,
+ const TablePropertyMapPtr& pProps )
+{
+ sal_uInt32 nRow = m_aRowProperties.size();
+ if ( pProps )
+ m_aCellProperties[nRow - 1].push_back( pProps.get() );
+ else
+ {
+ // Adding an empty cell properties map to be able to get
+ // the table defaults properties
+ TablePropertyMapPtr pEmptyProps( new TablePropertyMap( ) );
+ m_aCellProperties[nRow - 1].push_back( pEmptyProps.get() );
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("table.cell");
+ TagLogger::getInstance().startElement("table.cell.start");
+ TagLogger::getInstance().chars(XTextRangeToString(start));
+ TagLogger::getInstance().endElement();
+ if (pProps)
+ pProps->printProperties();
+#endif
+
+ //add a new 'row' of properties
+ m_aCellRange.clear();
+ uno::Reference<text::XTextRange> xStart;
+ if (start)
+ xStart = start->getStart();
+ m_aCellRange.push_back(xStart);
+}
+
+void DomainMapperTableHandler::endCell(const css::uno::Reference< css::text::XTextRange > & end)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("table.cell.end");
+ TagLogger::getInstance().chars(XTextRangeToString(end));
+ TagLogger::getInstance().endElement();
+ TagLogger::getInstance().endElement();
+#endif
+
+ uno::Reference<text::XTextRange> xEnd;
+ if (end)
+ xEnd = end->getEnd();
+ m_aCellRange.push_back(xEnd);
+ m_aRowRanges.push_back(comphelper::containerToSequence(m_aCellRange));
+}
+
+void DomainMapperTableHandler::setHadFootOrEndnote(bool bHadFootOrEndnote)
+{
+ m_bHadFootOrEndnote = bHadFootOrEndnote;
+}
+
+DomainMapper_Impl& DomainMapperTableHandler::getDomainMapperImpl()
+{
+ return m_rDMapper_Impl;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.hxx b/writerfilter/source/dmapper/DomainMapperTableHandler.hxx
new file mode 100644
index 000000000..4e396b6b2
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.hxx
@@ -0,0 +1,126 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "PropertyMap.hxx"
+#include <vector>
+
+#include <com/sun/star/text/XTextAppendAndConvert.hpp>
+
+namespace writerfilter::dmapper {
+
+typedef css::uno::Sequence< css::uno::Reference< css::text::XTextRange > > CellSequence_t;
+typedef css::uno::Sequence<CellSequence_t> RowSequence_t;
+
+typedef css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValues> > CellPropertyValuesSeq_t;
+
+typedef std::vector<PropertyMapPtr> PropertyMapVector1;
+typedef std::vector<PropertyMapVector1> PropertyMapVector2;
+
+class DomainMapper_Impl;
+class TableStyleSheetEntry;
+struct TableInfo;
+
+/// A horizontally merged cell is in fact a range of cells till its merge is performed.
+struct HorizontallyMergedCell
+{
+ sal_Int32 m_nFirstRow;
+ sal_Int32 m_nFirstCol;
+ sal_Int32 m_nLastRow;
+ sal_Int32 m_nLastCol;
+ HorizontallyMergedCell(sal_Int32 nFirstRow, sal_Int32 nFirstCol)
+ : m_nFirstRow(nFirstRow)
+ , m_nFirstCol(nFirstCol)
+ , m_nLastRow(nFirstRow)
+ , m_nLastCol(-1)
+ {
+ }
+};
+
+/// Class to handle events generated by TableManager::resolveCurrentTable().
+class DomainMapperTableHandler final : public virtual SvRefBase
+{
+ css::uno::Reference<css::text::XTextAppendAndConvert> m_xText;
+ DomainMapper_Impl& m_rDMapper_Impl;
+ std::vector< css::uno::Reference<css::text::XTextRange> > m_aCellRange;
+ std::vector<CellSequence_t> m_aRowRanges;
+ std::vector<RowSequence_t> m_aTableRanges;
+
+ // properties
+ PropertyMapVector2 m_aCellProperties;
+ PropertyMapVector1 m_aRowProperties;
+ TablePropertyMapPtr m_aTableProperties;
+
+ /// Did we have a foot or endnote in this table?
+ bool m_bHadFootOrEndnote;
+
+ TableStyleSheetEntry * endTableGetTableStyle(TableInfo & rInfo,
+ std::vector<css::beans::PropertyValue>& rFrameProperties,
+ bool bConvertToFloating);
+ CellPropertyValuesSeq_t endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges);
+ css::uno::Sequence<css::beans::PropertyValues> endTableGetRowProperties();
+
+public:
+ typedef tools::SvRef<DomainMapperTableHandler> Pointer_t;
+
+ DomainMapperTableHandler(css::uno::Reference<css::text::XTextAppendAndConvert> const& xText,
+ DomainMapper_Impl& rDMapper_Impl);
+ ~DomainMapperTableHandler() override;
+
+ /**
+ Handle start of table.
+
+ @param pProps properties of the table
+ */
+ void startTable(const TablePropertyMapPtr& pProps);
+
+ void ApplyParagraphPropertiesFromTableStyle(TableParagraph rParaProp, std::vector< PropertyIds > aAllTableProperties, const css::beans::PropertyValues rCellProperties);
+
+ /// Handle end of table.
+ void endTable(unsigned int nestedTableLevel, bool bTableStartsAtCellStart);
+ /**
+ Handle start of row.
+
+ @param pProps properties of the row
+ */
+ void startRow(const TablePropertyMapPtr& pProps);
+ /// Handle end of row.
+ void endRow();
+ /**
+ Handle start of cell.
+
+ @param rT start handle of the cell
+ @param pProps properties of the cell
+ */
+ void startCell(const css::uno::Reference< css::text::XTextRange > & start, const TablePropertyMapPtr& pProps);
+ /**
+ Handle end of cell.
+
+ @param rT end handle of cell
+ */
+ void endCell(const css::uno::Reference< css::text::XTextRange > & end);
+
+ void setHadFootOrEndnote(bool bHadFootOrEndnote);
+
+ DomainMapper_Impl& getDomainMapperImpl();
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapperTableManager.cxx b/writerfilter/source/dmapper/DomainMapperTableManager.cxx
new file mode 100644
index 000000000..004f34971
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapperTableManager.cxx
@@ -0,0 +1,859 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <optional>
+#include "DomainMapperTableManager.hxx"
+#include "ConversionHelper.hxx"
+#include "MeasureHandler.hxx"
+#include "TagLogger.hxx"
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TableColumnSeparator.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <o3tl/numeric.hxx>
+#include <o3tl/safeint.hxx>
+#include <ooxml/resourceids.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <numeric>
+#include "TrackChangesHandler.hxx"
+#include <oox/token/tokens.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+using namespace ::std;
+
+DomainMapperTableManager::DomainMapperTableManager() :
+ m_nRow(0),
+ m_nGridSpan(1),
+ m_nHeaderRepeat(0),
+ m_nTableWidth(0),
+ m_bIsInShape(false),
+ m_bPushCurrentWidth(false),
+ m_bTableSizeTypeInserted(false),
+ m_nLayoutType(0),
+ m_pTablePropsHandler(new TablePropertiesHandler())
+{
+ m_pTablePropsHandler->SetTableManager( this );
+}
+
+
+DomainMapperTableManager::~DomainMapperTableManager()
+{
+}
+
+bool DomainMapperTableManager::attribute(Id nName, Value const & rValue)
+{
+ bool bRet = true;
+
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_TblLook_val:
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_TBL_LOOK, uno::Any(sal_Int32(rValue.getInt())));
+ insertTableProps(pPropMap);
+ m_aTableLook["val"] <<= static_cast<sal_Int32>(rValue.getInt());
+ }
+ break;
+ case NS_ooxml::LN_CT_TblLook_noVBand:
+ m_aTableLook["noVBand"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_noHBand:
+ m_aTableLook["noHBand"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_lastColumn:
+ m_aTableLook["lastColumn"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_lastRow:
+ m_aTableLook["lastRow"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_firstColumn:
+ m_aTableLook["firstColumn"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_firstRow:
+ m_aTableLook["firstRow"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ default:
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+void DomainMapperTableManager::finishTableLook()
+{
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(META_PROP_TABLE_LOOK, uno::Any(m_aTableLook.getAsConstPropertyValueList()));
+ m_aTableLook.clear();
+ insertTableProps(pPropMap);
+}
+
+bool DomainMapperTableManager::sprm(Sprm & rSprm)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.sprm");
+ string sSprm = rSprm.toString();
+ TagLogger::getInstance().chars(sSprm);
+ TagLogger::getInstance().endElement();
+#endif
+ bool bRet = TableManager::sprm(rSprm);
+ if( !bRet )
+ {
+ bRet = m_pTablePropsHandler->sprm( rSprm );
+ }
+
+ if ( !bRet )
+ {
+ bRet = true;
+ sal_uInt32 nSprmId = rSprm.getId();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = (pValue ? pValue->getInt() : 0);
+ switch ( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TblPrBase_tblW:
+ case NS_ooxml::LN_CT_TblPrBase_tblInd:
+ {
+ //contains unit and value
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ if (nSprmId == sal_uInt32(NS_ooxml::LN_CT_TblPrBase_tblInd))
+ {
+ pPropMap->setValue( TablePropertyMap::LEFT_MARGIN, pMeasureHandler->getMeasureValue() );
+ }
+ else
+ {
+ m_nTableWidth = pMeasureHandler->getMeasureValue();
+ if( m_nTableWidth )
+ {
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
+ m_bTableSizeTypeInserted = true;
+ }
+ else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_pct )
+ {
+ sal_Int32 nPercent = pMeasureHandler->getValue() / 50;
+ if(nPercent > 100)
+ nPercent = 100;
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, nPercent );
+ m_bTableSizeTypeInserted = true;
+ }
+ else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto )
+ {
+ /*
+ This attribute specifies the width type of table. This is used as part of the table layout
+ algorithm specified by the tblLayout element.(See 17.4.64 and 17.4.65 of the ISO/IEC 29500-1:2011.)
+ If this value is 'auto', the table layout has to use the preferred widths on the table items to generate
+ the final sizing of the table, but then must use the contents of each cell to determine final column widths.
+ (See 17.18.87 of the ISO/IEC 29500-1:2011.)
+ */
+ IntVectorPtr pCellWidths = getCurrentCellWidths();
+ // Check whether all cells have fixed widths in the given row of table.
+ bool bFixed = std::find(pCellWidths->begin(), pCellWidths->end(), -1) == pCellWidths->end();
+ if (!bFixed)
+ {
+ // Set the width type of table with 'Auto' and set the width value to 0 (as per grid values)
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, 0 );
+ m_bTableSizeTypeInserted = true;
+ }
+ else if (getTableDepth() > 1)
+ {
+ // tdf#131819 limiting the fix for nested tables temporarily
+ // TODO revert the fix for tdf#104876 and reopen it
+ m_bTableSizeTypeInserted = true;
+ }
+ }
+ }
+#ifdef DBG_UTIL
+ pPropMap->dumpXml();
+#endif
+ insertTableProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_tblHeader:
+ // if nIntValue == 1 then the row is a repeated header line
+ // to prevent later rows from increasing the repeating m_nHeaderRepeat is set to NULL when repeating stops
+ if( nIntValue > 0 && m_nHeaderRepeat == static_cast<int>(m_nRow) )
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ // FIXME: DOCX tables with more than 10 repeating header lines imported
+ // without repeating header lines to mimic an MSO workaround for its usability bug.
+ // Explanation: it's very hard to set and modify repeating header rows in Word,
+ // often resulting tables with a special workaround: setting all table rows as
+ // repeating header, because exceeding the pages by "unlimited" header rows turns off the
+ // table headers automatically in MSO. 10-row limit is a reasonable temporary limit
+ // to handle DOCX tables with "unlimited" repeating header, till the same "turn off
+ // exceeding header" feature is ready (see tdf#88496).
+#define HEADER_ROW_LIMIT_FOR_MSO_WORKAROUND 10
+ if ( m_nHeaderRepeat == HEADER_ROW_LIMIT_FOR_MSO_WORKAROUND )
+ {
+ m_nHeaderRepeat = -1;
+ pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::Any(sal_Int32(0)));
+ }
+ else
+ {
+ ++m_nHeaderRepeat;
+ pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::Any( m_nHeaderRepeat ));
+ }
+ insertTableProps(pPropMap);
+ }
+ else
+ {
+ if ( nIntValue == 0 && m_nRow == 0 )
+ {
+ // explicit tblHeader=0 in the first row must overwrite table style
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::Any(sal_Int32(0)));
+ insertTableProps(pPropMap);
+ }
+ m_nHeaderRepeat = -1;
+ }
+ if (nIntValue)
+ {
+ // Store the info that this is a header, we'll need that when we apply table styles.
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_TBL_HEADER, uno::Any(nIntValue));
+ insertRowProps(pPropMap);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblStyle: //table style name
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( META_PROP_TABLE_STYLE_NAME, uno::Any( pValue->getString() ));
+ insertTableProps(pPropMap);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblGridBase_gridCol:
+ {
+ if (nIntValue == -1)
+ getCurrentGrid()->clear();
+ else
+ getCurrentGrid()->push_back( nIntValue );
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_vMerge : //vertical merge
+ {
+ // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0
+ TablePropertyMapPtr pMergeProps( new TablePropertyMap );
+ pMergeProps->Insert( PROP_VERTICAL_MERGE, uno::Any( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart ) );
+ cellProps( pMergeProps);
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_hMerge:
+ {
+ // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0
+ TablePropertyMapPtr pMergeProps(new TablePropertyMap());
+ pMergeProps->Insert(PROP_HORIZONTAL_MERGE, uno::Any( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart ));
+ cellProps(pMergeProps);
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_gridSpan: //number of grid positions spanned by this cell
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.GridSpan");
+ TagLogger::getInstance().attribute("gridSpan", nIntValue);
+ TagLogger::getInstance().endElement();
+#endif
+ m_nGridSpan = nIntValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_textDirection:
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ bool bInsertCellProps = true;
+ switch ( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ // Binary filter takes BiDirection into account ( but I have no idea about that here )
+ // or even what it is. But... here's where to handle it if it becomes an issue
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::TB_RL ));
+ SAL_INFO( "writerfilter", "Have inserted textDirection " << nIntValue );
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr:
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::BT_LR ));
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::LR_TB ));
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::TB_RL ));
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
+ default:
+ // Ignore - we can't handle these
+ bInsertCellProps = false;
+ break;
+ }
+ if ( bInsertCellProps )
+ cellProps( pPropMap );
+ break;
+ }
+ case NS_ooxml::LN_CT_TcPrBase_tcW:
+ {
+ // Contains unit and value, but unit is not interesting for
+ // us, later we'll just distribute these values in a
+ // 0..10000 scale.
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler(new MeasureHandler());
+ pProperties->resolve(*pMeasureHandler);
+ if (sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto)
+ getCurrentCellWidths()->push_back(sal_Int32(-1));
+ else
+ // store the original value to limit rounding mistakes, if it's there in a recognized measure (twip)
+ getCurrentCellWidths()->push_back(pMeasureHandler->getMeasureValue() ? pMeasureHandler->getValue() : sal_Int32(0));
+ if (getTableDepthDifference())
+ m_bPushCurrentWidth = true;
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblpPr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ // Ignore <w:tblpPr> in shape text, those tables should be always non-floating ones.
+ if (!m_bIsInShape && pProperties)
+ {
+ TablePositionHandlerPtr pHandler = m_aTmpPosition.back();
+ if ( !pHandler )
+ {
+ m_aTmpPosition.pop_back();
+ pHandler = new TablePositionHandler;
+ m_aTmpPosition.push_back( pHandler );
+ }
+ pProperties->resolve(*m_aTmpPosition.back());
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_gridBefore:
+ setCurrentGridBefore( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_gridAfter:
+ setCurrentGridAfter( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCaption:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblDescription:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_tblCellSpacing:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellSpacing:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_bidiVisual:
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_WRITING_MODE, uno::Any(sal_Int16(nIntValue ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB)));
+ insertTableProps(pPropMap);
+ break;
+ }
+ default:
+ bRet = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+ return bRet;
+}
+
+DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentGrid( )
+{
+ if (m_aTableGrid.empty())
+ throw std::out_of_range("no current grid");
+ return m_aTableGrid.back( );
+}
+
+DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentCellWidths( )
+{
+ return m_aCellWidths.back( );
+}
+
+uno::Sequence<beans::PropertyValue> DomainMapperTableManager::getCurrentTablePosition( )
+{
+ if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
+ return m_aTablePositions.back( )->getTablePosition();
+ else
+ return uno::Sequence< beans::PropertyValue >();
+}
+
+TablePositionHandler* DomainMapperTableManager::getCurrentTableRealPosition()
+{
+ if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
+ return m_aTablePositions.back().get();
+ else
+ return nullptr;
+}
+
+const TableParagraphVectorPtr & DomainMapperTableManager::getCurrentParagraphs( )
+{
+ return m_aParagraphsToEndTable.top( );
+}
+
+void DomainMapperTableManager::setIsInShape(bool bIsInShape)
+{
+ m_bIsInShape = bIsInShape;
+}
+
+void DomainMapperTableManager::startLevel( )
+{
+ TableManager::startLevel( );
+
+ // If requested, pop the value that was pushed too early.
+ std::optional<sal_Int32> oCurrentWidth;
+ if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
+ {
+ oCurrentWidth = m_aCellWidths.back()->back();
+ m_aCellWidths.back()->pop_back();
+ }
+ std::optional<TableParagraph> oParagraph;
+ if (getTableDepthDifference() > 0 && !m_aParagraphsToEndTable.empty() && !m_aParagraphsToEndTable.top()->empty())
+ {
+ oParagraph = m_aParagraphsToEndTable.top()->back();
+ m_aParagraphsToEndTable.top()->pop_back();
+ }
+
+ IntVectorPtr pNewGrid = std::make_shared<vector<sal_Int32>>();
+ IntVectorPtr pNewCellWidths = std::make_shared<vector<sal_Int32>>();
+ TablePositionHandlerPtr pNewPositionHandler;
+ m_aTableGrid.push_back( pNewGrid );
+ m_aCellWidths.push_back( pNewCellWidths );
+ m_aTablePositions.push_back( pNewPositionHandler );
+ // empty name will be replaced by the table style name, if it exists
+ m_aTableStyleNames.push_back( OUString() );
+ m_aMoved.push_back( OUString() );
+
+ TablePositionHandlerPtr pTmpPosition;
+ TablePropertyMapPtr pTmpProperties( new TablePropertyMap( ) );
+ m_aTmpPosition.push_back( pTmpPosition );
+ m_aTmpTableProperties.push_back( pTmpProperties );
+ m_nCell.push_back( 0 );
+ m_nTableWidth = 0;
+ m_nLayoutType = 0;
+ TableParagraphVectorPtr pNewParagraphs = std::make_shared<vector<TableParagraph>>();
+ m_aParagraphsToEndTable.push( pNewParagraphs );
+
+ // And push it back to the right level.
+ if (oCurrentWidth)
+ m_aCellWidths.back()->push_back(*oCurrentWidth);
+ if (oParagraph)
+ m_aParagraphsToEndTable.top()->push_back(*oParagraph);
+}
+
+void DomainMapperTableManager::endLevel( )
+{
+ if (m_aTableGrid.empty())
+ {
+ SAL_WARN("writerfilter.dmapper", "Table stack is empty");
+ return;
+ }
+
+ m_aTableGrid.pop_back( );
+
+ // Do the same trick as in startLevel(): pop the value that was pushed too early.
+ std::optional<sal_Int32> oCurrentWidth;
+ if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
+ oCurrentWidth = m_aCellWidths.back()->back();
+ m_aCellWidths.pop_back( );
+ // And push it back to the right level.
+ if (oCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
+ m_aCellWidths.back()->push_back(*oCurrentWidth);
+
+ m_nCell.pop_back( );
+ m_nTableWidth = 0;
+ m_nLayoutType = 0;
+
+ m_aTmpPosition.pop_back( );
+ m_aTmpTableProperties.pop_back( );
+
+ TableManager::endLevel( );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("dmappertablemanager.endLevel");
+ PropertyMapPtr pProps = getTableProps().get();
+ if (pProps)
+ getTableProps()->dumpXml();
+
+ TagLogger::getInstance().endElement();
+#endif
+
+ // Pop back the table position after endLevel as it's used
+ // in the endTable method called in endLevel.
+ m_aTablePositions.pop_back();
+ m_aTableStyleNames.pop_back();
+ m_aMoved.pop_back( );
+
+ std::optional<TableParagraph> oParagraph;
+ if (getTableDepthDifference() < 0 && !m_aParagraphsToEndTable.top()->empty())
+ oParagraph = m_aParagraphsToEndTable.top()->back();
+ m_aParagraphsToEndTable.pop();
+ if (oParagraph && m_aParagraphsToEndTable.size())
+ m_aParagraphsToEndTable.top()->push_back(*oParagraph);
+}
+
+void DomainMapperTableManager::endOfCellAction()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("endOFCellAction");
+#endif
+
+ if ( !isInTable() )
+ throw std::out_of_range("cell without a table");
+ if ( m_nGridSpan > 1 )
+ setCurrentGridSpan( m_nGridSpan );
+ m_nGridSpan = 1;
+ ++m_nCell.back( );
+}
+
+bool DomainMapperTableManager::shouldInsertRow(IntVectorPtr pCellWidths, IntVectorPtr pTableGrid, size_t nGrids, bool& rIsIncompleteGrid)
+{
+ if (pCellWidths->empty())
+ return false;
+ if (m_nLayoutType == NS_ooxml::LN_Value_doc_ST_TblLayout_fixed)
+ return true;
+ if (pCellWidths->size() == nGrids)
+ return true;
+ rIsIncompleteGrid = true;
+ return nGrids > pTableGrid->size();
+}
+
+void DomainMapperTableManager::endOfRowAction()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("endOfRowAction");
+#endif
+
+ // Compare the table position and style with the previous ones. We may need to split
+ // into two tables if those are different. We surely don't want to do anything
+ // if we don't have any row yet.
+ if (m_aTmpPosition.empty())
+ throw std::out_of_range("row without a position");
+ TablePositionHandlerPtr pTmpPosition = m_aTmpPosition.back();
+ TablePropertyMapPtr pTablePropMap = m_aTmpTableProperties.back( );
+ TablePositionHandlerPtr pCurrentPosition = m_aTablePositions.back();
+ bool bSamePosition = ( pTmpPosition == pCurrentPosition ) ||
+ ( pTmpPosition && pCurrentPosition && *pTmpPosition == *pCurrentPosition );
+ bool bIsSetTableStyle = pTablePropMap->isSet(META_PROP_TABLE_STYLE_NAME);
+ OUString sTableStyleName;
+ bool bSameTableStyle = ( !bIsSetTableStyle && m_aTableStyleNames.back().isEmpty()) ||
+ ( bIsSetTableStyle &&
+ (pTablePropMap->getProperty(META_PROP_TABLE_STYLE_NAME)->second >>= sTableStyleName) &&
+ sTableStyleName == m_aTableStyleNames.back() );
+ if ( (!bSamePosition || !bSameTableStyle) && m_nRow > 0 )
+ {
+ // Save the grid infos to have them survive the end/start level
+ IntVectorPtr pTmpTableGrid = m_aTableGrid.back();
+ IntVectorPtr pTmpCellWidths = m_aCellWidths.back();
+ sal_uInt32 nTmpCell = m_nCell.back();
+ TableParagraphVectorPtr pTableParagraphs = getCurrentParagraphs();
+
+ // endLevel and startLevel are taking care of the non finished row
+ // to carry it over to the next table
+ setKeepUnfinishedRow( true );
+ endLevel();
+ setKeepUnfinishedRow( false );
+ startLevel();
+
+ m_aTableGrid.pop_back();
+ m_aCellWidths.pop_back();
+ m_nCell.pop_back();
+ m_aTableGrid.push_back(pTmpTableGrid);
+ m_aCellWidths.push_back(pTmpCellWidths);
+ m_nCell.push_back(nTmpCell);
+ m_aParagraphsToEndTable.pop( );
+ m_aParagraphsToEndTable.push( pTableParagraphs );
+ }
+ // save table style in the first row for comparison
+ if ( m_nRow == 0 && pTablePropMap->isSet(META_PROP_TABLE_STYLE_NAME) )
+ {
+ pTablePropMap->getProperty(META_PROP_TABLE_STYLE_NAME)->second >>= sTableStyleName;
+ m_aTableStyleNames.pop_back();
+ m_aTableStyleNames.push_back( sTableStyleName );
+ }
+
+ // Push the tmp position now that we compared it
+ m_aTablePositions.pop_back();
+ m_aTablePositions.push_back( pTmpPosition );
+ m_aTmpPosition.back().clear( );
+
+
+ IntVectorPtr pTableGrid = getCurrentGrid( );
+ IntVectorPtr pCellWidths = getCurrentCellWidths( );
+ if(!m_nTableWidth && !pTableGrid->empty())
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tableWidth");
+#endif
+
+ for( const auto& rCell : *pTableGrid )
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("col");
+ TagLogger::getInstance().attribute("width", rCell);
+ TagLogger::getInstance().endElement();
+#endif
+
+ m_nTableWidth = o3tl::saturating_add(m_nTableWidth, rCell);
+ }
+ if (m_nTableWidth)
+ // convert sum of grid twip values to 1/100 mm with rounding up to avoid table width loss
+ m_nTableWidth = static_cast<sal_Int32>(ceil(ConversionHelper::convertTwipToMM100Double(m_nTableWidth)));
+
+ if (m_nTableWidth > 0 && !m_bTableSizeTypeInserted)
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
+ insertTableProps(pPropMap);
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+ }
+
+ std::vector<sal_uInt32> rCurrentSpans = getCurrentGridSpans();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("gridSpans");
+ {
+ for (const auto& rGridSpan : rCurrentSpans)
+ {
+ TagLogger::getInstance().startElement("gridSpan");
+ TagLogger::getInstance().attribute("span", rGridSpan);
+ TagLogger::getInstance().endElement();
+ }
+ }
+ TagLogger::getInstance().endElement();
+#endif
+
+ //calculate number of used grids - it has to match the size of m_aTableGrid
+ size_t nGrids = std::accumulate(rCurrentSpans.begin(), rCurrentSpans.end(), sal::static_int_cast<size_t>(0));
+
+ // sj: the grid is having no units... it is containing only relative values.
+ // a table with a grid of "1:2:1" looks identical as if the table is having
+ // a grid of "20:40:20" and it doesn't have to do something with the tableWidth
+ // -> so we have get the sum of each grid entry for the fullWidthRelative:
+ int nFullWidthRelative = 0;
+ for (int i : (*pTableGrid))
+ nFullWidthRelative = o3tl::saturating_add(nFullWidthRelative, i);
+
+ bool bIsIncompleteGrid = false;
+ if( pTableGrid->size() == nGrids && m_nCell.back( ) > 0 )
+ {
+ /*
+ * If table width property set earlier is smaller than the current table width,
+ * then replace the TABLE_WIDTH property, set earlier.
+ */
+ sal_Int32 nTableWidth(0);
+ sal_Int32 nTableWidthType(text::SizeType::VARIABLE);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType);
+ if ((nTableWidthType == text::SizeType::FIX) && (nTableWidth < m_nTableWidth))
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, m_nTableWidth);
+ }
+ if (nTableWidthType == text::SizeType::VARIABLE )
+ {
+ if(nTableWidth > 100 || nTableWidth <= 0)
+ {
+ if(getTableDepth() > 1 && !m_bTableSizeTypeInserted)
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, sal_Int32(100));
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE);
+ }
+ else
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, m_nTableWidth);
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX);
+ }
+ }
+ }
+ uno::Sequence< text::TableColumnSeparator > aSeparators( getCurrentGridBefore() + m_nCell.back() - 1 );
+ text::TableColumnSeparator* pSeparators = aSeparators.getArray();
+ double nLastRelPos = 0.0;
+ sal_uInt32 nBorderGridIndex = 0;
+
+ size_t nWidthsBound = getCurrentGridBefore() + m_nCell.back() - 1;
+ if (nWidthsBound)
+ {
+ ::std::vector< sal_uInt32 >::const_iterator aSpansIter = rCurrentSpans.begin();
+ for( size_t nBorder = 0; nBorder < nWidthsBound; ++nBorder )
+ {
+ double nRelPos, fGridWidth = 0.;
+ for ( sal_Int32 nGridCount = *aSpansIter; nGridCount > 0; --nGridCount )
+ fGridWidth += (*pTableGrid)[nBorderGridIndex++];
+
+ if (fGridWidth == 0.)
+ {
+ // allow nFullWidthRelative here, with a sane 0.0 result
+ nRelPos = 0.;
+ }
+ else
+ {
+ if (nFullWidthRelative == 0)
+ throw o3tl::divide_by_zero();
+
+ nRelPos = (fGridWidth * 10000) / nFullWidthRelative;
+ }
+
+ pSeparators[nBorder].Position = rtl::math::round(nRelPos + nLastRelPos);
+ pSeparators[nBorder].IsVisible = true;
+ nLastRelPos = nLastRelPos + nRelPos;
+ ++aSpansIter;
+ }
+ }
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::Any( aSeparators ) );
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("rowProperties");
+ pPropMap->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ // set row insertion/deletion at tracked drag & drop of tables
+ OUString aMoved = getMoved();
+ if ( !aMoved.isEmpty() )
+ {
+ auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>(
+ aMoved == getPropertyName( PROP_TABLE_ROW_DELETE )
+ ? oox::XML_tableRowDelete
+ : oox::XML_tableRowInsert );
+ uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties();
+ pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::Any( aTableRedlineProperties ));
+ }
+
+ insertRowProps(pPropMap);
+ }
+ else if (shouldInsertRow(pCellWidths, pTableGrid, nGrids, bIsIncompleteGrid))
+ {
+ // If we're here, then the number of cells does not equal to the amount
+ // defined by the grid, even after taking care of
+ // gridSpan/gridBefore/gridAfter. Handle this by ignoring the grid and
+ // providing the separators based on the provided cell widths, as long
+ // as we have a fixed layout;
+ // On the other hand even if the layout is not fixed, but the cell widths
+ // provided equal the total number of cells, and there are no after/before cells
+ // then use the cell widths to calculate the column separators.
+ // Also handle autofit tables with incomplete grids, when rows can have
+ // different widths and last cells can be wider, than their values.
+ uno::Sequence< text::TableColumnSeparator > aSeparators(pCellWidths->size() - 1);
+ text::TableColumnSeparator* pSeparators = aSeparators.getArray();
+ sal_Int16 nSum = 0;
+ sal_uInt32 nPos = 0;
+
+ if (bIsIncompleteGrid)
+ nFullWidthRelative = 0;
+
+ // Avoid divide by zero (if there's no grid, position using cell widths).
+ if( nFullWidthRelative == 0 )
+ for (size_t i = 0; i < pCellWidths->size(); ++i)
+ nFullWidthRelative += (*pCellWidths)[i];
+
+ if (bIsIncompleteGrid)
+ {
+ /*
+ * If table width property set earlier is smaller than the current table row width,
+ * then replace the TABLE_WIDTH property, set earlier.
+ */
+ sal_Int32 nFullWidth = static_cast<sal_Int32>(ceil(ConversionHelper::convertTwipToMM100Double(nFullWidthRelative)));
+ sal_Int32 nTableWidth(0);
+ sal_Int32 nTableWidthType(text::SizeType::VARIABLE);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType);
+ if (nTableWidth < nFullWidth)
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, nFullWidth);
+ }
+ }
+
+ size_t nWidthsBound = pCellWidths->size() - 1;
+ if (nWidthsBound)
+ {
+ // At incomplete table grids, last cell width can be smaller, than its final width.
+ // Correct it based on the last but one column width and their span values.
+ if ( bIsIncompleteGrid && rCurrentSpans.size()-1 == nWidthsBound )
+ {
+ auto aSpansIter = std::next(rCurrentSpans.begin(), nWidthsBound - 1);
+ sal_Int32 nFixLastCellWidth = (*pCellWidths)[nWidthsBound-1] / *aSpansIter * *std::next(aSpansIter);
+ if (nFixLastCellWidth > (*pCellWidths)[nWidthsBound])
+ nFullWidthRelative += nFixLastCellWidth - (*pCellWidths)[nWidthsBound];
+ }
+
+ // tdf#131203 handle missing w:tblGrid
+ if (nFullWidthRelative > 0)
+ {
+ for (size_t i = 0; i < nWidthsBound; ++i)
+ {
+ nSum += (*pCellWidths)[i];
+ pSeparators[nPos].Position = (nSum * 10000) / nFullWidthRelative; // Relative position
+ pSeparators[nPos].IsVisible = true;
+ nPos++;
+ }
+ }
+ }
+
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::Any( aSeparators ) );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("rowProperties");
+ pPropMap->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+ insertRowProps(pPropMap);
+ }
+
+ // Now that potentially opened table is closed, save the table properties
+ TableManager::insertTableProps(pTablePropMap);
+
+ m_aTmpTableProperties.pop_back();
+ TablePropertyMapPtr pEmptyTableProps( new TablePropertyMap() );
+ m_aTmpTableProperties.push_back( pEmptyTableProps );
+
+ ++m_nRow;
+ m_nCell.back( ) = 0;
+ getCurrentGrid()->clear();
+ pCellWidths->clear();
+
+ m_bTableSizeTypeInserted = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void DomainMapperTableManager::clearData()
+{
+ m_nRow = m_nHeaderRepeat = m_nTableWidth = m_nLayoutType = 0;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapperTableManager.hxx b/writerfilter/source/dmapper/DomainMapperTableManager.hxx
new file mode 100644
index 000000000..a2e492936
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapperTableManager.hxx
@@ -0,0 +1,172 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TablePropertiesHandler.hxx"
+#include "TablePositionHandler.hxx"
+
+#include "TableManager.hxx"
+#include "PropertyMap.hxx"
+#include <vector>
+#include <memory>
+#include <comphelper/sequenceashashmap.hxx>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+
+class DomainMapperTableManager : public TableManager
+{
+ typedef std::shared_ptr< std::vector<sal_Int32> > IntVectorPtr;
+
+ sal_uInt32 m_nRow;
+ ::std::vector< sal_uInt32 > m_nCell;
+ sal_uInt32 m_nGridSpan;
+ sal_Int32 m_nHeaderRepeat; //counter of repeated headers - if == -1 then the repeating stops
+ sal_Int32 m_nTableWidth; //might be set directly or has to be calculated from the column positions
+ /// Are we in a shape (text append stack is not empty) or in the body document?
+ bool m_bIsInShape;
+ std::vector< OUString > m_aTableStyleNames;
+ /// Moved table (in moveRangeFromStart...moveRangeFromEnd or moveRangeToStart...moveRangeToEnd)
+ std::vector< OUString > m_aMoved;
+ /// Grab-bag of table look attributes for preserving.
+ comphelper::SequenceAsHashMap m_aTableLook;
+ std::vector< TablePositionHandlerPtr > m_aTablePositions;
+ std::vector< TablePositionHandlerPtr > m_aTmpPosition; ///< Temporarily stores the position to compare it later
+ std::vector< TablePropertyMapPtr > m_aTmpTableProperties; ///< Temporarily stores the table properties until end of row
+
+ ::std::vector< IntVectorPtr > m_aTableGrid;
+ /// If this is true, then we pushed a width before the next level started, and that should be carried over when starting the next level.
+ bool m_bPushCurrentWidth;
+ /// Individual table cell width values, used only in case the number of cells doesn't match the table grid.
+ ::std::vector< IntVectorPtr > m_aCellWidths;
+ /// Remember if table width was already set, when we lack a w:tblW, it should be set manually at the end.
+ bool m_bTableSizeTypeInserted;
+ /// Table layout algorithm, IOW if we should consider fixed column width or not.
+ sal_uInt32 m_nLayoutType;
+ /// Collected table paragraphs for table style handling
+ std::stack< TableParagraphVectorPtr > m_aParagraphsToEndTable;
+
+ std::unique_ptr<TablePropertiesHandler> m_pTablePropsHandler;
+ PropertyMapPtr m_pStyleProps;
+
+ bool shouldInsertRow(IntVectorPtr pCellWidths, IntVectorPtr pTableGrid, size_t nGrids, bool& rIsIncompleteGrid);
+
+ virtual void clearData() override;
+
+public:
+
+ DomainMapperTableManager();
+ virtual ~DomainMapperTableManager() override;
+
+ // use this method to avoid adding the properties for the table
+ // but in the provided properties map.
+ void SetStyleProperties( PropertyMapPtr pProperties ) { m_pStyleProps = pProperties; };
+
+ virtual bool sprm(Sprm & rSprm) override;
+ bool attribute(Id nName, Value const & val);
+
+ virtual void startLevel( ) override;
+ virtual void endLevel( ) override;
+
+ virtual void endOfCellAction() override;
+ virtual void endOfRowAction() override;
+
+ IntVectorPtr const & getCurrentGrid( );
+ IntVectorPtr const & getCurrentCellWidths( );
+ const TableParagraphVectorPtr & getCurrentParagraphs( );
+
+ /// Turn the attributes collected so far in m_aTableLook into a property and clear the container.
+ void finishTableLook();
+ css::uno::Sequence<css::beans::PropertyValue> getCurrentTablePosition();
+ TablePositionHandler* getCurrentTableRealPosition();
+
+ virtual void cellProps(const TablePropertyMapPtr& pProps) override
+ {
+ if ( m_pStyleProps )
+ m_pStyleProps->InsertProps(pProps.get());
+ else
+ TableManager::cellProps( pProps );
+ };
+
+ virtual void insertRowProps(const TablePropertyMapPtr& pProps) override
+ {
+ if ( m_pStyleProps )
+ m_pStyleProps->InsertProps(pProps.get());
+ else
+ TableManager::insertRowProps( pProps );
+ };
+
+ virtual void insertTableProps(const TablePropertyMapPtr& pProps) override
+ {
+ if ( m_pStyleProps )
+ m_pStyleProps->InsertProps(pProps.get());
+ else
+ m_aTmpTableProperties.back()->InsertProps(pProps.get());
+ };
+
+ void SetLayoutType(sal_uInt32 nLayoutType)
+ {
+ m_nLayoutType = nLayoutType;
+ }
+
+ using TableManager::isInCell;
+
+ void setIsInShape(bool bIsInShape);
+
+ // moveFromRangeStart and moveToRangeStart are there
+ // in the first paragraph in the first cell of the
+ // table moved by drag & drop with track changes, but
+ // moveFromRangeEnd and moveToRangeEnd follow the
+ // table element w:tbl in the same level (not in paragraph).
+ // (Special indexing is related to the load of the tables:
+ // first-level tables handled by two levels during the
+ // import, to support table join etc. In the first cell,
+ // setMoved() writes the first level from these two levels
+ // i.e. second startLevel() hasn't been called, yet.)
+ // TODO: check drag & drop of only a part of the tables.
+ void setMoved(OUString sMoved)
+ {
+ if ( m_aMoved.empty() )
+ return;
+
+ if ( !sMoved.isEmpty() )
+ m_aMoved[m_aMoved.size() - 1] = sMoved;
+ else if ( m_aMoved.size() >= 2 )
+ // next table rows weren't moved
+ m_aMoved[m_aMoved.size() - 2] = "";
+ else
+ m_aMoved[m_aMoved.size() - 1] = "";
+ }
+
+ OUString getMoved() const
+ {
+ if ( m_aMoved.size() >= 2 && !m_aMoved[m_aMoved.size() - 2].isEmpty() )
+ return m_aMoved[m_aMoved.size() - 2];
+ else if ( !m_aMoved.empty() )
+ return m_aMoved[m_aMoved.size() -1 ];
+
+ return OUString();
+ }
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
new file mode 100644
index 000000000..ae0a8a27d
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -0,0 +1,8792 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <ooxml/resourceids.hxx>
+#include "DomainMapper_Impl.hxx"
+#include "ConversionHelper.hxx"
+#include "SdtHelper.hxx"
+#include "DomainMapperTableHandler.hxx"
+#include "TagLogger.hxx"
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/i18n/NumberFormatMapper.hpp>
+#include <com/sun/star/i18n/NumberFormatIndex.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/LineNumberPosition.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/text/ChapterFormat.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/text/SetVariableType.hpp>
+#include <com/sun/star/text/XDocumentIndex.hpp>
+#include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
+#include <com/sun/star/text/XFootnote.hpp>
+#include <com/sun/star/text/XEndnotesSupplier.hpp>
+#include <com/sun/star/text/XFootnotesSupplier.hpp>
+#include <com/sun/star/text/XLineNumberingProperties.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/PageNumberType.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/ReferenceFieldPart.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/ReferenceFieldSource.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/XDependentTextField.hpp>
+#include <com/sun/star/text/XParagraphCursor.hpp>
+#include <com/sun/star/text/XRedline.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
+#include <com/sun/star/text/RubyPosition.hpp>
+#include <com/sun/star/text/XTextRangeCompare.hpp>
+#include <com/sun/star/style/DropCapFormat.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/document/XViewDataSupplier.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/text/ControlCharacter.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+#include <com/sun/star/awt/CharSet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <comphelper/indexedpropertyvalues.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/unotext.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/temporary.hxx>
+#include <oox/mathml/import.hxx>
+#include <xmloff/odffields.hxx>
+#include <rtl/uri.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/string.hxx>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+
+#include <oox/token/tokens.hxx>
+
+#include <cmath>
+#include <optional>
+#include <map>
+#include <tuple>
+#include <unordered_map>
+#include <regex>
+#include <algorithm>
+
+#include <officecfg/Office/Common.hxx>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/ww8fields.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+#include <com/sun/star/drawing/FillStyle.hpp>
+
+#include <unicode/errorcode.h>
+#include <unicode/regex.h>
+
+using namespace ::com::sun::star;
+using namespace oox;
+namespace writerfilter::dmapper{
+
+//line numbering for header/footer
+static void lcl_linenumberingHeaderFooter( const uno::Reference<container::XNameContainer>& xStyles, const OUString& rname, DomainMapper_Impl* dmapper )
+{
+ const StyleSheetEntryPtr pEntry = dmapper->GetStyleSheetTable()->FindStyleSheetByISTD( rname );
+ if (!pEntry)
+ return;
+ const StyleSheetPropertyMap* pStyleSheetProperties = pEntry->pProperties.get();
+ if ( !pStyleSheetProperties )
+ return;
+ sal_Int32 nListId = pStyleSheetProperties->GetListId();
+ if( xStyles.is() )
+ {
+ if( xStyles->hasByName( rname ) )
+ {
+ uno::Reference< style::XStyle > xStyle;
+ xStyles->getByName( rname ) >>= xStyle;
+ if( !xStyle.is() )
+ return;
+ uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY );
+ xPropertySet->setPropertyValue( getPropertyName( PROP_PARA_LINE_NUMBER_COUNT ), uno::Any( nListId >= 0 ) );
+ }
+ }
+}
+
+// Populate Dropdown Field properties from FFData structure
+static void lcl_handleDropdownField( const uno::Reference< beans::XPropertySet >& rxFieldProps, const FFDataHandler::Pointer_t& pFFDataHandler )
+{
+ if ( !rxFieldProps.is() )
+ return;
+
+ if ( !pFFDataHandler->getName().isEmpty() )
+ rxFieldProps->setPropertyValue( "Name", uno::Any( pFFDataHandler->getName() ) );
+
+ const FFDataHandler::DropDownEntries_t& rEntries = pFFDataHandler->getDropDownEntries();
+ uno::Sequence< OUString > sItems( rEntries.size() );
+ ::std::copy( rEntries.begin(), rEntries.end(), sItems.getArray());
+ if ( sItems.hasElements() )
+ rxFieldProps->setPropertyValue( "Items", uno::Any( sItems ) );
+
+ sal_Int32 nResult = pFFDataHandler->getDropDownResult().toInt32();
+ if (nResult > 0 && o3tl::make_unsigned(nResult) < sItems.size())
+ rxFieldProps->setPropertyValue( "SelectedItem", uno::Any( std::as_const(sItems)[ nResult ] ) );
+ if ( !pFFDataHandler->getHelpText().isEmpty() )
+ rxFieldProps->setPropertyValue( "Help", uno::Any( pFFDataHandler->getHelpText() ) );
+}
+
+static void lcl_handleTextField( const uno::Reference< beans::XPropertySet >& rxFieldProps, const FFDataHandler::Pointer_t& pFFDataHandler )
+{
+ if ( rxFieldProps.is() && pFFDataHandler )
+ {
+ rxFieldProps->setPropertyValue
+ (getPropertyName(PROP_HINT),
+ uno::Any(pFFDataHandler->getStatusText()));
+ rxFieldProps->setPropertyValue
+ (getPropertyName(PROP_HELP),
+ uno::Any(pFFDataHandler->getHelpText()));
+ rxFieldProps->setPropertyValue
+ (getPropertyName(PROP_CONTENT),
+ uno::Any(pFFDataHandler->getTextDefault()));
+ }
+}
+
+/**
+ Very similar to DomainMapper_Impl::GetPropertyFromStyleSheet
+ It is focused on paragraph properties search in current & parent stylesheet entries.
+ But it will not take into account properties with listid: these are "list paragraph styles" and
+ not used in some cases.
+*/
+static uno::Any lcl_GetPropertyFromParaStyleSheetNoNum(PropertyIds eId, StyleSheetEntryPtr pEntry, const StyleSheetTablePtr& rStyleSheet)
+{
+ while (pEntry)
+ {
+ if (pEntry->pProperties)
+ {
+ std::optional<PropertyMap::Property> aProperty =
+ pEntry->pProperties->getProperty(eId);
+ if (aProperty)
+ {
+ if (pEntry->pProperties->GetListId())
+ // It is a paragraph style with list. Paragraph list styles are not taken into account
+ return uno::Any();
+ else
+ return aProperty->second;
+ }
+ }
+ //search until the property is set or no parent is available
+ StyleSheetEntryPtr pNewEntry;
+ if (!pEntry->sBaseStyleIdentifier.isEmpty())
+ pNewEntry = rStyleSheet->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
+
+ SAL_WARN_IF(pEntry == pNewEntry, "writerfilter.dmapper", "circular loop in style hierarchy?");
+
+ if (pEntry == pNewEntry) //fdo#49587
+ break;
+
+ pEntry = pNewEntry;
+ }
+ return uno::Any();
+}
+
+
+namespace {
+
+struct FieldConversion
+{
+ const char* cFieldServiceName;
+ FieldId eFieldId;
+};
+
+}
+
+typedef std::unordered_map<OUString, FieldConversion> FieldConversionMap_t;
+
+/// Gives access to the parent field context of the topmost one, if there is any.
+static FieldContextPtr GetParentFieldContext(const std::deque<FieldContextPtr>& rFieldStack)
+{
+ if (rFieldStack.size() < 2)
+ {
+ return nullptr;
+ }
+
+ return rFieldStack[rFieldStack.size() - 2];
+}
+
+/// Decides if the pInner field inside pOuter is allowed in Writer core, depending on their type.
+static bool IsFieldNestingAllowed(const FieldContextPtr& pOuter, const FieldContextPtr& pInner)
+{
+ std::optional<FieldId> oOuterFieldId = pOuter->GetFieldId();
+ OUString aCommand = pOuter->GetCommand();
+
+ // Ignore leading space before the field name, but don't accept IFF when we check for IF.
+ if (!aCommand.isEmpty() && aCommand[0] == ' ')
+ {
+ aCommand = aCommand.subView(1);
+ }
+
+ if (!oOuterFieldId && aCommand.startsWith("IF "))
+ {
+ // This will be FIELD_IF once the command is closed.
+ oOuterFieldId = FIELD_IF;
+ }
+
+ if (!oOuterFieldId)
+ {
+ return true;
+ }
+
+ if (!pInner->GetFieldId())
+ {
+ return true;
+ }
+
+ switch (*oOuterFieldId)
+ {
+ case FIELD_IF:
+ {
+ switch (*pInner->GetFieldId())
+ {
+ case FIELD_DOCVARIABLE:
+ case FIELD_FORMULA:
+ case FIELD_IF:
+ case FIELD_MERGEFIELD:
+ {
+ return false;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+uno::Any FloatingTableInfo::getPropertyValue(std::u16string_view propertyName)
+{
+ for( beans::PropertyValue const & propVal : std::as_const(m_aFrameProperties) )
+ if( propVal.Name == propertyName )
+ return propVal.Value ;
+ return uno::Any() ;
+}
+
+DomainMapper_Impl::DomainMapper_Impl(
+ DomainMapper& rDMapper,
+ uno::Reference<uno::XComponentContext> const& xContext,
+ uno::Reference<lang::XComponent> const& xModel,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc) :
+ m_eDocumentType( eDocumentType ),
+ m_rDMapper( rDMapper ),
+ m_pOOXMLDocument(nullptr),
+ m_xTextDocument( xModel, uno::UNO_QUERY ),
+ m_xTextFactory( xModel, uno::UNO_QUERY ),
+ m_xComponentContext( xContext ),
+ m_bForceGenericFields(!utl::ConfigManager::IsFuzzing() && officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::get()),
+ m_bIsDecimalComma( false ),
+ m_bSetUserFieldContent( false ),
+ m_bSetCitation( false ),
+ m_bSetDateValue( false ),
+ m_bIsFirstSection( true ),
+ m_bIsColumnBreakDeferred( false ),
+ m_bIsPageBreakDeferred( false ),
+ m_nLineBreaksDeferred( 0 ),
+ m_bSdtEndDeferred(false),
+ m_bParaSdtEndDeferred(false),
+ m_bStartTOC(false),
+ m_bStartTOCHeaderFooter(false),
+ m_bStartedTOC(false),
+ m_bStartIndex(false),
+ m_bStartBibliography(false),
+ m_nStartGenericField(0),
+ m_bTextInserted(false),
+ m_sCurrentPermId(0),
+ m_bFrameDirectionSet(false),
+ m_bInDocDefaultsImport(false),
+ m_bInStyleSheetImport( false ),
+ m_bInNumberingImport(false),
+ m_bInAnyTableImport( false ),
+ m_eInHeaderFooterImport( HeaderFooterImportState::none ),
+ m_bDiscardHeaderFooter( false ),
+ m_bInFootOrEndnote(false),
+ m_bInFootnote(false),
+ m_bHasFootnoteStyle(false),
+ m_bCheckFootnoteStyle(false),
+ m_eSkipFootnoteState(SkipFootnoteSeparator::OFF),
+ m_nFootnotes(-1),
+ m_nEndnotes(-1),
+ m_nFirstFootnoteIndex(-1),
+ m_nFirstEndnoteIndex(-1),
+ m_bLineNumberingSet( false ),
+ m_bIsInFootnoteProperties( false ),
+ m_bIsParaMarkerChange( false ),
+ m_bIsParaMarkerMove( false ),
+ m_bRedlineImageInPreviousRun( false ),
+ m_bParaChanged( false ),
+ m_bIsFirstParaInSection( true ),
+ m_bIsFirstParaInSectionAfterRedline( true ),
+ m_bDummyParaAddedForTableInSection( false ),
+ m_bDummyParaAddedForTableInSectionPage( false ),
+ m_bTextFrameInserted(false),
+ m_bIsPreviousParagraphFramed( false ),
+ m_bIsLastParaInSection( false ),
+ m_bIsLastSectionGroup( false ),
+ m_bIsInComments( false ),
+ m_bParaSectpr( false ),
+ m_bUsingEnhancedFields( false ),
+ m_bSdt(false),
+ m_bIsFirstRun(false),
+ m_bIsOutsideAParagraph(true),
+ m_nAnnotationId( -1 ),
+ m_aSmartTagHandler(m_xComponentContext, m_xTextDocument),
+ m_xInsertTextRange(rMediaDesc.getUnpackedValueOrDefault("TextInsertModeRange", uno::Reference<text::XTextRange>())),
+ m_xAltChunkStartingRange(rMediaDesc.getUnpackedValueOrDefault("AltChunkStartingRange", uno::Reference<text::XTextRange>())),
+ m_bIsInTextBox(false),
+ m_bIsNewDoc(!rMediaDesc.getUnpackedValueOrDefault("InsertMode", false)),
+ m_bIsAltChunk(rMediaDesc.getUnpackedValueOrDefault("AltChunkMode", false)),
+ m_bIsReadGlossaries(rMediaDesc.getUnpackedValueOrDefault("ReadGlossaries", false)),
+ m_nTableDepth(0),
+ m_nTableCellDepth(0),
+ m_nLastTableCellParagraphDepth(0),
+ m_bHasFtn(false),
+ m_bHasFtnSep(false),
+ m_bCheckFirstFootnoteTab(false),
+ m_bIgnoreNextTab(false),
+ m_bIsSplitPara(false),
+ m_bIsActualParagraphFramed( false ),
+ m_bParaHadField(false),
+ m_bSaveParaHadField(false),
+ m_bParaAutoBefore(false),
+ m_bFirstParagraphInCell(true),
+ m_bSaveFirstParagraphInCell(false),
+ m_bParaWithInlineObject(false),
+ m_bSaxError(false)
+{
+ m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_DOCUMENTBASEURL, OUString());
+ if (m_aBaseUrl.isEmpty()) {
+ m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_URL, OUString());
+ }
+
+ appendTableManager( );
+ GetBodyText();
+ if (!m_bIsNewDoc && !m_xBodyText)
+ {
+ throw uno::Exception("failed to find body text of the insert position", nullptr);
+ }
+
+ uno::Reference< text::XTextAppend > xBodyTextAppend( m_xBodyText, uno::UNO_QUERY );
+ m_aTextAppendStack.push(TextAppendContext(xBodyTextAppend,
+ m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(m_xInsertTextRange)));
+
+ //todo: does it makes sense to set the body text as static text interface?
+ uno::Reference< text::XTextAppendAndConvert > xBodyTextAppendAndConvert( m_xBodyText, uno::UNO_QUERY );
+ m_pTableHandler = new DomainMapperTableHandler(xBodyTextAppendAndConvert, *this);
+ getTableManager( ).setHandler(m_pTableHandler);
+
+ getTableManager( ).startLevel();
+ m_bUsingEnhancedFields = !utl::ConfigManager::IsFuzzing() && officecfg::Office::Common::Filter::Microsoft::Import::ImportWWFieldsAsEnhancedFields::get();
+
+ m_pSdtHelper = new SdtHelper(*this, m_xComponentContext);
+
+ m_aRedlines.push(std::vector<RedlineParamsPtr>());
+
+ if (m_bIsAltChunk)
+ {
+ m_bIsFirstSection = false;
+ }
+}
+
+
+DomainMapper_Impl::~DomainMapper_Impl()
+{
+ ChainTextFrames();
+ // Don't remove last paragraph when pasting, sw expects that empty paragraph.
+ if (m_bIsNewDoc)
+ RemoveLastParagraph();
+ if (hasTableManager())
+ {
+ getTableManager().endLevel();
+ popTableManager();
+ }
+}
+
+writerfilter::ooxml::OOXMLDocument* DomainMapper_Impl::getDocumentReference() const
+{
+ return m_pOOXMLDocument;
+}
+
+uno::Reference< container::XNameContainer > const & DomainMapper_Impl::GetPageStyles()
+{
+ if(!m_xPageStyles1.is())
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xSupplier( m_xTextDocument, uno::UNO_QUERY );
+ if (xSupplier.is())
+ xSupplier->getStyleFamilies()->getByName("PageStyles") >>= m_xPageStyles1;
+ }
+ return m_xPageStyles1;
+}
+
+OUString DomainMapper_Impl::GetUnusedPageStyleName()
+{
+ static const char DEFAULT_STYLE[] = "Converted";
+ if (!m_xNextUnusedPageStyleNo)
+ {
+ const uno::Sequence< OUString > aPageStyleNames = GetPageStyles()->getElementNames();
+ sal_Int32 nMaxIndex = 0;
+ // find the highest number x in each style with the name "DEFAULT_STYLE+x" and
+ // return an incremented name
+
+ for ( const auto& rStyleName : aPageStyleNames )
+ {
+ if ( rStyleName.startsWith( DEFAULT_STYLE ) )
+ {
+ sal_Int32 nIndex = o3tl::toInt32(rStyleName.subView( strlen( DEFAULT_STYLE ) ));
+ if ( nIndex > nMaxIndex )
+ nMaxIndex = nIndex;
+ }
+ }
+ m_xNextUnusedPageStyleNo = nMaxIndex + 1;
+ }
+
+ OUString sPageStyleName = DEFAULT_STYLE + OUString::number( *m_xNextUnusedPageStyleNo );
+ *m_xNextUnusedPageStyleNo = *m_xNextUnusedPageStyleNo + 1;
+ return sPageStyleName;
+}
+
+uno::Reference< container::XNameContainer > const & DomainMapper_Impl::GetCharacterStyles()
+{
+ if(!m_xCharacterStyles.is())
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xSupplier( m_xTextDocument, uno::UNO_QUERY );
+ if (xSupplier.is())
+ xSupplier->getStyleFamilies()->getByName("CharacterStyles") >>= m_xCharacterStyles;
+ }
+ return m_xCharacterStyles;
+}
+
+OUString DomainMapper_Impl::GetUnusedCharacterStyleName()
+{
+ static const char cListLabel[] = "ListLabel ";
+ if (!m_xNextUnusedCharacterStyleNo)
+ {
+ //search for all character styles with the name sListLabel + <index>
+ const uno::Sequence< OUString > aCharacterStyleNames = GetCharacterStyles()->getElementNames();
+ sal_Int32 nMaxIndex = 0;
+ for ( const auto& rStyleName : aCharacterStyleNames )
+ {
+ OUString sSuffix;
+ if ( rStyleName.startsWith( cListLabel, &sSuffix ) )
+ {
+ sal_Int32 nSuffix = sSuffix.toInt32();
+ if( nSuffix > 0 && nSuffix > nMaxIndex )
+ nMaxIndex = nSuffix;
+ }
+ }
+ m_xNextUnusedCharacterStyleNo = nMaxIndex + 1;
+ }
+
+ OUString sPageStyleName = cListLabel + OUString::number( *m_xNextUnusedCharacterStyleNo );
+ *m_xNextUnusedCharacterStyleNo = *m_xNextUnusedCharacterStyleNo + 1;
+ return sPageStyleName;
+}
+
+uno::Reference< text::XText > const & DomainMapper_Impl::GetBodyText()
+{
+ if(!m_xBodyText.is())
+ {
+ if (m_xInsertTextRange.is())
+ m_xBodyText = m_xInsertTextRange->getText();
+ else if (m_xTextDocument.is())
+ m_xBodyText = m_xTextDocument->getText();
+ }
+ return m_xBodyText;
+}
+
+
+uno::Reference< beans::XPropertySet > const & DomainMapper_Impl::GetDocumentSettings()
+{
+ if( !m_xDocumentSettings.is() && m_xTextFactory.is())
+ {
+ m_xDocumentSettings.set( m_xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY );
+ }
+ return m_xDocumentSettings;
+}
+
+
+void DomainMapper_Impl::SetDocumentSettingsProperty( const OUString& rPropName, const uno::Any& rValue )
+{
+ uno::Reference< beans::XPropertySet > xSettings = GetDocumentSettings();
+ if( xSettings.is() )
+ {
+ try
+ {
+ xSettings->setPropertyValue( rPropName, rValue );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+}
+void DomainMapper_Impl::RemoveDummyParaForTableInSection()
+{
+ SetIsDummyParaAddedForTableInSection(false);
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_SECTION);
+ SectionPropertyMap* pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
+ if (!pSectionContext)
+ return;
+
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is())
+ return;
+
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursorByRange(pSectionContext->GetStartingRange());
+
+ // Remove the extra NumPicBullets from the document,
+ // which get attached to the first paragraph in the
+ // document
+ ListsManager::Pointer pListTable = GetListTable();
+ pListTable->DisposeNumPicBullets();
+
+ uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xCursor, uno::UNO_QUERY);
+ if (xEnumerationAccess.is() && m_aTextAppendStack.size() == 1 )
+ {
+ uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ uno::Reference<lang::XComponent> xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
+ xParagraph->dispose();
+ }
+}
+void DomainMapper_Impl::AddDummyParaForTableInSection()
+{
+ // Shapes and textboxes can't have sections.
+ if (IsInShape() || m_bIsInTextBox)
+ return;
+
+ if (!m_aTextAppendStack.empty())
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is())
+ {
+ xTextAppend->finishParagraph( uno::Sequence< beans::PropertyValue >() );
+ SetIsDummyParaAddedForTableInSection(true);
+ }
+ }
+}
+
+ static OUString lcl_FindLastBookmark(const uno::Reference<text::XTextCursor>& xCursor)
+ {
+ OUString sName;
+ if (!xCursor.is())
+ return sName;
+
+ // Select 1 previous element
+ xCursor->goLeft(1, true);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCursor, uno::UNO_QUERY);
+ if (!xParaEnumAccess.is())
+ {
+ xCursor->goRight(1, true);
+ return sName;
+ }
+
+ // Iterate through selection paragraphs
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ if (!xParaEnum->hasMoreElements())
+ {
+ xCursor->goRight(1, true);
+ return sName;
+ }
+
+ // Iterate through first para portions
+ uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParaEnum->nextElement(),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ while (xRunEnum->hasMoreElements())
+ {
+ uno::Reference<beans::XPropertySet> xProps(xRunEnum->nextElement(), uno::UNO_QUERY_THROW);
+ uno::Any aType(xProps->getPropertyValue("TextPortionType"));
+ OUString sType;
+ aType >>= sType;
+ if (sType == "Bookmark")
+ {
+ uno::Reference<container::XNamed> xBookmark(xProps->getPropertyValue("Bookmark"),
+ uno::UNO_QUERY_THROW);
+ sName = xBookmark->getName();
+ // Do not stop the scan here. Maybe there are 2 bookmarks?
+ }
+ }
+
+ xCursor->goRight(1, true);
+ return sName;
+ }
+
+void DomainMapper_Impl::RemoveLastParagraph( )
+{
+ if (m_bDiscardHeaderFooter)
+ return;
+
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is())
+ return;
+ try
+ {
+ uno::Reference< text::XTextCursor > xCursor;
+ if (m_bIsNewDoc)
+ {
+ xCursor = xTextAppend->createTextCursor();
+ xCursor->gotoEnd(false);
+ }
+ else
+ xCursor = m_aTextAppendStack.top().xCursor;
+ uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xCursor, uno::UNO_QUERY);
+ // Keep the character properties of the last but one paragraph, even if
+ // it's empty. This works for headers/footers, and maybe in other cases
+ // as well, but surely not in textboxes.
+ // fdo#58327: also do this at the end of the document: when pasting,
+ // a table before the cursor position would be deleted
+ // (but only for paste/insert, not load; otherwise it can happen that
+ // flys anchored at the disposed paragraph are deleted (fdo47036.rtf))
+ bool const bEndOfDocument(m_aTextAppendStack.size() == 1);
+
+ // Try to find and remember last bookmark in document: it potentially
+ // can be deleted by xCursor->setString() but not by xParagraph->dispose()
+ OUString sLastBookmarkName;
+ if (bEndOfDocument)
+ sLastBookmarkName = lcl_FindLastBookmark(xCursor);
+
+ if ((IsInHeaderFooter() || (bEndOfDocument && !m_bIsNewDoc))
+ && xEnumerationAccess.is())
+ {
+ uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ uno::Reference<lang::XComponent> xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
+ xParagraph->dispose();
+ }
+ else if (xCursor.is())
+ {
+ xCursor->goLeft( 1, true );
+ // If this is a text on a shape, possibly the text has the trailing
+ // newline removed already.
+ if (xCursor->getString() == SAL_NEWLINE_STRING ||
+ // tdf#105444 comments need an exception, if SAL_NEWLINE_STRING defined as "\r\n"
+ (sizeof(SAL_NEWLINE_STRING)-1 == 2 && xCursor->getString() == "\n"))
+ {
+ uno::Reference<beans::XPropertySet> xDocProps(GetTextDocument(), uno::UNO_QUERY);
+ static const OUStringLiteral aRecordChanges(u"RecordChanges");
+ uno::Any aPreviousValue(xDocProps->getPropertyValue(aRecordChanges));
+
+ // disable redlining for this operation, otherwise we might
+ // end up with an unwanted recorded deletion
+ xDocProps->setPropertyValue(aRecordChanges, uno::Any(false));
+
+ // delete
+ xCursor->setString(OUString());
+
+ // While removing paragraphs that contain section properties, reset list
+ // related attributes to prevent them leaking into the following section's lists
+ if (GetParaSectpr())
+ {
+ uno::Reference<beans::XPropertySet> XCursorProps(xCursor, uno::UNO_QUERY);
+ XCursorProps->setPropertyValue("ResetParagraphListAttributes", uno::Any());
+ }
+
+ // call to xCursor->setString possibly did remove final bookmark
+ // from previous paragraph. We need to restore it, if there was any.
+ if (sLastBookmarkName.getLength())
+ {
+ OUString sBookmarkNameAfterRemoval = lcl_FindLastBookmark(xCursor);
+ if (sBookmarkNameAfterRemoval.isEmpty())
+ {
+ // Yes, it was removed. Restore
+ uno::Reference<text::XTextContent> xBookmark(
+ m_xTextFactory->createInstance("com.sun.star.text.Bookmark"),
+ uno::UNO_QUERY_THROW);
+
+ uno::Reference<container::XNamed> xBkmNamed(xBookmark,
+ uno::UNO_QUERY_THROW);
+ xBkmNamed->setName(sLastBookmarkName);
+ xTextAppend->insertTextContent(
+ uno::Reference<text::XTextRange>(xCursor, uno::UNO_QUERY_THROW),
+ xBookmark, !xCursor->isCollapsed());
+ }
+ }
+ // restore redline options again
+ xDocProps->setPropertyValue(aRecordChanges, aPreviousValue);
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+
+void DomainMapper_Impl::SetIsLastSectionGroup( bool bIsLast )
+{
+ m_bIsLastSectionGroup = bIsLast;
+}
+
+void DomainMapper_Impl::SetIsLastParagraphInSection( bool bIsLast )
+{
+ m_bIsLastParaInSection = bIsLast;
+}
+
+
+void DomainMapper_Impl::SetIsFirstParagraphInSection( bool bIsFirst )
+{
+ m_bIsFirstParaInSection = bIsFirst;
+}
+
+void DomainMapper_Impl::SetIsFirstParagraphInSectionAfterRedline( bool bIsFirstAfterRedline )
+{
+ m_bIsFirstParaInSectionAfterRedline = bIsFirstAfterRedline;
+}
+
+bool DomainMapper_Impl::GetIsFirstParagraphInSection( bool bAfterRedline ) const
+{
+ // Anchored objects may include multiple paragraphs,
+ // and none of them should be considered the first para in section.
+ return ( bAfterRedline ? m_bIsFirstParaInSectionAfterRedline : m_bIsFirstParaInSection )
+ && !IsInShape()
+ && !m_bIsInComments
+ && !IsInFootOrEndnote();
+}
+
+void DomainMapper_Impl::SetIsFirstParagraphInShape(bool bIsFirst)
+{
+ m_bIsFirstParaInShape = bIsFirst;
+}
+
+void DomainMapper_Impl::SetIsDummyParaAddedForTableInSection( bool bIsAdded )
+{
+ m_bDummyParaAddedForTableInSection = bIsAdded;
+ m_bDummyParaAddedForTableInSectionPage = bIsAdded;
+}
+
+void DomainMapper_Impl::SetIsDummyParaAddedForTableInSectionPage( bool bIsAdded )
+{
+ m_bDummyParaAddedForTableInSectionPage = bIsAdded;
+}
+
+
+void DomainMapper_Impl::SetIsTextFrameInserted( bool bIsInserted )
+{
+ m_bTextFrameInserted = bIsInserted;
+}
+
+
+void DomainMapper_Impl::SetParaSectpr(bool bParaSectpr)
+{
+ m_bParaSectpr = bParaSectpr;
+}
+
+
+void DomainMapper_Impl::SetSdt(bool bSdt)
+{
+ m_bSdt = bSdt;
+
+ if (m_bSdt && !m_aTextAppendStack.empty())
+ {
+ m_xSdtEntryStart = GetTopTextAppend()->getEnd();
+ }
+ else
+ {
+ m_xSdtEntryStart.clear();
+ }
+}
+
+void DomainMapper_Impl::PushSdt()
+{
+ if (m_aTextAppendStack.empty())
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ uno::Reference<text::XTextCursor> xCursor
+ = xTextAppend->getText()->createTextCursorByRange(xTextAppend->getEnd());
+ // Offset so the cursor is not adjusted as we import the SDT's content.
+ bool bStart = !xCursor->goLeft(1, /*bExpand=*/false);
+ m_xSdtStarts.push({bStart, OUString(), xCursor->getStart()});
+}
+
+const std::stack<BookmarkInsertPosition>& DomainMapper_Impl::GetSdtStarts() const
+{
+ return m_xSdtStarts;
+}
+
+void DomainMapper_Impl::PopSdt()
+{
+ if (m_xSdtStarts.empty())
+ {
+ return;
+ }
+
+ BookmarkInsertPosition aPosition = m_xSdtStarts.top();
+ m_xSdtStarts.pop();
+ uno::Reference<text::XTextRange> xStart = aPosition.m_xTextRange;
+ uno::Reference<text::XTextRange> xEnd = GetTopTextAppend()->getEnd();
+ uno::Reference<text::XText> xText = xEnd->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursorByRange(xStart);
+ if (!xCursor)
+ {
+ SAL_WARN("writerfilter.dmapper", "DomainMapper_Impl::PopSdt: no start position");
+ return;
+ }
+
+ if (aPosition.m_bIsStartOfText)
+ {
+ // Go to the start of the end's paragraph. This helps in case
+ // DomainMapper_Impl::AddDummyParaForTableInSection() would make our range multi-paragraph,
+ // while the intention is to keep start/end inside the same paragraph for run SDTs.
+ uno::Reference<text::XParagraphCursor> xParagraphCursor(xCursor, uno::UNO_QUERY);
+ if (xParagraphCursor.is())
+ {
+ xCursor->gotoRange(xEnd, /*bExpand=*/false);
+ xParagraphCursor->gotoStartOfParagraph(/*bExpand=*/false);
+ }
+ }
+ else
+ {
+ // Undo the goLeft() in DomainMapper_Impl::PushSdt();
+ xCursor->goRight(1, /*bExpand=*/false);
+ }
+ xCursor->gotoRange(xEnd, /*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ m_xTextFactory->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ if (m_pSdtHelper->GetShowingPlcHdr())
+ {
+ xContentControlProps->setPropertyValue("ShowingPlaceHolder",
+ uno::Any(m_pSdtHelper->GetShowingPlcHdr()));
+ }
+
+ if (!m_pSdtHelper->GetPlaceholderDocPart().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("PlaceholderDocPart",
+ uno::Any(m_pSdtHelper->GetPlaceholderDocPart()));
+ }
+
+ if (!m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("DataBindingPrefixMappings",
+ uno::Any(m_pSdtHelper->GetDataBindingPrefixMapping()));
+ }
+ if (!m_pSdtHelper->GetDataBindingXPath().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("DataBindingXpath",
+ uno::Any(m_pSdtHelper->GetDataBindingXPath()));
+ }
+ if (!m_pSdtHelper->GetDataBindingStoreItemID().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("DataBindingStoreItemID",
+ uno::Any(m_pSdtHelper->GetDataBindingStoreItemID()));
+ }
+
+ if (!m_pSdtHelper->GetColor().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Color",
+ uno::Any(m_pSdtHelper->GetColor()));
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::checkBox)
+ {
+ xContentControlProps->setPropertyValue("Checkbox", uno::Any(true));
+
+ xContentControlProps->setPropertyValue("Checked", uno::Any(m_pSdtHelper->GetChecked()));
+
+ xContentControlProps->setPropertyValue("CheckedState",
+ uno::Any(m_pSdtHelper->GetCheckedState()));
+
+ xContentControlProps->setPropertyValue("UncheckedState",
+ uno::Any(m_pSdtHelper->GetUncheckedState()));
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::dropDown)
+ {
+ std::vector<OUString>& rDisplayTexts = m_pSdtHelper->getDropDownDisplayTexts();
+ std::vector<OUString>& rValues = m_pSdtHelper->getDropDownItems();
+ if (rDisplayTexts.size() == rValues.size())
+ {
+ uno::Sequence<beans::PropertyValues> aItems(rValues.size());
+ beans::PropertyValues* pItems = aItems.getArray();
+ for (size_t i = 0; i < rValues.size(); ++i)
+ {
+ uno::Sequence<beans::PropertyValue> aItem = {
+ comphelper::makePropertyValue("DisplayText", rDisplayTexts[i]),
+ comphelper::makePropertyValue("Value", rValues[i]),
+ };
+ pItems[i] = aItem;
+ }
+ xContentControlProps->setPropertyValue("ListItems", uno::Any(aItems));
+ }
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::picture)
+ {
+ xContentControlProps->setPropertyValue("Picture", uno::Any(true));
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ {
+ xContentControlProps->setPropertyValue("Date", uno::Any(true));
+ OUString aDateFormat = m_pSdtHelper->getDateFormat().makeStringAndClear();
+ xContentControlProps->setPropertyValue("DateFormat",
+ uno::Any(aDateFormat.replaceAll("'", "\"")));
+ xContentControlProps->setPropertyValue("DateLanguage",
+ uno::Any(m_pSdtHelper->getLocale().makeStringAndClear()));
+ xContentControlProps->setPropertyValue("CurrentDate",
+ uno::Any(m_pSdtHelper->getDate().makeStringAndClear()));
+ }
+
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ m_pSdtHelper->clear();
+}
+
+void DomainMapper_Impl::PushProperties(ContextType eId)
+{
+ PropertyMapPtr pInsert(eId == CONTEXT_SECTION ?
+ (new SectionPropertyMap( m_bIsFirstSection )) :
+ eId == CONTEXT_PARAGRAPH ? new ParagraphPropertyMap : new PropertyMap);
+ if(eId == CONTEXT_SECTION)
+ {
+ if( m_bIsFirstSection )
+ m_bIsFirstSection = false;
+ // beginning with the second section group a section has to be inserted
+ // into the document
+ SectionPropertyMap* pSectionContext_ = dynamic_cast< SectionPropertyMap* >( pInsert.get() );
+ if (!m_aTextAppendStack.empty())
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is() && pSectionContext_)
+ pSectionContext_->SetStart( xTextAppend->getEnd() );
+ }
+ }
+ if(eId == CONTEXT_PARAGRAPH && m_bIsSplitPara)
+ {
+ m_aPropertyStacks[eId].push( GetTopContextOfType(eId));
+ m_bIsSplitPara = false;
+ }
+ else
+ {
+ m_aPropertyStacks[eId].push( pInsert );
+ }
+ m_aContextStack.push(eId);
+
+ m_pTopContext = m_aPropertyStacks[eId].top();
+}
+
+
+void DomainMapper_Impl::PushStyleProperties( const PropertyMapPtr& pStyleProperties )
+{
+ m_aPropertyStacks[CONTEXT_STYLESHEET].push( pStyleProperties );
+ m_aContextStack.push(CONTEXT_STYLESHEET);
+
+ m_pTopContext = m_aPropertyStacks[CONTEXT_STYLESHEET].top();
+}
+
+
+void DomainMapper_Impl::PushListProperties(const PropertyMapPtr& pListProperties)
+{
+ m_aPropertyStacks[CONTEXT_LIST].push( pListProperties );
+ m_aContextStack.push(CONTEXT_LIST);
+ m_pTopContext = m_aPropertyStacks[CONTEXT_LIST].top();
+}
+
+
+void DomainMapper_Impl::PopProperties(ContextType eId)
+{
+ OSL_ENSURE(!m_aPropertyStacks[eId].empty(), "section stack already empty");
+ if ( m_aPropertyStacks[eId].empty() )
+ return;
+
+ if ( eId == CONTEXT_SECTION )
+ {
+ if (m_aPropertyStacks[eId].size() == 1) // tdf#112202 only top level !!!
+ {
+ m_pLastSectionContext = m_aPropertyStacks[eId].top();
+ }
+ }
+ else if (eId == CONTEXT_CHARACTER)
+ {
+ m_pLastCharacterContext = m_aPropertyStacks[eId].top();
+ // Sadly an assert about deferredCharacterProperties being empty is not possible
+ // here, because appendTextPortion() may not be called for every character section.
+ deferredCharacterProperties.clear();
+ }
+
+ if (!IsInFootOrEndnote() && IsInCustomFootnote() && !m_aPropertyStacks[eId].empty())
+ {
+ PropertyMapPtr pRet = m_aPropertyStacks[eId].top();
+ if (pRet->GetFootnote().is() && m_pFootnoteContext.is())
+ EndCustomFootnote();
+ }
+
+ m_aPropertyStacks[eId].pop();
+ m_aContextStack.pop();
+ if(!m_aContextStack.empty() && !m_aPropertyStacks[m_aContextStack.top()].empty())
+
+ m_pTopContext = m_aPropertyStacks[m_aContextStack.top()].top();
+ else
+ {
+ // OSL_ENSURE(eId == CONTEXT_SECTION, "this should happen at a section context end");
+ m_pTopContext.clear();
+ }
+}
+
+
+PropertyMapPtr DomainMapper_Impl::GetTopContextOfType(ContextType eId)
+{
+ PropertyMapPtr pRet;
+ if(!m_aPropertyStacks[eId].empty())
+ pRet = m_aPropertyStacks[eId].top();
+ return pRet;
+}
+
+bool DomainMapper_Impl::HasTopText() const
+{
+ return !m_aTextAppendStack.empty();
+}
+
+uno::Reference< text::XTextAppend > const & DomainMapper_Impl::GetTopTextAppend()
+{
+ OSL_ENSURE(!m_aTextAppendStack.empty(), "text append stack is empty" );
+ return m_aTextAppendStack.top().xTextAppend;
+}
+
+FieldContextPtr const & DomainMapper_Impl::GetTopFieldContext()
+{
+ SAL_WARN_IF(m_aFieldStack.empty(), "writerfilter.dmapper", "Field stack is empty");
+ return m_aFieldStack.back();
+}
+
+bool DomainMapper_Impl::HasTopAnchoredObjects() const
+{
+ return !m_aTextAppendStack.empty() && !m_aTextAppendStack.top().m_aAnchoredObjects.empty();
+}
+
+void DomainMapper_Impl::InitTabStopFromStyle( const uno::Sequence< style::TabStop >& rInitTabStops )
+{
+ OSL_ENSURE(m_aCurrentTabStops.empty(), "tab stops already initialized");
+ for( const auto& rTabStop : rInitTabStops)
+ {
+ m_aCurrentTabStops.emplace_back(rTabStop);
+ }
+}
+
+void DomainMapper_Impl::IncorporateTabStop( const DeletableTabStop & rTabStop )
+{
+ sal_Int32 nConverted = rTabStop.Position;
+ auto aIt = std::find_if(m_aCurrentTabStops.begin(), m_aCurrentTabStops.end(),
+ [&nConverted](const DeletableTabStop& rCurrentTabStop) { return rCurrentTabStop.Position == nConverted; });
+ if( aIt != m_aCurrentTabStops.end() )
+ {
+ if( rTabStop.bDeleted )
+ m_aCurrentTabStops.erase( aIt );
+ else
+ *aIt = rTabStop;
+ }
+ else
+ m_aCurrentTabStops.push_back( rTabStop );
+}
+
+
+uno::Sequence< style::TabStop > DomainMapper_Impl::GetCurrentTabStopAndClear()
+{
+ std::vector<style::TabStop> aRet;
+ for (const DeletableTabStop& rStop : m_aCurrentTabStops)
+ {
+ if (!rStop.bDeleted)
+ aRet.push_back(rStop);
+ }
+ m_aCurrentTabStops.clear();
+ return comphelper::containerToSequence(aRet);
+}
+
+OUString DomainMapper_Impl::GetCurrentParaStyleName()
+{
+ OUString sName;
+ // use saved currParaStyleName as a fallback, in case no particular para style name applied.
+ // tdf#134784 except in the case of first paragraph of shapes to avoid bad fallback.
+ // TODO fix this "highly inaccurate" m_sCurrentParaStyleName
+ if ( !IsInShape() )
+ sName = m_sCurrentParaStyleName;
+
+ PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if ( pParaContext && pParaContext->isSet(PROP_PARA_STYLE_NAME) )
+ pParaContext->getProperty(PROP_PARA_STYLE_NAME)->second >>= sName;
+
+ // In rare situations the name might still be blank, so use the default style,
+ // despite documentation that states, "If this attribute is not specified for any style,
+ // then no properties shall be applied to objects of the specified type."
+ // Word, however, assigns "Normal" style even in these situations.
+ if ( !m_bInStyleSheetImport && sName.isEmpty() )
+ sName = GetDefaultParaStyleName();
+
+ return sName;
+}
+
+OUString DomainMapper_Impl::GetDefaultParaStyleName()
+{
+ // After import the default style won't change and is frequently requested: cache the LO style name.
+ // TODO assert !InStyleSheetImport? This function really only makes sense once import is finished anyway.
+ if ( m_sDefaultParaStyleName.isEmpty() )
+ {
+ const StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindDefaultParaStyle();
+ if ( pEntry && !pEntry->sConvertedStyleName.isEmpty() )
+ {
+ if ( !m_bInStyleSheetImport )
+ m_sDefaultParaStyleName = pEntry->sConvertedStyleName;
+ return pEntry->sConvertedStyleName;
+ }
+ else
+ return "Standard";
+ }
+ return m_sDefaultParaStyleName;
+}
+
+uno::Any DomainMapper_Impl::GetPropertyFromStyleSheet(PropertyIds eId, StyleSheetEntryPtr pEntry, const bool bDocDefaults, const bool bPara, bool* pIsDocDefault)
+{
+ while(pEntry)
+ {
+ if(pEntry->pProperties)
+ {
+ std::optional<PropertyMap::Property> aProperty =
+ pEntry->pProperties->getProperty(eId);
+ if( aProperty )
+ {
+ if (pIsDocDefault)
+ *pIsDocDefault = pEntry->pProperties->isDocDefault(eId);
+
+ return aProperty->second;
+ }
+ }
+ //search until the property is set or no parent is available
+ StyleSheetEntryPtr pNewEntry;
+ if ( !pEntry->sBaseStyleIdentifier.isEmpty() )
+ pNewEntry = GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
+
+ SAL_WARN_IF( pEntry == pNewEntry, "writerfilter.dmapper", "circular loop in style hierarchy?");
+
+ if (pEntry == pNewEntry) //fdo#49587
+ break;
+
+ pEntry = pNewEntry;
+ }
+ // not found in style, try the document's DocDefault properties
+ if ( bDocDefaults && bPara )
+ {
+ const PropertyMapPtr& pDefaultParaProps = GetStyleSheetTable()->GetDefaultParaProps();
+ if ( pDefaultParaProps )
+ {
+ std::optional<PropertyMap::Property> aProperty = pDefaultParaProps->getProperty(eId);
+ if ( aProperty )
+ {
+ if (pIsDocDefault)
+ *pIsDocDefault = true;
+
+ return aProperty->second;
+ }
+ }
+ }
+ if ( bDocDefaults && isCharacterProperty(eId) )
+ {
+ const PropertyMapPtr& pDefaultCharProps = GetStyleSheetTable()->GetDefaultCharProps();
+ if ( pDefaultCharProps )
+ {
+ std::optional<PropertyMap::Property> aProperty = pDefaultCharProps->getProperty(eId);
+ if ( aProperty )
+ {
+ if (pIsDocDefault)
+ *pIsDocDefault = true;
+
+ return aProperty->second;
+ }
+ }
+ }
+
+ if (pIsDocDefault)
+ *pIsDocDefault = false;
+
+ return uno::Any();
+}
+
+uno::Any DomainMapper_Impl::GetPropertyFromParaStyleSheet(PropertyIds eId)
+{
+ StyleSheetEntryPtr pEntry;
+ if ( m_bInStyleSheetImport )
+ pEntry = GetStyleSheetTable()->GetCurrentEntry();
+ else
+ pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(GetCurrentParaStyleName());
+ return GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true);
+}
+
+uno::Any DomainMapper_Impl::GetPropertyFromCharStyleSheet(PropertyIds eId, const PropertyMapPtr& rContext)
+{
+ if ( m_bInStyleSheetImport || eId == PROP_CHAR_STYLE_NAME || !isCharacterProperty(eId) )
+ return uno::Any();
+
+ StyleSheetEntryPtr pEntry;
+ OUString sCharStyleName;
+ if ( GetAnyProperty(PROP_CHAR_STYLE_NAME, rContext) >>= sCharStyleName )
+ pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(sCharStyleName);
+ return GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/false, /*bPara=*/false);
+}
+
+uno::Any DomainMapper_Impl::GetAnyProperty(PropertyIds eId, const PropertyMapPtr& rContext)
+{
+ // first look in directly applied attributes
+ if ( rContext )
+ {
+ std::optional<PropertyMap::Property> aProperty = rContext->getProperty(eId);
+ if ( aProperty )
+ return aProperty->second;
+ }
+
+ // then look whether it was directly applied as a paragraph property
+ PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (pParaContext && rContext != pParaContext)
+ {
+ std::optional<PropertyMap::Property> aProperty = pParaContext->getProperty(eId);
+ if (aProperty)
+ return aProperty->second;
+ }
+
+ // then look whether it was inherited from a directly applied character style
+ if ( eId != PROP_CHAR_STYLE_NAME && isCharacterProperty(eId) )
+ {
+ uno::Any aRet = GetPropertyFromCharStyleSheet(eId, rContext);
+ if ( aRet.hasValue() )
+ return aRet;
+ }
+
+ // then look in current paragraph style, and docDefaults
+ return GetPropertyFromParaStyleSheet(eId);
+}
+
+OUString DomainMapper_Impl::GetListStyleName(sal_Int32 nListId)
+{
+ auto const pList(GetListTable()->GetList( nListId ));
+ return pList ? pList->GetStyleName() : OUString();
+}
+
+ListsManager::Pointer const & DomainMapper_Impl::GetListTable()
+{
+ if(!m_pListTable)
+ m_pListTable =
+ new ListsManager( m_rDMapper, m_xTextFactory );
+ return m_pListTable;
+}
+
+
+void DomainMapper_Impl::deferBreak( BreakType deferredBreakType)
+{
+ switch (deferredBreakType)
+ {
+ case LINE_BREAK:
+ m_nLineBreaksDeferred++;
+ break;
+ case COLUMN_BREAK:
+ m_bIsColumnBreakDeferred = true;
+ break;
+ case PAGE_BREAK:
+ // See SwWW8ImplReader::HandlePageBreakChar(), page break should be
+ // ignored inside tables.
+ if (m_nTableDepth > 0)
+ return;
+
+ m_bIsPageBreakDeferred = true;
+ break;
+ default:
+ return;
+ }
+}
+
+bool DomainMapper_Impl::isBreakDeferred( BreakType deferredBreakType )
+{
+ switch (deferredBreakType)
+ {
+ case LINE_BREAK:
+ return m_nLineBreaksDeferred > 0;
+ case COLUMN_BREAK:
+ return m_bIsColumnBreakDeferred;
+ case PAGE_BREAK:
+ return m_bIsPageBreakDeferred;
+ default:
+ return false;
+ }
+}
+
+void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType)
+{
+ switch (deferredBreakType)
+ {
+ case LINE_BREAK:
+ assert(m_nLineBreaksDeferred > 0);
+ m_nLineBreaksDeferred--;
+ break;
+ case COLUMN_BREAK:
+ m_bIsColumnBreakDeferred = false;
+ break;
+ case PAGE_BREAK:
+ m_bIsPageBreakDeferred = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void DomainMapper_Impl::clearDeferredBreaks()
+{
+ m_nLineBreaksDeferred = 0;
+ m_bIsColumnBreakDeferred = false;
+ m_bIsPageBreakDeferred = false;
+}
+
+void DomainMapper_Impl::setSdtEndDeferred(bool bSdtEndDeferred)
+{
+ m_bSdtEndDeferred = bSdtEndDeferred;
+}
+
+bool DomainMapper_Impl::isSdtEndDeferred() const
+{
+ return m_bSdtEndDeferred;
+}
+
+void DomainMapper_Impl::setParaSdtEndDeferred(bool bParaSdtEndDeferred)
+{
+ m_bParaSdtEndDeferred = bParaSdtEndDeferred;
+}
+
+bool DomainMapper_Impl::isParaSdtEndDeferred() const
+{
+ return m_bParaSdtEndDeferred;
+}
+
+static void lcl_MoveBorderPropertiesToFrame(std::vector<beans::PropertyValue>& rFrameProperties,
+ uno::Reference<text::XTextRange> const& xStartTextRange,
+ uno::Reference<text::XTextRange> const& xEndTextRange )
+{
+ try
+ {
+ if (!xStartTextRange.is()) //rhbz#1077780
+ return;
+ uno::Reference<text::XTextCursor> xRangeCursor = xStartTextRange->getText()->createTextCursorByRange( xStartTextRange );
+ xRangeCursor->gotoRange( xEndTextRange, true );
+
+ uno::Reference<beans::XPropertySet> xTextRangeProperties(xRangeCursor, uno::UNO_QUERY);
+ if(!xTextRangeProperties.is())
+ return ;
+
+ static PropertyIds const aBorderProperties[] =
+ {
+ PROP_LEFT_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_TOP_BORDER,
+ PROP_BOTTOM_BORDER,
+ PROP_LEFT_BORDER_DISTANCE,
+ PROP_RIGHT_BORDER_DISTANCE,
+ PROP_TOP_BORDER_DISTANCE,
+ PROP_BOTTOM_BORDER_DISTANCE
+ };
+
+ for( size_t nProperty = 0; nProperty < SAL_N_ELEMENTS( aBorderProperties ); ++nProperty)
+ {
+ OUString sPropertyName = getPropertyName(aBorderProperties[nProperty]);
+ beans::PropertyValue aValue;
+ aValue.Name = sPropertyName;
+ aValue.Value = xTextRangeProperties->getPropertyValue(sPropertyName);
+ rFrameProperties.push_back(aValue);
+ if( nProperty < 4 )
+ xTextRangeProperties->setPropertyValue( sPropertyName, uno::Any(table::BorderLine2()));
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+
+static void lcl_AddRangeAndStyle(
+ ParagraphPropertiesPtr const & pToBeSavedProperties,
+ uno::Reference< text::XTextAppend > const& xTextAppend,
+ const PropertyMapPtr& pPropertyMap,
+ TextAppendContext const & rAppendContext)
+{
+ uno::Reference<text::XParagraphCursor> xParaCursor(
+ xTextAppend->createTextCursorByRange( rAppendContext.xInsertPosition.is() ? rAppendContext.xInsertPosition : xTextAppend->getEnd()), uno::UNO_QUERY_THROW );
+ pToBeSavedProperties->SetEndingRange(xParaCursor->getStart());
+ xParaCursor->gotoStartOfParagraph( false );
+
+ pToBeSavedProperties->SetStartingRange(xParaCursor->getStart());
+ if(pPropertyMap)
+ {
+ std::optional<PropertyMap::Property> aParaStyle = pPropertyMap->getProperty(PROP_PARA_STYLE_NAME);
+ if( aParaStyle )
+ {
+ OUString sName;
+ aParaStyle->second >>= sName;
+ pToBeSavedProperties->SetParaStyleName(sName);
+ }
+ }
+}
+
+
+//define some default frame width - 0cm ATM: this allow the frame to be wrapped around the text
+constexpr sal_Int32 DEFAULT_FRAME_MIN_WIDTH = 0;
+constexpr sal_Int32 DEFAULT_FRAME_MIN_HEIGHT = 0;
+constexpr sal_Int32 DEFAULT_VALUE = 0;
+
+void DomainMapper_Impl::CheckUnregisteredFrameConversion( )
+{
+ if (m_aTextAppendStack.empty())
+ return;
+ TextAppendContext& rAppendContext = m_aTextAppendStack.top();
+ // n#779642: ignore fly frame inside table as it could lead to messy situations
+ if (!rAppendContext.pLastParagraphProperties)
+ return;
+ if (!rAppendContext.pLastParagraphProperties->IsFrameMode())
+ return;
+ if (!hasTableManager())
+ return;
+ if (getTableManager().isInTable())
+ return;
+ try
+ {
+ StyleSheetEntryPtr pParaStyle =
+ GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(rAppendContext.pLastParagraphProperties->GetParaStyleName());
+
+ std::vector<beans::PropertyValue> aFrameProperties;
+
+ if ( pParaStyle )
+ {
+ const StyleSheetPropertyMap* pStyleProperties = pParaStyle->pProperties.get();
+ if (!pStyleProperties)
+ return;
+ sal_Int32 nWidth =
+ rAppendContext.pLastParagraphProperties->Getw() > 0 ?
+ rAppendContext.pLastParagraphProperties->Getw() :
+ pStyleProperties->Getw();
+ bool bAutoWidth = nWidth < 1;
+ if( bAutoWidth )
+ nWidth = DEFAULT_FRAME_MIN_WIDTH;
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH), nWidth));
+
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEIGHT),
+ rAppendContext.pLastParagraphProperties->Geth() > 0 ?
+ rAppendContext.pLastParagraphProperties->Geth() :
+ pStyleProperties->Geth() > 0 ? pStyleProperties->Geth() : DEFAULT_FRAME_MIN_HEIGHT));
+
+ sal_Int16 nhRule = sal_Int16(
+ rAppendContext.pLastParagraphProperties->GethRule() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GethRule() :
+ pStyleProperties->GethRule());
+ if ( nhRule < 0 )
+ {
+ if ( rAppendContext.pLastParagraphProperties->Geth() >= 0 ||
+ pStyleProperties->GethRule() >= 0 )
+ {
+ // [MS-OE376] Word uses a default value of "atLeast" for
+ // this attribute when the value of the h attribute is not 0.
+ nhRule = text::SizeType::MIN;
+ }
+ else
+ {
+ nhRule = text::SizeType::VARIABLE;
+ }
+ }
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), nhRule));
+
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), bAutoWidth ? text::SizeType::MIN : text::SizeType::FIX));
+
+ if (const std::optional<sal_Int16> nDirection = PopFrameDirection())
+ {
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_FRM_DIRECTION), *nDirection));
+ }
+
+ sal_Int16 nHoriOrient = sal_Int16(
+ rAppendContext.pLastParagraphProperties->GetxAlign() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetxAlign() :
+ pStyleProperties->GetxAlign() >= 0 ? pStyleProperties->GetxAlign() : text::HoriOrientation::NONE );
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), nHoriOrient));
+
+ //set a non negative default value
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_POSITION),
+ rAppendContext.pLastParagraphProperties->IsxValid() ?
+ rAppendContext.pLastParagraphProperties->Getx() :
+ pStyleProperties->IsxValid() ? pStyleProperties->Getx() : DEFAULT_VALUE));
+
+ //Default the anchor in case FramePr_hAnchor is missing ECMA 17.3.1.11
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_RELATION), sal_Int16(
+ rAppendContext.pLastParagraphProperties->GethAnchor() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GethAnchor() :
+ pStyleProperties->GethAnchor() >=0 ? pStyleProperties->GethAnchor() : text::RelOrientation::FRAME )));
+
+ sal_Int16 nVertOrient = sal_Int16(
+ rAppendContext.pLastParagraphProperties->GetyAlign() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetyAlign() :
+ pStyleProperties->GetyAlign() >= 0 ? pStyleProperties->GetyAlign() : text::VertOrientation::NONE );
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), nVertOrient));
+
+ //set a non negative default value
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_POSITION),
+ rAppendContext.pLastParagraphProperties->IsyValid() ?
+ rAppendContext.pLastParagraphProperties->Gety() :
+ pStyleProperties->IsyValid() ? pStyleProperties->Gety() : DEFAULT_VALUE));
+
+ //Default the anchor in case FramePr_vAnchor is missing ECMA 17.3.1.11
+ if (rAppendContext.pLastParagraphProperties->GetWrap() == text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE &&
+ pStyleProperties->GetWrap() == text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE)
+ {
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_RELATION), sal_Int16(
+ rAppendContext.pLastParagraphProperties->GetvAnchor() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetvAnchor() :
+ pStyleProperties->GetvAnchor() >= 0 ? pStyleProperties->GetvAnchor() : text::RelOrientation::FRAME)));
+ }
+ else
+ {
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_RELATION), sal_Int16(
+ rAppendContext.pLastParagraphProperties->GetvAnchor() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetvAnchor() :
+ pStyleProperties->GetvAnchor() >= 0 ? pStyleProperties->GetvAnchor() : text::RelOrientation::PAGE_PRINT_AREA)));
+ }
+
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SURROUND),
+ rAppendContext.pLastParagraphProperties->GetWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE
+ ? rAppendContext.pLastParagraphProperties->GetWrap()
+ : pStyleProperties->GetWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE
+ ? pStyleProperties->GetWrap()
+ : text::WrapTextMode_NONE ));
+
+ /** FDO#73546 : distL & distR should be unsigned integers <Ecma 20.4.3.6>
+ Swapped the array elements 11,12 & 13,14 since 11 & 12 are
+ LEFT & RIGHT margins and 13,14 are TOP and BOTTOM margins respectively.
+ */
+ sal_Int32 nRightDist;
+ sal_Int32 nLeftDist = nRightDist =
+ rAppendContext.pLastParagraphProperties->GethSpace() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GethSpace() :
+ pStyleProperties->GethSpace() >= 0 ? pStyleProperties->GethSpace() : 0;
+
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LEFT_MARGIN), nHoriOrient == text::HoriOrientation::LEFT ? 0 : nLeftDist));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_RIGHT_MARGIN), nHoriOrient == text::HoriOrientation::RIGHT ? 0 : nRightDist));
+
+ sal_Int32 nBottomDist;
+ sal_Int32 nTopDist = nBottomDist =
+ rAppendContext.pLastParagraphProperties->GetvSpace() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetvSpace() :
+ pStyleProperties->GetvSpace() >= 0 ? pStyleProperties->GetvSpace() : 0;
+
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_TOP_MARGIN), nVertOrient == text::VertOrientation::TOP ? 0 : nTopDist));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_BOTTOM_MARGIN), nVertOrient == text::VertOrientation::BOTTOM ? 0 : nBottomDist));
+ // If there is no fill, the Word default is 100% transparency.
+ // Otherwise CellColorHandler has priority, and this setting
+ // will be ignored.
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_BACK_COLOR_TRANSPARENCY), sal_Int32(100)));
+
+ uno::Sequence<beans::PropertyValue> aGrabBag( comphelper::InitPropertySequence({
+ { "ParaFrameProperties", uno::Any(rAppendContext.pLastParagraphProperties->IsFrameMode()) }
+ }));
+ aFrameProperties.push_back(comphelper::makePropertyValue("FrameInteropGrabBag", aGrabBag));
+
+ lcl_MoveBorderPropertiesToFrame(aFrameProperties,
+ rAppendContext.pLastParagraphProperties->GetStartingRange(),
+ rAppendContext.pLastParagraphProperties->GetEndingRange());
+ }
+ else
+ {
+ sal_Int32 nWidth = rAppendContext.pLastParagraphProperties->Getw();
+ bool bAutoWidth = nWidth < 1;
+ if( bAutoWidth )
+ nWidth = DEFAULT_FRAME_MIN_WIDTH;
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH), nWidth));
+
+ sal_Int16 nhRule = sal_Int16(rAppendContext.pLastParagraphProperties->GethRule());
+ if ( nhRule < 0 )
+ {
+ if ( rAppendContext.pLastParagraphProperties->Geth() >= 0 )
+ {
+ // [MS-OE376] Word uses a default value of atLeast for
+ // this attribute when the value of the h attribute is not 0.
+ nhRule = text::SizeType::MIN;
+ }
+ else
+ {
+ nhRule = text::SizeType::VARIABLE;
+ }
+ }
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), nhRule));
+
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), bAutoWidth ? text::SizeType::MIN : text::SizeType::FIX));
+
+ sal_Int16 nHoriOrient = sal_Int16(
+ rAppendContext.pLastParagraphProperties->GetxAlign() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetxAlign() :
+ text::HoriOrientation::NONE );
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), nHoriOrient));
+
+ sal_Int16 nVertOrient = sal_Int16(
+ rAppendContext.pLastParagraphProperties->GetyAlign() >= 0 ?
+ rAppendContext.pLastParagraphProperties->GetyAlign() :
+ text::VertOrientation::NONE );
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), nVertOrient));
+
+ sal_Int32 nVertDist = rAppendContext.pLastParagraphProperties->GethSpace();
+ if( nVertDist < 0 )
+ nVertDist = 0;
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LEFT_MARGIN), nVertOrient == text::VertOrientation::TOP ? 0 : nVertDist));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_RIGHT_MARGIN), nVertOrient == text::VertOrientation::BOTTOM ? 0 : nVertDist));
+
+ sal_Int32 nHoriDist = rAppendContext.pLastParagraphProperties->GetvSpace();
+ if( nHoriDist < 0 )
+ nHoriDist = 0;
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_TOP_MARGIN), nHoriOrient == text::HoriOrientation::LEFT ? 0 : nHoriDist));
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_BOTTOM_MARGIN), nHoriOrient == text::HoriOrientation::RIGHT ? 0 : nHoriDist));
+
+ if( rAppendContext.pLastParagraphProperties->Geth() > 0 )
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEIGHT), rAppendContext.pLastParagraphProperties->Geth()));
+
+ if( rAppendContext.pLastParagraphProperties->IsxValid() )
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_POSITION), rAppendContext.pLastParagraphProperties->Getx()));
+
+ if( rAppendContext.pLastParagraphProperties->GethAnchor() >= 0 )
+ aFrameProperties.push_back(comphelper::makePropertyValue("HoriOrientRelation", sal_Int16(rAppendContext.pLastParagraphProperties->GethAnchor())));
+
+ if( rAppendContext.pLastParagraphProperties->IsyValid() )
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_POSITION), rAppendContext.pLastParagraphProperties->Gety()));
+
+ if( rAppendContext.pLastParagraphProperties->GetvAnchor() >= 0 )
+ aFrameProperties.push_back(comphelper::makePropertyValue("VertOrientRelation", sal_Int16(rAppendContext.pLastParagraphProperties->GetvAnchor())));
+
+ if( rAppendContext.pLastParagraphProperties->GetWrap() >= text::WrapTextMode_NONE )
+ aFrameProperties.push_back(comphelper::makePropertyValue("Surround", rAppendContext.pLastParagraphProperties->GetWrap()));
+
+ lcl_MoveBorderPropertiesToFrame(aFrameProperties,
+ rAppendContext.pLastParagraphProperties->GetStartingRange(),
+ rAppendContext.pLastParagraphProperties->GetEndingRange());
+ }
+
+ //frame conversion has to be executed after table conversion
+ RegisterFrameConversion(
+ rAppendContext.pLastParagraphProperties->GetStartingRange(),
+ rAppendContext.pLastParagraphProperties->GetEndingRange(),
+ std::move(aFrameProperties) );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+/// Check if the style or its parent has a list id, recursively.
+static sal_Int32 lcl_getListId(const StyleSheetEntryPtr& rEntry, const StyleSheetTablePtr& rStyleTable, bool & rNumberingFromBaseStyle)
+{
+ const StyleSheetPropertyMap* pEntryProperties = rEntry->pProperties.get();
+ if (!pEntryProperties)
+ return -1;
+
+ sal_Int32 nListId = pEntryProperties->GetListId();
+ // The style itself has a list id.
+ if (nListId >= 0)
+ return nListId;
+
+ // The style has no parent.
+ if (rEntry->sBaseStyleIdentifier.isEmpty())
+ return -1;
+
+ const StyleSheetEntryPtr pParent = rStyleTable->FindStyleSheetByISTD(rEntry->sBaseStyleIdentifier);
+ // No such parent style or loop in the style hierarchy.
+ if (!pParent || pParent == rEntry)
+ return -1;
+
+ rNumberingFromBaseStyle = true;
+
+ return lcl_getListId(pParent, rStyleTable, rNumberingFromBaseStyle);
+}
+
+/// Return the paragraph's list level (from styles, unless pParacontext is provided).
+/// -1 indicates the level is not set anywhere. [In that case, with a numId, use 0 (level 1)]
+/// 9 indicates that numbering should be at body level (aka disabled) - rarely used by MSWord.
+/// 0-8 are the nine valid numbering levels.
+sal_Int16 DomainMapper_Impl::GetListLevel(const StyleSheetEntryPtr& pEntry,
+ const PropertyMapPtr& pParaContext)
+{
+ sal_Int16 nListLevel = -1;
+ if (pParaContext)
+ {
+ // Deliberately ignore inherited PROP_NUMBERING_LEVEL. Only trust StyleSheetEntry for that.
+ std::optional<PropertyMap::Property> aLvl = pParaContext->getProperty(PROP_NUMBERING_LEVEL);
+ if (aLvl)
+ aLvl->second >>= nListLevel;
+
+ if (nListLevel != -1)
+ return nListLevel;
+ }
+
+ if (!pEntry)
+ return -1;
+
+ const StyleSheetPropertyMap* pEntryProperties = pEntry->pProperties.get();
+ if (!pEntryProperties)
+ return -1;
+
+ nListLevel = pEntryProperties->GetListLevel();
+ // The style itself has a list level.
+ if (nListLevel >= 0)
+ return nListLevel;
+
+ // The style has no parent.
+ if (pEntry->sBaseStyleIdentifier.isEmpty())
+ return -1;
+
+ const StyleSheetEntryPtr pParent = GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
+ // No such parent style or loop in the style hierarchy.
+ if (!pParent || pParent == pEntry)
+ return -1;
+
+ return GetListLevel(pParent);
+}
+
+void DomainMapper_Impl::ValidateListLevel(const OUString& sStyleIdentifierD)
+{
+ StyleSheetEntryPtr pMyStyle = GetStyleSheetTable()->FindStyleSheetByISTD(sStyleIdentifierD);
+ if (!pMyStyle)
+ return;
+
+ sal_Int8 nListLevel = GetListLevel(pMyStyle);
+ if (nListLevel < 0 || nListLevel >= WW_OUTLINE_MAX)
+ return;
+
+ bool bDummy = false;
+ sal_Int16 nListId = lcl_getListId(pMyStyle, GetStyleSheetTable(), bDummy);
+ if (nListId < 1)
+ return;
+
+ auto const pList(GetListTable()->GetList(nListId));
+ if (!pList)
+ return;
+
+ auto pLevel = pList->GetLevel(nListLevel);
+ if (!pLevel && pList->GetAbstractDefinition())
+ pLevel = pList->GetAbstractDefinition()->GetLevel(nListLevel);
+ if (!pLevel)
+ return;
+
+ if (!pLevel->GetParaStyle())
+ {
+ // First come, first served, and it hasn't been claimed yet, so claim it now.
+ pLevel->SetParaStyle(pMyStyle);
+ }
+ else if (pLevel->GetParaStyle() != pMyStyle)
+ {
+ // This level is already used by another style, so prevent numbering via this style
+ // by setting to body level (9).
+ pMyStyle->pProperties->SetListLevel(WW_OUTLINE_MAX);
+ // WARNING: PROP_NUMBERING_LEVEL is now out of sync with GetListLevel()
+ }
+}
+
+void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove, const bool bNoNumbering )
+{
+ if (m_bDiscardHeaderFooter)
+ return;
+
+ if (!m_aFieldStack.empty())
+ {
+ FieldContextPtr pFieldContext = m_aFieldStack.back();
+ if (pFieldContext && !pFieldContext->IsCommandCompleted())
+ {
+ std::vector<OUString> aCommandParts = pFieldContext->GetCommandParts();
+ if (!aCommandParts.empty() && aCommandParts[0] == "IF")
+ {
+ // Conditional text field conditions don't support linebreaks in Writer.
+ return;
+ }
+ }
+
+ if (pFieldContext && pFieldContext->IsCommandCompleted())
+ {
+ if (pFieldContext->GetFieldId() == FIELD_IF)
+ {
+ // Conditional text fields can't contain newlines, finish the paragraph later.
+ FieldParagraph aFinish{pPropertyMap, bRemove};
+ pFieldContext->GetParagraphsToFinish().push_back(aFinish);
+ return;
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("finishParagraph");
+#endif
+
+ m_nLastTableCellParagraphDepth = m_nTableCellDepth;
+ ParagraphPropertyMap* pParaContext = dynamic_cast< ParagraphPropertyMap* >( pPropertyMap.get() );
+ if (m_aTextAppendStack.empty())
+ return;
+ TextAppendContext& rAppendContext = m_aTextAppendStack.top();
+ uno::Reference< text::XTextAppend > xTextAppend(rAppendContext.xTextAppend);
+#ifdef DBG_UTIL
+ TagLogger::getInstance().attribute("isTextAppend", sal_uInt32(xTextAppend.is()));
+#endif
+
+ const StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( GetCurrentParaStyleName() );
+ OSL_ENSURE( pEntry, "no style sheet found" );
+ const StyleSheetPropertyMap* pStyleSheetProperties = pEntry ? pEntry->pProperties.get() : nullptr;
+ sal_Int32 nListId = pParaContext ? pParaContext->GetListId() : -1;
+ bool isNumberingViaStyle(false);
+ bool isNumberingViaRule = nListId > -1;
+ if ( !bRemove && pStyleSheetProperties && pParaContext )
+ {
+ bool bNumberingFromBaseStyle = false;
+ if (!isNumberingViaRule)
+ nListId = lcl_getListId(pEntry, GetStyleSheetTable(), bNumberingFromBaseStyle);
+
+ //apply numbering level/style to paragraph if it was set at the style, but only if the paragraph itself
+ //does not specify the numbering
+ sal_Int16 nListLevel = GetListLevel(pEntry, pParaContext);
+ // Undefined listLevel with a valid numId is treated as a first level numbering.
+ if (nListLevel == -1 && nListId > (IsOOXMLImport() ? 0 : -1))
+ nListLevel = 0;
+
+ if (!bNoNumbering && nListLevel >= 0 && nListLevel < 9)
+ pParaContext->Insert( PROP_NUMBERING_LEVEL, uno::Any(nListLevel), false );
+
+ auto const pList(GetListTable()->GetList(nListId));
+ if (pList && !pParaContext->isSet(PROP_NUMBERING_STYLE_NAME))
+ {
+ // ListLevel 9 means Body Level/no numbering.
+ if (bNoNumbering || nListLevel == 9)
+ {
+ pParaContext->Insert(PROP_NUMBERING_STYLE_NAME, uno::Any(OUString()), true);
+ pParaContext->Erase(PROP_NUMBERING_LEVEL);
+ }
+ else if ( !isNumberingViaRule )
+ {
+ isNumberingViaStyle = true;
+ // Since LO7.0/tdf#131321 fixed the loss of numbering in styles, this OUGHT to be obsolete,
+ // but now other new/critical LO7.0 code expects it, and perhaps some corner cases still need it as well.
+ pParaContext->Insert(PROP_NUMBERING_STYLE_NAME, uno::Any(pList->GetStyleName()), true);
+ }
+ else
+ {
+ // we have direct numbering, as well as paragraph-style numbering.
+ // Apply the style if it uses the same list as the direct numbering,
+ // otherwise the directly-applied-to-paragraph status will be lost,
+ // and the priority of the numbering-style-indents will be lowered. tdf#133000
+ bool bDummy;
+ if (nListId == lcl_getListId(pEntry, GetStyleSheetTable(), bDummy))
+ pParaContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::Any(pList->GetStyleName()), true );
+ }
+ }
+
+ if ( isNumberingViaStyle )
+ {
+ // When numbering is defined by the paragraph style, then the para-style indents have priority.
+ // But since import has just copied para-style's PROP_NUMBERING_STYLE_NAME directly onto the paragraph,
+ // the numbering indents now have the priority.
+ // So now import must also copy the para-style indents directly onto the paragraph to compensate.
+ std::optional<PropertyMap::Property> oProperty;
+ const StyleSheetEntryPtr pParent = (!pEntry->sBaseStyleIdentifier.isEmpty()) ? GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier) : nullptr;
+ const StyleSheetPropertyMap* pParentProperties = pParent ? pParent->pProperties.get() : nullptr;
+ if (!pEntry->sBaseStyleIdentifier.isEmpty())
+ {
+ oProperty = pStyleSheetProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT);
+ if ( oProperty
+ // If the numbering comes from a base style, indent of the base style has also priority.
+ || (bNumberingFromBaseStyle && pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT))) )
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, oProperty->second, /*bOverwrite=*/false);
+ }
+ oProperty = pStyleSheetProperties->getProperty(PROP_PARA_LEFT_MARGIN);
+ if ( oProperty
+ || (bNumberingFromBaseStyle && pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_LEFT_MARGIN))) )
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, oProperty->second, /*bOverwrite=*/false);
+
+ // We're inheriting properties from a numbering style. Make sure a possible right margin is inherited from the base style.
+ sal_Int32 nParaRightMargin;
+ if ( pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_RIGHT_MARGIN)) && (nParaRightMargin = oProperty->second.get<sal_Int32>()) != 0 )
+ {
+ // If we're setting the right margin, we should set the first / left margin as well from the numbering style.
+ const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, nListLevel, "FirstLineIndent");
+ const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, nListLevel, "IndentAt");
+ if (nFirstLineIndent != 0)
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+ if (nParaLeftMargin != 0)
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+
+ // Override right margin value with value from current style, if any
+ if (pStyleSheetProperties && pStyleSheetProperties->isSet(PROP_PARA_RIGHT_MARGIN))
+ nParaRightMargin = pStyleSheetProperties->getProperty(PROP_PARA_RIGHT_MARGIN)->second.get<sal_Int32>();
+
+ pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, uno::Any(nParaRightMargin), /*bOverwrite=*/false);
+ }
+ }
+ // Paragraph style based right paragraph indentation affects not paragraph style based lists in DOCX.
+ // Apply it as direct formatting, also left and first line indentation of numbering to keep them.
+ else if (isNumberingViaRule)
+ {
+ uno::Any aRightMargin = GetPropertyFromParaStyleSheet(PROP_PARA_RIGHT_MARGIN);
+ if ( aRightMargin != uno::Any() )
+ {
+ pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, aRightMargin, /*bOverwrite=*/false);
+
+ const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, nListLevel, "FirstLineIndent");
+ const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, nListLevel, "IndentAt");
+ if (nFirstLineIndent != 0)
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+ if (nParaLeftMargin != 0)
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+ }
+ }
+
+ if (nListId == 0 && !pList)
+ {
+ // listid = 0 and no list definition is used in DOCX to stop numbering
+ // defined somewhere in parent styles
+ // And here we should explicitly set left margin and first-line margin.
+ // They can be taken from referred style, but not from styles with listid!
+ uno::Any aProp = lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_FIRST_LINE_INDENT, pEntry, m_pStyleSheetTable);
+ if (aProp.hasValue())
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, aProp, false);
+ else
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(sal_uInt32(0)), false);
+
+ aProp = lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_LEFT_MARGIN, pEntry, m_pStyleSheetTable);
+ if (aProp.hasValue())
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, aProp, false);
+ else
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(sal_uInt32(0)), false);
+ }
+ }
+
+ // apply AutoSpacing: it has priority over all other margin settings
+ // (note that numbering with autoSpacing is handled separately later on)
+ const bool bAllowAdjustments = !GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing();
+ sal_Int32 nBeforeAutospacing = -1;
+ bool bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING);
+ const bool bNoTopmargin = pParaContext && !pParaContext->isSet(PROP_PARA_TOP_MARGIN);
+ // apply INHERITED autospacing only if top margin is not set
+ if ( bIsAutoSet || bNoTopmargin )
+ {
+ GetAnyProperty(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, pPropertyMap) >>= nBeforeAutospacing;
+ // tdf#137655 only w:beforeAutospacing=0 was specified, but not PARA_TOP_MARGIN
+ // (see default_spacing = -1 in processing of LN_CT_Spacing_beforeAutospacing)
+ if ( bNoTopmargin && nBeforeAutospacing == ConversionHelper::convertTwipToMM100(-1) )
+ {
+ sal_Int32 nStyleAuto = -1;
+ GetPropertyFromParaStyleSheet(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING) >>= nStyleAuto;
+ if (nStyleAuto > 0)
+ nBeforeAutospacing = 0;
+ }
+ }
+ if ( nBeforeAutospacing > -1 && pParaContext )
+ {
+ if (bAllowAdjustments)
+ {
+ if ( GetIsFirstParagraphInShape() ||
+ (GetIsFirstParagraphInSection() && GetSectionContext() && GetSectionContext()->IsFirstSection()) ||
+ (m_bFirstParagraphInCell && m_nTableDepth > 0 && m_nTableDepth == m_nTableCellDepth) )
+ {
+ // export requires grabbag to match top_margin, so keep them in sync
+ if (nBeforeAutospacing && bIsAutoSet)
+ pParaContext->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::Any( sal_Int32(0) ),true, PARA_GRAB_BAG );
+ nBeforeAutospacing = 0;
+ }
+ }
+ pParaContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(nBeforeAutospacing));
+ }
+
+ sal_Int32 nAfterAutospacing = -1;
+ bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING);
+ const bool bNoBottomMargin = pParaContext && !pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN);
+ bool bAppliedBottomAutospacing = false;
+ if (bIsAutoSet || bNoBottomMargin)
+ {
+ GetAnyProperty(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, pPropertyMap) >>= nAfterAutospacing;
+ if (bNoBottomMargin && nAfterAutospacing == ConversionHelper::convertTwipToMM100(-1))
+ {
+ sal_Int32 nStyleAuto = -1;
+ GetPropertyFromParaStyleSheet(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING) >>= nStyleAuto;
+ if (nStyleAuto > 0)
+ nAfterAutospacing = 0;
+ }
+ }
+ if ( nAfterAutospacing > -1 && pParaContext )
+ {
+ pParaContext->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any(nAfterAutospacing));
+ bAppliedBottomAutospacing = bAllowAdjustments;
+ }
+
+ // tell TableManager to reset the bottom margin if it determines that this is the cell's last paragraph.
+ if ( hasTableManager() && getTableManager().isInCell() )
+ getTableManager().setCellLastParaAfterAutospacing(bAppliedBottomAutospacing);
+
+ if (xTextAppend.is() && pParaContext && hasTableManager() && !getTableManager().isIgnore())
+ {
+ try
+ {
+ /*the following combinations of previous and current frame settings can occur:
+ (1) - no old frame and no current frame -> no special action
+ (2) - no old frame and current DropCap -> save DropCap for later use, don't call finishParagraph
+ remove character properties of the DropCap?
+ (3) - no old frame and current Frame -> save Frame for later use
+ (4) - old DropCap and no current frame -> add DropCap to the properties of the finished paragraph, delete previous setting
+ (5) - old DropCap and current frame -> add DropCap to the properties of the finished paragraph, save current frame settings
+ (6) - old Frame and new DropCap -> add old Frame, save DropCap for later use
+ (7) - old Frame and new same Frame -> continue
+ (8) - old Frame and new different Frame -> add old Frame, save new Frame for later use
+ (9) - old Frame and no current frame -> add old Frame, delete previous settings
+
+ old _and_ new DropCap must not occur
+ */
+
+ bool bIsDropCap =
+ pParaContext->IsFrameMode() &&
+ sal::static_int_cast<Id>(pParaContext->GetDropCap()) != NS_ooxml::LN_Value_doc_ST_DropCap_none;
+
+ style::DropCapFormat aDrop;
+ ParagraphPropertiesPtr pToBeSavedProperties;
+ bool bKeepLastParagraphProperties = false;
+ if( bIsDropCap )
+ {
+ uno::Reference<text::XParagraphCursor> xParaCursor(
+ xTextAppend->createTextCursorByRange(xTextAppend->getEnd()), uno::UNO_QUERY_THROW);
+ //select paragraph
+ xParaCursor->gotoStartOfParagraph( true );
+ uno::Reference< beans::XPropertyState > xParaProperties( xParaCursor, uno::UNO_QUERY_THROW );
+ xParaProperties->setPropertyToDefault(getPropertyName(PROP_CHAR_ESCAPEMENT));
+ xParaProperties->setPropertyToDefault(getPropertyName(PROP_CHAR_HEIGHT));
+ //handles (2) and part of (6)
+ pToBeSavedProperties = new ParagraphProperties(*pParaContext);
+ sal_Int32 nCount = xParaCursor->getString().getLength();
+ pToBeSavedProperties->SetDropCapLength(nCount > 0 && nCount < 255 ? static_cast<sal_Int8>(nCount) : 1);
+ }
+ if( rAppendContext.pLastParagraphProperties )
+ {
+ if( sal::static_int_cast<Id>(rAppendContext.pLastParagraphProperties->GetDropCap()) != NS_ooxml::LN_Value_doc_ST_DropCap_none)
+ {
+ //handles (4) and part of (5)
+ //create a DropCap property, add it to the property sequence of finishParagraph
+ sal_Int32 nLines = rAppendContext.pLastParagraphProperties->GetLines();
+ aDrop.Lines = nLines > 0 && nLines < SAL_MAX_INT8 ? static_cast<sal_Int8>(nLines) : 2;
+ aDrop.Count = rAppendContext.pLastParagraphProperties->GetDropCapLength();
+ sal_Int32 nHSpace = rAppendContext.pLastParagraphProperties->GethSpace();
+ aDrop.Distance = nHSpace > 0 && nHSpace < SAL_MAX_INT16 ? static_cast<sal_Int16>(nHSpace) : 0;
+ //completes (5)
+ if( pParaContext->IsFrameMode() )
+ pToBeSavedProperties = new ParagraphProperties(*pParaContext);
+ }
+ else if(*rAppendContext.pLastParagraphProperties == *pParaContext )
+ {
+ //handles (7)
+ rAppendContext.pLastParagraphProperties->SetEndingRange(rAppendContext.xInsertPosition.is() ? rAppendContext.xInsertPosition : xTextAppend->getEnd());
+ bKeepLastParagraphProperties = true;
+ }
+ else
+ {
+ //handles (8)(9) and completes (6)
+ CheckUnregisteredFrameConversion( );
+
+ // If different frame properties are set on this paragraph, keep them.
+ if ( !bIsDropCap && pParaContext->IsFrameMode() )
+ {
+ pToBeSavedProperties = new ParagraphProperties(*pParaContext);
+ lcl_AddRangeAndStyle(pToBeSavedProperties, xTextAppend, pPropertyMap, rAppendContext);
+ }
+ }
+ }
+ else
+ {
+ // (1) doesn't need handling
+
+ if( !bIsDropCap && pParaContext->IsFrameMode() )
+ {
+ pToBeSavedProperties = new ParagraphProperties(*pParaContext);
+ lcl_AddRangeAndStyle(pToBeSavedProperties, xTextAppend, pPropertyMap, rAppendContext);
+ }
+ }
+ std::vector<beans::PropertyValue> aProperties;
+ if (pPropertyMap)
+ {
+ aProperties = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pPropertyMap->GetPropertyValues());
+ }
+ if (pPropertyMap)
+ {
+ // tdf#64222 filter out the "paragraph marker" formatting and
+ // set it as a separate paragraph property, not a empty hint at
+ // end of paragraph
+ std::vector<beans::NamedValue> charProperties;
+ for (auto it = aProperties.begin(); it != aProperties.end(); )
+ {
+ // this condition isn't ideal but as it happens all
+ // RES_CHRATR_* have names that start with "Char"
+ if (it->Name.startsWith("Char"))
+ {
+ charProperties.emplace_back(it->Name, it->Value);
+ // as testN793262 demonstrates, font size in rPr must
+ // affect the paragraph size => also insert empty hint!
+// it = aProperties.erase(it);
+ }
+ ++it;
+ }
+ if (!charProperties.empty())
+ {
+ aProperties.push_back(beans::PropertyValue("ListAutoFormat",
+ 0, uno::Any(comphelper::containerToSequence(charProperties)), beans::PropertyState_DIRECT_VALUE));
+ }
+ }
+ if( !bIsDropCap )
+ {
+ if( aDrop.Lines > 1 )
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = getPropertyName(PROP_DROP_CAP_FORMAT);
+ aValue.Value <<= aDrop;
+ aProperties.push_back(aValue);
+ }
+ uno::Reference< text::XTextRange > xTextRange;
+ if (rAppendContext.xInsertPosition.is())
+ {
+ xTextRange = xTextAppend->finishParagraphInsert( comphelper::containerToSequence(aProperties), rAppendContext.xInsertPosition );
+ rAppendContext.xCursor->gotoNextParagraph(false);
+ if (rAppendContext.pLastParagraphProperties)
+ rAppendContext.pLastParagraphProperties->SetEndingRange(xTextRange->getEnd());
+ }
+ else
+ {
+ uno::Reference<text::XTextCursor> xCursor;
+ if (m_bParaHadField && !m_bIsInComments && !xTOCMarkerCursor.is())
+ {
+ // Workaround to make sure char props of the field are not lost.
+ // Not relevant for editeng-based comments.
+ // Not relevant for fields inside a TOC field.
+ xCursor = xTextAppend->getText()->createTextCursor();
+ if (xCursor.is())
+ xCursor->gotoEnd(false);
+ PropertyMapPtr pEmpty(new PropertyMap());
+ appendTextPortion("X", pEmpty);
+ }
+
+ // Check if top / bottom margin has to be updated, now that we know the numbering status of both the previous and
+ // the current text node.
+ auto itNumberingRules = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "NumberingRules";
+ });
+
+ assert( isNumberingViaRule == (itNumberingRules != aProperties.end()) );
+ isNumberingViaRule = (itNumberingRules != aProperties.end());
+ if (m_xPreviousParagraph.is() && (isNumberingViaRule || isNumberingViaStyle))
+ {
+ // This textnode has numbering. Look up the numbering style name of the current and previous paragraph.
+ OUString aCurrentNumberingName;
+ OUString aPreviousNumberingName;
+ if (isNumberingViaRule)
+ {
+ assert(itNumberingRules != aProperties.end() && "by definition itNumberingRules is valid if isNumberingViaRule is true");
+ uno::Reference<container::XNamed> xCurrentNumberingRules(itNumberingRules->Value, uno::UNO_QUERY);
+ if (xCurrentNumberingRules.is())
+ aCurrentNumberingName = xCurrentNumberingRules->getName();
+ if (m_xPreviousParagraph.is())
+ {
+ uno::Reference<container::XNamed> xPreviousNumberingRules(m_xPreviousParagraph->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+ if (xPreviousNumberingRules.is())
+ aPreviousNumberingName = xPreviousNumberingRules->getName();
+ }
+ }
+ else if ( m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("NumberingStyleName") &&
+ // don't update before tables
+ (m_nTableDepth == 0 || !m_bFirstParagraphInCell))
+ {
+ aCurrentNumberingName = GetListStyleName(nListId);
+ m_xPreviousParagraph->getPropertyValue("NumberingStyleName") >>= aPreviousNumberingName;
+ }
+
+ if (!aPreviousNumberingName.isEmpty() && aCurrentNumberingName == aPreviousNumberingName)
+ {
+ uno::Sequence<beans::PropertyValue> aPrevPropertiesSeq;
+ m_xPreviousParagraph->getPropertyValue("ParaInteropGrabBag") >>= aPrevPropertiesSeq;
+ const auto & rPrevProperties = aPrevPropertiesSeq;
+ bool bParaAutoBefore = m_bParaAutoBefore || std::any_of(rPrevProperties.begin(), rPrevProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaTopMarginBeforeAutoSpacing";
+ });
+ // if style based spacing was set to auto in the previous paragraph, style of the actual paragraph must be the same
+ if (bParaAutoBefore && !m_bParaAutoBefore && m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("ParaStyleName"))
+ {
+ auto itParaStyle = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaStyleName";
+ });
+ bParaAutoBefore = itParaStyle != aProperties.end() &&
+ m_xPreviousParagraph->getPropertyValue("ParaStyleName") == itParaStyle->Value;
+ }
+ // There was a previous textnode and it had the same numbering.
+ if (bParaAutoBefore)
+ {
+ // This before spacing is set to auto, set before space to 0.
+ auto itParaTopMargin = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaTopMargin";
+ });
+ if (itParaTopMargin != aProperties.end())
+ itParaTopMargin->Value <<= static_cast<sal_Int32>(0);
+ else
+ aProperties.push_back(comphelper::makePropertyValue("ParaTopMargin", static_cast<sal_Int32>(0)));
+ }
+
+ bool bPrevParaAutoAfter = std::any_of(rPrevProperties.begin(), rPrevProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaBottomMarginAfterAutoSpacing";
+ });
+ if (bPrevParaAutoAfter)
+ {
+ // Previous after spacing is set to auto, set previous after space to 0.
+ m_xPreviousParagraph->setPropertyValue("ParaBottomMargin", uno::Any(static_cast<sal_Int32>(0)));
+ }
+ }
+ }
+
+ // apply redlines for inline images
+ if (IsParaWithInlineObject())
+ {
+ for (const auto& rAnchored : rAppendContext.m_aAnchoredObjects)
+ {
+ // process only inline objects with redlining
+ if (!rAnchored.m_xRedlineForInline)
+ continue;
+
+ // select the inline image and set its redline
+ auto xAnchorRange = rAnchored.m_xAnchoredObject->getAnchor();
+ uno::Reference< text::XTextCursor > xCursorOnImage =
+ xAnchorRange->getText()->createTextCursorByRange(xAnchorRange);
+ xCursorOnImage->goRight(1, true);
+ CreateRedline( xCursorOnImage, rAnchored.m_xRedlineForInline );
+ }
+ }
+
+ xTextRange = xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) );
+ m_xPreviousParagraph.set(xTextRange, uno::UNO_QUERY);
+
+ if (m_xPreviousParagraph.is() && // null for SvxUnoTextBase
+ (isNumberingViaStyle || isNumberingViaRule))
+ {
+ assert(pParaContext);
+ if (ListDef::Pointer const& pList = m_pListTable->GetList(nListId))
+ { // styles could refer to non-existing lists...
+ AbstractListDef::Pointer const& pAbsList =
+ pList->GetAbstractDefinition();
+ if (pAbsList &&
+ // SvxUnoTextRange doesn't have ListId
+ m_xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("ListId"))
+ {
+ OUString paraId;
+ m_xPreviousParagraph->getPropertyValue("ListId") >>= paraId;
+ if (!paraId.isEmpty()) // must be on some list?
+ {
+ OUString const listId = pAbsList->MapListId(paraId);
+ if (listId != paraId)
+ {
+ m_xPreviousParagraph->setPropertyValue("ListId", uno::Any(listId));
+ }
+ }
+ }
+
+ sal_Int16 nCurrentLevel = GetListLevel(pEntry, pPropertyMap);
+ if (nCurrentLevel == -1)
+ nCurrentLevel = 0;
+
+ const ListLevel::Pointer pListLevel = pList->GetLevel(nCurrentLevel);
+ if (pListLevel)
+ {
+ sal_Int16 nOverrideLevel = pListLevel->GetStartOverride();
+ if (nOverrideLevel != -1 && m_aListOverrideApplied.find(nListId) == m_aListOverrideApplied.end())
+ {
+ // Apply override: we have override instruction for this level
+ // And this was not done for this list before: we can do this only once on first occurrence
+ // of list with override
+ // TODO: Not tested variant with different levels override in different lists.
+ // Probably m_aListOverrideApplied as a set of overridden listids is not sufficient
+ // and we need to register level overrides separately.
+ m_xPreviousParagraph->setPropertyValue("ParaIsNumberingRestart", uno::Any(true));
+ m_xPreviousParagraph->setPropertyValue("NumberingStartValue", uno::Any(nOverrideLevel));
+ m_aListOverrideApplied.insert(nListId);
+ }
+ }
+ }
+ }
+
+ if (!rAppendContext.m_aAnchoredObjects.empty() && !IsInHeaderFooter())
+ {
+ // Remember what objects are anchored to this paragraph.
+ // That list is only used for Word compat purposes, and
+ // it is only relevant for body text.
+ AnchoredObjectsInfo aInfo;
+ aInfo.m_xParagraph = xTextRange;
+ aInfo.m_aAnchoredObjects = rAppendContext.m_aAnchoredObjects;
+ m_aAnchoredObjectAnchors.push_back(aInfo);
+ rAppendContext.m_aAnchoredObjects.clear();
+ }
+
+ // We're no longer right after a table conversion.
+ m_bConvertedTable = false;
+
+ if (xCursor.is())
+ {
+ xCursor->goLeft(1, true);
+ xCursor->setString(OUString());
+ }
+ }
+ getTableManager( ).handle(xTextRange);
+ m_aSmartTagHandler.handle(xTextRange);
+
+ if (xTextRange.is())
+ {
+ // Get the end of paragraph character inserted
+ uno::Reference< text::XTextCursor > xCur = xTextRange->getText( )->createTextCursor( );
+ if (rAppendContext.xInsertPosition.is())
+ xCur->gotoRange( rAppendContext.xInsertPosition, false );
+ else
+ xCur->gotoEnd( false );
+
+ // tdf#77417 trim right white spaces in table cells in 2010 compatibility mode
+ sal_Int32 nMode = GetSettingsTable()->GetWordCompatibilityMode();
+ if ( m_nTableDepth > 0 && nMode > 0 && nMode <= 14 )
+ {
+ // skip new line
+ xCur->goLeft(1, false);
+ while ( xCur->goLeft(1, true) )
+ {
+ OUString sChar = xCur->getString();
+ if ( sChar == " " || sChar == "\t" || sChar == OUStringChar(u'\x00A0') )
+ xCur->setString("");
+ else
+ break;
+ }
+
+ if (rAppendContext.xInsertPosition.is())
+ xCur->gotoRange(rAppendContext.xInsertPosition, false);
+ else
+ xCur->gotoEnd(false);
+ }
+
+ xCur->goLeft( 1 , true );
+ // Extend the redline ranges for empty paragraphs
+ if ( !m_bParaChanged && m_previousRedline )
+ CreateRedline( xCur, m_previousRedline );
+ CheckParaMarkerRedline( xCur );
+ }
+
+ css::uno::Reference<css::beans::XPropertySet> xParaProps(xTextRange, uno::UNO_QUERY);
+
+ // table style precedence and not hidden shapes anchored to hidden empty table paragraphs
+ if (xParaProps && (m_nTableDepth > 0 || !m_aAnchoredObjectAnchors.empty()) )
+ {
+ // table style has got bigger precedence than docDefault style
+ // collect these pending paragraph properties to process in endTable()
+ uno::Reference<text::XTextCursor> xCur = xTextRange->getText( )->createTextCursor( );
+ xCur->gotoEnd(false);
+ xCur->goLeft(1, false);
+ uno::Reference<text::XTextCursor> xCur2 = xTextRange->getText()->createTextCursorByRange(xCur);
+ uno::Reference<text::XParagraphCursor> xParaCursor(xCur2, uno::UNO_QUERY_THROW);
+ xParaCursor->gotoStartOfParagraph(false);
+ if (m_nTableDepth > 0)
+ {
+ TableParagraph aPending{xParaCursor, xCur, pParaContext, xParaProps};
+ getTableManager().getCurrentParagraphs()->push_back(aPending);
+ }
+
+ // hidden empty paragraph with a not hidden shape, set as not hidden
+ std::optional<PropertyMap::Property> pHidden;
+ if ( !m_aAnchoredObjectAnchors.empty() && (pHidden = pParaContext->getProperty(PROP_CHAR_HIDDEN)) )
+ {
+ bool bIsHidden = {}; // -Werror=maybe-uninitialized
+ pHidden->second >>= bIsHidden;
+ if (bIsHidden)
+ {
+ bIsHidden = false;
+ pHidden = GetTopContext()->getProperty(PROP_CHAR_HIDDEN);
+ if (pHidden)
+ pHidden->second >>= bIsHidden;
+ if (!bIsHidden)
+ {
+ uno::Reference<text::XTextCursor> xCur3 = xTextRange->getText()->createTextCursorByRange(xParaCursor);
+ xCur3->goRight(1, true);
+ if (xCur3->getString() == SAL_NEWLINE_STRING)
+ {
+ uno::Reference< beans::XPropertySet > xProp( xCur3, uno::UNO_QUERY );
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_HIDDEN), uno::Any(false));
+ }
+ }
+ }
+ }
+ }
+
+ // tdf#118521 set paragraph top or bottom margin based on the paragraph style
+ // if we already set the other margin with direct formatting
+ if (xParaProps)
+ {
+ const bool bTopSet = pParaContext->isSet(PROP_PARA_TOP_MARGIN);
+ const bool bBottomSet = pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN);
+ const bool bContextSet = pParaContext->isSet(PROP_PARA_CONTEXT_MARGIN);
+ if ( bTopSet != bBottomSet || bBottomSet != bContextSet )
+ {
+
+ if ( !bTopSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_TOP_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaTopMargin", aMargin);
+ }
+ if ( !bBottomSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_BOTTOM_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaBottomMargin", aMargin);
+ }
+ if ( !bContextSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_CONTEXT_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaContextMargin", aMargin);
+ }
+ }
+ }
+
+ // Left, Right, and Hanging settings are also grouped. Ensure that all or none are set.
+ if (xParaProps)
+ {
+ const bool bLeftSet = pParaContext->isSet(PROP_PARA_LEFT_MARGIN);
+ const bool bRightSet = pParaContext->isSet(PROP_PARA_RIGHT_MARGIN);
+ const bool bFirstSet = pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT);
+ if (bLeftSet != bRightSet || bRightSet != bFirstSet)
+ {
+ if ( !bLeftSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_LEFT_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaLeftMargin", aMargin);
+ else if (isNumberingViaStyle)
+ {
+ const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, GetListLevel(pEntry, pPropertyMap), "IndentAt");
+ if (nParaLeftMargin != 0)
+ xParaProps->setPropertyValue("ParaLeftMargin", uno::Any(nParaLeftMargin));
+ }
+ }
+ if ( !bRightSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_RIGHT_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaRightMargin", aMargin);
+ }
+ if ( !bFirstSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_FIRST_LINE_INDENT);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaFirstLineIndent", aMargin);
+ else if (isNumberingViaStyle)
+ {
+ const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, GetListLevel(pEntry, pPropertyMap), "FirstLineIndent");
+ if (nFirstLineIndent != 0)
+ xParaProps->setPropertyValue("ParaFirstLineIndent", uno::Any(nFirstLineIndent));
+ }
+ }
+ }
+ }
+
+ // fix table paragraph properties
+ if ( xTextRange.is() && xParaProps && m_nTableDepth > 0 )
+ {
+ // tdf#128959 table paragraphs haven't got window and orphan controls
+ uno::Any aAny(static_cast<sal_Int8>(0));
+ xParaProps->setPropertyValue("ParaOrphans", aAny);
+ xParaProps->setPropertyValue("ParaWidows", aAny);
+ }
+ }
+ if( !bKeepLastParagraphProperties )
+ rAppendContext.pLastParagraphProperties = pToBeSavedProperties;
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "DomainMapper_Impl::finishParagraph" );
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "finishParagraph()" );
+ }
+
+ }
+
+ bool bIgnoreFrameState = IsInHeaderFooter();
+ if( (!bIgnoreFrameState && pParaContext && pParaContext->IsFrameMode()) || (bIgnoreFrameState && GetIsPreviousParagraphFramed()) )
+ SetIsPreviousParagraphFramed(true);
+ else
+ SetIsPreviousParagraphFramed(false);
+
+ m_bRemoveThisParagraph = false;
+ if( !IsInHeaderFooter() && !IsInShape() && (!pParaContext || !pParaContext->IsFrameMode()) )
+ { // If the paragraph is in a frame, shape or header/footer, it's not a paragraph of the section itself.
+ SetIsFirstParagraphInSection(false);
+ // don't count an empty deleted paragraph as first paragraph in section to avoid of
+ // the deletion of the next empty paragraph later, resulting loss of the associated page break
+ if (!m_previousRedline || m_bParaChanged)
+ {
+ SetIsFirstParagraphInSectionAfterRedline(false);
+ SetIsLastParagraphInSection(false);
+ }
+ }
+ m_previousRedline.clear();
+ m_bParaChanged = false;
+
+ if (m_bIsInComments && pParaContext)
+ {
+ if (const OUString sParaId = pParaContext->GetParaId(); !sParaId.isEmpty())
+ {
+ if (const auto& item = m_aCommentProps.find(sParaId); item != m_aCommentProps.end())
+ {
+ m_bAnnotationResolved = item->second.bDone;
+ }
+ }
+ }
+
+ if (m_bIsFirstParaInShape)
+ m_bIsFirstParaInShape = false;
+
+ if (pParaContext)
+ {
+ // Reset the frame properties for the next paragraph
+ pParaContext->ResetFrameProperties();
+ }
+
+ SetIsOutsideAParagraph(true);
+ m_bParaHadField = false;
+
+ // don't overwrite m_bFirstParagraphInCell in table separator nodes
+ // and in text boxes anchored to the first paragraph of table cells
+ if (m_nTableDepth > 0 && m_nTableDepth == m_nTableCellDepth && !IsInShape())
+ m_bFirstParagraphInCell = false;
+
+ m_bParaAutoBefore = false;
+ m_bParaWithInlineObject = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+}
+
+void DomainMapper_Impl::appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap )
+{
+ if (m_bDiscardHeaderFooter)
+ return;
+
+ if (m_aTextAppendStack.empty())
+ return;
+ // Before placing call to processDeferredCharacterProperties(), TopContextType should be CONTEXT_CHARACTER
+ // processDeferredCharacterProperties() invokes only if character inserted
+ if( pPropertyMap == m_pTopContext && !deferredCharacterProperties.empty() && (GetTopContextType() == CONTEXT_CHARACTER) )
+ processDeferredCharacterProperties();
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is() || !hasTableManager() || getTableManager().isIgnore())
+ return;
+
+ try
+ {
+ // If we are in comments, then disable CharGrabBag, comment text doesn't support that.
+ uno::Sequence< beans::PropertyValue > aValues = pPropertyMap->GetPropertyValues(/*bCharGrabBag=*/!m_bIsInComments);
+
+ if (m_bStartTOC || m_bStartIndex || m_bStartBibliography)
+ for( auto& rValue : asNonConstRange(aValues) )
+ {
+ if (rValue.Name == "CharHidden")
+ rValue.Value <<= false;
+ }
+
+ // remove workaround for change tracked images, if they are part of a redline,
+ // i.e. if the next run is a tracked change with the same type, author and date,
+ // as in the change tracking of the image.
+ if ( m_bRedlineImageInPreviousRun )
+ {
+ auto pCurrentRedline = m_aRedlines.top().size() > 0
+ ? m_aRedlines.top().back()
+ : GetTopContextOfType(CONTEXT_CHARACTER) &&
+ GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0
+ ? GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().back()
+ : nullptr;
+ if ( m_previousRedline && pCurrentRedline &&
+ // same redline
+ (m_previousRedline->m_nToken & 0xffff) == (pCurrentRedline->m_nToken & 0xffff) &&
+ m_previousRedline->m_sAuthor == pCurrentRedline->m_sAuthor &&
+ m_previousRedline->m_sDate == pCurrentRedline->m_sDate )
+ {
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->getEnd()->getText( )->createTextCursor( );
+ assert(xCursor.is());
+ xCursor->gotoEnd(false);
+ xCursor->goLeft(2, true);
+ if ( xCursor->getString() == u"​​" )
+ {
+ xCursor->goRight(1, true);
+ xCursor->setString("");
+ xCursor->gotoEnd(false);
+ xCursor->goLeft(1, true);
+ xCursor->setString("");
+ }
+ }
+
+ m_bRedlineImageInPreviousRun = false;
+ }
+
+ uno::Reference< text::XTextRange > xTextRange;
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ {
+ xTextRange = xTextAppend->insertTextPortion(rString, aValues, m_aTextAppendStack.top().xInsertPosition);
+ m_aTextAppendStack.top().xCursor->gotoRange(xTextRange->getEnd(), true);
+ }
+ else
+ {
+ if (m_bStartTOC || m_bStartIndex || m_bStartBibliography || m_nStartGenericField != 0)
+ {
+ if (IsInHeaderFooter() && !m_bStartTOCHeaderFooter)
+ {
+ xTextRange = xTextAppend->appendTextPortion(rString, aValues);
+ }
+ else
+ {
+ m_bStartedTOC = true;
+ uno::Reference< text::XTextCursor > xTOCTextCursor = xTextAppend->getEnd()->getText( )->createTextCursor( );
+ assert(xTOCTextCursor.is());
+ xTOCTextCursor->gotoEnd(false);
+ if (m_nStartGenericField != 0)
+ {
+ xTOCTextCursor->goLeft(1, false);
+ }
+ xTextRange = xTextAppend->insertTextPortion(rString, aValues, xTOCTextCursor);
+ SAL_WARN_IF(!xTextRange.is(), "writerfilter.dmapper", "insertTextPortion failed");
+ if (!xTextRange.is())
+ throw uno::Exception("insertTextPortion failed", nullptr);
+ m_bTextInserted = true;
+ xTOCTextCursor->gotoRange(xTextRange->getEnd(), true);
+ if (m_nStartGenericField == 0)
+ {
+ m_aTextAppendStack.push(TextAppendContext(xTextAppend, xTOCTextCursor));
+ }
+ }
+ }
+ else
+ {
+#if !defined(MACOSX) // TODO: check layout differences and support all platforms, if needed
+ sal_Int32 nPos = 0;
+ OUString sFontName;
+ OUString sDoubleSpace(" ");
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_CHARACTER);
+ // tdf#123703 workaround for longer space sequences of the old or compatible RTF documents
+ if (GetSettingsTable()->GetLongerSpaceSequence() && !IsOpenFieldCommand() && (nPos = rString.indexOf(sDoubleSpace)) != -1 &&
+ // monospaced fonts have no longer space sequences, regardless of \fprq2 (not monospaced) font setting
+ // fix for the base monospaced font Courier
+ (!pContext || !pContext->isSet(PROP_CHAR_FONT_NAME) ||
+ ((pContext->getProperty(PROP_CHAR_FONT_NAME)->second >>= sFontName) && sFontName.indexOf("Courier") == -1)))
+ {
+ // an RTF space character is longer by an extra six-em-space in an old-style RTF space sequence,
+ // insert them to keep RTF document layout formatted by consecutive spaces
+ const sal_Unicode aExtraSpace[5] = { 0x2006, 0x20, 0x2006, 0x20, 0 };
+ const sal_Unicode aExtraSpace2[4] = { 0x20, 0x2006, 0x20, 0 };
+ xTextRange = xTextAppend->appendTextPortion(rString.replaceAll(sDoubleSpace, aExtraSpace, nPos)
+ .replaceAll(sDoubleSpace, aExtraSpace2, nPos), aValues);
+ }
+ else
+#endif
+ xTextRange = xTextAppend->appendTextPortion(rString, aValues);
+ }
+ }
+
+ // reset moveFrom/moveTo data of non-terminating runs of the paragraph
+ if ( m_pParaMarkerRedlineMove )
+ {
+ m_pParaMarkerRedlineMove.clear();
+ }
+ CheckRedline( xTextRange );
+ m_bParaChanged = true;
+
+ //getTableManager( ).handle(xTextRange);
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "DomainMapper_Impl::appendTextPortion" );
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "DomainMapper_Impl::appendTextPortion" );
+ }
+}
+
+void DomainMapper_Impl::appendTextContent(
+ const uno::Reference< text::XTextContent >& xContent,
+ const uno::Sequence< beans::PropertyValue >& xPropertyValues
+ )
+{
+ SAL_WARN_IF(m_aTextAppendStack.empty(), "writerfilter.dmapper", "no text append stack");
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( m_aTextAppendStack.top().xTextAppend, uno::UNO_QUERY );
+ OSL_ENSURE( xTextAppendAndConvert.is(), "trying to append a text content without XTextAppendAndConvert" );
+ if (!xTextAppendAndConvert.is() || !hasTableManager() || getTableManager().isIgnore())
+ return;
+
+ try
+ {
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ xTextAppendAndConvert->insertTextContentWithProperties( xContent, xPropertyValues, m_aTextAppendStack.top().xInsertPosition );
+ else
+ xTextAppendAndConvert->appendTextContent( xContent, xPropertyValues );
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ }
+ catch(const uno::Exception&)
+ {
+ }
+}
+
+void DomainMapper_Impl::appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOLEHandler )
+{
+ try
+ {
+ uno::Reference< text::XTextContent > xOLE( m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xOLEProperties(xOLE, uno::UNO_QUERY_THROW);
+
+ OUString aCLSID = pOLEHandler->getCLSID();
+ if (aCLSID.isEmpty())
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_STREAM_NAME ),
+ uno::Any( rStreamName ));
+ else
+ xOLEProperties->setPropertyValue("CLSID", uno::Any(aCLSID));
+
+ OUString aDrawAspect = pOLEHandler->GetDrawAspect();
+ if(!aDrawAspect.isEmpty())
+ xOLEProperties->setPropertyValue("DrawAspect", uno::Any(aDrawAspect));
+
+ awt::Size aSize = pOLEHandler->getSize();
+ if( !aSize.Width )
+ aSize.Width = 1000;
+ if( !aSize.Height )
+ aSize.Height = 1000;
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_WIDTH ),
+ uno::Any(aSize.Width));
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ),
+ uno::Any(aSize.Height));
+
+ OUString aVisAreaWidth = pOLEHandler->GetVisAreaWidth();
+ if(!aVisAreaWidth.isEmpty())
+ xOLEProperties->setPropertyValue("VisibleAreaWidth", uno::Any(aVisAreaWidth));
+
+ OUString aVisAreaHeight = pOLEHandler->GetVisAreaHeight();
+ if(!aVisAreaHeight.isEmpty())
+ xOLEProperties->setPropertyValue("VisibleAreaHeight", uno::Any(aVisAreaHeight));
+
+ uno::Reference< graphic::XGraphic > xGraphic = pOLEHandler->getReplacement();
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC ),
+ uno::Any(xGraphic));
+ uno::Reference<beans::XPropertySet> xReplacementProperties(pOLEHandler->getShape(), uno::UNO_QUERY);
+ if (xReplacementProperties.is())
+ {
+ table::BorderLine2 aBorderProps;
+ xReplacementProperties->getPropertyValue("LineColor") >>= aBorderProps.Color;
+ xReplacementProperties->getPropertyValue("LineWidth") >>= aBorderProps.LineWidth;
+ xReplacementProperties->getPropertyValue("LineStyle") >>= aBorderProps.LineStyle;
+
+ if (aBorderProps.LineStyle) // Set line props only if LineStyle is set
+ {
+ xOLEProperties->setPropertyValue("RightBorder", uno::Any(aBorderProps));
+ xOLEProperties->setPropertyValue("TopBorder", uno::Any(aBorderProps));
+ xOLEProperties->setPropertyValue("LeftBorder", uno::Any(aBorderProps));
+ xOLEProperties->setPropertyValue("BottomBorder", uno::Any(aBorderProps));
+ }
+ OUString pProperties[] = {
+ "AnchorType",
+ "Surround",
+ "SurroundContour",
+ "HoriOrient",
+ "HoriOrientPosition",
+ "VertOrient",
+ "VertOrientPosition",
+ "VertOrientRelation",
+ "HoriOrientRelation",
+ "LeftMargin",
+ "RightMargin",
+ "TopMargin",
+ "BottomMargin"
+ };
+ for (const OUString& s : pProperties)
+ {
+ const uno::Any aVal = xReplacementProperties->getPropertyValue(s);
+ xOLEProperties->setPropertyValue(s, aVal);
+ }
+
+ if (xReplacementProperties->getPropertyValue("FillStyle").get<css::drawing::FillStyle>()
+ != css::drawing::FillStyle::FillStyle_NONE) // Apply fill props if style is set
+ {
+ xOLEProperties->setPropertyValue(
+ "FillStyle", xReplacementProperties->getPropertyValue("FillStyle"));
+ xOLEProperties->setPropertyValue(
+ "FillColor", xReplacementProperties->getPropertyValue("FillColor"));
+ xOLEProperties->setPropertyValue(
+ "FillColor2", xReplacementProperties->getPropertyValue("FillColor2"));
+ }
+ }
+ else
+ // mimic the treatment of graphics here... it seems anchoring as character
+ // gives a better ( visually ) result
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_ANCHOR_TYPE ), uno::Any( text::TextContentAnchorType_AS_CHARACTER ) );
+ // remove ( if valid ) associated shape ( used for graphic replacement )
+ SAL_WARN_IF(m_aAnchoredStack.empty(), "writerfilter.dmapper", "no anchor stack");
+ if (!m_aAnchoredStack.empty())
+ m_aAnchoredStack.top( ).bToRemove = true;
+ RemoveLastParagraph();
+ SAL_WARN_IF(m_aTextAppendStack.empty(), "writerfilter.dmapper", "no text stack");
+ if (!m_aTextAppendStack.empty())
+ m_aTextAppendStack.pop();
+
+ appendTextContent( xOLE, uno::Sequence< beans::PropertyValue >() );
+
+ if (!aCLSID.isEmpty())
+ pOLEHandler->importStream(m_xComponentContext, GetTextDocument(), xOLE);
+
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "in creation of OLE object" );
+ }
+
+}
+
+void DomainMapper_Impl::appendStarMath( const Value& val )
+{
+ uno::Reference< embed::XEmbeddedObject > formula;
+ val.getAny() >>= formula;
+ if( !formula.is() )
+ return;
+
+ try
+ {
+ uno::Reference< text::XTextContent > xStarMath( m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xStarMathProperties(xStarMath, uno::UNO_QUERY_THROW);
+
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_EMBEDDED_OBJECT ),
+ val.getAny());
+ // tdf#66405: set zero margins for embedded object
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
+ uno::Any(sal_Int32(0)));
+
+ uno::Reference< uno::XInterface > xInterface( formula->getComponent(), uno::UNO_QUERY );
+ // set zero margins for object's component
+ uno::Reference< beans::XPropertySet > xComponentProperties( xInterface, uno::UNO_QUERY_THROW );
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ Size size( 1000, 1000 );
+ if( oox::FormulaImportBase* formulaimport = dynamic_cast< oox::FormulaImportBase* >( xInterface.get()))
+ size = formulaimport->getFormulaSize();
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_WIDTH ),
+ uno::Any( sal_Int32(size.Width())));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ),
+ uno::Any( sal_Int32(size.Height())));
+ xStarMathProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE),
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+ // mimic the treatment of graphics here... it seems anchoring as character
+ // gives a better ( visually ) result
+ appendTextContent(xStarMath, uno::Sequence<beans::PropertyValue>());
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "in creation of StarMath object" );
+ }
+}
+
+void DomainMapper_Impl::adjustLastPara(sal_Int8 nAlign)
+{
+ PropertyMapPtr pLastPara = GetTopContextOfType(dmapper::CONTEXT_PARAGRAPH);
+ pLastPara->Insert(PROP_PARA_ADJUST, uno::Any(nAlign), true);
+}
+
+uno::Reference< beans::XPropertySet > DomainMapper_Impl::appendTextSectionAfter(
+ uno::Reference< text::XTextRange > const & xBefore )
+{
+ uno::Reference< beans::XPropertySet > xRet;
+ if (m_aTextAppendStack.empty())
+ return xRet;
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(xTextAppend.is())
+ {
+ try
+ {
+ uno::Reference< text::XParagraphCursor > xCursor(
+ xTextAppend->createTextCursorByRange( xBefore ), uno::UNO_QUERY_THROW);
+ //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
+ xCursor->gotoStartOfParagraph( false );
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ xCursor->gotoRange( m_aTextAppendStack.top().xInsertPosition, true );
+ else
+ xCursor->gotoEnd( true );
+ //the paragraph after this new section is already inserted
+ xCursor->goLeft(1, true);
+ css::uno::Reference<css::text::XTextRange> xTextRange(xCursor, css::uno::UNO_QUERY_THROW);
+
+ if (css::uno::Reference<css::text::XDocumentIndexesSupplier> xIndexSupplier{
+ GetTextDocument(), css::uno::UNO_QUERY })
+ {
+ css::uno::Reference<css::text::XTextRangeCompare> xCompare(
+ xTextAppend, css::uno::UNO_QUERY);
+ const auto xIndexAccess = xIndexSupplier->getDocumentIndexes();
+ for (sal_Int32 i = xIndexAccess->getCount(); i > 0; --i)
+ {
+ if (css::uno::Reference<css::text::XDocumentIndex> xIndex{
+ xIndexAccess->getByIndex(i - 1), css::uno::UNO_QUERY })
+ {
+ const auto xIndexTextRange = xIndex->getAnchor();
+ if (xCompare->compareRegionStarts(xTextRange, xIndexTextRange) == 0
+ && xCompare->compareRegionEnds(xTextRange, xIndexTextRange) == 0)
+ {
+ // The boundaries coincide with an index: trying to attach a section
+ // to the range will insert the section inside the index. goRight will
+ // extend the range outside of the index, so that created section will
+ // be around it. Alternatively we could return index section itself
+ // instead : xRet.set(xIndex, uno::UNO_QUERY) - to set its properties,
+ // like columns/fill.
+ xCursor->goRight(1, true);
+ break;
+ }
+ }
+ }
+ }
+
+ uno::Reference< text::XTextContent > xSection( m_xTextFactory->createInstance("com.sun.star.text.TextSection"), uno::UNO_QUERY_THROW );
+ xSection->attach( xTextRange );
+ xRet.set(xSection, uno::UNO_QUERY );
+ }
+ catch(const uno::Exception&)
+ {
+ }
+
+ }
+
+ return xRet;
+}
+
+void DomainMapper_Impl::appendGlossaryEntry()
+{
+ appendTextSectionAfter(m_xGlossaryEntryStart);
+}
+
+void DomainMapper_Impl::fillEmptyFrameProperties(std::vector<beans::PropertyValue>& rFrameProperties, bool bSetAnchorToChar)
+{
+ if (bSetAnchorToChar)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_ANCHOR_TYPE), text::TextContentAnchorType_AS_CHARACTER));
+
+ uno::Any aEmptyBorder{table::BorderLine2()};
+ static const std::vector<PropertyIds> aBorderIds
+ = { PROP_BOTTOM_BORDER, PROP_LEFT_BORDER, PROP_RIGHT_BORDER, PROP_TOP_BORDER };
+ for (size_t i = 0; i < aBorderIds.size(); ++i)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(aBorderIds[i]), aEmptyBorder));
+
+ static const std::vector<PropertyIds> aMarginIds
+ = { PROP_BOTTOM_MARGIN, PROP_BOTTOM_BORDER_DISTANCE,
+ PROP_LEFT_MARGIN, PROP_LEFT_BORDER_DISTANCE,
+ PROP_RIGHT_MARGIN, PROP_RIGHT_BORDER_DISTANCE,
+ PROP_TOP_MARGIN, PROP_TOP_BORDER_DISTANCE };
+ for (size_t i = 0; i < aMarginIds.size(); ++i)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(aMarginIds[i]), static_cast<sal_Int32>(0)));
+}
+
+void DomainMapper_Impl::ConvertHeaderFooterToTextFrame(bool bDynamicHeightTop, bool bDynamicHeightBottom)
+{
+ while (!m_aHeaderFooterTextAppendStack.empty())
+ {
+ auto aFooterHeader = m_aHeaderFooterTextAppendStack.top();
+ if ((aFooterHeader.second && !bDynamicHeightTop) || (!aFooterHeader.second && !bDynamicHeightBottom))
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = aFooterHeader.first.xTextAppend;
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursor();
+ uno::Reference< text::XTextRange > xRangeStart, xRangeEnd;
+
+ xRangeStart = xCursor->getStart();
+ xCursor->gotoEnd(false);
+ xRangeEnd = xCursor->getStart();
+
+ std::vector<beans::PropertyValue> aFrameProperties
+ {
+ comphelper::makePropertyValue("TextWrap", css::text::WrapTextMode_THROUGH),
+ comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), text::HoriOrientation::LEFT),
+ comphelper::makePropertyValue(getPropertyName(PROP_OPAQUE), false),
+ comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), text::SizeType::MIN),
+ comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), text::SizeType::MIN),
+ // tdf#143384 If the header/footer started with a table, convertToTextFrame could not
+ // convert the table, because it used createTextCursor() -which ignore tables-
+ // to set the conversion range.
+ // This dummy property is set to make convertToTextFrame to use another CreateTextCursor
+ // method that can be parameterized to not ignore tables.
+ comphelper::makePropertyValue(getPropertyName(PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF), true)
+ };
+
+ fillEmptyFrameProperties(aFrameProperties, false);
+
+ // If it is a footer, then orient the frame to the bottom
+ if (!aFooterHeader.second)
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), text::VertOrientation::BOTTOM));
+
+ uno::Reference<text::XTextAppendAndConvert> xBodyText(
+ xRangeStart->getText(), uno::UNO_QUERY);
+ xBodyText->convertToTextFrame(xTextAppend, xRangeEnd,
+ comphelper::containerToSequence(aFrameProperties));
+ }
+ m_aHeaderFooterTextAppendStack.pop();
+ }
+}
+
+void DomainMapper_Impl::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType)
+{
+ m_bSaveParaHadField = m_bParaHadField;
+ m_aHeaderFooterStack.push(HeaderFooterContext(m_bTextInserted, m_nTableDepth));
+ m_bTextInserted = false;
+ m_nTableDepth = 0;
+
+ const PropertyIds ePropIsOn = bHeader? PROP_HEADER_IS_ON: PROP_FOOTER_IS_ON;
+ const PropertyIds ePropShared = bHeader? PROP_HEADER_IS_SHARED: PROP_FOOTER_IS_SHARED;
+ const PropertyIds ePropTextLeft = bHeader? PROP_HEADER_TEXT_LEFT: PROP_FOOTER_TEXT_LEFT;
+ const PropertyIds ePropText = bHeader? PROP_HEADER_TEXT: PROP_FOOTER_TEXT;
+
+ m_bDiscardHeaderFooter = true;
+ m_eInHeaderFooterImport
+ = bHeader ? HeaderFooterImportState::header : HeaderFooterImportState::footer;
+
+ //get the section context
+ PropertyMapPtr pContext = DomainMapper_Impl::GetTopContextOfType(CONTEXT_SECTION);
+ //ask for the header/footer name of the given type
+ SectionPropertyMap* pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
+ if(!pSectionContext)
+ return;
+
+ // clear the "Link To Previous" flag so that the header/footer
+ // content is not copied from the previous section
+ pSectionContext->ClearHeaderFooterLinkToPrevious(bHeader, eType);
+
+ if (!m_bIsNewDoc)
+ {
+ return; // TODO sw cannot Undo insert header/footer without crashing
+ }
+
+ uno::Reference< beans::XPropertySet > xPageStyle =
+ pSectionContext->GetPageStyle(
+ *this,
+ eType == SectionPropertyMap::PAGE_FIRST );
+ if (!xPageStyle.is())
+ return;
+ try
+ {
+ bool bLeft = eType == SectionPropertyMap::PAGE_LEFT;
+ bool bFirst = eType == SectionPropertyMap::PAGE_FIRST;
+ if (!bLeft || GetSettingsTable()->GetEvenAndOddHeaders())
+ {
+ //switch on header/footer use
+ xPageStyle->setPropertyValue(
+ getPropertyName(ePropIsOn),
+ uno::Any(true));
+
+ // If the 'Different Even & Odd Pages' flag is turned on - do not ignore it
+ // Even if the 'Even' header/footer is blank - the flag should be imported (so it would look in LO like in Word)
+ if (!bFirst && GetSettingsTable()->GetEvenAndOddHeaders())
+ xPageStyle->setPropertyValue(getPropertyName(ePropShared), uno::Any(false));
+
+ //set the interface
+ uno::Reference< text::XText > xText;
+ xPageStyle->getPropertyValue(getPropertyName(bLeft? ePropTextLeft: ePropText)) >>= xText;
+
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >(xText, uno::UNO_QUERY_THROW),
+ m_bIsNewDoc
+ ? uno::Reference<text::XTextCursor>()
+ : xText->createTextCursorByRange(xText->getStart())));
+ m_aHeaderFooterTextAppendStack.push(std::make_pair(TextAppendContext(uno::Reference< text::XTextAppend >(xText, uno::UNO_QUERY_THROW),
+ m_bIsNewDoc
+ ? uno::Reference<text::XTextCursor>()
+ : xText->createTextCursorByRange(xText->getStart())),
+ bHeader));
+ }
+ // If we have *hidden* header footer
+ else
+ {
+ bool bIsShared = false;
+ // Turn on the headers
+ xPageStyle->setPropertyValue(getPropertyName(ePropIsOn), uno::Any(true));
+ // Store the state of the previous state of shared prop
+ xPageStyle->getPropertyValue(getPropertyName(ePropShared)) >>= bIsShared;
+ // Turn on the shared prop in order to save the headers/footers in time
+ xPageStyle->setPropertyValue(getPropertyName(ePropShared), uno::Any(false));
+ // Add the content of the headers footers to the doc
+ uno::Reference<text::XText> xText;
+ xPageStyle->getPropertyValue(getPropertyName(bLeft ? ePropTextLeft : ePropText))
+ >>= xText;
+
+ m_aTextAppendStack.push(
+ TextAppendContext(uno::Reference<text::XTextAppend>(xText, uno::UNO_QUERY_THROW),
+ m_bIsNewDoc ? uno::Reference<text::XTextCursor>()
+ : xText->createTextCursorByRange(xText->getStart())));
+ // Restore the original state of the shared prop after we stored the necessary values.
+ xPageStyle->setPropertyValue(getPropertyName(ePropShared), uno::Any(bIsShared));
+ }
+ m_bDiscardHeaderFooter = false; // set only on success!
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+}
+
+void DomainMapper_Impl::PushPageHeader(SectionPropertyMap::PageType eType)
+{
+ PushPageHeaderFooter(/* bHeader = */ true, eType);
+}
+
+void DomainMapper_Impl::PushPageFooter(SectionPropertyMap::PageType eType)
+{
+ PushPageHeaderFooter(/* bHeader = */ false, eType);
+}
+
+void DomainMapper_Impl::PopPageHeaderFooter()
+{
+ //header and footer always have an empty paragraph at the end
+ //this has to be removed
+ RemoveLastParagraph( );
+
+ if (!m_aTextAppendStack.empty())
+ {
+ if (!m_bDiscardHeaderFooter)
+ {
+ m_aTextAppendStack.pop();
+ }
+ m_bDiscardHeaderFooter = false;
+ }
+ m_eInHeaderFooterImport = HeaderFooterImportState::none;
+
+ if (!m_aHeaderFooterStack.empty())
+ {
+ m_bTextInserted = m_aHeaderFooterStack.top().getTextInserted();
+ m_nTableDepth = m_aHeaderFooterStack.top().getTableDepth();
+ m_aHeaderFooterStack.pop();
+ }
+
+ m_bParaHadField = m_bSaveParaHadField;
+}
+
+void DomainMapper_Impl::PushFootOrEndnote( bool bIsFootnote )
+{
+ SAL_WARN_IF(m_bInFootOrEndnote, "writerfilter.dmapper", "PushFootOrEndnote() is called from another foot or endnote");
+ m_bInFootOrEndnote = true;
+ m_bInFootnote = bIsFootnote;
+ m_bCheckFirstFootnoteTab = true;
+ m_bSaveFirstParagraphInCell = m_bFirstParagraphInCell;
+ try
+ {
+ // Redlines outside the footnote should not affect footnote content
+ m_aRedlines.push(std::vector< RedlineParamsPtr >());
+
+ // IMHO character styles from footnote labels should be ignored in the edit view of Writer.
+ // This adds a hack on top of the following hack to save the style name in the context.
+ PropertyMapPtr pTopContext = GetTopContext();
+ OUString sFootnoteCharStyleName;
+ std::optional< PropertyMap::Property > aProp = pTopContext->getProperty(PROP_CHAR_STYLE_NAME);
+ if (aProp)
+ aProp->second >>= sFootnoteCharStyleName;
+
+ // Remove style reference, if any. This reference did appear here as a side effect of tdf#43017
+ // Seems it is not required by LO, but causes side effects during editing. So remove it
+ // for footnotes/endnotes to restore original LO behavior here.
+ pTopContext->Erase(PROP_CHAR_STYLE_NAME);
+
+ uno::Reference< text::XText > xFootnoteText;
+ if (GetTextFactory().is())
+ xFootnoteText.set( GetTextFactory()->createInstance(
+ bIsFootnote ?
+ OUString( "com.sun.star.text.Footnote" ) : OUString( "com.sun.star.text.Endnote" )),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< text::XFootnote > xFootnote( xFootnoteText, uno::UNO_QUERY_THROW );
+ pTopContext->SetFootnote(xFootnote, sFootnoteCharStyleName);
+ uno::Sequence< beans::PropertyValue > aFontProperties;
+ if (GetTopContextOfType(CONTEXT_CHARACTER))
+ aFontProperties = GetTopContextOfType(CONTEXT_CHARACTER)->GetPropertyValues();
+ appendTextContent( uno::Reference< text::XTextContent >( xFootnoteText, uno::UNO_QUERY_THROW ), aFontProperties );
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xFootnoteText, uno::UNO_QUERY_THROW ),
+ xFootnoteText->createTextCursorByRange(xFootnoteText->getStart())));
+
+ // Redlines for the footnote anchor in the main text content
+ std::vector< RedlineParamsPtr > aFootnoteRedline = std::move(m_aRedlines.top());
+ m_aRedlines.pop();
+ CheckRedline( xFootnote->getAnchor( ) );
+ m_aRedlines.push( aFootnoteRedline );
+
+ // Try scanning for custom footnote labels
+ if (!sFootnoteCharStyleName.isEmpty())
+ StartCustomFootnote(pTopContext);
+ else
+ EndCustomFootnote();
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "PushFootOrEndnote");
+ }
+}
+
+void DomainMapper_Impl::CreateRedline(uno::Reference<text::XTextRange> const& xRange,
+ const RedlineParamsPtr& pRedline)
+{
+ if ( !pRedline )
+ return;
+
+ bool bRedlineMoved = false;
+ try
+ {
+ OUString sType;
+ switch ( pRedline->m_nToken & 0xffff )
+ {
+ case XML_mod:
+ sType = getPropertyName( PROP_FORMAT );
+ break;
+ case XML_moveTo:
+ bRedlineMoved = true;
+ m_pParaMarkerRedlineMove = pRedline.get();
+ [[fallthrough]];
+ case XML_ins:
+ sType = getPropertyName( PROP_INSERT );
+ break;
+ case XML_moveFrom:
+ bRedlineMoved = true;
+ m_pParaMarkerRedlineMove = pRedline.get();
+ [[fallthrough]];
+ case XML_del:
+ sType = getPropertyName( PROP_DELETE );
+ break;
+ case XML_ParagraphFormat:
+ sType = getPropertyName( PROP_PARAGRAPH_FORMAT );
+ break;
+ default:
+ throw lang::IllegalArgumentException("illegal redline token type", nullptr, 0);
+ }
+ beans::PropertyValues aRedlineProperties( 4 );
+ beans::PropertyValue * pRedlineProperties = aRedlineProperties.getArray( );
+ pRedlineProperties[0].Name = getPropertyName( PROP_REDLINE_AUTHOR );
+ pRedlineProperties[0].Value <<= pRedline->m_sAuthor;
+ pRedlineProperties[1].Name = getPropertyName( PROP_REDLINE_DATE_TIME );
+ util::DateTime aDateTime = ConversionHelper::ConvertDateStringToDateTime( pRedline->m_sDate );
+ // tdf#146171 import not specified w:date (or specified as zero date "0-00-00")
+ // as Epoch time to avoid of losing change tracking data during ODF roundtrip
+ if ( aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0 )
+ {
+ aDateTime.Year = 1970;
+ aDateTime.Month = 1;
+ aDateTime.Day = 1;
+ }
+ pRedlineProperties[1].Value <<= aDateTime;
+ pRedlineProperties[2].Name = getPropertyName( PROP_REDLINE_REVERT_PROPERTIES );
+ pRedlineProperties[2].Value <<= pRedline->m_aRevertProperties;
+ pRedlineProperties[3].Name = "RedlineMoved";
+ pRedlineProperties[3].Value <<= bRedlineMoved;
+
+ if (!m_bIsActualParagraphFramed)
+ {
+ uno::Reference < text::XRedline > xRedline( xRange, uno::UNO_QUERY_THROW );
+ xRedline->makeRedline( sType, aRedlineProperties );
+ }
+ // store frame and (possible floating) table redline data for restoring them after frame conversion
+ enum StoredRedlines eType;
+ if (m_bIsActualParagraphFramed || m_nTableDepth > 0)
+ eType = StoredRedlines::FRAME;
+ else if (IsInFootOrEndnote())
+ eType = IsInFootnote() ? StoredRedlines::FOOTNOTE : StoredRedlines::ENDNOTE;
+ else
+ eType = StoredRedlines::NONE;
+
+ if (eType != StoredRedlines::NONE)
+ {
+ m_aStoredRedlines[eType].push_back( uno::Any(xRange) );
+ m_aStoredRedlines[eType].push_back( uno::Any(sType) );
+ m_aStoredRedlines[eType].push_back( uno::Any(aRedlineProperties) );
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "in makeRedline" );
+ }
+}
+
+void DomainMapper_Impl::CheckParaMarkerRedline( uno::Reference< text::XTextRange > const& xRange )
+{
+ if ( m_pParaMarkerRedline )
+ {
+ CreateRedline( xRange, m_pParaMarkerRedline );
+ if ( m_pParaMarkerRedline )
+ {
+ m_pParaMarkerRedline.clear();
+ m_currentRedline.clear();
+ }
+ }
+ else if ( m_pParaMarkerRedlineMove && m_bIsParaMarkerMove )
+ {
+ // terminating moveFrom/moveTo redline removes also the paragraph mark
+ CreateRedline( xRange, m_pParaMarkerRedlineMove );
+ }
+ if ( m_pParaMarkerRedlineMove )
+ {
+ m_pParaMarkerRedlineMove.clear();
+ EndParaMarkerMove();
+ }
+}
+
+void DomainMapper_Impl::CheckRedline( uno::Reference< text::XTextRange > const& xRange )
+{
+ // Writer core "officially" does not like overlapping redlines, and its UNO interface is stupid enough
+ // to not prevent that. However, in practice in fact everything appears to work fine (except for the debug warnings
+ // about redline table corruption, which may possibly be harmless in reality). So leave this as it is, since this
+ // is a better representation of how the changes happened. If this will ever become a problem, overlapping redlines
+ // will need to be merged into one, just like doing the changes in the UI does, which will lose some information
+ // (and so if that happens, it may be better to fix Writer).
+ // Create the redlines here from lowest (formats) to highest (inserts/removals) priority, since the last one is
+ // what Writer presents graphically, so this will show deletes as deleted text and not as just formatted text being there.
+ bool bUsedRange = m_aRedlines.top().size() > 0 || (GetTopContextOfType(CONTEXT_CHARACTER) &&
+ GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0);
+
+ // only export ParagraphFormat, when there is no other redline in the same text portion to avoid missing redline compression,
+ // but always export the first ParagraphFormat redline in a paragraph to keep the paragraph style change data for rejection
+ if( (!bUsedRange || !m_bParaChanged) && GetTopContextOfType(CONTEXT_PARAGRAPH) )
+ {
+ std::vector<RedlineParamsPtr>& avRedLines = GetTopContextOfType(CONTEXT_PARAGRAPH)->Redlines();
+ for( const auto& rRedline : avRedLines )
+ CreateRedline( xRange, rRedline );
+ }
+ if( GetTopContextOfType(CONTEXT_CHARACTER) )
+ {
+ std::vector<RedlineParamsPtr>& avRedLines = GetTopContextOfType(CONTEXT_CHARACTER)->Redlines();
+ for( const auto& rRedline : avRedLines )
+ CreateRedline( xRange, rRedline );
+ }
+ for (const auto& rRedline : m_aRedlines.top() )
+ CreateRedline( xRange, rRedline );
+}
+
+void DomainMapper_Impl::StartParaMarkerChange( )
+{
+ m_bIsParaMarkerChange = true;
+}
+
+void DomainMapper_Impl::EndParaMarkerChange( )
+{
+ m_bIsParaMarkerChange = false;
+ m_previousRedline = m_currentRedline;
+ m_currentRedline.clear();
+}
+
+void DomainMapper_Impl::StartParaMarkerMove( )
+{
+ m_bIsParaMarkerMove = true;
+}
+
+void DomainMapper_Impl::EndParaMarkerMove( )
+{
+ m_bIsParaMarkerMove = false;
+}
+
+void DomainMapper_Impl::StartCustomFootnote(const PropertyMapPtr pContext)
+{
+ if (pContext == m_pFootnoteContext)
+ return;
+
+ assert(pContext->GetFootnote().is());
+ m_bHasFootnoteStyle = true;
+ m_bCheckFootnoteStyle = !pContext->GetFootnoteStyle().isEmpty();
+ m_pFootnoteContext = pContext;
+}
+
+void DomainMapper_Impl::EndCustomFootnote()
+{
+ m_bHasFootnoteStyle = false;
+ m_bCheckFootnoteStyle = false;
+}
+
+void DomainMapper_Impl::PushAnnotation()
+{
+ try
+ {
+ m_bIsInComments = true;
+ if (!GetTextFactory().is())
+ return;
+ m_xAnnotationField.set( GetTextFactory()->createInstance( "com.sun.star.text.TextField.Annotation" ),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< text::XText > xAnnotationText;
+ m_xAnnotationField->getPropertyValue("TextRange") >>= xAnnotationText;
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xAnnotationText, uno::UNO_QUERY_THROW ),
+ m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : xAnnotationText->createTextCursorByRange(xAnnotationText->getStart())));
+ }
+ catch( const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+}
+
+static void lcl_CopyRedlines(
+ uno::Reference< text::XText > const& xSrc,
+ std::deque<css::uno::Any>& rRedlines,
+ std::vector<sal_Int32>& redPos,
+ std::vector<sal_Int32>& redLen,
+ sal_Int32& redIdx)
+{
+ redIdx = -1;
+ for( size_t i = 0; i < rRedlines.size(); i+=3)
+ {
+ uno::Reference< text::XTextRange > xRange;
+ rRedlines[i] >>= xRange;
+
+ // is this a redline of the temporary footnote?
+ uno::Reference<text::XTextCursor> xRangeCursor;
+ try
+ {
+ xRangeCursor = xSrc->createTextCursorByRange( xRange );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ if (xRangeCursor.is())
+ {
+ redIdx = i;
+ sal_Int32 nLen = xRange->getString().getLength();
+ redLen.push_back(nLen);
+ xRangeCursor->gotoRange(xSrc->getStart(), true);
+ redPos.push_back(xRangeCursor->getString().getLength() - nLen);
+ }
+ else
+ {
+ // we have already found all redlines of the footnote,
+ // skip checking the redlines of the other footnotes
+ if (redIdx > -1)
+ break;
+ // failed createTextCursorByRange(), for example, table inside the frame
+ redLen.push_back(-1);
+ redPos.push_back(-1);
+ }
+ }
+}
+
+static void lcl_PasteRedlines(
+ uno::Reference< text::XText > const& xDest,
+ std::deque<css::uno::Any>& rRedlines,
+ std::vector<sal_Int32>& redPos,
+ std::vector<sal_Int32>& redLen,
+ sal_Int32 redIdx)
+{
+ // create redlines in the copied footnote
+ for( size_t i = 0; redIdx > -1 && i <= sal::static_int_cast<size_t>(redIdx); i+=3)
+ {
+ OUString sType;
+ beans::PropertyValues aRedlineProperties( 3 );
+ // skip failed createTextCursorByRange()
+ if (redPos[i/3] == -1)
+ continue;
+ rRedlines[i+1] >>= sType;
+ rRedlines[i+2] >>= aRedlineProperties;
+ uno::Reference< text::XTextCursor > xCrsr = xDest->getText()->createTextCursor();
+ xCrsr->goRight(redPos[i/3], false);
+ xCrsr->goRight(redLen[i/3], true);
+ uno::Reference < text::XRedline > xRedline( xCrsr, uno::UNO_QUERY_THROW );
+ try {
+ xRedline->makeRedline( sType, aRedlineProperties );
+ }
+ catch(const uno::Exception&)
+ {
+ // ignore (footnotes of tracked deletions)
+ }
+ }
+}
+
+bool DomainMapper_Impl::CopyTemporaryNotes(
+ uno::Reference< text::XFootnote > xNoteSrc,
+ uno::Reference< text::XFootnote > xNoteDest )
+{
+ if (!m_bSaxError && xNoteSrc != xNoteDest)
+ {
+ uno::Reference< text::XText > xSrc( xNoteSrc, uno::UNO_QUERY_THROW );
+ uno::Reference< text::XText > xDest( xNoteDest, uno::UNO_QUERY_THROW );
+ uno::Reference< text::XTextCopy > xTxt, xTxt2;
+ xTxt.set( xSrc, uno::UNO_QUERY_THROW );
+ xTxt2.set( xDest, uno::UNO_QUERY_THROW );
+ xTxt2->copyText( xTxt );
+
+ // copy its redlines
+ std::vector<sal_Int32> redPos, redLen;
+ sal_Int32 redIdx;
+ enum StoredRedlines eType = IsInFootnote() ? StoredRedlines::FOOTNOTE : StoredRedlines::ENDNOTE;
+ lcl_CopyRedlines(xSrc, m_aStoredRedlines[eType], redPos, redLen, redIdx);
+ lcl_PasteRedlines(xDest, m_aStoredRedlines[eType], redPos, redLen, redIdx);
+
+ // remove processed redlines
+ for( size_t i = 0; redIdx > -1 && i <= sal::static_int_cast<size_t>(redIdx) + 2; i++)
+ m_aStoredRedlines[eType].pop_front();
+
+ return true;
+ }
+
+ return false;
+}
+
+void DomainMapper_Impl::RemoveTemporaryFootOrEndnotes()
+{
+ uno::Reference< text::XFootnotesSupplier> xFootnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< text::XEndnotesSupplier> xEndnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< text::XFootnote > xNote;
+ if (GetFootnoteCount() > 0)
+ {
+ auto xFootnotes = xFootnotesSupplier->getFootnotes();
+ if ( m_nFirstFootnoteIndex > 0 )
+ {
+ uno::Reference< text::XFootnote > xFirstNote;
+ xFootnotes->getByIndex(0) >>= xFirstNote;
+ uno::Reference< text::XText > xText( xFirstNote, uno::UNO_QUERY_THROW );
+ xText->setString("");
+ xFootnotes->getByIndex(m_nFirstFootnoteIndex) >>= xNote;
+ CopyTemporaryNotes(xNote, xFirstNote);
+ }
+ for (sal_Int32 i = GetFootnoteCount(); i > 0; --i)
+ {
+ xFootnotes->getByIndex(i) >>= xNote;
+ xNote->getAnchor()->setString("");
+ }
+ }
+ if (GetEndnoteCount() > 0)
+ {
+ auto xEndnotes = xEndnotesSupplier->getEndnotes();
+ if ( m_nFirstEndnoteIndex > 0 )
+ {
+ uno::Reference< text::XFootnote > xFirstNote;
+ xEndnotes->getByIndex(0) >>= xFirstNote;
+ uno::Reference< text::XText > xText( xFirstNote, uno::UNO_QUERY_THROW );
+ xText->setString("");
+ xEndnotes->getByIndex(m_nFirstEndnoteIndex) >>= xNote;
+ CopyTemporaryNotes(xNote, xFirstNote);
+ }
+ for (sal_Int32 i = GetEndnoteCount(); i > 0; --i)
+ {
+ xEndnotes->getByIndex(i) >>= xNote;
+ xNote->getAnchor()->setString("");
+ }
+ }
+}
+
+static void lcl_convertToNoteIndices(std::deque<sal_Int32>& rNoteIds, sal_Int32& rFirstNoteIndex)
+{
+ // rNoteIds contains XML footnote identifiers in the loaded order of the footnotes
+ // (the same order as in footnotes.xml), i.e. it maps temporary footnote positions to the
+ // identifiers. For example: Ids[0] = 100; Ids[1] = -1, Ids[2] = 5.
+ // To copy the footnotes in their final place, create an array, which map the (normalized)
+ // footnote identifiers to the temporary footnote positions. Using the previous example,
+ // Pos[0] = 1; Pos[1] = 2; Pos[2] = 0 (where [0], [1], [2] are the normalized
+ // -1, 5 and 100 identifiers).
+ std::deque<sal_Int32> aSortedIds = rNoteIds;
+ std::sort(aSortedIds.begin(), aSortedIds.end());
+ std::map<sal_Int32, size_t> aMapIds;
+ // normalize footnote identifiers to 0, 1, 2 ...
+ for (size_t i = 0; i < aSortedIds.size(); ++i)
+ aMapIds[aSortedIds[i]] = i;
+ // reusing rNoteIds, create the Pos array to map normalized identifiers to the loaded positions
+ std::deque<sal_Int32> aOrigNoteIds = rNoteIds;
+ for (size_t i = 0; i < rNoteIds.size(); ++i)
+ rNoteIds[aMapIds[aOrigNoteIds[i]]] = i;
+ rFirstNoteIndex = rNoteIds.front();
+ rNoteIds.pop_front();
+}
+
+void DomainMapper_Impl::PopFootOrEndnote()
+{
+ // content of the footnotes were inserted after the first footnote in temporary footnotes,
+ // restore the content of the actual footnote by copying its content from the first
+ // (remaining) temporary footnote and remove the temporary footnote.
+ uno::Reference< text::XFootnotesSupplier> xFootnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< text::XEndnotesSupplier> xEndnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ bool bCopied = false;
+ if ( IsInFootOrEndnote() && ( ( IsInFootnote() && GetFootnoteCount() > -1 && xFootnotesSupplier.is() ) ||
+ ( !IsInFootnote() && GetEndnoteCount() > -1 && xEndnotesSupplier.is() ) ) )
+ {
+ uno::Reference< text::XFootnote > xNoteFirst, xNoteLast;
+ auto xFootnotes = xFootnotesSupplier->getFootnotes();
+ auto xEndnotes = xEndnotesSupplier->getEndnotes();
+ if ( ( ( IsInFootnote() && xFootnotes->getCount() > 1 &&
+ ( xFootnotes->getByIndex(xFootnotes->getCount()-1) >>= xNoteLast ) ) ||
+ ( !IsInFootnote() && xEndnotes->getCount() > 1 &&
+ ( xEndnotes->getByIndex(xEndnotes->getCount()-1) >>= xNoteLast ) )
+ ) && xNoteLast->getLabel().isEmpty() )
+ {
+ // copy content of the next temporary footnote
+ try
+ {
+ if ( IsInFootnote() && !m_aFootnoteIds.empty() )
+ {
+ if ( m_nFirstFootnoteIndex == -1 )
+ lcl_convertToNoteIndices(m_aFootnoteIds, m_nFirstFootnoteIndex);
+ if (m_aFootnoteIds.empty()) // lcl_convertToNoteIndices pops m_aFootnoteIds
+ m_bSaxError = true;
+ else
+ {
+ xFootnotes->getByIndex(m_aFootnoteIds.front()) >>= xNoteFirst;
+ m_aFootnoteIds.pop_front();
+ }
+ }
+ else if ( !IsInFootnote() && !m_aEndnoteIds.empty() )
+ {
+ if ( m_nFirstEndnoteIndex == -1 )
+ lcl_convertToNoteIndices(m_aEndnoteIds, m_nFirstEndnoteIndex);
+ if (m_aEndnoteIds.empty()) // lcl_convertToNoteIndices pops m_aEndnoteIds
+ m_bSaxError = true;
+ else
+ {
+ xEndnotes->getByIndex(m_aEndnoteIds.front()) >>= xNoteFirst;
+ m_aEndnoteIds.pop_front();
+ }
+ }
+ else
+ m_bSaxError = true;
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "Cannot insert footnote/endnote");
+ m_bSaxError = true;
+ }
+
+ bCopied = CopyTemporaryNotes(xNoteFirst, xNoteLast);
+ }
+ }
+
+ if (!IsRTFImport() && !bCopied)
+ RemoveLastParagraph();
+
+ // In case the foot or endnote did not contain a tab.
+ m_bIgnoreNextTab = false;
+
+ if (!m_aTextAppendStack.empty())
+ m_aTextAppendStack.pop();
+
+ if (m_aRedlines.size() == 1)
+ {
+ SAL_WARN("writerfilter.dmapper", "PopFootOrEndnote() is called without PushFootOrEndnote()?");
+ return;
+ }
+ m_aRedlines.pop();
+ m_eSkipFootnoteState = SkipFootnoteSeparator::OFF;
+ m_bInFootOrEndnote = false;
+ m_pFootnoteContext = nullptr;
+ m_bFirstParagraphInCell = m_bSaveFirstParagraphInCell;
+}
+
+void DomainMapper_Impl::PopAnnotation()
+{
+ RemoveLastParagraph();
+
+ m_bIsInComments = false;
+ m_aTextAppendStack.pop();
+
+ try
+ {
+ if (m_bAnnotationResolved)
+ m_xAnnotationField->setPropertyValue("Resolved", css::uno::Any(true));
+
+ // See if the annotation will be a single position or a range.
+ if (m_nAnnotationId == -1 || !m_aAnnotationPositions[m_nAnnotationId].m_xStart.is() || !m_aAnnotationPositions[m_nAnnotationId].m_xEnd.is())
+ {
+ uno::Sequence< beans::PropertyValue > aEmptyProperties;
+ uno::Reference< text::XTextContent > xContent( m_xAnnotationField, uno::UNO_QUERY_THROW );
+ appendTextContent( xContent, aEmptyProperties );
+ CheckRedline( xContent->getAnchor( ) );
+ }
+ else
+ {
+ AnnotationPosition& aAnnotationPosition = m_aAnnotationPositions[m_nAnnotationId];
+ // Create a range that points to the annotation start/end.
+ uno::Reference<text::XText> const xText = aAnnotationPosition.m_xStart->getText();
+ uno::Reference<text::XTextCursor> const xCursor = xText->createTextCursorByRange(aAnnotationPosition.m_xStart);
+
+ bool bMarker = false;
+ uno::Reference<text::XTextRangeCompare> xTextRangeCompare(xText, uno::UNO_QUERY);
+ if (xTextRangeCompare->compareRegionStarts(aAnnotationPosition.m_xStart, aAnnotationPosition.m_xEnd) == 0)
+ {
+ // Insert a marker so that comment around an anchored image is not collapsed during
+ // insertion.
+ xText->insertString(xCursor, "x", false);
+ bMarker = true;
+ }
+
+ xCursor->gotoRange(aAnnotationPosition.m_xEnd, true);
+ uno::Reference<text::XTextRange> const xTextRange(xCursor, uno::UNO_QUERY_THROW);
+
+ // Attach the annotation to the range.
+ uno::Reference<text::XTextAppend> const xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ xTextAppend->insertTextContent(xTextRange, uno::Reference<text::XTextContent>(m_xAnnotationField, uno::UNO_QUERY_THROW), !xCursor->isCollapsed());
+
+ if (bMarker)
+ {
+ // Remove the marker.
+ xCursor->goLeft(1, true);
+ xCursor->setString(OUString());
+ }
+ }
+ m_aAnnotationPositions.erase( m_nAnnotationId );
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "Cannot insert annotation field");
+ }
+
+ m_xAnnotationField.clear();
+ m_nAnnotationId = -1;
+ m_bAnnotationResolved = false;
+}
+
+void DomainMapper_Impl::PushPendingShape( const uno::Reference< drawing::XShape > & xShape )
+{
+ m_aPendingShapes.push_back(xShape);
+}
+
+uno::Reference<drawing::XShape> DomainMapper_Impl::PopPendingShape()
+{
+ uno::Reference<drawing::XShape> xRet;
+ if (!m_aPendingShapes.empty())
+ {
+ xRet = m_aPendingShapes.front();
+ m_aPendingShapes.pop_front();
+ }
+ return xRet;
+}
+
+void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape > & xShape )
+{
+ // Append these early, so the context and the table manager stack will be
+ // in sync, even if the text append stack is empty.
+ appendTableManager();
+ appendTableHandler();
+ getTableManager().startLevel();
+
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+
+ try
+ {
+ uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
+ if (xSInfo->supportsService("com.sun.star.drawing.GroupShape"))
+ {
+ // Textboxes in shapes do not support styles, so check saved style information and apply properties directly to the child shapes.
+ const uno::Reference<drawing::XShapes> xShapes(xShape, uno::UNO_QUERY);
+ const sal_uInt32 nShapeCount = xShapes.is() ? xShapes->getCount() : 0;
+ for ( sal_uInt32 i = 0; i < nShapeCount; ++i )
+ {
+ try
+ {
+ uno::Reference<text::XTextRange> xFrame(xShapes->getByIndex(i), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xFramePropertySet;
+ if (xFrame)
+ xFramePropertySet.set(xFrame, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShapes->getByIndex(i), uno::UNO_QUERY_THROW);
+
+ comphelper::SequenceAsHashMap aGrabBag( xShapePropertySet->getPropertyValue("CharInteropGrabBag") );
+
+ // only VML import has checked for style. Don't apply default parastyle properties to other imported shapes
+ // - except for fontsize - to maintain compatibility with previous versions of LibreOffice.
+ const bool bOnlyApplyCharHeight = !aGrabBag["mso-pStyle"].hasValue();
+
+ OUString sStyleName;
+ aGrabBag["mso-pStyle"] >>= sStyleName;
+ StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByISTD( sStyleName );
+ if ( !pEntry )
+ {
+ // Use default style even in ambiguous cases (where multiple styles were defined) since MOST styles inherit
+ // MOST of their properties from the default style. In the ambiguous case, we have to accept some kind of compromise
+ // and the default paragraph style ought to be the safest one... (compared to DocDefaults or program defaults)
+ pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( GetDefaultParaStyleName() );
+ }
+ if ( pEntry )
+ {
+ // The Ids here come from oox/source/vml/vmltextbox.cxx.
+ // It probably could safely expand to all Ids that shapes support.
+ const PropertyIds eIds[] = {
+ PROP_CHAR_HEIGHT,
+ PROP_CHAR_FONT_NAME,
+ PROP_CHAR_WEIGHT,
+ PROP_CHAR_CHAR_KERNING,
+ PROP_CHAR_COLOR,
+ PROP_PARA_ADJUST
+ };
+ const uno::Reference<beans::XPropertyState> xShapePropertyState(xShapePropertySet, uno::UNO_QUERY_THROW);
+ for ( const auto& eId : eIds )
+ {
+ try
+ {
+ if ( bOnlyApplyCharHeight && eId != PROP_CHAR_HEIGHT )
+ continue;
+
+ const OUString sPropName = getPropertyName(eId);
+ if ( beans::PropertyState_DEFAULT_VALUE == xShapePropertyState->getPropertyState(sPropName) )
+ {
+ const uno::Any aProp = GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true);
+ if (aProp.hasValue())
+ {
+ if (xFrame)
+ xFramePropertySet->setPropertyValue(sPropName, aProp);
+ else
+ xShapePropertySet->setPropertyValue(sPropName, aProp);
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "PushShapeContext() text stylesheet property exception" );
+ }
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "PushShapeContext()" );
+ }
+ }
+
+ // A GroupShape doesn't implement text::XTextRange, but appending
+ // an empty reference to the stacks still makes sense, because this
+ // way bToRemove can be set, and we won't end up with duplicated
+ // shapes for OLE objects.
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xShape, uno::UNO_QUERY), uno::Reference<text::XTextCursor>()));
+ uno::Reference<text::XTextContent> xTxtContent(xShape, uno::UNO_QUERY);
+ m_aAnchoredStack.push(AnchoredContext(xTxtContent));
+ }
+ else if (xSInfo->supportsService("com.sun.star.drawing.OLE2Shape"))
+ {
+ // OLE2Shape from oox should be converted to a TextEmbeddedObject for sw.
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xShape, uno::UNO_QUERY), uno::Reference<text::XTextCursor>()));
+ uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY);
+ m_aAnchoredStack.push(AnchoredContext(xTextContent));
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+
+ m_xEmbedded.set(m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xEmbeddedProperties(m_xEmbedded, uno::UNO_QUERY_THROW);
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_EMBEDDED_OBJECT), xShapePropertySet->getPropertyValue(getPropertyName(PROP_EMBEDDED_OBJECT)));
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE), uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+ // So that the original bitmap-only shape will be replaced by the embedded object.
+ m_aAnchoredStack.top().bToRemove = true;
+ m_aTextAppendStack.pop();
+ appendTextContent(m_xEmbedded, uno::Sequence<beans::PropertyValue>());
+ }
+ else
+ {
+ uno::Reference<text::XTextRange> xShapeTextRange(xShape, uno::UNO_QUERY_THROW);
+ // Add the shape to the text append stack
+ uno::Reference<text::XTextAppend> xShapeTextAppend(xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextCursor> xTextCursor;
+ if (!m_bIsNewDoc)
+ {
+ xTextCursor = xShapeTextRange->getText()->createTextCursorByRange(
+ xShapeTextRange->getStart());
+ }
+ TextAppendContext aContext(xShapeTextAppend, xTextCursor);
+ m_aTextAppendStack.push(aContext);
+
+ // Add the shape to the anchored objects stack
+ uno::Reference< text::XTextContent > xTxtContent( xShape, uno::UNO_QUERY_THROW );
+ m_aAnchoredStack.push( AnchoredContext(xTxtContent) );
+
+ uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().unoPropertySet(xProps);
+#endif
+ text::TextContentAnchorType nAnchorType(text::TextContentAnchorType_AT_PARAGRAPH);
+ xProps->getPropertyValue(getPropertyName( PROP_ANCHOR_TYPE )) >>= nAnchorType;
+ bool checkZOrderStatus = false;
+ if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
+ {
+ SetIsTextFrameInserted(true);
+ // Extract the special "btLr text frame" mode, requested by oox, if needed.
+ // Extract vml ZOrder from FrameInteropGrabBag
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ xShapePropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
+
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ if (rProp.Name == "VML-Z-ORDER")
+ {
+ GraphicZOrderHelper* pZOrderHelper = m_rDMapper.graphicZOrderHelper();
+ sal_Int32 zOrder(0);
+ rProp.Value >>= zOrder;
+ xShapePropertySet->setPropertyValue( "ZOrder", uno::Any(pZOrderHelper->findZOrder(zOrder)));
+ pZOrderHelper->addItem(xShapePropertySet, zOrder);
+ xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any( zOrder >= 0 ) );
+ checkZOrderStatus = true;
+ }
+ else if ( rProp.Name == "TxbxHasLink" )
+ {
+ //Chaining of textboxes will happen in ~DomainMapper_Impl
+ //i.e when all the textboxes are read and all its attributes
+ //have been set ( basically the Name/LinkedDisplayName )
+ //which is set in Graphic Import.
+ m_vTextFramesForChaining.push_back(xShape);
+ }
+ }
+
+ uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRange> xTextRange(xTextAppend->createTextCursorByRange(xTextAppend->getEnd()), uno::UNO_QUERY_THROW);
+ xTextAppend->insertTextContent(xTextRange, xTextContent, false);
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+ // we need to re-set this value to xTextContent, then only values are preserved.
+ xPropertySet->setPropertyValue("FrameInteropGrabBag",uno::Any(aGrabBag));
+ }
+ else if (nAnchorType == text::TextContentAnchorType_AS_CHARACTER)
+ {
+ // Fix spacing for as-character objects. If the paragraph has CT_Spacing_after set,
+ // it needs to be set on the object too, as that's what object placement code uses.
+ PropertyMapPtr paragraphContext = GetTopContextOfType( CONTEXT_PARAGRAPH );
+ std::optional<PropertyMap::Property> aPropMargin = paragraphContext->getProperty(PROP_PARA_BOTTOM_MARGIN);
+ if(aPropMargin)
+ xProps->setPropertyValue( getPropertyName( PROP_BOTTOM_MARGIN ), aPropMargin->second );
+ }
+ else
+ {
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ xShapePropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ if (rProp.Name == "VML-Z-ORDER")
+ {
+ GraphicZOrderHelper* pZOrderHelper = m_rDMapper.graphicZOrderHelper();
+ sal_Int32 zOrder(0);
+ rProp.Value >>= zOrder;
+ xShapePropertySet->setPropertyValue( "ZOrder", uno::Any(pZOrderHelper->findZOrder(zOrder)));
+ pZOrderHelper->addItem(xShapePropertySet, zOrder);
+ xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any( zOrder >= 0 ) );
+ checkZOrderStatus = true;
+ }
+ else if ( rProp.Name == "TxbxHasLink" )
+ {
+ //Chaining of textboxes will happen in ~DomainMapper_Impl
+ //i.e when all the textboxes are read and all its attributes
+ //have been set ( basically the Name/LinkedDisplayName )
+ //which is set in Graphic Import.
+ m_vTextFramesForChaining.push_back(xShape);
+ }
+ }
+
+ if(IsSdtEndBefore())
+ {
+ uno::Reference< beans::XPropertySetInfo > xPropSetInfo;
+ if(xShapePropertySet.is())
+ {
+ xPropSetInfo = xShapePropertySet->getPropertySetInfo();
+ if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("InteropGrabBag"))
+ {
+ uno::Sequence<beans::PropertyValue> aShapeGrabBag( comphelper::InitPropertySequence({
+ { "SdtEndBefore", uno::Any(true) }
+ }));
+ xShapePropertySet->setPropertyValue("InteropGrabBag",uno::Any(aShapeGrabBag));
+ }
+ }
+ }
+ }
+ if (!IsInHeaderFooter() && !checkZOrderStatus)
+ xProps->setPropertyValue(
+ getPropertyName( PROP_OPAQUE ),
+ uno::Any( true ) );
+ }
+ m_bParaChanged = true;
+ getTableManager().setIsInShape(true);
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "Exception when adding shape");
+ }
+}
+/*
+ * Updating chart height and width after reading the actual values from wp:extent
+*/
+void DomainMapper_Impl::UpdateEmbeddedShapeProps(const uno::Reference< drawing::XShape > & xShape)
+{
+ if (!xShape.is())
+ return;
+
+ uno::Reference<beans::XPropertySet> xEmbeddedProperties(m_xEmbedded, uno::UNO_QUERY_THROW);
+ awt::Size aSize = xShape->getSize( );
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_WIDTH), uno::Any(sal_Int32(aSize.Width)));
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_HEIGHT), uno::Any(sal_Int32(aSize.Height)));
+}
+
+
+void DomainMapper_Impl::PopShapeContext()
+{
+ if (hasTableManager())
+ {
+ getTableManager().endLevel();
+ popTableManager();
+ }
+ if ( m_aAnchoredStack.empty() )
+ return;
+
+ // For OLE object replacement shape, the text append context was already removed
+ // or the OLE object couldn't be inserted.
+ if ( !m_aAnchoredStack.top().bToRemove )
+ {
+ RemoveLastParagraph();
+ if (!m_aTextAppendStack.empty())
+ m_aTextAppendStack.pop();
+ }
+
+ uno::Reference< text::XTextContent > xObj = m_aAnchoredStack.top( ).xTextContent;
+ try
+ {
+ appendTextContent( xObj, uno::Sequence< beans::PropertyValue >() );
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ // this is normal: the shape is already attached
+ }
+
+ const uno::Reference<drawing::XShape> xShape( xObj, uno::UNO_QUERY_THROW );
+ // Remove the shape if required (most likely replacement shape for OLE object)
+ // or anchored to a discarded header or footer
+ if ( m_aAnchoredStack.top().bToRemove || m_bDiscardHeaderFooter )
+ {
+ try
+ {
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ if ( xDrawPage.is() )
+ xDrawPage->remove( xShape );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ // Relative width calculations deferred until section's margins are defined.
+ // Being cautious: only deferring undefined/minimum-width shapes in order to avoid causing potential regressions
+ css::awt::Size aShapeSize;
+ try
+ {
+ aShapeSize = xShape->getSize();
+ }
+ catch (const css::uno::RuntimeException& e)
+ {
+ // May happen e.g. when text frame has no frame format
+ // See sw/qa/extras/ooxmlimport/data/n779627.docx
+ SAL_WARN("writerfilter.dmapper", "getSize failed. " << e.Message);
+ }
+ if( aShapeSize.Width <= 2 )
+ {
+ const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
+ SectionPropertyMap* pSectionContext = GetSectionContext();
+ if ( pSectionContext && (!hasTableManager() || !getTableManager().isInTable()) &&
+ xShapePropertySet->getPropertySetInfo()->hasPropertyByName(getPropertyName(PROP_RELATIVE_WIDTH)) )
+ {
+ pSectionContext->addRelativeWidthShape(xShape);
+ }
+ }
+
+ m_aAnchoredStack.pop();
+}
+
+bool DomainMapper_Impl::IsSdtEndBefore()
+{
+ bool bIsSdtEndBefore = false;
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_CHARACTER);
+ if(pContext)
+ {
+ const uno::Sequence< beans::PropertyValue > currentCharProps = pContext->GetPropertyValues();
+ for (const auto& rCurrentCharProp : currentCharProps)
+ {
+ if (rCurrentCharProp.Name == "CharInteropGrabBag")
+ {
+ uno::Sequence<beans::PropertyValue> aCharGrabBag;
+ rCurrentCharProp.Value >>= aCharGrabBag;
+ for (const auto& rProp : std::as_const(aCharGrabBag))
+ {
+ if(rProp.Name == "SdtEndBefore")
+ {
+ rProp.Value >>= bIsSdtEndBefore;
+ }
+ }
+ }
+ }
+ }
+ return bIsSdtEndBefore;
+}
+
+bool DomainMapper_Impl::IsDiscardHeaderFooter() const
+{
+ return m_bDiscardHeaderFooter;
+}
+
+// called from TableManager::closeCell()
+void DomainMapper_Impl::ClearPreviousParagraph()
+{
+ // in table cells, set bottom auto margin of last paragraph to 0, except in paragraphs with numbering
+ if ((m_nTableDepth == (m_nTableCellDepth + 1))
+ && m_xPreviousParagraph.is()
+ && hasTableManager() && getTableManager().isCellLastParaAfterAutospacing())
+ {
+ uno::Reference<container::XNamed> xPreviousNumberingRules(m_xPreviousParagraph->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+ if ( !xPreviousNumberingRules.is() || xPreviousNumberingRules->getName().isEmpty() )
+ m_xPreviousParagraph->setPropertyValue("ParaBottomMargin", uno::Any(static_cast<sal_Int32>(0)));
+ }
+
+ m_xPreviousParagraph.clear();
+
+ // next table paragraph will be first paragraph in a cell
+ m_bFirstParagraphInCell = true;
+}
+
+void DomainMapper_Impl::HandleAltChunk(const OUString& rStreamName)
+{
+ try
+ {
+ // Create the import filter.
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
+ comphelper::getProcessServiceFactory());
+ uno::Reference<uno::XInterface> xDocxFilter
+ = xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.WriterFilter");
+
+ // Set the target document.
+ uno::Reference<document::XImporter> xImporter(xDocxFilter, uno::UNO_QUERY);
+ xImporter->setTargetDocument(m_xTextDocument);
+
+ // Set the import parameters.
+ uno::Reference<embed::XHierarchicalStorageAccess> xStorageAccess(m_xDocumentStorage,
+ uno::UNO_QUERY);
+ if (!xStorageAccess.is())
+ {
+ return;
+ }
+ // Turn the ZIP stream into a seekable one, as the importer only works with such streams.
+ uno::Reference<io::XStream> xStream = xStorageAccess->openStreamElementByHierarchicalName(
+ rStreamName, embed::ElementModes::READ);
+ std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(xStream, true);
+ SvMemoryStream aMemory;
+ aMemory.WriteStream(*pStream);
+ uno::Reference<io::XStream> xInputStream = new utl::OStreamWrapper(aMemory);
+ // Not handling AltChunk during paste for now.
+ uno::Reference<text::XTextRange> xInsertTextRange = GetCurrentXText()->getEnd();
+ uno::Reference<text::XTextRange> xSectionStartingRange;
+ SectionPropertyMap* pSectionContext = GetSectionContext();
+ if (pSectionContext)
+ {
+ xSectionStartingRange = pSectionContext->GetStartingRange();
+ }
+ uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
+ { "InputStream", uno::Any(xInputStream) },
+ { "InsertMode", uno::Any(true) },
+ { "TextInsertModeRange", uno::Any(xInsertTextRange) },
+ { "AltChunkMode", uno::Any(true) },
+ { "AltChunkStartingRange", uno::Any(xSectionStartingRange) },
+ }));
+
+ // Do the actual import.
+ uno::Reference<document::XFilter> xFilter(xDocxFilter, uno::UNO_QUERY);
+ xFilter->filter(aDescriptor);
+ }
+ catch (const uno::Exception& rException)
+ {
+ SAL_WARN("writerfilter", "DomainMapper_Impl::HandleAltChunk: failed to handle alt chunk: "
+ << rException.Message);
+ }
+}
+
+void DomainMapper_Impl::HandlePTab(sal_Int32 nAlignment)
+{
+ // We only handle the case when the line already has content, so the left-aligned ptab is
+ // equivalent to a line break.
+ if (nAlignment != NS_ooxml::LN_Value_ST_PTabAlignment_left)
+ {
+ return;
+ }
+
+ if (m_aTextAppendStack.empty())
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is())
+ {
+ return;
+ }
+
+ uno::Reference<css::text::XTextRange> xInsertPosition
+ = m_aTextAppendStack.top().xInsertPosition;
+ if (!xInsertPosition.is())
+ {
+ xInsertPosition = xTextAppend->getEnd();
+ }
+ uno::Reference<text::XTextCursor> xCursor
+ = xTextAppend->createTextCursorByRange(xInsertPosition);
+
+ // Assume that we just inserted a tab character.
+ xCursor->goLeft(1, true);
+ if (xCursor->getString() != "\t")
+ {
+ return;
+ }
+
+ // Assume that there is some content before the tab character.
+ uno::Reference<text::XParagraphCursor> xParagraphCursor(xCursor, uno::UNO_QUERY);
+ if (!xParagraphCursor.is())
+ {
+ return;
+ }
+
+ xCursor->collapseToStart();
+ xParagraphCursor->gotoStartOfParagraph(true);
+ if (xCursor->isCollapsed())
+ {
+ return;
+ }
+
+ // Then select the tab again and replace with a line break.
+ xCursor->collapseToEnd();
+ xCursor->goRight(1, true);
+ xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::LINE_BREAK, true);
+}
+
+void DomainMapper_Impl::HandleLineBreakClear(sal_Int32 nClear)
+{
+ switch (nClear)
+ {
+ case NS_ooxml::LN_Value_ST_BrClear_left:
+ // SwLineBreakClear::LEFT
+ m_oLineBreakClear = 1;
+ break;
+ case NS_ooxml::LN_Value_ST_BrClear_right:
+ // SwLineBreakClear::RIGHT
+ m_oLineBreakClear = 2;
+ break;
+ case NS_ooxml::LN_Value_ST_BrClear_all:
+ // SwLineBreakClear::ALL
+ m_oLineBreakClear = 3;
+ break;
+ }
+}
+
+void DomainMapper_Impl::HandleLineBreak(const PropertyMapPtr& pPropertyMap)
+{
+ if (!m_oLineBreakClear.has_value())
+ {
+ appendTextPortion("\n", pPropertyMap);
+ return;
+ }
+
+ if (GetTextFactory().is())
+ {
+ uno::Reference<text::XTextContent> xLineBreak(
+ GetTextFactory()->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
+ xLineBreakProps->setPropertyValue("Clear", uno::Any(*m_oLineBreakClear));
+ appendTextContent(xLineBreak, pPropertyMap->GetPropertyValues());
+ }
+ m_oLineBreakClear.reset();
+}
+
+static sal_Int16 lcl_ParseNumberingType( std::u16string_view rCommand )
+{
+ sal_Int16 nRet = style::NumberingType::PAGE_DESCRIPTOR;
+
+ // The command looks like: " PAGE \* Arabic "
+ // tdf#132185: but may as well be "PAGE \* Arabic"
+ OUString sNumber;
+ constexpr OUStringLiteral rSeparator(u"\\* ");
+ if (size_t nStartIndex = rCommand.find(rSeparator); nStartIndex != std::u16string_view::npos)
+ {
+ sal_Int32 nStartIndex2 = nStartIndex + rSeparator.getLength();
+ sNumber = o3tl::getToken(rCommand, 0, ' ', nStartIndex2);
+ }
+
+ if( !sNumber.isEmpty() )
+ {
+ //todo: might make sense to hash this list, too
+ struct NumberingPairs
+ {
+ const char* cWordName;
+ sal_Int16 nType;
+ };
+ static const NumberingPairs aNumberingPairs[] =
+ {
+ {"Arabic", style::NumberingType::ARABIC}
+ ,{"ROMAN", style::NumberingType::ROMAN_UPPER}
+ ,{"roman", style::NumberingType::ROMAN_LOWER}
+ ,{"ALPHABETIC", style::NumberingType::CHARS_UPPER_LETTER}
+ ,{"alphabetic", style::NumberingType::CHARS_LOWER_LETTER}
+ ,{"CircleNum", style::NumberingType::CIRCLE_NUMBER}
+ ,{"ThaiArabic", style::NumberingType::CHARS_THAI}
+ ,{"ThaiCardText", style::NumberingType::CHARS_THAI}
+ ,{"ThaiLetter", style::NumberingType::CHARS_THAI}
+// ,{"SBCHAR", style::NumberingType::}
+// ,{"DBCHAR", style::NumberingType::}
+// ,{"DBNUM1", style::NumberingType::}
+// ,{"DBNUM2", style::NumberingType::}
+// ,{"DBNUM3", style::NumberingType::}
+// ,{"DBNUM4", style::NumberingType::}
+ ,{"Aiueo", style::NumberingType::AIU_FULLWIDTH_JA}
+ ,{"Iroha", style::NumberingType::IROHA_FULLWIDTH_JA}
+// ,{"ZODIAC1", style::NumberingType::}
+// ,{"ZODIAC2", style::NumberingType::}
+// ,{"ZODIAC3", style::NumberingType::}
+// ,{"CHINESENUM1", style::NumberingType::}
+// ,{"CHINESENUM2", style::NumberingType::}
+// ,{"CHINESENUM3", style::NumberingType::}
+ ,{"ArabicAlpha", style::NumberingType::CHARS_ARABIC}
+ ,{"ArabicAbjad", style::NumberingType::FULLWIDTH_ARABIC}
+ ,{"Ganada", style::NumberingType::HANGUL_JAMO_KO}
+ ,{"Chosung", style::NumberingType::HANGUL_SYLLABLE_KO}
+ ,{"KoreanCounting", style::NumberingType::NUMBER_HANGUL_KO}
+ ,{"KoreanLegal", style::NumberingType::NUMBER_LEGAL_KO}
+ ,{"KoreanDigital", style::NumberingType::NUMBER_DIGITAL_KO}
+ ,{"KoreanDigital2", style::NumberingType::NUMBER_DIGITAL2_KO}
+/* possible values:
+style::NumberingType::
+
+ CHARS_UPPER_LETTER_N
+ CHARS_LOWER_LETTER_N
+ TRANSLITERATION
+ NATIVE_NUMBERING
+ CIRCLE_NUMBER
+ NUMBER_LOWER_ZH
+ NUMBER_UPPER_ZH
+ NUMBER_UPPER_ZH_TW
+ TIAN_GAN_ZH
+ DI_ZI_ZH
+ NUMBER_TRADITIONAL_JA
+ AIU_HALFWIDTH_JA
+ IROHA_HALFWIDTH_JA
+ NUMBER_UPPER_KO
+ NUMBER_HANGUL_KO
+ HANGUL_JAMO_KO
+ HANGUL_SYLLABLE_KO
+ HANGUL_CIRCLED_JAMO_KO
+ HANGUL_CIRCLED_SYLLABLE_KO
+ CHARS_HEBREW
+ CHARS_NEPALI
+ CHARS_KHMER
+ CHARS_LAO
+ CHARS_TIBETAN
+ CHARS_CYRILLIC_UPPER_LETTER_BG
+ CHARS_CYRILLIC_LOWER_LETTER_BG
+ CHARS_CYRILLIC_UPPER_LETTER_N_BG
+ CHARS_CYRILLIC_LOWER_LETTER_N_BG
+ CHARS_CYRILLIC_UPPER_LETTER_RU
+ CHARS_CYRILLIC_LOWER_LETTER_RU
+ CHARS_CYRILLIC_UPPER_LETTER_N_RU
+ CHARS_CYRILLIC_LOWER_LETTER_N_RU
+ CHARS_CYRILLIC_UPPER_LETTER_SR
+ CHARS_CYRILLIC_LOWER_LETTER_SR
+ CHARS_CYRILLIC_UPPER_LETTER_N_SR
+ CHARS_CYRILLIC_LOWER_LETTER_N_SR*/
+
+ };
+ for(const NumberingPairs& rNumberingPair : aNumberingPairs)
+ {
+ if( /*sCommand*/sNumber.equalsAscii(rNumberingPair.cWordName ))
+ {
+ nRet = rNumberingPair.nType;
+ break;
+ }
+ }
+
+ }
+ return nRet;
+}
+
+
+static OUString lcl_ParseFormat( const OUString& rCommand )
+{
+ // The command looks like: " DATE \@"dd MMMM yyyy" or "09/02/2014"
+ OUString command;
+ sal_Int32 delimPos = rCommand.indexOf("\\@");
+ if (delimPos != -1)
+ {
+ // Remove whitespace permitted by standard between \@ and "
+ sal_Int32 wsChars = rCommand.indexOf('\"') - delimPos - 2;
+ command = rCommand.replaceAt(delimPos+2, wsChars, u"");
+ return OUString(msfilter::util::findQuotedText(command, "\\@\"", '\"'));
+ }
+
+ return OUString();
+}
+/*-------------------------------------------------------------------------
+extract a parameter (with or without quotes) between the command and the following backslash
+ -----------------------------------------------------------------------*/
+static OUString lcl_ExtractToken(OUString const& rCommand,
+ sal_Int32 & rIndex, bool & rHaveToken, bool & rIsSwitch)
+{
+ rHaveToken = false;
+ rIsSwitch = false;
+
+ OUStringBuffer token;
+ bool bQuoted(false);
+ for (; rIndex < rCommand.getLength(); ++rIndex)
+ {
+ sal_Unicode const currentChar(rCommand[rIndex]);
+ switch (currentChar)
+ {
+ case '\\':
+ {
+ if (rIndex == rCommand.getLength() - 1)
+ {
+ SAL_INFO("writerfilter.dmapper", "field: trailing escape");
+ ++rIndex;
+ return OUString();
+ }
+ sal_Unicode const nextChar(rCommand[rIndex+1]);
+ if (bQuoted || '\\' == nextChar)
+ {
+ ++rIndex; // read 2 chars
+ token.append(nextChar);
+ }
+ else // field switch (case insensitive)
+ {
+ rHaveToken = true;
+ if (token.isEmpty())
+ {
+ rIsSwitch = true;
+ rIndex += 2; // read 2 chars
+ return rCommand.copy(rIndex - 2, 2).toAsciiUpperCase();
+ }
+ else
+ { // leave rIndex, read it again next time
+ return token.makeStringAndClear();
+ }
+ }
+ }
+ break;
+ case '\"':
+ if (bQuoted || !token.isEmpty())
+ {
+ rHaveToken = true;
+ if (bQuoted)
+ {
+ ++rIndex;
+ }
+ return token.makeStringAndClear();
+ }
+ else
+ {
+ bQuoted = true;
+ }
+ break;
+ case ' ':
+ if (bQuoted)
+ {
+ token.append(' ');
+ }
+ else
+ {
+ if (!token.isEmpty())
+ {
+ rHaveToken = true;
+ ++rIndex;
+ return token.makeStringAndClear();
+ }
+ }
+ break;
+ case '=':
+ if (token.isEmpty())
+ {
+ rHaveToken = true;
+ ++rIndex;
+ return "FORMULA";
+ }
+ else
+ token.append('=');
+ break;
+ default:
+ token.append(currentChar);
+ break;
+ }
+ }
+ assert(rIndex == rCommand.getLength());
+ if (bQuoted)
+ {
+ // MS Word allows this, so just emit a debug message
+ SAL_INFO("writerfilter.dmapper",
+ "field argument with unterminated quote");
+ }
+ rHaveToken = !token.isEmpty();
+ return token.makeStringAndClear();
+}
+
+std::tuple<OUString, std::vector<OUString>, std::vector<OUString> > splitFieldCommand(const OUString& rCommand)
+{
+ OUString sType;
+ std::vector<OUString> arguments;
+ std::vector<OUString> switches;
+ sal_Int32 nStartIndex(0);
+ // tdf#54584: Field may be prepended by a backslash
+ // This is not an escapement, but already escaped literal "\"
+ // MS Word allows this, so just skip it
+ if ((rCommand.getLength() >= nStartIndex + 2) &&
+ (rCommand[nStartIndex] == L'\\') &&
+ (rCommand[nStartIndex + 1] != L'\\') &&
+ (rCommand[nStartIndex + 1] != L' '))
+ {
+ ++nStartIndex;
+ }
+
+ do
+ {
+ bool bHaveToken;
+ bool bIsSwitch;
+ OUString const token =
+ lcl_ExtractToken(rCommand, nStartIndex, bHaveToken, bIsSwitch);
+ assert(nStartIndex <= rCommand.getLength());
+ if (bHaveToken)
+ {
+ if (sType.isEmpty())
+ {
+ sType = token.toAsciiUpperCase();
+ }
+ else if (bIsSwitch || !switches.empty())
+ {
+ switches.push_back(token);
+ }
+ else
+ {
+ arguments.push_back(token);
+ }
+ }
+ } while (nStartIndex < rCommand.getLength());
+
+ return std::make_tuple(sType, arguments, switches);
+}
+
+static OUString lcl_ExtractVariableAndHint( std::u16string_view rCommand, OUString& rHint )
+{
+ // the first word after "ASK " is the variable
+ // the text after the variable and before a '\' is the hint
+ // if no hint is set the variable is used as hint
+ // the quotes of the hint have to be removed
+ size_t nIndex = rCommand.find( ' ', 2); //find last space after 'ASK'
+ if (nIndex == std::u16string_view::npos)
+ return OUString();
+ while (nIndex < rCommand.size() && rCommand[nIndex] == ' ')
+ ++nIndex;
+ std::u16string_view sShortCommand( rCommand.substr( nIndex ) ); //cut off the " ASK "
+
+ sShortCommand = o3tl::getToken(sShortCommand, 0, '\\');
+ sal_Int32 nIndex2 = 0;
+ std::u16string_view sRet = o3tl::getToken(sShortCommand, 0, ' ', nIndex2);
+ if( nIndex2 > 0)
+ rHint = sShortCommand.substr( nIndex2 );
+ if( rHint.isEmpty() )
+ rHint = sRet;
+ return OUString(sRet);
+}
+
+
+static bool lcl_FindInCommand(
+ const OUString& rCommand,
+ sal_Unicode cSwitch,
+ OUString& rValue )
+{
+ bool bRet = false;
+ OUString sSearch = "\\" + OUStringChar( cSwitch );
+ sal_Int32 nIndex = rCommand.indexOf( sSearch );
+ if( nIndex >= 0 )
+ {
+ bRet = true;
+ //find next '\' or end of string
+ sal_Int32 nEndIndex = rCommand.indexOf( '\\', nIndex + 1);
+ if( nEndIndex < 0 )
+ nEndIndex = rCommand.getLength() ;
+ if( nEndIndex - nIndex > 3 )
+ rValue = rCommand.copy( nIndex + 3, nEndIndex - nIndex - 3);
+ }
+ return bRet;
+}
+
+static OUString lcl_trim(std::u16string_view sValue)
+{
+ // it seems, all kind of quotation marks are allowed around index type identifiers
+ // TODO apply this on bookmarks, too, if needed
+ return OUString(o3tl::trim(sValue)).replaceAll("\"","").replaceAll(u"“", "").replaceAll(u"â€", "");
+}
+
+/*-------------------------------------------------------------------------
+ extract the number format from the command and apply the resulting number
+ format to the XPropertySet
+ -----------------------------------------------------------------------*/
+void DomainMapper_Impl::SetNumberFormat( const OUString& rCommand,
+ uno::Reference< beans::XPropertySet > const& xPropertySet,
+ bool const bDetectFormat)
+{
+ OUString sFormatString = lcl_ParseFormat( rCommand );
+ // find \h - hijri/luna calendar todo: what about saka/era calendar?
+ bool bHijri = 0 < rCommand.indexOf("\\h ");
+ lang::Locale aUSLocale;
+ aUSLocale.Language = "en";
+ aUSLocale.Country = "US";
+
+ lang::Locale aCurrentLocale;
+ GetAnyProperty(PROP_CHAR_LOCALE, GetTopContext()) >>= aCurrentLocale;
+
+ if (sFormatString.isEmpty())
+ {
+ // No format specified. MS Word uses different formats depending on w:lang,
+ // "M/d/yyyy h:mm:ss AM/PM" for en-US, and "dd/MM/yyyy hh:mm:ss AM/PM" for en-GB.
+ // ALSO SEE: ww8par5's GetWordDefaultDateStringAsUS.
+ sal_Int32 nPos = rCommand.indexOf(" \\");
+ OUString sCommand = nPos == -1 ? rCommand.trim()
+ : OUString(o3tl::trim(rCommand.subView(0, nPos)));
+ if (sCommand == "CREATEDATE" || sCommand == "PRINTDATE" || sCommand == "SAVEDATE")
+ {
+ try
+ {
+ css::uno::Reference<css::i18n::XNumberFormatCode> const& xNumberFormatCode =
+ i18n::NumberFormatMapper::create(m_xComponentContext);
+ sFormatString = xNumberFormatCode->getFormatCode(
+ css::i18n::NumberFormatIndex::DATE_SYSTEM_SHORT, aCurrentLocale).Code;
+ nPos = sFormatString.indexOf("YYYY");
+ if (nPos == -1)
+ sFormatString = sFormatString.replaceFirst("YY", "YYYY");
+ if (aCurrentLocale == aUSLocale)
+ sFormatString += " h:mm:ss AM/PM";
+ else
+ sFormatString += " hh:mm:ss AM/PM";
+ }
+ catch(const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+ }
+ }
+ OUString sFormat = ConversionHelper::ConvertMSFormatStringToSO( sFormatString, aCurrentLocale, bHijri);
+ //get the number formatter and convert the string to a format value
+ try
+ {
+ sal_Int32 nKey = 0;
+ uno::Reference< util::XNumberFormatsSupplier > xNumberSupplier( m_xTextDocument, uno::UNO_QUERY_THROW );
+ if( bDetectFormat )
+ {
+ uno::Reference< util::XNumberFormatter> xFormatter(util::NumberFormatter::create(m_xComponentContext), uno::UNO_QUERY_THROW);
+ xFormatter->attachNumberFormatsSupplier( xNumberSupplier );
+ nKey = xFormatter->detectNumberFormat( 0, rCommand );
+ }
+ else
+ {
+ nKey = xNumberSupplier->getNumberFormats()->addNewConverted( sFormat, aUSLocale, aCurrentLocale );
+ }
+ xPropertySet->setPropertyValue(
+ getPropertyName(PROP_NUMBER_FORMAT),
+ uno::Any( nKey ));
+ }
+ catch(const uno::Exception&)
+ {
+ }
+}
+
+static uno::Any lcl_getGrabBagValue( const uno::Sequence<beans::PropertyValue>& grabBag, OUString const & name )
+{
+ auto pProp = std::find_if(grabBag.begin(), grabBag.end(),
+ [&name](const beans::PropertyValue& rProp) { return rProp.Name == name; });
+ if (pProp != grabBag.end())
+ return pProp->Value;
+ return uno::Any();
+}
+
+//Link the text frames.
+void DomainMapper_Impl::ChainTextFrames()
+{
+ //can't link textboxes if there are not even two of them...
+ if( 2 > m_vTextFramesForChaining.size() )
+ return ;
+
+ struct TextFramesForChaining {
+ css::uno::Reference< css::drawing::XShape > xShape;
+ sal_Int32 nId;
+ sal_Int32 nSeq;
+ OUString s_mso_next_textbox;
+ OUString shapeName;
+ TextFramesForChaining() : nId(0), nSeq(0) {}
+ } ;
+ typedef std::map <OUString, TextFramesForChaining> ChainMap;
+
+ try
+ {
+ ChainMap aTextFramesForChainingHelper;
+ ::std::vector<TextFramesForChaining> chainingWPS;
+ OUString sChainNextName("ChainNextName");
+
+ //learn about ALL of the textboxes and their chaining values first - because frames are processed in no specific order.
+ for( const auto& rTextFrame : m_vTextFramesForChaining )
+ {
+ uno::Reference<text::XTextContent> xTextContent(rTextFrame, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo;
+ if( xPropertySet.is() )
+ xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY);
+
+ TextFramesForChaining aChainStruct;
+ OUString sShapeName;
+ OUString sLinkChainName;
+
+ //The chaining name and the shape name CAN be different in .docx.
+ //MUST use LinkDisplayName/ChainName as the shape name for establishing links.
+ if ( xServiceInfo->supportsService("com.sun.star.text.TextFrame") )
+ {
+ xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
+ xPropertySet->getPropertyValue("LinkDisplayName") >>= sShapeName;
+ }
+ else
+ {
+ xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ xPropertySet->getPropertyValue("ChainName") >>= sShapeName;
+ }
+
+ lcl_getGrabBagValue( aGrabBag, "Txbx-Id") >>= aChainStruct.nId;
+ lcl_getGrabBagValue( aGrabBag, "Txbx-Seq") >>= aChainStruct.nSeq;
+ lcl_getGrabBagValue( aGrabBag, "LinkChainName") >>= sLinkChainName;
+ lcl_getGrabBagValue( aGrabBag, "mso-next-textbox") >>= aChainStruct.s_mso_next_textbox;
+
+ //Sometimes the shape names have not been imported. If not, we may have a fallback name.
+ //Set name later, only if required for linking.
+ aChainStruct.shapeName = sShapeName;
+
+ if (!sLinkChainName.isEmpty())
+ {
+ aChainStruct.xShape = rTextFrame;
+ aTextFramesForChainingHelper[sLinkChainName] = aChainStruct;
+ }
+ if (aChainStruct.s_mso_next_textbox.isEmpty())
+ { // no VML chaining => try to chain DrawingML via IDs
+ aChainStruct.xShape = rTextFrame;
+ if (!sLinkChainName.isEmpty())
+ { // for member of group shapes, TestTdf73499
+ aChainStruct.shapeName = sLinkChainName;
+ }
+ chainingWPS.emplace_back(aChainStruct);
+ }
+ }
+
+ //if mso-next-textbox tags are provided, create those vml-style links first. Afterwards we will make dml-style id/seq links.
+ for (auto& msoItem : aTextFramesForChainingHelper)
+ {
+ //if no mso-next-textbox, we are done.
+ //if it points to itself, we are done.
+ if( !msoItem.second.s_mso_next_textbox.isEmpty()
+ && msoItem.second.s_mso_next_textbox != msoItem.first )
+ {
+ ChainMap::iterator nextFinder=aTextFramesForChainingHelper.find(msoItem.second.s_mso_next_textbox);
+ if( nextFinder != aTextFramesForChainingHelper.end() )
+ {
+ //if the frames have no name yet, then set them. LinkDisplayName / ChainName are read-only.
+ if (msoItem.second.shapeName.isEmpty())
+ {
+ uno::Reference< container::XNamed > xNamed( msoItem.second.xShape, uno::UNO_QUERY );
+ if ( xNamed.is() )
+ {
+ xNamed->setName( msoItem.first );
+ msoItem.second.shapeName = msoItem.first;
+ }
+ }
+ if (nextFinder->second.shapeName.isEmpty())
+ {
+ uno::Reference< container::XNamed > xNamed( nextFinder->second.xShape, uno::UNO_QUERY );
+ if ( xNamed.is() )
+ {
+ xNamed->setName( nextFinder->first );
+ nextFinder->second.shapeName = msoItem.first;
+ }
+ }
+
+ uno::Reference<text::XTextContent> xTextContent(msoItem.second.xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+
+ //The reverse chaining happens automatically, so only one direction needs to be set
+ xPropertySet->setPropertyValue(sChainNextName, uno::Any(nextFinder->second.shapeName));
+
+ //the last item in an mso-next-textbox chain is indistinguishable from id/seq items. Now that it is handled, remove it.
+ if( nextFinder->second.s_mso_next_textbox.isEmpty() )
+ aTextFramesForChainingHelper.erase(nextFinder->first);
+ }
+ }
+ }
+
+ //TODO: Perhaps allow reverse sequences when mso-layout-flow-alt = "bottom-to-top"
+ const sal_Int32 nDirection = 1;
+
+ //Finally - go through and attach the chains based on matching ID and incremented sequence number (dml-style).
+ for (const auto& rOuter : chainingWPS)
+ {
+ for (const auto& rInner : chainingWPS)
+ {
+ if (rInner.nId == rOuter.nId)
+ {
+ if (rInner.nSeq == (rOuter.nSeq + nDirection))
+ {
+ uno::Reference<text::XTextContent> const xTextContent(rOuter.xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+
+ //The reverse chaining happens automatically, so only one direction needs to be set
+ xPropertySet->setPropertyValue(sChainNextName, uno::Any(rInner.shapeName));
+ break ; //there cannot be more than one next frame
+ }
+ }
+ }
+ }
+ m_vTextFramesForChaining.clear(); //clear the vector
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+}
+
+void DomainMapper_Impl::PushTextBoxContent()
+{
+ if (m_bIsInTextBox)
+ return;
+
+ // tdf#154481: check for TOC creation with empty field stack,
+ // and close TOC, unless pages will lost. FIXME.
+ if (IsInTOC() && m_aFieldStack.size() == 0)
+ {
+ m_bStartTOC = false;
+ SAL_WARN("writerfilter.dmapper",
+ "broken TOC creation in textbox, but field stack is empty, so closing TOC!");
+ }
+
+ try
+ {
+ uno::Reference<text::XTextFrame> xTBoxFrame(
+ m_xTextFactory->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XNamed>(xTBoxFrame, uno::UNO_QUERY_THROW)
+ ->setName("textbox" + OUString::number(m_xPendingTextBoxFrames.size() + 1));
+ uno::Reference<text::XTextAppendAndConvert>(m_aTextAppendStack.top().xTextAppend,
+ uno::UNO_QUERY_THROW)
+ ->appendTextContent(xTBoxFrame, beans::PropertyValues());
+ m_xPendingTextBoxFrames.push(xTBoxFrame);
+
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xTBoxFrame, uno::UNO_QUERY_THROW), {}));
+ m_bIsInTextBox = true;
+
+ appendTableManager();
+ appendTableHandler();
+ getTableManager().startLevel();
+ }
+ catch (uno::Exception& e)
+ {
+ SAL_WARN("writerfilter.dmapper", "Exception during creating textbox (" + e.Message + ")!");
+ }
+}
+
+void DomainMapper_Impl::PopTextBoxContent()
+{
+ if (!m_bIsInTextBox || m_xPendingTextBoxFrames.empty())
+ return;
+
+ if (uno::Reference<text::XTextFrame>(m_aTextAppendStack.top().xTextAppend, uno::UNO_QUERY).is())
+ {
+ if (hasTableManager())
+ {
+ getTableManager().endLevel();
+ popTableManager();
+ }
+ RemoveLastParagraph();
+
+ m_aTextAppendStack.pop();
+ m_bIsInTextBox = false;
+ }
+}
+
+void DomainMapper_Impl::AttachTextBoxContentToShape(css::uno::Reference<css::drawing::XShape> xShape)
+{
+ // Without textbox or shape pointless to continue
+ if (m_xPendingTextBoxFrames.empty() || !xShape)
+ return;
+
+ uno::Reference< drawing::XShapes >xGroup(xShape, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet >xProps(xShape, uno::UNO_QUERY);
+
+ // If this is a group go inside
+ if (xGroup)
+ for (sal_Int32 i = 0; i < xGroup->getCount(); ++i)
+ AttachTextBoxContentToShape(
+ uno::Reference<drawing::XShape>(xGroup->getByIndex(i), uno::UNO_QUERY));
+
+ // if this shape has to be a textbox, attach the frame
+ if (!xProps->getPropertyValue("TextBox").get<bool>())
+ return;
+
+ // if this is a textbox there must be a waiting frame
+ auto xTextBox = m_xPendingTextBoxFrames.front();
+ if (!xTextBox)
+ return;
+
+ // Pop the pending frames
+ m_xPendingTextBoxFrames.pop();
+
+ // Attach the textbox to the shape
+ try
+ {
+ xProps->setPropertyValue("TextBoxContent", uno::Any(xTextBox));
+ }
+ catch (...)
+ {
+ SAL_WARN("writerfilter.dmapper", "Exception while trying to attach textboxes!");
+ return;
+ }
+
+ // If attaching is successful, then do the linking
+ try
+ {
+ // Get the name of the textbox
+ OUString sTextBoxName;
+ uno::Reference<container::XNamed> xName(xTextBox, uno::UNO_QUERY);
+ if (xName && !xName->getName().isEmpty())
+ sTextBoxName = xName->getName();
+
+ // Try to get the grabbag
+ uno::Sequence<beans::PropertyValue> aOldGrabBagSeq;
+ if (xProps->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
+ xProps->getPropertyValue("InteropGrabBag") >>= aOldGrabBagSeq;
+
+ // If the grabbag successfully get...
+ if (!aOldGrabBagSeq.hasElements())
+ return;
+
+ // Check for the existing linking information
+ bool bSuccess = false;
+ beans::PropertyValues aNewGrabBagSeq;
+ const auto& aHasLink = lcl_getGrabBagValue(aOldGrabBagSeq, "TxbxHasLink");
+
+ // If there must be a link, do it
+ if (aHasLink.hasValue() && aHasLink.get<bool>())
+ {
+ auto aLinkProp = comphelper::makePropertyValue("LinkChainName", sTextBoxName);
+ for (sal_uInt32 i = 0; i < aOldGrabBagSeq.size(); ++i)
+ {
+ aNewGrabBagSeq.realloc(i + 1);
+ // If this is the link name replace it
+ if (!aOldGrabBagSeq[i].Name.isEmpty() && !aLinkProp.Name.isEmpty()
+ && (aOldGrabBagSeq[i].Name == aLinkProp.Name))
+ {
+ aNewGrabBagSeq.getArray()[i] = aLinkProp;
+ bSuccess = true;
+ }
+ // else copy
+ else
+ aNewGrabBagSeq.getArray()[i] = aOldGrabBagSeq[i];
+ }
+
+ // If there was no replacement, append the linking data
+ if (!bSuccess)
+ {
+ aNewGrabBagSeq.realloc(aNewGrabBagSeq.size() + 1);
+ aNewGrabBagSeq.getArray()[aNewGrabBagSeq.size() - 1] = aLinkProp;
+ bSuccess = true;
+ }
+ }
+
+ // If the linking changed the grabbag, apply the modifications
+ if (aNewGrabBagSeq.hasElements() && bSuccess)
+ {
+ xProps->setPropertyValue("InteropGrabBag", uno::Any(aNewGrabBagSeq));
+ m_vTextFramesForChaining.push_back(xShape);
+ }
+ }
+ catch (...)
+ {
+ SAL_WARN("writerfilter.dmapper", "Exception while trying to link textboxes!");
+ }
+}
+
+uno::Reference<beans::XPropertySet> DomainMapper_Impl::FindOrCreateFieldMaster(const char* pFieldMasterService, const OUString& rFieldMasterName)
+{
+ // query master, create if not available
+ uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
+ uno::Reference< beans::XPropertySet > xMaster;
+ OUString sFieldMasterService( OUString::createFromAscii(pFieldMasterService) );
+ OUStringBuffer aFieldMasterName;
+ OUString sDatabaseDataSourceName = GetSettingsTable()->GetCurrentDatabaseDataSource();
+ bool bIsMergeField = sFieldMasterService.endsWith("Database");
+ aFieldMasterName.appendAscii( pFieldMasterService );
+ aFieldMasterName.append('.');
+ if ( bIsMergeField && !sDatabaseDataSourceName.isEmpty() )
+ {
+ aFieldMasterName.append(sDatabaseDataSourceName);
+ aFieldMasterName.append('.');
+ }
+ aFieldMasterName.append(rFieldMasterName);
+ OUString sFieldMasterName = aFieldMasterName.makeStringAndClear();
+ if(xFieldMasterAccess->hasByName(sFieldMasterName))
+ {
+ //get the master
+ xMaster.set(xFieldMasterAccess->getByName(sFieldMasterName), uno::UNO_QUERY_THROW);
+ }
+ else if( m_xTextFactory.is() )
+ {
+ //create the master
+ xMaster.set( m_xTextFactory->createInstance(sFieldMasterService), uno::UNO_QUERY_THROW);
+ if ( !bIsMergeField || sDatabaseDataSourceName.isEmpty() )
+ {
+ //set the master's name
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_NAME),
+ uno::Any(rFieldMasterName));
+ } else {
+ // set database data, based on the "databasename.tablename" of sDatabaseDataSourceName
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_DATABASE_NAME),
+ uno::Any(sDatabaseDataSourceName.copy(0, sDatabaseDataSourceName.indexOf('.'))));
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_COMMAND_TYPE),
+ uno::Any(sal_Int32(0)));
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_DATATABLE_NAME),
+ uno::Any(sDatabaseDataSourceName.copy(sDatabaseDataSourceName.indexOf('.') + 1)));
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_DATACOLUMN_NAME),
+ uno::Any(rFieldMasterName));
+ }
+ }
+ return xMaster;
+}
+
+void DomainMapper_Impl::PushFieldContext()
+{
+ m_bParaHadField = true;
+ if(m_bDiscardHeaderFooter)
+ return;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("pushFieldContext");
+#endif
+
+ uno::Reference<text::XTextCursor> xCrsr;
+ if (!m_aTextAppendStack.empty())
+ {
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is())
+ xCrsr = xTextAppend->createTextCursorByRange(
+ m_aTextAppendStack.top().xInsertPosition.is()
+ ? m_aTextAppendStack.top().xInsertPosition
+ : xTextAppend->getEnd());
+ }
+
+ uno::Reference< text::XTextRange > xStart;
+ if (xCrsr.is())
+ xStart = xCrsr->getStart();
+ m_aFieldStack.push_back(new FieldContext(xStart));
+}
+/*-------------------------------------------------------------------------
+//the current field context waits for the completion of the command
+ -----------------------------------------------------------------------*/
+bool DomainMapper_Impl::IsOpenFieldCommand() const
+{
+ return !m_aFieldStack.empty() && !m_aFieldStack.back()->IsCommandCompleted();
+}
+/*-------------------------------------------------------------------------
+//the current field context waits for the completion of the command
+ -----------------------------------------------------------------------*/
+bool DomainMapper_Impl::IsOpenField() const
+{
+ return !m_aFieldStack.empty();
+}
+
+// Mark top field context as containing a fixed field
+void DomainMapper_Impl::SetFieldLocked()
+{
+ if (IsOpenField())
+ m_aFieldStack.back()->SetFieldLocked();
+}
+
+HeaderFooterContext::HeaderFooterContext(bool bTextInserted, sal_Int32 nTableDepth)
+ : m_bTextInserted(bTextInserted)
+ , m_nTableDepth(nTableDepth)
+{
+}
+
+bool HeaderFooterContext::getTextInserted() const
+{
+ return m_bTextInserted;
+}
+
+sal_Int32 HeaderFooterContext::getTableDepth() const { return m_nTableDepth; }
+
+FieldContext::FieldContext(uno::Reference< text::XTextRange > const& xStart)
+ : m_bFieldCommandCompleted(false)
+ , m_xStartRange( xStart )
+ , m_bFieldLocked( false )
+{
+ m_pProperties = new PropertyMap();
+}
+
+
+FieldContext::~FieldContext()
+{
+}
+
+void FieldContext::SetTextField(uno::Reference<text::XTextField> const& xTextField)
+{
+#ifndef NDEBUG
+ if (xTextField.is())
+ {
+ uno::Reference<lang::XServiceInfo> const xServiceInfo(xTextField, uno::UNO_QUERY);
+ assert(xServiceInfo.is());
+ // those must be set by SetFormField()
+ assert(!xServiceInfo->supportsService("com.sun.star.text.Fieldmark")
+ && !xServiceInfo->supportsService("com.sun.star.text.FormFieldmark"));
+ }
+#endif
+ m_xTextField = xTextField;
+}
+
+void FieldContext::CacheVariableValue(const uno::Any& rAny)
+{
+ rAny >>= m_sVariableValue;
+}
+
+void FieldContext::AppendCommand(std::u16string_view rPart)
+{
+ m_sCommand += rPart;
+}
+
+::std::vector<OUString> FieldContext::GetCommandParts() const
+{
+ ::std::vector<OUString> aResult;
+ sal_Int32 nIndex = 0;
+ bool bInString = false;
+ OUString sPart;
+ while (nIndex != -1)
+ {
+ OUString sToken = GetCommand().getToken(0, ' ', nIndex);
+ bool bInStringNext = bInString;
+
+ if (sToken.isEmpty())
+ continue;
+
+ if (sToken[0] == '"')
+ {
+ bInStringNext = true;
+ sToken = sToken.copy(1);
+ }
+ if (sToken.endsWith("\""))
+ {
+ bInStringNext = false;
+ sToken = sToken.copy(0, sToken.getLength() - 1);
+ }
+
+ if (bInString)
+ {
+ sPart += " " + sToken;
+ if (!bInStringNext)
+ {
+ aResult.push_back(sPart);
+ }
+ }
+ else
+ {
+ if (bInStringNext)
+ {
+ sPart = sToken;
+ }
+ else
+ {
+ aResult.push_back(sToken);
+ }
+ }
+
+ bInString = bInStringNext;
+ }
+
+ return aResult;
+}
+
+/*-------------------------------------------------------------------------
+//collect the pieces of the command
+ -----------------------------------------------------------------------*/
+void DomainMapper_Impl::AppendFieldCommand(OUString const & rPartOfCommand)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("appendFieldCommand");
+ TagLogger::getInstance().chars(rPartOfCommand);
+ TagLogger::getInstance().endElement();
+#endif
+
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( pContext )
+ {
+ pContext->AppendCommand( rPartOfCommand );
+ }
+}
+
+
+typedef std::multimap < sal_Int32, OUString > TOCStyleMap;
+
+
+static ww::eField GetWW8FieldId(OUString const& rType)
+{
+ std::unordered_map<OUString, ww::eField> mapID
+ {
+ {"ADDRESSBLOCK", ww::eADDRESSBLOCK},
+ {"ADVANCE", ww::eADVANCE},
+ {"ASK", ww::eASK},
+ {"AUTONUM", ww::eAUTONUM},
+ {"AUTONUMLGL", ww::eAUTONUMLGL},
+ {"AUTONUMOUT", ww::eAUTONUMOUT},
+ {"AUTOTEXT", ww::eAUTOTEXT},
+ {"AUTOTEXTLIST", ww::eAUTOTEXTLIST},
+ {"AUTHOR", ww::eAUTHOR},
+ {"BARCODE", ww::eBARCODE},
+ {"BIDIOUTLINE", ww::eBIDIOUTLINE},
+ {"DATE", ww::eDATE},
+ {"COMMENTS", ww::eCOMMENTS},
+ {"COMPARE", ww::eCOMPARE},
+ {"CONTROL", ww::eCONTROL},
+ {"CREATEDATE", ww::eCREATEDATE},
+ {"DATABASE", ww::eDATABASE},
+ {"DDEAUTOREF", ww::eDDEAUTOREF},
+ {"DDEREF", ww::eDDEREF},
+ {"DOCPROPERTY", ww::eDOCPROPERTY},
+ {"DOCVARIABLE", ww::eDOCVARIABLE},
+ {"EDITTIME", ww::eEDITTIME},
+ {"EMBED", ww::eEMBED},
+ {"EQ", ww::eEQ},
+ {"FILLIN", ww::eFILLIN},
+ {"FILENAME", ww::eFILENAME},
+ {"FILESIZE", ww::eFILESIZE},
+ {"FOOTREF", ww::eFOOTREF},
+// {"FORMULA", ww::},
+ {"FORMCHECKBOX", ww::eFORMCHECKBOX},
+ {"FORMDROPDOWN", ww::eFORMDROPDOWN},
+ {"FORMTEXT", ww::eFORMTEXT},
+ {"GLOSSREF", ww::eGLOSSREF},
+ {"GOTOBUTTON", ww::eGOTOBUTTON},
+ {"GREETINGLINE", ww::eGREETINGLINE},
+ {"HTMLCONTROL", ww::eHTMLCONTROL},
+ {"HYPERLINK", ww::eHYPERLINK},
+ {"IF", ww::eIF},
+ {"INFO", ww::eINFO},
+ {"INCLUDEPICTURE", ww::eINCLUDEPICTURE},
+ {"INCLUDETEXT", ww::eINCLUDETEXT},
+ {"INCLUDETIFF", ww::eINCLUDETIFF},
+ {"KEYWORDS", ww::eKEYWORDS},
+ {"LASTSAVEDBY", ww::eLASTSAVEDBY},
+ {"LINK", ww::eLINK},
+ {"LISTNUM", ww::eLISTNUM},
+ {"MACRO", ww::eMACRO},
+ {"MACROBUTTON", ww::eMACROBUTTON},
+ {"MERGEDATA", ww::eMERGEDATA},
+ {"MERGEFIELD", ww::eMERGEFIELD},
+ {"MERGEINC", ww::eMERGEINC},
+ {"MERGEREC", ww::eMERGEREC},
+ {"MERGESEQ", ww::eMERGESEQ},
+ {"NEXT", ww::eNEXT},
+ {"NEXTIF", ww::eNEXTIF},
+ {"NOTEREF", ww::eNOTEREF},
+ {"PAGE", ww::ePAGE},
+ {"PAGEREF", ww::ePAGEREF},
+ {"PLUGIN", ww::ePLUGIN},
+ {"PRINT", ww::ePRINT},
+ {"PRINTDATE", ww::ePRINTDATE},
+ {"PRIVATE", ww::ePRIVATE},
+ {"QUOTE", ww::eQUOTE},
+ {"RD", ww::eRD},
+ {"REF", ww::eREF},
+ {"REVNUM", ww::eREVNUM},
+ {"SAVEDATE", ww::eSAVEDATE},
+ {"SECTION", ww::eSECTION},
+ {"SECTIONPAGES", ww::eSECTIONPAGES},
+ {"SEQ", ww::eSEQ},
+ {"SET", ww::eSET},
+ {"SKIPIF", ww::eSKIPIF},
+ {"STYLEREF", ww::eSTYLEREF},
+ {"SUBSCRIBER", ww::eSUBSCRIBER},
+ {"SUBJECT", ww::eSUBJECT},
+ {"SYMBOL", ww::eSYMBOL},
+ {"TA", ww::eTA},
+ {"TEMPLATE", ww::eTEMPLATE},
+ {"TIME", ww::eTIME},
+ {"TITLE", ww::eTITLE},
+ {"TOA", ww::eTOA},
+ {"USERINITIALS", ww::eUSERINITIALS},
+ {"USERADDRESS", ww::eUSERADDRESS},
+ {"USERNAME", ww::eUSERNAME},
+
+ {"TOC", ww::eTOC},
+ {"TC", ww::eTC},
+ {"NUMCHARS", ww::eNUMCHARS},
+ {"NUMWORDS", ww::eNUMWORDS},
+ {"NUMPAGES", ww::eNUMPAGES},
+ {"INDEX", ww::eINDEX},
+ {"XE", ww::eXE},
+ {"BIBLIOGRAPHY", ww::eBIBLIOGRAPHY},
+ {"CITATION", ww::eCITATION},
+ };
+ auto const it = mapID.find(rType);
+ return (it == mapID.end()) ? ww::eNONE : it->second;
+}
+
+static const FieldConversionMap_t & lcl_GetFieldConversion()
+{
+ static const FieldConversionMap_t aFieldConversionMap
+ {
+// {"ADDRESSBLOCK", {"", FIELD_ADDRESSBLOCK }},
+// {"ADVANCE", {"", FIELD_ADVANCE }},
+ {"ASK", {"SetExpression", FIELD_ASK }},
+ {"AUTONUM", {"SetExpression", FIELD_AUTONUM }},
+ {"AUTONUMLGL", {"SetExpression", FIELD_AUTONUMLGL }},
+ {"AUTONUMOUT", {"SetExpression", FIELD_AUTONUMOUT }},
+ {"AUTHOR", {"DocInfo.CreateAuthor", FIELD_AUTHOR }},
+ {"DATE", {"DateTime", FIELD_DATE }},
+ {"COMMENTS", {"DocInfo.Description", FIELD_COMMENTS }},
+ {"CREATEDATE", {"DocInfo.CreateDateTime", FIELD_CREATEDATE }},
+ {"DOCPROPERTY", {"", FIELD_DOCPROPERTY }},
+ {"DOCVARIABLE", {"User", FIELD_DOCVARIABLE }},
+ {"EDITTIME", {"DocInfo.EditTime", FIELD_EDITTIME }},
+ {"EQ", {"", FIELD_EQ }},
+ {"FILLIN", {"Input", FIELD_FILLIN }},
+ {"FILENAME", {"FileName", FIELD_FILENAME }},
+// {"FILESIZE", {"", FIELD_FILESIZE }},
+ {"FORMULA", {"TableFormula", FIELD_FORMULA }},
+ {"FORMCHECKBOX", {"", FIELD_FORMCHECKBOX }},
+ {"FORMDROPDOWN", {"DropDown", FIELD_FORMDROPDOWN }},
+ {"FORMTEXT", {"Input", FIELD_FORMTEXT }},
+ {"GOTOBUTTON", {"", FIELD_GOTOBUTTON }},
+ {"HYPERLINK", {"", FIELD_HYPERLINK }},
+ {"IF", {"ConditionalText", FIELD_IF }},
+// {"INFO", {"", FIELD_INFO }},
+ {"INCLUDEPICTURE", {"", FIELD_INCLUDEPICTURE}},
+ {"KEYWORDS", {"DocInfo.KeyWords", FIELD_KEYWORDS }},
+ {"LASTSAVEDBY", {"DocInfo.ChangeAuthor", FIELD_LASTSAVEDBY }},
+ {"MACROBUTTON", {"Macro", FIELD_MACROBUTTON }},
+ {"MERGEFIELD", {"Database", FIELD_MERGEFIELD }},
+ {"MERGEREC", {"DatabaseNumberOfSet", FIELD_MERGEREC }},
+// {"MERGESEQ", {"", FIELD_MERGESEQ }},
+ {"NEXT", {"DatabaseNextSet", FIELD_NEXT }},
+ {"NEXTIF", {"DatabaseNextSet", FIELD_NEXTIF }},
+ {"PAGE", {"PageNumber", FIELD_PAGE }},
+ {"PAGEREF", {"GetReference", FIELD_PAGEREF }},
+ {"PRINTDATE", {"DocInfo.PrintDateTime", FIELD_PRINTDATE }},
+ {"REF", {"GetReference", FIELD_REF }},
+ {"REVNUM", {"DocInfo.Revision", FIELD_REVNUM }},
+ {"SAVEDATE", {"DocInfo.ChangeDateTime", FIELD_SAVEDATE }},
+// {"SECTION", {"", FIELD_SECTION }},
+// {"SECTIONPAGES", {"", FIELD_SECTIONPAGES }},
+ {"SEQ", {"SetExpression", FIELD_SEQ }},
+ {"SET", {"SetExpression", FIELD_SET }},
+// {"SKIPIF", {"", FIELD_SKIPIF }},
+// {"STYLEREF", {"", FIELD_STYLEREF }},
+ {"SUBJECT", {"DocInfo.Subject", FIELD_SUBJECT }},
+ {"SYMBOL", {"", FIELD_SYMBOL }},
+ {"TEMPLATE", {"TemplateName", FIELD_TEMPLATE }},
+ {"TIME", {"DateTime", FIELD_TIME }},
+ {"TITLE", {"DocInfo.Title", FIELD_TITLE }},
+ {"USERINITIALS", {"Author", FIELD_USERINITIALS }},
+// {"USERADDRESS", {"", FIELD_USERADDRESS }},
+ {"USERNAME", {"Author", FIELD_USERNAME }},
+
+
+ {"TOC", {"com.sun.star.text.ContentIndex", FIELD_TOC }},
+ {"TC", {"com.sun.star.text.ContentIndexMark", FIELD_TC }},
+ {"NUMCHARS", {"CharacterCount", FIELD_NUMCHARS }},
+ {"NUMWORDS", {"WordCount", FIELD_NUMWORDS }},
+ {"NUMPAGES", {"PageCount", FIELD_NUMPAGES }},
+ {"INDEX", {"com.sun.star.text.DocumentIndex", FIELD_INDEX }},
+ {"XE", {"com.sun.star.text.DocumentIndexMark", FIELD_XE }},
+ {"BIBLIOGRAPHY",{"com.sun.star.text.Bibliography", FIELD_BIBLIOGRAPHY }},
+ {"CITATION", {"com.sun.star.text.TextField.Bibliography",FIELD_CITATION }},
+ };
+
+ return aFieldConversionMap;
+}
+
+static const FieldConversionMap_t & lcl_GetEnhancedFieldConversion()
+{
+ static const FieldConversionMap_t aEnhancedFieldConversionMap =
+ {
+ {"FORMCHECKBOX", {"FormFieldmark", FIELD_FORMCHECKBOX}},
+ {"FORMDROPDOWN", {"FormFieldmark", FIELD_FORMDROPDOWN}},
+ {"FORMTEXT", {"Fieldmark", FIELD_FORMTEXT}},
+ };
+
+ return aEnhancedFieldConversionMap;
+}
+
+void DomainMapper_Impl::handleFieldSet
+ (const FieldContextPtr& pContext,
+ uno::Reference< uno::XInterface > const & xFieldInterface,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ OUString sVariable, sHint;
+
+ sVariable = lcl_ExtractVariableAndHint(pContext->GetCommand(), sHint);
+
+ // remove surrounding "" if exists
+ if(sHint.getLength() >= 2)
+ {
+ std::u16string_view sTmp = o3tl::trim(sHint);
+ if (o3tl::starts_with(sTmp, u"\"") && o3tl::ends_with(sTmp, u"\""))
+ {
+ sHint = sTmp.substr(1, sTmp.size() - 2);
+ }
+ }
+
+ // determine field master name
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster
+ ("com.sun.star.text.FieldMaster.SetExpression", sVariable);
+
+ // a set field is a string
+ xMaster->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField
+ ( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+
+ uno::Any aAnyHint(sHint);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_HINT), aAnyHint);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), aAnyHint);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+
+ // Mimic MS Word behavior (hide the SET)
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::Any(false));
+}
+
+void DomainMapper_Impl::handleFieldAsk
+ (const FieldContextPtr& pContext,
+ uno::Reference< uno::XInterface > & xFieldInterface,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ //doesn the command contain a variable name?
+ OUString sVariable, sHint;
+
+ sVariable = lcl_ExtractVariableAndHint( pContext->GetCommand(),
+ sHint );
+ if(!sVariable.isEmpty())
+ {
+ // determine field master name
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster
+ ("com.sun.star.text.FieldMaster.SetExpression", sVariable );
+ // An ASK field is always a string of characters
+ xMaster->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField
+ ( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+
+ // set input flag at the field
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_INPUT), uno::Any( true ));
+ // set the prompt
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_HINT),
+ uno::Any( sHint ));
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+ // The ASK has no field value to display
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::Any(false));
+ }
+ else
+ {
+ //don't insert the field
+ //todo: maybe import a 'normal' input field here?
+ xFieldInterface = nullptr;
+ }
+}
+
+/**
+ * Converts a Microsoft Word field formula into LibreOffice syntax
+ * @param input The Microsoft Word field formula, with no leading '=' sign
+ * @return An equivalent LibreOffice field formula
+ */
+OUString DomainMapper_Impl::convertFieldFormula(const OUString& input) {
+
+ if (!m_pSettingsTable)
+ {
+ return input;
+ }
+
+ OUString listSeparator = m_pSettingsTable->GetListSeparator();
+
+ /* Replace logical condition functions with LO equivalent operators */
+ OUString changed = input.replaceAll(" <> ", " NEQ ");
+ changed = changed.replaceAll(" <= ", " LEQ ");
+ changed = changed.replaceAll(" >= ", " GEQ ");
+ changed = changed.replaceAll(" = " , " EQ ");
+ changed = changed.replaceAll(" < " , " L ");
+ changed = changed.replaceAll(" > " , " G ");
+
+ changed = changed.replaceAll("<>", " NEQ ");
+ changed = changed.replaceAll("<=", " LEQ ");
+ changed = changed.replaceAll(">=", " GEQ ");
+ changed = changed.replaceAll("=" , " EQ ");
+ changed = changed.replaceAll("<" , " L ");
+ changed = changed.replaceAll(">" , " G ");
+
+ /* Replace function calls with infix keywords for AND(), OR(), and ROUND(). Nothing needs to be
+ * done for NOT(). This simple regex will work properly with most common cases. However, it may
+ * not work correctly when the arguments are nested subcalls to other functions, like
+ * ROUND(MIN(1,2),MAX(3,4)). See TDF#134765. */
+ icu::ErrorCode status;
+ icu::UnicodeString usInput(changed.getStr());
+ const uint32_t rMatcherFlags = UREGEX_CASE_INSENSITIVE;
+ OUString regex = "\\b(AND|OR|ROUND)\\s*\\(\\s*([^" + listSeparator + "]+)\\s*" + listSeparator + "\\s*([^)]+)\\s*\\)";
+ icu::UnicodeString usRegex(regex.getStr());
+ icu::RegexMatcher rmatch1(usRegex, usInput, rMatcherFlags, status);
+ usInput = rmatch1.replaceAll(icu::UnicodeString("(($2) $1 ($3))"), status);
+
+ /* Assumes any remaining list separators separate arguments to functions that accept lists
+ * (SUM, MIN, MAX, MEAN, etc.) */
+ usInput.findAndReplace(icu::UnicodeString(listSeparator.getStr()), "|");
+
+ /* Surround single cell references with angle brackets.
+ * If there is ever added a function name that ends with a digit, this regex will need to be revisited. */
+ icu::RegexMatcher rmatch2("\\b([A-Z]{1,3}[0-9]+)\\b(?![(])", usInput, rMatcherFlags, status);
+ usInput = rmatch2.replaceAll(icu::UnicodeString("<$1>"), status);
+
+ /* Cell references must be upper case
+ * TODO: convert reference to other tables, e.g. SUM(Table1 A1:B2), where "Table1" is a bookmark of the table,
+ * TODO: also column range A:A */
+ icu::RegexMatcher rmatch3("(<[a-z]{1,3}[0-9]+>|\\b(above|below|left|right)\\b)", usInput, rMatcherFlags, status);
+ icu::UnicodeString replacedCellRefs;
+ while (rmatch3.find(status) && status.isSuccess()) {
+ rmatch3.appendReplacement(replacedCellRefs, rmatch3.group(status).toUpper(), status);
+ }
+ rmatch3.appendTail(replacedCellRefs);
+
+ /* Fix up cell ranges */
+ icu::RegexMatcher rmatch4("<([A-Z]{1,3}[0-9]+)>:<([A-Z]{1,3}[0-9]+)>", replacedCellRefs, rMatcherFlags, status);
+ usInput = rmatch4.replaceAll(icu::UnicodeString("<$1:$2>"), status);
+
+ /* Fix up user defined names */
+ icu::RegexMatcher rmatch5("\\bDEFINED\\s*\\(<([A-Z]+[0-9]+)>\\)", usInput, rMatcherFlags, status);
+ usInput = rmatch5.replaceAll(icu::UnicodeString("DEFINED($1)"), status);
+
+ /* Prepare replace of ABOVE/BELOW/LEFT/RIGHT by adding spaces around them */
+ icu::RegexMatcher rmatch6("\\b(ABOVE|BELOW|LEFT|RIGHT)\\b", usInput, rMatcherFlags, status);
+ usInput = rmatch6.replaceAll(icu::UnicodeString(" $1 "), status);
+
+ /* DOCX allows to set decimal symbol independently from the locale of the document, so if
+ * needed, convert decimal comma to get working formula in a document language (locale),
+ * which doesn't use decimal comma */
+ if ( m_pSettingsTable->GetDecimalSymbol() == "," && !m_bIsDecimalComma )
+ {
+ icu::RegexMatcher rmatch7("\\b([0-9]+),([0-9]+([eE][-]?[0-9]+)?)\\b", usInput, rMatcherFlags, status);
+ usInput = rmatch7.replaceAll(icu::UnicodeString("$1.$2"), status);
+ }
+
+ return OUString(usInput.getTerminatedBuffer());
+}
+
+void DomainMapper_Impl::handleFieldFormula
+ (const FieldContextPtr& pContext,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ OUString command = pContext->GetCommand().trim();
+
+ // Remove number formatting from \# to end of command
+ // TODO: handle custom number formatting
+ sal_Int32 delimPos = command.indexOf("\\#");
+ if (delimPos != -1)
+ {
+ command = command.replaceAt(delimPos, command.getLength() - delimPos, u"").trim();
+ }
+
+ // command must contains = and at least another char
+ if (command.getLength() < 2)
+ return;
+
+ // we don't copy the = symbol from the command
+ OUString formula = convertFieldFormula(command.copy(1));
+
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::Any(formula));
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_NUMBER_FORMAT), uno::Any(sal_Int32(0)));
+ xFieldProperties->setPropertyValue("IsShowFormula", uno::Any(false));
+
+ // grab-bag the original and converted formula
+ if (hasTableManager())
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_CELL_FORMULA, uno::Any(command.copy(1)), true, CELL_GRAB_BAG);
+ pPropMap->Insert(PROP_CELL_FORMULA_CONVERTED, uno::Any(formula), true, CELL_GRAB_BAG);
+ getTableManager().cellProps(pPropMap);
+ }
+}
+
+void DomainMapper_Impl::handleRubyEQField( const FieldContextPtr& pContext)
+{
+ const OUString & rCommand(pContext->GetCommand());
+ sal_Int32 nIndex = 0, nEnd = 0;
+ RubyInfo aInfo ;
+ nIndex = rCommand.indexOf("\\* jc" );
+ if (nIndex != -1)
+ {
+ nIndex += 5;
+ sal_uInt32 nJc = o3tl::toInt32(o3tl::getToken(rCommand, 0, ' ',nIndex));
+ const sal_Int32 aRubyAlignValues[] =
+ {
+ NS_ooxml::LN_Value_ST_RubyAlign_center,
+ NS_ooxml::LN_Value_ST_RubyAlign_distributeLetter,
+ NS_ooxml::LN_Value_ST_RubyAlign_distributeSpace,
+ NS_ooxml::LN_Value_ST_RubyAlign_left,
+ NS_ooxml::LN_Value_ST_RubyAlign_right,
+ NS_ooxml::LN_Value_ST_RubyAlign_rightVertical,
+ };
+ aInfo.nRubyAlign = aRubyAlignValues[(nJc<SAL_N_ELEMENTS(aRubyAlignValues))?nJc:0];
+ }
+
+ // we don't parse or use the font field in rCommand
+
+ nIndex = rCommand.indexOf("\\* hps" );
+ if (nIndex != -1)
+ {
+ nIndex += 6;
+ aInfo.nHps = o3tl::toInt32(o3tl::getToken(rCommand, 0, ' ',nIndex));
+ }
+
+ nIndex = rCommand.indexOf("\\o");
+ if (nIndex == -1)
+ return;
+ nIndex = rCommand.indexOf('(', nIndex);
+ if (nIndex == -1)
+ return;
+ nEnd = rCommand.lastIndexOf(')');
+ if (nEnd == -1)
+ return;
+ if (nEnd <= nIndex)
+ return;
+
+ std::u16string_view sRubyParts = rCommand.subView(nIndex+1,nEnd-nIndex-1);
+ nIndex = 0;
+ std::u16string_view sPart1 = o3tl::getToken(sRubyParts, 0, ',', nIndex);
+ std::u16string_view sPart2 = o3tl::getToken(sRubyParts, 0, ',', nIndex);
+ size_t nIndex2 = 0;
+ size_t nEnd2 = 0;
+ if ((nIndex2 = sPart1.find('(')) != std::u16string_view::npos && (nEnd2 = sPart1.rfind(')')) != std::u16string_view::npos && nEnd2 > nIndex2)
+ {
+ aInfo.sRubyText = sPart1.substr(nIndex2+1,nEnd2-nIndex2-1);
+ }
+
+ PropertyMapPtr pRubyContext(new PropertyMap());
+ pRubyContext->InsertProps(GetTopContext());
+ if (aInfo.nHps > 0)
+ {
+ double fVal = double(aInfo.nHps) / 2.;
+ uno::Any aVal( fVal );
+
+ pRubyContext->Insert(PROP_CHAR_HEIGHT, aVal);
+ pRubyContext->Insert(PROP_CHAR_HEIGHT_ASIAN, aVal);
+ }
+ PropertyValueVector_t aProps = comphelper::sequenceToContainer< PropertyValueVector_t >(pRubyContext->GetPropertyValues());
+ aInfo.sRubyStyle = m_rDMapper.getOrCreateCharStyle(aProps, /*bAlwaysCreate=*/false);
+ PropertyMapPtr pCharContext(new PropertyMap());
+ if (m_pLastCharacterContext)
+ pCharContext->InsertProps(m_pLastCharacterContext);
+ pCharContext->InsertProps(pContext->getProperties());
+ pCharContext->Insert(PROP_RUBY_TEXT, uno::Any( aInfo.sRubyText ) );
+ pCharContext->Insert(PROP_RUBY_ADJUST, uno::Any(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign))));
+ if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical )
+ pCharContext->Insert(PROP_RUBY_POSITION, uno::Any(css::text::RubyPosition::INTER_CHARACTER));
+ pCharContext->Insert(PROP_RUBY_STYLE, uno::Any(aInfo.sRubyStyle));
+ appendTextPortion(OUString(sPart2), pCharContext);
+
+}
+
+void DomainMapper_Impl::handleAutoNum
+ (const FieldContextPtr& pContext,
+ uno::Reference< uno::XInterface > const & xFieldInterface,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ //create a sequence field master "AutoNr"
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster
+ ("com.sun.star.text.FieldMaster.SetExpression",
+ "AutoNr");
+
+ xMaster->setPropertyValue( getPropertyName(PROP_SUB_TYPE),
+ uno::Any(text::SetVariableType::SEQUENCE));
+
+ //apply the numbering type
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField
+ ( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+}
+
+void DomainMapper_Impl::handleAuthor
+ (std::u16string_view,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties,
+ FieldId eFieldId )
+{
+ if (eFieldId == FIELD_USERNAME)
+ xFieldProperties->setPropertyValue
+ ( getPropertyName(PROP_FULL_NAME), uno::Any( true ));
+
+ // Always set as FIXED b/c MS Word only updates these fields via user intervention (F9)
+ // AUTHOR of course never changes and USERNAME is easily mis-used as an original author field.
+ // Additionally, this was forced as fixed if any special case-formatting was provided.
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ),
+ uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+}
+
+ void DomainMapper_Impl::handleDocProperty
+ (const FieldContextPtr& pContext,
+ OUString const& rFirstParam,
+ uno::Reference< uno::XInterface > & xFieldInterface)
+{
+ //some docproperties should be imported as document statistic fields, some as DocInfo fields
+ //others should be user fields
+ if (rFirstParam.isEmpty())
+ return;
+
+ constexpr sal_uInt8 SET_ARABIC = 0x01;
+ constexpr sal_uInt8 SET_DATE = 0x04;
+ struct DocPropertyMap
+ {
+ const char* pDocPropertyName;
+ const char* pServiceName;
+ sal_uInt8 nFlags;
+ };
+ static const DocPropertyMap aDocProperties[] =
+ {
+ {"CreateTime", "DocInfo.CreateDateTime", SET_DATE},
+ {"Characters", "CharacterCount", SET_ARABIC},
+ {"Comments", "DocInfo.Description", 0},
+ {"Keywords", "DocInfo.KeyWords", 0},
+ {"LastPrinted", "DocInfo.PrintDateTime", 0},
+ {"LastSavedBy", "DocInfo.ChangeAuthor", 0},
+ {"LastSavedTime", "DocInfo.ChangeDateTime", SET_DATE},
+ {"Paragraphs", "ParagraphCount", SET_ARABIC},
+ {"RevisionNumber", "DocInfo.Revision", 0},
+ {"Subject", "DocInfo.Subject", 0},
+ {"Template", "TemplateName", 0},
+ {"Title", "DocInfo.Title", 0},
+ {"TotalEditingTime", "DocInfo.EditTime", 0},
+ {"Words", "WordCount", SET_ARABIC}
+
+ //other available DocProperties:
+ //Bytes, Category, CharactersWithSpaces, Company
+ //HyperlinkBase,
+ //Lines, Manager, NameofApplication, ODMADocId, Pages,
+ //Security,
+ };
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(m_xTextDocument, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+ uno::Reference<beans::XPropertySet> xUserDefinedProps(xDocumentProperties->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xUserDefinedProps->getPropertySetInfo();
+ //search for a field mapping
+ OUString sFieldServiceName;
+ size_t nMap = 0;
+ if (!xPropertySetInfo->hasPropertyByName(rFirstParam))
+ {
+ for( ; nMap < SAL_N_ELEMENTS(aDocProperties); ++nMap )
+ {
+ if (rFirstParam.equalsAscii(aDocProperties[nMap].pDocPropertyName))
+ {
+ sFieldServiceName = OUString::createFromAscii(aDocProperties[nMap].pServiceName);
+ break;
+ }
+ }
+ }
+ else
+ pContext->CacheVariableValue(xUserDefinedProps->getPropertyValue(rFirstParam));
+
+ OUString sServiceName("com.sun.star.text.TextField.");
+ bool bIsCustomField = false;
+ if(sFieldServiceName.isEmpty())
+ {
+ //create a custom property field
+ sServiceName += "DocInfo.Custom";
+ bIsCustomField = true;
+ }
+ else
+ {
+ sServiceName += sFieldServiceName;
+ }
+ if (m_xTextFactory.is())
+ xFieldInterface = m_xTextFactory->createInstance(sServiceName);
+ uno::Reference<beans::XPropertySet> xFieldProperties( xFieldInterface, uno::UNO_QUERY_THROW);
+ if( bIsCustomField )
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NAME), uno::Any(rFirstParam));
+ pContext->SetCustomField( xFieldProperties );
+ }
+ else
+ {
+ if(0 != (aDocProperties[nMap].nFlags & SET_ARABIC))
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( style::NumberingType::ARABIC ));
+ else if(0 != (aDocProperties[nMap].nFlags & SET_DATE))
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_DATE),
+ uno::Any( true ));
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ }
+}
+
+static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool bHyperlinks, const OUString& sChapterNoSeparator,
+ const uno::Sequence< beans::PropertyValues >& aLevel )
+{
+ //create a copy of the level and add two new entries - hyperlink start and end
+ bool bChapterNoSeparator = !sChapterNoSeparator.isEmpty();
+ sal_Int32 nAdd = (bHyperlinks && bChapterNoSeparator) ? 4 : 2;
+ uno::Sequence< beans::PropertyValues > aNewLevel( aLevel.getLength() + nAdd);
+ beans::PropertyValues* pNewLevel = aNewLevel.getArray();
+ if( bHyperlinks )
+ {
+ beans::PropertyValues aHyperlink{ comphelper::makePropertyValue(
+ getPropertyName( PROP_TOKEN_TYPE ), getPropertyName( PROP_TOKEN_HYPERLINK_START )) };
+ pNewLevel[0] = aHyperlink;
+ aHyperlink = { comphelper::makePropertyValue(
+ getPropertyName(PROP_TOKEN_TYPE), getPropertyName( PROP_TOKEN_HYPERLINK_END )) };
+ pNewLevel[aNewLevel.getLength() -1] = aHyperlink;
+ }
+ if( bChapterNoSeparator )
+ {
+ beans::PropertyValues aChapterNo{
+ comphelper::makePropertyValue(getPropertyName( PROP_TOKEN_TYPE ),
+ getPropertyName( PROP_TOKEN_CHAPTER_INFO )),
+ comphelper::makePropertyValue(getPropertyName( PROP_CHAPTER_FORMAT ),
+ //todo: is ChapterFormat::Number correct?
+ sal_Int16(text::ChapterFormat::NUMBER))
+ };
+ pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 4 : 2) ] = aChapterNo;
+
+ beans::PropertyValues aChapterSeparator{
+ comphelper::makePropertyValue(getPropertyName( PROP_TOKEN_TYPE ),
+ getPropertyName( PROP_TOKEN_TEXT )),
+ comphelper::makePropertyValue(getPropertyName( PROP_TEXT ), sChapterNoSeparator)
+ };
+ pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 3 : 1)] = aChapterSeparator;
+ }
+ //copy the 'old' entries except the last (page no)
+ std::copy(aLevel.begin(), std::prev(aLevel.end()), std::next(pNewLevel));
+ //copy page no entry (last or last but one depending on bHyperlinks
+ sal_Int32 nPageNo = aNewLevel.getLength() - (bHyperlinks ? 2 : 3);
+ pNewLevel[nPageNo] = aLevel[aLevel.getLength() - 1];
+
+ return aNewLevel;
+}
+
+/// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
+OUString DomainMapper_Impl::extractTocTitle()
+{
+ if (!m_xSdtEntryStart.is())
+ return OUString();
+
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(!xTextAppend.is())
+ return OUString();
+
+ // try-catch was added in the same way as inside appendTextSectionAfter()
+ try
+ {
+ uno::Reference<text::XParagraphCursor> xCursor(xTextAppend->createTextCursorByRange(m_xSdtEntryStart), uno::UNO_QUERY_THROW);
+ if (!xCursor.is())
+ return OUString();
+
+ //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
+ xCursor->gotoStartOfParagraph( false );
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ xCursor->gotoRange( m_aTextAppendStack.top().xInsertPosition, true );
+ else
+ xCursor->gotoEnd( true );
+
+ // the paragraph after this new section might have been already inserted
+ OUString sResult = xCursor->getString();
+ if (sResult.endsWith(SAL_NEWLINE_STRING))
+ sResult = sResult.copy(0, sResult.getLength() - SAL_N_ELEMENTS(SAL_NEWLINE_STRING) + 1);
+
+ return sResult;
+ }
+ catch(const uno::Exception&)
+ {
+ }
+
+ return OUString();
+}
+
+css::uno::Reference<css::beans::XPropertySet>
+DomainMapper_Impl::StartIndexSectionChecked(const OUString& sServiceName)
+{
+ if (m_bParaChanged)
+ {
+ finishParagraph(GetTopContextOfType(CONTEXT_PARAGRAPH), false); // resets m_bParaChanged
+ PopProperties(CONTEXT_PARAGRAPH);
+ PushProperties(CONTEXT_PARAGRAPH);
+ SetIsFirstRun(true);
+ // The first paragraph of the index that is continuation of just finished one needs to be
+ // removed when finished (unless more content will arrive, which will set m_bParaChanged)
+ m_bRemoveThisParagraph = true;
+ }
+ const auto& xTextAppend = GetTopTextAppend();
+ const auto xTextRange = xTextAppend->getEnd();
+ const auto xRet = createSectionForRange(xTextRange, xTextRange, sServiceName, false);
+ if (!m_aTextAppendStack.top().xInsertPosition)
+ {
+ try
+ {
+ m_bStartedTOC = true;
+ uno::Reference<text::XTextCursor> xTOCTextCursor
+ = xTextRange->getText()->createTextCursor();
+ assert(xTOCTextCursor.is());
+ xTOCTextCursor->gotoEnd(false);
+ m_aTextAppendStack.push(TextAppendContext(xTextAppend, xTOCTextCursor));
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper",
+ "DomainMapper_Impl::StartIndexSectionChecked:");
+ }
+ }
+ return xRet;
+}
+
+void DomainMapper_Impl::handleToc
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName)
+{
+ OUString sValue;
+ if (IsInHeaderFooter())
+ m_bStartTOCHeaderFooter = true;
+ bool bTableOfFigures = false;
+ bool bHyperlinks = false;
+ bool bFromOutline = false;
+ bool bFromEntries = false;
+ bool bHideTabLeaderPageNumbers = false ;
+ bool bIsTabEntry = false ;
+ bool bNewLine = false ;
+ bool bParagraphOutlineLevel = false;
+
+ sal_Int16 nMaxLevel = 10;
+ OUString sTemplate;
+ OUString sChapterNoSeparator;
+ OUString sFigureSequence;
+ uno::Reference< beans::XPropertySet > xTOC;
+ OUString aBookmarkName;
+
+// \a Builds a table of figures but does not include the captions's label and number
+ if( lcl_FindInCommand( pContext->GetCommand(), 'a', sValue ))
+ { //make it a table of figures
+ bTableOfFigures = true;
+ }
+// \b Uses a bookmark to specify area of document from which to build table of contents
+ if( lcl_FindInCommand( pContext->GetCommand(), 'b', sValue ))
+ {
+ aBookmarkName = sValue.trim().replaceAll("\"","");
+ }
+ if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
+// \c Builds a table of figures of the given label
+ {
+ //todo: sValue contains the label's name
+ bTableOfFigures = true;
+ sFigureSequence = sValue.trim();
+ sFigureSequence = sFigureSequence.replaceAll("\"", "").replaceAll("'","");
+ }
+// \d Defines the separator between sequence and page numbers
+ if( lcl_FindInCommand( pContext->GetCommand(), 'd', sValue ))
+ {
+ //todo: insert the chapter number into each level and insert the separator additionally
+ sChapterNoSeparator = sValue;
+ }
+// \f Builds a table of contents using TC entries instead of outline levels
+ if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
+ {
+ //todo: sValue can contain a TOC entry identifier - use unclear
+ bFromEntries = true;
+ }
+// \h Hyperlinks the entries and page numbers within the table of contents
+ if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue ))
+ {
+ //todo: make all entries to hyperlinks
+ bHyperlinks = true;
+ }
+// \l Defines the TC entries field level used to build a table of contents
+// if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
+// {
+ //todo: entries can only be included completely
+// }
+// \n Builds a table of contents or a range of entries, such as 1-9 in a table of contents without page numbers
+// if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
+// {
+ //todo: what does the description mean?
+// }
+// \o Builds a table of contents by using outline levels instead of TC entries
+ if( lcl_FindInCommand( pContext->GetCommand(), 'o', sValue ))
+ {
+ bFromOutline = true;
+ if (sValue.isEmpty())
+ nMaxLevel = WW_OUTLINE_MAX;
+ else
+ {
+ sal_Int32 nIndex = 0;
+ o3tl::getToken(sValue, 0, '-', nIndex );
+ nMaxLevel = static_cast<sal_Int16>(nIndex != -1 ? o3tl::toInt32(sValue.subView(nIndex)) : 0);
+ }
+ }
+// \p Defines the separator between the table entry and its page number
+// \s Builds a table of contents by using a sequence type
+// \t Builds a table of contents by using style names other than the standard outline styles
+ if( lcl_FindInCommand( pContext->GetCommand(), 't', sValue ))
+ {
+ OUString sToken = sValue.getToken(1, '"');
+ sTemplate = sToken.isEmpty() ? sValue : sToken;
+ }
+// \u Builds a table of contents by using the applied paragraph outline level
+ if( lcl_FindInCommand( pContext->GetCommand(), 'u', sValue ))
+ {
+ bFromOutline = true;
+ bParagraphOutlineLevel = true;
+ //todo: what doesn 'the applied paragraph outline level' refer to?
+ }
+// \w Preserve tab characters within table entries
+ if( lcl_FindInCommand( pContext->GetCommand(), 'w', sValue ))
+ {
+ bIsTabEntry = true ;
+ }
+// \x Preserve newline characters within table entries
+ if( lcl_FindInCommand( pContext->GetCommand(), 'x', sValue ))
+ {
+ bNewLine = true ;
+ }
+// \z Hides page numbers within the table of contents when shown in Web Layout View
+ if( lcl_FindInCommand( pContext->GetCommand(), 'z', sValue ))
+ {
+ bHideTabLeaderPageNumbers = true ;
+ }
+
+ //if there's no option then it should be created from outline
+ if( !bFromOutline && !bFromEntries && sTemplate.isEmpty() )
+ bFromOutline = true;
+
+ const OUString aTocTitle = extractTocTitle();
+
+ if (m_xTextFactory.is() && ! m_aTextAppendStack.empty())
+ {
+ const auto& xTextAppend = GetTopTextAppend();
+ if (aTocTitle.isEmpty() || bTableOfFigures)
+ {
+ // reset marker of the TOC title
+ m_xSdtEntryStart.clear();
+
+ // Create section before setting m_bStartTOC: finishing paragraph
+ // inside StartIndexSectionChecked could do the wrong thing otherwise
+ xTOC = StartIndexSectionChecked(bTableOfFigures ? "com.sun.star.text.IllustrationsIndex"
+ : sTOCServiceName);
+
+ const auto xTextCursor = xTextAppend->getText()->createTextCursor();
+ if (xTextCursor)
+ xTextCursor->gotoEnd(false);
+ xTOCMarkerCursor = xTextCursor;
+ }
+ else
+ {
+ // create TOC section
+ css::uno::Reference<css::text::XTextRange> xTextRangeEndOfTocHeader = GetTopTextAppend()->getEnd();
+ xTOC = createSectionForRange(m_xSdtEntryStart, xTextRangeEndOfTocHeader, sTOCServiceName, false);
+
+ // init [xTOCMarkerCursor]
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ xTOCMarkerCursor = xCrsr;
+
+ // create header of the TOC with the TOC title inside
+ createSectionForRange(m_xSdtEntryStart, xTextRangeEndOfTocHeader, "com.sun.star.text.IndexHeaderSection", true);
+ }
+ }
+
+ m_bStartTOC = true;
+
+ if (xTOC.is())
+ xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::Any(aTocTitle));
+
+ if (!aBookmarkName.isEmpty())
+ xTOC->setPropertyValue(getPropertyName(PROP_TOC_BOOKMARK), uno::Any(aBookmarkName));
+ if( !bTableOfFigures && xTOC.is() )
+ {
+ xTOC->setPropertyValue( getPropertyName( PROP_LEVEL ), uno::Any( nMaxLevel ) );
+ xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_OUTLINE ), uno::Any( bFromOutline ));
+ xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_MARKS ), uno::Any( bFromEntries ));
+ xTOC->setPropertyValue( getPropertyName( PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS ), uno::Any( bHideTabLeaderPageNumbers ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TAB_IN_TOC ), uno::Any( bIsTabEntry ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TOC_NEW_LINE ), uno::Any( bNewLine ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TOC_PARAGRAPH_OUTLINE_LEVEL ), uno::Any( bParagraphOutlineLevel ));
+ if( !sTemplate.isEmpty() )
+ {
+ //the string contains comma separated the names and related levels
+ //like: "Heading 1,1,Heading 2,2"
+ TOCStyleMap aMap;
+ sal_Int32 nLevel;
+ sal_Int32 nPosition = 0;
+ while( nPosition >= 0)
+ {
+ OUString sStyleName = sTemplate.getToken( 0, ',', nPosition );
+ //empty tokens should be skipped
+ while( sStyleName.isEmpty() && nPosition > 0 )
+ sStyleName = sTemplate.getToken( 0, ',', nPosition );
+ nLevel = o3tl::toInt32(o3tl::getToken(sTemplate, 0, ',', nPosition ));
+ if( !nLevel )
+ nLevel = 1;
+ if( !sStyleName.isEmpty() )
+ aMap.emplace(nLevel, sStyleName);
+ }
+ uno::Reference< container::XIndexReplace> xParaStyles;
+ xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_PARAGRAPH_STYLES)) >>= xParaStyles;
+ for( nLevel = 1; nLevel < 10; ++nLevel)
+ {
+ sal_Int32 nLevelCount = aMap.count( nLevel );
+ if( nLevelCount )
+ {
+ TOCStyleMap::iterator aTOCStyleIter = aMap.find( nLevel );
+
+ uno::Sequence< OUString> aStyles( nLevelCount );
+ for ( auto& rStyle : asNonConstRange(aStyles) )
+ {
+ rStyle = (aTOCStyleIter++)->second;
+ }
+ xParaStyles->replaceByIndex(nLevel - 1, uno::Any(aStyles));
+ }
+ }
+ xTOC->setPropertyValue(getPropertyName(PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES), uno::Any( true ));
+
+ }
+ if(bHyperlinks || !sChapterNoSeparator.isEmpty())
+ {
+ uno::Reference< container::XIndexReplace> xLevelFormats;
+ xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats;
+ sal_Int32 nLevelCount = xLevelFormats->getCount();
+ //start with level 1, 0 is the header level
+ for( sal_Int32 nLevel = 1; nLevel < nLevelCount; ++nLevel)
+ {
+ uno::Sequence< beans::PropertyValues > aLevel;
+ xLevelFormats->getByIndex( nLevel ) >>= aLevel;
+
+ uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks(
+ bHyperlinks, sChapterNoSeparator,
+ aLevel );
+ xLevelFormats->replaceByIndex( nLevel, uno::Any( aNewLevel ) );
+ }
+ }
+ }
+ else if (bTableOfFigures && xTOC.is())
+ {
+ if (!sFigureSequence.isEmpty())
+ xTOC->setPropertyValue(getPropertyName(PROP_LABEL_CATEGORY),
+ uno::Any(sFigureSequence));
+
+ if ( bHyperlinks )
+ {
+ uno::Reference< container::XIndexReplace> xLevelFormats;
+ xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats;
+ uno::Sequence< beans::PropertyValues > aLevel;
+ xLevelFormats->getByIndex( 1 ) >>= aLevel;
+
+ uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks(
+ bHyperlinks, sChapterNoSeparator,
+ aLevel );
+ xLevelFormats->replaceByIndex( 1, uno::Any( aNewLevel ) );
+ }
+ }
+ pContext->SetTOC( xTOC );
+ m_bParaHadField = false;
+}
+
+uno::Reference<beans::XPropertySet> DomainMapper_Impl::createSectionForRange(
+ uno::Reference< css::text::XTextRange > xStart,
+ uno::Reference< css::text::XTextRange > xEnd,
+ const OUString & sObjectType,
+ bool stepLeft)
+{
+ if (!xStart.is())
+ return uno::Reference<beans::XPropertySet>();
+ if (!xEnd.is())
+ return uno::Reference<beans::XPropertySet>();
+
+ uno::Reference< beans::XPropertySet > xRet;
+ if (m_aTextAppendStack.empty())
+ return xRet;
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(xTextAppend.is())
+ {
+ try
+ {
+ uno::Reference< text::XParagraphCursor > xCursor(
+ xTextAppend->createTextCursorByRange( xStart ), uno::UNO_QUERY_THROW);
+ //the cursor has been moved to the end of the paragraph because of the appendTextPortion() calls
+ xCursor->gotoStartOfParagraph( false );
+ xCursor->gotoRange( xEnd, true );
+ //the paragraph after this new section is already inserted
+ if (stepLeft)
+ xCursor->goLeft(1, true);
+ uno::Reference< text::XTextContent > xSection( m_xTextFactory->createInstance(sObjectType), uno::UNO_QUERY_THROW );
+ xSection->attach( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW) );
+ xRet.set(xSection, uno::UNO_QUERY );
+ }
+ catch(const uno::Exception&)
+ {
+ }
+ }
+
+ return xRet;
+}
+
+void DomainMapper_Impl::handleBibliography
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName)
+{
+ if (m_aTextAppendStack.empty())
+ {
+ // tdf#130214: a workaround to avoid crash on import errors
+ SAL_WARN("writerfilter.dmapper", "no text append stack");
+ return;
+ }
+ // Create section before setting m_bStartTOC and m_bStartBibliography: finishing paragraph
+ // inside StartIndexSectionChecked could do the wrong thing otherwise
+ const auto xTOC = StartIndexSectionChecked(sTOCServiceName);
+ m_bStartTOC = true;
+ m_bStartBibliography = true;
+
+ if (xTOC.is())
+ xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::Any(OUString()));
+
+ pContext->SetTOC( xTOC );
+ m_bParaHadField = false;
+
+ uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
+ appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
+}
+
+void DomainMapper_Impl::handleIndex
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName)
+{
+ // only UserIndex can handle user index defined by \f
+ // e.g. INDEX \f "user-index-id"
+ OUString sUserIndex;
+ if ( lcl_FindInCommand( pContext->GetCommand(), 'f', sUserIndex ) )
+ sUserIndex = lcl_trim(sUserIndex);
+
+ // Create section before setting m_bStartTOC and m_bStartIndex: finishing paragraph
+ // inside StartIndexSectionChecked could do the wrong thing otherwise
+ const auto xTOC = StartIndexSectionChecked( sUserIndex.isEmpty()
+ ? sTOCServiceName
+ : "com.sun.star.text.UserIndex");
+
+ m_bStartTOC = true;
+ m_bStartIndex = true;
+ OUString sValue;
+ if (xTOC.is())
+ {
+ xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::Any(OUString()));
+
+ if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
+ {
+ xTOC->setPropertyValue("IsCommaSeparated", uno::Any(true));
+ }
+ if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue ))
+ {
+ xTOC->setPropertyValue("UseAlphabeticalSeparators", uno::Any(true));
+ }
+ if( !sUserIndex.isEmpty() )
+ {
+ xTOC->setPropertyValue("UserIndexName", uno::Any(sUserIndex));
+ }
+ }
+ pContext->SetTOC( xTOC );
+ m_bParaHadField = false;
+
+ uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
+ appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
+
+ if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
+ {
+ sValue = sValue.replaceAll("\"", "");
+ uno::Reference<text::XTextColumns> xTextColumns;
+ xTOC->getPropertyValue(getPropertyName( PROP_TEXT_COLUMNS )) >>= xTextColumns;
+ if (xTextColumns.is())
+ {
+ xTextColumns->setColumnCount( sValue.toInt32() );
+ xTOC->setPropertyValue( getPropertyName( PROP_TEXT_COLUMNS ), uno::Any( xTextColumns ) );
+ }
+ }
+}
+
+static auto InsertFieldmark(std::stack<TextAppendContext> & rTextAppendStack,
+ uno::Reference<text::XFormField> const& xFormField,
+ uno::Reference<text::XTextRange> const& xStartRange,
+ std::optional<FieldId> const oFieldId) -> void
+{
+ uno::Reference<text::XTextContent> const xTextContent(xFormField, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextAppend> const& xTextAppend(rTextAppendStack.top().xTextAppend);
+ uno::Reference<text::XTextCursor> const xCursor =
+ xTextAppend->createTextCursorByRange(xStartRange);
+ if (rTextAppendStack.top().xInsertPosition.is())
+ {
+ uno::Reference<text::XTextRangeCompare> const xCompare(
+ rTextAppendStack.top().xTextAppend,
+ uno::UNO_QUERY);
+ if (xCompare->compareRegionStarts(xStartRange, rTextAppendStack.top().xInsertPosition) < 0)
+ {
+ SAL_WARN("writerfilter.dmapper", "invalid field mark positions");
+ assert(false);
+ }
+ xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, true);
+ }
+ else
+ {
+ xCursor->gotoEnd(true);
+ }
+ xTextAppend->insertTextContent(xCursor, xTextContent, true);
+ if (oFieldId
+ && (oFieldId == FIELD_FORMCHECKBOX || oFieldId == FIELD_FORMDROPDOWN))
+ {
+ return; // only a single CH_TXT_ATR_FORMELEMENT!
+ }
+ // problem: the fieldmark must be inserted in CloseFieldCommand(), because
+ // attach() takes 2 positions, not 3!
+ // FAIL: AppendTextNode() ignores the content index!
+ // plan B: insert a spurious paragraph break now and join
+ // it in PopFieldContext()!
+ xCursor->gotoRange(xTextContent->getAnchor()->getEnd(), false);
+ xCursor->goLeft(1, false); // skip CH_TXT_ATR_FIELDEND
+ xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
+ xCursor->goLeft(1, false); // back to previous paragraph
+ rTextAppendStack.push(TextAppendContext(xTextAppend, xCursor));
+}
+
+static auto PopFieldmark(std::stack<TextAppendContext> & rTextAppendStack,
+ uno::Reference<text::XTextCursor> const& xCursor,
+ std::optional<FieldId> const oFieldId) -> void
+{
+ if (oFieldId
+ && (oFieldId == FIELD_FORMCHECKBOX || oFieldId == FIELD_FORMDROPDOWN))
+ {
+ return; // only a single CH_TXT_ATR_FORMELEMENT!
+ }
+ xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, false);
+ xCursor->goRight(1, true);
+ xCursor->setString(OUString()); // undo SplitNode from CloseFieldCommand()
+ // note: paragraph properties will be overwritten
+ // by finishParagraph() anyway so ignore here
+ rTextAppendStack.pop();
+}
+
+void DomainMapper_Impl::CloseFieldCommand()
+{
+ if(m_bDiscardHeaderFooter)
+ return;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("closeFieldCommand");
+#endif
+
+ FieldContextPtr pContext;
+ if(!m_aFieldStack.empty())
+ pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( !pContext )
+ return;
+
+ m_bSetUserFieldContent = false;
+ m_bSetCitation = false;
+ m_bSetDateValue = false;
+ const FieldConversionMap_t& aFieldConversionMap = lcl_GetFieldConversion();
+
+ try
+ {
+ uno::Reference< uno::XInterface > xFieldInterface;
+
+ const auto& [sType, vArguments, vSwitches]{ splitFieldCommand(pContext->GetCommand()) };
+ (void)vSwitches;
+ OUString const sFirstParam(vArguments.empty() ? OUString() : vArguments.front());
+
+ // apply font size to the form control
+ if (!m_aTextAppendStack.empty() && m_pLastCharacterContext && ( m_pLastCharacterContext->isSet(PROP_CHAR_HEIGHT) || m_pLastCharacterContext->isSet(PROP_CHAR_FONT_NAME )))
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is())
+ {
+ uno::Reference< text::XTextCursor > xCrsr = xTextAppend->getText()->createTextCursor();
+ if (xCrsr.is())
+ {
+ xCrsr->gotoEnd(false);
+ uno::Reference< beans::XPropertySet > xProp( xCrsr, uno::UNO_QUERY );
+ if (m_pLastCharacterContext->isSet(PROP_CHAR_HEIGHT))
+ {
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT), m_pLastCharacterContext->getProperty(PROP_CHAR_HEIGHT)->second);
+ if (m_pLastCharacterContext->isSet(PROP_CHAR_HEIGHT_COMPLEX))
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT_COMPLEX), m_pLastCharacterContext->getProperty(PROP_CHAR_HEIGHT_COMPLEX)->second);
+ }
+ if (m_pLastCharacterContext->isSet(PROP_CHAR_FONT_NAME))
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), m_pLastCharacterContext->getProperty(PROP_CHAR_FONT_NAME)->second);
+ }
+ }
+ }
+
+ FieldConversionMap_t::const_iterator const aIt = aFieldConversionMap.find(sType);
+ if (aIt != aFieldConversionMap.end()
+ && (!m_bForceGenericFields
+ // these need to convert ffData to properties...
+ || (aIt->second.eFieldId == FIELD_FORMCHECKBOX)
+ || (aIt->second.eFieldId == FIELD_FORMDROPDOWN)
+ || (aIt->second.eFieldId == FIELD_FORMTEXT)))
+ {
+ pContext->SetFieldId(aIt->second.eFieldId);
+ bool bCreateEnhancedField = false;
+ uno::Reference< beans::XPropertySet > xFieldProperties;
+ bool bCreateField = true;
+ switch (aIt->second.eFieldId)
+ {
+ case FIELD_HYPERLINK:
+ case FIELD_DOCPROPERTY:
+ case FIELD_TOC:
+ case FIELD_INDEX:
+ case FIELD_XE:
+ case FIELD_BIBLIOGRAPHY:
+ case FIELD_CITATION:
+ case FIELD_TC:
+ case FIELD_EQ:
+ case FIELD_INCLUDEPICTURE:
+ case FIELD_SYMBOL:
+ case FIELD_GOTOBUTTON:
+ bCreateField = false;
+ break;
+ case FIELD_FORMCHECKBOX :
+ case FIELD_FORMTEXT :
+ case FIELD_FORMDROPDOWN :
+ {
+ // If we use 'enhanced' fields then FIELD_FORMCHECKBOX,
+ // FIELD_FORMTEXT & FIELD_FORMDROPDOWN are treated specially
+ if ( m_bUsingEnhancedFields )
+ {
+ bCreateField = false;
+ bCreateEnhancedField = true;
+ }
+ // for non enhanced fields checkboxes are displayed
+ // as an awt control not a field
+ else if ( aIt->second.eFieldId == FIELD_FORMCHECKBOX )
+ bCreateField = false;
+ break;
+ }
+ default:
+ {
+ FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
+ if (pOuter)
+ {
+ if (!IsFieldNestingAllowed(pOuter, m_aFieldStack.back()))
+ {
+ // Parent field can't host this child field: don't create a child field
+ // in this case.
+ bCreateField = false;
+ }
+ }
+ break;
+ }
+ }
+ if (m_bStartTOC && (aIt->second.eFieldId == FIELD_PAGEREF) )
+ {
+ bCreateField = false;
+ }
+
+ if( bCreateField || bCreateEnhancedField )
+ {
+ //add the service prefix
+ OUString sServiceName("com.sun.star.text.");
+ if ( bCreateEnhancedField )
+ {
+ const FieldConversionMap_t& aEnhancedFieldConversionMap = lcl_GetEnhancedFieldConversion();
+ FieldConversionMap_t::const_iterator aEnhancedIt =
+ aEnhancedFieldConversionMap.find(sType);
+ if ( aEnhancedIt != aEnhancedFieldConversionMap.end())
+ sServiceName += OUString::createFromAscii(aEnhancedIt->second.cFieldServiceName );
+ }
+ else
+ {
+ sServiceName += "TextField." + OUString::createFromAscii(aIt->second.cFieldServiceName );
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("fieldService");
+ TagLogger::getInstance().chars(sServiceName);
+ TagLogger::getInstance().endElement();
+#endif
+
+ if (m_xTextFactory.is())
+ {
+ xFieldInterface = m_xTextFactory->createInstance(sServiceName);
+ xFieldProperties.set( xFieldInterface, uno::UNO_QUERY_THROW);
+ }
+ }
+ switch( aIt->second.eFieldId )
+ {
+ case FIELD_ADDRESSBLOCK: break;
+ case FIELD_ADVANCE : break;
+ case FIELD_ASK :
+ handleFieldAsk(pContext, xFieldInterface, xFieldProperties);
+ break;
+ case FIELD_AUTONUM :
+ case FIELD_AUTONUMLGL :
+ case FIELD_AUTONUMOUT :
+ handleAutoNum(pContext, xFieldInterface, xFieldProperties);
+ break;
+ case FIELD_AUTHOR :
+ case FIELD_USERNAME :
+ case FIELD_USERINITIALS :
+ handleAuthor(sFirstParam,
+ xFieldProperties,
+ aIt->second.eFieldId);
+ break;
+ case FIELD_DATE:
+ if (xFieldProperties.is())
+ {
+ // Get field fixed property from the context handler
+ if (pContext->IsFieldLocked())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED),
+ uno::Any( true ));
+ m_bSetDateValue = true;
+ }
+ else
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED),
+ uno::Any( false ));
+
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_DATE),
+ uno::Any( true ));
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ break;
+ case FIELD_COMMENTS :
+ {
+ // OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" COMMENTS") );
+ // A parameter with COMMENTS shouldn't set fixed
+ // ( or at least the binary filter doesn't )
+ // If we set fixed then we won't export a field cmd.
+ // Additionally the para in COMMENTS is more like an
+ // instruction to set the document property comments
+ // with the param ( e.g. each COMMENT with a param will
+ // overwrite the Comments document property
+ // #TODO implement the above too
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( false ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ break;
+ case FIELD_CREATEDATE :
+ case FIELD_PRINTDATE:
+ case FIELD_SAVEDATE:
+ {
+ if (pContext->IsFieldLocked())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED), uno::Any( true ));
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_DATE ), uno::Any( true ));
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ break;
+ case FIELD_DOCPROPERTY :
+ handleDocProperty(pContext, sFirstParam,
+ xFieldInterface);
+ break;
+ case FIELD_DOCVARIABLE :
+ {
+ if (bCreateField)
+ {
+ //create a user field and type
+ uno::Reference<beans::XPropertySet> xMaster = FindOrCreateFieldMaster(
+ "com.sun.star.text.FieldMaster.User", sFirstParam);
+ uno::Reference<text::XDependentTextField> xDependentField(
+ xFieldInterface, uno::UNO_QUERY_THROW);
+ xDependentField->attachTextFieldMaster(xMaster);
+ m_bSetUserFieldContent = true;
+ }
+ }
+ break;
+ case FIELD_EDITTIME :
+ //it's a numbering type, no number format! SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ break;
+ case FIELD_EQ:
+ {
+ OUString aCommand = pContext->GetCommand().trim();
+
+ msfilter::util::EquationResult aResult(msfilter::util::ParseCombinedChars(aCommand));
+ if (!aResult.sType.isEmpty() && m_xTextFactory.is())
+ {
+ xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField." + aResult.sType);
+ xFieldProperties =
+ uno::Reference< beans::XPropertySet >( xFieldInterface,
+ uno::UNO_QUERY_THROW);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::Any(aResult.sResult));
+ }
+ else
+ {
+ //merge Read_SubF_Ruby into filter/.../util.cxx and reuse that ?
+ sal_Int32 nSpaceIndex = aCommand.indexOf(' ');
+ if(nSpaceIndex > 0)
+ aCommand = o3tl::trim(aCommand.subView(nSpaceIndex));
+ if (aCommand.startsWith("\\s"))
+ {
+ aCommand = aCommand.copy(2);
+ if (aCommand.startsWith("\\do"))
+ {
+ aCommand = aCommand.copy(3);
+ sal_Int32 nStartIndex = aCommand.indexOf('(');
+ sal_Int32 nEndIndex = aCommand.indexOf(')');
+ if (nStartIndex > 0 && nEndIndex > 0)
+ {
+ // nDown is the requested "lower by" value in points.
+ sal_Int32 nDown = o3tl::toInt32(aCommand.subView(0, nStartIndex));
+ OUString aContent = aCommand.copy(nStartIndex + 1, nEndIndex - nStartIndex - 1);
+ PropertyMapPtr pCharContext = GetTopContext();
+ // dHeight is the font size of the current style.
+ double dHeight = 0;
+ if ((GetPropertyFromParaStyleSheet(PROP_CHAR_HEIGHT) >>= dHeight) && dHeight != 0)
+ // Character escapement should be given in negative percents for subscripts.
+ pCharContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( sal_Int16(- 100 * nDown / dHeight) ) );
+ appendTextPortion(aContent, pCharContext);
+ }
+ }
+ }
+ else if (aCommand.startsWith("\\* jc"))
+ {
+ handleRubyEQField(pContext);
+ }
+ }
+ }
+ break;
+ case FIELD_FILLIN :
+ if (xFieldProperties.is())
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_HINT), uno::Any( pContext->GetCommand().getToken(1, '\"')));
+ break;
+ case FIELD_FILENAME:
+ {
+ sal_Int32 nNumberingTypeIndex = pContext->GetCommand().indexOf("\\p");
+ if (xFieldProperties.is())
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_FILE_FORMAT),
+ uno::Any( nNumberingTypeIndex > 0 ? text::FilenameDisplayFormat::FULL : text::FilenameDisplayFormat::NAME_AND_EXT ));
+ }
+ break;
+ case FIELD_FILESIZE : break;
+ case FIELD_FORMULA :
+ if (bCreateField)
+ {
+ handleFieldFormula(pContext, xFieldProperties);
+ }
+ break;
+ case FIELD_FORMCHECKBOX :
+ case FIELD_FORMDROPDOWN :
+ case FIELD_FORMTEXT :
+ {
+ if (bCreateEnhancedField)
+ {
+ FFDataHandler::Pointer_t
+ pFFDataHandler(pContext->getFFDataHandler());
+ FormControlHelper::Pointer_t
+ pFormControlHelper(new FormControlHelper
+ (m_bUsingEnhancedFields ? aIt->second.eFieldId : FIELD_FORMCHECKBOX,
+
+ m_xTextDocument, pFFDataHandler));
+ pContext->setFormControlHelper(pFormControlHelper);
+ uno::Reference< text::XFormField > xFormField( xFieldInterface, uno::UNO_QUERY );
+ uno::Reference< container::XNamed > xNamed( xFormField, uno::UNO_QUERY );
+ if ( xNamed.is() )
+ {
+ if ( pFFDataHandler && !pFFDataHandler->getName().isEmpty() )
+ xNamed->setName( pFFDataHandler->getName() );
+ pContext->SetFormField( xFormField );
+ }
+ InsertFieldmark(m_aTextAppendStack,
+ xFormField, pContext->GetStartRange(),
+ pContext->GetFieldId());
+ }
+ else
+ {
+ if ( aIt->second.eFieldId == FIELD_FORMDROPDOWN )
+ lcl_handleDropdownField( xFieldProperties, pContext->getFFDataHandler() );
+ else
+ lcl_handleTextField( xFieldProperties, pContext->getFFDataHandler() );
+ }
+ }
+ break;
+ case FIELD_GOTOBUTTON : break;
+ case FIELD_HYPERLINK:
+ {
+ ::std::vector<OUString> aParts = pContext->GetCommandParts();
+
+ // Syntax is either:
+ // HYPERLINK "" \l "link"
+ // or
+ // HYPERLINK \l "link"
+ // Make sure "HYPERLINK" doesn't end up as part of link in the second case.
+ if (!aParts.empty() && aParts[0] == "HYPERLINK")
+ aParts.erase(aParts.begin());
+
+ ::std::vector<OUString>::const_iterator aItEnd = aParts.end();
+ ::std::vector<OUString>::const_iterator aPartIt = aParts.begin();
+
+ OUString sURL;
+ OUString sTarget;
+
+ while (aPartIt != aItEnd)
+ {
+ if ( *aPartIt == "\\l" )
+ {
+ ++aPartIt;
+
+ if (aPartIt == aItEnd)
+ break;
+
+ sURL += "#" + *aPartIt;
+ }
+ else if (*aPartIt == "\\m" || *aPartIt == "\\n" || *aPartIt == "\\h")
+ {
+ }
+ else if ( *aPartIt == "\\o" || *aPartIt == "\\t" )
+ {
+ ++aPartIt;
+
+ if (aPartIt == aItEnd)
+ break;
+
+ sTarget = *aPartIt;
+ }
+ else
+ {
+ sURL = *aPartIt;
+ }
+
+ ++aPartIt;
+ }
+
+ if (!sURL.isEmpty())
+ {
+ if (sURL.startsWith("file:///"))
+ {
+ // file:///absolute\\path\\to\\file => invalid file URI (Writer cannot open)
+ // convert all double backslashes to slashes:
+ sURL = sURL.replaceAll("\\\\", "/");
+
+ // file:///absolute\path\to\file => invalid file URI (Writer cannot open)
+ // convert all backslashes to slashes:
+ sURL = sURL.replace('\\', '/');
+ }
+ // Try to make absolute any relative URLs, except
+ // for relative same-document URLs that only contain
+ // a fragment part:
+ else if (!sURL.startsWith("#")) {
+ try {
+ sURL = rtl::Uri::convertRelToAbs(
+ m_aBaseUrl, sURL);
+ } catch (rtl::MalformedUriException & e) {
+ SAL_WARN(
+ "writerfilter.dmapper",
+ "MalformedUriException "
+ << e.getMessage());
+ }
+ }
+ pContext->SetHyperlinkURL(sURL);
+ }
+
+ if (!sTarget.isEmpty())
+ pContext->SetHyperlinkTarget(sTarget);
+ }
+ break;
+ case FIELD_IF : break;
+ case FIELD_INFO : break;
+ case FIELD_INCLUDEPICTURE: break;
+ case FIELD_KEYWORDS :
+ {
+ if (!sFirstParam.isEmpty())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ }
+ break;
+ case FIELD_LASTSAVEDBY :
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED), uno::Any(true));
+ break;
+ case FIELD_MACROBUTTON:
+ {
+ if (xFieldProperties.is())
+ {
+ sal_Int32 nIndex = sizeof(" MACROBUTTON ");
+ OUString sCommand = pContext->GetCommand();
+
+ //extract macro name
+ if (sCommand.getLength() >= nIndex)
+ {
+ OUString sMacro = sCommand.getToken(0, ' ', nIndex);
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_MACRO_NAME), uno::Any( sMacro ));
+ }
+
+ //extract quick help text
+ if (sCommand.getLength() > nIndex + 1)
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_HINT),
+ uno::Any( sCommand.copy( nIndex )));
+ }
+ }
+ }
+ break;
+ case FIELD_MERGEFIELD :
+ {
+ //todo: create a database field and fieldmaster pointing to a column, only
+ //create a user field and type
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster("com.sun.star.text.FieldMaster.Database", sFirstParam);
+
+// xFieldProperties->setPropertyValue(
+// "FieldCode",
+// uno::makeAny( pContext->GetCommand().copy( nIndex + 1 )));
+ uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+ }
+ break;
+ case FIELD_MERGEREC : break;
+ case FIELD_MERGESEQ : break;
+ case FIELD_NEXT : break;
+ case FIELD_NEXTIF : break;
+ case FIELD_PAGE :
+ if (xFieldProperties.is())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_SUB_TYPE),
+ uno::Any( text::PageNumberType_CURRENT ));
+ }
+
+ break;
+ case FIELD_PAGEREF:
+ case FIELD_REF:
+ if (xFieldProperties.is() && !m_bStartTOC)
+ {
+ bool bPageRef = aIt->second.eFieldId == FIELD_PAGEREF;
+
+ // Do we need a GetReference (default) or a GetExpression field?
+ uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
+
+ if (!xFieldMasterAccess->hasByName(
+ "com.sun.star.text.FieldMaster.SetExpression."
+ + sFirstParam))
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
+ uno::Any( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_SOURCE_NAME),
+ uno::Any(sFirstParam) );
+ sal_Int16 nFieldPart = (bPageRef ? text::ReferenceFieldPart::PAGE : text::ReferenceFieldPart::TEXT);
+ OUString sValue;
+ if( lcl_FindInCommand( pContext->GetCommand(), 'p', sValue ))
+ {
+ //above-below
+ nFieldPart = text::ReferenceFieldPart::UP_DOWN;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
+ {
+ //number
+ nFieldPart = text::ReferenceFieldPart::NUMBER;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
+ {
+ //number-no-context
+ nFieldPart = text::ReferenceFieldPart::NUMBER_NO_CONTEXT;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'w', sValue ))
+ {
+ //number-full-context
+ nFieldPart = text::ReferenceFieldPart::NUMBER_FULL_CONTEXT;
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_REFERENCE_FIELD_PART ), uno::Any( nFieldPart ));
+ }
+ else if( m_xTextFactory.is() )
+ {
+ xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField.GetExpression");
+ xFieldProperties.set(xFieldInterface, uno::UNO_QUERY);
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_CONTENT),
+ uno::Any(sFirstParam));
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+ }
+ }
+ break;
+ case FIELD_REVNUM : break;
+ case FIELD_SECTION : break;
+ case FIELD_SECTIONPAGES : break;
+ case FIELD_SEQ :
+ {
+ // command looks like: " SEQ Table \* ARABIC "
+ OUString sCmd(pContext->GetCommand());
+ // find the sequence name, e.g. "SEQ"
+ std::u16string_view sSeqName = msfilter::util::findQuotedText(sCmd, "SEQ ", '\\');
+ sSeqName = o3tl::trim(sSeqName);
+
+ // create a sequence field master using the sequence name
+ uno::Reference< beans::XPropertySet > xMaster = FindOrCreateFieldMaster(
+ "com.sun.star.text.FieldMaster.SetExpression",
+ OUString(sSeqName));
+
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_SUB_TYPE),
+ uno::Any(text::SetVariableType::SEQUENCE));
+
+ // apply the numbering type
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+
+ OUString sFormula = OUString::Concat(sSeqName) + "+1";
+ OUString sValue;
+ if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
+ {
+ sFormula = sSeqName;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
+ {
+ sFormula = sValue;
+ }
+ // TODO \s isn't handled, but the spec isn't easy to understand without
+ // an example for this one.
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_CONTENT),
+ uno::Any(sFormula));
+
+ // Take care of the numeric formatting definition, default is Arabic
+ sal_Int16 nNumberingType = lcl_ParseNumberingType(pContext->GetCommand());
+ if (nNumberingType == style::NumberingType::PAGE_DESCRIPTOR)
+ nNumberingType = style::NumberingType::ARABIC;
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any(nNumberingType));
+ }
+ break;
+ case FIELD_SET :
+ handleFieldSet(pContext, xFieldInterface, xFieldProperties);
+ break;
+ case FIELD_SKIPIF : break;
+ case FIELD_STYLEREF : break;
+ case FIELD_SUBJECT :
+ {
+ if (!sFirstParam.isEmpty())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ }
+ break;
+ case FIELD_SYMBOL:
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ OUString sSymbol( sal_Unicode( sFirstParam.startsWithIgnoreAsciiCase("0x") ? o3tl::toUInt32(sFirstParam.subView(2),16) : sFirstParam.toUInt32() ) );
+ OUString sFont;
+ bool bHasFont = lcl_FindInCommand( pContext->GetCommand(), 'f', sFont);
+ if ( bHasFont )
+ {
+ sFont = sFont.trim();
+ if (sFont.startsWith("\""))
+ sFont = sFont.copy(1);
+ if (sFont.endsWith("\""))
+ sFont = sFont.copy(0,sFont.getLength()-1);
+ }
+
+
+
+ if (xTextAppend.is())
+ {
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ if (xCrsr.is())
+ {
+ xCrsr->gotoEnd(false);
+ xText->insertString(xCrsr, sSymbol, true);
+ uno::Reference< beans::XPropertySet > xProp( xCrsr, uno::UNO_QUERY );
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_CHAR_SET), uno::Any(awt::CharSet::SYMBOL));
+ if(bHasFont)
+ {
+ uno::Any aVal( sFont );
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), aVal);
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_ASIAN), aVal);
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_COMPLEX), aVal);
+
+ }
+ }
+ }
+ }
+ break;
+ case FIELD_TEMPLATE: break;
+ case FIELD_TIME :
+ {
+ if (pContext->IsFieldLocked())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED),
+ uno::Any( true ));
+ m_bSetDateValue = true;
+ }
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ break;
+ case FIELD_TITLE :
+ {
+ if (!sFirstParam.isEmpty())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ }
+ break;
+ case FIELD_USERADDRESS : //todo: user address collects street, city ...
+ break;
+ case FIELD_INDEX:
+ handleIndex(pContext,
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ break;
+ case FIELD_BIBLIOGRAPHY:
+ handleBibliography(pContext,
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ break;
+ case FIELD_TOC:
+ handleToc(pContext,
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ break;
+ case FIELD_XE:
+ {
+ if( !m_xTextFactory.is() )
+ break;
+
+ // only UserIndexMark can handle user index types defined by \f
+ // e.g. XE "text" \f "user-index-id"
+ OUString sUserIndex;
+ OUString sFieldServiceName =
+ lcl_FindInCommand( pContext->GetCommand(), 'f', sUserIndex )
+ ? "com.sun.star.text.UserIndexMark"
+ : OUString::createFromAscii(aIt->second.cFieldServiceName);
+ uno::Reference< beans::XPropertySet > xTC(
+ m_xTextFactory->createInstance(sFieldServiceName),
+ uno::UNO_QUERY_THROW);
+
+ if (!sFirstParam.isEmpty())
+ {
+ xTC->setPropertyValue(sUserIndex.isEmpty()
+ ? OUString("PrimaryKey")
+ : OUString("AlternativeText"),
+ uno::Any(sFirstParam));
+ }
+
+ sUserIndex = lcl_trim(sUserIndex);
+ if (!sUserIndex.isEmpty())
+ {
+ xTC->setPropertyValue("UserIndexName",
+ uno::Any(sUserIndex));
+ }
+ uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY );
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is())
+ {
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ if (xCrsr.is())
+ {
+ xCrsr->gotoEnd(false);
+ xText->insertTextContent(uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW ), xToInsert, false);
+ }
+ }
+ }
+ break;
+ case FIELD_CITATION:
+ {
+ if( !m_xTextFactory.is() )
+ break;
+
+ xFieldInterface = m_xTextFactory->createInstance(
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ uno::Reference< beans::XPropertySet > xTC(xFieldInterface,
+ uno::UNO_QUERY_THROW);
+ OUString sCmd(pContext->GetCommand());//sCmd is the entire instrText including the index e.g. CITATION Kra06 \l 1033
+ if( !sCmd.isEmpty()){
+ uno::Sequence<beans::PropertyValue> aValues( comphelper::InitPropertySequence({
+ { "Identifier", uno::Any(sCmd) }
+ }));
+ xTC->setPropertyValue("Fields", uno::Any(aValues));
+ }
+ uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY );
+
+ uno::Sequence<beans::PropertyValue> aValues
+ = m_aFieldStack.back()->getProperties()->GetPropertyValues();
+ appendTextContent(xToInsert, aValues);
+ m_bSetCitation = true;
+ }
+ break;
+
+ case FIELD_TC :
+ {
+ if( !m_xTextFactory.is() )
+ break;
+
+ uno::Reference< beans::XPropertySet > xTC(
+ m_xTextFactory->createInstance(
+ OUString::createFromAscii(aIt->second.cFieldServiceName)),
+ uno::UNO_QUERY_THROW);
+ if (!sFirstParam.isEmpty())
+ {
+ xTC->setPropertyValue(getPropertyName(PROP_ALTERNATIVE_TEXT),
+ uno::Any(sFirstParam));
+ }
+ OUString sValue;
+ // \f TC entry in doc with multiple tables
+// if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
+// {
+ // todo: unsupported
+// }
+ if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
+ // \l Outline Level
+ {
+ sal_Int32 nLevel = sValue.toInt32();
+ if( !sValue.isEmpty() && nLevel >= 0 && nLevel <= 10 )
+ xTC->setPropertyValue(getPropertyName(PROP_LEVEL), uno::Any( static_cast<sal_Int16>(nLevel) ));
+ }
+// if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
+// \n Suppress page numbers
+// {
+ //todo: unsupported feature
+// }
+ pContext->SetTC( xTC );
+ }
+ break;
+ case FIELD_NUMCHARS:
+ case FIELD_NUMWORDS:
+ case FIELD_NUMPAGES:
+ if (xFieldProperties.is())
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+ break;
+ }
+
+ if (!bCreateEnhancedField)
+ {
+ pContext->SetTextField( uno::Reference<text::XTextField>(xFieldInterface, uno::UNO_QUERY) );
+ }
+ }
+ else
+ {
+ /* Unsupported fields will be handled here for docx file.
+ * To handle unsupported fields used fieldmark API.
+ */
+ OUString aCode( pContext->GetCommand().trim() );
+ // Don't waste resources on wrapping shapes inside a fieldmark.
+ if (sType != "SHAPE" && m_xTextFactory.is() && !m_aTextAppendStack.empty())
+ {
+ xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.Fieldmark");
+
+ uno::Reference<text::XFormField> const xFormField(xFieldInterface, uno::UNO_QUERY);
+ InsertFieldmark(m_aTextAppendStack, xFormField, pContext->GetStartRange(),
+ pContext->GetFieldId());
+ xFormField->setFieldType(ODF_UNHANDLED);
+ ++m_nStartGenericField;
+ pContext->SetFormField( xFormField );
+ uno::Reference<container::XNameContainer> const xNameCont(xFormField->getParameters());
+ // note: setting the code to empty string is *required* in
+ // m_bForceGenericFields mode, or the export will write
+ // the ODF_UNHANDLED string!
+ assert(!m_bForceGenericFields || aCode.isEmpty());
+ xNameCont->insertByName(ODF_CODE_PARAM, uno::Any(aCode));
+ ww::eField const id(GetWW8FieldId(sType));
+ if (id != ww::eNONE)
+ { // tdf#129247 tdf#134264 set WW8 id for WW8 export
+ xNameCont->insertByName(ODF_ID_PARAM, uno::Any(OUString::number(id)));
+ }
+ }
+ else
+ m_bParaHadField = false;
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "Exception in CloseFieldCommand()" );
+ }
+ pContext->SetCommandCompleted();
+}
+/*-------------------------------------------------------------------------
+//the _current_ fields require a string type result while TOCs accept richt results
+ -----------------------------------------------------------------------*/
+bool DomainMapper_Impl::IsFieldResultAsString()
+{
+ bool bRet = false;
+ OSL_ENSURE( !m_aFieldStack.empty(), "field stack empty?");
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( pContext )
+ {
+ bRet = pContext->GetTextField().is()
+ || pContext->GetFieldId() == FIELD_FORMDROPDOWN
+ || pContext->GetFieldId() == FIELD_FILLIN;
+ }
+
+ if (!bRet)
+ {
+ FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
+ if (pOuter)
+ {
+ if (!IsFieldNestingAllowed(pOuter, m_aFieldStack.back()))
+ {
+ // If nesting is not allowed, then the result can only be a string.
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+void DomainMapper_Impl::AppendFieldResult(std::u16string_view rString)
+{
+ assert(!m_aFieldStack.empty());
+ FieldContextPtr pContext = m_aFieldStack.back();
+ SAL_WARN_IF(!pContext, "writerfilter.dmapper", "no field context");
+ if (!pContext)
+ return;
+
+ FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
+ if (pOuter)
+ {
+ if (!IsFieldNestingAllowed(pOuter, pContext))
+ {
+ if (pOuter->IsCommandCompleted())
+ {
+ // Child can't host the field result, forward to parent's result.
+ pOuter->AppendResult(rString);
+ }
+ return;
+ }
+ }
+
+ pContext->AppendResult(rString);
+}
+
+// Calculates css::DateTime based on ddddd.sssss since 1899-12-30
+static util::DateTime lcl_dateTimeFromSerial(const double& dSerial)
+{
+ DateTime d(Date(30, 12, 1899));
+ d.AddTime(dSerial);
+ return d.GetUNODateTime();
+}
+
+void DomainMapper_Impl::SetFieldResult(OUString const& rResult)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("setFieldResult");
+ TagLogger::getInstance().chars(rResult);
+#endif
+
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+
+ if (m_aFieldStack.size() > 1)
+ {
+ // This is a nested field. See if the parent supports nesting on the Writer side.
+ FieldContextPtr pParentContext = m_aFieldStack[m_aFieldStack.size() - 2];
+ if (pParentContext)
+ {
+ std::vector<OUString> aParentParts = pParentContext->GetCommandParts();
+ // Conditional text fields don't support nesting in Writer.
+ if (!aParentParts.empty() && aParentParts[0] == "IF")
+ {
+ return;
+ }
+ }
+ }
+
+ if( !pContext )
+ return;
+
+ uno::Reference<text::XTextField> xTextField = pContext->GetTextField();
+ try
+ {
+ OSL_ENSURE( xTextField.is()
+ //||m_xTOC.is() ||m_xTC.is()
+ //||m_sHyperlinkURL.getLength()
+ , "DomainMapper_Impl::SetFieldResult: field not created" );
+ if(xTextField.is())
+ {
+ try
+ {
+ if( m_bSetUserFieldContent )
+ {
+ // user field content has to be set at the field master
+ uno::Reference< text::XDependentTextField > xDependentField( xTextField, uno::UNO_QUERY_THROW );
+ xDependentField->getTextFieldMaster()->setPropertyValue(
+ getPropertyName(PROP_CONTENT),
+ uno::Any( rResult ));
+ }
+ else if ( m_bSetCitation )
+ {
+
+ uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
+ // In case of SetExpression, the field result contains the content of the variable.
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY);
+
+ bool bIsSetbiblio = xServiceInfo->supportsService("com.sun.star.text.TextField.Bibliography");
+ if( bIsSetbiblio )
+ {
+ uno::Any aProperty = xFieldProperties->getPropertyValue("Fields");
+ uno::Sequence<beans::PropertyValue> aValues ;
+ aProperty >>= aValues;
+ beans::PropertyValue propertyVal;
+ sal_Int32 nTitleFoundIndex = -1;
+ for (sal_Int32 i = 0; i < aValues.getLength(); ++i)
+ {
+ propertyVal = aValues[i];
+ if (propertyVal.Name == "Title")
+ {
+ nTitleFoundIndex = i;
+ break;
+ }
+ }
+ if (nTitleFoundIndex != -1)
+ {
+ OUString titleStr;
+ uno::Any aValue(propertyVal.Value);
+ aValue >>= titleStr;
+ titleStr += rResult;
+ propertyVal.Value <<= titleStr;
+ aValues.getArray()[nTitleFoundIndex] = propertyVal;
+ }
+ else
+ {
+ aValues.realloc(aValues.getLength() + 1);
+ propertyVal.Name = "Title";
+ propertyVal.Value <<= rResult;
+ aValues.getArray()[aValues.getLength() - 1] = propertyVal;
+ }
+ xFieldProperties->setPropertyValue("Fields",
+ uno::Any(aValues));
+ }
+ }
+ else if ( m_bSetDateValue )
+ {
+ uno::Reference< util::XNumberFormatsSupplier > xNumberSupplier( m_xTextDocument, uno::UNO_QUERY_THROW );
+
+ uno::Reference<util::XNumberFormatter> xFormatter(util::NumberFormatter::create(m_xComponentContext), uno::UNO_QUERY_THROW);
+ xFormatter->attachNumberFormatsSupplier( xNumberSupplier );
+ sal_Int32 nKey = 0;
+
+ uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
+
+ xFieldProperties->getPropertyValue( "NumberFormat" ) >>= nKey;
+ xFieldProperties->setPropertyValue(
+ "DateTimeValue",
+ uno::Any( lcl_dateTimeFromSerial( xFormatter->convertStringToNumber( nKey, rResult ) ) ) );
+ }
+ else
+ {
+ uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
+ // In case of SetExpression, and Input fields the field result contains the content of the variable.
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY);
+ // there are fields with a content property, which aren't working correctly with
+ // a generalized try catch of the content, property, so just restrict content
+ // handling to these explicit services.
+ const bool bHasContent = xServiceInfo->supportsService("com.sun.star.text.TextField.SetExpression") ||
+ xServiceInfo->supportsService("com.sun.star.text.TextField.Input");
+ // If we already have content set, then use the current presentation
+ OUString sValue;
+ if (bHasContent)
+ {
+ // this will throw for field types without Content
+ uno::Any aValue(xFieldProperties->getPropertyValue(
+ getPropertyName(PROP_CONTENT)));
+ aValue >>= sValue;
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName(bHasContent && sValue.isEmpty()? PROP_CONTENT : PROP_CURRENT_PRESENTATION),
+ uno::Any( rResult ));
+
+ // LO always automatically updates a DocInfo field from the File-Properties-Custom Prop
+ // while MS Word requires the user to manually refresh the field (with F9).
+ // In other words, Word lets the field to be out of sync with the controlling variable.
+ // Marking as FIXEDFLD solves the automatic replacement problem, but of course prevents
+ // Writer from making any changes, even on an F9 refresh.
+ OUString sVariable = pContext->GetVariableValue();
+ if (rResult.getLength() != sVariable.getLength())
+ {
+ sal_Int32 nLen = sVariable.indexOf('\x0');
+ if (nLen >= 0)
+ sVariable = sVariable.copy(0, nLen);
+ }
+ bool bCustomFixedField = rResult != sVariable &&
+ xServiceInfo->supportsService("com.sun.star.text.TextField.DocInfo.Custom");
+
+ if (bCustomFixedField || xServiceInfo->supportsService(
+ "com.sun.star.text.TextField.DocInfo.CreateDateTime"))
+ {
+ // Creation time is const, don't try to update it.
+ xFieldProperties->setPropertyValue("IsFixed", uno::Any(true));
+ }
+ }
+ }
+ catch( const beans::UnknownPropertyException& )
+ {
+ //some fields don't have a CurrentPresentation (DateTime)
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "DomainMapper_Impl::SetFieldResult");
+ }
+}
+
+void DomainMapper_Impl::SetFieldFFData(const FFDataHandler::Pointer_t& pFFDataHandler)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("setFieldFFData");
+#endif
+
+ if (!m_aFieldStack.empty())
+ {
+ FieldContextPtr pContext = m_aFieldStack.back();
+ if (pContext)
+ {
+ pContext->setFFDataHandler(pFFDataHandler);
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void DomainMapper_Impl::PopFieldContext()
+{
+ if(m_bDiscardHeaderFooter)
+ return;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("popFieldContext");
+#endif
+
+ if (m_aFieldStack.empty())
+ return;
+
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( pContext )
+ {
+ if( !pContext->IsCommandCompleted() )
+ CloseFieldCommand();
+
+ if (!pContext->GetResult().isEmpty())
+ {
+ uno::Reference< beans::XPropertySet > xFieldProperties = pContext->GetCustomField();
+ if(xFieldProperties.is())
+ SetNumberFormat( pContext->GetResult(), xFieldProperties, true );
+ SetFieldResult( pContext->GetResult() );
+ }
+
+ //insert the field, TC or TOC
+ uno::Reference< text::XTextAppend > xTextAppend;
+ if (!m_aTextAppendStack.empty())
+ xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(xTextAppend.is())
+ {
+ try
+ {
+ uno::Reference< text::XTextContent > xToInsert( pContext->GetTOC(), uno::UNO_QUERY );
+ if( xToInsert.is() )
+ {
+ if (m_bStartedTOC || m_bStartIndex || m_bStartBibliography)
+ {
+ // inside SDT, last empty paragraph is also part of index
+ if (!m_bParaChanged && !m_xSdtEntryStart)
+ {
+ // End of index is the first item on a new paragraph - this paragraph
+ // should not be part of index
+ auto xCursor
+ = xTextAppend->createTextCursorByRange(
+ m_aTextAppendStack.top().xInsertPosition.is()
+ ? m_aTextAppendStack.top().xInsertPosition
+ : xTextAppend->getEnd());
+ xCursor->goLeft(1, true);
+ // delete
+ xCursor->setString(OUString());
+ // But a new paragraph should be started after the index instead
+ if (m_bIsNewDoc) // this check - see testTdf129402
+ { // where finishParagraph inserts between 2 EndNode
+ xTextAppend->finishParagraph(css::beans::PropertyValues());
+ }
+ else
+ {
+ xTextAppend->finishParagraphInsert(css::beans::PropertyValues(),
+ m_aTextAppendStack.top().xInsertPosition);
+ }
+ }
+ m_bStartedTOC = false;
+ m_aTextAppendStack.pop();
+ m_bTextInserted = false;
+ m_bParaChanged = true; // the paragraph must stay anyway
+ }
+ m_bStartTOC = false;
+ m_bStartIndex = false;
+ m_bStartBibliography = false;
+ if (IsInHeaderFooter() && m_bStartTOCHeaderFooter)
+ m_bStartTOCHeaderFooter = false;
+ }
+ else
+ {
+ xToInsert.set(pContext->GetTC(), uno::UNO_QUERY);
+ if( !xToInsert.is() && !m_bStartTOC && !m_bStartIndex && !m_bStartBibliography )
+ xToInsert = pContext->GetTextField();
+ if( xToInsert.is() && !m_bStartTOC && !m_bStartIndex && !m_bStartBibliography)
+ {
+ PropertyMap aMap;
+ // Character properties of the field show up here the
+ // last (always empty) run. Inherit character
+ // properties from there.
+ // Also merge in the properties from the field context,
+ // e.g. SdtEndBefore.
+ if (m_pLastCharacterContext)
+ aMap.InsertProps(m_pLastCharacterContext);
+ aMap.InsertProps(m_aFieldStack.back()->getProperties());
+ appendTextContent(xToInsert, aMap.GetPropertyValues());
+ CheckRedline( xToInsert->getAnchor( ) );
+ }
+ else
+ {
+ uno::Reference< text::XTextCursor > xCrsr = xTextAppend->createTextCursorByRange(pContext->GetStartRange());
+ FormControlHelper::Pointer_t pFormControlHelper(pContext->getFormControlHelper());
+ if (pFormControlHelper)
+ {
+ // xCrsr may be empty e.g. when pContext->GetStartRange() is outside of
+ // xTextAppend, like when a field started in a parent paragraph is being
+ // closed inside an anchored text box. It could be possible to throw an
+ // exception here, and abort import, but Word tolerates such invalid
+ // input, so it makes sense to do the same (tdf#152200)
+ if (xCrsr.is())
+ {
+ uno::Reference< text::XFormField > xFormField(pContext->GetFormField());
+ if (pFormControlHelper->hasFFDataHandler())
+ {
+ xToInsert.set(xFormField, uno::UNO_QUERY);
+ if (xFormField.is() && xToInsert.is())
+ {
+ PopFieldmark(m_aTextAppendStack, xCrsr,
+ pContext->GetFieldId());
+ pFormControlHelper->processField(xFormField);
+ }
+ else
+ {
+ pFormControlHelper->insertControl(xCrsr);
+ }
+ }
+ else
+ {
+ PopFieldmark(m_aTextAppendStack, xCrsr,
+ pContext->GetFieldId());
+ uno::Reference<lang::XComponent>(xFormField, uno::UNO_QUERY_THROW)->dispose(); // presumably invalid?
+ }
+ }
+ }
+ else if (!pContext->GetHyperlinkURL().isEmpty() && xCrsr.is())
+ {
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ {
+ xCrsr->gotoRange(m_aTextAppendStack.top().xInsertPosition, true);
+ }
+ else
+ {
+ xCrsr->gotoEnd(true);
+ }
+
+ // Draw components (like comments) need hyperlinks set differently
+ SvxUnoTextRangeBase* pDrawText = dynamic_cast<SvxUnoTextRangeBase*>(xCrsr.get());
+ if ( pDrawText )
+ pDrawText->attachField( std::make_unique<SvxURLField>(pContext->GetHyperlinkURL(), xCrsr->getString(), SvxURLFormat::AppDefault) );
+ else
+ {
+ uno::Reference< beans::XPropertySet > xCrsrProperties( xCrsr, uno::UNO_QUERY_THROW );
+ xCrsrProperties->setPropertyValue(getPropertyName(PROP_HYPER_LINK_U_R_L), uno::
+ Any(pContext->GetHyperlinkURL()));
+
+ if (!pContext->GetHyperlinkTarget().isEmpty())
+ xCrsrProperties->setPropertyValue("HyperLinkTarget", uno::Any(pContext->GetHyperlinkTarget()));
+
+ if (m_bStartTOC) {
+ OUString sDisplayName("Index Link");
+ xCrsrProperties->setPropertyValue("VisitedCharStyleName",uno::Any(sDisplayName));
+ xCrsrProperties->setPropertyValue("UnvisitedCharStyleName",uno::Any(sDisplayName));
+ }
+ else
+ {
+ uno::Any aAny = xCrsrProperties->getPropertyValue("CharStyleName");
+ OUString charStyle;
+ if (css::uno::fromAny(aAny, &charStyle))
+ {
+ if (charStyle.isEmpty())
+ {
+ xCrsrProperties->setPropertyValue("VisitedCharStyleName", uno::Any(OUString("Default Style")));
+ xCrsrProperties->setPropertyValue("UnvisitedCharStyleName", uno::Any(OUString("Default Style")));
+ }
+ else if (charStyle.equalsIgnoreAsciiCase("Internet Link"))
+ {
+ xCrsrProperties->setPropertyValue("CharStyleName", uno::Any(OUString("Default Style")));
+ }
+ else
+ {
+ xCrsrProperties->setPropertyValue("VisitedCharStyleName", aAny);
+ xCrsrProperties->setPropertyValue("UnvisitedCharStyleName", aAny);
+ }
+ }
+ }
+ }
+ }
+ else if (m_nStartGenericField != 0)
+ {
+ --m_nStartGenericField;
+ PopFieldmark(m_aTextAppendStack, xCrsr, pContext->GetFieldId());
+ if(m_bTextInserted)
+ {
+ m_bTextInserted = false;
+ }
+ }
+ }
+ }
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "PopFieldContext()" );
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "PopFieldContext()" );
+ }
+ }
+
+ //TOCs have to include all the imported content
+ }
+
+ std::vector<FieldParagraph> aParagraphsToFinish;
+ if (pContext)
+ {
+ aParagraphsToFinish = pContext->GetParagraphsToFinish();
+ }
+
+ //remove the field context
+ m_aFieldStack.pop_back();
+
+ // Finish the paragraph(s) now that the field is closed.
+ for (const auto& rFinish : aParagraphsToFinish)
+ {
+ finishParagraph(rFinish.m_pPropertyMap, rFinish.m_bRemove);
+ }
+}
+
+
+void DomainMapper_Impl::SetBookmarkName( const OUString& rBookmarkName )
+{
+ BookmarkMap_t::iterator aBookmarkIter = m_aBookmarkMap.find( m_sCurrentBkmkId );
+ if( aBookmarkIter != m_aBookmarkMap.end() )
+ {
+ // fields are internal bookmarks: consume redundant "normal" bookmark
+ if ( IsOpenField() )
+ {
+ FFDataHandler::Pointer_t pFFDataHandler(GetTopFieldContext()->getFFDataHandler());
+ if (pFFDataHandler && pFFDataHandler->getName() == rBookmarkName)
+ {
+ // HACK: At the END marker, StartOrEndBookmark will START
+ // a bookmark which will eventually be abandoned, not created.
+ m_aBookmarkMap.erase(aBookmarkIter);
+ return;
+ }
+ }
+
+ aBookmarkIter->second.m_sBookmarkName = m_sCurrentBkmkPrefix + rBookmarkName;
+ m_sCurrentBkmkPrefix.clear();
+ }
+ else
+ {
+ m_sCurrentBkmkName = rBookmarkName;
+ m_sCurrentBkmkPrefix.clear();
+ }
+}
+
+// This method was used as-is for DomainMapper_Impl::startOrEndPermissionRange() implementation.
+void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId )
+{
+ /*
+ * Add the dummy paragraph to handle section properties
+ * iff the first element in the section is a table. If the dummy para is not added yet, then add it;
+ * So bookmark is not attached to the wrong paragraph.
+ */
+ if(hasTableManager() && getTableManager().isInCell() && m_nTableDepth == 0 && GetIsFirstParagraphInSection()
+ && !GetIsDummyParaAddedForTableInSection() &&!GetIsTextFrameInserted())
+ {
+ AddDummyParaForTableInSection();
+ }
+
+ bool bIsAfterDummyPara = GetIsDummyParaAddedForTableInSection() && GetIsFirstParagraphInSection();
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ BookmarkMap_t::iterator aBookmarkIter = m_aBookmarkMap.find( rId );
+ //is the bookmark name already registered?
+ try
+ {
+ if( aBookmarkIter != m_aBookmarkMap.end() )
+ {
+ if (m_xTextFactory.is())
+ {
+ uno::Reference< text::XTextContent > xBookmark( m_xTextFactory->createInstance( "com.sun.star.text.Bookmark" ), uno::UNO_QUERY_THROW );
+ uno::Reference< text::XTextCursor > xCursor;
+ uno::Reference< text::XText > xText = aBookmarkIter->second.m_xTextRange->getText();
+ if( aBookmarkIter->second.m_bIsStartOfText && !bIsAfterDummyPara)
+ {
+ xCursor = xText->createTextCursorByRange( xText->getStart() );
+ }
+ else
+ {
+ xCursor = xText->createTextCursorByRange( aBookmarkIter->second.m_xTextRange );
+ xCursor->goRight( 1, false );
+ }
+
+ xCursor->gotoRange( xTextAppend->getEnd(), true );
+ // A Paragraph was recently finished, and a new Paragraph has not been started as yet
+ // then move the bookmark-End to the earlier paragraph
+ if (IsOutsideAParagraph())
+ {
+ // keep bookmark range
+ uno::Reference< text::XTextRange > xStart = xCursor->getStart();
+ xCursor->goLeft( 1, false );
+ xCursor->gotoRange(xStart, true );
+ }
+ uno::Reference< container::XNamed > xBkmNamed( xBookmark, uno::UNO_QUERY_THROW );
+ SAL_WARN_IF(aBookmarkIter->second.m_sBookmarkName.isEmpty(), "writerfilter.dmapper", "anonymous bookmark");
+ //todo: make sure the name is not used already!
+ xBkmNamed->setName( aBookmarkIter->second.m_sBookmarkName );
+ xTextAppend->insertTextContent( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW), xBookmark, !xCursor->isCollapsed() );
+ }
+ m_aBookmarkMap.erase( aBookmarkIter );
+ m_sCurrentBkmkId.clear();
+ }
+ else
+ {
+ //otherwise insert a text range as marker
+ bool bIsStart = true;
+ uno::Reference< text::XTextRange > xCurrent;
+ if (xTextAppend.is())
+ {
+ uno::Reference<text::XTextCursor> const xCursor =
+ xTextAppend->createTextCursorByRange(
+ m_aTextAppendStack.top().xInsertPosition.is()
+ ? m_aTextAppendStack.top().xInsertPosition
+ : xTextAppend->getEnd() );
+
+ if (!xCursor)
+ return;
+
+ if (!bIsAfterDummyPara)
+ bIsStart = !xCursor->goLeft(1, false);
+ xCurrent = xCursor->getStart();
+ }
+ m_sCurrentBkmkId = rId;
+ m_aBookmarkMap.emplace( rId, BookmarkInsertPosition( bIsStart, m_sCurrentBkmkName, xCurrent ) );
+ m_sCurrentBkmkName.clear();
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ //TODO: What happens to bookmarks where start and end are at different XText objects?
+ }
+}
+
+void DomainMapper_Impl::SetMoveBookmark( bool bIsFrom )
+{
+ static constexpr OUStringLiteral MoveFrom_Bookmark_NamePrefix = u"__RefMoveFrom__";
+ static constexpr OUStringLiteral MoveTo_Bookmark_NamePrefix = u"__RefMoveTo__";
+ if ( bIsFrom )
+ m_sCurrentBkmkPrefix = MoveFrom_Bookmark_NamePrefix;
+ else
+ m_sCurrentBkmkPrefix = MoveTo_Bookmark_NamePrefix;
+}
+
+void DomainMapper_Impl::setPermissionRangeEd(const OUString& user)
+{
+ PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
+ if (aPremIter != m_aPermMap.end())
+ aPremIter->second.m_Ed = user;
+ else
+ m_sCurrentPermEd = user;
+}
+
+void DomainMapper_Impl::setPermissionRangeEdGrp(const OUString& group)
+{
+ PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
+ if (aPremIter != m_aPermMap.end())
+ aPremIter->second.m_EdGrp = group;
+ else
+ m_sCurrentPermEdGrp = group;
+}
+
+// This method is based on implementation from DomainMapper_Impl::StartOrEndBookmark()
+void DomainMapper_Impl::startOrEndPermissionRange(sal_Int32 permissinId)
+{
+ /*
+ * Add the dummy paragraph to handle section properties
+ * if the first element in the section is a table. If the dummy para is not added yet, then add it;
+ * So permission is not attached to the wrong paragraph.
+ */
+ if (getTableManager().isInCell() && m_nTableDepth == 0 && GetIsFirstParagraphInSection()
+ && !GetIsDummyParaAddedForTableInSection() && !GetIsTextFrameInserted())
+ {
+ AddDummyParaForTableInSection();
+ }
+
+ if (m_aTextAppendStack.empty())
+ return;
+
+ const bool bIsAfterDummyPara = GetIsDummyParaAddedForTableInSection() && GetIsFirstParagraphInSection();
+
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ PermMap_t::iterator aPermIter = m_aPermMap.find(permissinId);
+
+ //is the bookmark name already registered?
+ try
+ {
+ if (aPermIter == m_aPermMap.end())
+ {
+ //otherwise insert a text range as marker
+ bool bIsStart = true;
+ uno::Reference< text::XTextRange > xCurrent;
+ if (xTextAppend.is())
+ {
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
+
+ if (!bIsAfterDummyPara)
+ bIsStart = !xCursor->goLeft(1, false);
+ xCurrent = xCursor->getStart();
+ }
+
+ // register the start of the new permission
+ m_sCurrentPermId = permissinId;
+ m_aPermMap.emplace(permissinId, PermInsertPosition(bIsStart, permissinId, m_sCurrentPermEd, m_sCurrentPermEdGrp, xCurrent));
+
+ // clean up
+ m_sCurrentPermEd.clear();
+ m_sCurrentPermEdGrp.clear();
+ }
+ else
+ {
+ if (m_xTextFactory.is())
+ {
+ uno::Reference< text::XTextCursor > xCursor;
+ uno::Reference< text::XText > xText = aPermIter->second.m_xTextRange->getText();
+ if (aPermIter->second.m_bIsStartOfText && !bIsAfterDummyPara)
+ {
+ xCursor = xText->createTextCursorByRange(xText->getStart());
+ }
+ else
+ {
+ xCursor = xText->createTextCursorByRange(aPermIter->second.m_xTextRange);
+ xCursor->goRight(1, false);
+ }
+
+ xCursor->gotoRange(xTextAppend->getEnd(), true);
+ // A Paragraph was recently finished, and a new Paragraph has not been started as yet
+ // then move the bookmark-End to the earlier paragraph
+ if (IsOutsideAParagraph())
+ {
+ xCursor->goLeft(1, false);
+ }
+
+ // create a new bookmark using specific bookmark name pattern for permissions
+ uno::Reference< text::XTextContent > xPerm(m_xTextFactory->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNamed > xPermNamed(xPerm, uno::UNO_QUERY_THROW);
+ xPermNamed->setName(aPermIter->second.createBookmarkName());
+
+ // add new bookmark
+ const bool bAbsorb = !xCursor->isCollapsed();
+ uno::Reference< text::XTextRange > xCurrent(xCursor, uno::UNO_QUERY_THROW);
+ xTextAppend->insertTextContent(xCurrent, xPerm, bAbsorb);
+ }
+
+ // remove processed permission
+ m_aPermMap.erase(aPermIter);
+
+ // clean up
+ m_sCurrentPermId = 0;
+ m_sCurrentPermEd.clear();
+ m_sCurrentPermEdGrp.clear();
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ //TODO: What happens to bookmarks where start and end are at different XText objects?
+ }
+}
+
+void DomainMapper_Impl::AddAnnotationPosition(
+ const bool bStart,
+ const sal_Int32 nAnnotationId)
+{
+ if (m_aTextAppendStack.empty())
+ return;
+
+ // Create a cursor, pointing to the current position.
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ uno::Reference<text::XTextRange> xCurrent;
+ if (xTextAppend.is())
+ {
+ uno::Reference<text::XTextCursor> xCursor;
+ if (m_bIsNewDoc)
+ xCursor = xTextAppend->createTextCursorByRange(xTextAppend->getEnd());
+ else
+ xCursor = m_aTextAppendStack.top().xCursor;
+ if (xCursor.is())
+ xCurrent = xCursor->getStart();
+ }
+
+ // And save it, to be used by PopAnnotation() later.
+ AnnotationPosition& aAnnotationPosition = m_aAnnotationPositions[ nAnnotationId ];
+ if (bStart)
+ {
+ aAnnotationPosition.m_xStart = xCurrent;
+ }
+ else
+ {
+ aAnnotationPosition.m_xEnd = xCurrent;
+ }
+ m_aAnnotationPositions[ nAnnotationId ] = aAnnotationPosition;
+}
+
+GraphicImportPtr const & DomainMapper_Impl::GetGraphicImport(GraphicImportType eGraphicImportType)
+{
+ if(!m_pGraphicImport)
+ m_pGraphicImport = new GraphicImport( m_xComponentContext, m_xTextFactory, m_rDMapper, eGraphicImportType, m_aPositionOffsets, m_aAligns, m_aPositivePercentages );
+ return m_pGraphicImport;
+}
+/*-------------------------------------------------------------------------
+ reset graphic import if the last import resulted in a shape, not a graphic
+ -----------------------------------------------------------------------*/
+void DomainMapper_Impl::ResetGraphicImport()
+{
+ m_pGraphicImport.clear();
+}
+
+
+void DomainMapper_Impl::ImportGraphic(const writerfilter::Reference< Properties >::Pointer_t& ref, GraphicImportType eGraphicImportType)
+{
+ GetGraphicImport(eGraphicImportType);
+ if( eGraphicImportType != IMPORT_AS_DETECTED_INLINE && eGraphicImportType != IMPORT_AS_DETECTED_ANCHOR )
+ {
+ //create the graphic
+ ref->resolve( *m_pGraphicImport );
+ }
+
+ //insert it into the document at the current cursor position
+
+ uno::Reference<text::XTextContent> xTextContent
+ (m_pGraphicImport->GetGraphicObject());
+
+ // In case the SDT starts with the text portion of the graphic, then set the SDT properties here.
+ bool bHasGrabBag = false;
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+ if (xPropertySet.is())
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ bHasGrabBag = xPropertySetInfo->hasPropertyByName("FrameInteropGrabBag");
+ // In case we're outside a paragraph, then the SDT properties are stored in the paragraph grab-bag, not the frame one.
+ if (!m_pSdtHelper->isInteropGrabBagEmpty() && bHasGrabBag && !m_pSdtHelper->isOutsideAParagraph())
+ {
+ comphelper::SequenceAsHashMap aFrameGrabBag(xPropertySet->getPropertyValue("FrameInteropGrabBag"));
+ aFrameGrabBag["SdtPr"] <<= m_pSdtHelper->getInteropGrabBagAndClear();
+ xPropertySet->setPropertyValue("FrameInteropGrabBag", uno::Any(aFrameGrabBag.getAsConstPropertyValueList()));
+ }
+ }
+
+ /* Set "SdtEndBefore" property on Drawing.
+ * It is required in a case when Drawing appears immediately after first run i.e.
+ * there is no text/space/tab in between two runs.
+ * In this case "SdtEndBefore" property needs to be set on Drawing.
+ */
+ if(IsSdtEndBefore())
+ {
+ if(xPropertySet.is() && bHasGrabBag)
+ {
+ uno::Sequence<beans::PropertyValue> aFrameGrabBag( comphelper::InitPropertySequence({
+ { "SdtEndBefore", uno::Any(true) }
+ }));
+ xPropertySet->setPropertyValue("FrameInteropGrabBag",uno::Any(aFrameGrabBag));
+ }
+ }
+
+
+ // Update the shape properties if it is embedded object.
+ if(m_xEmbedded.is()){
+ if (m_pGraphicImport->GetXShapeObject())
+ m_pGraphicImport->GetXShapeObject()->setPosition(
+ m_pGraphicImport->GetGraphicObjectPosition());
+
+ uno::Reference<drawing::XShape> xShape = m_pGraphicImport->GetXShapeObject();
+ UpdateEmbeddedShapeProps(xShape);
+ if (eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ uno::Reference<beans::XPropertySet> xEmbeddedProps(m_xEmbedded, uno::UNO_QUERY);
+ xEmbeddedProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ xEmbeddedProps->setPropertyValue("IsFollowingTextFlow", uno::Any(m_pGraphicImport->GetLayoutInCell()));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xEmbeddedProps->setPropertyValue("HoriOrient", xShapeProps->getPropertyValue("HoriOrient"));
+ xEmbeddedProps->setPropertyValue("HoriOrientPosition", xShapeProps->getPropertyValue("HoriOrientPosition"));
+ xEmbeddedProps->setPropertyValue("HoriOrientRelation", xShapeProps->getPropertyValue("HoriOrientRelation"));
+ xEmbeddedProps->setPropertyValue("VertOrient", xShapeProps->getPropertyValue("VertOrient"));
+ xEmbeddedProps->setPropertyValue("VertOrientPosition", xShapeProps->getPropertyValue("VertOrientPosition"));
+ xEmbeddedProps->setPropertyValue("VertOrientRelation", xShapeProps->getPropertyValue("VertOrientRelation"));
+ //tdf123873 fix missing textwrap import
+ xEmbeddedProps->setPropertyValue("TextWrap", xShapeProps->getPropertyValue("TextWrap"));
+
+ // GraphicZOrderHelper::findZOrder() was called already, so can just copy it over.
+ xEmbeddedProps->setPropertyValue("ZOrder", xShapeProps->getPropertyValue("ZOrder"));
+ }
+ }
+ //insert it into the document at the current cursor position
+ OSL_ENSURE( xTextContent.is(), "DomainMapper_Impl::ImportGraphic");
+ if( xTextContent.is())
+ {
+ bool bAppend = true;
+ // workaround for images anchored to characters: add ZWSPs around the anchoring point
+ if ( eGraphicImportType != IMPORT_AS_DETECTED_INLINE && !m_aRedlines.top().empty() )
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(xTextAppend.is())
+ {
+ try
+ {
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ xCrsr->gotoEnd(false);
+ PropertyMapPtr pEmpty(new PropertyMap());
+ appendTextPortion(u"​", pEmpty);
+ appendTextContent( xTextContent, uno::Sequence< beans::PropertyValue >() );
+ bAppend = false;
+ xCrsr->gotoEnd(false);
+ appendTextPortion(u"​", pEmpty);
+
+ m_bRedlineImageInPreviousRun = true;
+ m_previousRedline = m_currentRedline;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if ( bAppend )
+ appendTextContent( xTextContent, uno::Sequence< beans::PropertyValue >() );
+
+ if (eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR && !m_aTextAppendStack.empty())
+ {
+ // Remember this object is anchored to the current paragraph.
+ AnchoredObjectInfo aInfo;
+ aInfo.m_xAnchoredObject = xTextContent;
+ if (m_pGraphicImport)
+ {
+ // We still have the graphic import around, remember the original margin, so later
+ // SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing() can use it.
+ aInfo.m_nLeftMargin = m_pGraphicImport->GetLeftMarginOrig();
+ }
+ m_aTextAppendStack.top().m_aAnchoredObjects.push_back(aInfo);
+ }
+ else if (eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
+ {
+ m_bParaWithInlineObject = true;
+
+ // store inline images with track changes, because the anchor point
+ // to set redlining is not available yet
+ if (!m_aTextAppendStack.empty() && !m_aRedlines.top().empty() )
+ {
+ // Remember this object is anchored to the current paragraph.
+ AnchoredObjectInfo aInfo;
+ aInfo.m_xAnchoredObject = xTextContent;
+ aInfo.m_xRedlineForInline = m_aRedlines.top().back();
+ m_aTextAppendStack.top().m_aAnchoredObjects.push_back(aInfo);
+ }
+
+ }
+ }
+
+ // Clear the reference, so in case the embedded object is inside a
+ // TextFrame, we won't try to resize it (to match the size of the
+ // TextFrame) here.
+ m_xEmbedded.clear();
+ m_pGraphicImport.clear();
+}
+
+
+void DomainMapper_Impl::SetLineNumbering( sal_Int32 nLnnMod, sal_uInt32 nLnc, sal_Int32 ndxaLnn )
+{
+ if( !m_bLineNumberingSet )
+ {
+ try
+ {
+ uno::Reference< text::XLineNumberingProperties > xLineProperties( m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xProperties = xLineProperties->getLineNumberingProperties();
+ uno::Any aTrue( uno::Any( true ));
+ xProperties->setPropertyValue( getPropertyName( PROP_IS_ON ), aTrue);
+ xProperties->setPropertyValue( getPropertyName( PROP_COUNT_EMPTY_LINES ), aTrue );
+ xProperties->setPropertyValue( getPropertyName( PROP_COUNT_LINES_IN_FRAMES ), uno::Any( false ) );
+ xProperties->setPropertyValue( getPropertyName( PROP_INTERVAL ), uno::Any( static_cast< sal_Int16 >( nLnnMod )));
+ xProperties->setPropertyValue( getPropertyName( PROP_DISTANCE ), uno::Any( ConversionHelper::convertTwipToMM100(ndxaLnn) ));
+ xProperties->setPropertyValue( getPropertyName( PROP_NUMBER_POSITION ), uno::Any( style::LineNumberPosition::LEFT));
+ xProperties->setPropertyValue( getPropertyName( PROP_NUMBERING_TYPE ), uno::Any( style::NumberingType::ARABIC));
+ xProperties->setPropertyValue( getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::Any( nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newPage ));
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ m_bLineNumberingSet = true;
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( GetTextDocument(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xStyles;
+ xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xStyles;
+ lcl_linenumberingHeaderFooter( xStyles, "Header", this );
+ lcl_linenumberingHeaderFooter( xStyles, "Footer", this );
+}
+
+
+void DomainMapper_Impl::SetPageMarginTwip( PageMarElement eElement, sal_Int32 nValue )
+{
+ nValue = ConversionHelper::convertTwipToMM100(nValue);
+ switch(eElement)
+ {
+ case PAGE_MAR_TOP : m_aPageMargins.top = nValue; break;
+ case PAGE_MAR_RIGHT : m_aPageMargins.right = nValue; break;
+ case PAGE_MAR_BOTTOM : m_aPageMargins.bottom = nValue; break;
+ case PAGE_MAR_LEFT : m_aPageMargins.left = nValue; break;
+ case PAGE_MAR_HEADER : m_aPageMargins.header = nValue; break;
+ case PAGE_MAR_FOOTER : m_aPageMargins.footer = nValue; break;
+ case PAGE_MAR_GUTTER:
+ m_aPageMargins.gutter = nValue;
+ break;
+ }
+}
+
+
+PageMar::PageMar()
+ : top(ConversionHelper::convertTwipToMM100( sal_Int32(1440)))
+ // This is strange, the RTF spec says it's 1800, but it's clearly 1440 in Word
+ // OOXML seems not to specify a default value
+ , right(ConversionHelper::convertTwipToMM100( sal_Int32(1440)))
+ , bottom(top)
+ , left(right)
+ , header(ConversionHelper::convertTwipToMM100(sal_Int32(720)))
+ , footer(header)
+ , gutter(0)
+{
+}
+
+
+void DomainMapper_Impl::RegisterFrameConversion(
+ uno::Reference< text::XTextRange > const& xFrameStartRange,
+ uno::Reference< text::XTextRange > const& xFrameEndRange,
+ std::vector<beans::PropertyValue>&& rFrameProperties
+ )
+{
+ OSL_ENSURE(
+ m_aFrameProperties.empty() && !m_xFrameStartRange.is() && !m_xFrameEndRange.is(),
+ "frame properties not removed");
+ m_aFrameProperties = std::move(rFrameProperties);
+ m_xFrameStartRange = xFrameStartRange;
+ m_xFrameEndRange = xFrameEndRange;
+}
+
+
+void DomainMapper_Impl::ExecuteFrameConversion()
+{
+ if( m_xFrameStartRange.is() && m_xFrameEndRange.is() && !m_bDiscardHeaderFooter )
+ {
+ std::vector<sal_Int32> redPos, redLen;
+ try
+ {
+ uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( GetTopTextAppend(), uno::UNO_QUERY_THROW );
+ // convert redline ranges to cursor movement and character length
+ sal_Int32 redIdx;
+ lcl_CopyRedlines(GetTopTextAppend(), m_aStoredRedlines[StoredRedlines::FRAME], redPos, redLen, redIdx);
+
+ const uno::Reference< text::XTextContent >& xTextContent = xTextAppendAndConvert->convertToTextFrame(
+ m_xFrameStartRange,
+ m_xFrameEndRange,
+ comphelper::containerToSequence(m_aFrameProperties) );
+
+ uno::Reference< text::XText > xDest( xTextContent, uno::UNO_QUERY_THROW );
+ lcl_PasteRedlines(xDest, m_aStoredRedlines[StoredRedlines::FRAME], redPos, redLen, redIdx);
+ }
+ catch( const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION( "writerfilter.dmapper", "Exception caught when converting to frame");
+ }
+
+ m_bIsActualParagraphFramed = false;
+
+ if (redPos.size() == m_aStoredRedlines[StoredRedlines::FRAME].size()/3)
+ {
+ for( sal_Int32 i = m_aStoredRedlines[StoredRedlines::FRAME].size() - 1; i >= 0; --i)
+ {
+ // keep redlines of floating tables to process them in CloseSectionGroup()
+ if ( redPos[i/3] != -1 )
+ {
+ m_aStoredRedlines[StoredRedlines::FRAME].erase(m_aStoredRedlines[StoredRedlines::FRAME].begin() + i);
+ }
+ }
+ }
+ else
+ m_aStoredRedlines[StoredRedlines::FRAME].clear();
+ }
+ m_xFrameStartRange = nullptr;
+ m_xFrameEndRange = nullptr;
+ m_aFrameProperties.clear();
+}
+
+void DomainMapper_Impl::AddNewRedline( sal_uInt32 sprmId )
+{
+ RedlineParamsPtr pNew( new RedlineParams );
+ pNew->m_nToken = XML_mod;
+ if ( !m_bIsParaMarkerChange )
+ {
+ // <w:rPrChange> applies to the whole <w:r>, <w:pPrChange> applies to the whole <w:p>,
+ // so keep those two in CONTEXT_CHARACTERS and CONTEXT_PARAGRAPH, which will take
+ // care of their scope (i.e. when they should be used and discarded).
+ // Let's keep the rest the same way they used to be handled (explicitly dropped
+ // from a global stack by endtrackchange), but quite possibly they should not be handled
+ // that way either (I don't know).
+ if( sprmId == NS_ooxml::LN_EG_RPrContent_rPrChange )
+ GetTopContextOfType( CONTEXT_CHARACTER )->Redlines().push_back( pNew );
+ else if( sprmId == NS_ooxml::LN_CT_PPr_pPrChange )
+ GetTopContextOfType( CONTEXT_PARAGRAPH )->Redlines().push_back( pNew );
+ else if( sprmId != NS_ooxml::LN_CT_ParaRPr_rPrChange )
+ m_aRedlines.top().push_back( pNew );
+ }
+ else
+ {
+ m_pParaMarkerRedline = pNew;
+ }
+ // Newly read data will go into this redline.
+ m_currentRedline = pNew;
+}
+
+void DomainMapper_Impl::SetCurrentRedlineIsRead()
+{
+ m_currentRedline.clear();
+}
+
+sal_Int32 DomainMapper_Impl::GetCurrentRedlineToken( ) const
+{
+ assert(m_currentRedline);
+ return m_currentRedline->m_nToken;
+}
+
+void DomainMapper_Impl::SetCurrentRedlineAuthor( const OUString& sAuthor )
+{
+ if (!m_xAnnotationField.is())
+ {
+ if (m_currentRedline)
+ m_currentRedline->m_sAuthor = sAuthor;
+ else
+ SAL_INFO("writerfilter.dmapper", "numberingChange not implemented");
+ }
+ else
+ m_xAnnotationField->setPropertyValue("Author", uno::Any(sAuthor));
+}
+
+void DomainMapper_Impl::SetCurrentRedlineInitials( const OUString& sInitials )
+{
+ if (m_xAnnotationField.is())
+ m_xAnnotationField->setPropertyValue("Initials", uno::Any(sInitials));
+}
+
+void DomainMapper_Impl::SetCurrentRedlineDate( const OUString& sDate )
+{
+ if (!m_xAnnotationField.is())
+ {
+ if (m_currentRedline)
+ m_currentRedline->m_sDate = sDate;
+ else
+ SAL_INFO("writerfilter.dmapper", "numberingChange not implemented");
+ }
+ else
+ m_xAnnotationField->setPropertyValue("DateTimeValue", uno::Any(ConversionHelper::ConvertDateStringToDateTime(sDate)));
+}
+
+void DomainMapper_Impl::SetCurrentRedlineId( sal_Int32 sId )
+{
+ if (m_xAnnotationField.is())
+ {
+ m_nAnnotationId = sId;
+ }
+ else
+ {
+ // This should be an assert, but somebody had the smart idea to reuse this function also for comments and whatnot,
+ // and in some cases the id is actually not handled, which may be in fact a bug.
+ if( !m_currentRedline)
+ SAL_INFO("writerfilter.dmapper", "no current redline");
+ }
+}
+
+void DomainMapper_Impl::SetCurrentRedlineToken( sal_Int32 nToken )
+{
+ assert(m_currentRedline);
+ m_currentRedline->m_nToken = nToken;
+}
+
+void DomainMapper_Impl::SetCurrentRedlineRevertProperties( const uno::Sequence<beans::PropertyValue>& aProperties )
+{
+ assert(m_currentRedline);
+ m_currentRedline->m_aRevertProperties = aProperties;
+}
+
+
+// This removes only the last redline stored here, those stored in contexts are automatically removed when
+// the context is destroyed.
+void DomainMapper_Impl::RemoveTopRedline( )
+{
+ if (m_aRedlines.top().empty())
+ {
+ if (GetFootnoteCount() > -1 || GetEndnoteCount() > -1)
+ return;
+ SAL_WARN("writerfilter.dmapper", "RemoveTopRedline called with empty stack");
+ throw uno::Exception("RemoveTopRedline failed", nullptr);
+ }
+ m_aRedlines.top().pop_back( );
+ m_currentRedline.clear();
+}
+
+void DomainMapper_Impl::ApplySettingsTable()
+{
+ if (!(m_pSettingsTable && m_xTextFactory.is()))
+ return;
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xTextDefaults(m_xTextFactory->createInstance("com.sun.star.text.Defaults"), uno::UNO_QUERY_THROW );
+ sal_Int32 nDefTab = m_pSettingsTable->GetDefaultTabStop();
+ xTextDefaults->setPropertyValue( getPropertyName( PROP_TAB_STOP_DISTANCE ), uno::Any(nDefTab) );
+ if (m_pSettingsTable->GetLinkStyles())
+ {
+ // If linked styles are enabled, set paragraph defaults from Word's default template
+ xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_BOTTOM_MARGIN), uno::Any(ConversionHelper::convertTwipToMM100(200)));
+ style::LineSpacing aSpacing;
+ aSpacing.Mode = style::LineSpacingMode::PROP;
+ aSpacing.Height = sal_Int16(115);
+ xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_LINE_SPACING), uno::Any(aSpacing));
+ }
+
+ if (m_pSettingsTable->GetZoomFactor() || m_pSettingsTable->GetView())
+ {
+ std::vector<beans::PropertyValue> aViewProps;
+ if (m_pSettingsTable->GetZoomFactor())
+ {
+ aViewProps.emplace_back("ZoomFactor", -1, uno::Any(m_pSettingsTable->GetZoomFactor()), beans::PropertyState_DIRECT_VALUE);
+ aViewProps.emplace_back("VisibleBottom", -1, uno::Any(sal_Int32(0)), beans::PropertyState_DIRECT_VALUE);
+ aViewProps.emplace_back("ZoomType", -1,
+ uno::Any(m_pSettingsTable->GetZoomType()),
+ beans::PropertyState_DIRECT_VALUE);
+ }
+ rtl::Reference< comphelper::IndexedPropertyValuesContainer > xBox = new comphelper::IndexedPropertyValuesContainer();
+ xBox->insertByIndex(sal_Int32(0), uno::Any(comphelper::containerToSequence(aViewProps)));
+ uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_xTextDocument, uno::UNO_QUERY);
+ xViewDataSupplier->setViewData(xBox);
+ }
+
+ uno::Reference< beans::XPropertySet > xSettings(m_xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+
+ if (m_pSettingsTable->GetDoNotExpandShiftReturn())
+ xSettings->setPropertyValue( "DoNotJustifyLinesWithManualBreak", uno::Any(true) );
+ if (m_pSettingsTable->GetUsePrinterMetrics())
+ xSettings->setPropertyValue("PrinterIndependentLayout", uno::Any(document::PrinterIndependentLayout::DISABLED));
+ if( m_pSettingsTable->GetEmbedTrueTypeFonts())
+ xSettings->setPropertyValue( getPropertyName( PROP_EMBED_FONTS ), uno::Any(true) );
+ if( m_pSettingsTable->GetEmbedSystemFonts())
+ xSettings->setPropertyValue( getPropertyName( PROP_EMBED_SYSTEM_FONTS ), uno::Any(true) );
+ xSettings->setPropertyValue("AddParaTableSpacing", uno::Any(m_pSettingsTable->GetDoNotUseHTMLParagraphAutoSpacing()));
+ if (m_pSettingsTable->GetNoLeading())
+ {
+ xSettings->setPropertyValue("AddExternalLeading", uno::Any(!m_pSettingsTable->GetNoLeading()));
+ }
+ if( m_pSettingsTable->GetProtectForm() )
+ xSettings->setPropertyValue("ProtectForm", uno::Any( true ));
+ if( m_pSettingsTable->GetReadOnly() )
+ xSettings->setPropertyValue("LoadReadonly", uno::Any( true ));
+ if (m_pSettingsTable->GetGutterAtTop())
+ {
+ xSettings->setPropertyValue("GutterAtTop", uno::Any(true));
+ }
+ uno::Sequence<beans::PropertyValue> aWriteProtection
+ = m_pSettingsTable->GetWriteProtectionSettings();
+ if (aWriteProtection.hasElements())
+ xSettings->setPropertyValue("ModifyPasswordInfo", uno::Any(aWriteProtection));
+ }
+ catch(const uno::Exception&)
+ {
+ }
+}
+
+SectionPropertyMap * DomainMapper_Impl::GetSectionContext()
+{
+ SectionPropertyMap* pSectionContext = nullptr;
+ //the section context is not available before the first call of startSectionGroup()
+ if( !IsAnyTableImport() )
+ {
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_SECTION);
+ pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
+ }
+
+ return pSectionContext;
+}
+
+void DomainMapper_Impl::deferCharacterProperty(sal_Int32 id, const css::uno::Any& value)
+{
+ deferredCharacterProperties[ id ] = value;
+}
+
+void DomainMapper_Impl::processDeferredCharacterProperties()
+{
+ // Actually process in DomainMapper, so that it's the same source file like normal processing.
+ if( !deferredCharacterProperties.empty())
+ {
+ m_rDMapper.processDeferredCharacterProperties( deferredCharacterProperties );
+ deferredCharacterProperties.clear();
+ }
+}
+
+sal_Int32 DomainMapper_Impl::getNumberingProperty(const sal_Int32 nListId, sal_Int32 nNumberingLevel, const OUString& aProp)
+{
+ sal_Int32 nRet = 0;
+ if ( nListId < 0 )
+ return nRet;
+
+ try
+ {
+ if (nNumberingLevel < 0) // It seems it's valid to omit numbering level, and in that case it means zero.
+ nNumberingLevel = 0;
+
+ auto const pList(GetListTable()->GetList(nListId));
+ assert(pList);
+ const OUString aListName = pList->GetStyleName();
+ const uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY_THROW);
+ const uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xNumberingStyles;
+ xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles;
+ const uno::Reference<beans::XPropertySet> xStyle(xNumberingStyles->getByName(aListName), uno::UNO_QUERY);
+ const uno::Reference<container::XIndexAccess> xNumberingRules(xStyle->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+ if (xNumberingRules.is())
+ {
+ uno::Sequence<beans::PropertyValue> aProps;
+ xNumberingRules->getByIndex(nNumberingLevel) >>= aProps;
+ auto pProp = std::find_if(std::cbegin(aProps), std::cend(aProps),
+ [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; });
+ if (pProp != std::cend(aProps))
+ pProp->Value >>= nRet;
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ // This can happen when the doc contains some hand-crafted invalid list level.
+ }
+
+ return nRet;
+}
+
+sal_Int32 DomainMapper_Impl::getCurrentNumberingProperty(const OUString& aProp)
+{
+ sal_Int32 nRet = 0;
+
+ std::optional<PropertyMap::Property> pProp = m_pTopContext->getProperty(PROP_NUMBERING_RULES);
+ uno::Reference<container::XIndexAccess> xNumberingRules;
+ if (pProp)
+ xNumberingRules.set(pProp->second, uno::UNO_QUERY);
+ pProp = m_pTopContext->getProperty(PROP_NUMBERING_LEVEL);
+ // Default numbering level is the first one.
+ sal_Int32 nNumberingLevel = 0;
+ if (pProp)
+ pProp->second >>= nNumberingLevel;
+ if (xNumberingRules.is())
+ {
+ uno::Sequence<beans::PropertyValue> aProps;
+ xNumberingRules->getByIndex(nNumberingLevel) >>= aProps;
+ auto pPropVal = std::find_if(std::cbegin(aProps), std::cend(aProps),
+ [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; });
+ if (pPropVal != std::cend(aProps))
+ pPropVal->Value >>= nRet;
+ }
+
+ return nRet;
+}
+
+
+void DomainMapper_Impl::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+void DomainMapper_Impl::disableInteropGrabBag()
+{
+ m_aInteropGrabBagName.clear();
+ m_aInteropGrabBag.clear();
+ m_aSubInteropGrabBag.clear();
+}
+
+bool DomainMapper_Impl::isInteropGrabBagEnabled() const
+{
+ return !(m_aInteropGrabBagName.isEmpty());
+}
+
+void DomainMapper_Impl::appendGrabBag(std::vector<beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, const OUString& aValue)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ rInteropGrabBag.push_back(aProperty);
+}
+
+void DomainMapper_Impl::appendGrabBag(std::vector<beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, std::vector<beans::PropertyValue>& rValue)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= comphelper::containerToSequence(rValue);
+ rValue.clear();
+ rInteropGrabBag.push_back(aProperty);
+}
+
+void DomainMapper_Impl::substream(Id rName,
+ ::writerfilter::Reference<Stream>::Pointer_t const& ref)
+{
+#ifndef NDEBUG
+ size_t contextSize(m_aContextStack.size());
+ size_t propSize[NUMBER_OF_CONTEXTS];
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; ++i) {
+ propSize[i] = m_aPropertyStacks[i].size();
+ }
+#endif
+
+ // Save "has footnote" state, which is specific to a section in the body
+ // text, so state from substreams is not relevant.
+ bool bHasFtn = m_bHasFtn;
+
+ //finalize any waiting frames before starting alternate streams
+ CheckUnregisteredFrameConversion();
+ ExecuteFrameConversion();
+
+ appendTableManager();
+ // Appending a TableManager resets its TableHandler, so we need to append
+ // that as well, or tables won't be imported properly in headers/footers.
+ appendTableHandler();
+ getTableManager().startLevel();
+
+ //import of page header/footer
+ //Ensure that only one header/footer per section is pushed
+
+ switch( rName )
+ {
+ case NS_ooxml::LN_headerl:
+ PushPageHeader(SectionPropertyMap::PAGE_LEFT);
+ break;
+ case NS_ooxml::LN_headerr:
+ PushPageHeader(SectionPropertyMap::PAGE_RIGHT);
+ break;
+ case NS_ooxml::LN_headerf:
+ PushPageHeader(SectionPropertyMap::PAGE_FIRST);
+ break;
+ case NS_ooxml::LN_footerl:
+ PushPageFooter(SectionPropertyMap::PAGE_LEFT);
+ break;
+ case NS_ooxml::LN_footerr:
+ PushPageFooter(SectionPropertyMap::PAGE_RIGHT);
+ break;
+ case NS_ooxml::LN_footerf:
+ PushPageFooter(SectionPropertyMap::PAGE_FIRST);
+ break;
+ case NS_ooxml::LN_footnote:
+ case NS_ooxml::LN_endnote:
+ PushFootOrEndnote( NS_ooxml::LN_footnote == rName );
+ break;
+ case NS_ooxml::LN_annotation :
+ PushAnnotation();
+ break;
+ }
+
+ try
+ {
+ ref->resolve(m_rDMapper);
+ }
+ catch (xml::sax::SAXException const&)
+ {
+ m_bSaxError = true;
+ throw;
+ }
+
+ switch( rName )
+ {
+ case NS_ooxml::LN_headerl:
+ case NS_ooxml::LN_headerr:
+ case NS_ooxml::LN_headerf:
+ case NS_ooxml::LN_footerl:
+ case NS_ooxml::LN_footerr:
+ case NS_ooxml::LN_footerf:
+ PopPageHeaderFooter();
+ break;
+ case NS_ooxml::LN_footnote:
+ case NS_ooxml::LN_endnote:
+ PopFootOrEndnote();
+ break;
+ case NS_ooxml::LN_annotation :
+ PopAnnotation();
+ break;
+ }
+
+ getTableManager().endLevel();
+ popTableManager();
+ m_bHasFtn = bHasFtn;
+
+ switch(rName)
+ {
+ case NS_ooxml::LN_footnote:
+ case NS_ooxml::LN_endnote:
+ m_pTableHandler->setHadFootOrEndnote(true);
+ m_bHasFtn = true;
+ break;
+ }
+
+ // check that stacks are the same as before substream
+ assert(m_aContextStack.size() == contextSize);
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; ++i) {
+ assert(m_aPropertyStacks[i].size() == propSize[i]);
+ }
+}
+
+void DomainMapper_Impl::commentProps(const OUString& sId, const CommentProperties& rProps)
+{
+ m_aCommentProps[sId] = rProps;
+}
+
+
+bool DomainMapper_Impl::handlePreviousParagraphBorderInBetween() const
+{
+ if (!m_xPreviousParagraph.is())
+ return false;
+
+ // Connected borders ("ParaIsConnectBorder") are always on by default
+ // and never changed by DomainMapper. Except one case when border in
+ // between is used. So this is not the best, but easiest way to check
+ // is previous paragraph has border in between.
+ bool bConnectBorders = true;
+ m_xPreviousParagraph->getPropertyValue(getPropertyName(PROP_PARA_CONNECT_BORDERS)) >>= bConnectBorders;
+
+ if (bConnectBorders)
+ return false;
+
+ // Previous paragraph has border in between. Current one also has (since this
+ // method is called). So current paragraph will get border above, but
+ // also need to ensure, that no unexpected bottom border are remaining in previous
+ // paragraph: since ParaIsConnectBorder=false it will be displayed in unexpected way.
+ m_xPreviousParagraph->setPropertyValue(getPropertyName(PROP_BOTTOM_BORDER), uno::Any(table::BorderLine2()));
+
+ return true;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
new file mode 100644
index 000000000..4a8db689c
--- /dev/null
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -0,0 +1,1235 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/text/XParagraphCursor.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/XTextAppend.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <queue>
+#include <stack>
+#include <string_view>
+#include <o3tl/sorted_vector.hxx>
+#include <unordered_map>
+#include <vector>
+#include <optional>
+
+#include <dmapper/CommentProperties.hxx>
+
+#include "DomainMapper.hxx"
+#include "DomainMapperTableManager.hxx"
+#include "DomainMapperTableHandler.hxx"
+#include "PropertyMap.hxx"
+#include "FontTable.hxx"
+#include "NumberingManager.hxx"
+#include "StyleSheetTable.hxx"
+#include "SettingsTable.hxx"
+#include "ThemeTable.hxx"
+#include "GraphicImport.hxx"
+#include "OLEHandler.hxx"
+#include "FFDataHandler.hxx"
+#include "SmartTagHandler.hxx"
+#include "FormControlHelper.hxx"
+#include <map>
+
+namespace com::sun::star{
+ namespace awt{
+ struct Size;
+ }
+ namespace lang{
+ class XMultiServiceFactory;
+ struct Locale;
+ }
+ namespace text
+ {
+ class XTextField;
+ class XTextFrame;
+ class XFormField;
+ }
+ namespace beans{ class XPropertySet;}
+}
+
+namespace writerfilter::ooxml {
+ class OOXMLDocument;
+}
+
+namespace writerfilter::dmapper {
+
+class SdtHelper;
+
+struct PageMar
+{
+ sal_Int32 top;
+ sal_Int32 right;
+ sal_Int32 bottom;
+ sal_Int32 left;
+ sal_Int32 header;
+ sal_Int32 footer;
+ sal_Int32 gutter;
+ public:
+ PageMar();
+};
+enum PageMarElement
+{
+ PAGE_MAR_TOP,
+ PAGE_MAR_RIGHT,
+ PAGE_MAR_BOTTOM,
+ PAGE_MAR_LEFT,
+ PAGE_MAR_HEADER,
+ PAGE_MAR_FOOTER,
+ PAGE_MAR_GUTTER
+};
+
+/// property stack element
+enum ContextType
+{
+ CONTEXT_SECTION,
+ CONTEXT_PARAGRAPH,
+ CONTEXT_CHARACTER,
+ CONTEXT_STYLESHEET,
+ CONTEXT_LIST
+};
+enum { NUMBER_OF_CONTEXTS = CONTEXT_LIST + 1 };
+
+enum BreakType
+{
+ PAGE_BREAK,
+ COLUMN_BREAK,
+ LINE_BREAK
+};
+
+/**
+ * Two special footnotes are a separator line, and a continuation line.
+ * In MSOffice, these can contain text as well, but LO doesn't implement this
+ * rarely used feature, so the separator text needs to be skipped. (tdf#123262)
+ * Three-way logic is needed because there is no guaranteed on-off event.
+ * OFF == not in footnote separator
+ * ON == in footnote separator
+ * SKIPPING == ON status has been recognized.
+ */
+enum class SkipFootnoteSeparator
+{
+ OFF,
+ ON,
+ SKIPPING
+};
+
+// type of stored redlines
+enum StoredRedlines
+{
+ FRAME = 0,
+ FOOTNOTE,
+ ENDNOTE,
+ NONE
+};
+
+/**
+ * Storage for state that is relevant outside a header/footer, but not inside it.
+ *
+ * In case some state of DomainMapper_Impl should be reset before handling the
+ * header/footer and should be restored once handling of header/footer is done,
+ * then you can use this class to do so.
+ */
+class HeaderFooterContext
+{
+ bool m_bTextInserted;
+ sal_Int32 m_nTableDepth;
+
+public:
+ explicit HeaderFooterContext(bool bTextInserted, sal_Int32 nTableDepth);
+ bool getTextInserted() const;
+ sal_Int32 getTableDepth() const;
+};
+
+/// Information about a paragraph to be finished after a field end.
+struct FieldParagraph
+{
+ PropertyMapPtr m_pPropertyMap;
+ bool m_bRemove = false;
+};
+
+/// field stack element
+class FieldContext : public virtual SvRefBase
+{
+ bool m_bFieldCommandCompleted;
+ css::uno::Reference<css::text::XTextRange> m_xStartRange;
+
+ OUString m_sCommand;
+ OUString m_sResult;
+ OUString m_sVariableValue;
+ std::optional<FieldId> m_eFieldId;
+ bool m_bFieldLocked;
+
+ css::uno::Reference<css::text::XTextField> m_xTextField;
+ css::uno::Reference<css::text::XFormField> m_xFormField;
+ css::uno::Reference<css::beans::XPropertySet> m_xTOC;
+ css::uno::Reference<css::beans::XPropertySet> m_xTC; // TOX entry
+ css::uno::Reference<css::beans::XPropertySet> m_xCustomField;
+
+ OUString m_sHyperlinkURL;
+ /// A frame for the hyperlink when one exists.
+ OUString m_sHyperlinkTarget;
+
+ FFDataHandler::Pointer_t m_pFFDataHandler;
+ FormControlHelper::Pointer_t m_pFormControlHelper;
+ /// (Character) properties of the field itself.
+ PropertyMapPtr m_pProperties;
+
+ std::vector<FieldParagraph> m_aParagraphsToFinish;
+
+public:
+ explicit FieldContext(css::uno::Reference<css::text::XTextRange> const& xStart);
+ ~FieldContext() override;
+
+ const css::uno::Reference<css::text::XTextRange>& GetStartRange() const { return m_xStartRange; }
+
+ void AppendCommand(std::u16string_view rPart);
+ const OUString& GetCommand() const {return m_sCommand; }
+
+ void SetFieldId(FieldId eFieldId ) { m_eFieldId = eFieldId; }
+ std::optional<FieldId> const & GetFieldId() const { return m_eFieldId; }
+
+ void AppendResult(std::u16string_view rResult) { m_sResult += rResult; }
+ const OUString& GetResult() const { return m_sResult; }
+
+ void CacheVariableValue(const css::uno::Any& rAny);
+ const OUString& GetVariableValue() { return m_sVariableValue; }
+
+ void SetCommandCompleted() { m_bFieldCommandCompleted = true; }
+ bool IsCommandCompleted() const { return m_bFieldCommandCompleted; }
+
+ void SetFieldLocked() { m_bFieldLocked = true; }
+ bool IsFieldLocked() const { return m_bFieldLocked; }
+
+ const css::uno::Reference<css::beans::XPropertySet>& GetCustomField() const { return m_xCustomField; }
+ void SetCustomField(css::uno::Reference<css::beans::XPropertySet> const& xCustomField) { m_xCustomField = xCustomField; }
+ const css::uno::Reference<css::text::XTextField>& GetTextField() const { return m_xTextField;}
+ void SetTextField(css::uno::Reference<css::text::XTextField> const& xTextField);
+ const css::uno::Reference<css::text::XFormField>& GetFormField() const { return m_xFormField;}
+ void SetFormField(css::uno::Reference<css::text::XFormField> const& xFormField) { m_xFormField = xFormField;}
+
+ void SetTOC(css::uno::Reference<css::beans::XPropertySet> const& xTOC) { m_xTOC = xTOC; }
+ const css::uno::Reference<css::beans::XPropertySet>& GetTOC() const { return m_xTOC; }
+
+ void SetTC(css::uno::Reference<css::beans::XPropertySet> const& xTC) { m_xTC = xTC; }
+ const css::uno::Reference<css::beans::XPropertySet>& GetTC() const { return m_xTC; }
+
+ void SetHyperlinkURL( const OUString& rURL ) { m_sHyperlinkURL = rURL; }
+ const OUString& GetHyperlinkURL() const { return m_sHyperlinkURL; }
+ void SetHyperlinkTarget(const OUString& rTarget) { m_sHyperlinkTarget = rTarget; }
+ const OUString& GetHyperlinkTarget() const { return m_sHyperlinkTarget; }
+
+ void setFFDataHandler(FFDataHandler::Pointer_t pFFDataHandler) { m_pFFDataHandler = pFFDataHandler; }
+ const FFDataHandler::Pointer_t& getFFDataHandler() const { return m_pFFDataHandler; }
+
+ void setFormControlHelper(FormControlHelper::Pointer_t pFormControlHelper) { m_pFormControlHelper = pFormControlHelper; }
+ const FormControlHelper::Pointer_t& getFormControlHelper() const { return m_pFormControlHelper; }
+ const PropertyMapPtr& getProperties() const { return m_pProperties; }
+
+ ::std::vector<OUString> GetCommandParts() const;
+
+ std::vector<FieldParagraph>& GetParagraphsToFinish() { return m_aParagraphsToFinish; }
+};
+
+struct TextAppendContext
+{
+ css::uno::Reference<css::text::XTextAppend> xTextAppend;
+ css::uno::Reference<css::text::XTextRange> xInsertPosition;
+ css::uno::Reference<css::text::XParagraphCursor> xCursor;
+ ParagraphPropertiesPtr pLastParagraphProperties;
+
+ /**
+ * Objects anchored to the current paragraph, may affect the paragraph
+ * spacing.
+ */
+ std::vector<AnchoredObjectInfo> m_aAnchoredObjects;
+
+ inline TextAppendContext(const css::uno::Reference<css::text::XTextAppend>& xAppend, const css::uno::Reference<css::text::XTextCursor>& xCur);
+};
+
+struct AnchoredContext
+{
+ css::uno::Reference<css::text::XTextContent> xTextContent;
+ bool bToRemove;
+
+ explicit AnchoredContext(const css::uno::Reference<css::text::XTextContent>& xContent)
+ : xTextContent(xContent), bToRemove(false)
+ {
+ }
+};
+
+typedef tools::SvRef<FieldContext> FieldContextPtr;
+
+/*-------------------------------------------------------------------------
+ extended tab stop struct
+ -----------------------------------------------------------------------*/
+struct DeletableTabStop : public css::style::TabStop
+{
+ bool bDeleted;
+ explicit DeletableTabStop()
+ : bDeleted(false)
+ {
+ FillChar = ' '; // same default as SvxXMLTabStopContext_Impl
+ }
+ DeletableTabStop(const css::style::TabStop& rTabStop)
+ : TabStop(rTabStop),
+ bDeleted(false)
+ {
+ }
+};
+/// helper to remember bookmark start position
+struct BookmarkInsertPosition
+{
+ bool m_bIsStartOfText;
+ OUString m_sBookmarkName;
+ css::uno::Reference<css::text::XTextRange> m_xTextRange;
+ BookmarkInsertPosition(bool bIsStartOfText, const OUString& rName, css::uno::Reference<css::text::XTextRange> const& xTextRange):
+ m_bIsStartOfText( bIsStartOfText ),
+ m_sBookmarkName( rName ),
+ m_xTextRange( xTextRange )
+ {}
+};
+
+struct PermInsertPosition
+{
+ bool m_bIsStartOfText;
+ sal_Int32 m_Id;
+ OUString m_Ed;
+ OUString m_EdGrp;
+
+ css::uno::Reference<css::text::XTextRange> m_xTextRange;
+
+ PermInsertPosition(bool bIsStartOfText, sal_Int32 id, const OUString& ed, const OUString& edGrp, css::uno::Reference<css::text::XTextRange> const& xTextRange)
+ : m_bIsStartOfText(bIsStartOfText)
+ , m_Id(id)
+ , m_Ed(ed)
+ , m_EdGrp(edGrp)
+ , m_xTextRange(xTextRange)
+ {}
+
+ OUString createBookmarkName() const
+ {
+ OUString bookmarkName;
+
+ assert((!m_Ed.isEmpty()) || (!m_EdGrp.isEmpty()));
+
+ if (m_Ed.isEmpty())
+ {
+ bookmarkName += "permission-for-group:" +
+ OUString::number(m_Id) +
+ ":" +
+ m_EdGrp;
+ }
+ else
+ {
+ bookmarkName += "permission-for-user:" +
+ OUString::number(m_Id) +
+ ":" +
+ m_Ed;
+ }
+
+ //todo: make sure the name is not used already!
+ return bookmarkName;
+ }
+};
+
+/// Stores the start/end positions of an annotation before its insertion.
+struct AnnotationPosition
+{
+ css::uno::Reference<css::text::XTextRange> m_xStart;
+ css::uno::Reference<css::text::XTextRange> m_xEnd;
+};
+
+struct RubyInfo
+{
+ OUString sRubyText;
+ OUString sRubyStyle;
+ sal_uInt32 nSprmId;
+ sal_uInt32 nRubyAlign;
+ sal_uInt32 nHps;
+ sal_uInt32 nHpsBaseText;
+
+ RubyInfo():
+ nSprmId(0),
+ nRubyAlign(0),
+ nHps(0),
+ nHpsBaseText(0)
+ {
+ }
+};
+
+struct LineNumberSettings
+{
+ sal_Int32 nDistance;
+ sal_Int32 nInterval;
+ bool bRestartAtEachPage;
+ LineNumberSettings() :
+ nDistance(-1)
+ ,nInterval(0)
+ ,bRestartAtEachPage(true)
+ {}
+
+};
+
+/// Contains information about a table that will be potentially converted to a floating one at the section end.
+struct FloatingTableInfo
+{
+ css::uno::Reference<css::text::XTextRange> m_xStart;
+ css::uno::Reference<css::text::XTextRange> m_xEnd;
+ css::uno::Sequence<css::beans::PropertyValue> m_aFrameProperties;
+ sal_Int32 m_nTableWidth;
+ sal_Int32 m_nTableWidthType;
+ /// Break type of the section that contains this table.
+ sal_Int32 m_nBreakType = -1;
+ /// Tables in footnotes and endnotes are always floating
+ bool m_bConvertToFloatingInFootnote = false;
+
+ FloatingTableInfo(css::uno::Reference<css::text::XTextRange> const& xStart,
+ css::uno::Reference<css::text::XTextRange> const& xEnd,
+ const css::uno::Sequence<css::beans::PropertyValue>& aFrameProperties,
+ sal_Int32 nTableWidth, sal_Int32 nTableWidthType, bool bConvertToFloatingInFootnote)
+ : m_xStart(xStart),
+ m_xEnd(xEnd),
+ m_aFrameProperties(aFrameProperties),
+ m_nTableWidth(nTableWidth),
+ m_nTableWidthType(nTableWidthType),
+ m_bConvertToFloatingInFootnote(bConvertToFloatingInFootnote)
+ {
+ }
+ css::uno::Any getPropertyValue(std::u16string_view propertyName);
+};
+
+/// Stores original/in-file-format info about a single anchored object.
+struct AnchoredObjectInfo
+{
+ css::uno::Reference<css::text::XTextContent> m_xAnchoredObject;
+ sal_Int32 m_nLeftMargin = 0;
+ RedlineParamsPtr m_xRedlineForInline;
+};
+
+/// Stores info about objects anchored to a given paragraph.
+struct AnchoredObjectsInfo
+{
+ css::uno::Reference<css::text::XTextRange> m_xParagraph;
+ std::vector<AnchoredObjectInfo> m_aAnchoredObjects;
+};
+
+struct SymbolData
+{
+ sal_Unicode cSymbol;
+ OUString sFont;
+ SymbolData():
+ cSymbol(),
+ sFont()
+ { }
+};
+
+class DomainMapper;
+class DomainMapper_Impl final
+{
+public:
+ typedef std::map < OUString, BookmarkInsertPosition > BookmarkMap_t;
+ typedef std::map < sal_Int32, PermInsertPosition > PermMap_t;
+
+private:
+ SourceDocumentType m_eDocumentType;
+ DomainMapper& m_rDMapper;
+ writerfilter::ooxml::OOXMLDocument* m_pOOXMLDocument;
+ OUString m_aBaseUrl;
+ css::uno::Reference<css::text::XTextDocument> m_xTextDocument;
+ css::uno::Reference<css::beans::XPropertySet> m_xDocumentSettings;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xTextFactory;
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+ css::uno::Reference<css::container::XNameContainer> m_xPageStyles1;
+ // cache next available number, expensive to repeatedly compute
+ std::optional<int> m_xNextUnusedPageStyleNo;
+ css::uno::Reference<css::container::XNameContainer> m_xCharacterStyles;
+ // cache next available number, expensive to repeatedly compute
+ std::optional<int> m_xNextUnusedCharacterStyleNo;
+ css::uno::Reference<css::text::XText> m_xBodyText;
+ css::uno::Reference<css::text::XTextContent> m_xEmbedded;
+
+ std::stack<TextAppendContext> m_aTextAppendStack;
+ std::stack<AnchoredContext> m_aAnchoredStack;
+ std::stack<HeaderFooterContext> m_aHeaderFooterStack;
+ std::stack<std::pair<TextAppendContext, bool>> m_aHeaderFooterTextAppendStack;
+ std::deque<FieldContextPtr> m_aFieldStack;
+ bool m_bForceGenericFields;
+ /// Type of decimal symbol associated to the document language in Writer locale definition
+ bool m_bIsDecimalComma;
+ bool m_bSetUserFieldContent;
+ bool m_bSetCitation;
+ bool m_bSetDateValue;
+ bool m_bIsFirstSection;
+ bool m_bIsColumnBreakDeferred;
+ bool m_bIsPageBreakDeferred;
+ sal_Int32 m_nLineBreaksDeferred;
+ /// If we want to set "sdt end" on the next character context.
+ bool m_bSdtEndDeferred;
+ /// If we want to set "paragraph sdt end" on the next paragraph context.
+ bool m_bParaSdtEndDeferred;
+ bool m_bStartTOC;
+ bool m_bStartTOCHeaderFooter;
+ /// If we got any text that is the pre-rendered result of the TOC field.
+ bool m_bStartedTOC;
+ bool m_bStartIndex;
+ bool m_bStartBibliography;
+ unsigned int m_nStartGenericField;
+ bool m_bTextInserted;
+ LineNumberSettings m_aLineNumberSettings;
+
+ BookmarkMap_t m_aBookmarkMap;
+ OUString m_sCurrentBkmkId;
+ OUString m_sCurrentBkmkName;
+ OUString m_sCurrentBkmkPrefix;
+
+ PermMap_t m_aPermMap;
+ sal_Int32 m_sCurrentPermId;
+ OUString m_sCurrentPermEd;
+ OUString m_sCurrentPermEdGrp;
+
+ PageMar m_aPageMargins;
+ SymbolData m_aSymbolData;
+
+ // TableManagers are stacked: one for each stream to avoid any confusion
+ std::stack< tools::SvRef< DomainMapperTableManager > > m_aTableManagers;
+ tools::SvRef<DomainMapperTableHandler> m_pTableHandler;
+ // List of document lists overrides. They are applied only once on first occurrence in document
+ o3tl::sorted_vector<sal_Int32> m_aListOverrideApplied;
+
+ //each context needs a stack of currently used attributes
+ std::stack<PropertyMapPtr> m_aPropertyStacks[NUMBER_OF_CONTEXTS];
+ std::stack<ContextType> m_aContextStack;
+ std::queue<std::optional<sal_Int16>> m_aFrameDirectionQueue;
+ bool m_bFrameDirectionSet;
+ FontTablePtr m_pFontTable;
+ ListsManager::Pointer m_pListTable;
+ std::deque< css::uno::Reference<css::drawing::XShape> > m_aPendingShapes;
+ StyleSheetTablePtr m_pStyleSheetTable;
+ ThemeTablePtr m_pThemeTable;
+ SettingsTablePtr m_pSettingsTable;
+ GraphicImportPtr m_pGraphicImport;
+
+
+ PropertyMapPtr m_pTopContext;
+ PropertyMapPtr m_pLastSectionContext;
+ PropertyMapPtr m_pLastCharacterContext;
+
+ ::std::vector<DeletableTabStop> m_aCurrentTabStops;
+ OUString m_sCurrentParaStyleName; //highly inaccurate. Overwritten by "overlapping" paragraphs like comments, flys.
+ OUString m_sDefaultParaStyleName; //caches the ConvertedStyleName of the default paragraph style
+ bool m_bInDocDefaultsImport;
+ bool m_bInStyleSheetImport; //in import of fonts, styles, lists or lfos
+ bool m_bInNumberingImport; //in import of numbering (i.e. numbering.xml)
+ bool m_bInAnyTableImport; //in import of fonts, styles, lists or lfos
+ enum class HeaderFooterImportState
+ {
+ none,
+ header,
+ footer,
+ } m_eInHeaderFooterImport;
+ bool m_bDiscardHeaderFooter;
+ bool m_bInFootOrEndnote;
+ bool m_bInFootnote;
+ PropertyMapPtr m_pFootnoteContext;
+ bool m_bHasFootnoteStyle;
+ bool m_bCheckFootnoteStyle;
+ /// Skip paragraphs from the <w:separator/> footnote
+ SkipFootnoteSeparator m_eSkipFootnoteState;
+ /// preload footnotes and endnotes
+ sal_Int32 m_nFootnotes; // footnote count
+ sal_Int32 m_nEndnotes; // endnote count
+ // these are the real first notes, use their content in the first notes
+ sal_Int32 m_nFirstFootnoteIndex;
+ sal_Int32 m_nFirstEndnoteIndex;
+
+ bool m_bLineNumberingSet;
+ bool m_bIsInFootnoteProperties;
+
+ RubyInfo m_aRubyInfo;
+ //registered frame properties
+ std::vector<css::beans::PropertyValue> m_aFrameProperties;
+ css::uno::Reference<css::text::XTextRange> m_xFrameStartRange;
+ css::uno::Reference<css::text::XTextRange> m_xFrameEndRange;
+
+ // Redline stack
+ std::stack< std::vector< RedlineParamsPtr > > m_aRedlines;
+ // The redline currently read, may be also stored by a context instead of m_aRedlines.
+ RedlineParamsPtr m_currentRedline;
+ RedlineParamsPtr m_previousRedline;
+ RedlineParamsPtr m_pParaMarkerRedline;
+ bool m_bIsParaMarkerChange;
+ bool m_bIsParaMarkerMove;
+ // redline data of the terminating run, if it's a moveFrom deletion or a moveTo insertion
+ RedlineParamsPtr m_pParaMarkerRedlineMove;
+ // This is for removing workaround (double ZWSPs around the anchoring point) for track
+ // changed images anchored *to* character, if it's followed by a redline text run immediately.
+ // (In that case, the image is part of a tracked text range, no need for the dummy
+ // text ZWSPs to keep the change tracking of the image in Writer.)
+ bool m_bRedlineImageInPreviousRun;
+
+ /// If the current paragraph has any runs.
+ bool m_bParaChanged;
+ bool m_bIsFirstParaInSection;
+ bool m_bIsFirstParaInSectionAfterRedline;
+ bool m_bIsFirstParaInShape = false;
+ bool m_bDummyParaAddedForTableInSection;
+ bool m_bDummyParaAddedForTableInSectionPage;
+ bool m_bTextFrameInserted;
+ bool m_bIsPreviousParagraphFramed;
+ bool m_bIsLastParaInSection;
+ bool m_bIsLastSectionGroup;
+ bool m_bIsInComments;
+ /// If the current paragraph contains section property definitions.
+ bool m_bParaSectpr;
+ bool m_bUsingEnhancedFields;
+ /// If the current paragraph is inside a structured document element.
+ bool m_bSdt;
+ bool m_bIsFirstRun;
+ bool m_bIsOutsideAParagraph;
+ /// This is a continuation of already finished paragraph - e.g., first in an index section
+ bool m_bRemoveThisParagraph = false;
+
+ css::uno::Reference< css::text::XTextCursor > xTOCMarkerCursor;
+
+ //annotation import
+ css::uno::Reference< css::beans::XPropertySet > m_xAnnotationField;
+ sal_Int32 m_nAnnotationId;
+ bool m_bAnnotationResolved = false;
+ std::unordered_map< sal_Int32, AnnotationPosition > m_aAnnotationPositions;
+
+ void SetNumberFormat(const OUString& rCommand, css::uno::Reference<css::beans::XPropertySet> const& xPropertySet, bool bDetectFormat = false);
+ /// @throws css::uno::Exception
+ css::uno::Reference<css::beans::XPropertySet> FindOrCreateFieldMaster(const char* pFieldMasterService, const OUString& rFieldMasterName);
+ css::uno::Reference<css::beans::XPropertySet> const & GetDocumentSettings();
+
+ std::map<sal_Int32, css::uno::Any> deferredCharacterProperties;
+ SmartTagHandler m_aSmartTagHandler;
+
+ css::uno::Reference<css::text::XTextRange> m_xGlossaryEntryStart;
+ css::uno::Reference<css::text::XTextRange> m_xSdtEntryStart;
+ std::stack<BookmarkInsertPosition> m_xSdtStarts;
+
+ std::queue< css::uno::Reference< css::text::XTextFrame > > m_xPendingTextBoxFrames;
+
+public:
+ css::uno::Reference<css::text::XTextRange> m_xInsertTextRange;
+ css::uno::Reference<css::text::XTextRange> m_xAltChunkStartingRange;
+ std::deque<sal_Int32> m_aFootnoteIds;
+ std::deque<sal_Int32> m_aEndnoteIds;
+
+ bool m_bIsInTextBox;
+private:
+ bool m_bIsNewDoc;
+ bool m_bIsAltChunk = false;
+ bool m_bIsReadGlossaries;
+ std::optional<sal_Int16> m_oLineBreakClear;
+
+public:
+ DomainMapper_Impl(
+ DomainMapper& rDMapper,
+ css::uno::Reference < css::uno::XComponentContext > const& xContext,
+ css::uno::Reference< css::lang::XComponent > const& xModel,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc);
+ ~DomainMapper_Impl();
+
+ void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) { if (!m_pOOXMLDocument) m_pOOXMLDocument = pDocument; };
+ writerfilter::ooxml::OOXMLDocument* getDocumentReference() const;
+
+ SectionPropertyMap* GetLastSectionContext( )
+ {
+ return dynamic_cast< SectionPropertyMap* >( m_pLastSectionContext.get( ) );
+ }
+
+ css::uno::Reference<css::container::XNameContainer> const & GetPageStyles();
+ OUString GetUnusedPageStyleName();
+ css::uno::Reference<css::container::XNameContainer> const & GetCharacterStyles();
+ OUString GetUnusedCharacterStyleName();
+ css::uno::Reference<css::text::XText> const & GetBodyText();
+ const css::uno::Reference<css::lang::XMultiServiceFactory>& GetTextFactory() const
+ {
+ return m_xTextFactory;
+ }
+ const css::uno::Reference<css::text::XTextDocument>& GetTextDocument() const
+ {
+ return m_xTextDocument;
+ }
+ void SetDocumentSettingsProperty( const OUString& rPropName, const css::uno::Any& rValue );
+
+ void CreateRedline(css::uno::Reference<css::text::XTextRange> const& xRange, const RedlineParamsPtr& pRedline);
+
+ void CheckParaMarkerRedline(css::uno::Reference<css::text::XTextRange> const& xRange);
+
+ void CheckRedline(css::uno::Reference<css::text::XTextRange> const& xRange);
+
+ void StartParaMarkerChange( );
+ void EndParaMarkerChange( );
+ void StartParaMarkerMove( );
+ void EndParaMarkerMove( );
+ void ChainTextFrames();
+
+ void PushTextBoxContent();
+ void PopTextBoxContent();
+ void AttachTextBoxContentToShape(css::uno::Reference<css::drawing::XShape> xShape);
+
+ void RemoveDummyParaForTableInSection();
+ void AddDummyParaForTableInSection();
+ void RemoveLastParagraph( );
+ void SetIsDecimalComma() { m_bIsDecimalComma = true; };
+ void SetIsLastParagraphInSection( bool bIsLast );
+ bool GetIsLastParagraphInSection() const { return m_bIsLastParaInSection;}
+ void SetRubySprmId( sal_uInt32 nSprmId) { m_aRubyInfo.nSprmId = nSprmId ; }
+ void SetRubyText( OUString const &sText, OUString const &sStyle) {
+ m_aRubyInfo.sRubyText = sText;
+ m_aRubyInfo.sRubyStyle = sStyle;
+ }
+ const RubyInfo & GetRubyInfo() const { return m_aRubyInfo;}
+ void SetRubyInfo(const RubyInfo & rInfo) { m_aRubyInfo = rInfo;}
+
+ void SetIsLastSectionGroup( bool bIsLast );
+ bool GetIsLastSectionGroup() const { return m_bIsLastSectionGroup;}
+ void SetIsFirstParagraphInSection( bool bIsFirst );
+ void SetIsFirstParagraphInSectionAfterRedline( bool bIsFirstAfterRedline );
+ bool GetIsFirstParagraphInSection( bool bAfterRedline = false ) const;
+ void SetIsFirstParagraphInShape(bool bIsFirst);
+ bool GetIsFirstParagraphInShape() const { return m_bIsFirstParaInShape; }
+ void SetIsDummyParaAddedForTableInSection( bool bIsAdded );
+ bool GetIsDummyParaAddedForTableInSection() const { return m_bDummyParaAddedForTableInSection;}
+ void SetIsDummyParaAddedForTableInSectionPage(bool bIsAdded);
+ bool GetIsDummyParaAddedForTableInSectionPage() const { return m_bDummyParaAddedForTableInSectionPage; }
+
+ /// Track if a textframe has been inserted into this section
+ void SetIsTextFrameInserted( bool bIsInserted );
+ bool GetIsTextFrameInserted() const { return m_bTextFrameInserted;}
+
+ void SetIsPreviousParagraphFramed( bool bIsFramed ) { m_bIsPreviousParagraphFramed = bIsFramed; }
+ bool GetIsPreviousParagraphFramed() const { return m_bIsPreviousParagraphFramed; }
+ void SetParaSectpr(bool bParaSectpr);
+ bool GetParaSectpr() const { return m_bParaSectpr;}
+
+ void SetSymbolChar( sal_Int32 nSymbol) { m_aSymbolData.cSymbol = sal_Unicode(nSymbol); }
+ void SetSymbolFont( OUString const &rName ) { m_aSymbolData.sFont = rName; }
+ const SymbolData & GetSymbolData() const { return m_aSymbolData;}
+
+ /// Setter method for m_bSdt.
+ void SetSdt(bool bSdt);
+
+ void PushSdt();
+ void PopSdt();
+ /// Gives access to the currently open run/inline SDTs.
+ const std::stack<BookmarkInsertPosition>& GetSdtStarts() const;
+
+ /// Getter method for m_bSdt.
+ bool GetSdt() const { return m_bSdt;}
+ bool GetParaChanged() const { return m_bParaChanged;}
+ bool GetParaHadField() const { return m_bParaHadField; }
+ bool GetRemoveThisPara() const { return m_bRemoveThisParagraph; }
+
+ void deferBreak( BreakType deferredBreakType );
+ bool isBreakDeferred( BreakType deferredBreakType );
+ void clearDeferredBreaks();
+ void clearDeferredBreak(BreakType deferredBreakType);
+
+ void setSdtEndDeferred(bool bSdtEndDeferred);
+ bool isSdtEndDeferred() const;
+ void setParaSdtEndDeferred(bool bParaSdtEndDeferred);
+ bool isParaSdtEndDeferred() const;
+
+ void finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove = false, const bool bNoNumbering = false);
+ void appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap );
+ void appendTextContent(const css::uno::Reference<css::text::XTextContent>&, const css::uno::Sequence<css::beans::PropertyValue>&);
+ void appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOleHandler );
+ void appendStarMath( const Value& v);
+ void adjustLastPara(sal_Int8 nAlign);
+ css::uno::Reference<css::beans::XPropertySet> appendTextSectionAfter(css::uno::Reference<css::text::XTextRange> const & xBefore);
+
+ /// AutoText import: each entry is placed in the separate section
+ void appendGlossaryEntry();
+ /// Remember where entry was started
+ void setGlossaryEntryStart( css::uno::Reference<css::text::XTextRange> const & xStart )
+ {
+ m_xGlossaryEntryStart = xStart;
+ }
+
+ // push the new properties onto the stack and make it the 'current' property map
+ void PushProperties(ContextType eId);
+ void PushStyleProperties(const PropertyMapPtr& pStyleProperties);
+ void PushListProperties(const PropertyMapPtr& pListProperties);
+ void PopProperties(ContextType eId);
+
+ ContextType GetTopContextType() const { return m_aContextStack.top(); }
+ const PropertyMapPtr& GetTopContext() const
+ {
+ return m_pTopContext;
+ }
+ PropertyMapPtr GetTopContextOfType(ContextType eId);
+
+ bool HasTopText() const;
+ css::uno::Reference<css::text::XTextAppend> const & GetTopTextAppend();
+ FieldContextPtr const & GetTopFieldContext();
+
+ bool HasTopAnchoredObjects() const;
+
+ FontTablePtr const & GetFontTable()
+ {
+ if(!m_pFontTable)
+ m_pFontTable = new FontTable();
+ return m_pFontTable;
+ }
+ StyleSheetTablePtr const & GetStyleSheetTable()
+ {
+ if(!m_pStyleSheetTable)
+ m_pStyleSheetTable = new StyleSheetTable( m_rDMapper, m_xTextDocument, m_bIsNewDoc );
+ return m_pStyleSheetTable;
+ }
+ OUString GetListStyleName(sal_Int32 nListId);
+ ListsManager::Pointer const & GetListTable();
+ ThemeTablePtr const & GetThemeTable()
+ {
+ if(!m_pThemeTable)
+ m_pThemeTable = new ThemeTable;
+ return m_pThemeTable;
+ }
+
+ SettingsTablePtr const & GetSettingsTable()
+ {
+ if( !m_pSettingsTable )
+ m_pSettingsTable = new SettingsTable(m_rDMapper);
+ return m_pSettingsTable;
+ }
+
+ GraphicImportPtr const & GetGraphicImport( GraphicImportType eGraphicImportType );
+ void ResetGraphicImport();
+ // this method deletes the current m_pGraphicImport after import
+ void ImportGraphic(const writerfilter::Reference< Properties>::Pointer_t&, GraphicImportType eGraphicImportType );
+
+ void InitTabStopFromStyle(const css::uno::Sequence<css::style::TabStop>& rInitTabStops);
+ void IncorporateTabStop( const DeletableTabStop &aTabStop );
+ css::uno::Sequence<css::style::TabStop> GetCurrentTabStopAndClear();
+
+ void SetCurrentParaStyleName(const OUString& sStringValue) {m_sCurrentParaStyleName = sStringValue;}
+ OUString GetCurrentParaStyleName();
+ OUString GetDefaultParaStyleName();
+
+ // specified style - including inherited properties. Indicate whether paragraph defaults should be checked.
+ css::uno::Any GetPropertyFromStyleSheet(PropertyIds eId, StyleSheetEntryPtr pEntry, const bool bDocDefaults, const bool bPara, bool* bIsDocDefault = nullptr);
+ // current paragraph style - including inherited properties
+ css::uno::Any GetPropertyFromParaStyleSheet(PropertyIds eId);
+ // context's character style - including inherited properties
+ css::uno::Any GetPropertyFromCharStyleSheet(PropertyIds eId, const PropertyMapPtr& rContext);
+ // get property first from the given context, or secondly via inheritance from styles/docDefaults
+ css::uno::Any GetAnyProperty(PropertyIds eId, const PropertyMapPtr& rContext);
+ void SetDocDefaultsImport( bool bSet ) { m_bInDocDefaultsImport = bSet;}
+ bool IsDocDefaultsImport()const { return m_bInDocDefaultsImport;}
+ void SetStyleSheetImport( bool bSet ) { m_bInStyleSheetImport = bSet;}
+ bool IsStyleSheetImport()const { return m_bInStyleSheetImport;}
+ void SetNumberingImport( bool bSet ) { m_bInNumberingImport = bSet;}
+ bool IsNumberingImport() const { return m_bInNumberingImport;}
+ void SetAnyTableImport( bool bSet ) { m_bInAnyTableImport = bSet;}
+ bool IsAnyTableImport()const { return m_bInAnyTableImport;}
+ bool IsInShape()const { return m_aAnchoredStack.size() > 0;}
+
+ void PushShapeContext(const css::uno::Reference<css::drawing::XShape>& xShape);
+ void PopShapeContext();
+ void UpdateEmbeddedShapeProps(const css::uno::Reference<css::drawing::XShape>& xShape);
+ /// Add a pending shape: it's currently inserted into the document, but it should be removed before the import finishes.
+ void PushPendingShape(const css::uno::Reference<css::drawing::XShape>& xShape);
+ /// Get the first pending shape, if there are any.
+ css::uno::Reference<css::drawing::XShape> PopPendingShape();
+
+ void PushPageHeader(SectionPropertyMap::PageType eType);
+ void PushPageFooter(SectionPropertyMap::PageType eType);
+
+ void PopPageHeaderFooter();
+ bool IsInHeaderFooter() const { return m_eInHeaderFooterImport != HeaderFooterImportState::none; }
+ void ConvertHeaderFooterToTextFrame(bool, bool);
+ static void fillEmptyFrameProperties(std::vector<css::beans::PropertyValue>& rFrameProperties, bool bSetAnchorToChar);
+
+ bool IsInTOC() const { return m_bStartTOC; }
+
+ void PushFootOrEndnote( bool bIsFootnote );
+ void PopFootOrEndnote();
+ bool IsInFootOrEndnote() const { return m_bInFootOrEndnote; }
+ bool IsInFootnote() const { return m_bInFootnote; }
+
+ void StartCustomFootnote(const PropertyMapPtr pContext);
+ void EndCustomFootnote();
+ bool IsInCustomFootnote() const { return m_bHasFootnoteStyle; }
+ bool CheckFootnoteStyle() const { return m_bCheckFootnoteStyle; }
+ void SetHasFootnoteStyle(bool bVal) { m_bHasFootnoteStyle = bVal; }
+ void SetCheckFootnoteStyle(bool bVal) { m_bCheckFootnoteStyle = bVal; }
+
+ const PropertyMapPtr& GetFootnoteContext() const { return m_pFootnoteContext; }
+
+ SkipFootnoteSeparator GetSkipFootnoteState() const { return m_eSkipFootnoteState; }
+ void SetSkipFootnoteState(SkipFootnoteSeparator eId) { m_eSkipFootnoteState = eId; }
+ sal_Int32 GetFootnoteCount() const { return m_nFootnotes; }
+ void IncrementFootnoteCount() { ++m_nFootnotes; }
+ sal_Int32 GetEndnoteCount() const { return m_nEndnotes; }
+ void IncrementEndnoteCount() { ++m_nEndnotes; }
+ bool CopyTemporaryNotes(
+ css::uno::Reference< css::text::XFootnote > xNoteSrc,
+ css::uno::Reference< css::text::XFootnote > xNoteDest );
+ void RemoveTemporaryFootOrEndnotes();
+
+ void PushAnnotation();
+ void PopAnnotation();
+
+ /// A field context starts with a cFieldStart.
+ void PushFieldContext();
+ //the current field context waits for the completion of the command
+ bool IsOpenFieldCommand() const;
+ bool IsOpenField() const;
+ //mark field in current context as locked (fixed)
+ void SetFieldLocked();
+ //collect the pieces of the command
+ void AppendFieldCommand(OUString const & rPartOfCommand);
+ void handleRubyEQField( const FieldContextPtr& pContext);
+ void handleFieldSet
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::uno::XInterface > const & xFieldInterface,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ void handleFieldAsk
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::uno::XInterface > & xFieldInterface,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ OUString convertFieldFormula(const OUString& input);
+ void handleFieldFormula
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ void handleAutoNum
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::uno::XInterface > const & xFieldInterface,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ static void handleAuthor
+ (std::u16string_view rFirstParam,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties,
+ FieldId eFieldId);
+ void handleDocProperty
+ (const FieldContextPtr& pContext,
+ OUString const& rFirstParam,
+ css::uno::Reference< css::uno::XInterface > & xFieldInterface);
+ void handleToc
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName);
+ void handleIndex
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName);
+
+ void handleBibliography
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName);
+ /// The field command has to be closed (cFieldSep appeared).
+ void CloseFieldCommand();
+ //the _current_ fields require a string type result while TOCs accept richt results
+ bool IsFieldResultAsString();
+ void AppendFieldResult(std::u16string_view rResult);
+ //apply the result text to the related field
+ void SetFieldResult(OUString const& rResult);
+ // set FFData of top field context
+ void SetFieldFFData( const FFDataHandler::Pointer_t& pFFDataHandler );
+ /// The end of field is reached (cFieldEnd appeared) - the command might still be open.
+ void PopFieldContext();
+
+ /// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
+ OUString extractTocTitle();
+ css::uno::Reference<css::beans::XPropertySet> createSectionForRange(css::uno::Reference< css::text::XTextRange > xStart, css::uno::Reference< css::text::XTextRange > xEnd, const OUString & sObjectType, bool stepLeft);
+
+ void SetBookmarkName( const OUString& rBookmarkName );
+ void StartOrEndBookmark( const OUString& rId );
+
+ void SetMoveBookmark( bool IsFrom );
+
+ void setPermissionRangeEd(const OUString& user);
+ void setPermissionRangeEdGrp(const OUString& group);
+ void startOrEndPermissionRange(sal_Int32 permissinId);
+
+ void AddAnnotationPosition(
+ const bool bStart,
+ const sal_Int32 nAnnotationId );
+
+ bool hasTableManager() const
+ {
+ return !m_aTableManagers.empty();
+ }
+
+ DomainMapperTableManager& getTableManager()
+ {
+ return *m_aTableManagers.top();
+ }
+
+ void appendTableManager( )
+ {
+ tools::SvRef<DomainMapperTableManager> pMngr(new DomainMapperTableManager());
+ m_aTableManagers.push( pMngr );
+ }
+
+ void appendTableHandler( )
+ {
+ if (m_pTableHandler)
+ m_aTableManagers.top()->setHandler(m_pTableHandler);
+ }
+
+ void popTableManager( )
+ {
+ if (hasTableManager())
+ m_aTableManagers.pop();
+ }
+
+ void SetLineNumbering( sal_Int32 nLnnMod, sal_uInt32 nLnc, sal_Int32 ndxaLnn );
+ bool IsLineNumberingSet() const {return m_bLineNumberingSet;}
+
+ DeletableTabStop m_aCurrentTabStop;
+
+ /// If we're right after the end of a table.
+ bool m_bConvertedTable = false;
+
+ bool IsOOXMLImport() const { return m_eDocumentType == SourceDocumentType::OOXML; }
+
+ bool IsRTFImport() const { return m_eDocumentType == SourceDocumentType::RTF; }
+
+ void InitPageMargins() { m_aPageMargins = PageMar(); }
+ void SetPageMarginTwip( PageMarElement eElement, sal_Int32 nValue );
+ const PageMar& GetPageMargins() const {return m_aPageMargins;}
+
+ const LineNumberSettings& GetLineNumberSettings() const { return m_aLineNumberSettings;}
+ void SetLineNumberSettings(const LineNumberSettings& rSet) { m_aLineNumberSettings = rSet;}
+
+ void SetInFootnoteProperties(bool bSet) { m_bIsInFootnoteProperties = bSet;}
+ bool IsInFootnoteProperties() const { return m_bIsInFootnoteProperties;}
+
+ bool IsInComments() const { return m_bIsInComments; };
+
+ void CheckUnregisteredFrameConversion( );
+
+ void RegisterFrameConversion(css::uno::Reference<css::text::XTextRange> const& xFrameStartRange,
+ css::uno::Reference<css::text::XTextRange> const& xFrameEndRange,
+ std::vector<css::beans::PropertyValue>&& aFrameProperties);
+ void ExecuteFrameConversion();
+
+ void AddNewRedline( sal_uInt32 sprmId );
+
+ sal_Int32 GetCurrentRedlineToken( ) const;
+ void SetCurrentRedlineAuthor( const OUString& sAuthor );
+ void SetCurrentRedlineDate( const OUString& sDate );
+ void SetCurrentRedlineId( sal_Int32 nId );
+ void SetCurrentRedlineToken( sal_Int32 nToken );
+ void SetCurrentRedlineRevertProperties( const css::uno::Sequence<css::beans::PropertyValue>& aProperties );
+ void SetCurrentRedlineIsRead();
+ void RemoveTopRedline( );
+ void SetCurrentRedlineInitials( const OUString& sInitials );
+ bool IsFirstRun() const { return m_bIsFirstRun;}
+ void SetIsFirstRun(bool bval) { m_bIsFirstRun = bval;}
+ bool IsOutsideAParagraph() const { return m_bIsOutsideAParagraph;}
+ void SetIsOutsideAParagraph(bool bval) { m_bIsOutsideAParagraph = bval;}
+
+ void ApplySettingsTable();
+
+ css::uno::Reference<css::text::XTextAppend> GetCurrentXText() {
+ return m_aTextAppendStack.empty() ? nullptr : m_aTextAppendStack.top().xTextAppend;
+ }
+
+ void NewFrameDirection() {
+ m_aFrameDirectionQueue.push(std::nullopt);
+ m_bFrameDirectionSet = false;
+ }
+ void SetFrameDirection(sal_Int16 nDirection) {
+ if (!m_bFrameDirectionSet && !m_aFrameDirectionQueue.empty()) {
+ m_aFrameDirectionQueue.back() = nDirection;
+ m_bFrameDirectionSet = true;
+ }
+ }
+ std::optional<sal_Int16> PopFrameDirection() {
+ if (m_aFrameDirectionQueue.empty())
+ return {};
+ const std::optional<sal_Int16> nDirection = m_aFrameDirectionQueue.front();
+ m_aFrameDirectionQueue.pop();
+ return nDirection;
+ }
+
+ SectionPropertyMap * GetSectionContext();
+
+ sal_Int16 GetListLevel(const StyleSheetEntryPtr& pEntry, const PropertyMapPtr& pParaContext = nullptr);
+ void ValidateListLevel(const OUString& sStyleIdentifierD);
+
+ /**
+ Used for attributes/sprms which cannot be evaluated immediately (e.g. they depend
+ on another one that comes in the same CONTEXT_CHARACTER). The property will be processed
+ again in DomainMapper::processDeferredCharacterProperties().
+ */
+ void deferCharacterProperty(sal_Int32 id, const css::uno::Any& value);
+ /**
+ Processes properties deferred using deferCharacterProperty(). To be called whenever the top
+ CONTEXT_CHARACTER is going to be used (e.g. by appendText()).
+ */
+ void processDeferredCharacterProperties();
+
+ sal_Int32 getNumberingProperty(const sal_Int32 nListId, sal_Int32 nListLevel, const OUString& aProp);
+ /// Get a property of the current numbering style's current level.
+ sal_Int32 getCurrentNumberingProperty(const OUString& aProp);
+
+ /// If we're importing into a new document, or just pasting to an existing one.
+ bool IsNewDoc() const { return m_bIsNewDoc;}
+
+ bool IsAltChunk() const { return m_bIsAltChunk;}
+
+ /// If we're importing autotext.
+ bool IsReadGlossaries() const { return m_bIsReadGlossaries;}
+
+ tools::SvRef<SdtHelper> m_pSdtHelper;
+
+ /// Document background color, applied to every page style.
+ std::optional<sal_Int32> m_oBackgroundColor;
+
+ /**
+ * This contains the raw table depth. m_nTableDepth > 0 is the same as
+ * getTableManager().isInTable(), unless we're in the first paragraph of a
+ * table, or first paragraph after a table, as the table manager is only
+ * updated once we ended the paragraph (and know if the para has the
+ * inTbl SPRM or not).
+ */
+ sal_Int32 m_nTableDepth;
+ /// Raw table cell depth.
+ sal_Int32 m_nTableCellDepth;
+ /// Table cell depth of the last finished paragraph.
+ sal_Int32 m_nLastTableCellParagraphDepth;
+
+ /// If the current section has footnotes.
+ bool m_bHasFtn;
+ /// If the current section has a footnote separator.
+ bool m_bHasFtnSep;
+
+ /// If the next tab should be ignored, used for footnotes.
+ bool m_bCheckFirstFootnoteTab;
+ bool m_bIgnoreNextTab;
+ /// Pending floating tables: they may be converted to text frames at the section end.
+ std::vector<FloatingTableInfo> m_aPendingFloatingTables;
+
+ /// Paragraphs with anchored objects in the current section.
+ std::vector<AnchoredObjectsInfo> m_aAnchoredObjectAnchors;
+
+ /// Append a property to a sub-grabbag if necessary (e.g. 'lineRule', 'auto')
+ void appendGrabBag(std::vector<css::beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, const OUString& aValue);
+ void appendGrabBag(std::vector<css::beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, std::vector<css::beans::PropertyValue>& rValue);
+
+ /// Enable, disable and check status of grabbags
+ void enableInteropGrabBag(const OUString& aName);
+ void disableInteropGrabBag();
+ bool isInteropGrabBagEnabled() const;
+
+ /// Name of m_aInteropGrabBag.
+ OUString m_aInteropGrabBagName;
+
+ /// A toplevel dmapper grabbag, like 'pPr'.
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ /// A sub-grabbag of m_aInteropGrabBag, like 'spacing'.
+ std::vector<css::beans::PropertyValue> m_aSubInteropGrabBag;
+
+ /// ST_PositionOffset values we received
+ std::pair<OUString, OUString> m_aPositionOffsets;
+ /// ST_AlignH/V values we received
+ std::pair<OUString, OUString> m_aAligns;
+ /// ST_PositivePercentage values we received
+ std::queue<OUString> m_aPositivePercentages;
+ bool isInIndexContext() const { return m_bStartIndex;}
+ bool isInBibliographyContext() const { return m_bStartBibliography;}
+ SmartTagHandler& getSmartTagHandler() { return m_aSmartTagHandler; }
+
+ void substream(Id rName, ::writerfilter::Reference<Stream>::Pointer_t const& ref);
+
+ /// If the document needs to split paragraph.
+ bool m_bIsSplitPara;
+
+ /// Check if "SdtEndBefore" property is set
+ bool IsSdtEndBefore();
+
+ bool IsDiscardHeaderFooter() const;
+
+ bool IsForceGenericFields() const { return m_bForceGenericFields; }
+
+ void SetParaAutoBefore(bool bParaAutoBefore) { m_bParaAutoBefore = bParaAutoBefore; }
+
+ /// Forget about the previous paragraph, as it's not inside the same
+ /// start/end node.
+ void ClearPreviousParagraph();
+
+ /// Check if previous paragraph has borders in between and do the border magic to it if so
+ bool handlePreviousParagraphBorderInBetween() const;
+
+ /// Handle redline text portions in a frame, footnotes and redlines:
+ /// store their data, and create them after frame creation or footnote/endnote copying
+ bool m_bIsActualParagraphFramed;
+ std::deque<css::uno::Any> m_aStoredRedlines[StoredRedlines::NONE];
+
+ bool IsParaWithInlineObject() const { return m_bParaWithInlineObject; }
+
+ css::uno::Reference< css::embed::XStorage > m_xDocumentStorage;
+
+ /// Handles <w:altChunk>.
+ void HandleAltChunk(const OUString& rStreamName);
+
+ /// Handles <w:ptab>.
+ void HandlePTab(sal_Int32 nAlignment);
+
+ /// Handles <w:br w:clear="...">.
+ void HandleLineBreakClear(sal_Int32 nClear);
+
+ /// Handles <w:br>.
+ void HandleLineBreak(const PropertyMapPtr& pPropertyMap);
+
+ void commentProps(const OUString& sId, const CommentProperties& rProps);
+
+private:
+ void PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType);
+ // Start a new index section; if needed, finish current paragraph
+ css::uno::Reference<css::beans::XPropertySet> StartIndexSectionChecked(const OUString& sServiceName);
+ std::vector<css::uno::Reference< css::drawing::XShape > > m_vTextFramesForChaining ;
+ /// Current paragraph had at least one field in it.
+ bool m_bParaHadField;
+ bool m_bSaveParaHadField;
+ css::uno::Reference<css::beans::XPropertySet> m_xPreviousParagraph;
+ /// Current paragraph has automatic before spacing.
+ bool m_bParaAutoBefore;
+ /// Current paragraph in a table is first paragraph of a cell
+ bool m_bFirstParagraphInCell;
+ bool m_bSaveFirstParagraphInCell;
+ /// Current paragraph had at least one inline object in it.
+ bool m_bParaWithInlineObject;
+ /// SAXException was seen so document will be abandoned
+ bool m_bSaxError;
+
+ std::unordered_map<OUString, CommentProperties> m_aCommentProps;
+};
+
+TextAppendContext::TextAppendContext(const css::uno::Reference<css::text::XTextAppend>& xAppend, const css::uno::Reference<css::text::XTextCursor>& xCur)
+ : xTextAppend(xAppend)
+{
+ xCursor.set(xCur, css::uno::UNO_QUERY);
+ xInsertPosition = xCursor;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FFDataHandler.cxx b/writerfilter/source/dmapper/FFDataHandler.cxx
new file mode 100644
index 000000000..507327cf8
--- /dev/null
+++ b/writerfilter/source/dmapper/FFDataHandler.cxx
@@ -0,0 +1,190 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "FFDataHandler.hxx"
+#include "TagLogger.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper {
+
+/************************
+ * class: FFDataHandler *
+ ************************/
+
+FFDataHandler::FFDataHandler() :
+LoggedProperties("FFDataHandler"),
+m_nCheckboxHeight(0),
+m_bCheckboxAutoHeight(false),
+m_nCheckboxChecked(-1),
+m_nCheckboxDefault(-1),
+m_nTextMaxLength(0)
+{
+}
+
+
+FFDataHandler::~FFDataHandler()
+{
+}
+
+
+bool FFDataHandler::getCheckboxChecked() const
+{
+ if (m_nCheckboxChecked != -1)
+ return m_nCheckboxChecked;
+ else if (m_nCheckboxDefault != -1)
+ return m_nCheckboxDefault;
+ else
+ return false;
+}
+
+
+void FFDataHandler::lcl_sprm(Sprm & r_Sprm)
+{
+ switch(r_Sprm.getId())
+ {
+ case NS_ooxml::LN_CT_FFData_name:
+ {
+ m_sName = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_helpText:
+ {
+ resolveSprm(r_Sprm);
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_statusText:
+ {
+ resolveSprm(r_Sprm);
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_entryMacro:
+ {
+ m_sEntryMacro = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_exitMacro:
+ {
+ m_sExitMacro = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFCheckBox_size:
+ {
+ m_nCheckboxHeight = r_Sprm.getValue()->getInt();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFCheckBox_sizeAuto:
+ {
+ m_bCheckboxAutoHeight = r_Sprm.getValue()->getInt();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFCheckBox_checked:
+ {
+ m_nCheckboxChecked = r_Sprm.getValue()->getInt();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFCheckBox_default:
+ {
+ m_nCheckboxDefault = r_Sprm.getValue()->getInt();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_checkBox:
+ {
+ resolveSprm(r_Sprm);
+ }
+ break;
+ case NS_ooxml::LN_CT_FFDDList_result:
+ {
+ m_sDropDownResult = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFDDList_listEntry:
+ {
+ m_DropDownEntries.push_back(r_Sprm.getValue()->getString());
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_ddList:
+ {
+ resolveSprm(r_Sprm);
+ }
+ break;
+ case NS_ooxml::LN_CT_FFTextInput_type:
+ {
+ m_sTextType = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFTextInput_default:
+ {
+ m_sTextDefault = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFTextInput_maxLength:
+ {
+ m_nTextMaxLength = r_Sprm.getValue()->getInt();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFTextInput_format:
+ {
+ m_sTextFormat = r_Sprm.getValue()->getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFData_textInput:
+ {
+ resolveSprm(r_Sprm);
+ }
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+void FFDataHandler::resolveSprm(Sprm & r_Sprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProperties = r_Sprm.getProps();
+ if( pProperties)
+ pProperties->resolve(*this);
+}
+
+void FFDataHandler::lcl_attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_FFHelpText_val:
+ {
+ m_sHelpText = val.getString();
+ }
+ break;
+ case NS_ooxml::LN_CT_FFStatusText_val:
+ {
+ m_sStatusText = val.getString();
+ }
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FFDataHandler.hxx b/writerfilter/source/dmapper/FFDataHandler.hxx
new file mode 100644
index 000000000..f8a88f5c9
--- /dev/null
+++ b/writerfilter/source/dmapper/FFDataHandler.hxx
@@ -0,0 +1,99 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include "LoggedResources.hxx"
+#include <rtl/ustring.hxx>
+#include <vector>
+namespace writerfilter::dmapper
+{
+class FFDataHandler : public LoggedProperties
+{
+public:
+ // typedefs
+ typedef ::tools::SvRef<FFDataHandler> Pointer_t;
+ typedef ::std::vector<OUString> DropDownEntries_t;
+
+ // constructor
+ FFDataHandler();
+ // destructor
+ virtual ~FFDataHandler() override;
+
+ // member: name
+ const OUString& getName() const { return m_sName; }
+
+ // member: helpText
+ const OUString& getHelpText() const { return m_sHelpText; }
+
+ // member: statusText
+ const OUString& getStatusText() const { return m_sStatusText; }
+
+ const OUString& getEntryMacro() const { return m_sEntryMacro; }
+ const OUString& getExitMacro() const { return m_sExitMacro; }
+
+ // member: checkboxHeight
+ sal_uInt32 getCheckboxHeight() const { return m_nCheckboxHeight; }
+
+ // member: checkboxAutoHeight
+ bool getCheckboxAutoHeight() const { return m_bCheckboxAutoHeight; }
+
+ // member: checkboxChecked or checkboxDefault (if the previous is not set)
+ bool getCheckboxChecked() const;
+
+ // member: dropDownResult
+ const OUString& getDropDownResult() const { return m_sDropDownResult; }
+
+ // member: dropDownEntries
+ const DropDownEntries_t& getDropDownEntries() const { return m_DropDownEntries; }
+
+ // member: textDefault
+ const OUString& getTextDefault() const { return m_sTextDefault; }
+
+ const OUString& getTextType() const { return m_sTextType; }
+ const OUString& getTextFormat() const { return m_sTextFormat; }
+ sal_uInt16 getTextMaxLength() const { return m_nTextMaxLength; }
+
+ // sprm
+ void resolveSprm(Sprm& r_sprm);
+
+private:
+ OUString m_sName;
+ OUString m_sHelpText;
+ OUString m_sStatusText;
+ OUString m_sEntryMacro;
+ OUString m_sExitMacro;
+ sal_uInt32 m_nCheckboxHeight;
+ bool m_bCheckboxAutoHeight;
+ int m_nCheckboxChecked;
+ int m_nCheckboxDefault;
+ OUString m_sDropDownResult;
+ DropDownEntries_t m_DropDownEntries;
+ OUString m_sTextDefault;
+ OUString m_sTextType;
+ OUString m_sTextFormat;
+ sal_uInt16 m_nTextMaxLength;
+
+ // sprm
+ void lcl_sprm(Sprm& r_sprm) override;
+
+ // attribute
+ void lcl_attribute(Id name, Value& val) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FieldTypes.hxx b/writerfilter/source/dmapper/FieldTypes.hxx
new file mode 100644
index 000000000..a907a7af6
--- /dev/null
+++ b/writerfilter/source/dmapper/FieldTypes.hxx
@@ -0,0 +1,305 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+namespace writerfilter::dmapper {
+
+enum FieldId
+{
+ /* ADDRESSBLOCK \d \* MERGEFORMAT -> Addressblock completely unsupported*/
+ FIELD_ADDRESSBLOCK
+ /* ADVANCE \d downvalue \l leftvalue \r rightvalue \u upvalue \x xvalue \y yvalue -> unsupported*/
+ ,FIELD_ADVANCE
+ /* ASK bookmarkname "hint" \d defaultanswer \o \* MERGEFORMAT ->
+ the hint is not always quoted, inputfield with default answer, prompt before merge (\o)
+ */
+ ,FIELD_ASK
+ /* AUTONUM \* Numberingswitch ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTONUM
+ /* AUTONUMLGL \* Numberingswitch ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTONUMLGL
+ /* AUTONUMOUT \* Numberingswitch ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTONUMOUT
+ /* AUTHOR NewAuthor \* defaultswitch \* MERGEFORMAT ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTHOR
+ /* COMMENTS "comment" \* MERGEFORMAT ->
+ Docinfo-Comments
+ */
+ ,FIELD_COMMENTS
+ /* CREATEDATE \h \* MERGEFORMAT ->
+ docinfo-created-date
+ */
+ ,FIELD_CREATEDATE
+ /* DATE \@ "number format" \s \* MERGEFORMAT ->
+ ww8filterimprovement: multiple languages now supported
+ */
+ ,FIELD_DATE
+ /* DOCPROPERTY propertyname \* MERGEFORMAT ->
+ ww8filterimprovement: some fields imported as functionally equivalent fields if possible,
+ the others imported as UserField
+ */
+ ,FIELD_DOCPROPERTY
+ /* DOCVARIABLE Name \* MERGEFORMAT ->
+ ww8filterimprovement: now imported as user fields
+ */
+ ,FIELD_DOCVARIABLE
+ /* EDITTIME \# "displayformat" \* Numberingswitch \* MERGEFORMAT ->
+ DocInfo-Modified-Date
+ ww8filterimprovement: multiple languages now supported
+ */
+ ,FIELD_EDITTIME
+ ,FIELD_EQ
+ /* FILLIN "text to fill in" \d defaultanswer \o \* MERGEFORMAT ->
+ Function-InputField
+ */
+ ,FIELD_FILLIN
+ /* FILENAME \p \* * MERGEFORMAT ->
+ file name (\p with path)
+ */
+ ,FIELD_FILENAME
+ /* FILESIZE \* NumberingType \* MERGEFORMAT ->
+ not imported in old ww8 filter, see lcl_ParseNumberingType
+ todo find alternative field
+ */
+ ,FIELD_FILESIZE
+ /* =formula \# "number format"
+ todo find alternative field
+ */
+ ,FIELD_FORMULA
+ /* FORMCHECKBOX */
+ ,FIELD_FORMCHECKBOX
+ /* FORMDROPDOWN */
+ ,FIELD_FORMDROPDOWN
+ /* FORMTEXT */
+ ,FIELD_FORMTEXT
+ /* GOTOBUTTON text \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo find alternative field
+ */
+ ,FIELD_GOTOBUTTON
+ /* HYPERLINK "link" \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ ww8filterimprovement: now imported as hyperlink
+ */
+ ,FIELD_HYPERLINK
+ /* IF condition "then text" "else text" ->
+ not imported in old ww8 filter
+ ww8filterimprovement: now imported
+ todo: condition, if text, else text still missing
+ */
+ ,FIELD_IF
+ /* INFO NameOfInfo \* MERGEFORMAT -> old
+ todo: filter imports wrong?
+ */
+ ,FIELD_INFO
+ /* INCLUDEPICTURE path \* MERGEFORMAT->
+ old filter imports an embedded picture
+ */
+ ,FIELD_INCLUDEPICTURE
+ /* KEYWORDS keyword \* defaultswitch \* Numberingswitch \* MERGEFORMAT ->
+ DocInfo Keywords
+ */
+ ,FIELD_KEYWORDS
+ /* LASTSAVEDBY \* MERGEFORMAT ->
+ DocInfo-Modified-Author
+ */
+ ,FIELD_LASTSAVEDBY
+ /* MACROBUTTON MacroName quick help text ->
+ Macro field
+ */
+ ,FIELD_MACROBUTTON
+ /* MERGEFIELD ColumName \b prefix \f suffix \* MERGEFORMAT ->
+ ww8filterimprovement: column-only API now supported
+ */
+ ,FIELD_MERGEFIELD
+ /* MERGEREC \* MERGEFORMAT ->
+ RecordNumber field, maybe without db name
+ todo: currently unchecked
+ */
+ ,FIELD_MERGEREC
+ /* MERGESEQ \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ ww8filterimprovement: now imported
+ todo: currently unchecked
+ */
+ ,FIELD_MERGESEQ
+ /* NEXT text ->
+ Next record
+ todo: currently unchecked
+ */
+ ,FIELD_NEXT
+ /* NEXTIF condition
+ todo: condition not imported
+ */
+ ,FIELD_NEXTIF
+ /* PAGE \* Numberingswitch \* MERGEFORMAT ->
+ see lcl_ParseNumberingType
+ */
+ ,FIELD_PAGE
+ ,FIELD_PAGEREF
+ ,FIELD_PRINTDATE
+ /* REF targetbkm \f \* MERGEFORMAT ->
+ imports a ShowVariable (bookmarkname)?
+ \h hyperlink to paragraph
+ \p relative to para above/below
+ \f reference number
+ \d separator number separator
+ \n paragraph number
+ \r paragraph number in relative context
+ \t suppress non delimiters
+ \w paragraph number in full context
+ \* Upper/Lower...
+ */
+ ,FIELD_REF
+ /* REVNUM \* Numberingswitch \* MERGEFORMAT ->
+ DocInfo-revision number
+ */
+ ,FIELD_REVNUM
+ /* SAVEDATE \@ "NumberFormat"\* MERGEFORMAT ->
+ DocInfo-modified-date
+ */
+ ,FIELD_SAVEDATE
+ /* SECTION \* NumberFormat \* MERGEFORMAT ->
+ not imported in old ww8 filter see lcl_ParseNumberingType
+ todo: find alternative
+ */
+ ,FIELD_SECTION
+ /* SECTIONPAGES \* NumberFormat \* MERGEFORMAT ->
+ not imported in old ww8 filter see lcl_ParseNumberingType
+ todo: find alternative
+ */
+ ,FIELD_SECTIONPAGES
+ /* SEQ sequencename \h \c \n \r \s \* MERGEFORMAT ->
+ number range name:sequencename value:sequencename+1
+ todo: only partially implemented, switches unsupported
+ */
+ ,FIELD_SEQ
+ /* SET bookmarkname newtext \* MERGEFORMAT ->
+ SetVariable bookmarkname = newtext
+ todo: not implemented yet
+ */
+ ,FIELD_SET
+ /* SKIPIF condition \* MERGEFORMAT ->
+ ??
+ todo: not implemented yet
+ */
+ ,FIELD_SKIPIF
+ /* STYLEREF stylename \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo: add an equivalent field type
+ */
+ ,FIELD_STYLEREF
+ /* SUBJECT subject \* Defaultswitch \* MERGEFORMAT ->
+ DocInfo - subject
+ */
+ ,FIELD_SUBJECT
+ /* SYMBOL symbolnumber \* MERGEFORMAT ->
+ inserts a special char (symbolnumber)
+ todo: find alternative
+ */
+ ,FIELD_SYMBOL
+ /* TEMPLATE \* Defaultswitch \* MERGEFORMAT
+ TemplateName field
+ */
+ ,FIELD_TEMPLATE
+ /* TIME \@ "number format" \* MERGEFORMAT
+ ww8filterimprovement: multiple languages now supported
+ */
+ ,FIELD_TIME
+ /* TITLE \* Defaultswitch \* MERGEFORMAT ->
+ DocInfo-title
+ */
+ ,FIELD_TITLE
+ /* USERINITIALS newinitials \* MERGEFORMAT ->
+ ExtendedUser field (SHORTCUT)
+ */
+ ,FIELD_USERINITIALS
+ /* USERADDRESS \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo: find alternative
+ */
+ ,FIELD_USERADDRESS
+ /* USERNAME newusername \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo: import as extended user field(s)
+ */
+ ,FIELD_USERNAME
+ /*
+ TOC options:
+ \a Builds a table of figures but does not include the captions's label and number
+ \b Uses a bookmark to specify area of document from which to build table of contents
+ \c Builds a table of figures of the given label
+ \d Defines the separator between sequence and page numbers
+ \f Builds a table of contents using TC entries instead of outline levels
+ \h Hyperlinks the entries and page numbers within the table of contents
+ \l Defines the TC entries field level used to build a table of contents
+ \n Builds a table of contents or a range of entries, such as 1-9, in a table of contents without page numbers
+ \o Builds a table of contents by using outline levels instead of TC entries
+ \p Defines the separator between the table entry and its page number
+ \s Builds a table of contents by using a sequence type
+ \t Builds a table of contents by using style names other than the standard outline styles
+ \u Builds a table of contents by using the applied paragraph outline level
+ \w Preserve tab characters within table entries
+ \x Preserve newline characters within table entries
+ \z Hides page numbers within the table of contents when shown in Web Layout View
+ */
+ ,FIELD_TOC
+ /*
+ TOC entry: text
+ \f TC entry in doc with multiple tables
+ \l Outline Level
+ \n Suppress page numbers
+ example: TOC "EntryText \f \l 2 \n
+ */
+ ,FIELD_TC
+ /* document statistic - number of characters
+ */
+ ,FIELD_NUMCHARS
+ /* document statistic - number of words
+ */
+ ,FIELD_NUMWORDS
+ /* document statistic - number of pages
+ */
+ ,FIELD_NUMPAGES
+ /* Document alphabetical index
+ */
+ ,FIELD_INDEX
+ /* Document alphabetical index marks
+ */
+ ,FIELD_XE
+ /**
+ * Bibliography
+ */
+ ,FIELD_BIBLIOGRAPHY
+ /* Citation
+ */
+ ,FIELD_CITATION
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FontTable.cxx b/writerfilter/source/dmapper/FontTable.cxx
new file mode 100644
index 000000000..470deff83
--- /dev/null
+++ b/writerfilter/source/dmapper/FontTable.cxx
@@ -0,0 +1,299 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "FontTable.hxx"
+#include <o3tl/deleter.hxx>
+#include <ooxml/resourceids.hxx>
+#include <vector>
+#include <sal/log.hxx>
+#include <rtl/tencinfo.h>
+#include <vcl/embeddedfontshelper.hxx>
+#include <unotools/fontdefs.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+
+struct FontTable_Impl
+{
+ std::unique_ptr<EmbeddedFontsHelper, o3tl::default_delete<EmbeddedFontsHelper>> xEmbeddedFontHelper;
+ std::vector< FontEntry::Pointer_t > aFontEntries;
+ FontEntry::Pointer_t pCurrentEntry;
+ FontTable_Impl() {}
+};
+
+FontTable::FontTable()
+: LoggedProperties("FontTable")
+, LoggedTable("FontTable")
+, LoggedStream("FontTable")
+, m_pImpl( new FontTable_Impl )
+{
+}
+
+FontTable::~FontTable()
+{
+}
+
+void FontTable::lcl_attribute(Id Name, Value & val)
+{
+ SAL_WARN_IF( !m_pImpl->pCurrentEntry, "writerfilter.dmapper", "current entry has to be set here" );
+ if(!m_pImpl->pCurrentEntry)
+ return ;
+ int nIntValue = val.getInt();
+ OUString sValue = val.getString();
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_Pitch_val:
+ if (static_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Pitch_fixed)
+ ;
+ else if (static_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Pitch_variable)
+ ;
+ else if (static_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Pitch_default)
+ ;
+ else
+ SAL_WARN("writerfilter.dmapper", "FontTable::lcl_attribute: unhandled NS_ooxml::CT_Pitch_val: " << nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Font_name:
+ m_pImpl->pCurrentEntry->sFontName = sValue;
+ break;
+ case NS_ooxml::LN_CT_Charset_val:
+ // w:characterSet has higher priority, set only if that one is not set
+ if( m_pImpl->pCurrentEntry->nTextEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ m_pImpl->pCurrentEntry->nTextEncoding = rtl_getTextEncodingFromWindowsCharset( nIntValue );
+ if( IsStarSymbol( m_pImpl->pCurrentEntry->sFontName ))
+ m_pImpl->pCurrentEntry->nTextEncoding = RTL_TEXTENCODING_SYMBOL;
+ }
+ break;
+ case NS_ooxml::LN_CT_Charset_characterSet:
+ {
+ OString tmp;
+ sValue.convertToString( &tmp, RTL_TEXTENCODING_ASCII_US, OUSTRING_TO_OSTRING_CVTFLAGS );
+ m_pImpl->pCurrentEntry->nTextEncoding = rtl_getTextEncodingFromMimeCharset( tmp.getStr() );
+ // Older LO versions used to write incorrect character set for OpenSymbol, fix.
+ if( IsStarSymbol( m_pImpl->pCurrentEntry->sFontName ))
+ m_pImpl->pCurrentEntry->nTextEncoding = RTL_TEXTENCODING_SYMBOL;
+ break;
+ }
+ default: ;
+ }
+}
+
+void FontTable::lcl_sprm(Sprm& rSprm)
+{
+ SAL_WARN_IF( !m_pImpl->pCurrentEntry, "writerfilter.dmapper", "current entry has to be set here" );
+ if(!m_pImpl->pCurrentEntry)
+ return ;
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_Font_charset:
+ case NS_ooxml::LN_CT_Font_pitch:
+ resolveSprm( rSprm );
+ break;
+ case NS_ooxml::LN_CT_Font_embedRegular:
+ case NS_ooxml::LN_CT_Font_embedBold:
+ case NS_ooxml::LN_CT_Font_embedItalic:
+ case NS_ooxml::LN_CT_Font_embedBoldItalic:
+ {
+ writerfilter::Reference< Properties >::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ EmbeddedFontHandler handler(*this, m_pImpl->pCurrentEntry->sFontName,
+ nSprmId == NS_ooxml::LN_CT_Font_embedRegular ? ""
+ : nSprmId == NS_ooxml::LN_CT_Font_embedBold ? "b"
+ : nSprmId == NS_ooxml::LN_CT_Font_embedItalic ? "i"
+ : /*NS_ooxml::LN_CT_Font_embedBoldItalic*/ "bi" );
+ pProperties->resolve( handler );
+ }
+ break;
+ }
+ case NS_ooxml::LN_CT_Font_altName:
+ break;
+ case NS_ooxml::LN_CT_Font_panose1:
+ break;
+ case NS_ooxml::LN_CT_Font_family:
+ break;
+ case NS_ooxml::LN_CT_Font_sig:
+ break;
+ case NS_ooxml::LN_CT_Font_notTrueType:
+ break;
+ default:
+ SAL_WARN("writerfilter.dmapper", "FontTable::lcl_sprm: unhandled token: " << nSprmId);
+ break;
+ }
+}
+
+void FontTable::resolveSprm(Sprm & r_Sprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProperties = r_Sprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+}
+
+void FontTable::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+ //create a new font entry
+ SAL_WARN_IF( m_pImpl->pCurrentEntry, "writerfilter.dmapper", "current entry has to be NULL here" );
+ m_pImpl->pCurrentEntry = new FontEntry;
+ ref->resolve(*this);
+ //append it to the table
+ m_pImpl->aFontEntries.push_back( m_pImpl->pCurrentEntry );
+ m_pImpl->pCurrentEntry.clear();
+}
+
+void FontTable::lcl_startSectionGroup()
+{
+}
+
+void FontTable::lcl_endSectionGroup()
+{
+}
+
+void FontTable::lcl_startParagraphGroup()
+{
+}
+
+void FontTable::lcl_endParagraphGroup()
+{
+}
+
+void FontTable::lcl_startCharacterGroup()
+{
+}
+
+void FontTable::lcl_endCharacterGroup()
+{
+}
+
+void FontTable::lcl_text(const sal_uInt8*, size_t )
+{
+}
+
+void FontTable::lcl_utext(const sal_uInt8* , size_t)
+{
+}
+
+void FontTable::lcl_props(writerfilter::Reference<Properties>::Pointer_t)
+{
+}
+
+void FontTable::lcl_table(Id, writerfilter::Reference<Table>::Pointer_t)
+{
+}
+
+void FontTable::lcl_substream(Id, ::writerfilter::Reference<Stream>::Pointer_t)
+{
+}
+
+void FontTable::lcl_startShape(uno::Reference<drawing::XShape> const&)
+{
+}
+
+void FontTable::lcl_endShape( )
+{
+}
+
+FontEntry::Pointer_t FontTable::getFontEntry(sal_uInt32 nIndex)
+{
+ return (m_pImpl->aFontEntries.size() > nIndex)
+ ? m_pImpl->aFontEntries[nIndex]
+ : FontEntry::Pointer_t();
+}
+
+sal_uInt32 FontTable::size()
+{
+ return m_pImpl->aFontEntries.size();
+}
+
+void FontTable::addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream,
+ const OUString& fontName, const char* extra,
+ std::vector<unsigned char> const & key)
+{
+ if (!m_pImpl->xEmbeddedFontHelper)
+ m_pImpl->xEmbeddedFontHelper.reset(new EmbeddedFontsHelper);
+ m_pImpl->xEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key);
+}
+
+EmbeddedFontHandler::EmbeddedFontHandler(FontTable& rFontTable, const OUString& _fontName, const char* _style )
+: LoggedProperties("EmbeddedFontHandler")
+, fontTable( rFontTable )
+, fontName( _fontName )
+, style( _style )
+{
+}
+
+EmbeddedFontHandler::~EmbeddedFontHandler()
+{
+ if( !inputStream.is())
+ return;
+ std::vector< unsigned char > key( 32 );
+ if( !fontKey.isEmpty())
+ { // key for unobfuscating
+ // 1 3 5 7 10 2 5 7 20 2 5 7 9 1 3 5
+ // {62E79491-959F-41E9-B76B-6B32631DEA5C}
+ static const int pos[ 16 ] = { 35, 33, 31, 29, 27, 25, 22, 20, 17, 15, 12, 10, 7, 5, 3, 1 };
+ for( int i = 0;
+ i < 16;
+ ++i )
+ {
+ int v1 = fontKey[ pos[ i ]];
+ int v2 = fontKey[ pos[ i ] + 1 ];
+ assert(( v1 >= '0' && v1 <= '9' ) || ( v1 >= 'A' && v1 <= 'F' ));
+ assert(( v2 >= '0' && v2 <= '9' ) || ( v2 >= 'A' && v2 <= 'F' ));
+ int val = ( v1 - ( v1 <= '9' ? '0' : 'A' - 10 )) * 16 + v2 - ( v2 <= '9' ? '0' : 'A' - 10 );
+ key[ i ] = val;
+ key[ i + 16 ] = val;
+ }
+ }
+ fontTable.addEmbeddedFont( inputStream, fontName, style, key );
+ inputStream->closeInput();
+}
+
+void EmbeddedFontHandler::lcl_attribute( Id name, Value& val )
+{
+ OUString sValue = val.getString();
+ switch( name )
+ {
+ case NS_ooxml::LN_CT_FontRel_fontKey:
+ fontKey = sValue;
+ break;
+ case NS_ooxml::LN_CT_Rel_id:
+ break;
+ case NS_ooxml::LN_CT_FontRel_subsetted:
+ break; // TODO? Let's just ignore this for now and hope
+ // it doesn't break anything.
+ case NS_ooxml::LN_inputstream: // the actual font data as stream
+ val.getAny() >>= inputStream;
+ break;
+ default:
+ break;
+ }
+}
+
+void EmbeddedFontHandler::lcl_sprm( Sprm& )
+{
+}
+
+
+}//namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FontTable.hxx b/writerfilter/source/dmapper/FontTable.hxx
new file mode 100644
index 000000000..5f32776a2
--- /dev/null
+++ b/writerfilter/source/dmapper/FontTable.hxx
@@ -0,0 +1,106 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include "LoggedResources.hxx"
+#include <com/sun/star/io/XInputStream.hpp>
+
+namespace writerfilter::dmapper
+{
+
+struct FontTable_Impl;
+struct FontEntry : public virtual SvRefBase
+{
+ typedef tools::SvRef<FontEntry> Pointer_t;
+
+ OUString sFontName;
+ sal_Int32 nTextEncoding;
+ FontEntry() :
+ nTextEncoding( RTL_TEXTENCODING_DONTKNOW )
+ {}
+};
+
+class FontTable : public LoggedProperties, public LoggedTable
+ /*,public BinaryObj*/, public LoggedStream
+{
+ std::unique_ptr<FontTable_Impl> m_pImpl;
+
+ public:
+ FontTable();
+ virtual ~FontTable() override;
+
+ sal_uInt32 size();
+ FontEntry::Pointer_t getFontEntry(sal_uInt32 nIndex);
+
+ void addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream,
+ const OUString& fontName, const char* extra,
+ std::vector<unsigned char> const & key);
+
+ private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+ void resolveSprm(Sprm & r_sprm);
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+ // Stream
+ virtual void lcl_startSectionGroup() override;
+ virtual void lcl_endSectionGroup() override;
+ virtual void lcl_startParagraphGroup() override;
+ virtual void lcl_endParagraphGroup() override;
+ virtual void lcl_startCharacterGroup() override;
+ virtual void lcl_endCharacterGroup() override;
+ virtual void lcl_text(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_utext(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_props(writerfilter::Reference<Properties>::Pointer_t ref) override;
+ virtual void lcl_table(Id name,
+ writerfilter::Reference<Table>::Pointer_t ref) override;
+ virtual void lcl_substream(Id name,
+ ::writerfilter::Reference<Stream>::Pointer_t ref) override;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ virtual void lcl_endShape( ) override;
+ virtual void lcl_startTextBoxContent() override {};
+ virtual void lcl_endTextBoxContent() override {};
+};
+typedef tools::SvRef< FontTable > FontTablePtr;
+
+class EmbeddedFontHandler : public LoggedProperties
+{
+public:
+ EmbeddedFontHandler(FontTable& rFontTable, const OUString& fontName, const char* style);
+ virtual ~EmbeddedFontHandler() override;
+private:
+ virtual void lcl_attribute( Id name, Value& val ) override;
+ virtual void lcl_sprm( Sprm& rSprm ) override;
+ FontTable& fontTable;
+ OUString fontName;
+ const char* const style;
+ OUString fontKey;
+ css::uno::Reference<css::io::XInputStream> inputStream;
+};
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FormControlHelper.cxx b/writerfilter/source/dmapper/FormControlHelper.cxx
new file mode 100644
index 000000000..e00c4bebd
--- /dev/null
+++ b/writerfilter/source/dmapper/FormControlHelper.cxx
@@ -0,0 +1,378 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <math.h>
+
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/uno/Any.hxx>
+
+#include <o3tl/safeint.hxx>
+
+#include "FormControlHelper.hxx"
+#include <xmloff/odffields.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+struct FormControlHelper::FormControlHelper_Impl : public virtual SvRefBase
+{
+ FieldId m_eFieldId;
+ awt::Size aSize;
+ uno::Reference<drawing::XDrawPage> rDrawPage;
+ uno::Reference<form::XForm> rForm;
+ uno::Reference<form::XFormComponent> rFormComponent;
+ uno::Reference<lang::XMultiServiceFactory> rServiceFactory;
+ uno::Reference<text::XTextDocument> rTextDocument;
+
+ uno::Reference<drawing::XDrawPage> const & getDrawPage();
+ uno::Reference<lang::XMultiServiceFactory> const & getServiceFactory();
+ uno::Reference<form::XForm> const & getForm();
+ uno::Reference<container::XIndexContainer> getFormComps();
+};
+
+uno::Reference<drawing::XDrawPage> const & FormControlHelper::FormControlHelper_Impl::getDrawPage()
+{
+ if (! rDrawPage.is())
+ {
+ uno::Reference<drawing::XDrawPageSupplier>
+ xDrawPageSupplier(rTextDocument, uno::UNO_QUERY);
+ if (xDrawPageSupplier.is())
+ rDrawPage = xDrawPageSupplier->getDrawPage();
+ }
+
+ return rDrawPage;
+}
+
+uno::Reference<lang::XMultiServiceFactory> const & FormControlHelper::FormControlHelper_Impl::getServiceFactory()
+{
+ if (! rServiceFactory.is())
+ rServiceFactory.set(rTextDocument, uno::UNO_QUERY);
+
+ return rServiceFactory;
+}
+
+uno::Reference<form::XForm> const & FormControlHelper::FormControlHelper_Impl::getForm()
+{
+ if (! rForm.is())
+ {
+ uno::Reference<form::XFormsSupplier> xFormsSupplier(getDrawPage(), uno::UNO_QUERY);
+
+ if (xFormsSupplier.is())
+ {
+ uno::Reference<container::XNameContainer> xFormsNamedContainer(xFormsSupplier->getForms());
+ static constexpr OUStringLiteral sDOCXForm = u"DOCX-Standard";
+
+ OUString sFormName(sDOCXForm);
+ sal_uInt16 nUnique = 0;
+
+ while (xFormsNamedContainer->hasByName(sFormName))
+ {
+ ++nUnique;
+ sFormName = sDOCXForm + OUString::number(nUnique);
+ }
+
+ uno::Reference<uno::XInterface> xForm(getServiceFactory()->createInstance("com.sun.star.form.component.Form"));
+ if (xForm.is())
+ {
+ uno::Reference<beans::XPropertySet>
+ xFormProperties(xForm, uno::UNO_QUERY);
+ uno::Any aAny(sFormName);
+ xFormProperties->setPropertyValue("Name", aAny);
+ }
+
+ rForm.set(xForm, uno::UNO_QUERY);
+
+ uno::Reference<container::XIndexContainer> xForms(xFormsNamedContainer, uno::UNO_QUERY);
+ uno::Any aAny(xForm);
+ xForms->insertByIndex(xForms->getCount(), aAny);
+ }
+ }
+
+ return rForm;
+}
+
+uno::Reference<container::XIndexContainer> FormControlHelper::FormControlHelper_Impl::getFormComps()
+{
+ uno::Reference<container::XIndexContainer> xIndexContainer(getForm(), uno::UNO_QUERY);
+
+ return xIndexContainer;
+}
+
+FormControlHelper::FormControlHelper(FieldId eFieldId,
+ uno::Reference<text::XTextDocument> const& xTextDocument,
+ FFDataHandler::Pointer_t const & pFFData)
+ : m_pFFData(pFFData), m_pImpl(new FormControlHelper_Impl)
+{
+ m_pImpl->m_eFieldId = eFieldId;
+ m_pImpl->rTextDocument = xTextDocument;
+}
+
+FormControlHelper::~FormControlHelper()
+{
+}
+
+bool FormControlHelper::createCheckbox(uno::Reference<text::XTextRange> const& xTextRange,
+ const OUString & rControlName)
+{
+ if ( !m_pFFData )
+ return false;
+ uno::Reference<lang::XMultiServiceFactory>
+ xServiceFactory(m_pImpl->getServiceFactory());
+
+ if (! xServiceFactory.is())
+ return false;
+
+ uno::Reference<uno::XInterface> xInterface = xServiceFactory->createInstance("com.sun.star.form.component.CheckBox");
+
+ if (!xInterface.is())
+ return false;
+
+ m_pImpl->rFormComponent.set(xInterface, uno::UNO_QUERY);
+ if (!m_pImpl->rFormComponent.is())
+ return false;
+
+ uno::Reference<beans::XPropertySet> xPropSet(xInterface, uno::UNO_QUERY);
+
+ sal_uInt32 nCheckBoxHeight = 16 * m_pFFData->getCheckboxHeight();
+
+ if (m_pFFData->getCheckboxAutoHeight())
+ {
+ uno::Reference<beans::XPropertySet> xTextRangeProps(xTextRange, uno::UNO_QUERY);
+
+ try
+ {
+ float fCheckBoxHeight = 0.0;
+ xTextRangeProps->getPropertyValue("CharHeight") >>= fCheckBoxHeight;
+ nCheckBoxHeight = static_cast<sal_uInt32>(floor(fCheckBoxHeight * 35.3));
+ }
+ catch (beans::UnknownPropertyException &)
+ {
+ }
+ }
+
+ m_pImpl->aSize.Width = nCheckBoxHeight;
+ m_pImpl->aSize.Height = m_pImpl->aSize.Width;
+
+ if (!m_pFFData->getStatusText().isEmpty())
+ {
+ xPropSet->setPropertyValue("HelpText", uno::Any(m_pFFData->getStatusText()));
+ }
+
+ xPropSet->setPropertyValue("DefaultState", uno::Any(m_pFFData->getCheckboxChecked()));
+
+ if (!m_pFFData->getHelpText().isEmpty())
+ {
+ xPropSet->setPropertyValue("HelpF1Text", uno::Any(m_pFFData->getHelpText()));
+ }
+
+ xPropSet->setPropertyValue("Name", uno::Any(rControlName));
+
+ return true;
+}
+
+void FormControlHelper::processField(uno::Reference<text::XFormField> const& xFormField)
+{
+ // Set field type first before adding parameters.
+ if (m_pImpl->m_eFieldId == FIELD_FORMTEXT )
+ {
+ xFormField->setFieldType(ODF_FORMTEXT);
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMCHECKBOX )
+ {
+ xFormField->setFieldType(ODF_FORMCHECKBOX);
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMDROPDOWN )
+ {
+ xFormField->setFieldType(ODF_FORMDROPDOWN);
+ }
+
+ uno::Reference<container::XNameContainer> xNameCont = xFormField->getParameters();
+ uno::Reference<container::XNamed> xNamed( xFormField, uno::UNO_QUERY );
+ if ( !(m_pFFData && xNamed.is() && xNameCont.is()) )
+ return;
+
+ OUString sTmp = m_pFFData->getEntryMacro();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "EntryMacro", uno::Any(sTmp) );
+ sTmp = m_pFFData->getExitMacro();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "ExitMacro", uno::Any(sTmp) );
+
+ sTmp = m_pFFData->getHelpText();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Help", uno::Any(sTmp) );
+
+ sTmp = m_pFFData->getStatusText();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Hint", uno::Any(sTmp) );
+
+ if (m_pImpl->m_eFieldId == FIELD_FORMTEXT )
+ {
+ sTmp = m_pFFData->getName();
+ try
+ {
+ if ( !sTmp.isEmpty() )
+ xNamed->setName( sTmp );
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter", "Set Formfield name failed");
+ }
+
+ sTmp = m_pFFData->getTextType();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Type", uno::Any(sTmp) );
+
+ const sal_uInt16 nMaxLength = m_pFFData->getTextMaxLength();
+ if ( nMaxLength )
+ {
+ xNameCont->insertByName( "MaxLength", uno::Any(nMaxLength) );
+ }
+
+ sTmp = m_pFFData->getTextDefault();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Content", uno::Any(sTmp) );
+
+ sTmp = m_pFFData->getTextFormat();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Format", uno::Any(sTmp) );
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMCHECKBOX )
+ {
+ uno::Reference<beans::XPropertySet> xPropSet(xFormField, uno::UNO_QUERY);
+ uno::Any aAny;
+ aAny <<= m_pFFData->getCheckboxChecked();
+ if ( xPropSet.is() )
+ xPropSet->setPropertyValue("Checked", aAny);
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMDROPDOWN )
+ {
+ const FFDataHandler::DropDownEntries_t& rEntries = m_pFFData->getDropDownEntries();
+ if (!rEntries.empty())
+ {
+ if ( xNameCont->hasByName(ODF_FORMDROPDOWN_LISTENTRY) )
+ xNameCont->replaceByName(ODF_FORMDROPDOWN_LISTENTRY, uno::Any(comphelper::containerToSequence(rEntries)));
+ else
+ xNameCont->insertByName(ODF_FORMDROPDOWN_LISTENTRY, uno::Any(comphelper::containerToSequence(rEntries)));
+
+ sal_Int32 nResult = m_pFFData->getDropDownResult().toInt32();
+ // 0 is valid, but also how toInt32 reports parse error, but it's a sensible default...
+ if (0 <= nResult && o3tl::make_unsigned(nResult) < rEntries.size())
+ {
+ if ( xNameCont->hasByName(ODF_FORMDROPDOWN_RESULT) )
+ xNameCont->replaceByName(ODF_FORMDROPDOWN_RESULT, uno::Any( nResult ) );
+ else
+ xNameCont->insertByName(ODF_FORMDROPDOWN_RESULT, uno::Any( nResult ) );
+ }
+ }
+ }
+}
+
+void FormControlHelper::insertControl(uno::Reference<text::XTextRange> const& xTextRange)
+{
+ bool bCreated = false;
+ if ( !m_pFFData )
+ return;
+ uno::Reference<container::XNameContainer> xFormCompsByName(m_pImpl->getForm(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexContainer> xFormComps(m_pImpl->getFormComps());
+ if (! xFormComps.is())
+ return;
+
+ sal_Int32 nControl = 0;
+ bool bDone = false;
+ OUString sControlName;
+
+ do
+ {
+ OUString sTmp = "Control" + OUString::number(nControl);
+
+ nControl++;
+ if (! xFormCompsByName->hasByName(sTmp))
+ {
+ sControlName = sTmp;
+ bDone = true;
+ }
+ }
+ while (! bDone);
+
+ switch (m_pImpl->m_eFieldId)
+ {
+ case FIELD_FORMCHECKBOX:
+ bCreated = createCheckbox(xTextRange, sControlName);
+ break;
+ default:
+ break;
+ }
+
+ if (!bCreated)
+ return;
+
+ uno::Any aAny(m_pImpl->rFormComponent);
+ xFormComps->insertByIndex(xFormComps->getCount(), aAny);
+
+ if (! m_pImpl->getServiceFactory().is())
+ return;
+
+ uno::Reference<uno::XInterface> xInterface = m_pImpl->getServiceFactory()->createInstance("com.sun.star.drawing.ControlShape");
+
+ if (! xInterface.is())
+ return;
+
+ uno::Reference<drawing::XShape> xShape(xInterface, uno::UNO_QUERY);
+
+ if (! xShape.is())
+ return;
+
+ xShape->setSize(m_pImpl->aSize);
+
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+
+ sal_uInt16 nTmp = sal_uInt16(text::TextContentAnchorType_AS_CHARACTER);
+ xShapeProps->setPropertyValue("AnchorType", uno::Any(sal_uInt16(nTmp)));
+
+ nTmp = text::VertOrientation::CENTER;
+ xShapeProps->setPropertyValue("VertOrient", uno::Any(sal_uInt16(nTmp)));
+
+ xShapeProps->setPropertyValue("TextRange", uno::Any(xTextRange));
+
+ uno::Reference<drawing::XControlShape> xControlShape(xShape, uno::UNO_QUERY);
+ uno::Reference<awt::XControlModel> xControlModel(m_pImpl->rFormComponent, uno::UNO_QUERY);
+ xControlShape->setControl(xControlModel);
+
+ m_pImpl->getDrawPage()->add(xShape);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/FormControlHelper.hxx b/writerfilter/source/dmapper/FormControlHelper.hxx
new file mode 100644
index 000000000..b1f262024
--- /dev/null
+++ b/writerfilter/source/dmapper/FormControlHelper.hxx
@@ -0,0 +1,52 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "FFDataHandler.hxx"
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XFormField.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include "FieldTypes.hxx"
+
+namespace writerfilter::dmapper
+{
+class FormControlHelper : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<FormControlHelper> Pointer_t;
+ FormControlHelper(FieldId eFieldId,
+ css::uno::Reference<css::text::XTextDocument> const& rTextDocument,
+ FFDataHandler::Pointer_t const& pFFData);
+ ~FormControlHelper() override;
+
+ void insertControl(css::uno::Reference<css::text::XTextRange> const& xTextRange);
+ void processField(css::uno::Reference<css::text::XFormField> const& xFormField);
+ bool hasFFDataHandler() const { return (m_pFFData != nullptr); }
+
+private:
+ FFDataHandler::Pointer_t m_pFFData;
+ struct FormControlHelper_Impl;
+ tools::SvRef<FormControlHelper_Impl> m_pImpl;
+
+ bool createCheckbox(css::uno::Reference<css::text::XTextRange> const& xTextRange,
+ const OUString& rControlName);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/GraphicHelpers.cxx b/writerfilter/source/dmapper/GraphicHelpers.cxx
new file mode 100644
index 000000000..d4fc4b9a8
--- /dev/null
+++ b/writerfilter/source/dmapper/GraphicHelpers.cxx
@@ -0,0 +1,348 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "GraphicHelpers.hxx"
+#include "TagLogger.hxx"
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include "PropertyIds.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <sal/log.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <tools/diagnose_ex.h>
+
+#include <iostream>
+
+namespace writerfilter::dmapper {
+
+using namespace com::sun::star;
+
+PositionHandler::PositionHandler( std::pair<OUString, OUString>& rPositionOffsets, std::pair<OUString, OUString>& rAligns ) :
+LoggedProperties("PositionHandler"),
+m_nOrient(text::VertOrientation::NONE),
+m_nRelation(text::RelOrientation::FRAME),
+m_nPosition(0),
+m_rPositionOffsets(rPositionOffsets),
+m_rAligns(rAligns)
+{
+}
+
+PositionHandler::~PositionHandler( )
+{
+}
+
+void PositionHandler::lcl_attribute( Id aName, Value& rVal )
+{
+ sal_Int32 nIntValue = rVal.getInt( );
+ switch ( aName )
+ {
+ case NS_ooxml::LN_CT_PosV_relativeFrom:
+ {
+ switch ( nIntValue )
+ {
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_margin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page:
+ m_nRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_topMargin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA_TOP;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_bottomMargin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA_BOTTOM;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_paragraph:
+ m_nRelation = text::RelOrientation::FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_line:
+ m_nRelation = text::RelOrientation::TEXT_LINE;
+ break;
+
+ // TODO There are some other unhandled values
+ default:
+ SAL_WARN("writerfilter", "unhandled case (" << nIntValue << ") in NS_ooxml::LN_CT_PosV_relativeFrom");
+ }
+ }
+ break;
+
+ case NS_ooxml::LN_CT_PosH_relativeFrom:
+ {
+ switch ( nIntValue )
+ {
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_margin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page:
+ m_nRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_insideMargin:
+ m_nRelation = text::RelOrientation::PAGE_FRAME;
+ m_bPageToggle = true;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_column:
+ m_nRelation = text::RelOrientation::FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_character:
+ m_nRelation = text::RelOrientation::CHAR;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_leftMargin:
+ m_nRelation = text::RelOrientation::PAGE_LEFT;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_rightMargin:
+ m_nRelation = text::RelOrientation::PAGE_RIGHT;
+ break;
+
+ // TODO There are some other unhandled values
+ default:
+ SAL_WARN("writerfilter", "unhandled case (" << nIntValue << ") in NS_ooxml::LN_CT_PosH_relativeFrom");
+ }
+ }
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+void PositionHandler::lcl_sprm(Sprm& rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_PosH_posOffset:
+ m_nPosition = oox::drawingml::convertEmuToHmm(m_rPositionOffsets.first.toInt32());
+ m_rPositionOffsets.first.clear();
+ break;
+ case NS_ooxml::LN_CT_PosV_posOffset:
+ m_nPosition = oox::drawingml::convertEmuToHmm(m_rPositionOffsets.second.toInt32());
+ m_rPositionOffsets.second.clear();
+ break;
+ case NS_ooxml::LN_CT_PosH_align:
+ {
+ OUString& rAlign = m_rAligns.first;
+ if (rAlign == "left")
+ m_nOrient = text::HoriOrientation::LEFT;
+ else if (rAlign == "right")
+ m_nOrient = text::HoriOrientation::RIGHT;
+ else if (rAlign == "center")
+ m_nOrient = text::HoriOrientation::CENTER;
+ else if (rAlign == "inside")
+ m_nOrient = text::HoriOrientation::INSIDE;
+ else if (rAlign == "outside")
+ m_nOrient = text::HoriOrientation::OUTSIDE;
+ rAlign.clear();
+ break;
+ }
+ case NS_ooxml::LN_CT_PosV_align:
+ {
+ OUString& rAlign = m_rAligns.second;
+ if (rAlign == "top")
+ m_nOrient = text::VertOrientation::TOP;
+ else if (rAlign == "bottom")
+ m_nOrient = text::VertOrientation::BOTTOM;
+ else if (rAlign == "center")
+ m_nOrient = text::VertOrientation::CENTER;
+ else if (rAlign == "inside" && m_nRelation == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
+ m_nOrient = text::VertOrientation::TOP;
+ else if (rAlign == "outside" && m_nRelation == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
+ m_nOrient = text::VertOrientation::BOTTOM;
+ rAlign.clear();
+ break;
+ }
+ }
+}
+
+sal_Int16 PositionHandler::orientation() const
+{
+ if( m_nRelation == text::RelOrientation::TEXT_LINE )
+ { // It appears that to 'line of text' alignment is backwards to other alignments,
+ // 'top' meaning putting on top of the line instead of having top at the line.
+ if( m_nOrient == text::VertOrientation::TOP )
+ return text::VertOrientation::BOTTOM;
+ else if( m_nOrient == text::VertOrientation::BOTTOM )
+ return text::VertOrientation::TOP;
+ }
+ return m_nOrient;
+}
+
+WrapHandler::WrapHandler( ) :
+LoggedProperties("WrapHandler"),
+ m_nType( 0 ),
+ m_nSide( 0 )
+{
+}
+
+WrapHandler::~WrapHandler( )
+{
+}
+
+void WrapHandler::lcl_attribute( Id aName, Value& rVal )
+{
+ switch ( aName )
+ {
+ case NS_ooxml::LN_CT_Wrap_type:
+ m_nType = sal_Int32( rVal.getInt( ) );
+ break;
+ case NS_ooxml::LN_CT_Wrap_side:
+ m_nSide = sal_Int32( rVal.getInt( ) );
+ break;
+ default:;
+ }
+}
+
+void WrapHandler::lcl_sprm( Sprm& )
+{
+}
+
+text::WrapTextMode WrapHandler::getWrapMode( ) const
+{
+ // The wrap values do not map directly to our wrap mode,
+ // e.g. none in .docx actually means through in LO.
+ text::WrapTextMode nMode = text::WrapTextMode_THROUGH;
+
+ switch ( m_nType )
+ {
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_square:
+ // through and tight are somewhat complicated, approximate
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_tight:
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_through:
+ {
+ switch ( m_nSide )
+ {
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapSide_left:
+ nMode = text::WrapTextMode_LEFT;
+ break;
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapSide_right:
+ nMode = text::WrapTextMode_RIGHT;
+ break;
+ default:
+ nMode = text::WrapTextMode_PARALLEL;
+ }
+ }
+ break;
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_topAndBottom:
+ nMode = text::WrapTextMode_NONE;
+ break;
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_none:
+ default:
+ nMode = text::WrapTextMode_THROUGH;
+ }
+
+ return nMode;
+}
+
+
+void GraphicZOrderHelper::addItem(uno::Reference<beans::XPropertySet> const& props, sal_Int32 const relativeHeight)
+{
+ items[ relativeHeight ] = props;
+}
+
+// The relativeHeight value in .docx is an arbitrary number, where only the relative ordering matters.
+// But in Writer, the z-order is index in 0..(numitems-1) range, so whenever a new item needs to be
+// added in the proper z-order, it is necessary to find the proper index.
+sal_Int32 GraphicZOrderHelper::findZOrder( sal_Int32 relativeHeight, bool bOldStyle )
+{
+ // std::map is iterated sorted by key
+ auto it = std::find_if(items.cbegin(), items.cend(),
+ [relativeHeight, bOldStyle](const Items::value_type& rItem) {
+ // Old-style ordering differs in what should happen when there is already an item with the same z-order:
+ // we belong under it in case of new-style, but we belong above it in case of old-style.
+ return bOldStyle ? (rItem.first > relativeHeight) : (rItem.first >= relativeHeight);
+ }
+ );
+ sal_Int32 itemZOrderOffset(0); // before the item
+ if( it == items.end()) // we're topmost
+ {
+ if( items.empty())
+ return 0;
+ --it;
+ itemZOrderOffset = 1; // after the topmost
+
+ // Check if this shape has a textbox. If so, the textbox will have its own ZOrder, so
+ // suggest a larger offset.
+ bool bTextBox = false;
+ uno::Reference<beans::XPropertySet> xShape = it->second;
+ uno::Reference<beans::XPropertySetInfo> xInfo = xShape->getPropertySetInfo();
+ if (xInfo->hasPropertyByName("TextBox"))
+ {
+ xShape->getPropertyValue("TextBox") >>= bTextBox;
+ }
+ if (bTextBox)
+ {
+ ++itemZOrderOffset;
+ }
+ }
+ // SwXFrame::getPropertyValue throws uno::RuntimeException
+ // when its GetFrameFormat() returns nullptr
+ try {
+ sal_Int32 itemZOrder(0);
+ if( it->second->getPropertyValue(getPropertyName( PROP_Z_ORDER )) >>= itemZOrder )
+ return itemZOrder + itemZOrderOffset;
+ }
+ catch (const uno::RuntimeException&) {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Exception when getting item z-order");
+ }
+ SAL_WARN( "writerfilter", "findZOrder() didn't find item z-order" );
+ return 0; // this should not(?) happen
+}
+
+GraphicNamingHelper::GraphicNamingHelper()
+ : m_nCounter(0)
+{
+}
+
+OUString GraphicNamingHelper::NameGraphic(const OUString& rTemplate)
+{
+ OUString aRet = rTemplate;
+
+ if (aRet.isEmpty())
+ {
+ // Empty template: then auto-generate a unique name.
+ OUString aPrefix(SvxResId(STR_ObjNameSingulGRAF));
+ aRet += aPrefix + OUString::number(++m_nCounter);
+ }
+
+ return aRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/GraphicHelpers.hxx b/writerfilter/source/dmapper/GraphicHelpers.hxx
new file mode 100644
index 000000000..4d9c46394
--- /dev/null
+++ b/writerfilter/source/dmapper/GraphicHelpers.hxx
@@ -0,0 +1,79 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/text/WrapTextMode.hpp>
+
+#include <utility>
+
+namespace writerfilter::dmapper
+{
+class PositionHandler : public LoggedProperties
+{
+public:
+ PositionHandler(std::pair<OUString, OUString>& rPositionOffsets,
+ std::pair<OUString, OUString>& rAligns);
+ virtual ~PositionHandler() override;
+ sal_Int16 orientation() const;
+ sal_Int16 relation() const { return m_nRelation; }
+ sal_Int32 position() const { return m_nPosition; }
+ bool GetPageToggle() const { return m_bPageToggle; }
+
+private:
+ virtual void lcl_attribute(Id aName, Value& rVal) override;
+ virtual void lcl_sprm(Sprm& rSprm) override;
+ sal_Int16 m_nOrient;
+ sal_Int16 m_nRelation;
+ sal_Int32 m_nPosition;
+ std::pair<OUString, OUString>& m_rPositionOffsets;
+ std::pair<OUString, OUString>& m_rAligns;
+ bool m_bPageToggle = false;
+};
+
+class WrapHandler : public LoggedProperties
+{
+public:
+ WrapHandler();
+ virtual ~WrapHandler() override;
+
+ css::text::WrapTextMode getWrapMode() const;
+
+private:
+ virtual void lcl_attribute(Id aName, Value& rVal) override;
+ virtual void lcl_sprm(Sprm& rSprm) override;
+
+ sal_Int32 m_nType;
+ sal_Int32 m_nSide;
+};
+
+/// Keeps track of the next available unique automatic name.
+class GraphicNamingHelper
+{
+ int m_nCounter;
+
+public:
+ GraphicNamingHelper();
+ /// Name a graphic based on rTemplate.
+ OUString NameGraphic(const OUString& rTemplate);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/GraphicImport.cxx b/writerfilter/source/dmapper/GraphicImport.cxx
new file mode 100644
index 000000000..88a6be9ac
--- /dev/null
+++ b/writerfilter/source/dmapper/GraphicImport.cxx
@@ -0,0 +1,2029 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/unoapi.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <oox/drawingml/drawingmltypes.hxx>
+
+#include "DomainMapper.hxx"
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <ooxml/resourceids.hxx>
+
+#include "ConversionHelper.hxx"
+#include "GraphicHelpers.hxx"
+#include "GraphicImport.hxx"
+#include "PropertyMap.hxx"
+#include "TagLogger.hxx"
+#include "WrapPolygonHandler.hxx"
+#include "util.hxx"
+
+#include <comphelper/propertysequence.hxx>
+#include <algorithm>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <oox/export/drawingml.hxx>
+
+using namespace css;
+
+namespace
+{
+bool isTopGroupObj(const uno::Reference<drawing::XShape>& xShape)
+{
+ SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape);
+ if (!pObject)
+ return false;
+
+ if (pObject->getParentSdrObjectFromSdrObject())
+ return false;
+
+ return pObject->IsGroupObject();
+}
+}
+
+namespace writerfilter::dmapper
+{
+
+namespace {
+
+class XInputStreamHelper : public cppu::WeakImplHelper<io::XInputStream>
+{
+ const sal_uInt8* m_pBuffer;
+ const sal_Int32 m_nLength;
+ sal_Int32 m_nPosition;
+public:
+ XInputStreamHelper(const sal_uInt8* buf, size_t len);
+
+ virtual ::sal_Int32 SAL_CALL readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) override;
+ virtual ::sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) override;
+ virtual ::sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+};
+
+}
+
+XInputStreamHelper::XInputStreamHelper(const sal_uInt8* buf, size_t len) :
+ m_pBuffer( buf ),
+ m_nLength( len ),
+ m_nPosition( 0 )
+{
+}
+
+sal_Int32 XInputStreamHelper::readBytes( uno::Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead )
+{
+ return readSomeBytes( aData, nBytesToRead );
+}
+
+sal_Int32 XInputStreamHelper::readSomeBytes( uno::Sequence<sal_Int8>& aData, sal_Int32 nMaxBytesToRead )
+{
+ sal_Int32 nRet = 0;
+ if( nMaxBytesToRead > 0 )
+ {
+ if( nMaxBytesToRead > m_nLength - m_nPosition )
+ nRet = m_nLength - m_nPosition;
+ else
+ nRet = nMaxBytesToRead;
+ aData.realloc( nRet );
+ sal_Int8* pData = aData.getArray();
+ if( nRet )
+ {
+ memcpy( pData, m_pBuffer + m_nPosition, nRet );
+ m_nPosition += nRet;
+ }
+ }
+ return nRet;
+}
+
+
+void XInputStreamHelper::skipBytes( sal_Int32 nBytesToSkip )
+{
+ if( nBytesToSkip < 0 || m_nPosition + nBytesToSkip > m_nLength)
+ throw io::BufferSizeExceededException();
+ m_nPosition += nBytesToSkip;
+}
+
+
+sal_Int32 XInputStreamHelper::available( )
+{
+ return m_nLength - m_nPosition;
+}
+
+
+void XInputStreamHelper::closeInput( )
+{
+}
+
+namespace {
+
+struct GraphicBorderLine
+{
+ sal_Int32 nLineWidth;
+ bool bHasShadow;
+
+ GraphicBorderLine() :
+ nLineWidth(0)
+ ,bHasShadow(false)
+ {}
+
+ bool isEmpty() const
+ {
+ return nLineWidth == 0 && !bHasShadow;
+ }
+
+};
+
+}
+
+class GraphicImport_Impl
+{
+private:
+ sal_Int32 nXSize;
+ bool bXSizeValid;
+ sal_Int32 nYSize;
+ bool bYSizeValid;
+
+public:
+ GraphicImportType eGraphicImportType;
+ DomainMapper& rDomainMapper;
+
+ sal_Int32 nLeftPosition;
+ sal_Int32 nTopPosition;
+
+ bool bUseSimplePos;
+ sal_Int32 zOrder;
+
+ sal_Int16 nHoriOrient;
+ sal_Int16 nHoriRelation;
+ bool bPageToggle = false;
+ sal_Int16 nVertOrient;
+ sal_Int16 nVertRelation;
+ text::WrapTextMode nWrap;
+ bool bLayoutInCell;
+ bool bCompatForcedLayoutInCell;
+ bool bAllowOverlap = true;
+ bool bOpaque;
+ bool bBehindDoc;
+ bool bContour;
+ bool bContourOutside;
+ WrapPolygon::Pointer_t mpWrapPolygon;
+
+ sal_Int32 nLeftMargin;
+ sal_Int32 nLeftMarginOrig = 0;
+ sal_Int32 nRightMargin;
+ sal_Int32 nTopMargin;
+ sal_Int32 nBottomMargin;
+
+ bool bShadow;
+ sal_Int32 nShadowXDistance;
+ sal_Int32 nShadowYDistance;
+ sal_Int32 nShadowColor;
+ sal_Int32 nShadowTransparence;
+
+ sal_Int32 nContrast;
+ sal_Int32 nBrightness;
+
+ static constexpr sal_Int32 nFillColor = 0xffffffff;
+
+ drawing::ColorMode eColorMode;
+
+ GraphicBorderLine aBorders[4];
+
+ bool bIsGraphic;
+
+ bool bSizeProtected;
+ bool bPositionProtected;
+ bool bHidden;
+
+ sal_Int32 nShapeOptionType;
+
+ OUString sName;
+ OUString sAlternativeText;
+ OUString title;
+ OUString sHyperlinkURL;
+ std::pair<OUString, OUString>& m_rPositionOffsets;
+ std::pair<OUString, OUString>& m_rAligns;
+ std::queue<OUString>& m_rPositivePercentages;
+ OUString sAnchorId;
+ comphelper::SequenceAsHashMap m_aInteropGrabBag;
+ std::optional<sal_Int32> m_oEffectExtentLeft;
+ std::optional<sal_Int32> m_oEffectExtentTop;
+ std::optional<sal_Int32> m_oEffectExtentRight;
+ std::optional<sal_Int32> m_oEffectExtentBottom;
+
+ GraphicImport_Impl(GraphicImportType eImportType, DomainMapper& rDMapper, std::pair<OUString, OUString>& rPositionOffsets, std::pair<OUString, OUString>& rAligns, std::queue<OUString>& rPositivePercentages) :
+ nXSize(0)
+ ,bXSizeValid(false)
+ ,nYSize(0)
+ ,bYSizeValid(false)
+ ,eGraphicImportType( eImportType )
+ ,rDomainMapper( rDMapper )
+ ,nLeftPosition(0)
+ ,nTopPosition(0)
+ ,bUseSimplePos(false)
+ ,zOrder(-1)
+ ,nHoriOrient( text::HoriOrientation::NONE )
+ ,nHoriRelation( text::RelOrientation::FRAME )
+ ,nVertOrient( text::VertOrientation::NONE )
+ ,nVertRelation( text::RelOrientation::FRAME )
+ ,nWrap(text::WrapTextMode_NONE)
+ ,bLayoutInCell(true)
+ ,bCompatForcedLayoutInCell(false)
+ ,bOpaque( !rDMapper.IsInHeaderFooter() )
+ ,bBehindDoc(false)
+ ,bContour(false)
+ ,bContourOutside(true)
+ ,nLeftMargin(319)
+ ,nRightMargin(319)
+ ,nTopMargin(0)
+ ,nBottomMargin(0)
+ ,bShadow(false)
+ ,nShadowXDistance(0)
+ ,nShadowYDistance(0)
+ ,nShadowColor(0)
+ ,nShadowTransparence(0)
+ ,nContrast(0)
+ ,nBrightness(0)
+ ,eColorMode( drawing::ColorMode_STANDARD )
+ ,bIsGraphic(false)
+ ,bSizeProtected(false)
+ ,bPositionProtected(false)
+ ,bHidden(false)
+ ,nShapeOptionType(0)
+ ,m_rPositionOffsets(rPositionOffsets)
+ ,m_rAligns(rAligns)
+ ,m_rPositivePercentages(rPositivePercentages)
+ {
+ if (eGraphicImportType == GraphicImportType::IMPORT_AS_DETECTED_INLINE
+ && !rDMapper.IsInShape())
+ {
+ zOrder = 0;
+ }
+ }
+
+ void setXSize(sal_Int32 _nXSize)
+ {
+ nXSize = _nXSize;
+ bXSizeValid = true;
+ }
+
+ sal_uInt32 getXSize() const
+ {
+ return nXSize;
+ }
+
+ bool isXSizeValid() const
+ {
+ return bXSizeValid;
+ }
+
+ void setYSize(sal_Int32 _nYSize)
+ {
+ nYSize = _nYSize;
+ bYSizeValid = true;
+ }
+
+ sal_uInt32 getYSize() const
+ {
+ return nYSize;
+ }
+
+ bool isYSizeValid() const
+ {
+ return bYSizeValid;
+ }
+
+ void applyMargins(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ), uno::Any(nLeftMargin));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ), uno::Any(nRightMargin));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ), uno::Any(nTopMargin));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ), uno::Any(nBottomMargin));
+ }
+
+ void applyPosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT ),
+ uno::Any(nHoriOrient));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT ),
+ uno::Any(nVertOrient));
+ }
+
+ void applyRelativePosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties, bool bRelativeOnly = false) const
+ {
+ if (!bRelativeOnly)
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_POSITION),
+ uno::Any(nLeftPosition));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_RELATION ),
+ uno::Any(nHoriRelation));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_PAGE_TOGGLE),
+ uno::Any(bPageToggle));
+ if (!bRelativeOnly)
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_POSITION),
+ uno::Any(nTopPosition));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_RELATION ),
+ uno::Any(nVertRelation));
+ }
+
+ void applyZOrder(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const
+ {
+ if (zOrder >= 0)
+ {
+ // tdf#120760 Send objects with behinddoc=true to the back.
+ sal_Int32 nZOrder = zOrder;
+ if (bBehindDoc && rDomainMapper.IsInHeaderFooter())
+ nZOrder -= SAL_MAX_INT32;
+ GraphicZOrderHelper* pZOrderHelper = rDomainMapper.graphicZOrderHelper();
+ bool bOldStyle = eGraphicImportType == GraphicImportType::IMPORT_AS_DETECTED_INLINE;
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_Z_ORDER),
+ uno::Any(pZOrderHelper->findZOrder(nZOrder, bOldStyle)));
+ pZOrderHelper->addItem(xGraphicObjectProperties, nZOrder);
+ }
+ }
+
+ void applyName(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const
+ {
+ try
+ {
+ if (!sName.isEmpty())
+ {
+ uno::Reference<container::XNamed> const xNamed(xGraphicObjectProperties, uno::UNO_QUERY_THROW);
+ xNamed->setName(sName);
+ }
+ // else: name is automatically generated by SwDoc::MakeFlySection_()
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_DESCRIPTION ),
+ uno::Any( sAlternativeText ));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TITLE ),
+ uno::Any( title ));
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "failed");
+ }
+ }
+
+ void applyHyperlink(uno::Reference<beans::XPropertySet> const & xShapeProps, bool bIsShape)
+ {
+ // Graphic objects have a different hyperlink prop than shapes
+ auto aHyperlinkProp = bIsShape ? PROP_HYPERLINK : PROP_HYPER_LINK_U_R_L;
+ if (!sHyperlinkURL.isEmpty())
+ {
+ xShapeProps->setPropertyValue(
+ getPropertyName(aHyperlinkProp), uno::Any(sHyperlinkURL));
+ }
+ }
+
+ /// Getter for m_aInteropGrabBag, but also merges in the values from other members if they are set.
+ comphelper::SequenceAsHashMap const & getInteropGrabBag()
+ {
+ comphelper::SequenceAsHashMap aEffectExtent;
+ if (m_oEffectExtentLeft)
+ aEffectExtent["l"] <<= *m_oEffectExtentLeft;
+ if (m_oEffectExtentTop)
+ aEffectExtent["t"] <<= *m_oEffectExtentTop;
+ if (m_oEffectExtentRight)
+ aEffectExtent["r"] <<= *m_oEffectExtentRight;
+ if (m_oEffectExtentBottom)
+ aEffectExtent["b"] <<= *m_oEffectExtentBottom;
+ if (!aEffectExtent.empty())
+ m_aInteropGrabBag["CT_EffectExtent"] <<= aEffectExtent.getAsConstPropertyValueList();
+ return m_aInteropGrabBag;
+ }
+};
+
+GraphicImport::GraphicImport(uno::Reference<uno::XComponentContext> const& xComponentContext,
+ uno::Reference<lang::XMultiServiceFactory> const& xTextFactory,
+ DomainMapper& rDMapper,
+ GraphicImportType eImportType,
+ std::pair<OUString, OUString>& rPositionOffsets,
+ std::pair<OUString, OUString>& rAligns,
+ std::queue<OUString>& rPositivePercentages)
+: LoggedProperties("GraphicImport")
+, LoggedTable("GraphicImport")
+, LoggedStream("GraphicImport")
+, m_pImpl(new GraphicImport_Impl(eImportType, rDMapper, rPositionOffsets, rAligns, rPositivePercentages))
+, m_xComponentContext(xComponentContext)
+, m_xTextFactory(xTextFactory)
+{
+}
+
+GraphicImport::~GraphicImport()
+{
+}
+
+com::sun::star::awt::Point GraphicImport::GetGraphicObjectPosition() const
+{
+ return (com::sun::star::awt::Point(m_pImpl->nLeftPosition, m_pImpl->nTopPosition));
+}
+
+bool GraphicImport::GetLayoutInCell() const
+{
+ return m_pImpl->bLayoutInCell;
+}
+
+void GraphicImport::handleWrapTextValue(sal_uInt32 nVal)
+{
+ switch (nVal)
+ {
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides: // 90920;
+ m_pImpl->nWrap = text::WrapTextMode_PARALLEL;
+ break;
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left: // 90921;
+ m_pImpl->nWrap = text::WrapTextMode_LEFT;
+ break;
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right: // 90922;
+ m_pImpl->nWrap = text::WrapTextMode_RIGHT;
+ break;
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest: // 90923;
+ m_pImpl->nWrap = text::WrapTextMode_DYNAMIC;
+ break;
+ default:;
+ }
+}
+
+void GraphicImport::putPropertyToFrameGrabBag( const OUString& sPropertyName, const uno::Any& aPropertyValue )
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = sPropertyName;
+ aProperty.Value = aPropertyValue;
+
+ if (!m_xShape.is())
+ return;
+
+ uno::Reference< beans::XPropertySet > xSet(m_xShape, uno::UNO_QUERY_THROW);
+
+ uno::Reference< beans::XPropertySetInfo > xSetInfo(xSet->getPropertySetInfo());
+ if (!xSetInfo.is())
+ return;
+
+ OUString aGrabBagPropName;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
+ if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ aGrabBagPropName = "FrameInteropGrabBag";
+ else
+ aGrabBagPropName = "InteropGrabBag";
+
+ if (xSetInfo->hasPropertyByName(aGrabBagPropName))
+ {
+ //Add pProperty to the end of the Sequence for aGrabBagPropName
+ uno::Sequence<beans::PropertyValue> aTmp;
+ xSet->getPropertyValue(aGrabBagPropName) >>= aTmp;
+ std::vector<beans::PropertyValue> aGrabBag(comphelper::sequenceToContainer<std::vector<beans::PropertyValue> >(aTmp));
+ aGrabBag.push_back(aProperty);
+
+ xSet->setPropertyValue(aGrabBagPropName, uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+}
+
+static bool lcl_bHasGroupSlantedChild(const SdrObject* pObj)
+{
+ // Returns true, if a child object differs more than 0.02deg from horizontal or vertical.
+ // Because lines sometimes are imported as customshapes, a horizontal or vertical line
+ // might not have exactly 0, 90, 180, or 270 degree as rotate angle.
+ if (!pObj)
+ return false;
+ if (!pObj->IsGroupObject())
+ return false;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if (!pSubList)
+ return false;
+ SdrObjListIter aIterator(pSubList, SdrIterMode::DeepNoGroups);
+ while (aIterator.IsMore())
+ {
+ const SdrObject* pSubObj = aIterator.Next();
+ const Degree100 nRotateAngle = NormAngle36000(pSubObj->GetRotateAngle());
+ const sal_uInt16 nRot = nRotateAngle.get();
+ if ((3 < nRot && nRot < 8997) || (9003 < nRot && nRot < 17997)
+ || (18003 < nRot && nRot < 26997) || (27003 < nRot && nRot < 35997))
+ return true;
+ }
+ return false;
+}
+
+void GraphicImport::lcl_correctWord2007EffectExtent(const sal_Int32 nMSOAngle)
+{
+ // Word versions older than 14 do not swap width and height (see lcl_doMSOWidthHeightSwap)
+ // and therefore generate different effectExtent. We correct them here.
+ sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
+ if (nAngleDeg < 45 || nAngleDeg >= 135)
+ return;
+
+ sal_Int32 nDiff = o3tl::convert(
+ (double(m_pImpl->getXSize()) - double(m_pImpl->getYSize())) / 2.0,
+ o3tl::Length::mm100, o3tl::Length::emu);
+ if (m_pImpl->m_oEffectExtentLeft)
+ *m_pImpl->m_oEffectExtentLeft += nDiff;
+ if (m_pImpl->m_oEffectExtentRight)
+ *m_pImpl->m_oEffectExtentRight += nDiff;
+ if (m_pImpl->m_oEffectExtentTop)
+ *m_pImpl->m_oEffectExtentTop -= nDiff;
+ if (m_pImpl->m_oEffectExtentBottom)
+ *m_pImpl->m_oEffectExtentBottom -= nDiff;
+}
+
+static void lcl_doMSOWidthHeightSwap(awt::Point& rLeftTop, awt::Size& rSize,
+ const sal_Int32 nMSOAngle)
+{
+ if (nMSOAngle == 0)
+ return;
+ // convert nMSOAngle to degree in [0°,180°[
+ sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
+ if (nAngleDeg >= 45 && nAngleDeg < 135)
+ {
+ // keep center of rectangle given in rLeftTop and rSize
+ sal_Int32 aTemp = rSize.Width - rSize.Height;
+ rLeftTop.X += aTemp / 2;
+ rLeftTop.Y -= aTemp / 2;
+ std::swap(rSize.Width, rSize.Height);
+ }
+ return;
+}
+
+void GraphicImport::lcl_expandRectangleByEffectExtent(awt::Point& rLeftTop, awt::Size& rSize)
+{
+ sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
+ : 0;
+ rLeftTop.X -= nEffectExtent;
+ rSize.Width += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentRight)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight)
+ : 0;
+ rSize.Width += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentTop)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop)
+ : 0;
+ rLeftTop.Y -= nEffectExtent;
+ rSize.Height += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom)
+ : 0;
+ rSize.Height += nEffectExtent;
+}
+
+void GraphicImport::lcl_attribute(Id nName, Value& rValue)
+{
+ sal_Int32 nIntValue = rValue.getInt();
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_Hyperlink_URL://90682;
+ m_pImpl->sHyperlinkURL = rValue.getString();
+ break;
+ case NS_ooxml::LN_blip: //the binary graphic data in a shape
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rValue.getProperties();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_payload :
+ {
+ writerfilter::Reference<BinaryObj>::Pointer_t pPictureData = rValue.getBinary();
+ if( pPictureData )
+ pPictureData->resolve(*this);
+ }
+ break;
+
+ //border properties
+ case NS_ooxml::LN_CT_Border_sz:
+ m_pImpl->aBorders[BORDER_TOP].nLineWidth = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ //graphic borders don't support different line types
+ break;
+ case NS_ooxml::LN_CT_Border_space:
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ m_pImpl->aBorders[BORDER_TOP].bHasShadow = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Border_frame:
+ break;
+ case NS_ooxml::LN_CT_PositiveSize2D_cx:
+ case NS_ooxml::LN_CT_PositiveSize2D_cy:
+ {
+ sal_Int32 nDim = oox::drawingml::convertEmuToHmm(nIntValue);
+ // drawingML equivalent of oox::vml::ShapeType::getAbsRectangle():
+ // make sure a shape isn't hidden implicitly just because it has
+ // zero height or width.
+ if (nDim == 0)
+ nDim = 1;
+
+ if( nName == NS_ooxml::LN_CT_PositiveSize2D_cx )
+ m_pImpl->setXSize(nDim);
+ else
+ m_pImpl->setYSize(nDim);
+ }
+ break;
+ case NS_ooxml::LN_CT_EffectExtent_l:
+ m_pImpl->m_oEffectExtentLeft = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_EffectExtent_t:
+ m_pImpl->m_oEffectExtentTop = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_EffectExtent_r:
+ m_pImpl->m_oEffectExtentRight = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_EffectExtent_b:
+ m_pImpl->m_oEffectExtentBottom = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_id:// 90650;
+ //id of the object - ignored
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_name:// 90651;
+ //name of the object
+ m_pImpl->sName = rValue.getString();
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_descr:// 90652;
+ //alternative text
+ m_pImpl->sAlternativeText = rValue.getString();
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_title:
+ //alternative text
+ m_pImpl->title = rValue.getString();
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_hidden:
+ m_pImpl->bHidden = (nIntValue == 1);
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noChangeAspect://90644;
+ //disallow aspect ratio change - ignored
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noMove:// 90645;
+ m_pImpl->bPositionProtected = true;
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noResize: // 90646;
+ m_pImpl->bSizeProtected = true;
+ break;
+ case NS_ooxml::LN_CT_Anchor_distT: // 90983;
+ case NS_ooxml::LN_CT_Anchor_distB: // 90984;
+ case NS_ooxml::LN_CT_Anchor_distL: // 90985;
+ case NS_ooxml::LN_CT_Anchor_distR: // 90986;
+ {
+ m_pImpl->nShapeOptionType = nName;
+ ProcessShapeOptions(rValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_simplePos_attr: // 90987;
+ m_pImpl->bUseSimplePos = nIntValue > 0;
+ break;
+ case NS_ooxml::LN_CT_Anchor_relativeHeight: // 90988;
+ m_pImpl->zOrder = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Anchor_behindDoc: // 90989; - in background
+ if (nIntValue > 0)
+ {
+ m_pImpl->bOpaque = false;
+ m_pImpl->bBehindDoc = true;
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_locked: // 90990; - ignored
+ break;
+ case NS_ooxml::LN_CT_Anchor_layoutInCell: // 90991; - ignored
+ // Starting in MSO 2013, anchors are ALWAYS considered to be laid out in table cell.
+ m_pImpl->bCompatForcedLayoutInCell = !nIntValue
+ && m_pImpl->rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14
+ && m_pImpl->rDomainMapper.IsInTable();
+ m_pImpl->bLayoutInCell = m_pImpl->bCompatForcedLayoutInCell || nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Anchor_hidden: // 90992; - ignored
+ break;
+ case NS_ooxml::LN_CT_Anchor_allowOverlap:
+ m_pImpl->bAllowOverlap = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Anchor_wp14_anchorId:
+ case NS_ooxml::LN_CT_Inline_wp14_anchorId:
+ {
+ OUStringBuffer aBuffer = OUString::number(nIntValue, 16);
+ OUStringBuffer aString;
+ comphelper::string::padToLength(aString, 8 - aBuffer.getLength(), '0');
+ aString.append(aBuffer.getStr());
+ m_pImpl->sAnchorId = aString.makeStringAndClear().toAsciiUpperCase();
+ }
+ break;
+ case NS_ooxml::LN_CT_Point2D_x: // 90405;
+ m_pImpl->nLeftPosition = ConversionHelper::convertTwipToMM100(nIntValue);
+ m_pImpl->nHoriRelation = text::RelOrientation::PAGE_FRAME;
+ m_pImpl->nHoriOrient = text::HoriOrientation::NONE;
+ break;
+ case NS_ooxml::LN_CT_Point2D_y: // 90406;
+ m_pImpl->nTopPosition = ConversionHelper::convertTwipToMM100(nIntValue);
+ m_pImpl->nVertRelation = text::RelOrientation::PAGE_FRAME;
+ m_pImpl->nVertOrient = text::VertOrientation::NONE;
+ break;
+ case NS_ooxml::LN_CT_WrapTight_wrapText: // 90934;
+ m_pImpl->bContour = true;
+ m_pImpl->bContourOutside = true;
+
+ handleWrapTextValue(rValue.getInt());
+
+ break;
+ case NS_ooxml::LN_CT_WrapThrough_wrapText:
+ m_pImpl->bContour = true;
+ m_pImpl->bContourOutside = false;
+
+ handleWrapTextValue(rValue.getInt());
+
+ break;
+ case NS_ooxml::LN_CT_WrapSquare_wrapText: //90928;
+ handleWrapTextValue(rValue.getInt());
+ break;
+ case NS_ooxml::LN_shape:
+ {
+ uno::Reference< drawing::XShape> xShape;
+ rValue.getAny( ) >>= xShape;
+ if ( xShape.is( ) )
+ {
+ // Is it a graphic image
+ bool bUseShape = true;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps
+ ( xShape, uno::UNO_QUERY_THROW );
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+ xShapeProps->getPropertyValue("Graphic") >>= xGraphic;
+
+ sal_Int32 nRotation = 0;
+ xShapeProps->getPropertyValue("RotateAngle") >>= nRotation;
+
+ css::beans::PropertyValues aGrabBag;
+ xShapeProps->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ // if the shape contains effects in the grab bag, we should not transform it
+ // in a XTextContent so those effects can be preserved
+ bool bContainsEffects = std::any_of(std::cbegin(aGrabBag), std::cend(aGrabBag), [](const auto& rProp) {
+ return rProp.Name == "EffectProperties"
+ || rProp.Name == "3DEffectProperties"
+ || rProp.Name == "ArtisticEffectProperties";
+ });
+
+ xShapeProps->getPropertyValue("Shadow") >>= m_pImpl->bShadow;
+ if (m_pImpl->bShadow)
+ {
+ xShapeProps->getPropertyValue("ShadowXDistance") >>= m_pImpl->nShadowXDistance;
+ xShapeProps->getPropertyValue("ShadowYDistance") >>= m_pImpl->nShadowYDistance;
+ xShapeProps->getPropertyValue("ShadowColor") >>= m_pImpl->nShadowColor;
+ xShapeProps->getPropertyValue("ShadowTransparence") >>= m_pImpl->nShadowTransparence;
+ }
+
+ xShapeProps->getPropertyValue("GraphicColorMode") >>= m_pImpl->eColorMode;
+ xShapeProps->getPropertyValue("AdjustLuminance") >>= m_pImpl->nBrightness;
+ xShapeProps->getPropertyValue("AdjustContrast") >>= m_pImpl->nContrast;
+
+ // fdo#70457: transform XShape into a SwXTextGraphicObject only if there's no rotation
+ if ( nRotation == 0 && !bContainsEffects )
+ m_xGraphicObject = createGraphicObject( xGraphic, xShapeProps );
+
+ bUseShape = !m_xGraphicObject.is( );
+
+ if ( !bUseShape )
+ {
+ // Define the object size
+ uno::Reference< beans::XPropertySet > xGraphProps( m_xGraphicObject,
+ uno::UNO_QUERY );
+ awt::Size aSize = xShape->getSize( );
+ xGraphProps->setPropertyValue("Height",
+ uno::Any( aSize.Height ) );
+ xGraphProps->setPropertyValue("Width",
+ uno::Any( aSize.Width ) );
+
+ text::GraphicCrop aGraphicCrop( 0, 0, 0, 0 );
+ uno::Reference< beans::XPropertySet > xSourceGraphProps( xShape, uno::UNO_QUERY );
+ uno::Any aAny = xSourceGraphProps->getPropertyValue("GraphicCrop");
+ if(aAny >>= aGraphicCrop) {
+ xGraphProps->setPropertyValue("GraphicCrop",
+ uno::Any( aGraphicCrop ) );
+ }
+
+ // We need to drop the shape here somehow
+ uno::Reference< lang::XComponent > xShapeComponent( xShape, uno::UNO_QUERY );
+ xShapeComponent->dispose( );
+ }
+ }
+ catch( const beans::UnknownPropertyException & )
+ {
+ // It isn't a graphic image
+ }
+
+ if ( bUseShape )
+ m_xShape = xShape;
+
+ if ( m_xShape.is( ) )
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps
+ (m_xShape, uno::UNO_QUERY_THROW);
+
+
+ xShapeProps->setPropertyValue
+ (getPropertyName(PROP_ANCHOR_TYPE),
+ uno::Any
+ (text::TextContentAnchorType_AS_CHARACTER));
+
+ // In Word, if a shape is anchored inline, that
+ // excludes being in the background.
+ xShapeProps->setPropertyValue("Opaque", uno::Any(true));
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
+
+ // TextFrames can't be rotated. But for anything else,
+ // make sure that setting size doesn't affect rotation,
+ // that would not match Word's definition of rotation.
+ bool bKeepRotation = false;
+ if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ {
+ bKeepRotation = true;
+ xShapeProps->setPropertyValue
+ (getPropertyName(PROP_TEXT_RANGE),
+ uno::Any
+ (m_pImpl->rDomainMapper.GetCurrentTextRange()));
+ }
+
+ awt::Size aSize(m_xShape->getSize());
+
+ // One purpose of the next part is, to set the logic rectangle of the SdrObject
+ // to nXSize and nYSize from import. That doesn't work for groups or lines,
+ // because they do not have a logic rectangle and m_xShape->getSize and
+ // m_xShape->setSize would work on the snap rectangle. In case a shape is
+ // rotated, non-uniform scaling the snap rectangle will introduce shearing on
+ // the shape. In case group or line is rotated, nXSize and nYSize contain the
+ // unrotated size from oox. The rotation is already incorporated into group
+ // children and line points. We must not scale them to unrotated size. Exclude
+ // those shapes here.
+
+ // Get MSO rotation angle. GetRotateAngle from SdrObject is not suitable
+ // here, because it returns the rotate angle of the first child for groups
+ // and slope angle for lines, even if line or group had not been rotated.
+ // Import in oox has put the rotation from oox file into InteropGrabBag.
+ comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
+ sal_Int32 nOOXAngle(0);
+ aInteropGrabBag.getValue("mso-rotation-angle") >>= nOOXAngle; // 1/60000 deg
+ // tdf#143455: A diagram is imported as group, but has no valid object list
+ // and contour wrap is different to Word. As workaround diagrams are excluded
+ // here in various places.
+ const SdrObject* pDiagramCandidate(SdrObject::getSdrObjectFromXShape(m_xShape));
+ const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram());
+ // tdf#143476: A lockedCanvas (Word2007) is imported as group, but has not
+ // got size and position. Values from m_Impl has to be used.
+ bool bIsLockedCanvas(false);
+ aInteropGrabBag.getValue("LockedCanvas") >>= bIsLockedCanvas;
+ const bool bIsGroupOrLine = (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape")
+ && !bIsDiagram && !bIsLockedCanvas)
+ || xServiceInfo->supportsService("com.sun.star.drawing.LineShape");
+ SdrObject* pShape = SdrObject::getSdrObjectFromXShape(m_xShape);
+ if ((bIsGroupOrLine && !lcl_bHasGroupSlantedChild(pShape) && nOOXAngle == 0)
+ || !bIsGroupOrLine)
+ {
+ if (m_pImpl->isXSizeValid())
+ aSize.Width = m_pImpl->getXSize();
+ if (m_pImpl->isYSizeValid())
+ aSize.Height = m_pImpl->getYSize();
+ }
+
+ Degree100 nRotation;
+ if (bKeepRotation)
+ {
+ // Use internal API, getPropertyValue("RotateAngle")
+ // would use GetObjectRotation(), which is not what
+ // we want.
+ if (pShape)
+ nRotation = pShape->GetRotateAngle();
+ }
+ m_xShape->setSize(aSize);
+ if (bKeepRotation)
+ {
+ xShapeProps->setPropertyValue("RotateAngle", uno::Any(nRotation.get()));
+ }
+
+ m_pImpl->bIsGraphic = true;
+
+ if (!m_pImpl->sAnchorId.isEmpty())
+ {
+ putPropertyToFrameGrabBag("AnchorId", uno::Any(m_pImpl->sAnchorId));
+ }
+
+ // Calculate mso unrotated rectangle and its center, needed below
+ awt::Size aImportSize(m_xShape->getSize()); // here only fallback
+ if (m_pImpl->isXSizeValid())
+ aImportSize.Width = m_pImpl->getXSize(); // Hmm
+ if (m_pImpl->isYSizeValid())
+ aImportSize.Height = m_pImpl->getYSize(); // Hmm
+ const awt::Point aImportPosition(GetGraphicObjectPosition()); // Hmm
+ double fCentrumX = aImportPosition.X + aImportSize.Width / 2.0;
+ double fCentrumY = aImportPosition.Y + aImportSize.Height / 2.0;
+
+ // In case of group and lines, transformations are incorporated in the child
+ // shapes or points respectively in LO. MSO has rotation as separate property.
+ // The position refers to the unrotated rectangle of MSO. We need to adapt it
+ // to the left-top of the transformed shape.
+ awt::Size aLOSize(m_xShape->getSize()); // LO snap rectangle size in Hmm
+ if (bIsGroupOrLine && !(m_pImpl->mpWrapPolygon))
+ {
+ // Set LO position. MSO rotation is done on shape center.
+ if(pShape && pShape->IsGroupObject())
+ {
+ tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twips
+ m_pImpl->nLeftPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
+ m_pImpl->nTopPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
+ aLOSize.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getWidth());
+ aLOSize.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getHeight());
+ }
+ else
+ {
+ m_pImpl->nLeftPosition = fCentrumX - aLOSize.Width / 2.0;
+ m_pImpl->nTopPosition = fCentrumY - aLOSize.Height / 2.0;
+ }
+ m_xShape->setPosition(GetGraphicObjectPosition());
+ }
+ // ToDo: Rotated shapes with position type "Alignment" (UI of Word) have
+ // wrong position. Word aligns the unrotated logic rectangle, LO the rotated
+ // snap rectangle.
+
+ // Margin correction
+
+ // tdf#143475: Word 2007 (vers 12) calculates effectExtent for rotated images
+ // based on the unrotated image without width-height-swap. We correct this to
+ // those values, which would be calculated if width-height-swap was used.
+ if (m_pImpl->rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() < 14
+ && xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")
+ && nOOXAngle != 0)
+ {
+ lcl_correctWord2007EffectExtent(nOOXAngle);
+ }
+
+ if (m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
+ {
+ if (nOOXAngle == 0)
+ {
+ // EffectExtent contains all needed additional space, including fat
+ // stroke and shadow. Simple add it to the margins.
+ sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
+ : 0;
+ m_pImpl->nLeftMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentRight)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight) : 0;
+ m_pImpl->nRightMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentTop)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop) : 0;
+ m_pImpl->nTopMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom) : 0;
+ m_pImpl->nBottomMargin += nEffectExtent;
+ }
+ else
+ {
+ // As of June 2021 LibreOffice uses an area, which is large enough to
+ // contain the rotated snap rectangle. MSO uses a smaller area, so
+ // that the rotated snap rectangle covers text.
+ awt::Point aMSOBaseLeftTop = aImportPosition;
+ awt::Size aMSOBaseSize = aImportSize;
+ lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
+ lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
+
+ // Get LO SnapRect from SdrObject if possible
+ awt::Rectangle aLOSnapRect;
+ // For case we have no SdrObject, initialize with values from m_pImpl
+ aLOSnapRect.X = m_pImpl->nLeftPosition;
+ aLOSnapRect.Y = m_pImpl->nTopPosition;
+ aLOSnapRect.Width = aLOSize.Width;
+ aLOSnapRect.Height = aLOSize.Height;
+ if (pShape)
+ {
+ tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twip
+ aLOSnapRect.X = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
+ aLOSnapRect.Y = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
+ aLOSnapRect.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getWidth());
+ aLOSnapRect.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getHeight());
+ }
+
+ m_pImpl->nLeftMargin += aLOSnapRect.X - aMSOBaseLeftTop.X;
+ m_pImpl->nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
+ - (aLOSnapRect.X + aLOSnapRect.Width);
+ m_pImpl->nTopMargin += aLOSnapRect.Y - aMSOBaseLeftTop.Y;
+ m_pImpl->nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
+ - (aLOSnapRect.Y + aLOSnapRect.Height);
+ // tdf#141880 LibreOffice cannot handle negative vertical margins.
+ // Those cases are caught below at common place.
+ }
+ } // end IMPORT_AS_DETECTED_INLINE
+ else if ((m_pImpl->nWrap == text::WrapTextMode_PARALLEL
+ || m_pImpl->nWrap == text::WrapTextMode_DYNAMIC
+ || m_pImpl->nWrap == text::WrapTextMode_LEFT
+ || m_pImpl->nWrap == text::WrapTextMode_RIGHT
+ || m_pImpl->nWrap == text::WrapTextMode_NONE)
+ && !(m_pImpl->mpWrapPolygon) && !bIsDiagram)
+ {
+ // For wrap "Square" an area is defined around which the text wraps. MSO
+ // describes the area by a base rectangle and effectExtent. LO uses the
+ // shape bounding box and margins. We adapt the margins to get the same
+ // area as MSO.
+ awt::Point aMSOBaseLeftTop = aImportPosition;
+ awt::Size aMSOBaseSize = aImportSize;
+ lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
+ lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
+
+ // Get LO bound rectangle from SdrObject if possible
+ awt::Rectangle aLOBoundRect;
+ // For case we have no SdrObject, initialize with values from m_pImpl
+ aLOBoundRect.X = m_pImpl->nLeftPosition;
+ aLOBoundRect.Y = m_pImpl->nTopPosition;
+ aLOBoundRect.Width = aLOSize.Width;
+ aLOBoundRect.Height = aLOSize.Height;
+ if (pShape)
+ {
+ tools::Rectangle aBoundRect = pShape->GetCurrentBoundRect(); // Twip
+ aLOBoundRect.X = ConversionHelper::convertTwipToMM100(aBoundRect.Left());
+ aLOBoundRect.Y = ConversionHelper::convertTwipToMM100(aBoundRect.Top());
+ aLOBoundRect.Width = ConversionHelper::convertTwipToMM100(aBoundRect.getWidth());
+ aLOBoundRect.Height = ConversionHelper::convertTwipToMM100(aBoundRect.getHeight());
+ }
+
+ m_pImpl->nLeftMargin += aLOBoundRect.X - aMSOBaseLeftTop.X;
+ m_pImpl->nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
+ - (aLOBoundRect.X + aLOBoundRect.Width);
+ m_pImpl->nTopMargin += aLOBoundRect.Y - aMSOBaseLeftTop.Y;
+ m_pImpl->nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
+ - (aLOBoundRect.Y + aLOBoundRect.Height);
+ }
+ else if (m_pImpl->mpWrapPolygon && !bIsDiagram)
+ {
+ // Word uses a wrap polygon, LibreOffice has no explicit wrap polygon
+ // but creates the wrap contour based on the shape geometry, without
+ // stroke width and shadow, but with rotation and flip. The concepts
+ // are not compatible. We approximate Word's rendering by setting
+ // wrap margins.
+
+ // Build a range from the wrap polygon from Word.
+ const drawing::PointSequenceSequence aWrapPolygon
+ = m_pImpl->mpWrapPolygon->getPointSequenceSequence();
+ basegfx::B2DPolyPolygon aB2DWrapPolyPolygon
+ = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
+ aWrapPolygon);
+ // Wrap polygon values are relative to 0..21600|0..21600.
+ // Scale to shape size (in Hmm).
+ basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleB2DHomMatrix(
+ aImportSize.Width / 21600.0, aImportSize.Height / 21600.0);
+ aB2DWrapPolyPolygon.transform(aMatrix);
+
+ // Shape geometry will be rotated, rotate wrap polygon too.
+ if (nOOXAngle != 0)
+ {
+ aMatrix = basegfx::utils::createRotateAroundPoint(
+ aImportSize.Width / 2.0, aImportSize.Height / 2.0,
+ basegfx::deg2rad<60000>(nOOXAngle));
+ aB2DWrapPolyPolygon.transform(aMatrix);
+ }
+ basegfx::B2DRange aB2DWrapRange = aB2DWrapPolyPolygon.getB2DRange();
+
+ // Build a range from shape geometry
+ basegfx::B2DRange aShapeRange;
+ if (pShape)
+ {
+ basegfx::B2DPolyPolygon aShapePolygon = pShape->TakeXorPoly(); // Twips
+ aMatrix = basegfx::utils::createScaleB2DHomMatrix(
+ o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100),
+ o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100));
+ aShapePolygon.transform(aMatrix);
+ // Wrap polygon treats left/top of shape as origin, shift shape polygon accordingly
+ aMatrix = basegfx::utils::createTranslateB2DHomMatrix(
+ -aImportPosition.X, -aImportPosition.Y);
+ aShapePolygon.transform(aMatrix);
+ aShapeRange = aShapePolygon.getB2DRange();
+ }
+ else // can this happen?
+ {
+ aShapeRange
+ = basegfx::B2DRange(0, 0, aImportSize.Width, aImportSize.Height);
+ if (nOOXAngle != 0)
+ {
+ aMatrix = basegfx::utils::createRotateB2DHomMatrix(
+ basegfx::deg2rad<60000>(nOOXAngle));
+ aShapeRange.transform(aMatrix);
+ }
+ }
+
+ // Add difference between shape and wrap range to margin and remember
+ // difference in Twips for export.
+ comphelper::SequenceAsHashMap aAnchorDistDiff;
+
+ const double fTopDiff = aShapeRange.getMinY() - aB2DWrapRange.getMinY();
+ m_pImpl->nTopMargin += basegfx::fround(fTopDiff);
+ aAnchorDistDiff["distTDiff"] <<= basegfx::fround(
+ o3tl::convert(fTopDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ const double fBottomDiff = aB2DWrapRange.getMaxY() - aShapeRange.getMaxY();
+ m_pImpl->nBottomMargin += basegfx::fround(fBottomDiff);
+ aAnchorDistDiff["distBDiff"] <<= basegfx::fround(
+ o3tl::convert(fBottomDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ const double fLeftDiff = aShapeRange.getMinX() - aB2DWrapRange.getMinX();
+ m_pImpl->nLeftMargin += basegfx::fround(fLeftDiff);
+ aAnchorDistDiff["distLDiff"] <<= basegfx::fround(
+ o3tl::convert(fLeftDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ const double fRightDiff = aB2DWrapRange.getMaxX() - aShapeRange.getMaxX();
+ m_pImpl->nRightMargin += basegfx::fround(fRightDiff);
+ aAnchorDistDiff["distRDiff"] <<= basegfx::fround(
+ o3tl::convert(fRightDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ m_pImpl->m_aInteropGrabBag["AnchorDistDiff"]
+ <<= aAnchorDistDiff.getAsConstPropertyValueList();
+
+ // FixMe: tdf#141880. LibreOffice cannot handle negative horizontal margin in contour wrap
+ if (m_pImpl->nLeftMargin < 0)
+ m_pImpl->nLeftMargin = 0;
+ if (m_pImpl->nRightMargin < 0)
+ m_pImpl->nRightMargin = 0;
+ }
+ else if (!bIsDiagram) // text::WrapTextMode_THROUGH
+ {
+ // Word writes and evaluates the effectExtent in case of position
+ // type 'Alignment' (UI). We move these values to margin to approximate
+ // Word's rendering.
+ if (m_pImpl->m_oEffectExtentLeft)
+ {
+ m_pImpl->nLeftMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft);
+ }
+ if (m_pImpl->m_oEffectExtentTop)
+ {
+ m_pImpl->nTopMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop);
+ }
+ if (m_pImpl->m_oEffectExtentRight)
+ {
+ m_pImpl->nRightMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight);
+ }
+ if (m_pImpl->m_oEffectExtentBottom)
+ {
+ m_pImpl->nBottomMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom);
+ }
+ }
+
+ // FixMe: tdf#141880 LibreOffice cannot handle negative vertical margins
+ // although they are allowed in ODF.
+ if (m_pImpl->nTopMargin < 0)
+ m_pImpl->nTopMargin = 0;
+ if (m_pImpl->nBottomMargin < 0)
+ m_pImpl->nBottomMargin = 0;
+ }
+
+ if (bUseShape && m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ // If we are here, this is a drawingML shape. For those, only dmapper (and not oox) knows the anchoring infos (just like for Writer pictures).
+ // But they aren't Writer pictures, either (which are already handled above).
+ uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
+
+ if (m_pImpl->nWrap == text::WrapTextMode_THROUGH && m_pImpl->nHoriRelation == text::RelOrientation::FRAME)
+ {
+ // text::RelOrientation::FRAME is OOXML's "column", which behaves as if
+ // layout-in-cell would be always off.
+ m_pImpl->bLayoutInCell = false;
+ }
+
+ // Anchored: Word only supports at-char in that case.
+ text::TextContentAnchorType eAnchorType = text::TextContentAnchorType_AT_CHARACTER;
+
+ if (m_pImpl->bHidden)
+ {
+ xShapeProps->setPropertyValue("Visible", uno::Any(false));
+ xShapeProps->setPropertyValue("Printable", uno::Any(false));
+ }
+
+ // Avoid setting AnchorType for TextBoxes till SwTextBoxHelper::syncProperty() doesn't handle transition.
+ bool bTextBox = false;
+ xShapeProps->getPropertyValue("TextBox") >>= bTextBox;
+
+ // The positioning change caused by LayoutInCell doesn't sync well
+ // in the text / frame duo. So the compatibility fix only correctly
+ // positions the frame and not the text currently.
+ // tdf#135943: Instead of half-fixing and making a complete mess,
+ // just avoid until layout's repositioning is sync'd to the text frame.
+ if (m_pImpl->bLayoutInCell && bTextBox)
+ m_pImpl->bLayoutInCell = !m_pImpl->bCompatForcedLayoutInCell;
+
+ xShapeProps->setPropertyValue("AnchorType", uno::Any(eAnchorType));
+
+ if (m_pImpl->nVertRelation == text::RelOrientation::TEXT_LINE)
+ {
+ // Word's "line" is "below the bottom of the line", our TEXT_LINE is
+ // "towards top, from the bottom of the line", so invert the vertical
+ // position.
+ awt::Point aPoint = xShape->getPosition();
+ aPoint.Y *= -1;
+ xShape->setPosition(aPoint);
+ }
+
+ if (m_pImpl->bLayoutInCell && bTextBox && m_pImpl->rDomainMapper.IsInTable()
+ && m_pImpl->nHoriRelation == text::RelOrientation::PAGE_FRAME)
+ m_pImpl->nHoriRelation = text::RelOrientation::FRAME;
+ if(m_pImpl->rDomainMapper.IsInTable())
+ xShapeProps->setPropertyValue(getPropertyName(PROP_FOLLOW_TEXT_FLOW),
+ uno::Any(m_pImpl->bLayoutInCell));
+ //only the position orientation is handled in applyPosition()
+ m_pImpl->applyPosition(xShapeProps);
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
+ if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape") ||
+ xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ // You would expect that position and rotation are
+ // independent, but they are not. Till we are not
+ // there yet to handle all scaling, translation and
+ // rotation with a single transformation matrix,
+ // make sure there is no graphic rotation set when we set
+ // the position.
+ sal_Int32 nRotation = 0;
+ if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ xShapeProps->getPropertyValue("RotateAngle") >>= nRotation;
+ }
+ if (nRotation)
+ xShapeProps->setPropertyValue("RotateAngle", uno::Any(sal_Int32(0)));
+
+ // Position of the groupshape should be set after children have been added.
+ // Long-term we should get rid of positioning group
+ // shapes, though. Do it for top-level ones with
+ // absolute page position as a start.
+ // fdo#80555: also set position for graphic shapes here
+ if (!isTopGroupObj(m_xShape)
+ || m_pImpl->nHoriRelation != text::RelOrientation::PAGE_FRAME
+ || m_pImpl->nVertRelation != text::RelOrientation::PAGE_FRAME)
+ m_xShape->setPosition(
+ awt::Point(m_pImpl->nLeftPosition, m_pImpl->nTopPosition));
+
+ if (nRotation)
+ xShapeProps->setPropertyValue("RotateAngle", uno::Any(nRotation));
+ }
+
+
+ m_pImpl->applyRelativePosition(xShapeProps, /*bRelativeOnly=*/true);
+
+ xShapeProps->setPropertyValue("SurroundContour", uno::Any(m_pImpl->bContour));
+ xShapeProps->setPropertyValue("ContourOutside", uno::Any(m_pImpl->bContourOutside));
+ m_pImpl->applyMargins(xShapeProps);
+ xShapeProps->setPropertyValue("Opaque", uno::Any(m_pImpl->bOpaque));
+ xShapeProps->setPropertyValue("Surround", uno::Any(static_cast<sal_Int32>(m_pImpl->nWrap)));
+ m_pImpl->applyZOrder(xShapeProps);
+ m_pImpl->applyName(xShapeProps);
+ m_pImpl->applyHyperlink(xShapeProps, bUseShape);
+ xShapeProps->setPropertyValue("AllowOverlap",
+ uno::Any(m_pImpl->bAllowOverlap));
+
+ // Get the grab-bag set by oox, merge with our one and then put it back.
+ comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
+ aInteropGrabBag.update(m_pImpl->getInteropGrabBag());
+ xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag.getAsConstPropertyValueList()));
+ }
+ else if (bUseShape && m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
+ m_pImpl->applyMargins(xShapeProps);
+ m_pImpl->applyZOrder(xShapeProps);
+ comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
+ aInteropGrabBag.update(m_pImpl->getInteropGrabBag());
+ xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag.getAsConstPropertyValueList()));
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Inline_distT:
+ m_pImpl->nTopMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_Inline_distB:
+ m_pImpl->nBottomMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_Inline_distL:
+ m_pImpl->nLeftMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_Inline_distR:
+ m_pImpl->nRightMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectData_uri:
+ rValue.getString();
+ //TODO: does it need to be handled?
+ break;
+ case NS_ooxml::LN_CT_SizeRelH_relativeFrom:
+ {
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_ST_SizeRelFromH_margin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::FRAME));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromH_leftMargin:
+ case NS_ooxml::LN_ST_SizeRelFromH_outsideMargin:
+ if (m_xShape.is())
+ {
+ // Here we handle the relative size of the width of some shape.
+ // The size of the shape's width is going to be relative to the size of the left margin.
+ // E.g.: (left margin = 8 && relative size = 150%) -> width of some shape = 12.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_LEFT));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromH_rightMargin:
+ case NS_ooxml::LN_ST_SizeRelFromH_insideMargin:
+ if (m_xShape.is())
+ {
+ // Same as the left margin above.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_RIGHT));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromH_page:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_FRAME));
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "GraphicImport::lcl_attribute: unhandled NS_ooxml::LN_CT_SizeRelH_relativeFrom value: " << nIntValue);
+ break;
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SizeRelV_relativeFrom:
+ {
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_ST_SizeRelFromV_margin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::FRAME));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromV_page:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_FRAME));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromV_topMargin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_PRINT_AREA));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromV_bottomMargin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_PRINT_AREA_BOTTOM));
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "GraphicImport::lcl_attribute: unhandled NS_ooxml::LN_CT_SizeRelV_relativeFrom value: " << nIntValue);
+ break;
+ }
+ }
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+uno::Reference<text::XTextContent> GraphicImport::GetGraphicObject()
+{
+ uno::Reference<text::XTextContent> xResult;
+
+ if (m_xGraphicObject.is())
+ xResult = m_xGraphicObject;
+ else if (m_xShape.is())
+ {
+ xResult.set(m_xShape, uno::UNO_QUERY_THROW);
+ }
+
+ return xResult;
+}
+
+
+void GraphicImport::ProcessShapeOptions(Value const & rValue)
+{
+ sal_Int32 nIntValue = rValue.getInt();
+ switch( m_pImpl->nShapeOptionType )
+ {
+ case NS_ooxml::LN_CT_Anchor_distL:
+ m_pImpl->nLeftMargin = nIntValue / 360;
+ m_pImpl->nLeftMarginOrig = m_pImpl->nLeftMargin;
+ break;
+ case NS_ooxml::LN_CT_Anchor_distT:
+ //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustULWrapForWordMargins()
+ m_pImpl->nTopMargin = nIntValue / 360;
+ break;
+ case NS_ooxml::LN_CT_Anchor_distR:
+ //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustLRWrapForWordMargins()
+ m_pImpl->nRightMargin = nIntValue / 360;
+ break;
+ case NS_ooxml::LN_CT_Anchor_distB:
+ //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustULWrapForWordMargins()
+ m_pImpl->nBottomMargin = nIntValue / 360;
+ break;
+ default:
+ OSL_FAIL( "shape option unsupported?");
+ }
+}
+
+
+void GraphicImport::lcl_sprm(Sprm& rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_Inline_extent: // 90911;
+ case NS_ooxml::LN_CT_Inline_effectExtent: // 90912;
+ case NS_ooxml::LN_CT_Inline_docPr: // 90913;
+ case NS_ooxml::LN_CT_Inline_cNvGraphicFramePr: // 90914;
+ case NS_ooxml::LN_CT_NonVisualGraphicFrameProperties_graphicFrameLocks:// 90657
+ case NS_ooxml::LN_CT_Inline_a_graphic:// 90915
+ case NS_ooxml::LN_CT_Anchor_simplePos_elem: // 90975;
+ case NS_ooxml::LN_CT_Anchor_extent: // 90978;
+ case NS_ooxml::LN_CT_Anchor_effectExtent: // 90979;
+ case NS_ooxml::LN_EG_WrapType_wrapSquare: // 90945;
+ case NS_ooxml::LN_EG_WrapType_wrapTight: // 90946;
+ case NS_ooxml::LN_EG_WrapType_wrapThrough:
+ case NS_ooxml::LN_CT_Anchor_docPr: // 90980;
+ case NS_ooxml::LN_CT_Anchor_cNvGraphicFramePr: // 90981;
+ case NS_ooxml::LN_CT_Anchor_a_graphic: // 90982;
+ case NS_ooxml::LN_CT_WrapPath_start: // 90924;
+ case NS_ooxml::LN_CT_WrapPath_lineTo: // 90925;
+ case NS_ooxml::LN_graphic_graphic:
+ case NS_ooxml::LN_pic_pic:
+ case NS_ooxml::LN_dgm_relIds:
+ case NS_ooxml::LN_lc_lockedCanvas:
+ case NS_ooxml::LN_c_chart:
+ case NS_ooxml::LN_wps_wsp:
+ case NS_ooxml::LN_wpg_wgp:
+ case NS_ooxml::LN_sizeRelH_sizeRelH:
+ case NS_ooxml::LN_sizeRelV_sizeRelV:
+ case NS_ooxml::LN_hlinkClick_hlinkClick:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+
+ // We'll map these to PARALLEL, save the original wrap type.
+ if (nSprmId == NS_ooxml::LN_EG_WrapType_wrapTight)
+ m_pImpl->m_aInteropGrabBag["EG_WrapType"] <<= OUString("wrapTight");
+ else if (nSprmId == NS_ooxml::LN_EG_WrapType_wrapThrough)
+ m_pImpl->m_aInteropGrabBag["EG_WrapType"] <<= OUString("wrapThrough");
+
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_EG_WrapType_wrapSquare:
+ case NS_ooxml::LN_EG_WrapType_wrapThrough:
+ case NS_ooxml::LN_EG_WrapType_wrapTight:
+ {
+ // tdf#137850: Word >= 2013 seems to ignore bBehindDoc except for wrapNone, but older versions honour it.
+ if (m_pImpl->bBehindDoc && m_pImpl->rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ m_pImpl->bOpaque = true;
+ }
+ break;
+ }
+
+ }
+ break;
+ case NS_ooxml::LN_CT_WrapTight_wrapPolygon:
+ case NS_ooxml::LN_CT_WrapThrough_wrapPolygon:
+ {
+ WrapPolygonHandler aHandler;
+
+ resolveSprmProps(aHandler, rSprm);
+
+ m_pImpl->mpWrapPolygon = aHandler.getPolygon();
+
+ // Save the wrap path in case we can't handle it natively: drawinglayer shapes, TextFrames.
+ m_pImpl->m_aInteropGrabBag["CT_WrapPath"] <<= m_pImpl->mpWrapPolygon->getPointSequenceSequence();
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_positionH: // 90976;
+ {
+ // Use a special handler for the positioning
+ auto pHandler = std::make_shared<PositionHandler>( m_pImpl->m_rPositionOffsets, m_pImpl->m_rAligns );
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve( *pHandler );
+ if( !m_pImpl->bUseSimplePos )
+ {
+ m_pImpl->nHoriRelation = pHandler->relation();
+ m_pImpl->bPageToggle = pHandler->GetPageToggle();
+ m_pImpl->nHoriOrient = pHandler->orientation();
+ m_pImpl->nLeftPosition = pHandler->position();
+
+ // Left adjustments: if horizontally aligned to left of margin, then remove the
+ // left wrapping.
+ if (m_pImpl->nHoriOrient == text::HoriOrientation::LEFT)
+ {
+ if (m_pImpl->nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA)
+ {
+ m_pImpl->nLeftMargin = 0;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_positionV: // 90977;
+ {
+ // Use a special handler for the positioning
+ auto pHandler = std::make_shared<PositionHandler>( m_pImpl->m_rPositionOffsets, m_pImpl->m_rAligns);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve( *pHandler );
+ if( !m_pImpl->bUseSimplePos )
+ {
+ m_pImpl->nVertRelation = pHandler->relation();
+ m_pImpl->nVertOrient = pHandler->orientation();
+ m_pImpl->nTopPosition = pHandler->position();
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SizeRelH_pctWidth:
+ case NS_ooxml::LN_CT_SizeRelV_pctHeight:
+ if (m_pImpl->m_rPositivePercentages.empty())
+ break;
+
+ if (m_xShape.is())
+ {
+ sal_Int16 nPositivePercentage = rtl::math::round(m_pImpl->m_rPositivePercentages.front().toDouble() / oox::drawingml::PER_PERCENT);
+
+ if (nPositivePercentage)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ OUString aProperty = nSprmId == NS_ooxml::LN_CT_SizeRelH_pctWidth ? OUString("RelativeWidth") : OUString("RelativeHeight");
+
+ sal_Int32 nTextPreRotateAngle = 0;
+ uno::Any aAny;
+ if (xPropertySet->getPropertySetInfo()->hasPropertyByName(
+ "CustomShapeGeometry"))
+ {
+ aAny = xPropertySet->getPropertyValue("CustomShapeGeometry");
+ }
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(aAny);
+ auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
+ if (it != aCustomShapeGeometry.end())
+ {
+ nTextPreRotateAngle = it->second.get<sal_Int32>();
+ }
+ if (nTextPreRotateAngle == 0)
+ {
+ xPropertySet->setPropertyValue(aProperty,
+ uno::Any(nPositivePercentage));
+ }
+ }
+ }
+
+ // Make sure the token is consumed even if xShape is an empty
+ // reference.
+ m_pImpl->m_rPositivePercentages.pop();
+ break;
+ case NS_ooxml::LN_EG_WrapType_wrapNone: // 90944; - doesn't contain attributes
+ //depending on the behindDoc attribute text wraps through behind or in front of the object
+ m_pImpl->nWrap = text::WrapTextMode_THROUGH;
+
+ // Wrap though means the margins defined earlier should not be
+ // respected.
+ m_pImpl->nLeftMargin = 0;
+ m_pImpl->nTopMargin = 0;
+ m_pImpl->nRightMargin = 0;
+ m_pImpl->nBottomMargin = 0;
+ break;
+ case NS_ooxml::LN_EG_WrapType_wrapTopAndBottom: // 90948;
+ // tdf#137850: Word >= 2013 seems to ignore bBehindDoc except for wrapNone, but older versions honour it.
+ if (m_pImpl->bBehindDoc && m_pImpl->rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ m_pImpl->bOpaque = true;
+ m_pImpl->nWrap = text::WrapTextMode_NONE;
+ break;
+ case NS_ooxml::LN_CT_GraphicalObject_graphicData:// 90660;
+ {
+ m_pImpl->bIsGraphic = true;
+
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_a_hlinkClick: // 90689;
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve( *this );
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "GraphicImport::lcl_sprm: unhandled token: " << nSprmId);
+ break;
+ }
+}
+
+void GraphicImport::lcl_entry(writerfilter::Reference<Properties>::Pointer_t /*ref*/)
+{
+}
+
+uno::Reference<text::XTextContent> GraphicImport::createGraphicObject(uno::Reference<graphic::XGraphic> const & rxGraphic,
+ uno::Reference<beans::XPropertySet> const & xShapeProps)
+{
+ uno::Reference<text::XTextContent> xGraphicObject;
+ try
+ {
+ if (rxGraphic.is())
+ {
+ uno::Reference< beans::XPropertySet > xGraphicObjectProperties(
+ m_xTextFactory->createInstance("com.sun.star.text.TextGraphicObject"),
+ uno::UNO_QUERY_THROW);
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_GRAPHIC), uno::Any(rxGraphic));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE),
+ uno::Any( m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR ?
+ text::TextContentAnchorType_AT_CHARACTER :
+ text::TextContentAnchorType_AS_CHARACTER ));
+ xGraphicObject.set( xGraphicObjectProperties, uno::UNO_QUERY_THROW );
+
+ //shapes have only one border
+ table::BorderLine2 aBorderLine;
+ GraphicBorderLine& rBorderLine = m_pImpl->aBorders[0];
+ if (rBorderLine.isEmpty() && xShapeProps.is() && xShapeProps->getPropertyValue("LineStyle").get<drawing::LineStyle>() != drawing::LineStyle_NONE)
+ {
+ // In case we got no border tokens and we have the
+ // original shape, then use its line properties as the
+ // border.
+ aBorderLine.Color = xShapeProps->getPropertyValue("LineColor").get<sal_Int32>();
+ aBorderLine.LineWidth = xShapeProps->getPropertyValue("LineWidth").get<sal_Int32>();
+ }
+ else
+ {
+ aBorderLine.Color = 0;
+ aBorderLine.InnerLineWidth = 0;
+ aBorderLine.OuterLineWidth = static_cast<sal_Int16>(rBorderLine.nLineWidth);
+ aBorderLine.LineDistance = 0;
+ }
+ PropertyIds const aBorderProps[] =
+ {
+ PROP_LEFT_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_TOP_BORDER,
+ PROP_BOTTOM_BORDER
+ };
+
+ for(PropertyIds const & rBorderProp : aBorderProps)
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(rBorderProp), uno::Any(aBorderLine));
+
+ // setting graphic object shadow properties
+ if (m_pImpl->bShadow)
+ {
+ // Shadow width is approximated by average of X and Y
+ table::ShadowFormat aShadow;
+ sal_uInt32 nShadowColor = m_pImpl->nShadowColor & 0x00FFFFFF; // The shadow color we get is RGB only.
+ sal_Int32 nShadowWidth = (abs(m_pImpl->nShadowXDistance)
+ + abs(m_pImpl->nShadowYDistance)) / 2;
+
+ aShadow.ShadowWidth = nShadowWidth;
+ sal_uInt8 nShadowTransparence = float(m_pImpl->nShadowTransparence) * 2.55;
+ nShadowColor |= (nShadowTransparence << 24); // Add transparence to the color.
+ aShadow.Color = nShadowColor;
+ // Distances -ve for top and right, +ve for bottom and left
+ if (m_pImpl->nShadowXDistance > 0)
+ {
+ if (m_pImpl->nShadowYDistance > 0)
+ aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT;
+ else
+ aShadow.Location = table::ShadowLocation_TOP_RIGHT;
+ }
+ else
+ {
+ if (m_pImpl->nShadowYDistance > 0)
+ aShadow.Location = table::ShadowLocation_BOTTOM_LEFT;
+ else
+ aShadow.Location = table::ShadowLocation_TOP_LEFT;
+ }
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_SHADOW_FORMAT), uno::Any(aShadow));
+ }
+
+ // setting properties for all types
+ if( m_pImpl->bPositionProtected )
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_POSITION_PROTECTED ),
+ uno::Any(true));
+ if( m_pImpl->bSizeProtected )
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SIZE_PROTECTED ),
+ uno::Any(true));
+
+ sal_Int32 nWidth = - m_pImpl->nLeftPosition;
+ if (m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ //adjust margins
+ if( (m_pImpl->nHoriOrient == text::HoriOrientation::LEFT &&
+ (m_pImpl->nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->nHoriRelation == text::RelOrientation::FRAME) ) ||
+ (m_pImpl->nHoriOrient == text::HoriOrientation::INSIDE &&
+ m_pImpl->nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ))
+ m_pImpl->nLeftMargin = 0;
+ if((m_pImpl->nHoriOrient == text::HoriOrientation::RIGHT &&
+ (m_pImpl->nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->nHoriRelation == text::RelOrientation::FRAME) ) ||
+ (m_pImpl->nHoriOrient == text::HoriOrientation::INSIDE &&
+ m_pImpl->nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ))
+ m_pImpl->nRightMargin = 0;
+ // adjust top/bottom margins
+ if( m_pImpl->nVertOrient == text::VertOrientation::TOP &&
+ ( m_pImpl->nVertRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->nVertRelation == text::RelOrientation::PAGE_FRAME))
+ m_pImpl->nTopMargin = 0;
+ if( m_pImpl->nVertOrient == text::VertOrientation::BOTTOM &&
+ ( m_pImpl->nVertRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->nVertRelation == text::RelOrientation::PAGE_FRAME))
+ m_pImpl->nBottomMargin = 0;
+ if( m_pImpl->nVertOrient == text::VertOrientation::BOTTOM &&
+ m_pImpl->nVertRelation == text::RelOrientation::PAGE_PRINT_AREA )
+ m_pImpl->nBottomMargin = 0;
+ //adjust alignment
+ if( m_pImpl->nHoriOrient == text::HoriOrientation::INSIDE &&
+ m_pImpl->nHoriRelation == text::RelOrientation::PAGE_FRAME )
+ {
+ // convert 'left to page' to 'from left -<width> to page text area'
+ m_pImpl->nHoriOrient = text::HoriOrientation::NONE;
+ m_pImpl->nHoriRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ m_pImpl->nLeftPosition = - nWidth;
+ }
+ else if( m_pImpl->nHoriOrient == text::HoriOrientation::OUTSIDE &&
+ m_pImpl->nHoriRelation == text::RelOrientation::PAGE_FRAME )
+ {
+ // convert 'right to page' to 'from left 0 to right page border'
+ m_pImpl->nHoriOrient = text::HoriOrientation::NONE;
+ m_pImpl->nHoriRelation = text::RelOrientation::PAGE_RIGHT;
+ m_pImpl->nLeftPosition = 0;
+ }
+
+ m_pImpl->applyPosition(xGraphicObjectProperties);
+ m_pImpl->applyRelativePosition(xGraphicObjectProperties);
+ if( !m_pImpl->bOpaque )
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any(m_pImpl->bOpaque));
+ }
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND ),
+ uno::Any(static_cast<sal_Int32>(m_pImpl->nWrap)));
+ if( m_pImpl->rDomainMapper.IsInTable())
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_FOLLOW_TEXT_FLOW ),
+ uno::Any(m_pImpl->bLayoutInCell));
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND_CONTOUR ),
+ uno::Any(m_pImpl->bContour));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_CONTOUR_OUTSIDE ),
+ uno::Any(m_pImpl->bContourOutside));
+ m_pImpl->applyMargins(xGraphicObjectProperties);
+ }
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_CONTRAST ),
+ uno::Any(static_cast<sal_Int16>(m_pImpl->nContrast)));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_LUMINANCE ),
+ uno::Any(static_cast<sal_Int16>(m_pImpl->nBrightness)));
+ if(m_pImpl->eColorMode != drawing::ColorMode_STANDARD)
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC_COLOR_MODE ),
+ uno::Any(m_pImpl->eColorMode));
+ }
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BACK_COLOR ),
+ uno::Any( GraphicImport_Impl::nFillColor ));
+ m_pImpl->applyZOrder(xGraphicObjectProperties);
+
+ //there seems to be no way to detect the original size via _real_ API
+ uno::Reference< beans::XPropertySet > xGraphicProperties(rxGraphic, uno::UNO_QUERY_THROW);
+
+ if (m_pImpl->mpWrapPolygon)
+ {
+ uno::Any aContourPolyPolygon;
+ awt::Size aGraphicSize;
+ WrapPolygon::Pointer_t pCorrected;
+ xGraphicProperties->getPropertyValue(getPropertyName(PROP_SIZE100th_M_M)) >>= aGraphicSize;
+ if (aGraphicSize.Width && aGraphicSize.Height)
+ {
+ pCorrected = m_pImpl->mpWrapPolygon->correctWordWrapPolygon(aGraphicSize);
+ }
+ else
+ {
+ xGraphicProperties->getPropertyValue(getPropertyName(PROP_SIZE_PIXEL)) >>= aGraphicSize;
+ if (aGraphicSize.Width && aGraphicSize.Height)
+ {
+ pCorrected = m_pImpl->mpWrapPolygon->correctWordWrapPolygonPixel(aGraphicSize);
+ }
+ }
+
+ text::GraphicCrop aGraphicCrop;
+ xShapeProps->getPropertyValue("GraphicCrop") >>= aGraphicCrop;
+ if (aGraphicCrop.Top != 0 || aGraphicCrop.Bottom != 0 || aGraphicCrop.Left != 0
+ || aGraphicCrop.Right != 0)
+ {
+ // Word's wrap polygon deals with a canvas which has the size of the already
+ // cropped graphic, correct our polygon to have the same render result.
+ pCorrected = pCorrected->correctCrop(aGraphicSize, aGraphicCrop);
+ }
+
+ if (pCorrected)
+ {
+ aContourPolyPolygon <<= pCorrected->getPointSequenceSequence();
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_CONTOUR_POLY_POLYGON),
+ aContourPolyPolygon);
+ // We should bring it to front, even if wp:anchor's behindDoc="1",
+ // because otherwise paragraph background (if set) overlaps the graphic
+ // TODO: if paragraph's background becomes bottommost, then remove this hack
+ xGraphicObjectProperties->setPropertyValue("Opaque", uno::Any(true));
+ }
+ }
+
+
+ if(m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_INLINE || m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ if( m_pImpl->getXSize() && m_pImpl->getYSize() )
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_SIZE),
+ uno::Any( awt::Size( m_pImpl->getXSize(), m_pImpl->getYSize() )));
+ m_pImpl->applyMargins(xGraphicObjectProperties);
+ m_pImpl->applyName(xGraphicObjectProperties);
+ m_pImpl->applyHyperlink(xGraphicObjectProperties, false);
+ }
+
+ // Handle horizontal flip.
+ bool bMirrored = false;
+ xShapeProps->getPropertyValue("IsMirrored") >>= bMirrored;
+ if (bMirrored)
+ {
+ xGraphicObjectProperties->setPropertyValue("HoriMirroredOnEvenPages",
+ uno::Any(true));
+ xGraphicObjectProperties->setPropertyValue("HoriMirroredOnOddPages",
+ uno::Any(true));
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "");
+ }
+ return xGraphicObject;
+}
+
+
+void GraphicImport::data(const sal_uInt8* buf, size_t len)
+{
+ uno::Reference< io::XInputStream > xIStream = new XInputStreamHelper( buf, len );
+ beans::PropertyValues aMediaProperties{ comphelper::makePropertyValue(
+ getPropertyName(PROP_INPUT_STREAM), xIStream) };
+
+ uno::Reference<beans::XPropertySet> xPropertySet;
+ uno::Reference<graphic::XGraphicProvider> xGraphicProvider(graphic::GraphicProvider::create(m_xComponentContext));
+ uno::Reference<graphic::XGraphic> xGraphic = xGraphicProvider->queryGraphic(aMediaProperties);
+ m_xGraphicObject = createGraphicObject(xGraphic, xPropertySet);
+}
+
+
+void GraphicImport::lcl_startSectionGroup()
+{
+}
+
+
+void GraphicImport::lcl_endSectionGroup()
+{
+}
+
+
+void GraphicImport::lcl_startParagraphGroup()
+{
+}
+
+
+void GraphicImport::lcl_endParagraphGroup()
+{
+}
+
+
+void GraphicImport::lcl_startCharacterGroup()
+{
+}
+
+
+void GraphicImport::lcl_endCharacterGroup()
+{
+}
+
+
+void GraphicImport::lcl_text(const sal_uInt8 * /*_data*/, size_t /*len*/)
+{
+}
+
+
+void GraphicImport::lcl_utext(const sal_uInt8 * /*_data*/, size_t /*len*/)
+{
+}
+
+
+void GraphicImport::lcl_props(writerfilter::Reference<Properties>::Pointer_t /*ref*/)
+{
+}
+
+
+void GraphicImport::lcl_table(Id /*name*/, writerfilter::Reference<Table>::Pointer_t /*ref*/)
+{
+}
+
+
+void GraphicImport::lcl_substream(Id /*name*/, ::writerfilter::Reference<Stream>::Pointer_t /*ref*/)
+{
+}
+
+void GraphicImport::lcl_startShape(uno::Reference<drawing::XShape> const&)
+{
+}
+
+void GraphicImport::lcl_endShape( )
+{
+}
+
+bool GraphicImport::IsGraphic() const
+{
+ return m_pImpl->bIsGraphic;
+}
+
+sal_Int32 GraphicImport::GetLeftMarginOrig() const
+{
+ return m_pImpl->nLeftMarginOrig;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/GraphicImport.hxx b/writerfilter/source/dmapper/GraphicImport.hxx
new file mode 100644
index 000000000..93be2df3f
--- /dev/null
+++ b/writerfilter/source/dmapper/GraphicImport.hxx
@@ -0,0 +1,140 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <queue>
+#include <memory>
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+namespace com::sun::star {
+ namespace uno
+ {
+ class XComponentContext;
+ }
+ namespace lang
+ {
+ class XMultiServiceFactory;
+ }
+ namespace text
+ {
+ class XTextContent;
+ }
+ namespace drawing
+ {
+ class XShape;
+ }
+ namespace beans
+ {
+ struct PropertyValue;
+ }
+}
+
+namespace writerfilter::dmapper
+{
+class GraphicImport_Impl;
+class DomainMapper;
+
+enum GraphicImportType
+{
+ IMPORT_AS_DETECTED_INLINE,
+ IMPORT_AS_DETECTED_ANCHOR
+};
+
+class GraphicImport : public LoggedProperties, public LoggedTable
+ ,public BinaryObj, public LoggedStream
+{
+ std::unique_ptr<GraphicImport_Impl> m_pImpl;
+
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xTextFactory;
+
+ css::uno::Reference<css::text::XTextContent> m_xGraphicObject;
+
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ void ProcessShapeOptions(Value const & val);
+
+ css::uno::Reference<css::text::XTextContent>
+ createGraphicObject(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
+ css::uno::Reference<css::beans::XPropertySet> const & xShapeProps);
+
+ void putPropertyToFrameGrabBag( const OUString& sPropertyName, const css::uno::Any& aPropertyValue );
+
+public:
+ explicit GraphicImport( css::uno::Reference<css::uno::XComponentContext> const& xComponentContext,
+ css::uno::Reference<css::lang::XMultiServiceFactory> const& xTextFactory,
+ DomainMapper& rDomainMapper,
+ GraphicImportType eGraphicImportType,
+ std::pair<OUString, OUString>& rPositionOffsets,
+ std::pair<OUString, OUString>& rAligns,
+ std::queue<OUString>& rPositivePercentages);
+ virtual ~GraphicImport() override;
+
+ // BinaryObj
+ virtual void data(const sal_uInt8* buffer, size_t len) override;
+
+ css::uno::Reference<css::text::XTextContent> GetGraphicObject();
+ const css::uno::Reference<css::drawing::XShape>& GetXShapeObject() const { return m_xShape;}
+ bool IsGraphic() const;
+ sal_Int32 GetLeftMarginOrig() const;
+
+ com::sun::star::awt::Point GetGraphicObjectPosition() const;
+
+ bool GetLayoutInCell() const;
+
+ private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+ // Stream
+ virtual void lcl_startSectionGroup() override;
+ virtual void lcl_endSectionGroup() override;
+ virtual void lcl_startParagraphGroup() override;
+ virtual void lcl_endParagraphGroup() override;
+ virtual void lcl_startCharacterGroup() override;
+ virtual void lcl_endCharacterGroup() override;
+ virtual void lcl_text(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_utext(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_props(writerfilter::Reference<Properties>::Pointer_t ref) override;
+ virtual void lcl_table(Id name,
+ writerfilter::Reference<Table>::Pointer_t ref) override;
+ virtual void lcl_substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref) override;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ virtual void lcl_startTextBoxContent() override {};
+ virtual void lcl_endTextBoxContent() override {};
+ virtual void lcl_endShape() override;
+
+ void handleWrapTextValue(sal_uInt32 nVal);
+ void lcl_expandRectangleByEffectExtent(css::awt::Point& rLeftTop, css::awt::Size& rSize);
+ void lcl_correctWord2007EffectExtent(const sal_Int32 nMSOAngle);
+};
+
+typedef tools::SvRef<GraphicImport> GraphicImportPtr;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/LatentStyleHandler.cxx b/writerfilter/source/dmapper/LatentStyleHandler.cxx
new file mode 100644
index 000000000..bc381d21f
--- /dev/null
+++ b/writerfilter/source/dmapper/LatentStyleHandler.cxx
@@ -0,0 +1,71 @@
+/* -*- 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 "LatentStyleHandler.hxx"
+#include "TagLogger.hxx"
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+LatentStyleHandler::LatentStyleHandler()
+ : LoggedProperties("LatentStyleHandler")
+{
+}
+
+LatentStyleHandler::~LatentStyleHandler() = default;
+
+void LatentStyleHandler::lcl_attribute(Id nId, Value& rVal)
+{
+ beans::PropertyValue aValue;
+ bool bFound = true;
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_LsdException_name:
+ aValue.Name = "name";
+ break;
+ case NS_ooxml::LN_CT_LsdException_locked:
+ aValue.Name = "locked";
+ break;
+ case NS_ooxml::LN_CT_LsdException_uiPriority:
+ aValue.Name = "uiPriority";
+ break;
+ case NS_ooxml::LN_CT_LsdException_semiHidden:
+ aValue.Name = "semiHidden";
+ break;
+ case NS_ooxml::LN_CT_LsdException_unhideWhenUsed:
+ aValue.Name = "unhideWhenUsed";
+ break;
+ case NS_ooxml::LN_CT_LsdException_qFormat:
+ aValue.Name = "qFormat";
+ break;
+ default:
+ bFound = false;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+ if (bFound)
+ {
+ aValue.Value <<= rVal.getString();
+ m_aAttributes.push_back(aValue);
+ }
+}
+
+void LatentStyleHandler::lcl_sprm(Sprm& /*rSprm*/) {}
+
+const std::vector<beans::PropertyValue>& LatentStyleHandler::getAttributes() const
+{
+ return m_aAttributes;
+}
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/LatentStyleHandler.hxx b/writerfilter/source/dmapper/LatentStyleHandler.hxx
new file mode 100644
index 000000000..52a4d9e7c
--- /dev/null
+++ b/writerfilter/source/dmapper/LatentStyleHandler.hxx
@@ -0,0 +1,35 @@
+/* -*- 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/.
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+/// Handler for a latent style (w:lsdException element)
+class LatentStyleHandler : public LoggedProperties
+{
+ std::vector<css::beans::PropertyValue> m_aAttributes;
+
+ // Properties
+ void lcl_attribute(Id nId, Value& rVal) override;
+ void lcl_sprm(Sprm& sprm) override;
+
+public:
+ LatentStyleHandler();
+ ~LatentStyleHandler() override;
+
+ const std::vector<css::beans::PropertyValue>& getAttributes() const;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/LoggedResources.cxx b/writerfilter/source/dmapper/LoggedResources.cxx
new file mode 100644
index 000000000..4eeb5db10
--- /dev/null
+++ b/writerfilter/source/dmapper/LoggedResources.cxx
@@ -0,0 +1,400 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "LoggedResources.hxx"
+#include "TagLogger.hxx"
+#include <ooxml/QNameToString.hxx>
+
+using namespace ::com::sun::star;
+
+namespace writerfilter
+{
+#ifdef DBG_UTIL
+
+LoggedResourcesHelper::LoggedResourcesHelper(const std::string& sPrefix)
+ : msPrefix(sPrefix)
+{
+}
+
+LoggedResourcesHelper::~LoggedResourcesHelper() {}
+
+void LoggedResourcesHelper::startElement(const std::string& sElement)
+{
+ TagLogger::getInstance().startElement(msPrefix + "." + sElement);
+}
+
+void LoggedResourcesHelper::endElement() { TagLogger::getInstance().endElement(); }
+
+void LoggedResourcesHelper::chars(std::u16string_view rChars)
+{
+ TagLogger::getInstance().chars(rChars);
+}
+
+void LoggedResourcesHelper::chars(const std::string& rChars)
+{
+ TagLogger::getInstance().chars(rChars);
+}
+
+void LoggedResourcesHelper::attribute(const std::string& rName, const std::string& rValue)
+{
+ TagLogger::getInstance().attribute(rName, rValue);
+}
+
+void LoggedResourcesHelper::attribute(const std::string& rName, sal_uInt32 nValue)
+{
+ TagLogger::getInstance().attribute(rName, nValue);
+}
+
+#endif
+
+LoggedStream::LoggedStream(
+#ifdef DBG_UTIL
+ const std::string& sPrefix)
+ : mHelper(sPrefix)
+#else
+ const std::string&)
+#endif
+{
+}
+
+LoggedStream::~LoggedStream() {}
+
+void LoggedStream::startSectionGroup()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("section");
+#endif
+
+ lcl_startSectionGroup();
+}
+
+void LoggedStream::endSectionGroup()
+{
+ lcl_endSectionGroup();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startParagraphGroup()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("paragraph");
+#endif
+
+ lcl_startParagraphGroup();
+}
+
+void LoggedStream::endParagraphGroup()
+{
+ lcl_endParagraphGroup();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startCharacterGroup()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("charactergroup");
+#endif
+
+ lcl_startCharacterGroup();
+}
+
+void LoggedStream::endCharacterGroup()
+{
+ lcl_endCharacterGroup();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startShape(uno::Reference<drawing::XShape> const& xShape)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("shape");
+#endif
+
+ lcl_startShape(xShape);
+}
+
+void LoggedStream::endShape()
+{
+ lcl_endShape();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startTextBoxContent() { lcl_startTextBoxContent(); }
+
+void LoggedStream::endTextBoxContent() { lcl_endTextBoxContent(); }
+
+void LoggedStream::text(const sal_uInt8* data, size_t len)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("text");
+
+ OUString sText(reinterpret_cast<const char*>(data), len, RTL_TEXTENCODING_MS_1252);
+
+ mHelper.startElement("data");
+ LoggedResourcesHelper::chars(sText);
+ LoggedResourcesHelper::endElement();
+#endif
+
+ lcl_text(data, len);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::utext(const sal_uInt8* data, size_t len)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("utext");
+ mHelper.startElement("data");
+
+ OUString sText(reinterpret_cast<const sal_Unicode*>(data), len);
+
+ LoggedResourcesHelper::chars(sText);
+
+ LoggedResourcesHelper::endElement();
+#endif
+
+ lcl_utext(data, len);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::positionOffset(const OUString& rText, bool bVertical)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("positionOffset");
+ LoggedResourcesHelper::attribute("vertical", static_cast<int>(bVertical));
+ LoggedResourcesHelper::chars(rText);
+#endif
+
+ lcl_positionOffset(rText, bVertical);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::align(const OUString& rText, bool bVertical)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("align");
+ LoggedResourcesHelper::attribute("vertical", static_cast<int>(bVertical));
+ LoggedResourcesHelper::chars(rText);
+#endif
+
+ lcl_align(rText, bVertical);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::positivePercentage(const OUString& rText)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("positivePercentage");
+ LoggedResourcesHelper::chars(rText);
+#endif
+
+ lcl_positivePercentage(rText);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::props(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("props");
+#endif
+
+ lcl_props(ref);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::table(Id name, writerfilter::Reference<Table>::Pointer_t ref)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("table");
+ LoggedResourcesHelper::attribute("name", QNameToString(name));
+#endif
+
+ lcl_table(name, ref);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("substream");
+ LoggedResourcesHelper::attribute("name", QNameToString(name));
+#endif
+
+ lcl_substream(name, ref);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::info(const std::string& _info)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("info");
+ LoggedResourcesHelper::attribute("text", _info);
+#else
+ (void)_info;
+#endif
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startGlossaryEntry()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("startGlossaryEntry");
+#endif
+
+ lcl_startGlossaryEntry();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::endGlossaryEntry()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("endGlossaryEntry");
+#endif
+
+ lcl_endGlossaryEntry();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::checkId(const sal_Int32 nId)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("checkId");
+ LoggedResourcesHelper::chars(OUString::number(nId));
+#endif
+
+ lcl_checkId(nId);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+LoggedProperties::LoggedProperties(
+#ifdef DBG_UTIL
+ const std::string& sPrefix)
+ : mHelper(sPrefix)
+#else
+ const std::string&)
+#endif
+{
+}
+
+LoggedProperties::~LoggedProperties() {}
+
+void LoggedProperties::attribute(Id name, Value& val)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("attribute");
+ LoggedResourcesHelper::attribute("name", QNameToString(name));
+ LoggedResourcesHelper::attribute("value", val.toString());
+ LoggedResourcesHelper::endElement();
+#endif
+
+ lcl_attribute(name, val);
+}
+
+void LoggedProperties::sprm(Sprm& rSprm)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("sprm");
+ LoggedResourcesHelper::attribute("name", QNameToString(rSprm.getId()));
+ LoggedResourcesHelper::chars(rSprm.toString());
+#endif
+
+ lcl_sprm(rSprm);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+LoggedTable::LoggedTable(
+#ifdef DBG_UTIL
+ const std::string& sPrefix)
+ : mHelper(sPrefix)
+#else
+ const std::string&)
+#endif
+{
+}
+
+LoggedTable::~LoggedTable() {}
+
+void LoggedTable::entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("entry");
+ LoggedResourcesHelper::attribute("pos", pos);
+#else
+ (void)pos;
+#endif
+
+ lcl_entry(ref);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/LoggedResources.hxx b/writerfilter/source/dmapper/LoggedResources.hxx
new file mode 100644
index 000000000..76efbe5c4
--- /dev/null
+++ b/writerfilter/source/dmapper/LoggedResources.hxx
@@ -0,0 +1,144 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter
+{
+#ifdef DBG_UTIL
+class LoggedResourcesHelper final
+{
+public:
+ explicit LoggedResourcesHelper(const std::string& sPrefix);
+ ~LoggedResourcesHelper();
+
+ void startElement(const std::string& sElement);
+ static void endElement();
+ static void chars(std::u16string_view rChars);
+ static void chars(const std::string& rChars);
+ static void attribute(const std::string& rName, const std::string& rValue);
+ static void attribute(const std::string& rName, sal_uInt32 nValue);
+
+private:
+ std::string msPrefix;
+};
+#endif
+
+class LoggedStream : public Stream
+{
+public:
+ explicit LoggedStream(const std::string& sPrefix);
+ virtual ~LoggedStream() override;
+
+ void startSectionGroup() override;
+ void endSectionGroup() override;
+ void startParagraphGroup() override;
+ void endParagraphGroup() override;
+ void startCharacterGroup() override;
+ void endCharacterGroup() override;
+ void startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ void endShape() override;
+ void startTextBoxContent() override;
+ void endTextBoxContent() override;
+ void text(const sal_uInt8* data, size_t len) override;
+ void utext(const sal_uInt8* data, size_t len) override;
+ void positionOffset(const OUString& rText, bool bVertical) override;
+ void align(const OUString& rText, bool bVertical) override;
+ void positivePercentage(const OUString& rText) override;
+ void props(writerfilter::Reference<Properties>::Pointer_t ref) override;
+ void table(Id name, writerfilter::Reference<Table>::Pointer_t ref) override;
+ void substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref) override;
+ void info(const std::string& info) override;
+ void startGlossaryEntry() override;
+ void endGlossaryEntry() override;
+ void checkId(const sal_Int32 nId) override;
+
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* /*pDocument*/) override{};
+
+protected:
+ virtual void lcl_startSectionGroup() = 0;
+ virtual void lcl_endSectionGroup() = 0;
+ virtual void lcl_startParagraphGroup() = 0;
+ virtual void lcl_endParagraphGroup() = 0;
+ virtual void lcl_startCharacterGroup() = 0;
+ virtual void lcl_endCharacterGroup() = 0;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) = 0;
+ virtual void lcl_endShape() = 0;
+ virtual void lcl_startTextBoxContent() = 0;
+ virtual void lcl_endTextBoxContent() = 0;
+ virtual void lcl_text(const sal_uInt8* data, size_t len) = 0;
+ virtual void lcl_utext(const sal_uInt8* data, size_t len) = 0;
+ virtual void lcl_positionOffset(const OUString& /*rText*/, bool /*bVertical*/) {}
+ virtual css::awt::Point getPositionOffset() override { return css::awt::Point(); }
+ virtual void lcl_align(const OUString& /*rText*/, bool /*bVertical*/) {}
+ virtual void lcl_positivePercentage(const OUString& /*rText*/) {}
+ virtual void lcl_props(writerfilter::Reference<Properties>::Pointer_t ref) = 0;
+ virtual void lcl_table(Id name, writerfilter::Reference<Table>::Pointer_t ref) = 0;
+ virtual void lcl_substream(Id name, writerfilter::Reference<Stream>::Pointer_t ref) = 0;
+ virtual void lcl_startGlossaryEntry() {}
+ virtual void lcl_endGlossaryEntry() {}
+ virtual void lcl_checkId(const sal_Int32) {}
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper mHelper;
+#endif
+};
+
+class LoggedProperties : public Properties
+{
+public:
+ explicit LoggedProperties(const std::string& sPrefix);
+ virtual ~LoggedProperties() override;
+
+ void attribute(Id name, Value& val) override;
+ void sprm(Sprm& sprm) override;
+
+protected:
+ virtual void lcl_attribute(Id name, Value& val) = 0;
+ virtual void lcl_sprm(Sprm& sprm) = 0;
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper mHelper;
+#endif
+};
+
+class LoggedTable : public Table
+{
+public:
+ explicit LoggedTable(const std::string& sPrefix);
+ virtual ~LoggedTable() override;
+
+ void entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+protected:
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) = 0;
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper mHelper;
+#endif
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/MeasureHandler.cxx b/writerfilter/source/dmapper/MeasureHandler.cxx
new file mode 100644
index 000000000..5eea9a5c6
--- /dev/null
+++ b/writerfilter/source/dmapper/MeasureHandler.cxx
@@ -0,0 +1,136 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "MeasureHandler.hxx"
+#include "ConversionHelper.hxx"
+#include <ooxml/resourceids.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/text/SizeType.hpp>
+#include <comphelper/sequence.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+MeasureHandler::MeasureHandler() :
+LoggedProperties("MeasureHandler"),
+m_nMeasureValue( 0 ),
+m_nUnit( -1 ),
+m_nRowHeightSizeType( text::SizeType::MIN )
+{
+}
+
+
+MeasureHandler::~MeasureHandler()
+{
+}
+
+
+void MeasureHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_TblWidth_type:
+ {
+ //can be: NS_ooxml::LN_Value_ST_TblWidth_nil, NS_ooxml::LN_Value_ST_TblWidth_pct,
+ // NS_ooxml::LN_Value_ST_TblWidth_dxa, NS_ooxml::LN_Value_ST_TblWidth_auto;
+ m_nUnit = nIntValue;
+
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "type";
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TblWidth_nil: aValue.Value <<= OUString("nil"); break;
+ case NS_ooxml::LN_Value_ST_TblWidth_pct: aValue.Value <<= OUString("pct"); break;
+ case NS_ooxml::LN_Value_ST_TblWidth_dxa: aValue.Value <<= OUString("dxa"); break;
+ case NS_ooxml::LN_Value_ST_TblWidth_auto: aValue.Value <<= OUString("auto"); break;
+ }
+ m_aInteropGrabBag.push_back(aValue);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Height_hRule:
+ {
+ OUString sHeightType = rVal.getString();
+ if ( sHeightType == "exact" )
+ m_nRowHeightSizeType = text::SizeType::FIX;
+ }
+ break;
+ case NS_ooxml::LN_CT_TblWidth_w:
+ m_nMeasureValue = nIntValue;
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "w";
+ aValue.Value <<= nIntValue;
+ m_aInteropGrabBag.push_back(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Height_val: // a string value
+ {
+ m_nUnit = NS_ooxml::LN_Value_ST_TblWidth_dxa;
+ OUString sHeight = rVal.getString();
+ m_nMeasureValue = sHeight.toInt32();
+ }
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+
+void MeasureHandler::lcl_sprm(Sprm &) {}
+
+
+sal_Int32 MeasureHandler::getMeasureValue() const
+{
+ sal_Int32 nRet = 0;
+ if( m_nMeasureValue != 0 && m_nUnit >= 0 )
+ {
+ // TODO m_nUnit 3 - twip, other values unknown :-(
+ if( m_nUnit == 3 || sal::static_int_cast<Id>(m_nUnit) == NS_ooxml::LN_Value_ST_TblWidth_dxa)
+ {
+ nRet = ConversionHelper::convertTwipToMM100( m_nMeasureValue );
+ }
+ //todo: handle additional width types:
+ //NS_ooxml::LN_Value_ST_TblWidth_nil, NS_ooxml::LN_Value_ST_TblWidth_pct,
+ //NS_ooxml::LN_Value_ST_TblWidth_dxa, NS_ooxml::LN_Value_ST_TblWidth_auto;
+ }
+ return nRet;
+}
+
+void MeasureHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue MeasureHandler::getInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = m_aInteropGrabBagName;
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/MeasureHandler.hxx b/writerfilter/source/dmapper/MeasureHandler.hxx
new file mode 100644
index 000000000..8a6f9639e
--- /dev/null
+++ b/writerfilter/source/dmapper/MeasureHandler.hxx
@@ -0,0 +1,60 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+/** Handler for sprms that contain a measure and a unit
+ - Left indent of tables
+ - Preferred width of tables
+ */
+class MeasureHandler : public LoggedProperties
+{
+ sal_Int32 m_nMeasureValue;
+ sal_Int32 m_nUnit;
+ sal_Int16 m_nRowHeightSizeType; //table row height type
+
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+public:
+ MeasureHandler();
+ virtual ~MeasureHandler() override;
+
+ sal_Int32 getMeasureValue() const;
+
+ sal_Int32 getValue() const { return m_nMeasureValue; }
+ sal_Int32 getUnit() const { return m_nUnit; }
+
+ sal_Int16 GetRowHeightSizeType() const { return m_nRowHeightSizeType; }
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag();
+};
+typedef tools::SvRef<MeasureHandler> MeasureHandlerPtr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ModelEventListener.cxx b/writerfilter/source/dmapper/ModelEventListener.cxx
new file mode 100644
index 000000000..8e20f7ad9
--- /dev/null
+++ b/writerfilter/source/dmapper/ModelEventListener.cxx
@@ -0,0 +1,117 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "ModelEventListener.hxx"
+#include "PropertyIds.hxx"
+#include <rtl/ustring.hxx>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/ReferenceFieldPart.hpp>
+#include <com/sun/star/text/ReferenceFieldSource.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/view/XFormLayerAccess.hpp>
+#include <tools/diagnose_ex.h>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+ModelEventListener::ModelEventListener(bool bIndexes, bool bControls)
+ : m_bIndexes(bIndexes),
+ m_bControls(bControls)
+{
+}
+
+
+ModelEventListener::~ModelEventListener()
+{
+}
+
+
+void ModelEventListener::notifyEvent( const document::EventObject& rEvent )
+{
+ if ( rEvent.EventName == "OnFocus" && m_bIndexes)
+ {
+ try
+ {
+ //remove listener
+ uno::Reference<document::XEventBroadcaster>(rEvent.Source, uno::UNO_QUERY_THROW )->removeEventListener(
+ uno::Reference<document::XEventListener>(this));
+
+ // If we have PAGEREF fields, update fields as well.
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(rEvent.Source, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xEnumeration = xTextFieldsSupplier->getTextFields()->createEnumeration();
+ sal_Int32 nIndex = 0;
+ while(xEnumeration->hasMoreElements())
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xEnumeration->nextElement(), uno::UNO_QUERY);
+ sal_Int16 nSource = 0;
+ xPropertySet->getPropertyValue(getPropertyName(PROP_REFERENCE_FIELD_SOURCE)) >>= nSource;
+ sal_Int16 nPart = 0;
+ xPropertySet->getPropertyValue(getPropertyName(PROP_REFERENCE_FIELD_PART)) >>= nPart;
+ if (nSource == text::ReferenceFieldSource::BOOKMARK && nPart == text::ReferenceFieldPart::PAGE)
+ ++nIndex;
+ }
+ catch( const beans::UnknownPropertyException& )
+ {
+ // doesn't even have such a property? ignore
+ }
+ }
+ if (nIndex)
+ {
+ uno::Reference<util::XRefreshable> xRefreshable(xTextFieldsSupplier->getTextFields(), uno::UNO_QUERY);
+ xRefreshable->refresh();
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "exception while updating indexes");
+ }
+ }
+
+ if ( rEvent.EventName == "OnFocus" && m_bControls)
+ {
+
+ // Form design mode is enabled by default in Writer, not in Word.
+ uno::Reference<frame::XModel> xModel(rEvent.Source, uno::UNO_QUERY);
+ uno::Reference<view::XFormLayerAccess> xFormLayerAccess(xModel->getCurrentController(), uno::UNO_QUERY);
+ xFormLayerAccess->setFormDesignMode(false);
+ }
+}
+
+
+void ModelEventListener::disposing( const lang::EventObject& rEvent )
+{
+ try
+ {
+ uno::Reference<document::XEventBroadcaster>(rEvent.Source, uno::UNO_QUERY_THROW )->removeEventListener(
+ uno::Reference<document::XEventListener>(this));
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ModelEventListener.hxx b/writerfilter/source/dmapper/ModelEventListener.hxx
new file mode 100644
index 000000000..47cd94b80
--- /dev/null
+++ b/writerfilter/source/dmapper/ModelEventListener.hxx
@@ -0,0 +1,40 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/document/XEventListener.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace writerfilter::dmapper
+{
+class ModelEventListener : public cppu::WeakImplHelper<css::document::XEventListener>
+{
+ bool m_bIndexes;
+ bool m_bControls;
+
+public:
+ ModelEventListener(bool bIndexes, bool bControls);
+ virtual ~ModelEventListener() override;
+
+ virtual void SAL_CALL notifyEvent(const css::document::EventObject& Event) override;
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+};
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/NumberingManager.cxx b/writerfilter/source/dmapper/NumberingManager.cxx
new file mode 100644
index 000000000..cb97f59ff
--- /dev/null
+++ b/writerfilter/source/dmapper/NumberingManager.cxx
@@ -0,0 +1,1210 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "ConversionHelper.hxx"
+#include "NumberingManager.hxx"
+#include "StyleSheetTable.hxx"
+#include "PropertyIds.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/PositionAndSpaceMode.hpp>
+#include <com/sun/star/text/XChapterNumberingSupplier.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <regex>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper {
+
+//--------------------------------------------------- Utility functions
+template <typename T>
+static beans::PropertyValue lcl_makePropVal(PropertyIds nNameID, T const & aValue)
+{
+ return {getPropertyName(nNameID), 0, uno::Any(aValue), beans::PropertyState_DIRECT_VALUE};
+}
+
+static sal_Int32 lcl_findProperty( const uno::Sequence< beans::PropertyValue >& aProps, std::u16string_view sName )
+{
+ sal_Int32 i = 0;
+ sal_Int32 nLen = aProps.getLength( );
+ sal_Int32 nPos = -1;
+
+ while ( nPos == -1 && i < nLen )
+ {
+ if ( aProps[i].Name == sName )
+ nPos = i;
+ else
+ i++;
+ }
+
+ return nPos;
+}
+
+static void lcl_mergeProperties( const uno::Sequence< beans::PropertyValue >& aSrc,
+ uno::Sequence< beans::PropertyValue >& aDst )
+{
+ for ( const auto& rProp : aSrc )
+ {
+ // Look for the same property in aDst
+ sal_Int32 nPos = lcl_findProperty( aDst, rProp.Name );
+ if ( nPos >= 0 )
+ {
+ // Replace the property value by the one in aSrc
+ aDst.getArray()[nPos] = rProp;
+ }
+ else
+ {
+ // Simply add the new value
+ aDst.realloc( aDst.getLength( ) + 1 );
+ aDst.getArray()[ aDst.getLength( ) - 1 ] = rProp;
+ }
+ }
+}
+
+//-------------------------------------------- ListLevel implementation
+void ListLevel::SetValue( Id nId, sal_Int32 nValue )
+{
+ switch( nId )
+ {
+ case NS_ooxml::LN_CT_Lvl_start:
+ m_nIStartAt = nValue;
+ break;
+ case NS_ooxml::LN_CT_NumLvl_startOverride:
+ m_nStartOverride = nValue;
+ break;
+ case NS_ooxml::LN_CT_NumFmt_val:
+ m_nNFC = nValue;
+ break;
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ break;
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ break;
+ case NS_ooxml::LN_CT_Lvl_suff:
+ m_nXChFollow = nValue;
+ break;
+ case NS_ooxml::LN_CT_TabStop_pos:
+ if (nValue < 0)
+ {
+ SAL_INFO("writerfilter",
+ "unsupported list tab stop position " << nValue);
+ }
+ else
+ m_nTabstop = nValue;
+ break;
+ default:
+ OSL_FAIL( "this line should never be reached");
+ }
+ m_bHasValues = true;
+}
+
+void ListLevel::SetCustomNumberFormat(const OUString& rValue) { m_aCustomNumberFormat = rValue; }
+
+sal_Int16 ListLevel::GetNumberingType(sal_Int16 nDefault) const
+{
+ return ConversionHelper::ConvertNumberingType(m_nNFC, nDefault);
+}
+
+bool ListLevel::HasValues() const
+{
+ return m_bHasValues;
+}
+
+void ListLevel::SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle )
+{
+ if (!pStyle)
+ return;
+ m_pParaStyle = pStyle;
+}
+
+uno::Sequence<beans::PropertyValue> ListLevel::GetProperties(bool bDefaults)
+{
+ uno::Sequence<beans::PropertyValue> aLevelProps = GetLevelProperties(bDefaults);
+ if (m_pParaStyle)
+ AddParaProperties( &aLevelProps );
+ return aLevelProps;
+}
+
+static bool IgnoreForCharStyle(std::u16string_view aStr, const bool bIsSymbol)
+{
+ //Names found in PropertyIds.cxx, Lines 56-396
+ return (aStr==u"Adjust" || aStr==u"IndentAt" || aStr==u"FirstLineIndent"
+ || aStr==u"FirstLineOffset" || aStr==u"LeftMargin"
+ // We need font names when they are different for the bullet and for the text.
+ // But leave symbols alone, we only want to keep the font style for letters and numbers.
+ || (bIsSymbol && aStr==u"CharFontName")
+ );
+}
+uno::Sequence< beans::PropertyValue > ListLevel::GetCharStyleProperties( )
+{
+ PropertyValueVector_t rProperties;
+
+ const uno::Sequence< beans::PropertyValue > vPropVals = PropertyMap::GetPropertyValues();
+ const bool bIsSymbol(GetBulletChar().getLength() <= 1);
+ for( const auto& rPropNal : vPropVals )
+ if (! IgnoreForCharStyle(rPropNal.Name, bIsSymbol))
+ rProperties.emplace_back(rPropNal.Name, 0, rPropNal.Value, beans::PropertyState_DIRECT_VALUE);
+
+ return comphelper::containerToSequence(rProperties);
+}
+
+uno::Sequence<beans::PropertyValue> ListLevel::GetLevelProperties(bool bDefaults)
+{
+ std::vector<beans::PropertyValue> aNumberingProperties;
+
+ if (m_nIStartAt >= 0)
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_START_WITH, m_nIStartAt) );
+ else if (bDefaults)
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_START_WITH, 0));
+
+ sal_Int16 nNumberFormat = -1;
+ if (m_nNFC == NS_ooxml::LN_Value_ST_NumberFormat_custom)
+ {
+ nNumberFormat = ConversionHelper::ConvertCustomNumberFormat(m_aCustomNumberFormat);
+ }
+ else
+ {
+ nNumberFormat = ConversionHelper::ConvertNumberingType(m_nNFC);
+ }
+ if( m_nNFC >= 0)
+ {
+ if (m_xGraphicBitmap.is())
+ nNumberFormat = style::NumberingType::BITMAP;
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_NUMBERING_TYPE, nNumberFormat));
+ }
+
+ // todo: this is not the bullet char
+ if( nNumberFormat == style::NumberingType::CHAR_SPECIAL )
+ {
+ if (!GetBulletChar().isEmpty())
+ {
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_BULLET_CHAR, m_sBulletChar->copy(0, 1)));
+ }
+ else
+ {
+ // If w:lvlText's value is null - set bullet char to zero.
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Unicode>(PROP_BULLET_CHAR, 0));
+ }
+ }
+ if (m_xGraphicBitmap.is())
+ {
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_GRAPHIC_BITMAP, m_xGraphicBitmap));
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_GRAPHIC_SIZE, m_aGraphicSize));
+ }
+
+ if (m_nTabstop.has_value())
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_LISTTAB_STOP_POSITION, *m_nTabstop));
+ else if (bDefaults)
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_LISTTAB_STOP_POSITION, 0));
+
+ //TODO: handling of nFLegal?
+ //TODO: nFNoRestart lower levels do not restart when higher levels are incremented, like:
+ //1.
+ //1.1
+ //2.2
+ //2.3
+ //3.4
+
+// TODO: sRGBXchNums; array of inherited numbers
+
+// nXChFollow; following character 0 - tab, 1 - space, 2 - nothing
+ if (bDefaults || m_nXChFollow != SvxNumberFormat::LISTTAB)
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_LEVEL_FOLLOW, m_nXChFollow));
+
+ PropertyIds const aReadIds[] =
+ {
+ PROP_ADJUST, PROP_INDENT_AT, PROP_FIRST_LINE_INDENT,
+ PROP_FIRST_LINE_OFFSET, PROP_LEFT_MARGIN
+ };
+ for(PropertyIds const & rReadId : aReadIds) {
+ std::optional<PropertyMap::Property> aProp = getProperty(rReadId);
+ if (aProp)
+ aNumberingProperties.emplace_back( getPropertyName(aProp->first), 0, aProp->second, beans::PropertyState_DIRECT_VALUE );
+ else if (rReadId == PROP_FIRST_LINE_INDENT && bDefaults)
+ // Writer default is -360 twips, Word default seems to be 0.
+ aNumberingProperties.emplace_back("FirstLineIndent", 0, uno::Any(static_cast<sal_Int32>(0)), beans::PropertyState_DIRECT_VALUE);
+ else if (rReadId == PROP_INDENT_AT && bDefaults)
+ // Writer default is 720 twips, Word default seems to be 0.
+ aNumberingProperties.emplace_back("IndentAt", 0,
+ uno::Any(static_cast<sal_Int32>(0)),
+ beans::PropertyState_DIRECT_VALUE);
+ }
+
+ std::optional<PropertyMap::Property> aPropFont = getProperty(PROP_CHAR_FONT_NAME);
+ if (aPropFont)
+ aNumberingProperties.emplace_back( getPropertyName(PROP_BULLET_FONT_NAME), 0, aPropFont->second, beans::PropertyState_DIRECT_VALUE );
+
+ return comphelper::containerToSequence(aNumberingProperties);
+}
+
+// Add the properties only if they do not already exist in the sequence.
+void ListLevel::AddParaProperties( uno::Sequence< beans::PropertyValue >* props )
+{
+ uno::Sequence< beans::PropertyValue >& aProps = *props;
+
+ OUString sFirstLineIndent = getPropertyName(
+ PROP_FIRST_LINE_INDENT );
+ OUString sIndentAt = getPropertyName(
+ PROP_INDENT_AT );
+
+ bool hasFirstLineIndent = lcl_findProperty( aProps, sFirstLineIndent );
+ bool hasIndentAt = lcl_findProperty( aProps, sIndentAt );
+
+ if( hasFirstLineIndent && hasIndentAt )
+ return; // has them all, nothing to add
+
+ const uno::Sequence< beans::PropertyValue > aParaProps = m_pParaStyle->pProperties->GetPropertyValues( );
+
+ // ParaFirstLineIndent -> FirstLineIndent
+ // ParaLeftMargin -> IndentAt
+
+ OUString sParaIndent = getPropertyName(
+ PROP_PARA_FIRST_LINE_INDENT );
+ OUString sParaLeftMargin = getPropertyName(
+ PROP_PARA_LEFT_MARGIN );
+
+ for ( const auto& rParaProp : aParaProps )
+ {
+ if ( !hasFirstLineIndent && rParaProp.Name == sParaIndent )
+ {
+ aProps.realloc( aProps.getLength() + 1 );
+ auto pProps = aProps.getArray();
+ pProps[aProps.getLength( ) - 1] = rParaProp;
+ pProps[aProps.getLength( ) - 1].Name = sFirstLineIndent;
+ }
+ else if ( !hasIndentAt && rParaProp.Name == sParaLeftMargin )
+ {
+ aProps.realloc( aProps.getLength() + 1 );
+ auto pProps = aProps.getArray();
+ pProps[aProps.getLength( ) - 1] = rParaProp;
+ pProps[aProps.getLength( ) - 1].Name = sIndentAt;
+ }
+
+ }
+}
+
+NumPicBullet::NumPicBullet()
+ : m_nId(0)
+{
+}
+
+NumPicBullet::~NumPicBullet()
+{
+}
+
+void NumPicBullet::SetId(sal_Int32 nId)
+{
+ m_nId = nId;
+}
+
+void NumPicBullet::SetShape(uno::Reference<drawing::XShape> const& xShape)
+{
+ m_xShape = xShape;
+}
+
+
+//--------------------------------------- AbstractListDef implementation
+
+AbstractListDef::AbstractListDef( ) :
+ m_nId( -1 )
+{
+}
+
+AbstractListDef::~AbstractListDef( )
+{
+}
+
+void AbstractListDef::SetValue( sal_uInt32 nSprmId )
+{
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ break;
+ default:
+ OSL_FAIL( "this line should never be reached");
+ }
+}
+
+ListLevel::Pointer AbstractListDef::GetLevel( sal_uInt16 nLvl )
+{
+ ListLevel::Pointer pLevel;
+ if ( m_aLevels.size( ) > nLvl )
+ pLevel = m_aLevels[ nLvl ];
+ return pLevel;
+}
+
+void AbstractListDef::AddLevel( sal_uInt16 nLvl )
+{
+ if ( nLvl >= m_aLevels.size() )
+ m_aLevels.resize( nLvl+1 );
+
+ if (!m_aLevels[nLvl])
+ {
+ m_aLevels[nLvl] = new ListLevel;
+ }
+
+ m_pCurrentLevel = m_aLevels[nLvl];
+}
+
+uno::Sequence<uno::Sequence<beans::PropertyValue>> AbstractListDef::GetPropertyValues(bool bDefaults)
+{
+ uno::Sequence< uno::Sequence< beans::PropertyValue > > result( sal_Int32( m_aLevels.size( ) ) );
+ uno::Sequence< beans::PropertyValue >* aResult = result.getArray( );
+
+ int nLevels = m_aLevels.size( );
+ for ( int i = 0; i < nLevels; i++ )
+ {
+ if (m_aLevels[i])
+ aResult[i] = m_aLevels[i]->GetProperties(bDefaults);
+ }
+
+ return result;
+}
+
+const OUString& AbstractListDef::MapListId(OUString const& rId)
+{
+ if (!m_oListId)
+ {
+ m_oListId = rId;
+ }
+ return *m_oListId;
+}
+
+//---------------------------------------------- ListDef implementation
+
+ListDef::ListDef( )
+{
+}
+
+ListDef::~ListDef( )
+{
+}
+
+const OUString & ListDef::GetStyleName(sal_Int32 const nId,
+ uno::Reference<container::XNameContainer> const& xStyles)
+{
+ if (xStyles.is())
+ {
+ OUString sStyleName = "WWNum" + OUString::number( nId );
+
+ while (xStyles->hasByName(sStyleName)) // unique
+ {
+ sStyleName += "a";
+ }
+
+ m_StyleName = sStyleName;
+ }
+ else
+ {
+// fails in rtftok test assert(!m_StyleName.isEmpty()); // must be inited first
+ }
+
+ return m_StyleName;
+}
+
+uno::Sequence<uno::Sequence<beans::PropertyValue>> ListDef::GetMergedPropertyValues()
+{
+ if (!m_pAbstractDef)
+ return uno::Sequence< uno::Sequence< beans::PropertyValue > >();
+
+ // [1] Call the same method on the abstract list
+ uno::Sequence<uno::Sequence<beans::PropertyValue>> aAbstract
+ = m_pAbstractDef->GetPropertyValues(/*bDefaults=*/true);
+ auto aAbstractRange = asNonConstRange(aAbstract);
+
+ // [2] Call the upper class method
+ uno::Sequence<uno::Sequence<beans::PropertyValue>> aThis
+ = AbstractListDef::GetPropertyValues(/*bDefaults=*/false);
+
+ // Merge the results of [2] in [1]
+ sal_Int32 nThisCount = aThis.getLength( );
+ sal_Int32 nAbstractCount = aAbstract.getLength( );
+ for ( sal_Int32 i = 0; i < nThisCount && i < nAbstractCount; i++ )
+ {
+ uno::Sequence< beans::PropertyValue > level = aThis[i];
+ if (level.hasElements() && GetLevel(i)->HasValues())
+ {
+ // If the element contains something, merge it, but ignore stub overrides.
+ lcl_mergeProperties( level, aAbstractRange[i] );
+ }
+ }
+
+ return aAbstract;
+}
+
+static uno::Reference< container::XNameContainer > lcl_getUnoNumberingStyles(
+ uno::Reference<lang::XMultiServiceFactory> const& xFactory)
+{
+ uno::Reference< container::XNameContainer > xStyles;
+
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xFamilies( xFactory, uno::UNO_QUERY_THROW );
+ uno::Any oFamily = xFamilies->getStyleFamilies( )->getByName("NumberingStyles");
+
+ oFamily >>= xStyles;
+ }
+ catch ( const uno::Exception & )
+ {
+ }
+
+ return xStyles;
+}
+
+/// Rank the list in terms of suitability for becoming the Outline numbering rule in LO.
+sal_uInt16 ListDef::GetChapterNumberingWeight() const
+{
+ sal_Int16 nWeight = 0;
+ const sal_Int8 nAbstLevels = m_pAbstractDef ? m_pAbstractDef->Size() : 0;
+ for (sal_Int8 nLevel = 0; nLevel < nAbstLevels; ++nLevel)
+ {
+ const ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel(nLevel);
+ if (!pAbsLevel)
+ continue;
+ const StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle();
+ if (!pParaStyle)
+ continue;
+ const StyleSheetPropertyMap& rProps = *pParaStyle->pProperties;
+ // In LO, the level's paraStyle outlineLevel always matches this listLevel.
+ // An undefined listLevel is treated as the first level.
+ sal_Int8 nListLevel = std::clamp<sal_Int8>(rProps.GetListLevel(), 0, 9);
+ if (nListLevel != nLevel || rProps.GetOutlineLevel() != nLevel)
+ return 0;
+ else if (pAbsLevel->GetNumberingType(style::NumberingType::NUMBER_NONE)
+ != style::NumberingType::NUMBER_NONE)
+ {
+ // Arbitrarily chosen weighting factors - trying to round-trip LO choices if possible.
+ // LibreOffice always saves Outline rule (usually containing heading styles) as numId 1.
+ sal_uInt16 nWeightingFactor = GetId() == 1 ? 8 : 1;
+ if (pParaStyle->sStyleIdentifierD.startsWith("Heading") )
+ ++nWeightingFactor;
+ nWeight += nWeightingFactor;
+ }
+ }
+ return nWeight;
+}
+
+void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
+ uno::Reference<lang::XMultiServiceFactory> const& xFactory, sal_Int16 nOutline)
+{
+ // Get the UNO Numbering styles
+ uno::Reference< container::XNameContainer > xStyles = lcl_getUnoNumberingStyles( xFactory );
+
+ // Do the whole thing
+ if( !(!m_xNumRules.is() && xFactory.is() && xStyles.is( )) )
+ return;
+
+ try
+ {
+ // Create the numbering style
+ uno::Reference< beans::XPropertySet > xStyle (
+ xFactory->createInstance("com.sun.star.style.NumberingStyle"),
+ uno::UNO_QUERY_THROW );
+
+ if (GetId() == nOutline)
+ m_StyleName = "Outline"; //SwNumRule.GetOutlineRuleName()
+ else
+ xStyles->insertByName(GetStyleName(GetId(), xStyles), css::uno::Any(xStyle));
+
+ uno::Any oStyle = xStyles->getByName(GetStyleName());
+ xStyle.set( oStyle, uno::UNO_QUERY_THROW );
+
+ // Get the default OOo Numbering style rules
+ uno::Any aRules = xStyle->getPropertyValue( getPropertyName( PROP_NUMBERING_RULES ) );
+ aRules >>= m_xNumRules;
+
+ uno::Sequence<uno::Sequence<beans::PropertyValue>> aProps = GetMergedPropertyValues();
+
+ sal_Int32 nAbstLevels = m_pAbstractDef ? m_pAbstractDef->Size() : 0;
+ sal_Int32 nLevel = 0;
+ while ( nLevel < nAbstLevels )
+ {
+ ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel( nLevel );
+ ListLevel::Pointer pLevel = GetLevel( nLevel );
+
+ // Get the merged level properties
+ auto aLvlProps = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aProps[nLevel]);
+
+ // Get the char style
+ auto aAbsCharStyleProps = pAbsLevel
+ ? pAbsLevel->GetCharStyleProperties()
+ : uno::Sequence<beans::PropertyValue>();
+ if ( pLevel )
+ {
+ uno::Sequence< beans::PropertyValue >& rAbsCharStyleProps = aAbsCharStyleProps;
+ uno::Sequence< beans::PropertyValue > aCharStyleProps =
+ pLevel->GetCharStyleProperties( );
+ uno::Sequence< beans::PropertyValue >& rCharStyleProps = aCharStyleProps;
+ lcl_mergeProperties( rAbsCharStyleProps, rCharStyleProps );
+ }
+
+ // Change the sequence into a vector
+ auto aStyleProps
+ = comphelper::sequenceToContainer<PropertyValueVector_t>(aAbsCharStyleProps);
+
+ //create (or find) a character style containing the character
+ // attributes of the symbol and apply it to the numbering level
+ OUString sStyle = rDMapper.getOrCreateCharStyle(aStyleProps, /*bAlwaysCreate=*/true);
+ aLvlProps.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_CHAR_STYLE_NAME), sStyle));
+
+ OUString sText = pAbsLevel
+ ? pAbsLevel->GetBulletChar()
+ : OUString();
+ // Inherit <w:lvlText> from the abstract level in case the override would be empty.
+ if (pLevel && pLevel->HasBulletChar())
+ sText = pLevel->GetBulletChar( );
+
+ aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LIST_FORMAT), sText));
+
+ aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_POSITION_AND_SPACE_MODE), sal_Int16(text::PositionAndSpaceMode::LABEL_ALIGNMENT)));
+
+ // Replace the numbering rules for the level
+ m_xNumRules->replaceByIndex(nLevel, uno::Any(comphelper::containerToSequence(aLvlProps)));
+
+ // Handle the outline level here
+ if (GetId() == nOutline && pAbsLevel && pAbsLevel->GetParaStyle())
+ {
+ uno::Reference< text::XChapterNumberingSupplier > xOutlines (
+ xFactory, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexReplace > xOutlineRules =
+ xOutlines->getChapterNumberingRules( );
+
+ StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle( );
+ pParaStyle->bAssignedAsChapterNumbering = true;
+ aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEADING_STYLE_NAME), pParaStyle->sConvertedStyleName));
+
+ xOutlineRules->replaceByIndex(nLevel, uno::Any(comphelper::containerToSequence(aLvlProps)));
+ }
+
+ nLevel++;
+ }
+
+ // Create the numbering style for these rules
+ OUString sNumRulesName = getPropertyName( PROP_NUMBERING_RULES );
+ xStyle->setPropertyValue( sNumRulesName, uno::Any( m_xNumRules ) );
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "" );
+ assert( !"Incorrect argument to UNO call" );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "" );
+ assert( !"Incorrect argument to UNO call" );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "" );
+ }
+
+}
+
+//------------------------------------- NumberingManager implementation
+
+
+ListsManager::ListsManager(DomainMapper& rDMapper,
+ const uno::Reference<lang::XMultiServiceFactory> & xFactory)
+ : LoggedProperties("ListsManager")
+ , LoggedTable("ListsManager")
+ , m_rDMapper(rDMapper)
+ , m_xFactory(xFactory)
+{
+}
+
+ListsManager::~ListsManager( )
+{
+ DisposeNumPicBullets();
+}
+
+void ListsManager::DisposeNumPicBullets( )
+{
+ uno::Reference<drawing::XShape> xShape;
+ for (const auto& rNumPicBullet : m_aNumPicBullets)
+ {
+ xShape = rNumPicBullet->GetShape();
+ if (xShape.is())
+ {
+ uno::Reference<lang::XComponent> xShapeComponent(xShape, uno::UNO_QUERY);
+ xShapeComponent->dispose();
+ }
+ }
+}
+
+void ListsManager::lcl_attribute( Id nName, Value& rVal )
+{
+ ListLevel::Pointer pCurrentLvl;
+
+ if (nName != NS_ooxml::LN_CT_NumPicBullet_numPicBulletId)
+ {
+ OSL_ENSURE( m_pCurrentDefinition, "current entry has to be set here");
+ if(!m_pCurrentDefinition)
+ return ;
+ pCurrentLvl = m_pCurrentDefinition->GetCurrentLevel( );
+ }
+ else
+ {
+ SAL_WARN_IF(!m_pCurrentNumPicBullet, "writerfilter", "current entry has to be set here");
+ if (!m_pCurrentNumPicBullet)
+ return;
+ }
+ int nIntValue = rVal.getInt();
+
+
+ switch(nName)
+ {
+ case NS_ooxml::LN_CT_LevelText_val:
+ {
+ if(pCurrentLvl)
+ {
+ //if the BulletChar is a soft-hyphen (0xad)
+ //replace it with a hard-hyphen (0x2d)
+ //-> this fixes missing hyphen export in PDF etc.
+ // see tdf#101626
+ std::string sLevelText = rVal.getString().replace(0xad, 0x2d).toUtf8().getStr();
+
+ // DOCX level-text contains levels definition in format "%1.%2.%3"
+ // we need to convert it to LO internal representation: "%1%.%2%.%3%"
+ static const std::regex aTokenRegex("(%\\d)");
+ sLevelText = std::regex_replace(sLevelText, aTokenRegex, "$1%");
+ pCurrentLvl->SetBulletChar( OUString::fromUtf8(sLevelText) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_start:
+ case NS_ooxml::LN_CT_Lvl_numFmt:
+ case NS_ooxml::LN_CT_NumFmt_format:
+ case NS_ooxml::LN_CT_NumFmt_val:
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ if ( pCurrentLvl )
+ {
+ if (nName == NS_ooxml::LN_CT_NumFmt_format)
+ {
+ pCurrentLvl->SetCustomNumberFormat(rVal.getString());
+ }
+ else
+ {
+ pCurrentLvl->SetValue(nName, sal_Int32(nIntValue));
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Num_numId:
+ m_pCurrentDefinition->SetId( rVal.getString().toInt32( ) );
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_nsid:
+ m_pCurrentDefinition->SetId( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ AbstractListDef::SetValue( nName );
+ break;
+ case NS_ooxml::LN_CT_NumLvl_ilvl:
+ //add a new level to the level vector and make it the current one
+ m_pCurrentDefinition->AddLevel(rVal.getString().toUInt32());
+ break;
+ case NS_ooxml::LN_CT_Lvl_ilvl:
+ m_pCurrentDefinition->AddLevel(rVal.getString().toUInt32());
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_abstractNumId:
+ {
+ // This one corresponds to the AbstractNum Id definition
+ // The reference to the abstract num is in the sprm method
+ sal_Int32 nVal = rVal.getString().toInt32();
+ m_pCurrentDefinition->SetId( nVal );
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_start:
+ case NS_ooxml::LN_CT_Ind_left:
+ if ( pCurrentLvl )
+ pCurrentLvl->Insert(
+ PROP_INDENT_AT, uno::Any( ConversionHelper::convertTwipToMM100( nIntValue ) ));
+ break;
+ case NS_ooxml::LN_CT_Ind_hanging:
+ if ( pCurrentLvl )
+ pCurrentLvl->Insert(
+ PROP_FIRST_LINE_INDENT, uno::Any( - ConversionHelper::convertTwipToMM100( nIntValue ) ));
+ break;
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ if ( pCurrentLvl )
+ pCurrentLvl->Insert(
+ PROP_FIRST_LINE_INDENT, uno::Any( ConversionHelper::convertTwipToMM100( nIntValue ) ));
+ break;
+ case NS_ooxml::LN_CT_Lvl_tplc: //template code - unsupported
+ case NS_ooxml::LN_CT_Lvl_tentative: //marks level as unused in the document - unsupported
+ break;
+ case NS_ooxml::LN_CT_TabStop_pos:
+ {
+ //no paragraph attributes in ListTable char style sheets
+ if ( pCurrentLvl )
+ pCurrentLvl->SetValue( nName,
+ ConversionHelper::convertTwipToMM100( nIntValue ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_TabStop_val:
+ {
+ // TODO Do something of that
+ }
+ break;
+ case NS_ooxml::LN_CT_NumPicBullet_numPicBulletId:
+ m_pCurrentNumPicBullet->SetId(rVal.getString().toInt32());
+ break;
+ default:
+ SAL_WARN("writerfilter", "ListsManager::lcl_attribute: unhandled token: " << nName);
+ }
+}
+
+void ListsManager::lcl_sprm( Sprm& rSprm )
+{
+ //fill the attributes of the style sheet
+ sal_uInt32 nSprmId = rSprm.getId();
+ if( !(m_pCurrentDefinition ||
+ nSprmId == NS_ooxml::LN_CT_Numbering_abstractNum ||
+ nSprmId == NS_ooxml::LN_CT_Numbering_num ||
+ (nSprmId == NS_ooxml::LN_CT_NumPicBullet_pict && m_pCurrentNumPicBullet) ||
+ nSprmId == NS_ooxml::LN_CT_Numbering_numPicBullet))
+ return;
+
+ static bool bIsStartVisited = false;
+ sal_Int32 nIntValue = rSprm.getValue()->getInt();
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_Numbering_abstractNum:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ {
+ //create a new Abstract list entry
+ OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
+ m_pCurrentDefinition = new AbstractListDef;
+ pProperties->resolve( *this );
+ //append it to the table
+ m_aAbstractLists.push_back( m_pCurrentDefinition );
+ m_pCurrentDefinition = AbstractListDef::Pointer();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Numbering_num:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ {
+ // Create a new list entry
+ OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
+ ListDef::Pointer listDef( new ListDef );
+ m_pCurrentDefinition = listDef.get();
+ pProperties->resolve( *this );
+ //append it to the table
+ m_aLists.push_back( listDef );
+
+ m_pCurrentDefinition = AbstractListDef::Pointer();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Numbering_numPicBullet:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ NumPicBullet::Pointer numPicBullet(new NumPicBullet());
+ m_pCurrentNumPicBullet = numPicBullet;
+ pProperties->resolve(*this);
+ m_aNumPicBullets.push_back(numPicBullet);
+ m_pCurrentNumPicBullet = NumPicBullet::Pointer();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_NumPicBullet_pict:
+ {
+ uno::Reference<drawing::XShape> xShape = m_rDMapper.PopPendingShape();
+
+ m_pCurrentNumPicBullet->SetShape(xShape);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_lvlPicBulletId:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ uno::Reference<drawing::XShape> xShape;
+ for (const auto& rNumPicBullet : m_aNumPicBullets)
+ {
+ if (rNumPicBullet->GetId() == nIntValue)
+ {
+ xShape = rNumPicBullet->GetShape();
+ break;
+ }
+ }
+ if (xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ try
+ {
+ uno::Any aAny = xPropertySet->getPropertyValue("Graphic");
+ if (aAny.has<uno::Reference<graphic::XGraphic>>() && pCurrentLevel)
+ {
+ auto xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>();
+ if (xGraphic.is())
+ {
+ uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
+ pCurrentLevel->SetGraphicBitmap(xBitmap);
+ }
+ }
+ }
+ catch (const beans::UnknownPropertyException&)
+ {}
+
+ // Respect only the aspect ratio of the picture, not its size.
+ awt::Size aPrefSize = xShape->getSize();
+ if ( aPrefSize.Height * aPrefSize.Width != 0 )
+ {
+ // See SwDefBulletConfig::InitFont(), default height is 14.
+ const int nFontHeight = 14;
+ // Point -> mm100.
+ const int nHeight = nFontHeight * 35;
+ int nWidth = (nHeight * aPrefSize.Width) / aPrefSize.Height;
+
+ awt::Size aSize( o3tl::toTwips(nWidth, o3tl::Length::mm100), o3tl::toTwips(nHeight, o3tl::Length::mm100) );
+ pCurrentLevel->SetGraphicSize( aSize );
+ }
+ else
+ {
+ awt::Size aSize( o3tl::toTwips(aPrefSize.Width, o3tl::Length::mm100), o3tl::toTwips(aPrefSize.Height, o3tl::Length::mm100) );
+ pCurrentLevel->SetGraphicSize( aSize );
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Num_abstractNumId:
+ {
+ sal_Int32 nAbstractNumId = rSprm.getValue()->getInt();
+ ListDef* pListDef = dynamic_cast< ListDef* >( m_pCurrentDefinition.get( ) );
+ if ( pListDef != nullptr )
+ {
+ // The current def should be a ListDef
+ pListDef->SetAbstractDefinition(
+ GetAbstractList( nAbstractNumId ) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_multiLevelType:
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ AbstractListDef::SetValue( nSprmId );
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_lvl:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_start:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ pCurrentLevel->SetValue( nSprmId, nIntValue );
+ bIsStartVisited = true;
+ break;
+ case NS_ooxml::LN_CT_Lvl_numFmt:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ if( !bIsStartVisited )
+ {
+ pCurrentLevel->SetValue( NS_ooxml::LN_CT_Lvl_start, 0 );
+ bIsStartVisited = true;
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ pCurrentLevel->SetValue(nSprmId, nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_suff:
+ {
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ SvxNumberFormat::LabelFollowedBy value = SvxNumberFormat::LISTTAB;
+ if( rSprm.getValue()->getString() == "tab" )
+ value = SvxNumberFormat::LISTTAB;
+ else if( rSprm.getValue()->getString() == "space" )
+ value = SvxNumberFormat::SPACE;
+ else if( rSprm.getValue()->getString() == "nothing" )
+ value = SvxNumberFormat::NOTHING;
+ else
+ SAL_WARN( "writerfilter", "Unknown ST_LevelSuffix value "
+ << rSprm.getValue()->getString());
+ pCurrentLevel->SetValue( nSprmId, value );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_lvlText:
+ case NS_ooxml::LN_CT_Lvl_rPr : //contains LN_EG_RPrBase_rFonts
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumLvl_lvl:
+ {
+ // overwrite level
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_lvlJc:
+ {
+ sal_Int16 nValue = text::HoriOrientation::NONE;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Jc_left:
+ case NS_ooxml::LN_Value_ST_Jc_start:
+ nValue = text::HoriOrientation::LEFT;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_center:
+ nValue = text::HoriOrientation::CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_right:
+ case NS_ooxml::LN_Value_ST_Jc_end:
+ nValue = text::HoriOrientation::RIGHT;
+ break;
+ }
+
+ if (nValue != text::HoriOrientation::NONE)
+ {
+ if (ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ pLevel->Insert(
+ PROP_ADJUST, uno::Any( nValue ) );
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_pPr:
+ case NS_ooxml::LN_CT_PPrBase_ind:
+ {
+ //todo: how to handle paragraph properties within numbering levels (except LeftIndent and FirstLineIndent)?
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_tabs:
+ case NS_ooxml::LN_CT_Tabs_tab:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_pStyle:
+ {
+ OUString sStyleName = rSprm.getValue( )->getString( );
+ if (ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
+ const StyleSheetEntryPtr pStyle = pStylesTable->FindStyleSheetByISTD( sStyleName );
+ pLevel->SetParaStyle( pStyle );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Num_lvlOverride:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumLvl_startOverride:
+ {
+ if(m_pCurrentDefinition)
+ {
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ pCurrentLevel->SetValue(NS_ooxml::LN_CT_NumLvl_startOverride, nIntValue);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_numStyleLink:
+ {
+ OUString sStyleName = rSprm.getValue( )->getString( );
+ m_pCurrentDefinition->SetNumStyleLink(sStyleName);
+ }
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_styleLink:
+ {
+ OUString sStyleName = rSprm.getValue()->getString();
+ m_pCurrentDefinition->SetStyleLink(sStyleName);
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_rFonts: //contains font properties
+ case NS_ooxml::LN_EG_RPrBase_color:
+ case NS_ooxml::LN_EG_RPrBase_u:
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ case NS_ooxml::LN_EG_RPrBase_lang:
+ case NS_ooxml::LN_EG_RPrBase_eastAsianLayout:
+ //no break!
+ default:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ m_rDMapper.PushListProperties(pCurrentLevel.get());
+ m_rDMapper.sprm( rSprm );
+ m_rDMapper.PopListProperties();
+ }
+ }
+}
+
+void ListsManager::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref )
+{
+ if( m_rDMapper.IsOOXMLImport() || m_rDMapper.IsRTFImport() )
+ {
+ ref->resolve(*this);
+ }
+ else
+ {
+ // Create AbstractListDef's
+ OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
+ m_pCurrentDefinition = new AbstractListDef( );
+ ref->resolve(*this);
+ //append it to the table
+ m_aAbstractLists.push_back( m_pCurrentDefinition );
+ m_pCurrentDefinition = AbstractListDef::Pointer();
+ }
+}
+
+AbstractListDef::Pointer ListsManager::GetAbstractList( sal_Int32 nId )
+{
+ for (const auto& listDef : m_aAbstractLists)
+ {
+ if (listDef->GetId( ) == nId)
+ {
+ if (listDef->GetNumStyleLink().getLength() > 0)
+ {
+ // If the abstract num has a style linked, check the linked style's number id.
+ StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
+
+ const StyleSheetEntryPtr pStyleSheetEntry =
+ pStylesTable->FindStyleSheetByISTD(listDef->GetNumStyleLink() );
+
+ const StyleSheetPropertyMap* pStyleSheetProperties =
+ pStyleSheetEntry ? pStyleSheetEntry->pProperties.get() : nullptr;
+
+ if( pStyleSheetProperties && pStyleSheetProperties->GetListId() >= 0 )
+ {
+ ListDef::Pointer pList = GetList( pStyleSheetProperties->GetListId() );
+ if ( pList!=nullptr )
+ return pList->GetAbstractDefinition();
+ }
+
+ // In stylesheet we did not found anything useful. Try to find base abstractnum having this stylelink
+ for (const auto & baseListDef : m_aAbstractLists)
+ {
+ if (baseListDef->GetStyleLink() == listDef->GetNumStyleLink())
+ {
+ return baseListDef;
+ }
+ }
+ }
+
+ // Standalone abstract list
+ return listDef;
+ }
+ }
+
+ return nullptr;
+}
+
+ListDef::Pointer ListsManager::GetList( sal_Int32 nId )
+{
+ ListDef::Pointer pList;
+ if (nId == -1)
+ return pList;
+
+ int nLen = m_aLists.size( );
+ int i = 0;
+ while ( !pList && i < nLen )
+ {
+ if ( m_aLists[i]->GetId( ) == nId )
+ pList = m_aLists[i];
+ i++;
+ }
+
+ // nId 0 is only valid for abstractNum, not numId (which has an abstract definition)
+ assert(!pList || nId || !pList->GetAbstractDefinition() || m_rDMapper.IsRTFImport());
+
+ return pList;
+}
+
+void ListsManager::CreateNumberingRules( )
+{
+ // Try to determine which numId would best work as LO's Chapter Numbering Outline rule.
+ // (The best fix for many import bugs is just to prevent ANY assignment as chapter numbering.)
+ sal_Int16 nChosenAsChapterNumberingId = -1;
+ sal_uInt16 nHighestWeight = 5; // arbitrarily chosen minimum threshold
+ for (const auto& rList : m_aLists)
+ {
+ sal_uInt16 nWeight = rList->GetChapterNumberingWeight();
+ if (nWeight > nHighestWeight)
+ {
+ nHighestWeight = nWeight;
+ nChosenAsChapterNumberingId = rList->GetId();
+ //Optimization: if the weight cannot be beaten anymore, then quit early
+ if (nHighestWeight > 17)
+ break;
+ }
+ }
+
+ // Loop over the definitions
+ for ( const auto& rList : m_aLists )
+ {
+ rList->CreateNumberingRules(m_rDMapper, m_xFactory, nChosenAsChapterNumberingId);
+ }
+ m_rDMapper.GetStyleSheetTable()->ReApplyInheritedOutlineLevelFromChapterNumbering();
+ m_rDMapper.GetStyleSheetTable()->ApplyNumberingStyleNameToParaStyles();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/NumberingManager.hxx b/writerfilter/source/dmapper/NumberingManager.hxx
new file mode 100644
index 000000000..2c1e0af3c
--- /dev/null
+++ b/writerfilter/source/dmapper/NumberingManager.hxx
@@ -0,0 +1,250 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "PropertyMap.hxx"
+
+#include "DomainMapper.hxx"
+#include "LoggedResources.hxx"
+#include "StyleSheetTable.hxx"
+
+#include <editeng/numitem.hxx>
+
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+class StyleSheetEntry;
+
+
+/** Class representing the numbering level properties.
+ */
+class ListLevel : public PropertyMap
+{
+ sal_Int32 m_nIStartAt; //LN_CT_Lvl_start
+ sal_Int32 m_nStartOverride;
+ sal_Int32 m_nNFC; //LN_CT_Lvl_numFmt
+ /// LN_CT_NumFmt_format, in case m_nNFC is custom.
+ OUString m_aCustomNumberFormat;
+ sal_Int16 m_nXChFollow; //LN_IXCHFOLLOW
+ std::optional<OUString> m_sBulletChar;
+ css::awt::Size m_aGraphicSize;
+ css::uno::Reference<css::awt::XBitmap> m_xGraphicBitmap;
+ std::optional<sal_Int32> m_nTabstop;
+ tools::SvRef< StyleSheetEntry > m_pParaStyle;
+ bool m_bHasValues = false;
+
+public:
+
+ typedef tools::SvRef< ListLevel > Pointer;
+
+ ListLevel() :
+ m_nIStartAt(-1)
+ ,m_nStartOverride(-1)
+ ,m_nNFC(-1)
+ ,m_nXChFollow(SvxNumberFormat::LISTTAB)
+ {}
+
+ // Setters for the import
+ void SetValue( Id nId, sal_Int32 nValue );
+ void SetCustomNumberFormat(const OUString& rValue);
+ void SetBulletChar( const OUString& sValue ) { m_sBulletChar = sValue; };
+ void SetGraphicSize( const css::awt::Size& aValue ) { m_aGraphicSize = aValue; };
+
+ void SetGraphicBitmap(css::uno::Reference<css::awt::XBitmap> const& xGraphicBitmap)
+ { m_xGraphicBitmap = xGraphicBitmap; }
+ void SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle );
+
+ // Getters
+ sal_Int16 GetNumberingType(sal_Int16 nDefault) const;
+ bool HasBulletChar() const { return m_sBulletChar.has_value(); };
+ OUString GetBulletChar( ) const { return m_sBulletChar.has_value()? *m_sBulletChar : OUString(); };
+ const tools::SvRef< StyleSheetEntry >& GetParaStyle( ) const { return m_pParaStyle; };
+ sal_Int32 GetStartOverride() const { return m_nStartOverride; };
+ /// Determines if SetValue() was called at least once.
+ bool HasValues() const;
+
+ // UNO mapping functions
+ css::uno::Sequence<css::beans::PropertyValue> GetProperties(bool bDefaults);
+
+ css::uno::Sequence<css::beans::PropertyValue> GetCharStyleProperties();
+private:
+
+ css::uno::Sequence<css::beans::PropertyValue> GetLevelProperties(bool bDefaults);
+
+ void AddParaProperties(css::uno::Sequence<css::beans::PropertyValue>* pProps);
+};
+
+/// Represents a numbering picture bullet: an id and a graphic.
+class NumPicBullet final : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<NumPicBullet> Pointer;
+ NumPicBullet();
+ ~NumPicBullet() override;
+
+ void SetId(sal_Int32 nId);
+ sal_Int32 GetId() const { return m_nId;}
+ void SetShape(css::uno::Reference<css::drawing::XShape> const& xShape);
+ const css::uno::Reference<css::drawing::XShape>& GetShape() const { return m_xShape; }
+private:
+ sal_Int32 m_nId;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+};
+
+class AbstractListDef : public virtual SvRefBase
+{
+private:
+ // The ID member reflects either the abstractNumId or the numId
+ // depending on the use of the class
+ sal_Int32 m_nId;
+
+ // Properties of each level. This can also reflect the overridden
+ // levels of a numbering.
+ ::std::vector< ListLevel::Pointer > m_aLevels;
+
+ // Only used during the numbering import
+ ListLevel::Pointer m_pCurrentLevel;
+
+ // The style name linked to.
+ OUString m_sNumStyleLink;
+
+ // This abstract numbering is a base definition for this style
+ OUString m_sStyleLink;
+
+ /// list id to use for all derived numbering definitions
+ std::optional<OUString> m_oListId;
+
+public:
+ typedef tools::SvRef< AbstractListDef > Pointer;
+
+ AbstractListDef( );
+ virtual ~AbstractListDef( ) override;
+
+ // Setters using during the import
+ void SetId( sal_Int32 nId ) { m_nId = nId; };
+ static void SetValue( sal_uInt32 nSprmId );
+
+ // Accessors
+ sal_Int32 GetId( ) const { return m_nId; };
+
+ sal_Int16 Size( ) { return sal_Int16( m_aLevels.size( ) ); };
+ ListLevel::Pointer GetLevel( sal_uInt16 nLvl );
+ void AddLevel( sal_uInt16 nLvl );
+
+ const ListLevel::Pointer& GetCurrentLevel( ) const { return m_pCurrentLevel; };
+
+ css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValue> > GetPropertyValues(bool bDefaults);
+
+ void SetNumStyleLink(const OUString& sValue) { m_sNumStyleLink = sValue; };
+ const OUString& GetNumStyleLink() const { return m_sNumStyleLink; };
+
+ void SetStyleLink(const OUString& sValue) { m_sStyleLink = sValue; };
+ const OUString& GetStyleLink() const { return m_sStyleLink; };
+
+ const OUString& MapListId(OUString const& rId);
+};
+
+class ListDef : public AbstractListDef
+{
+private:
+ // Pointer to the abstract numbering
+ AbstractListDef::Pointer m_pAbstractDef;
+
+ // Cache for the UNO numbering rules
+ css::uno::Reference< css::container::XIndexReplace > m_xNumRules;
+
+ /// mapped list style name
+ OUString m_StyleName;
+
+public:
+ typedef tools::SvRef< ListDef > Pointer;
+
+ ListDef( );
+ virtual ~ListDef( ) override;
+
+ // Accessors
+ void SetAbstractDefinition( AbstractListDef::Pointer pAbstract ) { m_pAbstractDef = pAbstract; };
+ const AbstractListDef::Pointer& GetAbstractDefinition( ) const { return m_pAbstractDef; };
+
+ // Mapping functions
+ const OUString & GetStyleName() const { return m_StyleName; };
+ const OUString & GetStyleName(sal_Int32 nId, css::uno::Reference<css::container::XNameContainer> const& xStyles);
+
+ css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValue> > GetMergedPropertyValues();
+
+ sal_uInt16 GetChapterNumberingWeight() const;
+ void CreateNumberingRules(DomainMapper& rDMapper, css::uno::Reference<css::lang::XMultiServiceFactory> const& xFactory, sal_Int16 nOutline);
+
+ const css::uno::Reference<css::container::XIndexReplace>& GetNumberingRules() const { return m_xNumRules; }
+
+};
+
+/** This class provides access to the defined numbering styles.
+ */
+class ListsManager :
+ public LoggedProperties,
+ public LoggedTable
+{
+private:
+
+ DomainMapper& m_rDMapper;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xFactory;
+
+ // The numbering entries
+ std::vector< NumPicBullet::Pointer > m_aNumPicBullets;
+ std::vector< AbstractListDef::Pointer > m_aAbstractLists;
+ std::vector< ListDef::Pointer > m_aLists;
+
+
+ // These members are used for import only
+ AbstractListDef::Pointer m_pCurrentDefinition;
+ NumPicBullet::Pointer m_pCurrentNumPicBullet;
+
+ AbstractListDef::Pointer GetAbstractList( sal_Int32 nId );
+
+ // Properties
+ virtual void lcl_attribute( Id nName, Value & rVal ) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+public:
+
+ ListsManager(DomainMapper& rDMapper, const css::uno::Reference<css::lang::XMultiServiceFactory>& xFactory);
+ virtual ~ListsManager() override;
+
+ typedef tools::SvRef< ListsManager > Pointer;
+
+ ListDef::Pointer GetList( sal_Int32 nId );
+
+ // Mapping methods
+ void CreateNumberingRules( );
+
+ // Dispose the NumPicBullets
+ void DisposeNumPicBullets( );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/OLEHandler.cxx b/writerfilter/source/dmapper/OLEHandler.cxx
new file mode 100644
index 000000000..8a495e32f
--- /dev/null
+++ b/writerfilter/source/dmapper/OLEHandler.cxx
@@ -0,0 +1,331 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "OLEHandler.hxx"
+#include "DomainMapper.hxx"
+#include "GraphicHelpers.hxx"
+
+#include <oox/ole/oleobjecthelper.hxx>
+#include <ooxml/resourceids.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include <unotools/mediadescriptor.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/document/XEmbeddedObjectResolver.hpp>
+#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+OLEHandler::OLEHandler(DomainMapper& rDomainMapper) :
+LoggedProperties("OLEHandler"),
+ m_nWrapMode(text::WrapTextMode_THROUGHT),
+ m_rDomainMapper(rDomainMapper)
+{
+}
+
+
+OLEHandler::~OLEHandler()
+{
+}
+
+
+void OLEHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ OUString sStringValue = rVal.getString();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_OLEObject_Type:
+ break;
+ case NS_ooxml::LN_CT_OLEObject_ProgID:
+ m_sProgId = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_OLEObject_ShapeID:
+ break;
+ case NS_ooxml::LN_CT_OLEObject_DrawAspect:
+ m_sDrawAspect = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_OLEObject_ObjectID:
+ break;
+ case NS_ooxml::LN_CT_OLEObject_r_id:
+ break;
+ case NS_ooxml::LN_inputstream:
+ rVal.getAny() >>= m_xInputStream;
+ break;
+ case NS_ooxml::LN_CT_Object_dxaOrig:
+ m_sVisAreaWidth = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_Object_dyaOrig:
+ m_sVisAreaHeight = sStringValue;
+ break;
+ case NS_ooxml::LN_shape:
+ {
+ uno::Reference< drawing::XShape > xTempShape;
+ rVal.getAny() >>= xTempShape;
+
+ // Control shape is handled on a different code path
+ uno::Reference< lang::XServiceInfo > xSInfo( xTempShape, uno::UNO_QUERY_THROW );
+ if(xSInfo->supportsService("com.sun.star.drawing.ControlShape"))
+ {
+ m_rDomainMapper.hasControls(true);
+ break;
+ }
+
+ if( xTempShape.is() )
+ {
+ m_xShape.set( xTempShape );
+
+ // No need to set the wrapping here as it's either set in oox or will be set later
+
+ // Shapes in the header or footer should be in the background, since the default is WrapTextMode_THROUGH.
+ if (m_rDomainMapper.IsInHeaderFooter())
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(m_xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("Opaque", uno::Any(false));
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Exception in OLE Handler");
+ }
+ }
+ }
+ }
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+css::awt::Size OLEHandler::getSize() const
+{
+ if (!m_xShape)
+ return css::awt::Size();
+ return m_xShape->getSize();
+}
+
+css::uno::Reference<css::graphic::XGraphic> OLEHandler::getReplacement() const
+{
+ if (!m_xShape)
+ return nullptr;
+ uno::Reference<beans::XPropertySet> xShapeProps(m_xShape, uno::UNO_QUERY);
+ css::uno::Reference<css::graphic::XGraphic> xReplacement;
+ xShapeProps->getPropertyValue(getPropertyName(PROP_BITMAP)) >>= xReplacement;
+ return xReplacement;
+}
+
+void OLEHandler::lcl_sprm(Sprm & rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_OLEObject_OLEObject:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_wrap_wrap:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if ( pProperties )
+ {
+ tools::SvRef<WrapHandler> pHandler( new WrapHandler );
+ pProperties->resolve( *pHandler );
+
+ m_nWrapMode = pHandler->getWrapMode( );
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps( m_xShape, uno::UNO_QUERY_THROW );
+
+ xShapeProps->setPropertyValue(
+ getPropertyName( PROP_SURROUND ),
+ uno::Any( static_cast<sal_Int32>(m_nWrapMode) ) );
+
+ // Through shapes in the header or footer(that spill into the body) should be in the background.
+ // It is just assumed that all shapes will spill into the body.
+ if( m_rDomainMapper.IsInHeaderFooter() )
+ xShapeProps->setPropertyValue("Opaque", uno::Any(m_nWrapMode != text::WrapTextMode_THROUGH));
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Exception in OLE Handler");
+ }
+ }
+ }
+ break;
+ default:
+ {
+ OSL_FAIL( "unknown attribute");
+ }
+ }
+}
+
+void OLEHandler::importStream(const uno::Reference<uno::XComponentContext>& xComponentContext, const uno::Reference<text::XTextDocument>& xTextDocument, const uno::Reference<text::XTextContent>& xOLE)
+{
+ OUString aFilterService;
+ if (m_sProgId == "Word.Document.12")
+ aFilterService = "com.sun.star.comp.Writer.WriterFilter";
+ else if (m_sProgId == "Excel.Sheet.12")
+ aFilterService = "com.sun.star.comp.oox.xls.ExcelFilter";
+ else if (m_sProgId == "Equation.3")
+ aFilterService = "com.sun.star.comp.Math.MathTypeFilter";
+ else
+ SAL_WARN("writerfilter", "OLEHandler::importStream: unhandled m_sProgId: " << m_sProgId);
+
+ if (!m_xInputStream.is() || aFilterService.isEmpty())
+ return;
+
+ // Create the filter service.
+ uno::Reference<uno::XInterface> xInterface = xComponentContext->getServiceManager()->createInstanceWithContext(aFilterService, xComponentContext);
+
+ // Set target document.
+ uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier> xSupplier(xOLE, uno::UNO_QUERY);
+ uno::Reference<lang::XComponent> xEmbeddedObject = xSupplier->getEmbeddedObject();
+ if (!xEmbeddedObject.is())
+ return;
+ xImporter->setTargetDocument( xEmbeddedObject );
+
+ // Import the input stream.
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["InputStream"] <<= m_xInputStream;
+ uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY);
+ xFilter->filter(aMediaDescriptor.getAsConstPropertyValueList());
+
+ // Now that the data is imported, update the (typically) changed stream name.
+ uno::Reference<beans::XPropertySet> xPropertySet(xOLE, uno::UNO_QUERY);
+ ::oox::ole::SaveInteropProperties(xTextDocument,
+ xPropertySet->getPropertyValue("StreamName").get<OUString>(), &m_aURL,
+ m_sProgId);
+}
+
+OUString OLEHandler::getCLSID() const
+{
+ OUString aRet;
+
+ // See officecfg/registry/data/org/openoffice/Office/Embedding.xcu.
+ if (m_sProgId == "Word.Document.12")
+ {
+ if (officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::get())
+ aRet = "8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6";
+ }
+ else if (m_sProgId == "Excel.Sheet.12")
+ {
+ if (officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::get())
+ aRet = "47BBB4CB-CE4C-4E80-A591-42D9AE74950F";
+ }
+ else if (m_sProgId == "Equation.3")
+ {
+ if (officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::get())
+ aRet = "078B7ABA-54FC-457F-8551-6147E776A997";
+ }
+ else
+ SAL_WARN("writerfilter", "OLEHandler::getCLSID: unhandled m_sProgId: " << m_sProgId);
+
+ return aRet;
+}
+
+OUString const & OLEHandler::GetDrawAspect() const
+{
+ return m_sDrawAspect;
+}
+
+OUString const & OLEHandler::GetVisAreaWidth() const
+{
+ return m_sVisAreaWidth;
+}
+
+OUString const & OLEHandler::GetVisAreaHeight() const
+{
+ return m_sVisAreaHeight;
+}
+
+OUString OLEHandler::copyOLEOStream(
+ uno::Reference<text::XTextDocument> const& xTextDocument)
+{
+ OUString sRet;
+ if( !m_xInputStream.is( ) )
+ return sRet;
+ try
+ {
+ uno::Reference < lang::XMultiServiceFactory > xFactory(xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference< document::XEmbeddedObjectResolver > xEmbeddedResolver(
+ xFactory->createInstance("com.sun.star.document.ImportEmbeddedObjectResolver"), uno::UNO_QUERY_THROW );
+ //hack to work with the ImportEmbeddedObjectResolver
+ static sal_Int32 nObjectCount = 100;
+ uno::Reference< container::XNameAccess > xNA( xEmbeddedResolver, uno::UNO_QUERY_THROW );
+ OUString aURL = "Obj" + OUString::number( nObjectCount++ );
+ uno::Reference < io::XOutputStream > xOLEStream;
+ if( (xNA->getByName( aURL ) >>= xOLEStream) && xOLEStream.is() )
+ {
+ const sal_Int32 nReadRequest = 0x1000;
+ uno::Sequence< sal_Int8 > aData;
+
+ while( true )
+ {
+ sal_Int32 nRead = m_xInputStream->readBytes( aData, nReadRequest );
+ xOLEStream->writeBytes( aData );
+ if( nRead < nReadRequest )
+ {
+ xOLEStream->closeOutput();
+ break;
+ }
+ }
+
+ ::oox::ole::SaveInteropProperties(xTextDocument, aURL, nullptr, m_sProgId);
+
+ OUString aPersistName( xEmbeddedResolver->resolveEmbeddedObjectURL( aURL ) );
+ sRet = aPersistName.copy( strlen("vnd.sun.star.EmbeddedObject:") );
+
+ }
+ uno::Reference< lang::XComponent > xComp( xEmbeddedResolver, uno::UNO_QUERY_THROW );
+ xComp->dispose();
+ m_aURL = aURL;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "OLEHandler::createOLEObject");
+ }
+ return sRet;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/OLEHandler.hxx b/writerfilter/source/dmapper/OLEHandler.hxx
new file mode 100644
index 000000000..67fed0128
--- /dev/null
+++ b/writerfilter/source/dmapper/OLEHandler.hxx
@@ -0,0 +1,94 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+
+namespace com::sun::star{
+ namespace graphic{
+ class XGraphic;
+ }
+ namespace io{
+ class XInputStream;
+ }
+ namespace text{
+ class XTextContent;
+ class XTextDocument;
+ }
+ namespace uno {
+ class XComponentContext;
+ }
+}
+namespace writerfilter::dmapper
+{
+class DomainMapper;
+/** Handler for OLE objects
+ */
+class OLEHandler : public LoggedProperties
+{
+ OUString m_sProgId;
+ OUString m_sDrawAspect;
+ OUString m_sVisAreaWidth;
+ OUString m_sVisAreaHeight;
+ /// The stream URL right after the import of the raw data.
+ OUString m_aURL;
+
+ css::text::WrapTextMode m_nWrapMode;
+
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+
+ css::uno::Reference<css::io::XInputStream> m_xInputStream;
+ DomainMapper& m_rDomainMapper;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ explicit OLEHandler(DomainMapper& rDomainMapper);
+ virtual ~OLEHandler() override;
+
+ const css::uno::Reference<css::drawing::XShape>& getShape() const { return m_xShape; };
+
+ bool isOLEObject() const { return m_xInputStream.is(); }
+
+ /// In case of a valid CLSID, import the native data to the previously created empty OLE object.
+ void importStream(const css::uno::Reference<css::uno::XComponentContext>& xComponentContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument,
+ const css::uno::Reference<css::text::XTextContent>& xOLE);
+
+ /// Get the CLSID of the OLE object, in case we can find one based on m_sProgId.
+ OUString getCLSID() const;
+
+ OUString const & GetDrawAspect() const;
+ OUString const & GetVisAreaWidth() const;
+ OUString const & GetVisAreaHeight() const;
+
+ OUString copyOLEOStream(css::uno::Reference<css::text::XTextDocument> const& xTextDocument);
+
+ css::awt::Size getSize() const;
+ css::uno::Reference<css::graphic::XGraphic> getReplacement() const;
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PageBordersHandler.cxx b/writerfilter/source/dmapper/PageBordersHandler.cxx
new file mode 100644
index 000000000..89548eb35
--- /dev/null
+++ b/writerfilter/source/dmapper/PageBordersHandler.cxx
@@ -0,0 +1,145 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "BorderHandler.hxx"
+#include "PageBordersHandler.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper {
+
+PgBorder::PgBorder( ) :
+ m_nDistance( 0 ),
+ m_ePos( BORDER_RIGHT ),
+ m_bShadow(false)
+{
+}
+
+PageBordersHandler::PageBordersHandler( ) :
+LoggedProperties("PageBordersHandler"),
+m_eBorderApply(SectionPropertyMap::BorderApply::ToAllInSection),
+m_eOffsetFrom(SectionPropertyMap::BorderOffsetFrom::Text)
+{
+}
+
+PageBordersHandler::~PageBordersHandler( )
+{
+}
+
+void PageBordersHandler::lcl_attribute( Id eName, Value& rVal )
+{
+ int nIntValue = rVal.getInt( );
+ switch ( eName )
+ {
+ case NS_ooxml::LN_CT_PageBorders_display:
+ {
+ switch ( nIntValue )
+ {
+ default:
+ case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_allPages:
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToAllInSection;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_firstPage:
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToFirstPageInSection;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_notFirstPage:
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToAllButFirstInSection;
+ break;
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PageBorders_offsetFrom:
+ {
+ switch ( nIntValue )
+ {
+ default:
+ case NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page:
+ m_eOffsetFrom = SectionPropertyMap::BorderOffsetFrom::Edge;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_PageBorderOffset_text:
+ m_eOffsetFrom = SectionPropertyMap::BorderOffsetFrom::Text;
+ break;
+ }
+ }
+ break;
+ default:;
+ }
+}
+
+void PageBordersHandler::lcl_sprm( Sprm& rSprm )
+{
+ switch ( rSprm.getId( ) )
+ {
+ case NS_ooxml::LN_CT_PageBorders_top:
+ case NS_ooxml::LN_CT_PageBorders_left:
+ case NS_ooxml::LN_CT_PageBorders_bottom:
+ case NS_ooxml::LN_CT_PageBorders_right:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>( true );
+ pProperties->resolve(*pBorderHandler);
+ BorderPosition ePos = BorderPosition( 0 );
+ switch( rSprm.getId( ) )
+ {
+ case NS_ooxml::LN_CT_PageBorders_top:
+ ePos = BORDER_TOP;
+ break;
+ case NS_ooxml::LN_CT_PageBorders_left:
+ ePos = BORDER_LEFT;
+ break;
+ case NS_ooxml::LN_CT_PageBorders_bottom:
+ ePos = BORDER_BOTTOM;
+ break;
+ case NS_ooxml::LN_CT_PageBorders_right:
+ ePos = BORDER_RIGHT;
+ break;
+ default:;
+ }
+
+ PgBorder aPgBorder;
+ aPgBorder.m_rLine = pBorderHandler->getBorderLine( );
+ aPgBorder.m_nDistance = pBorderHandler->getLineDistance( );
+ aPgBorder.m_ePos = ePos;
+ aPgBorder.m_bShadow = pBorderHandler->getShadow();
+ if (pBorderHandler->getLineType() != NS_ooxml::LN_Value_ST_Border_none)
+ {
+ m_aBorders.push_back( aPgBorder );
+ }
+ }
+ }
+ break;
+ default:;
+ }
+}
+
+void PageBordersHandler::SetBorders( SectionPropertyMap* pSectContext )
+{
+ for (const PgBorder& rBorder : m_aBorders)
+ {
+ pSectContext->SetBorder( rBorder.m_ePos, rBorder.m_nDistance, rBorder.m_rLine, rBorder.m_bShadow );
+ }
+ pSectContext->SetBorderApply(m_eBorderApply);
+ pSectContext->SetBorderOffsetFrom(m_eOffsetFrom);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PageBordersHandler.hxx b/writerfilter/source/dmapper/PageBordersHandler.hxx
new file mode 100644
index 000000000..537d34b81
--- /dev/null
+++ b/writerfilter/source/dmapper/PageBordersHandler.hxx
@@ -0,0 +1,62 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "PropertyMap.hxx"
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/table/BorderLine2.hpp>
+
+#include <vector>
+
+namespace writerfilter::dmapper
+{
+class PgBorder
+{
+public:
+ css::table::BorderLine2 m_rLine;
+ sal_Int32 m_nDistance;
+ BorderPosition m_ePos;
+ bool m_bShadow;
+
+ PgBorder();
+};
+
+class PageBordersHandler : public LoggedProperties
+{
+private:
+ // See implementation of SectionPropertyMap::ApplyBorderToPageStyles
+ SectionPropertyMap::BorderApply m_eBorderApply;
+ SectionPropertyMap::BorderOffsetFrom m_eOffsetFrom;
+ std::vector<PgBorder> m_aBorders;
+
+ // Properties
+ virtual void lcl_attribute(Id eName, Value& rVal) override;
+ virtual void lcl_sprm(Sprm& rSprm) override;
+
+public:
+ PageBordersHandler();
+ virtual ~PageBordersHandler() override;
+
+ void SetBorders(SectionPropertyMap* pSectContext);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx
new file mode 100644
index 000000000..658a73040
--- /dev/null
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -0,0 +1,386 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <rtl/ustring.hxx>
+#include "PropertyIds.hxx"
+
+namespace writerfilter::dmapper{
+
+OUString getPropertyName( PropertyIds eId )
+{
+ OUString sName;
+ switch(eId) {
+ case PROP_CHAR_WEIGHT: sName = "CharWeight"; break;
+ case PROP_CHAR_POSTURE: sName = "CharPosture"; break;
+ case PROP_CHAR_STRIKEOUT: sName = "CharStrikeout"; break;
+ case PROP_CHAR_CONTOURED: sName = "CharContoured"; break;
+ case PROP_CHAR_SHADOWED: sName = "CharShadowed"; break;
+ case PROP_CHAR_CASE_MAP: sName = "CharCaseMap"; break;
+ case PROP_CHAR_COLOR: sName = "CharColor"; break;
+ case PROP_CHAR_RELIEF: sName = "CharRelief"; break;
+ case PROP_CHAR_UNDERLINE: sName = "CharUnderline"; break;
+ case PROP_CHAR_UNDERLINE_COLOR: sName = "CharUnderlineColor"; break;
+ case PROP_CHAR_UNDERLINE_HAS_COLOR: sName = "CharUnderlineHasColor"; break;
+ case PROP_CHAR_WORD_MODE: sName = "CharWordMode"; break;
+ case PROP_CHAR_ESCAPEMENT : sName = "CharEscapement"; break;
+ case PROP_CHAR_ESCAPEMENT_HEIGHT: sName = "CharEscapementHeight"; break;
+ case PROP_CHAR_HEIGHT: sName = "CharHeight"; break;
+ case PROP_CHAR_HEIGHT_COMPLEX: sName = "CharHeightComplex"; break;
+ case PROP_CHAR_LOCALE: sName = "CharLocale"; break;
+ case PROP_CHAR_LOCALE_ASIAN: sName = "CharLocaleAsian"; break;
+ case PROP_CHAR_LOCALE_COMPLEX: sName = "CharLocaleComplex"; break;
+ case PROP_CHAR_WEIGHT_COMPLEX : sName = "CharWeightComplex"; break;
+ case PROP_CHAR_POSTURE_COMPLEX: sName = "CharPostureComplex"; break;
+ case PROP_CHAR_CHAR_KERNING: sName = "CharKerning"; break;
+ case PROP_CHAR_AUTO_KERNING: sName = "CharAutoKerning"; break;
+ case PROP_CHAR_SCALE_WIDTH: sName = "CharScaleWidth"; break;
+ case PROP_CHAR_STYLE_NAME: sName = "CharStyleName"; break;
+ case PROP_CHAR_FONT_NAME: sName = "CharFontName"; break;
+ case PROP_CHAR_FONT_CHAR_SET: sName = "CharFontCharSet"; break;
+ case PROP_CHAR_FONT_NAME_ASIAN : sName = "CharFontNameAsian"; break;
+ case PROP_CHAR_HEIGHT_ASIAN : sName = "CharHeightAsian"; break;
+ case PROP_CHAR_FONT_NAME_COMPLEX : sName = "CharFontNameComplex"; break;
+ case PROP_CHAR_HIDDEN : sName = "CharHidden"; break;
+ case PROP_CHAR_WEIGHT_ASIAN : sName = "CharWeightAsian"; break;
+ case PROP_CHAR_POSTURE_ASIAN : sName = "CharPostureAsian"; break;
+ case PROP_CHAR_BACK_COLOR: sName = "CharBackColor"; break;
+ case PROP_CHAR_EMPHASIS: sName = "CharEmphasis"; break;
+ case PROP_CHAR_COMBINE_IS_ON: sName = "CharCombineIsOn"; break;
+ case PROP_CHAR_COMBINE_PREFIX: sName = "CharCombinePrefix"; break;
+ case PROP_CHAR_COMBINE_SUFFIX: sName = "CharCombineSuffix"; break;
+ case PROP_CHAR_ROTATION: sName = "CharRotation"; break;
+ case PROP_CHAR_ROTATION_IS_FIT_TO_LINE: sName = "CharRotationIsFitToLine"; break;
+ case PROP_CHAR_FLASH: sName = "CharFlash"; break;
+ case PROP_CHAR_LEFT_BORDER: sName = "CharLeftBorder";break;
+ case PROP_CHAR_RIGHT_BORDER: sName = "CharRightBorder";break;
+ case PROP_CHAR_TOP_BORDER: sName = "CharTopBorder";break;
+ case PROP_CHAR_BOTTOM_BORDER: sName = "CharBottomBorder";break;
+ case PROP_CHAR_LEFT_BORDER_DISTANCE: sName = "CharLeftBorderDistance"; break;
+ case PROP_CHAR_RIGHT_BORDER_DISTANCE: sName = "CharRightBorderDistance"; break;
+ case PROP_CHAR_TOP_BORDER_DISTANCE: sName = "CharTopBorderDistance";break;
+ case PROP_CHAR_BOTTOM_BORDER_DISTANCE: sName = "CharBottomBorderDistance"; break;
+ case PROP_CHAR_SHADOW_FORMAT: sName = "CharShadowFormat"; break;
+ case PROP_CHAR_HIGHLIGHT: sName = "CharHighlight"; break;
+ case PROP_PARA_STYLE_NAME: sName = "ParaStyleName"; break;
+ case PROP_PARA_ADJUST: sName = "ParaAdjust"; break;
+ case PROP_PARA_VERT_ALIGNMENT: sName = "ParaVertAlignment"; break;
+ case PROP_PARA_LAST_LINE_ADJUST: sName = "ParaLastLineAdjust"; break;
+ case PROP_PARA_RIGHT_MARGIN : sName = "ParaRightMargin"; break;
+ case PROP_PARA_LEFT_MARGIN : sName = "ParaLeftMargin"; break;
+ case PROP_PARA_FIRST_LINE_INDENT: sName = "ParaFirstLineIndent"; break;
+ case PROP_PARA_KEEP_TOGETHER: sName = "ParaKeepTogether"; break;
+ case PROP_PARA_TOP_MARGIN: sName = "ParaTopMargin"; break;
+ case PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING: sName = "ParaTopMarginBeforeAutoSpacing"; break;
+ case PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING: sName = "ParaBottomMarginAfterAutoSpacing"; break;
+ case PROP_PARA_CONTEXT_MARGIN: sName = "ParaContextMargin"; break;
+ case PROP_PARA_BOTTOM_MARGIN: sName = "ParaBottomMargin"; break;
+ case PROP_PARA_IS_HYPHENATION: sName = "ParaIsHyphenation"; break;
+ case PROP_PARA_HYPHENATION_NO_CAPS: sName = "ParaHyphenationNoCaps"; break;
+ case PROP_PARA_HYPHENATION_ZONE: sName = "ParaHyphenationZone"; break;
+ case PROP_PARA_LINE_NUMBER_COUNT: sName = "ParaLineNumberCount"; break;
+ case PROP_PARA_IS_HANGING_PUNCTUATION: sName = "ParaIsHangingPunctuation"; break;
+ case PROP_PARA_LINE_SPACING: sName = "ParaLineSpacing"; break;
+ case PROP_PARA_TAB_STOPS: sName = "ParaTabStops"; break;
+ case PROP_PARA_WIDOWS: sName = "ParaWidows"; break;
+ case PROP_PARA_ORPHANS: sName = "ParaOrphans"; break;
+ case PROP_PARA_LINE_NUMBER_START_VALUE: sName = "ParaLineNumberStartValue"; break;
+ case PROP_NUMBERING_LEVEL: sName = "NumberingLevel"; break;
+ case PROP_NUMBERING_RULES: sName = "NumberingRules"; break;
+ case PROP_NUMBERING_TYPE: sName = "NumberingType"; break;
+ case PROP_START_WITH: sName = "StartWith"; break;
+ case PROP_ADJUST: sName = "Adjust"; break;
+ case PROP_PARENT_NUMBERING: sName = "ParentNumbering"; break;
+ case PROP_RIGHT_MARGIN : sName = "RightMargin"; break;
+ case PROP_LEFT_MARGIN : sName = "LeftMargin"; break;
+ case PROP_TOP_MARGIN : sName = "TopMargin"; break;
+ case PROP_BOTTOM_MARGIN : sName = "BottomMargin"; break;
+ case PROP_FIRST_LINE_OFFSET: sName = "FirstLineOffset"; break;
+ case PROP_LEFT_BORDER : sName = "LeftBorder";break;
+ case PROP_RIGHT_BORDER : sName = "RightBorder";break;
+ case PROP_TOP_BORDER : sName = "TopBorder";break;
+ case PROP_BOTTOM_BORDER : sName = "BottomBorder";break;
+ case PROP_TABLE_BORDER : sName = "TableBorder";break;
+ case PROP_TABLE_ROW_DELETE : sName = "TableRowDelete"; break;
+ case PROP_TABLE_ROW_INSERT : sName = "TableRowInsert"; break;
+ case PROP_TABLE_CELL_DELETE : sName = "TableCellDelete"; break;
+ case PROP_TABLE_CELL_INSERT : sName = "TableCellInsert"; break;
+ case PROP_LEFT_BORDER_DISTANCE : sName = "LeftBorderDistance"; break;
+ case PROP_RIGHT_BORDER_DISTANCE : sName = "RightBorderDistance"; break;
+ case PROP_TOP_BORDER_DISTANCE : sName = "TopBorderDistance";break;
+ case PROP_BOTTOM_BORDER_DISTANCE: sName = "BottomBorderDistance"; break;
+ case PROP_CURRENT_PRESENTATION : sName = "CurrentPresentation"; break;
+ case PROP_IS_FIXED : sName = "IsFixed"; break;
+ case PROP_SUB_TYPE : sName = "SubType"; break;
+ case PROP_FILE_FORMAT : sName = "FileFormat"; break;
+ case PROP_HYPER_LINK_U_R_L : sName = "HyperLinkURL"; break;
+ case PROP_HYPERLINK : sName = "Hyperlink"; break;
+ case PROP_NUMBER_FORMAT : sName = "NumberFormat"; break;
+ case PROP_NAME : sName = "Name"; break;
+ case PROP_IS_INPUT : sName = "IsInput"; break;
+ case PROP_HINT : sName = "Hint"; break;
+ case PROP_FULL_NAME : sName = "FullName"; break;
+ case PROP_DESCRIPTION : sName = "Description"; break;
+ case PROP_MACRO_NAME : sName = "MacroName"; break;
+ case PROP_TITLE : sName = "Title"; break;
+ case PROP_CONTENT : sName = "Content"; break;
+ case PROP_INPUT_STREAM : sName = "InputStream"; break;
+ case PROP_GRAPHIC : sName = "Graphic"; break;
+ case PROP_ANCHOR_TYPE : sName = "AnchorType"; break;
+ case PROP_SIZE : sName = "Size"; break;
+ case PROP_HORI_ORIENT : sName = "HoriOrient"; break;
+ case PROP_HORI_ORIENT_POSITION : sName = "HoriOrientPosition"; break;
+ case PROP_HORI_ORIENT_RELATION : sName = "HoriOrientRelation"; break;
+ case PROP_VERT_ORIENT : sName = "VertOrient"; break;
+ case PROP_VERT_ORIENT_POSITION : sName = "VertOrientPosition"; break;
+ case PROP_VERT_ORIENT_RELATION : sName = "VertOrientRelation"; break;
+ case PROP_SIZE100th_M_M : sName = "Size100thMM"; break;
+ case PROP_SIZE_PIXEL : sName = "SizePixel"; break;
+ case PROP_SURROUND : sName = "Surround"; break;
+ case PROP_SURROUND_CONTOUR : sName = "SurroundContour"; break;
+ case PROP_ADJUST_CONTRAST : sName = "AdjustContrast"; break;
+ case PROP_ADJUST_LUMINANCE : sName = "AdjustLuminance"; break;
+ case PROP_GRAPHIC_COLOR_MODE : sName = "GraphicColorMode"; break;
+ case PROP_CONTOUR_OUTSIDE : sName = "ContourOutside"; break;
+ case PROP_CONTOUR_POLY_POLYGON : sName = "ContourPolyPolygon"; break;
+ case PROP_PAGE_TOGGLE : sName = "PageToggle"; break;
+ case PROP_BACK_COLOR : sName = "BackColor"; break;
+ case PROP_BACK_COLOR_TRANSPARENCY: sName = "BackColorTransparency"; break;
+ case PROP_ALTERNATIVE_TEXT : sName = "AlternativeText"; break;
+ case PROP_HEADER_TEXT_LEFT : sName = "HeaderTextLeft"; break;
+ case PROP_HEADER_TEXT : sName = "HeaderText"; break;
+ case PROP_HEADER_IS_SHARED : sName = "HeaderIsShared"; break;
+ case PROP_HEADER_IS_ON : sName = "HeaderIsOn"; break;
+ case PROP_FOOTER_TEXT_LEFT : sName = "FooterTextLeft"; break;
+ case PROP_FOOTER_TEXT : sName = "FooterText"; break;
+ case PROP_FOOTER_IS_SHARED : sName = "FooterIsShared"; break;
+ case PROP_FOOTER_IS_ON : sName = "FooterIsOn"; break;
+ case PROP_FOOTNOTE_COUNTING : sName = "FootnoteCounting"; break;
+ case PROP_FOOTNOTE_LINE_ADJUST : sName = "FootnoteLineAdjust"; break;
+ case PROP_WIDTH : sName = "Width"; break;
+ case PROP_HEIGHT : sName = "Height"; break;
+ case PROP_TEXT_COLUMNS : sName = "TextColumns"; break;
+ case PROP_AUTOMATIC_DISTANCE : sName = "AutomaticDistance"; break;
+ case PROP_IS_LANDSCAPE : sName = "IsLandscape"; break;
+ case PROP_FIRST_PAGE : sName = "First Page"; break;
+ case PROP_PAGE_DESC_NAME : sName = "PageDescName"; break;
+ case PROP_PAGE_NUMBER_OFFSET: sName = "PageNumberOffset"; break;
+ case PROP_BREAK_TYPE : sName = "BreakType"; break;
+ case PROP_FOOTER_IS_DYNAMIC_HEIGHT: sName = "FooterIsDynamicHeight"; break;
+ case PROP_FOOTER_DYNAMIC_SPACING: sName = "FooterDynamicSpacing"; break;
+ case PROP_FOOTER_HEIGHT : sName = "FooterHeight"; break;
+ case PROP_FOOTER_BODY_DISTANCE : sName = "FooterBodyDistance"; break;
+ case PROP_HEADER_IS_DYNAMIC_HEIGHT: sName = "HeaderIsDynamicHeight"; break;
+ case PROP_HEADER_DYNAMIC_SPACING: sName = "HeaderDynamicSpacing"; break;
+ case PROP_HEADER_HEIGHT : sName = "HeaderHeight"; break;
+ case PROP_HEADER_BODY_DISTANCE : sName = "HeaderBodyDistance"; break;
+ case PROP_WRITING_MODE : sName = "WritingMode"; break;
+ case PROP_GRID_MODE : sName = "GridMode"; break;
+ case PROP_GRID_DISPLAY : sName = "GridDisplay"; break;
+ case PROP_GRID_PRINT : sName = "GridPrint"; break;
+ case PROP_GRID_LINES : sName = "GridLines"; break;
+ case PROP_GRID_BASE_HEIGHT : sName = "GridBaseHeight"; break;
+ case PROP_GRID_BASE_WIDTH : sName = "GridBaseWidth"; break;
+ case PROP_GRID_RUBY_HEIGHT : sName = "GridRubyHeight"; break;
+ case PROP_GRID_STANDARD_MODE : sName = "StandardPageMode"; break;
+ case PROP_IS_ON : sName = "IsOn"; break;
+ case PROP_RESTART_AT_EACH_PAGE : sName = "RestartAtEachPage"; break;
+ case PROP_COUNT_EMPTY_LINES : sName = "CountEmptyLines"; break;
+ case PROP_COUNT_LINES_IN_FRAMES : sName = "CountLinesInFrames"; break;
+ case PROP_INTERVAL : sName = "Interval"; break;
+ case PROP_DISTANCE : sName = "Distance"; break;
+ case PROP_NUMBER_POSITION : sName = "NumberPosition"; break;
+ case PROP_LEVEL : sName = "Level"; break;
+ case PROP_LEVEL_FOLLOW : sName = "LabelFollowedBy"; break;
+ case PROP_LEVEL_PARAGRAPH_STYLES : sName = "LevelParagraphStyles"; break;
+ case PROP_LEVEL_FORMAT : sName = "LevelFormat"; break;
+ case PROP_LIST_FORMAT : sName = "ListFormat"; break;
+ case PROP_TOKEN_TYPE : sName = "TokenType"; break;
+ case PROP_TOKEN_HYPERLINK_START : sName = "TokenHyperlinkStart"; break;
+ case PROP_TOKEN_HYPERLINK_END : sName = "TokenHyperlinkEnd"; break;
+ case PROP_TOKEN_CHAPTER_INFO : sName = "TokenChapterInfo"; break;
+ case PROP_CHAPTER_FORMAT : sName = "ChapterFormat"; break;
+ case PROP_TOKEN_TEXT : sName = "TokenText"; break;
+ case PROP_TEXT : sName = "Text"; break;
+ case PROP_CREATE_FROM_OUTLINE : sName = "CreateFromOutline"; break;
+ case PROP_CREATE_FROM_MARKS : sName = "CreateFromMarks"; break;
+ case PROP_STANDARD : sName = "Standard"; break;
+ case PROP_SPLIT : sName = "Split"; break;
+ case PROP_IS_SPLIT_ALLOWED : sName = "IsSplitAllowed"; break;
+ case META_PROP_VERTICAL_BORDER : sName = "VerticalBorder"; break;
+ case META_PROP_HORIZONTAL_BORDER : sName = "HorizontalBorder"; break;
+ case PROP_HEADER_ROW_COUNT : sName = "HeaderRowCount"; break;
+ case PROP_SIZE_TYPE : sName = "SizeType"; break;
+ case PROP_TABLE_COLUMN_SEPARATORS: sName = "TableColumnSeparators"; break;
+ case META_PROP_TABLE_STYLE_NAME : sName = "TableStyleName"; break;
+ case PROP_TABLE_REDLINE_PARAMS : sName = "TableRedlineParams"; break;
+ case PROP_REDLINE_AUTHOR : sName = "RedlineAuthor"; break;
+ case PROP_REDLINE_DATE_TIME : sName = "RedlineDateTime"; break;
+ case PROP_REDLINE_TYPE : sName = "RedlineType"; break;
+ case PROP_REDLINE_REVERT_PROPERTIES: sName = "RedlineRevertProperties"; break;
+ case PROP_IS_PROTECTED : sName = "IsProtected"; break;
+ case PROP_SIZE_PROTECTED : sName = "SizeProtected"; break;
+ case PROP_POSITION_PROTECTED : sName = "PositionProtected"; break;
+ case PROP_OPAQUE : sName = "Opaque"; break;
+ case PROP_VERTICAL_MERGE : sName = "VerticalMerge"; break;
+ case PROP_BULLET_CHAR : sName = "BulletChar"; break;
+ case PROP_BULLET_FONT_NAME : sName = "BulletFontName"; break;
+ case PROP_TABS_RELATIVE_TO_INDENT: sName = "TabsRelativeToIndent"; break;
+ case PROP_PREFIX : sName = "Prefix"; break;
+ case PROP_SUFFIX : sName = "Suffix"; break;
+ case PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES: sName = "CreateFromLevelParagraphStyles"; break;
+ case PROP_DROP_CAP_FORMAT : sName = "DropCapFormat"; break;
+ case PROP_REFERENCE_FIELD_PART : sName = "ReferenceFieldPart"; break;
+ case PROP_SOURCE_NAME: sName = "SourceName"; break;
+ case PROP_REFERENCE_FIELD_SOURCE : sName = "ReferenceFieldSource"; break;
+ case PROP_WIDTH_TYPE : sName = "WidthType"; break;
+ case PROP_TBL_LOOK : sName = "TblLook"; break;
+ case PROP_TEXT_RANGE: sName = "TextRange"; break;
+ case PROP_TEXT_VERTICAL_ADJUST : sName = "TextVerticalAdjust"; break;
+ case PROP_SERVICE_CHAR_STYLE : sName = "com.sun.star.style.CharacterStyle"; break;
+ case PROP_SERVICE_PARA_STYLE : sName = "com.sun.star.style.ParagraphStyle"; break;
+ case PROP_CHARACTER_STYLES : sName = "CharacterStyles"; break;
+ case PROP_PARAGRAPH_STYLES : sName = "ParagraphStyles"; break;
+ case PROP_TABLE_BORDER_DISTANCES: sName = "TableBorderDistances"; break;
+ case META_PROP_CELL_MAR_TOP : sName = "MetaPropCellMarTop"; break;
+ case META_PROP_CELL_MAR_BOTTOM : sName = "MetaPropCellMarBottom"; break;
+ case META_PROP_CELL_MAR_LEFT : sName = "MetaPropCellMarLeft"; break;
+ case META_PROP_CELL_MAR_RIGHT : sName = "MetaPropCellMarRight"; break;
+ case PROP_START_AT : sName = "StartAt"; break;
+ case PROP_CHAR_PROP_HEIGHT : sName = "CharPropHeight"; break;
+ case PROP_CHAR_PROP_HEIGHT_ASIAN : sName = "CharPropHeightAsian"; break;
+ case PROP_CHAR_PROP_HEIGHT_COMPLEX: sName = "CharPropHeightComplex"; break;
+ case PROP_FORMAT : sName = "Format"; break;
+ case PROP_INSERT : sName = "Insert"; break;
+ case PROP_DELETE : sName = "Delete"; break;
+ case PROP_PARAGRAPH_FORMAT : sName = "ParagraphFormat"; break;
+ case PROP_STREAM_NAME: sName = "StreamName"; break;
+ case PROP_BITMAP : sName = "Bitmap"; break;
+ case PROP_IS_DATE : sName = "IsDate"; break;
+ case PROP_TAB_STOP_DISTANCE : sName = "TabStopDistance"; break;
+ case PROP_INDENT_AT : sName = "IndentAt"; break;
+ case PROP_FIRST_LINE_INDENT : sName = "FirstLineIndent"; break;
+ case PROP_NUMBERING_STYLE_NAME : sName = "NumberingStyleName"; break;
+ case PROP_OUTLINE_LEVEL : sName = "OutlineLevel"; break;
+ case PROP_LISTTAB_STOP_POSITION : sName = "ListtabStopPosition"; break;
+ case PROP_POSITION_AND_SPACE_MODE : sName = "PositionAndSpaceMode"; break;
+ case PROP_PARA_SPLIT: sName = "ParaSplit"; break;
+ case PROP_HELP: sName = "Help"; break;
+ case PROP_HEADING_STYLE_NAME: sName = "HeadingStyleName"; break;
+ case PROP_FRM_DIRECTION: sName = "FRMDirection"; break;
+ case PROP_EMBEDDED_OBJECT : sName = "EmbeddedObject"; break;
+ case PROP_IS_VISIBLE: sName = "IsVisible"; break;
+ case PROP_PAGE_STYLE_LAYOUT: sName = "PageStyleLayout"; break;
+ case PROP_Z_ORDER: sName = "ZOrder"; break;
+ case PROP_EMBED_FONTS: sName = "EmbedFonts"; break;
+ case PROP_EMBED_SYSTEM_FONTS: sName = "EmbedSystemFonts"; break;
+ case PROP_SHADOW_FORMAT: sName = "ShadowFormat"; break;
+ case PROP_RELATIVE_WIDTH: sName = "RelativeWidth"; break;
+ case PROP_IS_WIDTH_RELATIVE: sName = "IsWidthRelative"; break;
+ case PROP_GRAPHIC_BITMAP: sName = "GraphicBitmap"; break;
+ case PROP_GRAPHIC_SIZE: sName = "GraphicSize"; break;
+ case PROP_CHAR_SHADING_VALUE: sName = "CharShadingValue"; break;
+ case PROP_CHAR_SHADING_MARKER: sName = "CharShadingMarker"; break;
+ case PROP_LABEL_CATEGORY: sName = "LabelCategory"; break;
+ case PROP_MIRROR_INDENTS : sName = "MirrorIndents"; break;
+ case PROP_SURROUND_TEXT_WRAP_SMALL: sName = "SurroundTextWrapSmall"; break;
+ case PROP_PARA_SHADOW_FORMAT: sName = "ParaShadowFormat"; break;
+ case PROP_FOOTNOTE_LINE_RELATIVE_WIDTH: sName = "FootnoteLineRelativeWidth"; break;
+ case PROP_TBL_HEADER: sName = "TblHeader"; break;
+ case PROP_CHAR_THEME_NAME_ASCII : sName = "CharThemeNameAscii"; break;
+ case PROP_CHAR_THEME_NAME_CS : sName = "CharThemeNameCs"; break;
+ case PROP_CHAR_THEME_NAME_H_ANSI : sName = "CharThemeNameHAnsi"; break;
+ case PROP_CHAR_THEME_NAME_EAST_ASIA : sName = "CharThemeNameEastAsia"; break;
+ case PROP_CHAR_THEME_FONT_NAME_ASCII : sName = "CharThemeFontNameAscii"; break;
+ case PROP_CHAR_THEME_FONT_NAME_CS : sName = "CharThemeFontNameCs"; break;
+ case PROP_CHAR_THEME_FONT_NAME_EAST_ASIA: sName = "CharThemeFontNameEastAsia"; break;
+ case PROP_CHAR_THEME_COLOR : sName = "CharThemeColor"; break;
+ case PROP_CHAR_THEME_ORIGINAL_COLOR : sName = "CharThemeOriginalColor"; break;
+ case PROP_CHAR_THEME_COLOR_SHADE : sName = "CharThemeColorShade"; break;
+ case PROP_CHAR_THEME_FILL : sName = "CharThemeFill"; break;
+ case PROP_HORIZONTAL_MERGE: sName = "HorizontalMerge"; break;
+ case PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS : sName = "HideTabLeaderAndPageNumber" ; break ;
+ case PROP_TAB_IN_TOC : sName = "TabInTOC"; break ;
+ case PROP_TOC_BOOKMARK: sName = "TOCBookmark"; break;
+ case PROP_TOC_NEW_LINE: sName = "TOCNewLine"; break;
+ case PROP_TOC_PARAGRAPH_OUTLINE_LEVEL : sName = "TOCParagraphOutlineLevel"; break;
+ case PROP_CHAR_THEME_COLOR_TINT : sName = "CharThemeColorTint"; break;
+ case PROP_CHAR_GLOW_TEXT_EFFECT : sName = "CharGlowTextEffect"; break;
+ case PROP_CHAR_SHADOW_TEXT_EFFECT : sName = "CharShadowTextEffect"; break;
+ case PROP_CHAR_REFLECTION_TEXT_EFFECT : sName = "CharReflectionTextEffect"; break;
+ case PROP_CHAR_TEXTOUTLINE_TEXT_EFFECT : sName = "CharTextOutlineTextEffect"; break;
+ case PROP_CHAR_TEXTFILL_TEXT_EFFECT : sName = "CharTextFillTextEffect"; break;
+ case PROP_CHAR_SCENE3D_TEXT_EFFECT : sName = "CharScene3DTextEffect"; break;
+ case PROP_CHAR_PROPS3D_TEXT_EFFECT : sName = "CharProps3DTextEffect"; break;
+ case PROP_CHAR_LIGATURES_TEXT_EFFECT : sName = "CharLigaturesTextEffect"; break;
+ case PROP_CHAR_NUMFORM_TEXT_EFFECT : sName = "CharNumFormTextEffect"; break;
+ case PROP_CHAR_NUMSPACING_TEXT_EFFECT : sName = "CharNumSpacingTextEffect"; break;
+ case PROP_CHAR_STYLISTICSETS_TEXT_EFFECT : sName = "CharStylisticSetsTextEffect"; break;
+ case PROP_CHAR_CNTXTALTS_TEXT_EFFECT : sName = "CharCntxtAltsTextEffect"; break;
+ case PROP_SDTPR : sName = "SdtPr"; break;
+ case PROP_CELL_INTEROP_GRAB_BAG : sName = "CellInteropGrabBag"; break;
+ case PROP_TABLE_INTEROP_GRAB_BAG : sName = "TableInteropGrabBag"; break;
+ case PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING : sName = "ApplyParagraphMarkFormatToNumbering"; break;
+ case PROP_SDT_END_BEFORE: sName = "SdtEndBefore"; break;
+ case PROP_PARA_SDT_END_BEFORE: sName = "ParaSdtEndBefore"; break;
+ case META_PROP_TABLE_LOOK: sName = "TableStyleLook"; break;
+ case PROP_PARA_CNF_STYLE: sName = "ParaCnfStyle"; break;
+ case PROP_CELL_CNF_STYLE: sName = "CellCnfStyle"; break;
+ case PROP_ROW_CNF_STYLE: sName = "RowCnfStyle"; break;
+ case PROP_CELL_HIDE_MARK: sName = "CellHideMark"; break;
+ case PROP_FOLLOW_TEXT_FLOW: sName = "IsFollowingTextFlow"; break;
+ case PROP_FILL_STYLE: sName = "FillStyle"; break;
+ case PROP_FILL_COLOR: sName = "FillColor"; break;
+ case PROP_SNAP_TO_GRID: sName = "SnapToGrid"; break;
+ case PROP_GRID_SNAP_TO_CHARS: sName = "GridSnapToChars"; break;
+ case PROP_RUBY_STYLE: sName = "RubyCharStyleName"; break;
+ case PROP_RUBY_TEXT: sName = "RubyText"; break;
+ case PROP_RUBY_ADJUST: sName = "RubyAdjust"; break;
+ case PROP_RUBY_POSITION: sName = "RubyPosition"; break;
+ case PROP_DATABASE_NAME: sName = "DataBaseName"; break;
+ case PROP_COMMAND_TYPE: sName = "DataCommandType"; break;
+ case PROP_DATATABLE_NAME: sName = "DataTableName"; break;
+ case PROP_DATACOLUMN_NAME: sName = "DataColumnName"; break;
+ case PROP_CHAR_TRANSPARENCE: sName = "CharTransparence"; break;
+ case PROP_CELL_FORMULA: sName = "CellFormula"; break;
+ case PROP_CELL_FORMULA_CONVERTED: sName = "CellFormulaConverted"; break;
+ case PROP_GUTTER_MARGIN:
+ sName = "GutterMargin";
+ break;
+ case PROP_RTL_GUTTER:
+ sName = "RtlGutter";
+ break;
+ case PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF: sName = "CursorNotIgnoreTables"; break;
+ case PROP_PARA_CONNECT_BORDERS: sName= "ParaIsConnectBorder"; break;
+ }
+ assert(sName.getLength()>0);
+ return sName;
+}
+
+bool isCharacterProperty( const PropertyIds eId )
+{
+ return eId > PROP_CHARACTER_STYLES && eId < PROP_CHARACTER_END;
+}
+
+bool isParagraphProperty( const PropertyIds eId )
+{
+ return (eId >= PROP_PARA_ADJUST && eId <= PROP_PARA_WIDOWS) || eId == PROP_FILL_COLOR;
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx
new file mode 100644
index 000000000..20e4a1cc0
--- /dev/null
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -0,0 +1,377 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace writerfilter::dmapper{
+// Ensure that Character Properties are placed between PROP_CHARACTER_STYLES and PROP_CHARACTER_END
+enum PropertyIds
+ {
+ PROP_ID_START = 1
+ ,META_PROP_CELL_MAR_BOTTOM = PROP_ID_START
+ ,META_PROP_CELL_MAR_LEFT
+ ,META_PROP_CELL_MAR_RIGHT
+ ,META_PROP_CELL_MAR_TOP
+ ,META_PROP_HORIZONTAL_BORDER
+ ,META_PROP_TABLE_STYLE_NAME
+ ,META_PROP_VERTICAL_BORDER
+ ,PROP_ADJUST
+ ,PROP_ADJUST_CONTRAST
+ ,PROP_ADJUST_LUMINANCE
+ ,PROP_ALTERNATIVE_TEXT
+ ,PROP_ANCHOR_TYPE
+ ,PROP_AUTOMATIC_DISTANCE
+ ,PROP_BACK_COLOR
+ ,PROP_BACK_COLOR_TRANSPARENCY
+ ,PROP_BITMAP
+ ,PROP_BOTTOM_BORDER
+ ,PROP_BOTTOM_BORDER_DISTANCE
+ ,PROP_BOTTOM_MARGIN
+ ,PROP_BREAK_TYPE
+ ,PROP_BULLET_CHAR
+ ,PROP_BULLET_FONT_NAME
+ ,PROP_CHAPTER_FORMAT
+ ,PROP_CHARACTER_STYLES
+ ,PROP_CHAR_AUTO_KERNING
+ ,PROP_CHAR_BACK_COLOR
+ ,PROP_CHAR_CASE_MAP
+ ,PROP_CHAR_CHAR_KERNING
+ ,PROP_CHAR_COLOR
+ ,PROP_CHAR_COMBINE_IS_ON
+ ,PROP_CHAR_COMBINE_PREFIX
+ ,PROP_CHAR_COMBINE_SUFFIX
+ ,PROP_CHAR_CONTOURED
+ ,PROP_CHAR_LEFT_BORDER
+ ,PROP_CHAR_RIGHT_BORDER
+ ,PROP_CHAR_TOP_BORDER
+ ,PROP_CHAR_BOTTOM_BORDER
+ ,PROP_CHAR_LEFT_BORDER_DISTANCE
+ ,PROP_CHAR_RIGHT_BORDER_DISTANCE
+ ,PROP_CHAR_TOP_BORDER_DISTANCE
+ ,PROP_CHAR_BOTTOM_BORDER_DISTANCE
+ ,PROP_CHAR_EMPHASIS
+ ,PROP_CHAR_ESCAPEMENT
+ ,PROP_CHAR_ESCAPEMENT_HEIGHT
+ ,PROP_CHAR_FLASH
+ ,PROP_CHAR_FONT_CHAR_SET
+ ,PROP_CHAR_FONT_NAME
+ ,PROP_CHAR_FONT_NAME_ASIAN
+ ,PROP_CHAR_FONT_NAME_COMPLEX
+ ,PROP_CHAR_HEIGHT
+ ,PROP_CHAR_HEIGHT_ASIAN
+ ,PROP_CHAR_HEIGHT_COMPLEX
+ ,PROP_CHAR_HIDDEN
+ ,PROP_CHAR_HIGHLIGHT
+ ,PROP_CHAR_LOCALE
+ ,PROP_CHAR_LOCALE_ASIAN
+ ,PROP_CHAR_LOCALE_COMPLEX
+ ,PROP_CHAR_POSTURE
+ ,PROP_CHAR_POSTURE_ASIAN
+ ,PROP_CHAR_POSTURE_COMPLEX
+ ,PROP_CHAR_PROP_HEIGHT
+ ,PROP_CHAR_PROP_HEIGHT_ASIAN
+ ,PROP_CHAR_PROP_HEIGHT_COMPLEX
+ ,PROP_CHAR_RELIEF
+ ,PROP_CHAR_ROTATION
+ ,PROP_CHAR_ROTATION_IS_FIT_TO_LINE
+ ,PROP_CHAR_SCALE_WIDTH
+ ,PROP_CHAR_SHADOW_FORMAT
+ ,PROP_CHAR_SHADING_MARKER
+ ,PROP_CHAR_SHADING_VALUE
+ ,PROP_CHAR_SHADOWED
+ ,PROP_CHAR_STRIKEOUT
+ ,PROP_CHAR_STYLE_NAME
+ ,PROP_CHAR_TEXTOUTLINE_TEXT_EFFECT
+ ,PROP_CHAR_TEXTFILL_TEXT_EFFECT
+ ,PROP_CHAR_THEME_NAME_ASCII
+ ,PROP_CHAR_THEME_NAME_CS
+ ,PROP_CHAR_THEME_NAME_H_ANSI
+ ,PROP_CHAR_THEME_NAME_EAST_ASIA
+ ,PROP_CHAR_THEME_FONT_NAME_ASCII
+ ,PROP_CHAR_THEME_FONT_NAME_CS
+ ,PROP_CHAR_THEME_FONT_NAME_EAST_ASIA
+ ,PROP_CHAR_THEME_COLOR
+ ,PROP_CHAR_THEME_ORIGINAL_COLOR
+ ,PROP_CHAR_THEME_COLOR_SHADE
+ ,PROP_CHAR_THEME_FILL
+ ,PROP_CHAR_THEME_COLOR_TINT
+ ,PROP_CHAR_UNDERLINE
+ ,PROP_CHAR_UNDERLINE_COLOR
+ ,PROP_CHAR_UNDERLINE_HAS_COLOR
+ ,PROP_CHAR_WEIGHT
+ ,PROP_CHAR_WEIGHT_ASIAN
+ ,PROP_CHAR_WEIGHT_COMPLEX
+ ,PROP_CHAR_WORD_MODE
+ ,PROP_CHAR_GLOW_TEXT_EFFECT
+ ,PROP_CHAR_SHADOW_TEXT_EFFECT
+ ,PROP_CHAR_REFLECTION_TEXT_EFFECT
+ ,PROP_CHAR_SCENE3D_TEXT_EFFECT
+ ,PROP_CHAR_PROPS3D_TEXT_EFFECT
+ ,PROP_CHAR_LIGATURES_TEXT_EFFECT
+ ,PROP_CHAR_NUMFORM_TEXT_EFFECT
+ ,PROP_CHAR_NUMSPACING_TEXT_EFFECT
+ ,PROP_CHAR_STYLISTICSETS_TEXT_EFFECT
+ ,PROP_CHAR_CNTXTALTS_TEXT_EFFECT
+ ,PROP_CHARACTER_END
+ ,PROP_CONTENT = PROP_CHARACTER_END
+ ,PROP_CONTOUR_OUTSIDE
+ ,PROP_CONTOUR_POLY_POLYGON
+ ,PROP_COUNT_EMPTY_LINES
+ ,PROP_COUNT_LINES_IN_FRAMES
+ ,PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES
+ ,PROP_CREATE_FROM_MARKS
+ ,PROP_CREATE_FROM_OUTLINE
+ ,PROP_CURRENT_PRESENTATION
+ ,PROP_DELETE
+ ,PROP_DESCRIPTION
+ ,PROP_DISTANCE
+ ,PROP_DROP_CAP_FORMAT
+ ,PROP_FILE_FORMAT
+ ,PROP_FIRST_LINE_INDENT
+ ,PROP_FIRST_LINE_OFFSET
+ ,PROP_FIRST_PAGE
+ ,PROP_FOOTER_BODY_DISTANCE
+ ,PROP_FOOTER_DYNAMIC_SPACING
+ ,PROP_FOOTER_HEIGHT
+ ,PROP_FOOTER_IS_DYNAMIC_HEIGHT
+ ,PROP_FOOTER_IS_ON
+ ,PROP_FOOTER_IS_SHARED
+ ,PROP_FOOTER_TEXT
+ ,PROP_FOOTER_TEXT_LEFT
+ ,PROP_FOOTNOTE_COUNTING
+ ,PROP_FOOTNOTE_LINE_ADJUST
+ ,PROP_FORMAT
+ ,PROP_FULL_NAME
+ ,PROP_GRAPHIC
+ ,PROP_GRAPHIC_COLOR_MODE
+ ,PROP_GRID_BASE_HEIGHT
+ ,PROP_GRID_BASE_WIDTH
+ ,PROP_GRID_DISPLAY
+ ,PROP_GRID_LINES
+ ,PROP_GRID_MODE
+ ,PROP_GRID_PRINT
+ ,PROP_GRID_RUBY_HEIGHT
+ ,PROP_HEADER_BODY_DISTANCE
+ ,PROP_HEADER_DYNAMIC_SPACING
+ ,PROP_HEADER_HEIGHT
+ ,PROP_HEADER_IS_DYNAMIC_HEIGHT
+ ,PROP_HEADER_IS_ON
+ ,PROP_HEADER_IS_SHARED
+ ,PROP_HEADER_ROW_COUNT
+ ,PROP_HEADER_TEXT
+ ,PROP_HEADER_TEXT_LEFT
+ ,PROP_HEADING_STYLE_NAME
+ ,PROP_HEIGHT
+ ,PROP_HELP
+ ,PROP_HINT
+ ,PROP_HORI_ORIENT
+ ,PROP_HORI_ORIENT_POSITION
+ ,PROP_HORI_ORIENT_RELATION
+ ,PROP_HYPER_LINK_U_R_L
+ ,PROP_HYPERLINK
+ ,PROP_INDENT_AT
+ ,PROP_INPUT_STREAM
+ ,PROP_INSERT
+ ,PROP_INTERVAL
+ ,PROP_IS_DATE
+ ,PROP_IS_FIXED
+ ,PROP_IS_INPUT
+ ,PROP_IS_LANDSCAPE
+ ,PROP_IS_ON
+ ,PROP_IS_SPLIT_ALLOWED
+ ,PROP_IS_VISIBLE
+ ,PROP_LABEL_CATEGORY
+ ,PROP_LEFT_BORDER
+ ,PROP_LEFT_BORDER_DISTANCE
+ ,PROP_LEFT_MARGIN
+ ,PROP_LEVEL
+ ,PROP_LEVEL_FOLLOW
+ ,PROP_LEVEL_FORMAT
+ ,PROP_LEVEL_PARAGRAPH_STYLES
+ ,PROP_LISTTAB_STOP_POSITION
+ ,PROP_LIST_FORMAT
+ ,PROP_MACRO_NAME
+ ,PROP_NAME
+ ,PROP_NUMBERING_LEVEL
+ ,PROP_NUMBERING_RULES
+ ,PROP_NUMBERING_STYLE_NAME
+ ,PROP_NUMBERING_TYPE
+ ,PROP_NUMBER_FORMAT
+ ,PROP_NUMBER_POSITION
+ ,PROP_OPAQUE
+ ,PROP_OUTLINE_LEVEL
+ ,PROP_PAGE_DESC_NAME
+ ,PROP_PAGE_NUMBER_OFFSET
+ ,PROP_PAGE_TOGGLE
+ ,PROP_PARAGRAPH_FORMAT
+ ,PROP_PARAGRAPH_STYLES
+ ,PROP_PARA_ADJUST
+ ,PROP_PARA_BOTTOM_MARGIN
+ ,PROP_PARA_FIRST_LINE_INDENT
+ ,PROP_PARA_IS_HANGING_PUNCTUATION
+ ,PROP_PARA_IS_HYPHENATION
+ ,PROP_PARA_HYPHENATION_NO_CAPS
+ ,PROP_PARA_HYPHENATION_ZONE
+ ,PROP_PARA_KEEP_TOGETHER
+ ,PROP_PARA_LAST_LINE_ADJUST
+ ,PROP_PARA_LEFT_MARGIN
+ ,PROP_PARA_LINE_NUMBER_COUNT
+ ,PROP_PARA_LINE_NUMBER_START_VALUE
+ ,PROP_PARA_LINE_SPACING
+ ,PROP_PARA_ORPHANS
+ ,PROP_PARA_RIGHT_MARGIN
+ ,PROP_PARA_SPLIT
+ ,PROP_PARA_STYLE_NAME
+ ,PROP_PARA_TAB_STOPS
+ ,PROP_PARA_TOP_MARGIN
+ ,PROP_PARA_VERT_ALIGNMENT
+ ,PROP_PARA_WIDOWS
+ ,PROP_PARENT_NUMBERING
+ ,PROP_POSITION_AND_SPACE_MODE
+ ,PROP_POSITION_PROTECTED
+ ,PROP_IS_PROTECTED
+ ,PROP_PREFIX
+ ,PROP_REDLINE_AUTHOR
+ ,PROP_REDLINE_DATE_TIME
+ ,PROP_REDLINE_TYPE
+ ,PROP_REDLINE_REVERT_PROPERTIES
+ ,PROP_REFERENCE_FIELD_PART
+ ,PROP_REFERENCE_FIELD_SOURCE
+ ,PROP_RESTART_AT_EACH_PAGE
+ ,PROP_RIGHT_BORDER
+ ,PROP_RIGHT_BORDER_DISTANCE
+ ,PROP_RIGHT_MARGIN
+ ,PROP_SERVICE_CHAR_STYLE
+ ,PROP_SERVICE_PARA_STYLE
+ ,PROP_SIZE
+ ,PROP_SIZE100th_M_M
+ ,PROP_SIZE_PIXEL
+ ,PROP_SIZE_PROTECTED
+ ,PROP_SIZE_TYPE
+ ,PROP_SOURCE_NAME
+ ,PROP_SPLIT
+ ,PROP_STANDARD
+ ,PROP_START_AT
+ ,PROP_START_WITH
+ ,PROP_STREAM_NAME
+ ,PROP_SUB_TYPE
+ ,PROP_SUFFIX
+ ,PROP_SURROUND
+ ,PROP_SURROUND_CONTOUR
+ ,PROP_TABLE_BORDER
+ ,PROP_TABLE_BORDER_DISTANCES
+ ,PROP_TABLE_COLUMN_SEPARATORS
+ ,PROP_TABLE_REDLINE_PARAMS
+ ,PROP_TABLE_ROW_DELETE
+ ,PROP_TABLE_ROW_INSERT
+ ,PROP_TABLE_CELL_DELETE
+ ,PROP_TABLE_CELL_INSERT
+ ,PROP_TABS_RELATIVE_TO_INDENT
+ ,PROP_TAB_STOP_DISTANCE
+ ,PROP_TEXT
+ ,PROP_TEXT_COLUMNS
+ ,PROP_TEXT_RANGE
+ ,PROP_TEXT_VERTICAL_ADJUST
+ ,PROP_TITLE
+ ,PROP_TOKEN_CHAPTER_INFO
+ ,PROP_TOKEN_HYPERLINK_END
+ ,PROP_TOKEN_HYPERLINK_START
+ ,PROP_TOKEN_TEXT
+ ,PROP_TOKEN_TYPE
+ ,PROP_TOP_BORDER
+ ,PROP_TOP_BORDER_DISTANCE
+ ,PROP_TOP_MARGIN
+ ,PROP_VERTICAL_MERGE
+ ,PROP_GRID_STANDARD_MODE
+ ,PROP_VERT_ORIENT
+ ,PROP_VERT_ORIENT_POSITION
+ ,PROP_VERT_ORIENT_RELATION
+ ,PROP_WIDTH
+ ,PROP_WIDTH_TYPE
+ ,PROP_TBL_LOOK
+ ,PROP_WRITING_MODE
+ ,PROP_FRM_DIRECTION
+ ,PROP_EMBEDDED_OBJECT
+ ,PROP_PARA_CONTEXT_MARGIN
+ ,PROP_PAGE_STYLE_LAYOUT
+ ,PROP_Z_ORDER
+ ,PROP_EMBED_FONTS
+ ,PROP_EMBED_SYSTEM_FONTS
+ ,PROP_SHADOW_FORMAT
+ ,PROP_RELATIVE_WIDTH
+ ,PROP_IS_WIDTH_RELATIVE
+ ,PROP_GRAPHIC_BITMAP
+ ,PROP_GRAPHIC_SIZE
+ ,PROP_MIRROR_INDENTS
+ ,PROP_SURROUND_TEXT_WRAP_SMALL
+ ,PROP_PARA_SHADOW_FORMAT
+ ,PROP_FOOTNOTE_LINE_RELATIVE_WIDTH
+ ,PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING
+ ,PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING
+ ,PROP_TBL_HEADER
+ ,PROP_HORIZONTAL_MERGE
+ ,PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS
+ ,PROP_TAB_IN_TOC
+ ,PROP_TOC_BOOKMARK
+ ,PROP_TOC_NEW_LINE
+ ,PROP_TOC_PARAGRAPH_OUTLINE_LEVEL
+ ,PROP_SDTPR
+ ,PROP_CELL_INTEROP_GRAB_BAG
+ ,PROP_TABLE_INTEROP_GRAB_BAG
+ ,PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING
+ ,PROP_SDT_END_BEFORE
+ ,PROP_PARA_SDT_END_BEFORE
+ ,META_PROP_TABLE_LOOK
+ ,PROP_PARA_CNF_STYLE
+ ,PROP_CELL_CNF_STYLE
+ ,PROP_ROW_CNF_STYLE
+ ,PROP_CELL_HIDE_MARK
+ ,PROP_FOLLOW_TEXT_FLOW
+ ,PROP_FILL_STYLE
+ ,PROP_FILL_COLOR
+ ,PROP_SNAP_TO_GRID
+ ,PROP_GRID_SNAP_TO_CHARS
+ ,PROP_RUBY_STYLE
+ ,PROP_RUBY_TEXT
+ ,PROP_RUBY_ADJUST
+ ,PROP_RUBY_POSITION
+ ,PROP_DATABASE_NAME
+ ,PROP_COMMAND_TYPE
+ ,PROP_DATATABLE_NAME
+ ,PROP_DATACOLUMN_NAME
+ ,PROP_CHAR_TRANSPARENCE
+ ,PROP_CELL_FORMULA
+ ,PROP_CELL_FORMULA_CONVERTED
+ ,PROP_GUTTER_MARGIN
+ ,PROP_RTL_GUTTER
+ ,PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF
+ ,PROP_PARA_CONNECT_BORDERS
+ };
+
+//Returns the UNO string equivalent to eId.
+OUString getPropertyName(PropertyIds eId);
+
+bool isCharacterProperty(const PropertyIds eId);
+
+bool isParagraphProperty(const PropertyIds eId);
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx
new file mode 100644
index 000000000..1ae28759d
--- /dev/null
+++ b/writerfilter/source/dmapper/PropertyMap.cxx
@@ -0,0 +1,2219 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "PropertyMap.hxx"
+#include "TagLogger.hxx"
+#include <ooxml/resourceids.hxx>
+#include "DomainMapper_Impl.hxx"
+#include "ConversionHelper.hxx"
+#include <editeng/boxitem.hxx>
+#include <i18nutil/paper.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/style/BreakType.hpp>
+#include <com/sun/star/style/PageStyleLayout.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/HorizontalAdjust.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XRedline.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/text/TextGridMode.hpp>
+#include <com/sun/star/text/XTextCopy.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <tools/diagnose_ex.h>
+#include "PropertyMapHelper.hxx"
+#include <o3tl/sorted_vector.hxx>
+#include <o3tl/unit_conversion.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper {
+
+uno::Sequence< beans::PropertyValue > PropertyMap::GetPropertyValues( bool bCharGrabBag )
+{
+ using comphelper::makePropertyValue;
+
+ if ( !m_aValues.empty() || m_vMap.empty() )
+ return comphelper::containerToSequence( m_aValues );
+
+ size_t nCharGrabBag = 0;
+ size_t nParaGrabBag = 0;
+ size_t nCellGrabBag = 0;
+ size_t nRowGrabBag = 0;
+
+ const PropValue* pParaStyleProp = nullptr;
+ const PropValue* pCharStyleProp = nullptr;
+ const PropValue* pNumRuleProp = nullptr;
+
+ m_aValues.reserve( m_vMap.size() );
+ for ( const auto& rPropPair : m_vMap )
+ {
+ if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
+ nCharGrabBag++;
+ else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
+ nParaGrabBag++;
+ else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
+ nCellGrabBag++;
+ else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
+ {
+ uno::Sequence< beans::PropertyValue > aSeq;
+ rPropPair.second.getValue() >>= aSeq;
+ nCellGrabBag += aSeq.getLength();
+ }
+ else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
+ nRowGrabBag++;
+
+ if ( rPropPair.first == PROP_PARA_STYLE_NAME ) pParaStyleProp = &rPropPair.second;
+ if ( rPropPair.first == PROP_CHAR_STYLE_NAME ) pCharStyleProp = &rPropPair.second;
+ if ( rPropPair.first == PROP_NUMBERING_RULES ) pNumRuleProp = &rPropPair.second;
+ }
+
+ // Style names have to be the first elements within the property sequence
+ // otherwise they will overwrite 'hard' attributes
+ if ( pParaStyleProp != nullptr )
+ m_aValues.push_back( makePropertyValue( getPropertyName( PROP_PARA_STYLE_NAME ), pParaStyleProp->getValue() ) );
+ if ( pCharStyleProp != nullptr )
+ m_aValues.push_back( makePropertyValue( getPropertyName( PROP_CHAR_STYLE_NAME ), pCharStyleProp->getValue() ) );
+ if ( pNumRuleProp != nullptr )
+ m_aValues.push_back( makePropertyValue(getPropertyName( PROP_NUMBERING_RULES ), pNumRuleProp->getValue() ) );
+
+ // If there are any grab bag properties, we need one slot for them.
+ uno::Sequence< beans::PropertyValue > aCharGrabBagValues( nCharGrabBag );
+ uno::Sequence< beans::PropertyValue > aParaGrabBagValues( nParaGrabBag );
+ uno::Sequence< beans::PropertyValue > aCellGrabBagValues( nCellGrabBag );
+ uno::Sequence< beans::PropertyValue > aRowGrabBagValues ( nRowGrabBag );
+ beans::PropertyValue* pCharGrabBagValues = aCharGrabBagValues.getArray();
+ beans::PropertyValue* pParaGrabBagValues = aParaGrabBagValues.getArray();
+ beans::PropertyValue* pCellGrabBagValues = aCellGrabBagValues.getArray();
+ beans::PropertyValue* pRowGrabBagValues = aRowGrabBagValues.getArray();
+ // Record index for the next property to be added in each grab bag.
+ sal_Int32 nRowGrabBagValue = 0;
+ sal_Int32 nCellGrabBagValue = 0;
+ sal_Int32 nParaGrabBagValue = 0;
+ sal_Int32 nCharGrabBagValue = 0;
+
+ for ( const auto& rPropPair : m_vMap )
+ {
+ if ( rPropPair.first != PROP_PARA_STYLE_NAME &&
+ rPropPair.first != PROP_CHAR_STYLE_NAME &&
+ rPropPair.first != PROP_NUMBERING_RULES )
+ {
+ if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
+ {
+ if ( bCharGrabBag )
+ {
+ pCharGrabBagValues[nCharGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pCharGrabBagValues[nCharGrabBagValue].Value = rPropPair.second.getValue();
+ ++nCharGrabBagValue;
+ }
+ }
+ else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
+ {
+ pParaGrabBagValues[nParaGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pParaGrabBagValues[nParaGrabBagValue].Value = rPropPair.second.getValue();
+ ++nParaGrabBagValue;
+ }
+ else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
+ {
+ pCellGrabBagValues[nCellGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pCellGrabBagValues[nCellGrabBagValue].Value = rPropPair.second.getValue();
+ ++nCellGrabBagValue;
+ }
+ else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
+ {
+ pRowGrabBagValues[nRowGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pRowGrabBagValues[nRowGrabBagValue].Value = rPropPair.second.getValue();
+ ++nRowGrabBagValue;
+ }
+ else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
+ {
+ uno::Sequence< beans::PropertyValue > aSeq;
+ rPropPair.second.getValue() >>= aSeq;
+ std::copy(std::cbegin(aSeq), std::cend(aSeq), pCellGrabBagValues + nCellGrabBagValue);
+ nCellGrabBagValue += aSeq.getLength();
+ }
+ else
+ {
+ m_aValues.push_back( makePropertyValue( getPropertyName( rPropPair.first ), rPropPair.second.getValue() ) );
+ }
+ }
+ }
+
+ if ( nCharGrabBag && bCharGrabBag )
+ m_aValues.push_back( makePropertyValue( "CharInteropGrabBag", uno::Any( aCharGrabBagValues ) ) );
+
+ if ( nParaGrabBag )
+ m_aValues.push_back( makePropertyValue( "ParaInteropGrabBag", uno::Any( aParaGrabBagValues ) ) );
+
+ if ( nCellGrabBag )
+ m_aValues.push_back( makePropertyValue( "CellInteropGrabBag", uno::Any( aCellGrabBagValues ) ) );
+
+ if ( nRowGrabBag )
+ m_aValues.push_back( makePropertyValue( "RowInteropGrabBag", uno::Any( aRowGrabBagValues ) ) );
+
+ return comphelper::containerToSequence( m_aValues );
+}
+
+std::vector< PropertyIds > PropertyMap::GetPropertyIds()
+{
+ std::vector< PropertyIds > aRet;
+ for ( const auto& rPropPair : m_vMap )
+ aRet.push_back( rPropPair.first );
+ return aRet;
+}
+
+#ifdef DBG_UTIL
+static void lcl_AnyToTag( const uno::Any& rAny )
+{
+ try {
+ sal_Int32 aInt = 0;
+ if ( rAny >>= aInt )
+ {
+ TagLogger::getInstance().attribute( "value", rAny );
+ }
+ else
+ {
+ TagLogger::getInstance().attribute( "unsignedValue", 0 );
+ }
+
+ sal_uInt32 auInt = 0;
+ rAny >>= auInt;
+ TagLogger::getInstance().attribute( "unsignedValue", auInt );
+
+ float aFloat = 0.0f;
+ if ( rAny >>= aFloat )
+ {
+ TagLogger::getInstance().attribute( "floatValue", rAny );
+ }
+ else
+ {
+ TagLogger::getInstance().attribute( "unsignedValue", 0 );
+ }
+
+ OUString aStr;
+ rAny >>= aStr;
+ TagLogger::getInstance().attribute( "stringValue", aStr );
+ }
+ catch ( ... )
+ {
+ }
+}
+#endif
+
+void PropertyMap::Insert( PropertyIds eId, const uno::Any& rAny, bool bOverwrite, GrabBagType i_GrabBagType, bool bDocDefault )
+{
+#ifdef DBG_UTIL
+ const OUString& rInsert = getPropertyName(eId);
+
+ TagLogger::getInstance().startElement("propertyMap.insert");
+ TagLogger::getInstance().attribute("name", rInsert);
+ lcl_AnyToTag(rAny);
+ TagLogger::getInstance().endElement();
+#endif
+
+ if ( !bOverwrite )
+ m_vMap.insert(std::make_pair(eId, PropValue(rAny, i_GrabBagType, bDocDefault)));
+ else
+ m_vMap[eId] = PropValue(rAny, i_GrabBagType);
+
+ Invalidate();
+}
+
+void PropertyMap::Erase( PropertyIds eId )
+{
+ // Safe call to erase, it throws no exceptions, even if eId is not in m_vMap
+ m_vMap.erase(eId);
+
+ Invalidate();
+}
+
+std::optional< PropertyMap::Property > PropertyMap::getProperty( PropertyIds eId ) const
+{
+ std::map< PropertyIds, PropValue >::const_iterator aIter = m_vMap.find( eId );
+ if ( aIter == m_vMap.end() )
+ return std::optional<Property>();
+ else
+ return std::make_pair( eId, aIter->second.getValue() );
+}
+
+bool PropertyMap::isSet( PropertyIds eId) const
+{
+ return m_vMap.find( eId ) != m_vMap.end();
+}
+
+bool PropertyMap::isDocDefault( PropertyIds eId ) const
+{
+ std::map< PropertyIds, PropValue >::const_iterator aIter = m_vMap.find( eId );
+ if ( aIter == m_vMap.end() )
+ return false;
+ else
+ return aIter->second.getIsDocDefault();
+}
+
+#ifdef DBG_UTIL
+void PropertyMap::dumpXml() const
+{
+ TagLogger::getInstance().startElement( "PropertyMap" );
+
+ for ( const auto& rPropPair : m_vMap )
+ {
+ TagLogger::getInstance().startElement( "property" );
+
+ TagLogger::getInstance().attribute( "name", getPropertyName( rPropPair.first ) );
+
+ switch ( rPropPair.first )
+ {
+ case PROP_TABLE_COLUMN_SEPARATORS:
+ lcl_DumpTableColumnSeparators( rPropPair.second.getValue() );
+ break;
+ default:
+ {
+ try
+ {
+ sal_Int32 aInt = 0;
+ rPropPair.second.getValue() >>= aInt;
+ TagLogger::getInstance().attribute( "value", aInt );
+
+ sal_uInt32 auInt = 0;
+ rPropPair.second.getValue() >>= auInt;
+ TagLogger::getInstance().attribute( "unsignedValue", auInt );
+
+ float aFloat = 0.0;
+ rPropPair.second.getValue() >>= aFloat;
+ TagLogger::getInstance().attribute( "floatValue", aFloat );
+
+ rPropPair.second.getValue() >>= auInt;
+ TagLogger::getInstance().attribute( "stringValue", std::u16string_view() );
+ }
+ catch ( ... )
+ {
+ }
+ }
+ break;
+ }
+
+ TagLogger::getInstance().endElement();
+ }
+
+ TagLogger::getInstance().endElement();
+}
+#endif
+
+void PropertyMap::InsertProps( const PropertyMapPtr& rMap, const bool bOverwrite )
+{
+ if ( !rMap )
+ return;
+
+ for ( const auto& rPropPair : rMap->m_vMap )
+ {
+ if ( bOverwrite || !m_vMap.count(rPropPair.first) )
+ {
+ if ( !bOverwrite && !rPropPair.second.getIsDocDefault() )
+ m_vMap.insert(std::make_pair(rPropPair.first, PropValue(rPropPair.second.getValue(), rPropPair.second.getGrabBagType(), true)));
+ else
+ m_vMap[rPropPair.first] = rPropPair.second;
+ }
+ }
+
+ insertTableProperties( rMap.get(), bOverwrite );
+
+ Invalidate();
+}
+
+void PropertyMap::insertTableProperties( const PropertyMap*, const bool )
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element( "PropertyMap.insertTableProperties" );
+#endif
+}
+
+void PropertyMap::printProperties()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement( "properties" );
+
+ for ( const auto& rPropPair : m_vMap )
+ {
+ SAL_INFO( "writerfilter", getPropertyName( rPropPair.first ) );
+
+ table::BorderLine2 aLine;
+ sal_Int32 nColor;
+ if ( rPropPair.second.getValue() >>= aLine )
+ {
+ TagLogger::getInstance().startElement( "borderline" );
+ TagLogger::getInstance().attribute( "color", aLine.Color );
+ TagLogger::getInstance().attribute( "inner", aLine.InnerLineWidth );
+ TagLogger::getInstance().attribute( "outer", aLine.OuterLineWidth );
+ TagLogger::getInstance().endElement();
+ }
+ else if ( rPropPair.second.getValue() >>= nColor )
+ {
+ TagLogger::getInstance().startElement( "color" );
+ TagLogger::getInstance().attribute( "number", nColor );
+ TagLogger::getInstance().endElement();
+ }
+ }
+
+ TagLogger::getInstance().endElement();
+#else
+ (void) this; // avoid loplugin:staticmethods
+#endif
+}
+
+SectionPropertyMap::SectionPropertyMap( bool bIsFirstSection )
+ : m_bIsFirstSection( bIsFirstSection )
+ , m_eBorderApply( BorderApply::ToAllInSection )
+ , m_eBorderOffsetFrom( BorderOffsetFrom::Text )
+ , m_bTitlePage( false )
+ , m_nColumnCount( 0 )
+ , m_nColumnDistance( 1249 )
+ , m_bSeparatorLineIsOn( false )
+ , m_bEvenlySpaced( false )
+ , m_nPageNumber( -1 )
+ , m_nPageNumberType( -1 )
+ , m_nBreakType( -1 )
+ , m_nLeftMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nRightMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nGutterMargin(0)
+ , m_nTopMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nBottomMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nHeaderTop( o3tl::convert(0.5, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nHeaderBottom( o3tl::convert(0.5, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nGridType( 0 )
+ , m_nGridLinePitch( 1 )
+ , m_nDxtCharSpace( 0 )
+ , m_bGridSnapToChars( true )
+ , m_nLnnMod( 0 )
+ , m_nLnc(NS_ooxml::LN_Value_ST_LineNumberRestart_newPage)
+ , m_ndxaLnn( 0 )
+ , m_nLnnMin( 0 )
+ , m_bDynamicHeightTop( true )
+ , m_bDynamicHeightBottom( true )
+ , m_bDefaultHeaderLinkToPrevious( true )
+ , m_bEvenPageHeaderLinkToPrevious( true )
+ , m_bFirstPageHeaderLinkToPrevious( true )
+ , m_bDefaultFooterLinkToPrevious( true )
+ , m_bEvenPageFooterLinkToPrevious( true )
+ , m_bFirstPageFooterLinkToPrevious( true )
+{
+#ifdef DBG_UTIL
+ static sal_Int32 nNumber = 0;
+ m_nDebugSectionNumber = nNumber++;
+#endif
+
+ for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
+ {
+ m_nBorderDistances[nBorder] = -1;
+ m_bBorderShadows[nBorder] = false;
+ }
+ // todo: set defaults in ApplyPropertiesToPageStyles
+ // initialize defaults
+ PaperInfo aLetter( PAPER_LETTER );
+ // page height, 1/100mm
+ Insert( PROP_HEIGHT, uno::Any( static_cast<sal_Int32>(aLetter.getHeight()) ) );
+ // page width, 1/100mm
+ Insert( PROP_WIDTH, uno::Any( static_cast<sal_Int32>(aLetter.getWidth()) ) );
+ // page left margin, 1/100 mm
+ Insert( PROP_LEFT_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page right margin, 1/100 mm
+ Insert( PROP_RIGHT_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page top margin, 1/100 mm
+ Insert( PROP_TOP_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page bottom margin, 1/100 mm
+ Insert( PROP_BOTTOM_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page style layout
+ Insert( PROP_PAGE_STYLE_LAYOUT, uno::Any( style::PageStyleLayout_ALL ) );
+ uno::Any aFalse( uno::Any( false ) );
+ Insert( PROP_GRID_DISPLAY, aFalse );
+ Insert( PROP_GRID_PRINT, aFalse );
+ Insert( PROP_GRID_MODE, uno::Any( text::TextGridMode::NONE ) );
+
+ if ( m_bIsFirstSection )
+ {
+ m_sFirstPageStyleName = getPropertyName( PROP_FIRST_PAGE );
+ m_sFollowPageStyleName = getPropertyName( PROP_STANDARD );
+ }
+}
+
+uno::Reference< beans::XPropertySet > SectionPropertyMap::GetPageStyle( DomainMapper_Impl& rDM_Impl,
+ bool bFirst )
+{
+ const uno::Reference< container::XNameContainer >& xPageStyles = rDM_Impl.GetPageStyles();
+ const uno::Reference < lang::XMultiServiceFactory >& xTextFactory = rDM_Impl.GetTextFactory();
+ uno::Reference< beans::XPropertySet > xRet;
+ try
+ {
+ if ( bFirst )
+ {
+ if ( m_sFirstPageStyleName.isEmpty() && xPageStyles.is() )
+ {
+ assert( !rDM_Impl.IsInFootOrEndnote() && "Don't create useless page styles" );
+ m_sFirstPageStyleName = rDM_Impl.GetUnusedPageStyleName();
+ m_aFirstPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ),
+ uno::UNO_QUERY );
+
+ // Call insertByName() before GetPageStyle(), otherwise the
+ // first and the follow page style will have the same name, and
+ // insertByName() will fail.
+ if ( xPageStyles.is() )
+ xPageStyles->insertByName( m_sFirstPageStyleName, uno::Any( m_aFirstPageStyle ) );
+
+ // Ensure that m_aFollowPageStyle has been created
+ GetPageStyle( rDM_Impl, false );
+ // Chain m_aFollowPageStyle to be after m_aFirstPageStyle
+ m_aFirstPageStyle->setPropertyValue( "FollowStyle",
+ uno::Any( m_sFollowPageStyleName ) );
+ }
+ else if ( !m_aFirstPageStyle.is() && xPageStyles.is() )
+ {
+ xPageStyles->getByName( m_sFirstPageStyleName ) >>= m_aFirstPageStyle;
+ }
+ xRet = m_aFirstPageStyle;
+ }
+ else
+ {
+ if ( m_sFollowPageStyleName.isEmpty() && xPageStyles.is() )
+ {
+ assert( !rDM_Impl.IsInFootOrEndnote() && "Don't create useless page styles" );
+ m_sFollowPageStyleName = rDM_Impl.GetUnusedPageStyleName();
+ m_aFollowPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ),
+ uno::UNO_QUERY );
+ xPageStyles->insertByName( m_sFollowPageStyleName, uno::Any( m_aFollowPageStyle ) );
+ }
+ else if ( !m_aFollowPageStyle.is() && xPageStyles.is() )
+ {
+ xPageStyles->getByName( m_sFollowPageStyleName ) >>= m_aFollowPageStyle;
+ }
+ xRet = m_aFollowPageStyle;
+ }
+
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION( "writerfilter" );
+ }
+
+ return xRet;
+}
+
+void SectionPropertyMap::SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const table::BorderLine2& rBorderLine, bool bShadow )
+{
+ m_oBorderLines[ePos] = rBorderLine;
+ m_nBorderDistances[ePos] = nLineDistance;
+ m_bBorderShadows[ePos] = bShadow;
+}
+
+void SectionPropertyMap::ApplyBorderToPageStyles( DomainMapper_Impl& rDM_Impl,
+ BorderApply eBorderApply, BorderOffsetFrom eOffsetFrom )
+{
+ /*
+ page border applies to:
+ nIntValue & 0x07 ->
+ 0 all pages in this section
+ 1 first page in this section
+ 2 all pages in this section but first
+ 3 whole document (all sections)
+ nIntValue & 0x18 -> page border depth 0 - in front 1- in back
+ nIntValue & 0xe0 ->
+ page border offset from:
+ 0 offset from text
+ 1 offset from edge of page
+ */
+ uno::Reference< beans::XPropertySet > xFirst;
+ uno::Reference< beans::XPropertySet > xSecond;
+ // todo: negative spacing (from ww8par6.cxx)
+ switch ( eBorderApply )
+ {
+ case BorderApply::ToAllInSection: // all styles
+ if ( !m_sFollowPageStyleName.isEmpty() )
+ xFirst = GetPageStyle( rDM_Impl, false );
+ if ( !m_sFirstPageStyleName.isEmpty() )
+ xSecond = GetPageStyle( rDM_Impl, true );
+ break;
+ case BorderApply::ToFirstPageInSection: // first page
+ if ( !m_sFirstPageStyleName.isEmpty() )
+ xFirst = GetPageStyle( rDM_Impl, true );
+ break;
+ case BorderApply::ToAllButFirstInSection: // left and right
+ if ( !m_sFollowPageStyleName.isEmpty() )
+ xFirst = GetPageStyle( rDM_Impl, false );
+ break;
+ default:
+ return;
+ }
+
+ // has to be sorted like enum BorderPosition: l-r-t-b
+ const PropertyIds aBorderIds[4] =
+ {
+ PROP_LEFT_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_TOP_BORDER,
+ PROP_BOTTOM_BORDER
+ };
+
+ const PropertyIds aBorderDistanceIds[4] =
+ {
+ PROP_LEFT_BORDER_DISTANCE,
+ PROP_RIGHT_BORDER_DISTANCE,
+ PROP_TOP_BORDER_DISTANCE,
+ PROP_BOTTOM_BORDER_DISTANCE
+ };
+
+ const PropertyIds aMarginIds[4] =
+ {
+ PROP_LEFT_MARGIN,
+ PROP_RIGHT_MARGIN,
+ PROP_TOP_MARGIN,
+ PROP_BOTTOM_MARGIN
+ };
+
+ for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
+ {
+ if ( m_oBorderLines[nBorder] )
+ {
+ const OUString sBorderName = getPropertyName( aBorderIds[nBorder] );
+ if ( xFirst.is() )
+ xFirst->setPropertyValue( sBorderName, uno::Any( *m_oBorderLines[nBorder] ) );
+ if ( xSecond.is() )
+ xSecond->setPropertyValue( sBorderName, uno::Any( *m_oBorderLines[nBorder] ) );
+ }
+ if ( m_nBorderDistances[nBorder] >= 0 )
+ {
+ sal_uInt32 nLineWidth = 0;
+ if ( m_oBorderLines[nBorder] )
+ nLineWidth = m_oBorderLines[nBorder]->LineWidth;
+ if ( xFirst.is() )
+ SetBorderDistance( xFirst, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
+ m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth, rDM_Impl );
+ if ( xSecond.is() )
+ SetBorderDistance( xSecond, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
+ m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth, rDM_Impl );
+ }
+ }
+
+ if ( m_bBorderShadows[BORDER_RIGHT] )
+ {
+ table::ShadowFormat aFormat = getShadowFromBorder( *m_oBorderLines[BORDER_RIGHT] );
+ if ( xFirst.is() )
+ xFirst->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::Any( aFormat ) );
+ if ( xSecond.is() )
+ xSecond->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::Any( aFormat ) );
+ }
+}
+
+table::ShadowFormat PropertyMap::getShadowFromBorder( const table::BorderLine2& rBorder )
+{
+ // In Word UI, shadow is a boolean property, in OOXML, it's a boolean
+ // property of each 4 border type, finally in Writer the border is a
+ // property of the page style, with shadow location, distance and
+ // color. See SwWW8ImplReader::SetShadow().
+ table::ShadowFormat aFormat;
+ aFormat.Color = sal_Int32(COL_BLACK);
+ aFormat.Location = table::ShadowLocation_BOTTOM_RIGHT;
+ aFormat.ShadowWidth = rBorder.LineWidth;
+ return aFormat;
+}
+
+void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XPropertySet >& xStyle,
+ PropertyIds eMarginId,
+ PropertyIds eDistId,
+ sal_Int32 nDistance,
+ BorderOffsetFrom eOffsetFrom,
+ sal_uInt32 nLineWidth,
+ DomainMapper_Impl& rDM_Impl )
+{
+ if (!xStyle.is())
+ return;
+ const OUString sMarginName = getPropertyName( eMarginId );
+ const OUString sBorderDistanceName = getPropertyName( eDistId );
+ uno::Any aMargin = xStyle->getPropertyValue( sMarginName );
+ sal_Int32 nMargin = 0;
+ aMargin >>= nMargin;
+ editeng::BorderDistanceFromWord(eOffsetFrom == BorderOffsetFrom::Edge, nMargin, nDistance,
+ nLineWidth);
+
+ if (eOffsetFrom == BorderOffsetFrom::Edge)
+ {
+ uno::Any aGutterMargin = xStyle->getPropertyValue( "GutterMargin" );
+ sal_Int32 nGutterMargin = 0;
+ aGutterMargin >>= nGutterMargin;
+
+ if (eMarginId == PROP_LEFT_MARGIN && !rDM_Impl.GetSettingsTable()->GetGutterAtTop())
+ {
+ nMargin -= nGutterMargin;
+ nDistance += nGutterMargin;
+ }
+
+ if (eMarginId == PROP_TOP_MARGIN && rDM_Impl.GetSettingsTable()->GetGutterAtTop())
+ {
+ nMargin -= nGutterMargin;
+ nDistance += nGutterMargin;
+ }
+ }
+
+ // Change the margins with the border distance
+ uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
+ uno::Sequence<OUString> aProperties { sMarginName, sBorderDistanceName };
+ uno::Sequence<uno::Any> aValues { uno::Any( nMargin ), uno::Any( nDistance ) };
+ xMultiSet->setPropertyValues( aProperties, aValues );
+}
+
+void SectionPropertyMap::DontBalanceTextColumns()
+{
+ try
+ {
+ if ( m_xColumnContainer.is() )
+ m_xColumnContainer->setPropertyValue( "DontBalanceTextColumns", uno::Any( true ) );
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::DontBalanceTextColumns" );
+ }
+}
+
+void SectionPropertyMap::ApplySectionProperties( const uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& /*rDM_Impl*/ )
+{
+ try
+ {
+ if ( xSection.is() )
+ {
+ std::optional< PropertyMap::Property > pProp = getProperty( PROP_WRITING_MODE );
+ if ( pProp )
+ xSection->setPropertyValue( "WritingMode", pProp->second );
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception in SectionPropertyMap::ApplySectionProperties");
+ }
+}
+
+void SectionPropertyMap::ApplyProtectionProperties( uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& rDM_Impl )
+{
+ try
+ {
+ // Word implements section protection differently than LO.
+ // PROP_IS_PROTECTED only applies if global setting GetProtectForm is enabled.
+ bool bIsProtected = rDM_Impl.GetSettingsTable()->GetProtectForm();
+ if ( bIsProtected )
+ {
+ // If form protection is enabled then section protection is enabled, unless explicitly disabled
+ if ( isSet(PROP_IS_PROTECTED) )
+ getProperty(PROP_IS_PROTECTED)->second >>= bIsProtected;
+ if ( !xSection.is() )
+ xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
+ if ( xSection.is() )
+ xSection->setPropertyValue( getPropertyName(PROP_IS_PROTECTED), uno::Any(bIsProtected) );
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "ApplyProtectionProperties failed setting PROP_IS_PROTECTED");
+ }
+}
+
+uno::Reference< text::XTextColumns > SectionPropertyMap::ApplyColumnProperties( const uno::Reference< beans::XPropertySet >& xColumnContainer,
+ DomainMapper_Impl& rDM_Impl )
+{
+ uno::Reference< text::XTextColumns > xColumns;
+ assert( m_nColumnCount > 1 && "ApplyColumnProperties called without any columns" );
+ try
+ {
+ const OUString sTextColumns = getPropertyName( PROP_TEXT_COLUMNS );
+ if ( xColumnContainer.is() )
+ xColumnContainer->getPropertyValue( sTextColumns ) >>= xColumns;
+ uno::Reference< beans::XPropertySet > xColumnPropSet( xColumns, uno::UNO_QUERY_THROW );
+ if ( !m_bEvenlySpaced &&
+ ( sal_Int32(m_aColWidth.size()) == m_nColumnCount ) &&
+ ( (sal_Int32(m_aColDistance.size()) == m_nColumnCount - 1) || (sal_Int32(m_aColDistance.size()) == m_nColumnCount) ) )
+ {
+ // the column width in word is an absolute value, in OOo it's relative
+ // the distances are both absolute
+ sal_Int32 nColSum = 0;
+ for ( sal_Int32 nCol = 0; nCol < m_nColumnCount; ++nCol )
+ {
+ nColSum += m_aColWidth[nCol];
+ if ( nCol )
+ nColSum += m_aColDistance[nCol - 1];
+ }
+
+ sal_Int32 nRefValue = xColumns->getReferenceValue();
+ double fRel = nColSum ? double( nRefValue ) / double( nColSum ) : 0.0;
+ uno::Sequence< text::TextColumn > aColumns( m_nColumnCount );
+ text::TextColumn* pColumn = aColumns.getArray();
+
+ nColSum = 0;
+ for ( sal_Int32 nCol = 0; nCol < m_nColumnCount; ++nCol )
+ {
+ const double fLeft = nCol ? m_aColDistance[nCol - 1] / 2 : 0;
+ pColumn[nCol].LeftMargin = fLeft;
+ const double fRight = (nCol == m_nColumnCount - 1) ? 0 : m_aColDistance[nCol] / 2;
+ pColumn[nCol].RightMargin = fRight;
+ const double fWidth = m_aColWidth[nCol];
+ pColumn[nCol].Width = (fWidth + fLeft + fRight) * fRel;
+ nColSum += pColumn[nCol].Width;
+ }
+ if ( nColSum != nRefValue )
+ pColumn[m_nColumnCount - 1].Width += (nRefValue - nColSum);
+ assert( pColumn[m_nColumnCount - 1].Width >= 0 );
+
+ xColumns->setColumns( aColumns );
+ }
+ else
+ {
+ xColumns->setColumnCount( m_nColumnCount );
+ xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::Any( m_nColumnDistance ) );
+ }
+
+ if ( m_bSeparatorLineIsOn )
+ {
+ xColumnPropSet->setPropertyValue( "SeparatorLineIsOn", uno::Any( true ) );
+ xColumnPropSet->setPropertyValue( "SeparatorLineVerticalAlignment", uno::Any( style::VerticalAlignment_TOP ) );
+ xColumnPropSet->setPropertyValue( "SeparatorLineRelativeHeight", uno::Any( static_cast<sal_Int8>(100) ) );
+ xColumnPropSet->setPropertyValue( "SeparatorLineColor", uno::Any( static_cast<sal_Int32>(COL_BLACK) ) );
+ // 1 twip -> 2 mm100.
+ xColumnPropSet->setPropertyValue( "SeparatorLineWidth", uno::Any( static_cast<sal_Int32>(2) ) );
+ }
+ xColumnContainer->setPropertyValue( sTextColumns, uno::Any( xColumns ) );
+ // Set the columns to be unbalanced if that compatibility option is set or this is the last section.
+ m_xColumnContainer = xColumnContainer;
+ if ( rDM_Impl.GetSettingsTable()->GetNoColumnBalance() || rDM_Impl.GetIsLastSectionGroup() )
+ DontBalanceTextColumns();
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::ApplyColumnProperties" );
+ }
+ return xColumns;
+}
+
+bool SectionPropertyMap::HasHeader( bool bFirstPage ) const
+{
+ bool bRet = false;
+ if ( (bFirstPage && m_aFirstPageStyle.is()) || (!bFirstPage && m_aFollowPageStyle.is()) )
+ {
+ if ( bFirstPage )
+ m_aFirstPageStyle->getPropertyValue(
+ getPropertyName( PROP_HEADER_IS_ON ) ) >>= bRet;
+ else
+ m_aFollowPageStyle->getPropertyValue(
+ getPropertyName( PROP_HEADER_IS_ON ) ) >>= bRet;
+ }
+ return bRet;
+}
+
+bool SectionPropertyMap::HasFooter( bool bFirstPage ) const
+{
+ bool bRet = false;
+ if ( (bFirstPage && m_aFirstPageStyle.is()) || (!bFirstPage && m_aFollowPageStyle.is()) )
+ {
+ if ( bFirstPage )
+ m_aFirstPageStyle->getPropertyValue( getPropertyName( PROP_FOOTER_IS_ON ) ) >>= bRet;
+ else
+ m_aFollowPageStyle->getPropertyValue( getPropertyName( PROP_FOOTER_IS_ON ) ) >>= bRet;
+ }
+ return bRet;
+}
+
+#define MIN_HEAD_FOOT_HEIGHT 100 // minimum header/footer height
+
+void SectionPropertyMap::CopyHeaderFooterTextProperty( const uno::Reference< beans::XPropertySet >& xPrevStyle,
+ const uno::Reference< beans::XPropertySet >& xStyle,
+ PropertyIds ePropId )
+{
+ try {
+ OUString sName = getPropertyName( ePropId );
+
+ SAL_INFO( "writerfilter", "Copying " << sName );
+ uno::Reference< text::XTextCopy > xTxt;
+ if ( xStyle.is() )
+ xTxt.set( xStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
+
+ uno::Reference< text::XTextCopy > xPrevTxt;
+ if ( xPrevStyle.is() )
+ xPrevTxt.set( xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
+
+ xTxt->copyText( xPrevTxt );
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_INFO_EXCEPTION( "writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooterTextProperty( )" );
+ }
+}
+
+// Copy headers and footers from the previous page style.
+void SectionPropertyMap::CopyHeaderFooter( const DomainMapper_Impl& rDM_Impl,
+ const uno::Reference< beans::XPropertySet >& xPrevStyle,
+ const uno::Reference< beans::XPropertySet >& xStyle,
+ bool bOmitRightHeader,
+ bool bOmitLeftHeader,
+ bool bOmitRightFooter,
+ bool bOmitLeftFooter )
+{
+ if (!rDM_Impl.IsNewDoc())
+ { // see also DomainMapper_Impl::PushPageHeaderFooter()
+ return; // tdf#139737 SwUndoInserts cannot deal with new header/footer
+ }
+ bool bHasPrevHeader = false;
+ bool bHeaderIsShared = true;
+ OUString sHeaderIsOn = getPropertyName( PROP_HEADER_IS_ON );
+ OUString sHeaderIsShared = getPropertyName( PROP_HEADER_IS_SHARED );
+ if ( xPrevStyle.is() )
+ {
+ xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader;
+ xPrevStyle->getPropertyValue( sHeaderIsShared ) >>= bHeaderIsShared;
+ }
+
+ if ( bHasPrevHeader )
+ {
+ uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
+ uno::Sequence<OUString> aProperties { sHeaderIsOn, sHeaderIsShared };
+ uno::Sequence<uno::Any> aValues { uno::Any( true ), uno::Any( bHeaderIsShared ) };
+ xMultiSet->setPropertyValues( aProperties, aValues );
+ if ( !bOmitRightHeader )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_HEADER_TEXT );
+ }
+ if ( !bHeaderIsShared && !bOmitLeftHeader )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_HEADER_TEXT_LEFT );
+ }
+ }
+
+ bool bHasPrevFooter = false;
+ bool bFooterIsShared = true;
+ OUString sFooterIsOn = getPropertyName( PROP_FOOTER_IS_ON );
+ OUString sFooterIsShared = getPropertyName( PROP_FOOTER_IS_SHARED );
+ if ( xPrevStyle.is() )
+ {
+ xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter;
+ xPrevStyle->getPropertyValue( sFooterIsShared ) >>= bFooterIsShared;
+ }
+
+ if ( !bHasPrevFooter )
+ return;
+
+ uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
+ uno::Sequence<OUString> aProperties { sFooterIsOn, sFooterIsShared };
+ uno::Sequence<uno::Any> aValues { uno::Any( true ), uno::Any( bFooterIsShared ) };
+ xMultiSet->setPropertyValues( aProperties, aValues );
+ if ( !bOmitRightFooter )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_FOOTER_TEXT );
+ }
+ if ( !bFooterIsShared && !bOmitLeftFooter )
+ {
+ CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
+ PROP_FOOTER_TEXT_LEFT );
+ }
+}
+
+// Copy header and footer content from the previous docx section as needed.
+//
+// Any headers and footers which were not defined in this docx section
+// should be "linked" with the corresponding header or footer from the
+// previous section. LO does not support linking of header/footer content
+// across page styles so we just copy the content from the previous section.
+void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
+{
+ SAL_INFO( "writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()" );
+ SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
+ if ( pLastContext )
+ {
+ const bool bUseEvenPages = rDM_Impl.GetSettingsTable()->GetEvenAndOddHeaders();
+ uno::Reference< beans::XPropertySet > xPrevStyle = pLastContext->GetPageStyle( rDM_Impl,
+ bFirstPage );
+ uno::Reference< beans::XPropertySet > xStyle = GetPageStyle( rDM_Impl,
+ bFirstPage );
+
+ if ( bFirstPage )
+ {
+ CopyHeaderFooter(rDM_Impl, xPrevStyle, xStyle,
+ !m_bFirstPageHeaderLinkToPrevious, true,
+ !m_bFirstPageFooterLinkToPrevious, true );
+ }
+ else
+ {
+ CopyHeaderFooter(rDM_Impl, xPrevStyle, xStyle,
+ !m_bDefaultHeaderLinkToPrevious,
+ !(m_bEvenPageHeaderLinkToPrevious && bUseEvenPages),
+ !m_bDefaultFooterLinkToPrevious,
+ !(m_bEvenPageFooterLinkToPrevious && bUseEvenPages));
+ }
+ }
+ SAL_INFO( "writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()" );
+}
+
+void SectionPropertyMap::PrepareHeaderFooterProperties( bool bFirstPage )
+{
+ bool bCopyFirstToFollow = bFirstPage && m_bTitlePage && m_aFollowPageStyle.is();
+
+ sal_Int32 nTopMargin = m_nTopMargin;
+ sal_Int32 nHeaderHeight = m_nHeaderTop;
+ if ( HasHeader( bFirstPage ) )
+ {
+ nTopMargin = m_nHeaderTop;
+ nHeaderHeight = m_nTopMargin - m_nHeaderTop;
+
+ // minimum header height 1mm
+ if ( nHeaderHeight < MIN_HEAD_FOOT_HEIGHT )
+ nHeaderHeight = MIN_HEAD_FOOT_HEIGHT;
+ }
+
+ Insert(PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::Any(m_bDynamicHeightTop));
+ Insert(PROP_HEADER_DYNAMIC_SPACING, uno::Any(m_bDynamicHeightTop));
+ Insert(PROP_HEADER_BODY_DISTANCE, uno::Any(nHeaderHeight - MIN_HEAD_FOOT_HEIGHT));
+ Insert(PROP_HEADER_HEIGHT, uno::Any(nHeaderHeight));
+ // looks like PROP_HEADER_HEIGHT = height of the header + space between the header, and the body
+
+ if ( m_bDynamicHeightTop ) //fixed height header -> see WW8Par6.hxx
+ {
+ if (bCopyFirstToFollow && HasHeader(/*bFirstPage=*/true))
+ {
+ m_aFollowPageStyle->setPropertyValue("HeaderDynamicSpacing",
+ getProperty(PROP_HEADER_DYNAMIC_SPACING)->second);
+ m_aFollowPageStyle->setPropertyValue("HeaderHeight",
+ getProperty(PROP_HEADER_HEIGHT)->second);
+ }
+ }
+
+ sal_Int32 nBottomMargin = m_nBottomMargin;
+ sal_Int32 nFooterHeight = m_nHeaderBottom;
+ if ( HasFooter( bFirstPage ) )
+ {
+ nBottomMargin = m_nHeaderBottom;
+ nFooterHeight = m_nBottomMargin - m_nHeaderBottom;
+
+ // minimum footer height 1mm
+ if ( nFooterHeight < MIN_HEAD_FOOT_HEIGHT )
+ nFooterHeight = MIN_HEAD_FOOT_HEIGHT;
+ }
+
+ Insert(PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::Any(m_bDynamicHeightBottom));
+ Insert(PROP_FOOTER_DYNAMIC_SPACING, uno::Any(m_bDynamicHeightBottom));
+ Insert(PROP_FOOTER_BODY_DISTANCE, uno::Any(nFooterHeight - MIN_HEAD_FOOT_HEIGHT));
+ Insert(PROP_FOOTER_HEIGHT, uno::Any(nFooterHeight));
+ if (m_bDynamicHeightBottom) //fixed height footer -> see WW8Par6.hxx
+ {
+ if (bCopyFirstToFollow && HasFooter(/*bFirstPage=*/true))
+ {
+ m_aFollowPageStyle->setPropertyValue("FooterDynamicSpacing",
+ getProperty(PROP_FOOTER_DYNAMIC_SPACING)->second);
+ m_aFollowPageStyle->setPropertyValue("FooterHeight",
+ getProperty(PROP_FOOTER_HEIGHT)->second);
+ }
+ }
+
+ //now set the top/bottom margin for the follow page style
+ Insert( PROP_TOP_MARGIN, uno::Any( std::max<sal_Int32>(nTopMargin, 0) ) );
+ Insert( PROP_BOTTOM_MARGIN, uno::Any( std::max<sal_Int32>(nBottomMargin, 0) ) );
+}
+
+static uno::Reference< beans::XPropertySet > lcl_GetRangeProperties( bool bIsFirstSection,
+ DomainMapper_Impl& rDM_Impl,
+ const uno::Reference< text::XTextRange >& xStartingRange )
+{
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( bIsFirstSection && rDM_Impl.GetBodyText().is() )
+ {
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( rDM_Impl.GetBodyText(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
+ xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ if ( rDM_Impl.GetIsDummyParaAddedForTableInSection() && xEnum->hasMoreElements() )
+ xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ }
+ else if ( xStartingRange.is() )
+ xRangeProperties.set( xStartingRange, uno::UNO_QUERY_THROW );
+ return xRangeProperties;
+}
+
+void SectionPropertyMap::HandleMarginsHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
+{
+ Insert( PROP_LEFT_MARGIN, uno::Any( m_nLeftMargin ) );
+ Insert( PROP_RIGHT_MARGIN, uno::Any( m_nRightMargin ) );
+ Insert(PROP_GUTTER_MARGIN, uno::Any(m_nGutterMargin));
+
+ if ( rDM_Impl.m_oBackgroundColor )
+ Insert( PROP_BACK_COLOR, uno::Any( *rDM_Impl.m_oBackgroundColor ) );
+
+ // Check for missing footnote separator only in case there is at least
+ // one footnote.
+ if (rDM_Impl.m_bHasFtn && !rDM_Impl.m_bHasFtnSep)
+ {
+ // Set footnote line width to zero, document has no footnote separator.
+ Insert(PROP_FOOTNOTE_LINE_RELATIVE_WIDTH, uno::Any(sal_Int32(0)));
+ }
+ if ( rDM_Impl.m_bHasFtnSep )
+ {
+ //If default paragraph style is RTL, footnote separator should be right aligned
+ //and for RTL locales, LTR default paragraph style should present a left aligned footnote separator
+ try
+ {
+ uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
+ if ( xStylesSupplier.is() )
+ {
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xParagraphStyles;
+ if ( xStyleFamilies.is() )
+ xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles;
+ uno::Reference<beans::XPropertySet> xStandard;
+ if ( xParagraphStyles.is() )
+ xParagraphStyles->getByName("Standard") >>= xStandard;
+ if ( xStandard.is() )
+ {
+ sal_Int16 aWritingMode(0);
+ xStandard->getPropertyValue( getPropertyName(PROP_WRITING_MODE) ) >>= aWritingMode;
+ if( aWritingMode == text::WritingMode2::RL_TB )
+ Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::Any( sal_Int16(text::HorizontalAdjust_RIGHT) ), false );
+ else
+ Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::Any( sal_Int16(text::HorizontalAdjust_LEFT) ), false );
+ }
+ }
+ }
+ catch ( const uno::Exception& ) {}
+ }
+
+ /*** if headers/footers are available then the top/bottom margins of the
+ header/footer are copied to the top/bottom margin of the page
+ */
+ CopyLastHeaderFooter( bFirstPage, rDM_Impl );
+ PrepareHeaderFooterProperties( bFirstPage );
+
+ // tdf#119952: If top/bottom margin was negative during docx import,
+ // then the header/footer and the body could be on top of each other
+ // writer is unable to display both of them in the same position, but can be simulated
+ // by moving the header/footer text into a flyframe anchored to the header/footer,
+ // leaving an empty dummy header/footer.
+ rDM_Impl.ConvertHeaderFooterToTextFrame(m_bDynamicHeightTop, m_bDynamicHeightBottom);
+}
+
+bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo )
+{
+ // always convert non-floating tables to floating ones in footnotes and endnotes
+ if ( rInfo.m_bConvertToFloatingInFootnote )
+ return true;
+ // This is OOXML version of the code deciding if the table needs to be
+ // in a floating frame.
+ // For ww8 code, see SwWW8ImplReader::FloatingTableConversion in
+ // sw/source/filter/ww8/ww8par.cxx
+ // The two should do the same, so if you make changes here, please check
+ // that the other is in sync.
+
+ // Note that this is just a list of heuristics till sw core can have a
+ // table that is floating and can span over multiple pages at the same
+ // time.
+
+ // If there is an explicit section break right after a table, then there
+ // will be no wrapping anyway.
+ if (rDM_Impl.m_bConvertedTable && !rDM_Impl.GetIsLastSectionGroup() && rInfo.m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextPage)
+ return false;
+
+ sal_Int32 nVertOrientPosition = rInfo.getPropertyValue(u"VertOrientPosition").get<sal_Int32>();
+ sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue( u"HoriOrientRelation" ).get<sal_Int16>();
+ if (nVertOrientPosition < 0 && nHoriOrientRelation != text::RelOrientation::PAGE_FRAME)
+ {
+ // Negative vertical position: then need a floating table, as normal tables can't have
+ // negative top margins.
+ return true;
+ }
+
+ sal_Int32 nPageWidth = GetPageWidth();
+ sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
+ // Count the layout width of the table.
+ sal_Int32 nTableWidth = rInfo.m_nTableWidth;
+ if (rInfo.m_nTableWidthType == text::SizeType::VARIABLE)
+ {
+ nTableWidth *= nTextAreaWidth / 100.0;
+ }
+ sal_Int32 nLeftMargin = 0;
+ if ( rInfo.getPropertyValue( u"LeftMargin" ) >>= nLeftMargin )
+ nTableWidth += nLeftMargin;
+ sal_Int32 nRightMargin = 0;
+ if ( rInfo.getPropertyValue( u"RightMargin" ) >>= nRightMargin )
+ nTableWidth += nRightMargin;
+
+ sal_Int16 nVertOrientRelation = rInfo.getPropertyValue( u"VertOrientRelation" ).get<sal_Int16>();
+ if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME && nVertOrientRelation == text::RelOrientation::PAGE_FRAME )
+ {
+ sal_Int16 nHoriOrient = rInfo.getPropertyValue( u"HoriOrient" ).get<sal_Int16>();
+ sal_Int16 nVertOrient = rInfo.getPropertyValue( u"VertOrient" ).get<sal_Int16>();
+ if ( nHoriOrient == text::HoriOrientation::NONE && nVertOrient == text::VertOrientation::NONE )
+ {
+ // Anchor position is relative to the page horizontally and vertically as well and is an absolute position.
+ // The more close we are to the left edge, the less likely there will be any wrapping.
+ // The more close we are to the bottom, the more likely the table will span over to the next page
+ // So if we're in the bottom left quarter, don't do any conversion.
+ sal_Int32 nHoriOrientPosition = rInfo.getPropertyValue( u"HoriOrientPosition" ).get<sal_Int32>();
+ sal_Int32 nPageHeight = getProperty( PROP_HEIGHT )->second.get<sal_Int32>();
+ if ( nHoriOrientPosition < (nPageWidth / 2) && nVertOrientPosition >( nPageHeight / 2 ) )
+ return false;
+ }
+ }
+
+ // It seems Word has a limit here, so that in case the table width is quite
+ // close to the text area width, then it won't perform a wrapping, even in
+ // case the content (e.g. an empty paragraph) would fit. The magic constant
+ // here represents this limit.
+ const sal_Int32 nMagicNumber = 469;
+
+ // If the table's width is smaller than the text area width, text might
+ // be next to the table and so it should behave as a floating table.
+ if ( (nTableWidth + nMagicNumber) < nTextAreaWidth )
+ return true;
+
+ // If the position is relative to the edge of the page, then we need to check the whole
+ // page width to see whether text can fit next to the table.
+ if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME )
+ {
+ // If the table is wide enough so that no text fits next to it, then don't create a fly
+ // for the table: no wrapping will be performed anyway, but multi-page
+ // tables will be broken.
+ if ((nTableWidth + nMagicNumber) < (nPageWidth - std::min(GetLeftMargin(), GetRightMargin())))
+ return true;
+ }
+
+ // If there are columns, always create the fly, otherwise the columns would
+ // restrict geometry of the table.
+ if ( ColumnCount() > 1 )
+ return true;
+
+ return false;
+}
+
+void SectionPropertyMap::InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Impl )
+{
+ // if no new styles have been created for this section, inherit from the previous section,
+ // otherwise apply this section's settings to the new style.
+ // Ensure that FollowPage is inherited first - otherwise GetPageStyle may auto-create a follow when checking FirstPage.
+ SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
+ //tdf124637 TODO: identify and skip special sections (like footnotes/endnotes)
+ if ( pLastContext && m_sFollowPageStyleName.isEmpty() )
+ m_sFollowPageStyleName = pLastContext->GetPageStyleName();
+ else
+ {
+ HandleMarginsHeaderFooter( /*bFirst=*/false, rDM_Impl );
+ GetPageStyle( rDM_Impl, /*bFirst=*/false );
+ if ( rDM_Impl.IsNewDoc() && m_aFollowPageStyle.is() )
+ ApplyProperties_( m_aFollowPageStyle );
+ }
+
+ // FirstPageStyle may only be inherited if it will not be used or re-linked to a different follow
+ if ( !m_bTitlePage && pLastContext && m_sFirstPageStyleName.isEmpty() )
+ m_sFirstPageStyleName = pLastContext->GetPageStyleName( /*bFirst=*/true );
+ else
+ {
+ HandleMarginsHeaderFooter( /*bFirst=*/true, rDM_Impl );
+ GetPageStyle( rDM_Impl, /*bFirst=*/true );
+ if ( rDM_Impl.IsNewDoc() && m_aFirstPageStyle.is() )
+ ApplyProperties_( m_aFirstPageStyle );
+
+ // Chain m_aFollowPageStyle to be after m_aFirstPageStyle
+ m_aFirstPageStyle->setPropertyValue( "FollowStyle", uno::Any( m_sFollowPageStyleName ) );
+ }
+}
+
+void SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl)
+{
+ // Ignore Word 2010 and older.
+ if (rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() < 15)
+ return;
+
+ sal_Int32 nPageWidth = GetPageWidth();
+ sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
+
+ std::vector<AnchoredObjectsInfo>& rAnchoredObjectAnchors = rDM_Impl.m_aAnchoredObjectAnchors;
+ for (const auto& rAnchor : rAnchoredObjectAnchors)
+ {
+ // Ignore this paragraph when there are not enough shapes to trigger the Word bug we
+ // emulate.
+ if (rAnchor.m_aAnchoredObjects.size() < 4)
+ continue;
+
+ // Ignore this paragraph if none of the objects are wrapped in the background.
+ sal_Int32 nOpaqueCount = 0;
+ for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
+ {
+ // Ignore inline objects stored only for redlining.
+ if (rAnchored.m_xRedlineForInline)
+ continue;
+
+ uno::Reference<beans::XPropertySet> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
+ if (!xShape.is())
+ {
+ continue;
+ }
+
+ bool bOpaque = true;
+ xShape->getPropertyValue("Opaque") >>= bOpaque;
+ if (!bOpaque)
+ {
+ ++nOpaqueCount;
+ }
+ }
+ if (nOpaqueCount < 1)
+ {
+ continue;
+ }
+
+ // Analyze the anchored objects of this paragraph, now that we know the
+ // page width.
+ sal_Int32 nShapesWidth = 0;
+ for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
+ {
+ uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
+ if (!xShape.is())
+ continue;
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ if (!xPropertySet.is())
+ continue;
+
+ // Ignore objects with no wrapping.
+ text::WrapTextMode eWrap = text::WrapTextMode_THROUGH;
+ xPropertySet->getPropertyValue("Surround") >>= eWrap;
+ if (eWrap == text::WrapTextMode_THROUGH)
+ continue;
+
+ // Use the original left margin, in case GraphicImport::lcl_sprm() reduced the doc model
+ // one to 0.
+ sal_Int32 nLeftMargin = rAnchored.m_nLeftMargin;
+ sal_Int32 nRightMargin = 0;
+ xPropertySet->getPropertyValue("RightMargin") >>= nRightMargin;
+ nShapesWidth += xShape->getSize().Width + nLeftMargin + nRightMargin;
+ }
+
+ // Ignore cases when we have enough horizontal space for the shapes.
+ if (nTextAreaWidth > nShapesWidth)
+ continue;
+
+ sal_Int32 nHeight = 0;
+ for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
+ {
+ uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
+ if (!xShape.is())
+ continue;
+
+ nHeight += xShape->getSize().Height;
+ }
+
+ uno::Reference<beans::XPropertySet> xParagraph(rAnchor.m_xParagraph, uno::UNO_QUERY);
+ if (xParagraph.is())
+ {
+ sal_Int32 nTopMargin = 0;
+ xParagraph->getPropertyValue("ParaTopMargin") >>= nTopMargin;
+ // Increase top spacing of the paragraph to match Word layout
+ // behavior.
+ nTopMargin = std::max(nTopMargin, nHeight);
+ xParagraph->setPropertyValue("ParaTopMargin", uno::Any(nTopMargin));
+ }
+ }
+ rAnchoredObjectAnchors.clear();
+}
+
+void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
+{
+ SectionPropertyMap* pPrevSection = rDM_Impl.GetLastSectionContext();
+
+ // The default section type is nextPage.
+ if ( m_nBreakType == -1 )
+ m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextColumn )
+ {
+ // Word 2013+ seems to treat a section column break as a page break all the time.
+ // It always acts like a page break if there are no columns, or a different number of columns.
+ // Also, if this is the first section, the break type is basically irrelevant - works best as nextPage.
+ if ( rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() > 14
+ || !pPrevSection
+ || m_nColumnCount < 2
+ || m_nColumnCount != pPrevSection->ColumnCount()
+ )
+ {
+ m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ }
+ }
+ else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous )
+ {
+ // if page orientation differs from previous section, it can't be treated as continuous
+ if ( pPrevSection )
+ {
+ bool bIsLandscape = false;
+ std::optional< PropertyMap::Property > pProp = getProperty( PROP_IS_LANDSCAPE );
+ if ( pProp )
+ pProp->second >>= bIsLandscape;
+
+ bool bPrevIsLandscape = false;
+ pProp = pPrevSection->getProperty( PROP_IS_LANDSCAPE );
+ if ( pProp )
+ pProp->second >>= bPrevIsLandscape;
+
+ if ( bIsLandscape != bPrevIsLandscape )
+ m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ }
+ }
+
+ // Text area width is known at the end of a section: decide if tables should be converted or not.
+ std::vector<FloatingTableInfo>& rPendingFloatingTables = rDM_Impl.m_aPendingFloatingTables;
+ for ( FloatingTableInfo & rInfo : rPendingFloatingTables )
+ {
+ rInfo.m_nBreakType = m_nBreakType;
+ if ( FloatingTableConversion( rDM_Impl, rInfo ) )
+ {
+ uno::Reference<text::XTextAppendAndConvert> xBodyText(
+ rInfo.m_bConvertToFloatingInFootnote
+ ? rInfo.m_xStart->getText()
+ : rDM_Impl.GetBodyText(), uno::UNO_QUERY );
+ std::deque<css::uno::Any> aFramedRedlines = rDM_Impl.m_aStoredRedlines[StoredRedlines::FRAME];
+ try
+ {
+ // convert redline ranges to cursor movement and character length
+ std::vector<sal_Int32> redPos, redLen;
+ std::vector<OUString> redCell;
+ std::vector<OUString> redTable;
+ for( size_t i = 0; i < aFramedRedlines.size(); i+=3)
+ {
+ uno::Reference<text::XText> xCell;
+ uno::Reference< text::XTextRange > xRange;
+ aFramedRedlines[i] >>= xRange;
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( xRange.is() )
+ {
+ OUString sTableName;
+ OUString sCellName;
+ xRangeProperties.set( xRange, uno::UNO_QUERY_THROW );
+ if (xRangeProperties->getPropertySetInfo()->hasPropertyByName("TextTable"))
+ {
+ uno::Any aTable = xRangeProperties->getPropertyValue("TextTable");
+ if ( aTable != uno::Any() )
+ {
+ uno::Reference<text::XTextTable> xTable;
+ aTable >>= xTable;
+ uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
+ xTableProperties->getPropertyValue("TableName") >>= sTableName;
+ }
+ if (xRangeProperties->getPropertySetInfo()->hasPropertyByName("Cell"))
+ {
+ uno::Any aCell = xRangeProperties->getPropertyValue("Cell");
+ if ( aCell != uno::Any() )
+ {
+ aCell >>= xCell;
+ uno::Reference<beans::XPropertySet> xCellProperties(xCell, uno::UNO_QUERY);
+ xCellProperties->getPropertyValue("CellName") >>= sCellName;
+ }
+ }
+ }
+ redTable.push_back(sTableName);
+ redCell.push_back(sCellName);
+ bool bOk = false;
+ if (!sTableName.isEmpty() && !sCellName.isEmpty())
+ {
+ uno::Reference<text::XTextCursor> xRangeCursor = xCell->createTextCursorByRange( xRange );
+ if ( xRangeCursor.is() )
+ {
+ bOk = true;
+ sal_Int32 nLen = xRange->getString().getLength();
+ redLen.push_back(nLen);
+ xRangeCursor->gotoStart(true);
+ redPos.push_back(xRangeCursor->getString().getLength() - nLen);
+ }
+ }
+ if (!bOk)
+ {
+ // missing cell or failed createTextCursorByRange()
+ redLen.push_back(-1);
+ redPos.push_back(-1);
+ }
+ }
+ }
+
+ const uno::Reference< text::XTextContent >& xTextContent =
+ xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd,
+ rInfo.m_aFrameProperties);
+
+ // paragraph of the anchoring point of the floating table needs zero top and bottom
+ // margins, if the table was a not floating table in the footnote, otherwise
+ // docDefault margins could result bigger vertical spaces around the table
+ if ( rInfo.m_bConvertToFloatingInFootnote && xTextContent.is() )
+ {
+ uno::Reference<beans::XPropertySet> xParagraph(
+ xTextContent->getAnchor(), uno::UNO_QUERY);
+ if ( xParagraph.is() )
+ {
+ xParagraph->setPropertyValue("ParaTopMargin",
+ uno::Any(static_cast<sal_Int32>(0)));
+ xParagraph->setPropertyValue("ParaBottomMargin",
+ uno::Any(static_cast<sal_Int32>(0)));
+ }
+ }
+
+ uno::Reference<text::XTextTablesSupplier> xTextDocument(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xTables = xTextDocument->getTextTables();
+ for( size_t i = 0; i < aFramedRedlines.size(); i+=3)
+ {
+ OUString sType;
+ beans::PropertyValues aRedlineProperties( 3 );
+ // skip failed createTextCursorByRange()
+ if (redPos[i/3] == -1)
+ continue;
+ aFramedRedlines[i+1] >>= sType;
+ aFramedRedlines[i+2] >>= aRedlineProperties;
+ uno::Reference<text::XTextTable> xTable(xTables->getByName(redTable[i/3]), uno::UNO_QUERY);
+ uno::Reference<text::XText> xCell(xTable->getCellByName(redCell[i/3]), uno::UNO_QUERY);
+ uno::Reference<text::XTextCursor> xCrsr = xCell->createTextCursor();
+ xCrsr->goRight(redPos[i/3], false);
+ xCrsr->goRight(redLen[i/3], true);
+ uno::Reference < text::XRedline > xRedline( xCrsr, uno::UNO_QUERY_THROW );
+ try
+ {
+ xRedline->makeRedline( sType, aRedlineProperties );
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "makeRedline() failed");
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "convertToTextFrame() failed");
+ }
+
+ aFramedRedlines.clear();
+ }
+ }
+ rPendingFloatingTables.clear();
+
+ try
+ {
+ HandleIncreasedAnchoredObjectSpacing(rDM_Impl);
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "HandleIncreasedAnchoredObjectSpacing() failed");
+ }
+
+ if ( m_nLnnMod )
+ {
+ bool bFirst = rDM_Impl.IsLineNumberingSet();
+ rDM_Impl.SetLineNumbering( m_nLnnMod, m_nLnc, m_ndxaLnn );
+ if ( m_nLnnMin > 0 || (bFirst && m_nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newSection) )
+ {
+ //set the starting value at the beginning of the section
+ try
+ {
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( m_xStartingRange.is() )
+ {
+ xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
+ }
+ else
+ {
+ //set the start value at the beginning of the document
+ xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
+ }
+ // Writer is 1-based, Word is 0-based.
+ xRangeProperties->setPropertyValue(
+ getPropertyName(PROP_PARA_LINE_NUMBER_START_VALUE),
+ uno::Any(m_nLnnMin + 1));
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
+ }
+ }
+ }
+
+ if (m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous
+ && !rDM_Impl.IsInComments())
+ {
+ //todo: insert a section or access the already inserted section
+ uno::Reference< beans::XPropertySet > xSection =
+ rDM_Impl.appendTextSectionAfter( m_xStartingRange );
+ if ( xSection.is() )
+ {
+ if ( m_nColumnCount > 1 )
+ ApplyColumnProperties( xSection, rDM_Impl );
+
+ ApplyProtectionProperties( xSection, rDM_Impl );
+ }
+
+ try
+ {
+ InheritOrFinalizePageStyles( rDM_Impl );
+ ApplySectionProperties( xSection, rDM_Impl ); //depends on InheritOrFinalizePageStyles
+ OUString aName = m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName;
+ uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
+ if ( m_bIsFirstSection && !aName.isEmpty() && xRangeProperties.is() )
+ {
+ xRangeProperties->setPropertyValue( getPropertyName( PROP_PAGE_DESC_NAME ), uno::Any( aName ) );
+ }
+ else if ((!m_bFirstPageHeaderLinkToPrevious ||
+ !m_bFirstPageFooterLinkToPrevious ||
+ !m_bDefaultHeaderLinkToPrevious ||
+ !m_bDefaultFooterLinkToPrevious ||
+ !m_bEvenPageHeaderLinkToPrevious ||
+ !m_bEvenPageFooterLinkToPrevious)
+ && rDM_Impl.GetCurrentXText())
+ { // find a node in the section that has a page break and change
+ // it to apply the page style; see "nightmare scenario" in
+ // wwSectionManager::InsertSegments()
+ auto xTextAppend = rDM_Impl.GetCurrentXText();
+ uno::Reference<container::XEnumerationAccess> const xCursor(
+ xTextAppend->createTextCursorByRange(
+ uno::Reference<text::XTextContent>(xSection, uno::UNO_QUERY_THROW)->getAnchor()),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumeration> const xEnum(
+ xCursor->createEnumeration());
+ bool isFound = false;
+ while (xEnum->hasMoreElements())
+ {
+ uno::Reference<beans::XPropertySet> xElem;
+ xEnum->nextElement() >>= xElem;
+ if (xElem->getPropertySetInfo()->hasPropertyByName("BreakType"))
+ {
+ style::BreakType bt;
+ if ((xElem->getPropertyValue("BreakType") >>= bt)
+ && bt == style::BreakType_PAGE_BEFORE)
+ {
+ // tdf#112201: do *not* use m_sFirstPageStyleName here!
+ xElem->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME),
+ uno::Any(m_sFollowPageStyleName));
+ isFound = true;
+ break;
+ }
+ }
+ }
+ uno::Reference<text::XParagraphCursor> const xPCursor(xCursor,
+ uno::UNO_QUERY_THROW);
+ float fCharHeight = 0;
+ if (!isFound)
+ { // HACK: try the last paragraph of the previous section
+ xPCursor->gotoPreviousParagraph(false);
+ uno::Reference<beans::XPropertySet> const xPSCursor(xCursor, uno::UNO_QUERY_THROW);
+ style::BreakType bt;
+ if ((xPSCursor->getPropertyValue("BreakType") >>= bt)
+ && bt == style::BreakType_PAGE_BEFORE)
+ {
+ xPSCursor->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME),
+ uno::Any(m_sFollowPageStyleName));
+ isFound = true;
+ }
+ else
+ {
+ xPSCursor->getPropertyValue("CharHeight") >>= fCharHeight;
+ }
+ }
+ if (!isFound && fCharHeight <= 1.0)
+ {
+ // If still not found, see if the last paragraph is ~invisible, and work with
+ // the last-in-practice paragraph.
+ xPCursor->gotoPreviousParagraph(false);
+ uno::Reference<beans::XPropertySet> xPropertySet(xCursor, uno::UNO_QUERY_THROW);
+ OUString aPageDescName;
+ if ((xPropertySet->getPropertyValue("PageDescName") >>= aPageDescName)
+ && !aPageDescName.isEmpty())
+ {
+ uno::Reference<beans::XPropertySet> xPageStyle(
+ rDM_Impl.GetPageStyles()->getByName(aPageDescName), uno::UNO_QUERY);
+ xPageStyle->setPropertyValue("FollowStyle",
+ uno::Any(m_sFollowPageStyleName));
+ }
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ SAL_WARN( "writerfilter", "failed to set PageDescName!" );
+ }
+ }
+ // If the section is of type "New column" (0x01), then simply insert a column break.
+ // But only if there actually are columns on the page, otherwise a column break
+ // seems to be handled like a page break by MSO.
+ else if (m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextColumn
+ && m_nColumnCount > 1 && !rDM_Impl.IsInComments())
+ {
+ try
+ {
+ InheritOrFinalizePageStyles( rDM_Impl );
+ /*TODO tdf#135343: Just inserting a column break sounds like the right idea, but the implementation is wrong.
+ * Somehow, the previous column section needs to be extended to cover this new text.
+ * Currently, it is completely broken, producing a no-column section that starts on a new page.
+ */
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( m_xStartingRange.is() )
+ {
+ xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
+ }
+ else
+ {
+ //set the start value at the beginning of the document
+ xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
+ }
+ xRangeProperties->setPropertyValue( getPropertyName( PROP_BREAK_TYPE ), uno::Any( style::BreakType_COLUMN_BEFORE ) );
+ }
+ catch ( const uno::Exception& ) {}
+ }
+ else if (!rDM_Impl.IsInComments())
+ {
+ uno::Reference< beans::XPropertySet > xSection;
+ ApplyProtectionProperties( xSection, rDM_Impl );
+
+ //get the properties and create appropriate page styles
+ uno::Reference< beans::XPropertySet > xFollowPageStyle;
+ //This part certainly is not needed for footnotes, so don't create unused page styles.
+ if ( !rDM_Impl.IsInFootOrEndnote() )
+ {
+ xFollowPageStyle.set( GetPageStyle( rDM_Impl, false ) );
+
+ HandleMarginsHeaderFooter(/*bFirstPage=*/false, rDM_Impl );
+ }
+
+ if ( rDM_Impl.GetSettingsTable()->GetMirrorMarginSettings() )
+ {
+ Insert( PROP_PAGE_STYLE_LAYOUT, uno::Any( style::PageStyleLayout_MIRRORED ) );
+ }
+ uno::Reference< text::XTextColumns > xColumns;
+ if ( m_nColumnCount > 1 )
+ {
+ // prefer setting column properties into a section, not a page style if at all possible.
+ if ( !xSection.is() )
+ xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
+ if ( xSection.is() )
+ ApplyColumnProperties( xSection, rDM_Impl );
+ else if ( xFollowPageStyle.is() )
+ xColumns = ApplyColumnProperties( xFollowPageStyle, rDM_Impl );
+ }
+
+ // these BreakTypes are effectively page-breaks: don't evenly distribute text in columns before a page break;
+ if ( pPrevSection && pPrevSection->ColumnCount() )
+ pPrevSection->DontBalanceTextColumns();
+
+ //prepare text grid properties
+ sal_Int32 nHeight = 1;
+ std::optional< PropertyMap::Property > pProp = getProperty( PROP_HEIGHT );
+ if ( pProp )
+ pProp->second >>= nHeight;
+
+ sal_Int32 nWidth = 1;
+ pProp = getProperty( PROP_WIDTH );
+ if ( pProp )
+ pProp->second >>= nWidth;
+
+ sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
+ pProp = getProperty( PROP_WRITING_MODE );
+ if ( pProp )
+ pProp->second >>= nWritingMode;
+
+ sal_Int32 nTextAreaHeight = nWritingMode == text::WritingMode2::LR_TB ?
+ nHeight - m_nTopMargin - m_nBottomMargin :
+ nWidth - m_nLeftMargin - m_nRightMargin;
+
+ sal_Int32 nGridLinePitch = m_nGridLinePitch;
+ //sep.dyaLinePitch
+ if ( nGridLinePitch < 1 || nGridLinePitch > 31680 )
+ {
+ SAL_WARN( "writerfilter", "sep.dyaLinePitch outside legal range: " << nGridLinePitch );
+ nGridLinePitch = 1;
+ }
+
+ const sal_Int32 nGridLines = nTextAreaHeight / nGridLinePitch;
+ sal_Int16 nGridType = m_nGridType;
+ if ( nGridLines >= 0 && nGridLines <= SAL_MAX_INT16 )
+ Insert( PROP_GRID_LINES, uno::Any( sal_Int16(nGridLines) ) );
+ else
+ nGridType = text::TextGridMode::NONE;
+
+ // PROP_GRID_MODE
+ if ( nGridType == text::TextGridMode::LINES_AND_CHARS )
+ {
+ if (!m_nDxtCharSpace)
+ nGridType = text::TextGridMode::LINES;
+ else
+ Insert( PROP_GRID_SNAP_TO_CHARS, uno::Any( m_bGridSnapToChars ) );
+ }
+
+ Insert( PROP_GRID_MODE, uno::Any( nGridType ) );
+
+ sal_Int32 nCharWidth = 423; //240 twip/ 12 pt
+ const StyleSheetEntryPtr pEntry = rDM_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( u"Standard" );
+ if ( pEntry )
+ {
+ std::optional< PropertyMap::Property > pPropHeight = pEntry->pProperties->getProperty( PROP_CHAR_HEIGHT_ASIAN );
+ if ( pPropHeight )
+ {
+ double fHeight = 0;
+ if ( pPropHeight->second >>= fHeight )
+ nCharWidth = ConversionHelper::convertTwipToMM100( static_cast<tools::Long>(fHeight * 20.0 + 0.5) );
+ }
+ }
+
+ //dxtCharSpace
+ if ( m_nDxtCharSpace )
+ {
+ sal_Int32 nCharSpace = m_nDxtCharSpace;
+ //main lives in top 20 bits, and is signed.
+ sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
+ nMain /= 0x1000;
+ nCharWidth += ConversionHelper::convertTwipToMM100( nMain * 20 );
+
+ sal_Int32 nFraction = (nCharSpace & 0x00000FFF);
+ nFraction = (nFraction * 20) / 0xFFF;
+ nCharWidth += ConversionHelper::convertTwipToMM100( nFraction );
+ }
+
+ if ( m_nPageNumberType >= 0 )
+ Insert( PROP_NUMBERING_TYPE, uno::Any( m_nPageNumberType ) );
+
+ // #i119558#, force to set document as standard page mode,
+ // refer to ww8 import process function "SwWW8ImplReader::SetDocumentGrid"
+ try
+ {
+ uno::Reference< beans::XPropertySet > xDocProperties;
+ xDocProperties.set( rDM_Impl.GetTextDocument(), uno::UNO_QUERY_THROW );
+ Insert(PROP_GRID_STANDARD_MODE, uno::Any(true));
+ xDocProperties->setPropertyValue("DefaultPageMode", uno::Any(false));
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
+ }
+
+ Insert( PROP_GRID_BASE_HEIGHT, uno::Any( nGridLinePitch ) );
+ Insert( PROP_GRID_BASE_WIDTH, uno::Any( nCharWidth ) );
+ Insert( PROP_GRID_RUBY_HEIGHT, uno::Any( sal_Int32( 0 ) ) );
+
+ if ( rDM_Impl.IsNewDoc() && xFollowPageStyle.is() )
+ ApplyProperties_( xFollowPageStyle );
+
+ //todo: creating a "First Page" style depends on HasTitlePage and _fFacingPage_
+ if ( m_bTitlePage )
+ {
+ CopyLastHeaderFooter( true, rDM_Impl );
+ PrepareHeaderFooterProperties( true );
+ uno::Reference< beans::XPropertySet > xFirstPageStyle = GetPageStyle(
+ rDM_Impl, true );
+ if ( rDM_Impl.IsNewDoc() )
+ ApplyProperties_( xFirstPageStyle );
+
+ if ( xColumns.is() )
+ xFirstPageStyle->setPropertyValue(
+ getPropertyName( PROP_TEXT_COLUMNS ), uno::Any( xColumns ) );
+ }
+
+ ApplyBorderToPageStyles( rDM_Impl, m_eBorderApply, m_eBorderOffsetFrom );
+
+ try
+ {
+ //now apply this break at the first paragraph of this section
+ uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
+
+ // Handle page breaks with odd/even page numbering. We need to use an extra page style for setting the page style
+ // to left/right, because if we set it to the normal style, we'd set it to "First Page"/"Default Style", which would
+ // break them (all default pages would be only left or right).
+ if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_evenPage || m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_oddPage )
+ {
+ OUString* pageStyle = m_bTitlePage ? &m_sFirstPageStyleName : &m_sFollowPageStyleName;
+ OUString evenOddStyleName = rDM_Impl.GetUnusedPageStyleName();
+ uno::Reference< beans::XPropertySet > evenOddStyle(
+ rDM_Impl.GetTextFactory()->createInstance( "com.sun.star.style.PageStyle" ),
+ uno::UNO_QUERY );
+ // Unfortunately using setParent() does not work for page styles, so make a deep copy of the page style.
+ uno::Reference< beans::XPropertySet > pageProperties( m_bTitlePage ? m_aFirstPageStyle : m_aFollowPageStyle );
+ uno::Reference< beans::XPropertySetInfo > pagePropertiesInfo( pageProperties->getPropertySetInfo() );
+ const uno::Sequence< beans::Property > propertyList( pagePropertiesInfo->getProperties() );
+ // Ignore write-only properties.
+ static const o3tl::sorted_vector<OUString> aDenylist
+ = { "FooterBackGraphicURL", "BackGraphicURL", "HeaderBackGraphicURL" };
+ for ( const auto& rProperty : propertyList )
+ {
+ if ( (rProperty.Attributes & beans::PropertyAttribute::READONLY) == 0 )
+ {
+ if (aDenylist.find(rProperty.Name) == aDenylist.end())
+ evenOddStyle->setPropertyValue(
+ rProperty.Name,
+ pageProperties->getPropertyValue(rProperty.Name));
+ }
+ }
+ evenOddStyle->setPropertyValue( "FollowStyle", uno::Any( *pageStyle ) );
+ rDM_Impl.GetPageStyles()->insertByName( evenOddStyleName, uno::Any( evenOddStyle ) );
+ evenOddStyle->setPropertyValue( "HeaderIsOn", uno::Any( false ) );
+ evenOddStyle->setPropertyValue( "FooterIsOn", uno::Any( false ) );
+ CopyHeaderFooter(rDM_Impl, pageProperties, evenOddStyle);
+ *pageStyle = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one).
+ if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_evenPage )
+ evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::Any( style::PageStyleLayout_LEFT ) );
+ else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_oddPage )
+ evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::Any( style::PageStyleLayout_RIGHT ) );
+ }
+
+ if (rDM_Impl.m_xAltChunkStartingRange.is())
+ {
+ xRangeProperties.set(rDM_Impl.m_xAltChunkStartingRange, uno::UNO_QUERY);
+ }
+ if (xRangeProperties.is() && (rDM_Impl.IsNewDoc() || rDM_Impl.IsAltChunk()))
+ {
+ // Avoid setting page style in case of autotext: so inserting the autotext at the
+ // end of the document does not introduce an unwanted page break.
+ // Also avoid setting the page style at the very beginning if it still is the default page style.
+ const OUString sPageStyle = m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName;
+ if (!rDM_Impl.IsReadGlossaries()
+ && !rDM_Impl.IsInFootOrEndnote()
+ && !(m_bIsFirstSection && sPageStyle == getPropertyName( PROP_STANDARD ) && m_nPageNumber < 0)
+ )
+ {
+ xRangeProperties->setPropertyValue(
+ getPropertyName( PROP_PAGE_DESC_NAME ),
+ uno::Any(sPageStyle) );
+ }
+
+ if (0 <= m_nPageNumber)
+ {
+ sal_Int16 nPageNumber = static_cast< sal_Int16 >(m_nPageNumber);
+ xRangeProperties->setPropertyValue(getPropertyName(PROP_PAGE_NUMBER_OFFSET),
+ uno::Any(nPageNumber));
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::CloseSectionGroup" );
+ }
+ }
+
+ // Now that the margins are known, resize relative width shapes because some shapes in LO do not support percentage-sizes
+ sal_Int32 nParagraphWidth = GetPageWidth() - m_nLeftMargin - m_nRightMargin;
+ if ( m_nColumnCount > 1 )
+ {
+ // skip custom-width columns since we don't know what column the shape is in.
+ if ( !m_aColWidth.empty() )
+ nParagraphWidth = 0;
+ else
+ nParagraphWidth = (nParagraphWidth - (m_nColumnDistance * (m_nColumnCount - 1))) / m_nColumnCount;
+ }
+ if ( nParagraphWidth > 0 )
+ {
+ const OUString sPropRelativeWidth = getPropertyName(PROP_RELATIVE_WIDTH);
+ for ( const auto& xShape : m_xRelativeWidthShapes )
+ {
+ const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
+ if ( xShapePropertySet->getPropertySetInfo()->hasPropertyByName(sPropRelativeWidth) )
+ {
+ sal_uInt16 nPercent = 0;
+ try
+ {
+ xShapePropertySet->getPropertyValue(sPropRelativeWidth) >>= nPercent;
+ }
+ catch (const css::uno::RuntimeException& e)
+ {
+ // May happen e.g. when text frame has no frame format
+ // See sw/qa/extras/ooxmlimport/data/n779627.docx
+ SAL_WARN("writerfilter", "Getting relative width failed. " << e.Message);
+ }
+ if ( nPercent )
+ {
+ const sal_Int32 nWidth = nParagraphWidth * nPercent / 100;
+ xShape->setSize( awt::Size( nWidth, xShape->getSize().Height ) );
+ }
+ }
+ }
+ }
+ m_xRelativeWidthShapes.clear();
+
+ rDM_Impl.SetIsLastSectionGroup( false );
+ rDM_Impl.SetIsFirstParagraphInSection( true );
+
+ if ( !rDM_Impl.IsInFootOrEndnote() && !rDM_Impl.IsInComments() )
+ {
+ rDM_Impl.m_bHasFtn = false;
+ rDM_Impl.m_bHasFtnSep = false;
+ }
+}
+
+// Clear the flag that says we should take the header/footer content from
+// the previous section. This should be called when we encounter a header
+// or footer definition for this section.
+void SectionPropertyMap::ClearHeaderFooterLinkToPrevious( bool bHeader, PageType eType )
+{
+ if ( bHeader )
+ {
+ switch ( eType )
+ {
+ case PAGE_FIRST: m_bFirstPageHeaderLinkToPrevious = false; break;
+ case PAGE_LEFT: m_bEvenPageHeaderLinkToPrevious = false; break;
+ case PAGE_RIGHT: m_bDefaultHeaderLinkToPrevious = false; break;
+ // no default case as all enumeration values have been covered
+ }
+ }
+ else
+ {
+ switch ( eType )
+ {
+ case PAGE_FIRST: m_bFirstPageFooterLinkToPrevious = false; break;
+ case PAGE_LEFT: m_bEvenPageFooterLinkToPrevious = false; break;
+ case PAGE_RIGHT: m_bDefaultFooterLinkToPrevious = false; break;
+ }
+ }
+}
+
+namespace {
+
+class NamedPropertyValue
+{
+private:
+ OUString m_aName;
+
+public:
+ explicit NamedPropertyValue( const OUString& i_aStr )
+ : m_aName( i_aStr )
+ {
+ }
+
+ bool operator() ( beans::PropertyValue const & aVal )
+ {
+ return aVal.Name == m_aName;
+ }
+};
+
+}
+
+void SectionPropertyMap::ApplyProperties_( const uno::Reference< beans::XPropertySet >& xStyle )
+{
+ uno::Reference< beans::XMultiPropertySet > const xMultiSet( xStyle, uno::UNO_QUERY );
+
+ std::vector< OUString > vNames;
+ std::vector< uno::Any > vValues;
+ {
+ // Convert GetPropertyValues() value into something useful
+ const uno::Sequence< beans::PropertyValue > vPropVals = GetPropertyValues();
+
+ //Temporarily store the items that are in grab bags
+ uno::Sequence< beans::PropertyValue > vCharVals;
+ uno::Sequence< beans::PropertyValue > vParaVals;
+ const beans::PropertyValue* pCharGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "CharInteropGrabBag" ) );
+ if ( pCharGrabBag != vPropVals.end() )
+ (pCharGrabBag->Value) >>= vCharVals;
+ const beans::PropertyValue* pParaGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "ParaInteropGrabBag" ) );
+ if ( pParaGrabBag != vPropVals.end() )
+ (pParaGrabBag->Value) >>= vParaVals;
+
+ for ( const beans::PropertyValue* pIter = vPropVals.begin(); pIter != vPropVals.end(); ++pIter )
+ {
+ if ( pIter != pCharGrabBag && pIter != pParaGrabBag
+ && pIter->Name != "IsProtected" //section-only property
+ )
+ {
+ vNames.push_back( pIter->Name );
+ vValues.push_back( pIter->Value );
+ }
+ }
+ for ( const beans::PropertyValue & v : std::as_const(vCharVals) )
+ {
+ vNames.push_back( v.Name );
+ vValues.push_back( v.Value );
+ }
+ for ( const beans::PropertyValue & v : std::as_const(vParaVals) )
+ {
+ vNames.push_back( v.Name );
+ vValues.push_back( v.Value );
+ }
+ }
+ if ( xMultiSet.is() )
+ {
+ try
+ {
+ xMultiSet->setPropertyValues( comphelper::containerToSequence( vNames ), comphelper::containerToSequence( vValues ) );
+ return;
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::ApplyProperties_" );
+ }
+ }
+ for ( size_t i = 0; i < vNames.size(); ++i )
+ {
+ try
+ {
+ if ( xStyle.is() )
+ xStyle->setPropertyValue( vNames[i], vValues[i] );
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::ApplyProperties_" );
+ }
+ }
+}
+
+sal_Int32 SectionPropertyMap::GetPageWidth() const
+{
+ return getProperty( PROP_WIDTH )->second.get<sal_Int32>();
+}
+
+StyleSheetPropertyMap::StyleSheetPropertyMap()
+ : mnListLevel( -1 )
+ , mnOutlineLevel( -1 )
+{
+}
+
+ParagraphProperties::ParagraphProperties()
+ : m_bFrameMode( false )
+ , m_nDropCap( NS_ooxml::LN_Value_doc_ST_DropCap_none )
+ , m_nLines( 0 )
+ , m_w( -1 )
+ , m_h( -1 )
+ , m_nWrap( text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE )
+ , m_hAnchor( -1 )
+ , m_vAnchor( -1 )
+ , m_x( -1 )
+ , m_bxValid( false )
+ , m_y( -1 )
+ , m_byValid( false )
+ , m_hSpace( -1 )
+ , m_vSpace( -1 )
+ , m_hRule( -1 )
+ , m_xAlign( -1 )
+ , m_yAlign( -1 )
+ , m_nDropCapLength( 0 )
+{
+}
+
+bool ParagraphProperties::operator==( const ParagraphProperties& rCompare )
+{
+ return ( m_bFrameMode == rCompare.m_bFrameMode &&
+ m_nDropCap == rCompare.m_nDropCap &&
+ m_nLines == rCompare.m_nLines &&
+ m_w == rCompare.m_w &&
+ m_h == rCompare.m_h &&
+ m_nWrap == rCompare.m_nWrap &&
+ m_hAnchor == rCompare.m_hAnchor &&
+ m_vAnchor == rCompare.m_vAnchor &&
+ m_x == rCompare.m_x &&
+ m_bxValid == rCompare.m_bxValid &&
+ m_y == rCompare.m_y &&
+ m_byValid == rCompare.m_byValid &&
+ m_hSpace == rCompare.m_hSpace &&
+ m_vSpace == rCompare.m_vSpace &&
+ m_hRule == rCompare.m_hRule &&
+ m_xAlign == rCompare.m_xAlign &&
+ m_yAlign == rCompare.m_yAlign );
+}
+
+void ParagraphProperties::ResetFrameProperties()
+{
+ m_bFrameMode = false;
+ m_nDropCap = NS_ooxml::LN_Value_doc_ST_DropCap_none;
+ m_nLines = 0;
+ m_w = -1;
+ m_h = -1;
+ m_nWrap = text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE;
+ m_hAnchor = -1;
+ m_vAnchor = -1;
+ m_x = -1;
+ m_bxValid = false;
+ m_y = -1;
+ m_byValid = false;
+ m_hSpace = -1;
+ m_vSpace = -1;
+ m_hRule = -1;
+ m_xAlign = -1;
+ m_yAlign = -1;
+ m_nDropCapLength = 0;
+}
+
+bool TablePropertyMap::getValue( TablePropertyMapTarget eWhich, sal_Int32& nFill )
+{
+ if ( eWhich < TablePropertyMapTarget_MAX )
+ {
+ if ( m_aValidValues[eWhich].bValid )
+ nFill = m_aValidValues[eWhich].nValue;
+ return m_aValidValues[eWhich].bValid;
+ }
+ else
+ {
+ OSL_FAIL( "invalid TablePropertyMapTarget" );
+ return false;
+ }
+}
+
+void TablePropertyMap::setValue( TablePropertyMapTarget eWhich, sal_Int32 nSet )
+{
+ if ( eWhich < TablePropertyMapTarget_MAX )
+ {
+ m_aValidValues[eWhich].bValid = true;
+ m_aValidValues[eWhich].nValue = nSet;
+ }
+ else
+ OSL_FAIL( "invalid TablePropertyMapTarget" );
+}
+
+void TablePropertyMap::insertTableProperties( const PropertyMap* pMap, const bool bOverwrite )
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement( "TablePropertyMap.insertTableProperties" );
+ pMap->dumpXml();
+#endif
+
+ const TablePropertyMap* pSource = dynamic_cast< const TablePropertyMap* >(pMap);
+ if ( pSource )
+ {
+ for ( sal_Int32 eTarget = TablePropertyMapTarget_START;
+ eTarget < TablePropertyMapTarget_MAX; ++eTarget )
+ {
+ if ( pSource->m_aValidValues[eTarget].bValid && (bOverwrite || !m_aValidValues[eTarget].bValid) )
+ {
+ m_aValidValues[eTarget].bValid = true;
+ m_aValidValues[eTarget].nValue = pSource->m_aValidValues[eTarget].nValue;
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PropertyMap.hxx b/writerfilter/source/dmapper/PropertyMap.hxx
new file mode 100644
index 000000000..988c99b02
--- /dev/null
+++ b/writerfilter/source/dmapper/PropertyMap.hxx
@@ -0,0 +1,614 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/uno/Any.h>
+#include <com/sun/star/drawing/XShape.hpp>
+#include "PropertyIds.hxx"
+#include <memory>
+#include <optional>
+#include <map>
+#include <vector>
+#include <set>
+
+namespace com::sun::star {
+ namespace beans {
+ struct PropertyValue;
+ }
+ namespace container {
+ class XNameContainer;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+ namespace text {
+ class XTextRange;
+ class XTextColumns;
+ class XFootnote;
+ }
+ namespace table {
+ struct BorderLine2;
+ struct ShadowFormat;
+ }
+}
+
+namespace writerfilter::dmapper {
+
+class DomainMapper_Impl;
+struct FloatingTableInfo;
+struct AnchoredObjectInfo;
+
+enum BorderPosition
+{
+ BORDER_LEFT,
+ BORDER_RIGHT,
+ BORDER_TOP,
+ BORDER_BOTTOM
+};
+
+enum GrabBagType
+{
+ NO_GRAB_BAG,
+ ROW_GRAB_BAG,
+ CELL_GRAB_BAG,
+ PARA_GRAB_BAG,
+ CHAR_GRAB_BAG
+};
+
+struct RedlineParams : public virtual SvRefBase
+{
+ OUString m_sAuthor;
+ OUString m_sDate;
+ sal_Int32 m_nToken;
+
+ // This can hold properties of runs that had formatted 'track changes' properties
+ css::uno::Sequence< css::beans::PropertyValue > m_aRevertProperties;
+};
+
+typedef tools::SvRef< RedlineParams > RedlineParamsPtr;
+
+class PropValue
+{
+private:
+ css::uno::Any m_aValue;
+ GrabBagType m_GrabBagType;
+ bool m_bIsDocDefault;
+
+public:
+ PropValue( const css::uno::Any& rValue, GrabBagType i_GrabBagType, bool bDocDefault )
+ : m_aValue( rValue )
+ , m_GrabBagType( i_GrabBagType )
+ , m_bIsDocDefault( bDocDefault )
+ {
+ }
+
+ PropValue( const css::uno::Any& rValue, GrabBagType i_GrabBagType )
+ : m_aValue( rValue )
+ , m_GrabBagType( i_GrabBagType )
+ , m_bIsDocDefault( false )
+ {
+ }
+
+ PropValue()
+ : m_aValue()
+ , m_GrabBagType( NO_GRAB_BAG )
+ , m_bIsDocDefault( false )
+ {
+ }
+
+ const css::uno::Any& getValue() const { return m_aValue; }
+
+ GrabBagType getGrabBagType() const { return m_GrabBagType; }
+
+ bool getIsDocDefault() const { return m_bIsDocDefault; }
+};
+
+class PropertyMap;
+typedef tools::SvRef< PropertyMap > PropertyMapPtr;
+
+class PropertyMap : public virtual SvRefBase
+{
+private:
+ // Cache the property values for the GetPropertyValues() call(s).
+ std::vector< css::beans::PropertyValue > m_aValues;
+
+ // marks context as footnote context - ::text( ) events contain either the footnote character or can be ignored
+ // depending on sprmCSymbol
+ css::uno::Reference< css::text::XFootnote > m_xFootnote;
+ OUString m_sFootnoteCharStyleName;
+ std::map< PropertyIds, PropValue > m_vMap;
+ std::vector< RedlineParamsPtr > m_aRedlines;
+
+public:
+ typedef std::pair< PropertyIds, css::uno::Any > Property;
+
+ PropertyMap() {}
+
+ // Sequence: Grab Bags: The CHAR_GRAB_BAG has Name "CharInteropGrabBag" and the PARA_GRAB_BAG has Name "ParaInteropGrabBag"
+ // the contained properties are their Value.
+ css::uno::Sequence< css::beans::PropertyValue > GetPropertyValues( bool bCharGrabBag = true );
+
+ std::vector< PropertyIds > GetPropertyIds();
+
+ // Add property, optionally overwriting existing attributes
+ void Insert( PropertyIds eId, const css::uno::Any& rAny, bool bOverwrite = true, GrabBagType i_GrabBagType = NO_GRAB_BAG, bool bDocDefault = false );
+
+ // Remove a named property from *this, does nothing if the property id has not been set
+ void Erase( PropertyIds eId);
+
+ // Imports properties from pMap (bOverwrite==false means m_bIsDocDefault=true setting)
+ void InsertProps( const PropertyMapPtr& rMap, const bool bOverwrite = true );
+
+ // Returns a copy of the property if it exists, .first is its PropertyIds and .second is its Value (type css::uno::Any)
+ std::optional< Property > getProperty( PropertyIds eId ) const;
+
+ // Has the property named been set (via Insert)?
+ bool isSet( PropertyIds eId ) const;
+ bool isDocDefault( PropertyIds eId ) const;
+
+ const css::uno::Reference< css::text::XFootnote >& GetFootnote() const { return m_xFootnote; }
+ const OUString& GetFootnoteStyle() const { return m_sFootnoteCharStyleName; }
+
+ void SetFootnote(const css::uno::Reference< css::text::XFootnote >& xFootnote, const OUString& sStyleName)
+ {
+ m_xFootnote = xFootnote;
+ m_sFootnoteCharStyleName = sStyleName;
+ }
+
+ virtual void insertTableProperties( const PropertyMap*, const bool bOverwrite = true );
+
+ const std::vector< RedlineParamsPtr >& Redlines() const { return m_aRedlines; }
+
+ std::vector< RedlineParamsPtr >& Redlines() { return m_aRedlines; }
+
+ void printProperties();
+
+#ifdef DBG_UTIL
+ void dumpXml() const;
+#endif
+
+ static css::table::ShadowFormat getShadowFromBorder( const css::table::BorderLine2& rBorder );
+
+protected:
+ void Invalidate()
+ {
+ if ( m_aValues.size() )
+ m_aValues.clear();
+ }
+};
+
+class SectionPropertyMap : public PropertyMap
+{
+public:
+ enum class BorderApply
+ {
+ ToAllInSection = 0,
+ ToFirstPageInSection = 1,
+ ToAllButFirstInSection = 2
+ };
+ enum class BorderOffsetFrom
+ {
+ Text = 0,
+ Edge = 1,
+ };
+private:
+#ifdef DBG_UTIL
+ sal_Int32 m_nDebugSectionNumber;
+#endif
+
+ // 'temporarily' the section page settings are imported as page styles
+ // empty strings mark page settings as not yet imported
+
+ bool m_bIsFirstSection;
+ css::uno::Reference< css::text::XTextRange > m_xStartingRange;
+
+ OUString m_sFirstPageStyleName;
+ OUString m_sFollowPageStyleName;
+ css::uno::Reference< css::beans::XPropertySet > m_aFirstPageStyle;
+ css::uno::Reference< css::beans::XPropertySet > m_aFollowPageStyle;
+
+ std::optional< css::table::BorderLine2 > m_oBorderLines[4];
+ sal_Int32 m_nBorderDistances[4];
+ BorderApply m_eBorderApply;
+ BorderOffsetFrom m_eBorderOffsetFrom;
+ bool m_bBorderShadows[4];
+
+ bool m_bTitlePage;
+ sal_Int16 m_nColumnCount;
+ sal_Int32 m_nColumnDistance;
+ css::uno::Reference< css::beans::XPropertySet > m_xColumnContainer;
+ std::vector< sal_Int32 > m_aColWidth;
+ std::vector< sal_Int32 > m_aColDistance;
+
+ bool m_bSeparatorLineIsOn;
+ bool m_bEvenlySpaced;
+
+ sal_Int32 m_nPageNumber;
+ // Page number type is a value from css::style::NumberingType.
+ sal_Int16 m_nPageNumberType;
+ sal_Int32 m_nBreakType;
+
+ sal_Int32 m_nLeftMargin;
+ sal_Int32 m_nRightMargin;
+ sal_Int32 m_nGutterMargin;
+ sal_Int32 m_nTopMargin;
+ sal_Int32 m_nBottomMargin;
+ sal_Int32 m_nHeaderTop;
+ sal_Int32 m_nHeaderBottom;
+
+ sal_Int32 m_nGridType;
+ sal_Int32 m_nGridLinePitch;
+ sal_Int32 m_nDxtCharSpace;
+ bool m_bGridSnapToChars;
+
+ // line numbering
+ sal_Int32 m_nLnnMod;
+ sal_uInt32 m_nLnc;
+ sal_Int32 m_ndxaLnn;
+ sal_Int32 m_nLnnMin;
+
+ bool m_bDynamicHeightTop;
+ bool m_bDynamicHeightBottom;
+
+ std::vector<css::uno::Reference<css::drawing::XShape>> m_xRelativeWidthShapes;
+
+ // The "Link To Previous" flag indicates whether the header/footer
+ // content should be taken from the previous section
+ bool m_bDefaultHeaderLinkToPrevious;
+ bool m_bEvenPageHeaderLinkToPrevious;
+ bool m_bFirstPageHeaderLinkToPrevious;
+ bool m_bDefaultFooterLinkToPrevious;
+ bool m_bEvenPageFooterLinkToPrevious;
+ bool m_bFirstPageFooterLinkToPrevious;
+
+ void ApplyProperties_( const css::uno::Reference< css::beans::XPropertySet >& xStyle );
+
+ void DontBalanceTextColumns();
+
+ /// Apply section-specific properties: only valid to use after PageStyle has been determined by InheritOrFinalizePageStyles
+ void ApplySectionProperties( const css::uno::Reference< css::beans::XPropertySet >& xSection, DomainMapper_Impl& rDM_Impl );
+
+ /// Check if document is protected. If so, ensure a section exists, and apply its protected value.
+ void ApplyProtectionProperties( css::uno::Reference< css::beans::XPropertySet >& xSection, DomainMapper_Impl& rDM_Impl );
+
+ css::uno::Reference< css::text::XTextColumns > ApplyColumnProperties( const css::uno::Reference< css::beans::XPropertySet >& xFollowPageStyle,
+ DomainMapper_Impl& rDM_Impl);
+
+ void CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl );
+
+ static void CopyHeaderFooter( const DomainMapper_Impl& rDM_Impl,
+ const css::uno::Reference< css::beans::XPropertySet >& xPrevStyle,
+ const css::uno::Reference< css::beans::XPropertySet >& xStyle,
+ bool bOmitRightHeader = false, bool bOmitLeftHeader = false,
+ bool bOmitRightFooter = false, bool bOmitLeftFooter = false );
+
+ static void CopyHeaderFooterTextProperty( const css::uno::Reference< css::beans::XPropertySet >& xPrevStyle,
+ const css::uno::Reference< css::beans::XPropertySet >& xStyle,
+ PropertyIds ePropId );
+
+ void PrepareHeaderFooterProperties( bool bFirstPage );
+
+ bool HasHeader( bool bFirstPage ) const;
+ bool HasFooter( bool bFirstPage ) const;
+
+ static void SetBorderDistance( const css::uno::Reference< css::beans::XPropertySet >& xStyle,
+ PropertyIds eMarginId,
+ PropertyIds eDistId,
+ sal_Int32 nDistance,
+ BorderOffsetFrom eOffsetFrom,
+ sal_uInt32 nLineWidth,
+ DomainMapper_Impl& rDM_Impl );
+
+ // Determines if conversion of a given floating table is wanted or not.
+ bool FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo );
+
+ /// Increases paragraph spacing according to Word 2013+ needs if necessary.
+ void HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl);
+
+public:
+ enum PageType
+ {
+ PAGE_FIRST,
+ PAGE_LEFT,
+ PAGE_RIGHT
+ };
+
+ explicit SectionPropertyMap( bool bIsFirstSection );
+
+ bool IsFirstSection() const { return m_bIsFirstSection; }
+
+ void SetStart( const css::uno::Reference< css::text::XTextRange >& xRange ) { m_xStartingRange = xRange; }
+
+ const css::uno::Reference< css::text::XTextRange >& GetStartingRange() const { return m_xStartingRange; }
+
+ css::uno::Reference< css::beans::XPropertySet > GetPageStyle( DomainMapper_Impl& rDM_Impl, bool bFirst );
+
+ const OUString& GetPageStyleName( bool bFirstPage = false )
+ {
+ return bFirstPage ? m_sFirstPageStyleName : m_sFollowPageStyleName;
+ }
+
+ // @throws css::beans::UnknownPropertyException
+ // @throws css::beans::PropertyVetoException
+ // @throws css::lang::IllegalArgumentException
+ // @throws css::lang::WrappedTargetException
+ // @throws css::uno::RuntimeException
+ void InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Impl );
+
+ void SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const css::table::BorderLine2& rBorderLine, bool bShadow );
+ void SetBorderApply( BorderApply nSet ) { m_eBorderApply = nSet; }
+ void SetBorderOffsetFrom( BorderOffsetFrom nSet ) { m_eBorderOffsetFrom = nSet; }
+
+ void SetColumnCount( sal_Int16 nCount ) { m_nColumnCount = nCount; }
+ sal_Int16 ColumnCount() const { return m_nColumnCount; }
+
+ void SetColumnDistance( sal_Int32 nDist ) { m_nColumnDistance = nDist; }
+ void AppendColumnWidth( sal_Int32 nWidth ) { m_aColWidth.push_back( nWidth ); }
+ void AppendColumnSpacing( sal_Int32 nDist ) { m_aColDistance.push_back( nDist ); }
+
+ void SetTitlePage( bool bSet ) { m_bTitlePage = bSet; }
+ void SetSeparatorLine( bool bSet ) { m_bSeparatorLineIsOn = bSet; }
+ void SetEvenlySpaced( bool bSet ) { m_bEvenlySpaced = bSet; }
+ void SetPageNumber( sal_Int32 nSet ) { m_nPageNumber = nSet; }
+ void SetPageNumberType( sal_Int32 nSet ) { m_nPageNumberType = nSet; }
+ void SetBreakType( sal_Int32 nSet ) { m_nBreakType = nSet; }
+ // GetBreakType returns -1 if the breakType has not yet been identified for the section
+ sal_Int32 GetBreakType() const { return m_nBreakType; }
+
+ void SetLeftMargin( sal_Int32 nSet ) { m_nLeftMargin = nSet; }
+ sal_Int32 GetLeftMargin() const { return m_nLeftMargin; }
+ void SetRightMargin( sal_Int32 nSet ) { m_nRightMargin = nSet; }
+ sal_Int32 GetRightMargin() const { return m_nRightMargin; }
+ void SetTopMargin(sal_Int32 nSet) { m_bDynamicHeightTop = nSet >= 0; m_nTopMargin = std::abs(nSet); }
+ void SetBottomMargin( sal_Int32 nSet ) { m_bDynamicHeightBottom = nSet >= 0; m_nBottomMargin = std::abs(nSet); }
+ void SetHeaderTop( sal_Int32 nSet ) { m_nHeaderTop = nSet; }
+ void SetHeaderBottom( sal_Int32 nSet ) { m_nHeaderBottom = nSet; }
+ void SetGutterMargin( sal_Int32 nGutterMargin ) { m_nGutterMargin = nGutterMargin; }
+ sal_Int32 GetPageWidth() const;
+
+ void SetGridType( sal_Int32 nSet ) { m_nGridType = nSet; }
+ void SetGridLinePitch( sal_Int32 nSet ) { m_nGridLinePitch = nSet; }
+ void SetGridSnapToChars( bool bSet ) { m_bGridSnapToChars = bSet; }
+ void SetDxtCharSpace( sal_Int32 nSet ) { m_nDxtCharSpace = nSet; }
+
+ void SetLnnMod( sal_Int32 nValue ) { m_nLnnMod = nValue; }
+ void SetLnc( sal_Int32 nValue ) { m_nLnc = nValue; }
+ void SetdxaLnn( sal_Int32 nValue ) { m_ndxaLnn = nValue; }
+ void SetLnnMin( sal_Int32 nValue ) { m_nLnnMin = nValue; }
+
+ void addRelativeWidthShape( css::uno::Reference<css::drawing::XShape> xShape ) { m_xRelativeWidthShapes.push_back( xShape ); }
+
+ // determine which style gets the borders
+ void ApplyBorderToPageStyles( DomainMapper_Impl &rDM_Impl,
+ BorderApply eBorderApply, BorderOffsetFrom eOffsetFrom );
+
+ void CloseSectionGroup( DomainMapper_Impl& rDM_Impl );
+ // Handling of margins, header and footer for any kind of sections breaks.
+ void HandleMarginsHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl );
+ void ClearHeaderFooterLinkToPrevious( bool bHeader, PageType eType );
+};
+
+class ParagraphProperties : public virtual SvRefBase
+{
+private:
+ bool m_bFrameMode;
+ sal_Int32 m_nDropCap; // drop, margin ST_DropCap
+ sal_Int32 m_nLines; // number of lines of the drop cap
+ sal_Int32 m_w; // width
+ sal_Int32 m_h; // height
+ css::text::WrapTextMode m_nWrap; // from ST_Wrap around, auto, none, notBeside, through, tight
+ sal_Int32 m_hAnchor; // page, from ST_HAnchor margin, page, text
+ sal_Int32 m_vAnchor; // around from ST_VAnchor margin, page, text
+ sal_Int32 m_x; // x-position
+ bool m_bxValid;
+ sal_Int32 m_y; // y-position
+ bool m_byValid;
+ sal_Int32 m_hSpace; // frame padding h
+ sal_Int32 m_vSpace; // frame padding v
+ sal_Int32 m_hRule; // from ST_HeightRule exact, atLeast, auto
+ sal_Int32 m_xAlign; // from ST_XAlign center, inside, left, outside, right
+ sal_Int32 m_yAlign; // from ST_YAlign bottom, center, inline, inside, outside, top
+ sal_Int8 m_nDropCapLength; // number of characters
+ OUString m_sParaStyleName;
+ OUString m_sParaId; // [MS-DOCX] sect. 2.2.4 "p and tr Extensions"
+
+ css::uno::Reference< css::text::XTextRange > m_xStartingRange; // start of a frame
+ css::uno::Reference< css::text::XTextRange > m_xEndingRange; // end of the frame
+ sal_Int32 m_nListId = -1;
+
+public:
+ ParagraphProperties();
+
+ ParagraphProperties(ParagraphProperties const &) = default;
+ ParagraphProperties(ParagraphProperties &&) = default;
+ ParagraphProperties & operator =(ParagraphProperties const &) = default;
+ ParagraphProperties & operator =(ParagraphProperties &&) = default;
+
+ // Does not compare the starting/ending range, m_sParaStyleName and m_nDropCapLength
+ bool operator==( const ParagraphProperties& );
+
+ sal_Int32 GetListId() const { return m_nListId; }
+ void SetListId( sal_Int32 nId ) { m_nListId = nId; }
+
+ bool IsFrameMode() const { return m_bFrameMode; }
+ void SetFrameMode( bool set = true ) { m_bFrameMode = set; }
+
+ sal_Int32 GetDropCap() const { return m_nDropCap; }
+ void SetDropCap( sal_Int32 nSet ) { m_nDropCap = nSet; }
+
+ sal_Int32 GetLines() const { return m_nLines; }
+ void SetLines( sal_Int32 nSet ) { m_nLines = nSet; }
+
+ sal_Int32 Getw() const { return m_w; }
+ void Setw( sal_Int32 nSet ) { m_w = nSet; }
+
+ sal_Int32 Geth() const { return m_h; }
+ void Seth( sal_Int32 nSet ) { m_h = nSet; }
+
+ css::text::WrapTextMode GetWrap() const { return m_nWrap; }
+ void SetWrap( css::text::WrapTextMode nSet ) { m_nWrap = nSet; }
+
+ sal_Int32 GethAnchor() const { return m_hAnchor; }
+ void SethAnchor( sal_Int32 nSet ) { m_hAnchor = nSet; }
+
+ sal_Int32 GetvAnchor() const { return m_vAnchor; }
+ void SetvAnchor( sal_Int32 nSet ) { m_vAnchor = nSet; }
+
+ sal_Int32 Getx() const { return m_x; }
+ void Setx( sal_Int32 nSet ) { m_x = nSet; m_bxValid = true; }
+ bool IsxValid() const { return m_bxValid; }
+
+ sal_Int32 Gety() const { return m_y; }
+ void Sety( sal_Int32 nSet ) { m_y = nSet; m_byValid = true; }
+ bool IsyValid() const { return m_byValid; }
+
+ void SethSpace( sal_Int32 nSet ) { m_hSpace = nSet; }
+ sal_Int32 GethSpace() const { return m_hSpace; }
+
+ sal_Int32 GetvSpace() const { return m_vSpace; }
+ void SetvSpace( sal_Int32 nSet ) { m_vSpace = nSet; }
+
+ sal_Int32 GethRule() const { return m_hRule; }
+ void SethRule( sal_Int32 nSet ) { m_hRule = nSet; }
+
+ sal_Int32 GetxAlign() const { return m_xAlign; }
+ void SetxAlign( sal_Int32 nSet ) { m_xAlign = nSet; }
+
+ sal_Int32 GetyAlign() const { return m_yAlign; }
+ void SetyAlign( sal_Int32 nSet ) { m_yAlign = nSet; }
+
+ sal_Int8 GetDropCapLength() const { return m_nDropCapLength; }
+ void SetDropCapLength( sal_Int8 nSet ) { m_nDropCapLength = nSet; }
+
+ const css::uno::Reference< css::text::XTextRange >& GetStartingRange() const { return m_xStartingRange; }
+ void SetStartingRange( const css::uno::Reference< css::text::XTextRange >& xSet ) { m_xStartingRange = xSet; }
+
+ const css::uno::Reference< css::text::XTextRange >& GetEndingRange() const { return m_xEndingRange; }
+ void SetEndingRange( const css::uno::Reference< css::text::XTextRange >& xSet ) { m_xEndingRange = xSet; }
+
+ const OUString& GetParaStyleName() const { return m_sParaStyleName; }
+ void SetParaStyleName( const OUString& rSet ) { m_sParaStyleName = rSet; }
+
+ const OUString& GetParaId() const { return m_sParaId; }
+ void SetParaId(const OUString& rSet) { m_sParaId = rSet; }
+
+ void ResetFrameProperties();
+};
+
+typedef tools::SvRef< ParagraphProperties > ParagraphPropertiesPtr;
+
+/*-------------------------------------------------------------------------
+ property map of a stylesheet
+ -----------------------------------------------------------------------*/
+
+#define WW_OUTLINE_MAX sal_Int16( 9 )
+#define WW_OUTLINE_MIN sal_Int16( 0 )
+
+class StyleSheetPropertyMap
+ : public PropertyMap
+ , public ParagraphProperties
+{
+private:
+ sal_Int16 mnListLevel;
+ sal_Int16 mnOutlineLevel;
+
+public:
+ explicit StyleSheetPropertyMap();
+
+ sal_Int16 GetListLevel() const { return mnListLevel; }
+ void SetListLevel( sal_Int16 nLevel ) { mnListLevel = nLevel; }
+
+ sal_Int16 GetOutlineLevel() const { return mnOutlineLevel; }
+ void SetOutlineLevel(sal_Int16 nLevel) { if (nLevel <= WW_OUTLINE_MAX) mnOutlineLevel = nLevel; }
+};
+
+class ParagraphPropertyMap
+ : public PropertyMap
+ , public ParagraphProperties
+{
+public:
+ explicit ParagraphPropertyMap() {}
+};
+
+class TablePropertyMap
+ : public PropertyMap
+{
+public:
+ enum TablePropertyMapTarget
+ {
+ TablePropertyMapTarget_START,
+ CELL_MAR_LEFT = TablePropertyMapTarget_START,
+ CELL_MAR_RIGHT,
+ CELL_MAR_TOP,
+ CELL_MAR_BOTTOM,
+ TABLE_WIDTH,
+ TABLE_WIDTH_TYPE,
+ GAP_HALF,
+ LEFT_MARGIN,
+ HORI_ORIENT,
+ TablePropertyMapTarget_MAX
+ };
+
+private:
+ struct ValidValue
+ {
+ sal_Int32 nValue;
+ bool bValid;
+
+ ValidValue()
+ : nValue( 0 )
+ , bValid( false )
+ {
+ }
+ };
+
+ ValidValue m_aValidValues[TablePropertyMapTarget_MAX];
+
+public:
+ explicit TablePropertyMap() {}
+
+ bool getValue( TablePropertyMapTarget eWhich, sal_Int32& nFill );
+ void setValue( TablePropertyMapTarget eWhich, sal_Int32 nSet );
+
+ virtual void insertTableProperties( const PropertyMap*, const bool bOverwrite = true ) override;
+};
+
+typedef tools::SvRef< TablePropertyMap > TablePropertyMapPtr;
+
+/// Information about a paragraph to be finished after a table end.
+struct TableParagraph
+{
+ css::uno::Reference<css::text::XTextRange> m_rStartParagraph;
+ css::uno::Reference<css::text::XTextRange> m_rEndParagraph;
+ PropertyMapPtr m_pPropertyMap;
+ css::uno::Reference<css::beans::XPropertySet> m_rPropertySet;
+};
+
+typedef std::shared_ptr< std::vector<TableParagraph> > TableParagraphVectorPtr;
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PropertyMapHelper.cxx b/writerfilter/source/dmapper/PropertyMapHelper.cxx
new file mode 100644
index 000000000..a944dc147
--- /dev/null
+++ b/writerfilter/source/dmapper/PropertyMapHelper.cxx
@@ -0,0 +1,98 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/text/TableColumnSeparator.hpp>
+#include "TagLogger.hxx"
+#include "PropertyMapHelper.hxx"
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+void lcl_DumpTableColumnSeparators(const uno::Any& rTableColumnSeparators)
+{
+#ifdef DBG_UTIL
+ uno::Sequence<text::TableColumnSeparator> aSeq;
+ rTableColumnSeparators >>= aSeq;
+
+ TagLogger::getInstance().startElement("property.TableColumnSeparators");
+
+ sal_uInt32 nLength = aSeq.getLength();
+ for (sal_uInt32 n = 0; n < nLength; ++n)
+ {
+ TagLogger::getInstance().startElement("separator");
+
+ TagLogger::getInstance().attribute("position", aSeq[n].Position);
+ TagLogger::getInstance().attribute("visible", sal_uInt32(aSeq[n].IsVisible));
+
+ TagLogger::getInstance().endElement();
+ }
+
+ TagLogger::getInstance().endElement();
+#else
+ (void)rTableColumnSeparators;
+#endif // DBG_UTIL
+}
+
+#ifdef DBG_UTIL
+void lcl_DumpPropertyValues(beans::PropertyValues const& rValues)
+{
+ TagLogger::getInstance().startElement("propertyValues");
+
+ for (beans::PropertyValue const& propVal : rValues)
+ {
+ TagLogger::getInstance().startElement("propertyValue");
+
+ TagLogger::getInstance().attribute("name", propVal.Name);
+
+ try
+ {
+ sal_Int32 aInt = 0;
+ propVal.Value >>= aInt;
+ TagLogger::getInstance().attribute("value", aInt);
+ }
+ catch (...)
+ {
+ }
+
+ if (propVal.Name == "TableColumnSeparators")
+ {
+ lcl_DumpTableColumnSeparators(propVal.Value);
+ }
+
+ TagLogger::getInstance().endElement();
+ }
+ TagLogger::getInstance().endElement();
+}
+
+void lcl_DumpPropertyValueSeq(css::uno::Sequence<css::beans::PropertyValues> const& rPropValSeq)
+{
+ TagLogger::getInstance().startElement("PropertyValueSeq");
+
+ for (auto const& propVal : rPropValSeq)
+ {
+ lcl_DumpPropertyValues(propVal);
+ }
+
+ TagLogger::getInstance().endElement();
+}
+#endif // DBG_UTIL
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/PropertyMapHelper.hxx b/writerfilter/source/dmapper/PropertyMapHelper.hxx
new file mode 100644
index 000000000..472e1bcfa
--- /dev/null
+++ b/writerfilter/source/dmapper/PropertyMapHelper.hxx
@@ -0,0 +1,34 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/PropertyValues.hpp>
+
+namespace writerfilter::dmapper
+{
+void lcl_DumpTableColumnSeparators(const css::uno::Any& rTableColumnSeparators);
+#ifdef DBG_UTIL
+void lcl_DumpPropertyValues(css::beans::PropertyValues const& rValues);
+
+void lcl_DumpPropertyValueSeq(css::uno::Sequence<css::beans::PropertyValues> const& rPropValSeq);
+#endif // DBG_UTIL
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx
new file mode 100644
index 000000000..31c83d5a3
--- /dev/null
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -0,0 +1,513 @@
+/* -*- 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 "SdtHelper.hxx"
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <editeng/unoprnms.hxx>
+#include <sal/log.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
+#include <xmloff/odffields.hxx>
+#include <com/sun/star/text/XTextField.hpp>
+#include "DomainMapper_Impl.hxx"
+#include "StyleSheetTable.hxx"
+#include <officecfg/Office/Writer.hxx>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <ooxml/OOXMLDocument.hxx>
+#include <com/sun/star/xml/xpath/XPathAPI.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+using namespace ::css::xml::xpath;
+using namespace ::comphelper;
+
+/// w:sdt's w:dropDownList doesn't have width, so guess the size based on the longest string.
+static awt::Size lcl_getOptimalWidth(const StyleSheetTablePtr& pStyleSheet,
+ OUString const& rDefault, std::vector<OUString>& rItems)
+{
+ OUString aLongest = rDefault;
+ sal_Int32 nHeight = 0;
+ for (const OUString& rItem : rItems)
+ if (rItem.getLength() > aLongest.getLength())
+ aLongest = rItem;
+
+ MapMode aMap(MapUnit::Map100thMM);
+ OutputDevice* pOut = Application::GetDefaultDevice();
+ pOut->Push(vcl::PushFlags::FONT | vcl::PushFlags::MAPMODE);
+
+ PropertyMapPtr pDefaultCharProps = pStyleSheet->GetDefaultCharProps();
+ vcl::Font aFont(pOut->GetFont());
+ std::optional<PropertyMap::Property> aFontName
+ = pDefaultCharProps->getProperty(PROP_CHAR_FONT_NAME);
+ if (aFontName)
+ aFont.SetFamilyName(aFontName->second.get<OUString>());
+ std::optional<PropertyMap::Property> aHeight = pDefaultCharProps->getProperty(PROP_CHAR_HEIGHT);
+ if (aHeight)
+ {
+ nHeight = aHeight->second.get<double>() * 35; // points -> mm100
+ aFont.SetFontSize(Size(0, nHeight));
+ }
+ pOut->SetFont(aFont);
+ pOut->SetMapMode(aMap);
+ sal_Int32 nWidth = pOut->GetTextWidth(aLongest);
+
+ pOut->Pop();
+
+ // Border: see PDFWriterImpl::drawFieldBorder(), border size is font height / 4,
+ // so additional width / height needed is height / 2.
+ sal_Int32 nBorder = nHeight / 2;
+
+ // Width: space for the text + the square having the dropdown arrow.
+ return { nWidth + nBorder + nHeight, nHeight + nBorder };
+}
+
+SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl,
+ css::uno::Reference<css::uno::XComponentContext> const& xContext)
+ : m_rDM_Impl(rDM_Impl)
+ , m_xComponentContext(xContext)
+ , m_aControlType(SdtControlType::unknown)
+ , m_bHasElements(false)
+ , m_bOutsideAParagraph(false)
+ , m_bPropertiesXMLsLoaded(false)
+{
+}
+
+SdtHelper::~SdtHelper() = default;
+
+void SdtHelper::loadPropertiesXMLs()
+{
+ // Initialize properties xml storage (m_xPropertiesXMLs)
+ uno::Reference<uno::XInterface> xTemp
+ = m_xComponentContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.OOXMLDocumentPropertiesImporter", m_xComponentContext);
+ uno::Reference<document::XOOXMLDocumentPropertiesImporter> xImporter(xTemp, uno::UNO_QUERY);
+ if (!xImporter.is())
+ return;
+
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(
+ xml::dom::DocumentBuilder::create(m_xComponentContext));
+ if (!xDomBuilder.is())
+ return;
+
+ // Load core properties
+ try
+ {
+ auto xCorePropsStream = xImporter->getCorePropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ m_xPropertiesXMLs.insert(
+ { OUString("{6C3C8BC8-F283-45AE-878A-BAB7291924A1}"), // hardcoded id for core props
+ xDomBuilder->parse(xCorePropsStream) });
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading core properties XML");
+ }
+
+ // Load extended properties
+ try
+ {
+ auto xExtPropsStream
+ = xImporter->getExtendedPropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ m_xPropertiesXMLs.insert(
+ { OUString("{6668398D-A668-4E3E-A5EB-62B293D839F1}"), // hardcoded id for extended props
+ xDomBuilder->parse(xExtPropsStream) });
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading extended properties XML");
+ }
+
+ // TODO: some other property items?
+
+ // Add custom XMLs
+ uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmls
+ = m_rDM_Impl.getDocumentReference()->getCustomXmlDomList();
+ uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmlProps
+ = m_rDM_Impl.getDocumentReference()->getCustomXmlDomPropsList();
+ if (aCustomXmls.getLength())
+ {
+ uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+ xXpathAPI->registerNS("ds",
+ "http://schemas.openxmlformats.org/officeDocument/2006/customXml");
+ sal_Int32 nItem = 0;
+ // Hereby we assume that items from getCustomXmlDomList() and getCustomXmlDomPropsList()
+ // are matching each other:
+ // item1.xml -> itemProps1.xml, item2.xml -> itemProps2.xml
+ // This does works practically, but is it true in general?
+ for (const auto& xDoc : aCustomXmls)
+ {
+ // Retrieve storeid from properties xml
+ OUString aStoreId;
+ uno::Reference<XXPathObject> xResult
+ = xXpathAPI->eval(aCustomXmlProps[nItem], "string(/ds:datastoreItem/@ds:itemID)");
+
+ if (xResult.is() && xResult->getString().getLength())
+ {
+ aStoreId = xResult->getString();
+ }
+ else
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: can't fetch storeid for custom doc!");
+ }
+
+ m_xPropertiesXMLs.insert({ aStoreId, xDoc });
+ nItem++;
+ }
+ }
+
+ m_bPropertiesXMLsLoaded = true;
+}
+
+static void lcl_registerNamespaces(std::u16string_view sNamespaceString,
+ const uno::Reference<XXPathAPI>& xXPathAPI)
+{
+ // Split namespaces and register it in XPathAPI
+ auto aNamespaces = string::split(sNamespaceString, ' ');
+ for (const auto& sNamespace : aNamespaces)
+ {
+ // Here we have just one namespace in format "xmlns:ns0='http://someurl'"
+ auto aNamespace = string::split(sNamespace, '=');
+ if (aNamespace.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << sNamespace);
+ continue;
+ }
+
+ auto aNamespaceId = string::split(aNamespace[0], ':');
+ if (aNamespaceId.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << aNamespace[0]);
+ continue;
+ }
+
+ OUString sNamespaceURL = aNamespace[1];
+ sNamespaceURL = string::strip(sNamespaceURL, ' ');
+ sNamespaceURL = string::strip(sNamespaceURL, '\'');
+
+ xXPathAPI->registerNS(aNamespaceId[1], sNamespaceURL);
+ }
+}
+
+std::optional<OUString> SdtHelper::getValueFromDataBinding()
+{
+ // No xpath - nothing to do
+ if (m_sDataBindingXPath.isEmpty())
+ return {};
+
+ // Load properties XMLs
+ if (!m_bPropertiesXMLsLoaded)
+ loadPropertiesXMLs();
+
+ uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+
+ lcl_registerNamespaces(m_sDataBindingPrefixMapping, xXpathAPI);
+
+ // Find storage by store id and eval xpath there
+ const auto& aSourceIt = m_xPropertiesXMLs.find(m_sDataBindingStoreItemID);
+ if (aSourceIt != m_xPropertiesXMLs.end())
+ {
+ uno::Reference<XXPathObject> xResult
+ = xXpathAPI->eval(aSourceIt->second, m_sDataBindingXPath);
+
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength()
+ && xResult->getString().getLength())
+ {
+ return xResult->getString();
+ }
+ }
+
+ // Nothing found? Try to iterate storages and eval xpath
+ for (const auto& aSource : m_xPropertiesXMLs)
+ {
+ uno::Reference<XXPathObject> xResult = xXpathAPI->eval(aSource.second, m_sDataBindingXPath);
+
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength()
+ && xResult->getString().getLength())
+ {
+ return xResult->getString();
+ }
+ }
+
+ // No data
+ return {};
+}
+
+void SdtHelper::createDropDownControl()
+{
+ assert(getControlType() == SdtControlType::dropDown);
+
+ const bool bDropDown
+ = officecfg::Office::Writer::Filter::Import::DOCX::ImportComboBoxAsDropDown::get();
+ const OUString aDefaultText = m_aSdtTexts.makeStringAndClear();
+
+ if (bDropDown)
+ {
+ // create field
+ uno::Reference<css::text::XTextField> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.DropDown"),
+ uno::UNO_QUERY);
+
+ const auto it = std::find_if(
+ m_aDropDownItems.begin(), m_aDropDownItems.end(),
+ [aDefaultText](const OUString& item) -> bool { return !item.compareTo(aDefaultText); });
+
+ if (m_aDropDownItems.end() == it)
+ {
+ m_aDropDownItems.push_back(aDefaultText);
+ }
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("SelectedItem", uno::Any(aDefaultText));
+ xPropertySet->setPropertyValue("Items",
+ uno::Any(comphelper::containerToSequence(m_aDropDownItems)));
+
+ // add it into document
+ m_rDM_Impl.appendTextContent(xControlModel, uno::Sequence<beans::PropertyValue>());
+
+ m_bHasElements = true;
+ }
+ else
+ {
+ // create control
+ uno::Reference<awt::XControlModel> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.form.component.ComboBox"),
+ uno::UNO_QUERY);
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("DefaultText", uno::Any(aDefaultText));
+ xPropertySet->setPropertyValue("Dropdown", uno::Any(true));
+ xPropertySet->setPropertyValue("StringItemList",
+ uno::Any(comphelper::containerToSequence(m_aDropDownItems)));
+
+ // add it into document
+ createControlShape(
+ lcl_getOptimalWidth(m_rDM_Impl.GetStyleSheetTable(), aDefaultText, m_aDropDownItems),
+ xControlModel, uno::Sequence<beans::PropertyValue>());
+ }
+
+ // clean up
+ clear();
+}
+
+void SdtHelper::createPlainTextControl()
+{
+ assert(getControlType() == SdtControlType::plainText);
+
+ OUString aDefaultText = m_aSdtTexts.makeStringAndClear();
+
+ // create field
+ uno::Reference<css::text::XTextField> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.Input"),
+ uno::UNO_QUERY);
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ aDefaultText = *oData;
+
+ xPropertySet->setPropertyValue("Content", uno::Any(aDefaultText));
+
+ // add it into document
+ m_rDM_Impl.appendTextContent(xControlModel, uno::Sequence<beans::PropertyValue>());
+
+ // Store all unused sdt parameters from grabbag
+ xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::Any(getInteropGrabBagAndClear()));
+
+ // clean up
+ clear();
+}
+
+void SdtHelper::createDateContentControl()
+{
+ if (!m_xDateFieldStartRange.is())
+ return;
+
+ uno::Reference<text::XTextCursor> xCrsr;
+ if (m_rDM_Impl.HasTopText())
+ {
+ uno::Reference<text::XTextAppend> xTextAppend = m_rDM_Impl.GetTopTextAppend();
+ if (xTextAppend.is())
+ {
+ xCrsr = xTextAppend->createTextCursorByRange(xTextAppend);
+ }
+ }
+ if (!xCrsr.is())
+ return;
+
+ try
+ {
+ xCrsr->gotoRange(m_xDateFieldStartRange, false);
+ bool bIsInTable = (m_rDM_Impl.hasTableManager() && m_rDM_Impl.getTableManager().isInTable())
+ || (m_rDM_Impl.m_nTableDepth > 0);
+ if (bIsInTable)
+ xCrsr->goRight(1, false);
+ xCrsr->gotoEnd(true);
+ }
+ catch (uno::Exception&)
+ {
+ OSL_ENSURE(false, "Cannot get the right text range for date field");
+ return;
+ }
+
+ uno::Reference<uno::XInterface> xFieldInterface
+ = m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.Fieldmark");
+ uno::Reference<text::XFormField> xFormField(xFieldInterface, uno::UNO_QUERY);
+ uno::Reference<text::XTextContent> xToInsert(xFormField, uno::UNO_QUERY);
+ if (!(xFormField.is() && xToInsert.is()))
+ return;
+
+ xToInsert->attach(uno::Reference<text::XTextRange>(xCrsr, uno::UNO_QUERY_THROW));
+ xFormField->setFieldType(ODF_FORMDATE);
+ uno::Reference<container::XNameContainer> xNameCont = xFormField->getParameters();
+ if (xNameCont.is())
+ {
+ OUString sDateFormat = m_sDateFormat.makeStringAndClear();
+
+ // Replace quotation mark used for marking static strings in date format
+ sDateFormat = sDateFormat.replaceAll("'", "\"");
+ xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT, uno::Any(sDateFormat));
+ xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT_LANGUAGE,
+ uno::Any(m_sLocale.makeStringAndClear()));
+ }
+ OUString sFullDate = m_sDate.makeStringAndClear();
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ sFullDate = *oData;
+
+ if (!sFullDate.isEmpty())
+ {
+ sal_Int32 nTimeSep = sFullDate.indexOf("T");
+ if (nTimeSep != -1)
+ sFullDate = sFullDate.copy(0, nTimeSep);
+ xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, uno::Any(sFullDate));
+ }
+
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(m_rDM_Impl.GetTextDocument(),
+ uno::UNO_QUERY);
+ uno::Reference<util::XRefreshable> xRefreshable(xTextFieldsSupplier->getTextFields(),
+ uno::UNO_QUERY);
+ xRefreshable->refresh();
+
+ // Store all unused sdt parameters from grabbag
+ xNameCont->insertByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::Any(getInteropGrabBagAndClear()));
+
+ clear();
+}
+
+void SdtHelper::createControlShape(awt::Size aSize,
+ uno::Reference<awt::XControlModel> const& xControlModel,
+ const uno::Sequence<beans::PropertyValue>& rGrabBag)
+{
+ uno::Reference<drawing::XControlShape> xControlShape(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.drawing.ControlShape"),
+ uno::UNO_QUERY);
+ xControlShape->setSize(aSize);
+ xControlShape->setControl(xControlModel);
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::CENTER));
+
+ if (rGrabBag.hasElements())
+ xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG, uno::Any(rGrabBag));
+
+ uno::Reference<text::XTextContent> xTextContent(xControlShape, uno::UNO_QUERY);
+ m_rDM_Impl.appendTextContent(xTextContent, uno::Sequence<beans::PropertyValue>());
+ m_bHasElements = true;
+}
+
+void SdtHelper::appendToInteropGrabBag(const beans::PropertyValue& rValue)
+{
+ m_aGrabBag.push_back(rValue);
+}
+
+uno::Sequence<beans::PropertyValue> SdtHelper::getInteropGrabBagAndClear()
+{
+ uno::Sequence<beans::PropertyValue> aRet = comphelper::containerToSequence(m_aGrabBag);
+ m_aGrabBag.clear();
+ return aRet;
+}
+
+bool SdtHelper::isInteropGrabBagEmpty() const { return m_aGrabBag.empty(); }
+
+sal_Int32 SdtHelper::getInteropGrabBagSize() const { return m_aGrabBag.size(); }
+
+bool SdtHelper::containedInInteropGrabBag(const OUString& rValueName)
+{
+ return std::any_of(
+ m_aGrabBag.begin(), m_aGrabBag.end(),
+ [&rValueName](const beans::PropertyValue& i) { return i.Name == rValueName; });
+}
+
+void SdtHelper::SetShowingPlcHdr() { m_bShowingPlcHdr = true; }
+
+bool SdtHelper::GetShowingPlcHdr() const { return m_bShowingPlcHdr; }
+
+void SdtHelper::SetChecked() { m_bChecked = true; }
+
+bool SdtHelper::GetChecked() const { return m_bChecked; }
+
+void SdtHelper::SetCheckedState(const OUString& rCheckedState) { m_aCheckedState = rCheckedState; }
+
+OUString SdtHelper::GetCheckedState() const { return m_aCheckedState; }
+
+void SdtHelper::SetUncheckedState(const OUString& rUncheckedState)
+{
+ m_aUncheckedState = rUncheckedState;
+}
+
+OUString SdtHelper::GetUncheckedState() const { return m_aUncheckedState; }
+
+void SdtHelper::clear()
+{
+ m_aDropDownItems.clear();
+ m_aDropDownDisplayTexts.clear();
+ setControlType(SdtControlType::unknown);
+ m_sDataBindingPrefixMapping.clear();
+ m_sDataBindingXPath.clear();
+ m_sDataBindingStoreItemID.clear();
+ m_aGrabBag.clear();
+ m_bShowingPlcHdr = false;
+ m_bChecked = false;
+ m_aCheckedState.clear();
+ m_aUncheckedState.clear();
+}
+
+void SdtHelper::SetPlaceholderDocPart(const OUString& rPlaceholderDocPart)
+{
+ m_aPlaceholderDocPart = rPlaceholderDocPart;
+}
+
+OUString SdtHelper::GetPlaceholderDocPart() const { return m_aPlaceholderDocPart; }
+
+void SdtHelper::SetColor(const OUString& rColor) { m_aColor = rColor; }
+
+OUString SdtHelper::GetColor() const { return m_aColor; }
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx
new file mode 100644
index 000000000..11bdfdcd1
--- /dev/null
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -0,0 +1,208 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <vector>
+#include <optional>
+#include <unordered_map>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star
+{
+namespace uno
+{
+class XComponentContext;
+}
+namespace awt
+{
+struct Size;
+class XControlModel;
+}
+}
+
+namespace writerfilter::dmapper
+{
+class DomainMapper_Impl;
+
+enum class SdtControlType
+{
+ datePicker,
+ dropDown,
+ plainText,
+ richText,
+ checkBox,
+ picture,
+ unsupported, // Sdt block is defined, but we still do not support such type of field
+ unknown
+};
+
+/**
+ * Helper to create form controls from w:sdt tokens.
+ *
+ * w:sdt tokens can't be imported as form fields, as w:sdt supports
+ * e.g. date picking as well.
+ */
+class SdtHelper final : public virtual SvRefBase
+{
+ DomainMapper_Impl& m_rDM_Impl;
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+
+ /// Items of the drop-down control: <w:listItem w:value="...">.
+ std::vector<OUString> m_aDropDownItems;
+ /// Display texts of a drop-down control: <w:listItem w:displayText="...">.
+ std::vector<OUString> m_aDropDownDisplayTexts;
+ /// Type of sdt control
+ SdtControlType m_aControlType;
+ /// Pieces of the default text -- currently used only by the dropdown control.
+ OUStringBuffer m_aSdtTexts;
+ /// Date ISO string contained in the w:date element, used by the date control.
+ OUStringBuffer m_sDate;
+ /// Date format string as it comes from the ooxml document.
+ OUStringBuffer m_sDateFormat;
+
+ /// <w:dataBinding w:prefixMappings="">
+ OUString m_sDataBindingPrefixMapping;
+ /// <w:dataBinding w:xpath="">
+ OUString m_sDataBindingXPath;
+ /// <w:dataBinding w:storeItemID="">
+ OUString m_sDataBindingStoreItemID;
+
+ /// Start range of the date field
+ css::uno::Reference<css::text::XTextRange> m_xDateFieldStartRange;
+ /// Locale string as it comes from the ooxml document.
+ OUStringBuffer m_sLocale;
+ /// Grab bag to store unsupported SDTs, aiming to save them back on export.
+ std::vector<css::beans::PropertyValue> m_aGrabBag;
+
+ bool m_bHasElements;
+ /// The last stored SDT element is outside paragraphs.
+ bool m_bOutsideAParagraph;
+
+ /// Storage for all properties documents as xml::dom::XDocument for later querying xpath for data
+ std::unordered_map<OUString, css::uno::Reference<css::xml::dom::XDocument>> m_xPropertiesXMLs;
+
+ /// Check if m_xPropertiesXMLs is initialized and loaded (need extra flag to distinguish
+ /// empty sequence from not yet initialized)
+ bool m_bPropertiesXMLsLoaded;
+
+ /// Current contents are placeholder text.
+ bool m_bShowingPlcHdr = false;
+
+ /// If this is a checkbox, is the checkbox checked?
+ bool m_bChecked = false;
+
+ /// If this is a checkbox, the value of a checked checkbox.
+ OUString m_aCheckedState;
+
+ /// If this is a checkbox, the value of an unchecked checkbox.
+ OUString m_aUncheckedState;
+
+ /// Create and append the drawing::XControlShape, containing the various models.
+ void createControlShape(css::awt::Size aSize,
+ css::uno::Reference<css::awt::XControlModel> const& xControlModel,
+ const css::uno::Sequence<css::beans::PropertyValue>& rGrabBag);
+
+ std::optional<OUString> getValueFromDataBinding();
+
+ void loadPropertiesXMLs();
+
+ /// <w:placeholder>'s <w:docPart w:val="...">.
+ OUString m_aPlaceholderDocPart;
+
+ /// <w:sdtPr>'s <w15:color w:val="...">.
+ OUString m_aColor;
+
+public:
+ explicit SdtHelper(DomainMapper_Impl& rDM_Impl,
+ css::uno::Reference<css::uno::XComponentContext> const& xContext);
+ ~SdtHelper() override;
+
+ std::vector<OUString>& getDropDownItems() { return m_aDropDownItems; }
+ std::vector<OUString>& getDropDownDisplayTexts() { return m_aDropDownDisplayTexts; }
+ OUStringBuffer& getSdtTexts() { return m_aSdtTexts; }
+
+ OUStringBuffer& getDate() { return m_sDate; }
+
+ OUStringBuffer& getDateFormat() { return m_sDateFormat; }
+
+ void setDataBindingPrefixMapping(const OUString& sValue)
+ {
+ m_sDataBindingPrefixMapping = sValue;
+ }
+ OUString GetDataBindingPrefixMapping() const { return m_sDataBindingPrefixMapping; }
+
+ void setDataBindingXPath(const OUString& sValue) { m_sDataBindingXPath = sValue; }
+ OUString GetDataBindingXPath() const { return m_sDataBindingXPath; }
+
+ void setDataBindingStoreItemID(const OUString& sValue) { m_sDataBindingStoreItemID = sValue; }
+ OUString GetDataBindingStoreItemID() const { return m_sDataBindingStoreItemID; }
+
+ void setDateFieldStartRange(const css::uno::Reference<css::text::XTextRange>& xStartRange)
+ {
+ m_xDateFieldStartRange = xStartRange;
+ }
+
+ OUStringBuffer& getLocale() { return m_sLocale; }
+ /// If createControlShape() was ever called.
+ bool hasElements() const { return m_bHasElements; }
+
+ void setOutsideAParagraph(bool bOutsideAParagraph)
+ {
+ m_bOutsideAParagraph = bOutsideAParagraph;
+ }
+
+ bool isOutsideAParagraph() const { return m_bOutsideAParagraph; }
+
+ SdtControlType getControlType() { return m_aControlType; }
+ void setControlType(SdtControlType aType) { m_aControlType = aType; }
+
+ /// Create drop-down control from w:sdt's w:dropDownList.
+ void createDropDownControl();
+ /// Create date control from w:sdt's w:date.
+ void createDateContentControl();
+
+ void createPlainTextControl();
+
+ void appendToInteropGrabBag(const css::beans::PropertyValue& rValue);
+ css::uno::Sequence<css::beans::PropertyValue> getInteropGrabBagAndClear();
+ bool isInteropGrabBagEmpty() const;
+ bool containedInInteropGrabBag(const OUString& rValueName);
+ sal_Int32 getInteropGrabBagSize() const;
+
+ void SetShowingPlcHdr();
+ bool GetShowingPlcHdr() const;
+
+ void SetChecked();
+ bool GetChecked() const;
+ void SetCheckedState(const OUString& rCheckedState);
+ OUString GetCheckedState() const;
+ void SetUncheckedState(const OUString& rUncheckedState);
+ OUString GetUncheckedState() const;
+
+ /// Clear all collected attributes for further reuse
+ void clear();
+
+ void SetPlaceholderDocPart(const OUString& rPlaceholderDocPart);
+ OUString GetPlaceholderDocPart() const;
+
+ void SetColor(const OUString& rColor);
+ OUString GetColor() const;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SectionColumnHandler.cxx b/writerfilter/source/dmapper/SectionColumnHandler.cxx
new file mode 100644
index 000000000..9fed9c34a
--- /dev/null
+++ b/writerfilter/source/dmapper/SectionColumnHandler.cxx
@@ -0,0 +1,90 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "SectionColumnHandler.hxx"
+#include "ConversionHelper.hxx"
+#include <ooxml/resourceids.hxx>
+#include <osl/diagnose.h>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+SectionColumnHandler::SectionColumnHandler()
+ : LoggedProperties("SectionColumnHandler")
+ , m_bEqualWidth(false)
+ , m_nSpace(1270) // 720 twips
+ , m_nNum(0)
+ , m_bSep(false)
+{
+ m_aTempColumn.nWidth = m_aTempColumn.nSpace = 0;
+}
+
+SectionColumnHandler::~SectionColumnHandler() {}
+
+void SectionColumnHandler::lcl_attribute(Id rName, Value& rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch (rName)
+ {
+ case NS_ooxml::LN_CT_Columns_equalWidth:
+ m_bEqualWidth = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_Columns_space:
+ m_nSpace = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Columns_num:
+ m_nNum = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Columns_sep:
+ m_bSep = (nIntValue != 0);
+ break;
+
+ case NS_ooxml::LN_CT_Column_w:
+ m_aTempColumn.nWidth = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Column_space:
+ m_aTempColumn.nSpace = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+ default:
+ OSL_FAIL("SectionColumnHandler: unknown attribute");
+ }
+}
+
+void SectionColumnHandler::lcl_sprm(Sprm& rSprm)
+{
+ switch (rSprm.getId())
+ {
+ case NS_ooxml::LN_CT_Columns_col:
+ {
+ m_aTempColumn.nWidth = m_aTempColumn.nSpace = 0;
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ m_aCols.push_back(m_aTempColumn);
+ }
+ }
+ break;
+ default:
+ OSL_FAIL("SectionColumnHandler: unknown sprm");
+ }
+}
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SectionColumnHandler.hxx b/writerfilter/source/dmapper/SectionColumnHandler.hxx
new file mode 100644
index 000000000..cbef67460
--- /dev/null
+++ b/writerfilter/source/dmapper/SectionColumnHandler.hxx
@@ -0,0 +1,62 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+
+namespace writerfilter::dmapper
+{
+struct Column_
+{
+ sal_Int32 nWidth;
+ sal_Int32 nSpace;
+};
+
+
+class SectionColumnHandler : public LoggedProperties
+{
+ bool m_bEqualWidth;
+ sal_Int32 m_nSpace;
+ sal_Int32 m_nNum;
+ bool m_bSep;
+ std::vector<Column_> m_aCols;
+
+ Column_ m_aTempColumn;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ SectionColumnHandler();
+ virtual ~SectionColumnHandler() override;
+
+ bool IsEqualWidth() const { return m_bEqualWidth; }
+ sal_Int32 GetSpace() const { return m_nSpace; }
+ sal_Int32 GetNum() const { return m_nNum; }
+ bool IsSeparator() const { return m_bSep; }
+
+ const std::vector<Column_>& GetColumns() const { return m_aCols;}
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SettingsTable.cxx b/writerfilter/source/dmapper/SettingsTable.cxx
new file mode 100644
index 000000000..45dc67b9f
--- /dev/null
+++ b/writerfilter/source/dmapper/SettingsTable.cxx
@@ -0,0 +1,692 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SettingsTable.hxx"
+#include "DocumentProtection.hxx"
+#include "TagLogger.hxx"
+#include "WriteProtection.hxx"
+
+#include <vector>
+
+#include <rtl/ustring.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include "ConversionHelper.hxx"
+#include "DomainMapper.hxx"
+#include "util.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter {
+namespace
+{
+/// Maps OOXML <w:zoom w:val="..."> to SvxZoomType.
+sal_Int16 lcl_GetZoomType(Id nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_Value_doc_ST_Zoom_fullPage:
+ return sal_Int16(SvxZoomType::WHOLEPAGE);
+ case NS_ooxml::LN_Value_doc_ST_Zoom_bestFit:
+ return sal_Int16(SvxZoomType::PAGEWIDTH);
+ case NS_ooxml::LN_Value_doc_ST_Zoom_textFit:
+ return sal_Int16(SvxZoomType::OPTIMAL);
+ }
+
+ return sal_Int16(SvxZoomType::PERCENT);
+}
+}
+
+namespace dmapper
+{
+
+struct SettingsTable_Impl
+{
+ int m_nDefaultTabStop;
+
+ bool m_bRecordChanges;
+ bool m_bShowInsDelChanges;
+ bool m_bShowFormattingChanges;
+ bool m_bShowMarkupChanges;
+ bool m_bLinkStyles;
+ sal_Int16 m_nZoomFactor;
+ sal_Int16 m_nZoomType = 0;
+ sal_Int32 m_nWordCompatibilityMode;
+ Id m_nView;
+ bool m_bEvenAndOddHeaders;
+ bool m_bUsePrinterMetrics;
+ bool embedTrueTypeFonts;
+ bool embedSystemFonts;
+ bool m_bDoNotUseHTMLParagraphAutoSpacing;
+ bool m_bNoColumnBalance;
+ bool m_bAutoHyphenation;
+ bool m_bNoHyphenateCaps;
+ sal_Int16 m_nHyphenationZone;
+ bool m_bWidowControl;
+ bool m_bLongerSpaceSequence;
+ bool m_bSplitPgBreakAndParaMark;
+ bool m_bMirrorMargin;
+ bool m_bDoNotExpandShiftReturn;
+ bool m_bDisplayBackgroundShape;
+ bool m_bNoLeading = false;
+ OUString m_sDecimalSymbol;
+ OUString m_sListSeparator;
+
+ uno::Sequence<beans::PropertyValue> m_pThemeFontLangProps;
+
+ std::vector<beans::PropertyValue> m_aCompatSettings;
+ uno::Sequence<beans::PropertyValue> m_pCurrentCompatSetting;
+ OUString m_sCurrentDatabaseDataSource;
+
+ std::shared_ptr<DocumentProtection> m_pDocumentProtection;
+ std::shared_ptr<WriteProtection> m_pWriteProtection;
+ bool m_bGutterAtTop = false;
+
+ SettingsTable_Impl() :
+ m_nDefaultTabStop( 720 ) //default is 1/2 in
+ , m_bRecordChanges(false)
+ , m_bShowInsDelChanges(true)
+ , m_bShowFormattingChanges(false)
+ , m_bShowMarkupChanges(true)
+ , m_bLinkStyles(false)
+ , m_nZoomFactor(0)
+ , m_nWordCompatibilityMode(-1)
+ , m_nView(0)
+ , m_bEvenAndOddHeaders(false)
+ , m_bUsePrinterMetrics(false)
+ , embedTrueTypeFonts(false)
+ , embedSystemFonts(false)
+ , m_bDoNotUseHTMLParagraphAutoSpacing(false)
+ , m_bNoColumnBalance(false)
+ , m_bAutoHyphenation(false)
+ , m_bNoHyphenateCaps(false)
+ , m_nHyphenationZone(0)
+ , m_bWidowControl(false)
+ , m_bLongerSpaceSequence(false)
+ , m_bSplitPgBreakAndParaMark(false)
+ , m_bMirrorMargin(false)
+ , m_bDoNotExpandShiftReturn(false)
+ , m_bDisplayBackgroundShape(false)
+ , m_sDecimalSymbol(".")
+ , m_sListSeparator(",")
+ , m_pThemeFontLangProps(3)
+ , m_pCurrentCompatSetting(3)
+ {}
+
+};
+
+SettingsTable::SettingsTable(const DomainMapper& rDomainMapper)
+: LoggedProperties("SettingsTable")
+, LoggedTable("SettingsTable")
+, m_pImpl( new SettingsTable_Impl )
+{
+ if (rDomainMapper.IsRTFImport())
+ {
+ // HTML paragraph auto-spacing is opt-in for RTF, opt-out for OOXML.
+ m_pImpl->m_bDoNotUseHTMLParagraphAutoSpacing = true;
+ // Longer space sequence is opt-in for RTF, and not in OOXML.
+ m_pImpl->m_bLongerSpaceSequence = true;
+ }
+ m_pImpl->m_pDocumentProtection = std::make_shared<DocumentProtection>();
+ m_pImpl->m_pWriteProtection = std::make_shared<WriteProtection>();
+}
+
+SettingsTable::~SettingsTable()
+{
+}
+
+void SettingsTable::lcl_attribute(Id nName, Value & val)
+{
+ int nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ switch(nName)
+ {
+ case NS_ooxml::LN_CT_Zoom_percent:
+ m_pImpl->m_nZoomFactor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Zoom_val:
+ m_pImpl->m_nZoomType = lcl_GetZoomType(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Language_val:
+ m_pImpl->m_pThemeFontLangProps.getArray()[0]
+ = comphelper::makePropertyValue("val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Language_eastAsia:
+ m_pImpl->m_pThemeFontLangProps.getArray()[1]
+ = comphelper::makePropertyValue("eastAsia", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Language_bidi:
+ m_pImpl->m_pThemeFontLangProps.getArray()[2]
+ = comphelper::makePropertyValue("bidi", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_View_val:
+ m_pImpl->m_nView = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_CompatSetting_name:
+ m_pImpl->m_pCurrentCompatSetting.getArray()[0]
+ = comphelper::makePropertyValue("name", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_CompatSetting_uri:
+ m_pImpl->m_pCurrentCompatSetting.getArray()[1]
+ = comphelper::makePropertyValue("uri", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_CompatSetting_val:
+ m_pImpl->m_pCurrentCompatSetting.getArray()[2]
+ = comphelper::makePropertyValue("val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_TrackChangesView_insDel:
+ m_pImpl->m_bShowInsDelChanges = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_TrackChangesView_formatting:
+ m_pImpl->m_bShowFormattingChanges = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_TrackChangesView_markup:
+ m_pImpl->m_bShowMarkupChanges = (nIntValue != 0);
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void SettingsTable::lcl_sprm(Sprm& rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = pValue->getInt();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_Settings_zoom: // 92469;
+ case NS_ooxml::LN_CT_Settings_proofState: // 92489;
+ case NS_ooxml::LN_CT_Settings_attachedTemplate: // 92491;
+ case NS_ooxml::LN_CT_Settings_hdrShapeDefaults: // 92544;
+ case NS_ooxml::LN_CT_Settings_footnotePr: // 92545;
+ case NS_ooxml::LN_CT_Settings_endnotePr: // 92546;
+ case NS_ooxml::LN_CT_Settings_compat: // 92547;
+ case NS_ooxml::LN_CT_Settings_themeFontLang: // 92552;
+ case NS_ooxml::LN_CT_Settings_shapeDefaults: // 92560;
+ case NS_ooxml::LN_CT_Settings_view:
+ //PropertySetValues - need to be resolved
+ {
+ resolveSprmProps(*this, rSprm);
+ }
+ break;
+ case NS_ooxml::LN_CT_Settings_stylePaneFormatFilter: // 92493;
+ break;
+ case NS_ooxml::LN_CT_Settings_defaultTabStop: // 92505;
+ m_pImpl->m_nDefaultTabStop = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_linkStyles: // 92663;
+ m_pImpl->m_bLinkStyles = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_evenAndOddHeaders:
+ m_pImpl->m_bEvenAndOddHeaders = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_noPunctuationKerning: // 92526;
+ break;
+ case NS_ooxml::LN_CT_Settings_characterSpacingControl: // 92527;
+ // doNotCompress, compressPunctuation, compressPunctuationAndJapaneseKana
+ break;
+ case NS_ooxml::LN_CT_Settings_doNotIncludeSubdocsInStats: // 92554; // Do Not Include Content in Text Boxes, Footnotes, and Endnotes in Document Statistics)
+ break;
+ case NS_ooxml::LN_CT_Settings_decimalSymbol: // 92562;
+ m_pImpl->m_sDecimalSymbol = pValue->getString();
+ break;
+ case NS_ooxml::LN_CT_Settings_listSeparator: // 92563;
+ m_pImpl->m_sListSeparator = pValue->getString();
+ break;
+ case NS_ooxml::LN_CT_Settings_rsids: // 92549; revision save Ids - probably not necessary
+ break;
+ case NS_ooxml::LN_CT_Settings_hyphenationZone: // 92508;
+ m_pImpl->m_nHyphenationZone = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_useFELayout: // 92422;
+ // useFELayout (Do Not Bypass East Asian/Complex Script Layout Code - support of old versions of Word - ignored)
+ break;
+ case NS_ooxml::LN_CT_Settings_trackRevisions:
+ {
+ m_pImpl->m_bRecordChanges = bool(rSprm.getValue( )->getInt( ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_Settings_revisionView:
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_CT_Settings_documentProtection:
+ resolveSprmProps(*(m_pImpl->m_pDocumentProtection), rSprm);
+ break;
+ case NS_ooxml::LN_CT_Settings_writeProtection:
+ resolveSprmProps(*(m_pImpl->m_pWriteProtection), rSprm);
+ break;
+ case NS_ooxml::LN_CT_Compat_usePrinterMetrics:
+ m_pImpl->m_bUsePrinterMetrics = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_embedTrueTypeFonts:
+ m_pImpl->embedTrueTypeFonts = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Settings_embedSystemFonts:
+ m_pImpl->embedSystemFonts = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Compat_doNotUseHTMLParagraphAutoSpacing:
+ m_pImpl->m_bDoNotUseHTMLParagraphAutoSpacing = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_splitPgBreakAndParaMark:
+ m_pImpl->m_bSplitPgBreakAndParaMark = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_mirrorMargins:
+ m_pImpl->m_bMirrorMargin = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_mailMerge:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_MailMerge_query:
+ {
+ // try to get the "database.table" name from the query saved previously
+ OUString sVal = pValue->getString();
+ if ( sVal.endsWith("$") && sVal.indexOf(".dbo.") > 0 )
+ {
+ sal_Int32 nSpace = sVal.lastIndexOf(' ');
+ sal_Int32 nDbo = sVal.lastIndexOf(".dbo.");
+ if ( nSpace > 0 && nSpace < nDbo - 1 )
+ {
+ m_pImpl->m_sCurrentDatabaseDataSource = OUString::Concat(sVal.subView(nSpace + 1, nDbo - nSpace - 1)) +
+ sVal.subView(nDbo + 4, sVal.getLength() - nDbo - 5);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Compat_compatSetting:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+
+ beans::PropertyValue aValue;
+ aValue.Name = "compatSetting";
+ aValue.Value <<= m_pImpl->m_pCurrentCompatSetting;
+ m_pImpl->m_aCompatSettings.push_back(aValue);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Compat_noColumnBalance:
+ m_pImpl->m_bNoColumnBalance = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_autoHyphenation:
+ m_pImpl->m_bAutoHyphenation = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_doNotHyphenateCaps:
+ m_pImpl->m_bNoHyphenateCaps = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_widowControl:
+ m_pImpl->m_bWidowControl = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_longerSpaceSequence:
+ m_pImpl->m_bLongerSpaceSequence = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_doNotExpandShiftReturn:
+ m_pImpl->m_bDoNotExpandShiftReturn = true;
+ break;
+ case NS_ooxml::LN_CT_Settings_displayBackgroundShape:
+ m_pImpl->m_bDisplayBackgroundShape = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_noLeading:
+ m_pImpl->m_bNoLeading = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Settings_gutterAtTop:
+ m_pImpl->m_bGutterAtTop = nIntValue != 0;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void SettingsTable::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+ ref->resolve(*this);
+}
+
+//returns default TabStop in 1/100th mm
+int SettingsTable::GetDefaultTabStop() const
+{
+ return ConversionHelper::convertTwipToMM100( m_pImpl->m_nDefaultTabStop );
+}
+
+bool SettingsTable::GetLinkStyles() const
+{
+ return m_pImpl->m_bLinkStyles;
+}
+
+sal_Int16 SettingsTable::GetZoomFactor() const
+{
+ return m_pImpl->m_nZoomFactor;
+}
+
+sal_Int16 SettingsTable::GetZoomType() const { return m_pImpl->m_nZoomType; }
+
+Id SettingsTable::GetView() const
+{
+ return m_pImpl->m_nView;
+}
+
+bool SettingsTable::GetUsePrinterMetrics() const
+{
+ return m_pImpl->m_bUsePrinterMetrics;
+}
+
+bool SettingsTable::GetEvenAndOddHeaders() const
+{
+ return m_pImpl->m_bEvenAndOddHeaders;
+}
+
+bool SettingsTable::GetEmbedTrueTypeFonts() const
+{
+ return m_pImpl->embedTrueTypeFonts;
+}
+
+bool SettingsTable::GetEmbedSystemFonts() const
+{
+ return m_pImpl->embedSystemFonts;
+}
+
+bool SettingsTable::GetDoNotUseHTMLParagraphAutoSpacing() const
+{
+ return m_pImpl->m_bDoNotUseHTMLParagraphAutoSpacing;
+}
+
+bool SettingsTable::GetNoColumnBalance() const
+{
+ return m_pImpl->m_bNoColumnBalance;
+}
+
+bool SettingsTable::GetSplitPgBreakAndParaMark() const
+{
+ return m_pImpl->m_bSplitPgBreakAndParaMark;
+}
+
+bool SettingsTable::GetMirrorMarginSettings() const
+{
+ return m_pImpl->m_bMirrorMargin;
+}
+
+bool SettingsTable::GetDisplayBackgroundShape() const
+{
+ return m_pImpl->m_bDisplayBackgroundShape;
+}
+
+bool SettingsTable::GetDoNotExpandShiftReturn() const
+{
+ return m_pImpl->m_bDoNotExpandShiftReturn;
+}
+
+bool SettingsTable::GetProtectForm() const
+{
+ return m_pImpl->m_pDocumentProtection->getProtectForm()
+ && m_pImpl->m_pDocumentProtection->getEnforcement();
+}
+
+bool SettingsTable::GetReadOnly() const
+{
+ return m_pImpl->m_pWriteProtection->getRecommended()
+ || (m_pImpl->m_pDocumentProtection->getReadOnly()
+ && m_pImpl->m_pDocumentProtection->getEnforcement());
+}
+
+bool SettingsTable::GetNoHyphenateCaps() const
+{
+ return m_pImpl->m_bNoHyphenateCaps;
+}
+
+sal_Int16 SettingsTable::GetHyphenationZone() const
+{
+ return m_pImpl->m_nHyphenationZone;
+}
+
+const OUString & SettingsTable::GetDecimalSymbol() const
+{
+ return m_pImpl->m_sDecimalSymbol;
+}
+
+const OUString & SettingsTable::GetListSeparator() const
+{
+ return m_pImpl->m_sListSeparator;
+}
+
+
+uno::Sequence<beans::PropertyValue> const & SettingsTable::GetThemeFontLangProperties() const
+{
+ return m_pImpl->m_pThemeFontLangProps;
+}
+
+uno::Sequence<beans::PropertyValue> SettingsTable::GetCompatSettings() const
+{
+ if ( GetWordCompatibilityMode() == -1 )
+ {
+ // the default value for an undefined compatibilityMode is 12 (Word 2007)
+ uno::Sequence<beans::PropertyValue> aCompatSetting( comphelper::InitPropertySequence({
+ { "name", uno::Any(OUString("compatibilityMode")) },
+ { "uri", uno::Any(OUString("http://schemas.microsoft.com/office/word")) },
+ { "val", uno::Any(OUString("12")) } //12: Use word processing features specified in ECMA-376. This is the default.
+ }));
+
+ beans::PropertyValue aValue;
+ aValue.Name = "compatSetting";
+ aValue.Value <<= aCompatSetting;
+
+ m_pImpl->m_aCompatSettings.push_back(aValue);
+ }
+
+ return comphelper::containerToSequence(m_pImpl->m_aCompatSettings);
+}
+
+uno::Sequence<beans::PropertyValue> SettingsTable::GetDocumentProtectionSettings() const
+{
+ return m_pImpl->m_pDocumentProtection->toSequence();
+}
+
+uno::Sequence<beans::PropertyValue> SettingsTable::GetWriteProtectionSettings() const
+{
+ return m_pImpl->m_pWriteProtection->toSequence();
+}
+
+const OUString & SettingsTable::GetCurrentDatabaseDataSource() const
+{
+ return m_pImpl->m_sCurrentDatabaseDataSource;
+}
+
+static bool lcl_isDefault(const uno::Reference<beans::XPropertyState>& xPropertyState, const OUString& rPropertyName)
+{
+ return xPropertyState->getPropertyState(rPropertyName) == beans::PropertyState_DEFAULT_VALUE;
+}
+
+void SettingsTable::ApplyProperties(uno::Reference<text::XTextDocument> const& xDoc)
+{
+ uno::Reference< beans::XPropertySet> xDocProps( xDoc, uno::UNO_QUERY );
+ uno::Reference<lang::XMultiServiceFactory> xTextFactory(xDoc, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xDocumentSettings(xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW);
+
+ xDocumentSettings->setPropertyValue("TableRowKeep", uno::Any(true));
+
+ if (GetWordCompatibilityMode() <= 14)
+ {
+ xDocumentSettings->setPropertyValue("MsWordCompMinLineHeightByFly", uno::Any(true));
+ xDocumentSettings->setPropertyValue("TabOverMargin", uno::Any(true));
+ }
+
+ // Show changes value
+ if (xDocProps.is())
+ {
+ bool bHideChanges = !m_pImpl->m_bShowInsDelChanges || !m_pImpl->m_bShowMarkupChanges;
+ xDocProps->setPropertyValue("ShowChanges", uno::Any( !bHideChanges || m_pImpl->m_bShowFormattingChanges ) );
+ }
+
+ // Record changes value
+ if (xDocProps.is())
+ {
+ xDocProps->setPropertyValue("RecordChanges", uno::Any( m_pImpl->m_bRecordChanges ) );
+ // Password protected Record changes
+ if (m_pImpl->m_bRecordChanges && m_pImpl->m_pDocumentProtection->getRedlineProtection()
+ && m_pImpl->m_pDocumentProtection->getEnforcement())
+ {
+ // use dummy protection key to forbid disabling of Record changes without a notice
+ // (extending the recent GrabBag support) TODO support password verification...
+ css::uno::Sequence<sal_Int8> aDummyKey { 1 };
+ xDocProps->setPropertyValue("RedlineProtectionKey", uno::Any( aDummyKey ));
+ }
+ }
+
+ // Auto hyphenation: turns on hyphenation by default, <w:suppressAutoHyphens/> may still disable it at a paragraph level.
+ // Situation is similar for RTF_WIDOWCTRL, which turns on widow / orphan control by default.
+ if (!(m_pImpl->m_bAutoHyphenation || m_pImpl->m_bNoHyphenateCaps || m_pImpl->m_bWidowControl))
+ return;
+
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xDoc, uno::UNO_QUERY);
+ if (!xStyleFamiliesSupplier.is())
+ return;
+
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xParagraphStyles = xStyleFamilies->getByName("ParagraphStyles").get< uno::Reference<container::XNameContainer> >();
+ uno::Reference<style::XStyle> xDefault = xParagraphStyles->getByName("Standard").get< uno::Reference<style::XStyle> >();
+ uno::Reference<beans::XPropertyState> xPropertyState(xDefault, uno::UNO_QUERY);
+ if (m_pImpl->m_bAutoHyphenation && lcl_isDefault(xPropertyState, "ParaIsHyphenation"))
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaIsHyphenation", uno::Any(true));
+ }
+ if (m_pImpl->m_bNoHyphenateCaps)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaHyphenationNoCaps", uno::Any(true));
+ }
+ if (m_pImpl->m_nHyphenationZone)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaHyphenationZone", uno::Any(GetHyphenationZone()));
+ }
+ if (m_pImpl->m_bWidowControl && lcl_isDefault(xPropertyState, "ParaWidows") && lcl_isDefault(xPropertyState, "ParaOrphans"))
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ uno::Any aAny(static_cast<sal_Int8>(2));
+ xPropertySet->setPropertyValue("ParaWidows", aAny);
+ xPropertySet->setPropertyValue("ParaOrphans", aAny);
+ }
+}
+
+bool SettingsTable::GetCompatSettingValue( std::u16string_view sCompatName ) const
+{
+ bool bRet = false;
+ for (const auto& rProp : m_pImpl->m_aCompatSettings)
+ {
+ if (rProp.Name == "compatSetting") //always true
+ {
+ css::uno::Sequence<css::beans::PropertyValue> aCurrentCompatSettings;
+ rProp.Value >>= aCurrentCompatSettings;
+
+ OUString sName;
+ aCurrentCompatSettings[0].Value >>= sName;
+ if ( sName != sCompatName )
+ continue;
+
+ OUString sUri;
+ aCurrentCompatSettings[1].Value >>= sUri;
+ if ( sUri != "http://schemas.microsoft.com/office/word" )
+ continue;
+
+ OUString sVal;
+ aCurrentCompatSettings[2].Value >>= sVal;
+ // if repeated, what happens? Last one wins
+ bRet = sVal.toBoolean();
+ }
+ }
+
+ return bRet;
+}
+
+//Keep this function in-sync with the one in sw/.../docxattributeoutput.cxx
+sal_Int32 SettingsTable::GetWordCompatibilityMode() const
+{
+ if ( m_pImpl->m_nWordCompatibilityMode != -1 )
+ return m_pImpl->m_nWordCompatibilityMode;
+
+ for (const auto& rProp : m_pImpl->m_aCompatSettings)
+ {
+ if (rProp.Name == "compatSetting") //always true
+ {
+ css::uno::Sequence<css::beans::PropertyValue> aCurrentCompatSettings;
+ rProp.Value >>= aCurrentCompatSettings;
+
+ OUString sName;
+ aCurrentCompatSettings[0].Value >>= sName;
+ if ( sName != "compatibilityMode" )
+ continue;
+
+ OUString sUri;
+ aCurrentCompatSettings[1].Value >>= sUri;
+ if ( sUri != "http://schemas.microsoft.com/office/word" )
+ continue;
+
+ OUString sVal;
+ aCurrentCompatSettings[2].Value >>= sVal;
+ const sal_Int32 nValidMode = sVal.toInt32();
+ // if repeated, highest mode wins in MS Word. 11 is the first valid mode.
+ if ( nValidMode > 10 && nValidMode > m_pImpl->m_nWordCompatibilityMode )
+ m_pImpl->m_nWordCompatibilityMode = nValidMode;
+ }
+ }
+
+ return m_pImpl->m_nWordCompatibilityMode;
+}
+
+bool SettingsTable::GetLongerSpaceSequence() const
+{
+ return m_pImpl->m_bLongerSpaceSequence;
+}
+
+bool SettingsTable::GetNoLeading() const
+{
+ return m_pImpl->m_bNoLeading;
+}
+
+bool SettingsTable::GetGutterAtTop() const { return m_pImpl->m_bGutterAtTop; }
+
+}//namespace dmapper
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SettingsTable.hxx b/writerfilter/source/dmapper/SettingsTable.hxx
new file mode 100644
index 000000000..a0af31bed
--- /dev/null
+++ b/writerfilter/source/dmapper/SettingsTable.hxx
@@ -0,0 +1,111 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <memory>
+
+namespace com::sun::star::lang
+{
+class XMultiServiceFactory;
+struct Locale;
+}
+
+namespace writerfilter::dmapper
+{
+class DomainMapper;
+
+struct SettingsTable_Impl;
+
+class SettingsTable : public LoggedProperties, public LoggedTable
+{
+ std::unique_ptr<SettingsTable_Impl> m_pImpl;
+
+public:
+ SettingsTable(const DomainMapper& rDomainMapper);
+ virtual ~SettingsTable() override;
+
+ //returns default TabStop in 1/100th mm
+ int GetDefaultTabStop() const;
+
+ /// Automatically update styles from document template?
+ bool GetLinkStyles() const;
+
+ /// What's the zoom factor set in percents?
+ sal_Int16 GetZoomFactor() const;
+
+ /// Gets the type of the zoom.
+ sal_Int16 GetZoomType() const;
+
+ /// What's the requested view? E.g. "web".
+ Id GetView() const;
+
+ bool GetEvenAndOddHeaders() const;
+
+ bool GetUsePrinterMetrics() const;
+
+ bool GetEmbedTrueTypeFonts() const;
+ bool GetEmbedSystemFonts() const;
+
+ bool GetDoNotUseHTMLParagraphAutoSpacing() const;
+ bool GetSplitPgBreakAndParaMark() const;
+ bool GetMirrorMarginSettings() const;
+ bool GetDisplayBackgroundShape() const;
+ bool GetDoNotExpandShiftReturn() const;
+ bool GetNoColumnBalance() const;
+ bool GetProtectForm() const;
+ bool GetReadOnly() const;
+ bool GetLongerSpaceSequence() const;
+ bool GetNoLeading() const;
+ bool GetNoHyphenateCaps() const;
+ sal_Int16 GetHyphenationZone() const;
+
+ const OUString& GetDecimalSymbol() const;
+ const OUString& GetListSeparator() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> const& GetThemeFontLangProperties() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> GetCompatSettings() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> GetDocumentProtectionSettings() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> GetWriteProtectionSettings() const;
+
+ void ApplyProperties(css::uno::Reference<css::text::XTextDocument> const& xDoc);
+
+ bool GetCompatSettingValue(std::u16string_view sCompatName) const;
+ sal_Int32 GetWordCompatibilityMode() const;
+
+ const OUString& GetCurrentDatabaseDataSource() const;
+ bool GetGutterAtTop() const;
+
+private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+};
+typedef tools::SvRef<SettingsTable> SettingsTablePtr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SmartTagHandler.cxx b/writerfilter/source/dmapper/SmartTagHandler.cxx
new file mode 100644
index 000000000..c92fa7c44
--- /dev/null
+++ b/writerfilter/source/dmapper/SmartTagHandler.cxx
@@ -0,0 +1,127 @@
+/* -*- 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 "SmartTagHandler.hxx"
+
+#include <com/sun/star/rdf/Literal.hpp>
+#include <com/sun/star/rdf/URI.hpp>
+#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+namespace
+{
+OUString lcl_getTypePath(OUString& rType)
+{
+ OUString aRet;
+ if (rType.startsWith("urn:bails"))
+ {
+ rType = "urn:bails";
+ aRet = "tscp/bails.rdf";
+ }
+ return aRet;
+}
+}
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+SmartTagHandler::SmartTagHandler(uno::Reference<uno::XComponentContext> xComponentContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument)
+ : LoggedProperties("SmartTagHandler")
+ , m_xComponentContext(std::move(xComponentContext))
+ , m_xDocumentMetadataAccess(xTextDocument, uno::UNO_QUERY)
+{
+}
+
+SmartTagHandler::~SmartTagHandler() = default;
+
+void SmartTagHandler::lcl_attribute(Id nId, Value& rValue)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_Attr_name:
+ m_aAttributes.emplace_back(rValue.getString(), OUString());
+ break;
+ case NS_ooxml::LN_CT_Attr_val:
+ if (!m_aAttributes.empty())
+ m_aAttributes.back().second = rValue.getString();
+ break;
+ default:
+ SAL_WARN("writerfilter", "SmartTagHandler::lcl_attribute: unhandled attribute "
+ << nId << " (string value: '" << rValue.getString()
+ << "')");
+ break;
+ }
+}
+
+void SmartTagHandler::lcl_sprm(Sprm& rSprm)
+{
+ switch (rSprm.getId())
+ {
+ case NS_ooxml::LN_CT_SmartTagPr_attr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ break;
+ }
+ }
+}
+
+void SmartTagHandler::setURI(const OUString& rURI) { m_aURI = rURI; }
+
+void SmartTagHandler::setElement(const OUString& rElement) { m_aElement = rElement; }
+
+void SmartTagHandler::handle(const uno::Reference<text::XTextRange>& xParagraph)
+{
+ if (m_aURI.isEmpty() || m_aElement.isEmpty() || m_aAttributes.empty())
+ return;
+
+ uno::Reference<rdf::XResource> xSubject(xParagraph, uno::UNO_QUERY);
+
+ for (const std::pair<OUString, OUString>& rAttribute : m_aAttributes)
+ {
+ OUString aTypeNS = rAttribute.first;
+ OUString aMetadataFilePath = lcl_getTypePath(aTypeNS);
+ if (aMetadataFilePath.isEmpty())
+ continue;
+
+ uno::Reference<rdf::XURI> xType = rdf::URI::create(m_xComponentContext, aTypeNS);
+ uno::Sequence<uno::Reference<rdf::XURI>> aGraphNames
+ = m_xDocumentMetadataAccess->getMetadataGraphsWithType(xType);
+ uno::Reference<rdf::XURI> xGraphName;
+ if (aGraphNames.hasElements())
+ xGraphName = aGraphNames[0];
+ else
+ {
+ uno::Sequence<uno::Reference<rdf::XURI>> xTypes = { xType };
+ xGraphName = m_xDocumentMetadataAccess->addMetadataFile(aMetadataFilePath, xTypes);
+ }
+ uno::Reference<rdf::XNamedGraph> xGraph
+ = m_xDocumentMetadataAccess->getRDFRepository()->getGraph(xGraphName);
+ uno::Reference<rdf::XURI> xKey = rdf::URI::create(m_xComponentContext, rAttribute.first);
+ uno::Reference<rdf::XLiteral> xValue
+ = rdf::Literal::create(m_xComponentContext, rAttribute.second);
+ xGraph->addStatement(xSubject, xKey, xValue);
+ }
+
+ m_aURI.clear();
+ m_aElement.clear();
+ m_aAttributes.clear();
+}
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SmartTagHandler.hxx b/writerfilter/source/dmapper/SmartTagHandler.hxx
new file mode 100644
index 000000000..7999b9dcc
--- /dev/null
+++ b/writerfilter/source/dmapper/SmartTagHandler.hxx
@@ -0,0 +1,60 @@
+/* -*- 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/.
+ */
+#pragma once
+
+#include <vector>
+
+#include "LoggedResources.hxx"
+
+namespace com::sun::star
+{
+namespace rdf
+{
+class XDocumentMetadataAccess;
+}
+namespace text
+{
+class XTextDocument;
+class XTextRange;
+}
+namespace uno
+{
+class XComponentContext;
+}
+}
+
+namespace writerfilter::dmapper
+{
+/// Handler for smart tags, i.e. <w:smartTag> and below.
+class SmartTagHandler : public LoggedProperties
+{
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+ css::uno::Reference<css::rdf::XDocumentMetadataAccess> m_xDocumentMetadataAccess;
+ OUString m_aURI;
+ OUString m_aElement;
+ std::vector<std::pair<OUString, OUString>> m_aAttributes;
+
+public:
+ SmartTagHandler(css::uno::Reference<css::uno::XComponentContext> xComponentContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument);
+ ~SmartTagHandler() override;
+
+ void lcl_attribute(Id nId, Value& rValue) override;
+ void lcl_sprm(Sprm& rSprm) override;
+
+ void setURI(const OUString& rURI);
+ void setElement(const OUString& rElement);
+
+ /// Set m_aAttributes as RDF statements on xParagraph.
+ void handle(const css::uno::Reference<css::text::XTextRange>& xParagraph);
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/StyleSheetTable.cxx b/writerfilter/source/dmapper/StyleSheetTable.cxx
new file mode 100644
index 000000000..3a6d540b7
--- /dev/null
+++ b/writerfilter/source/dmapper/StyleSheetTable.cxx
@@ -0,0 +1,1707 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "StyleSheetTable.hxx"
+#include "util.hxx"
+#include "ConversionHelper.hxx"
+#include "TblStylePrHandler.hxx"
+#include "TagLogger.hxx"
+#include "BorderHandler.hxx"
+#include "LatentStyleHandler.hxx"
+#include <ooxml/resourceids.hxx>
+#include <vector>
+#include <iterator>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <map>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/sorted_vector.hxx>
+
+using namespace ::com::sun::star;
+
+namespace writerfilter::dmapper
+{
+
+StyleSheetEntry::StyleSheetEntry() :
+ bIsDefaultStyle(false)
+ ,bAssignedAsChapterNumbering(false)
+ ,bInvalidHeight(false)
+ ,bHasUPE(false)
+ ,nStyleTypeCode(STYLE_TYPE_UNKNOWN)
+ ,pProperties(new StyleSheetPropertyMap)
+ ,bAutoRedefine(false)
+{
+}
+
+StyleSheetEntry::~StyleSheetEntry()
+{
+}
+
+TableStyleSheetEntry::TableStyleSheetEntry( StyleSheetEntry const & rEntry )
+{
+ bIsDefaultStyle = rEntry.bIsDefaultStyle;
+ bInvalidHeight = rEntry.bInvalidHeight;
+ bHasUPE = rEntry.bHasUPE;
+ nStyleTypeCode = STYLE_TYPE_TABLE;
+ sBaseStyleIdentifier = rEntry.sBaseStyleIdentifier;
+ sNextStyleIdentifier = rEntry.sNextStyleIdentifier;
+ sLinkStyleIdentifier = rEntry.sLinkStyleIdentifier;
+ sStyleName = rEntry.sStyleName;
+ sStyleIdentifierD = rEntry.sStyleIdentifierD;
+}
+
+TableStyleSheetEntry::~TableStyleSheetEntry( )
+{
+}
+
+void TableStyleSheetEntry::AddTblStylePr( TblStyleType nType, const PropertyMapPtr& pProps )
+{
+ static const int nTypesProps = 4;
+ static const TblStyleType pTypesToFix[nTypesProps] =
+ {
+ TBL_STYLE_FIRSTROW,
+ TBL_STYLE_LASTROW,
+ TBL_STYLE_FIRSTCOL,
+ TBL_STYLE_LASTCOL
+ };
+
+ static const PropertyIds pPropsToCheck[nTypesProps] =
+ {
+ PROP_BOTTOM_BORDER,
+ PROP_TOP_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_LEFT_BORDER
+ };
+
+ for (int i=0; i < nTypesProps; ++i )
+ {
+ if ( nType == pTypesToFix[i] )
+ {
+ PropertyIds nChecked = pPropsToCheck[i];
+ std::optional<PropertyMap::Property> pChecked = pProps->getProperty(nChecked);
+
+ PropertyIds nInsideProp = ( i < 2 ) ? META_PROP_HORIZONTAL_BORDER : META_PROP_VERTICAL_BORDER;
+ std::optional<PropertyMap::Property> pInside = pProps->getProperty(nInsideProp);
+
+ if ( pChecked && pInside )
+ {
+ // In this case, remove the inside border
+ pProps->Erase( nInsideProp );
+ }
+
+ break;
+ }
+ }
+
+ // Append the tblStylePr
+ m_aStyles[nType] = pProps;
+}
+
+PropertyMapPtr TableStyleSheetEntry::GetProperties( sal_Int32 nMask )
+{
+ PropertyMapPtr pProps( new PropertyMap );
+
+ // And finally get the mask ones
+ pProps->InsertProps(GetLocalPropertiesFromMask(nMask));
+
+ return pProps;
+}
+
+beans::PropertyValues StyleSheetEntry::GetInteropGrabBagSeq() const
+{
+ return comphelper::containerToSequence(m_aInteropGrabBag);
+}
+
+beans::PropertyValue StyleSheetEntry::GetInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = sStyleIdentifierD;
+
+ beans::PropertyValues aSeq = GetInteropGrabBagSeq();
+ aRet.Value <<= aSeq;
+ return aRet;
+}
+
+void StyleSheetEntry::AppendInteropGrabBag(const beans::PropertyValue& rValue)
+{
+ m_aInteropGrabBag.push_back(rValue);
+}
+
+PropertyMapPtr StyleSheetEntry::GetMergedInheritedProperties(const StyleSheetTablePtr& pStyleSheetTable)
+{
+ PropertyMapPtr pRet;
+ if ( pStyleSheetTable && !sBaseStyleIdentifier.isEmpty() && sBaseStyleIdentifier != sStyleIdentifierD )
+ {
+ const StyleSheetEntryPtr pParentStyleSheet = pStyleSheetTable->FindStyleSheetByISTD(sBaseStyleIdentifier);
+ if ( pParentStyleSheet )
+ pRet = pParentStyleSheet->GetMergedInheritedProperties(pStyleSheetTable);
+ }
+
+ if ( !pRet )
+ pRet = new PropertyMap;
+
+ pRet->InsertProps(pProperties.get());
+
+ return pRet;
+}
+
+static void lcl_mergeProps( const PropertyMapPtr& pToFill, const PropertyMapPtr& pToAdd, TblStyleType nStyleId )
+{
+ static const PropertyIds pPropsToCheck[] =
+ {
+ PROP_BOTTOM_BORDER,
+ PROP_TOP_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_LEFT_BORDER,
+ };
+
+ bool pRemoveInside[] =
+ {
+ ( nStyleId == TBL_STYLE_FIRSTROW ),
+ ( nStyleId == TBL_STYLE_LASTROW ),
+ ( nStyleId == TBL_STYLE_LASTCOL ),
+ ( nStyleId == TBL_STYLE_FIRSTCOL )
+ };
+
+ for ( unsigned i = 0 ; i != SAL_N_ELEMENTS(pPropsToCheck); i++ )
+ {
+ PropertyIds nId = pPropsToCheck[i];
+ std::optional<PropertyMap::Property> pProp = pToAdd->getProperty(nId);
+
+ if ( pProp )
+ {
+ if ( pRemoveInside[i] )
+ {
+ // Remove the insideH and insideV depending on the cell pos
+ PropertyIds nInsideProp = ( i < 2 ) ? META_PROP_HORIZONTAL_BORDER : META_PROP_VERTICAL_BORDER;
+ pToFill->Erase(nInsideProp);
+ }
+ }
+ }
+
+ pToFill->InsertProps(pToAdd);
+}
+
+PropertyMapPtr TableStyleSheetEntry::GetLocalPropertiesFromMask( sal_Int32 nMask )
+{
+ // Order from right to left
+ struct TblStyleTypeAndMask {
+ sal_Int32 mask;
+ TblStyleType type;
+ };
+
+ static const TblStyleTypeAndMask aOrderedStyleTable[] =
+ {
+ { 0x010, TBL_STYLE_BAND2HORZ },
+ { 0x020, TBL_STYLE_BAND1HORZ },
+ { 0x040, TBL_STYLE_BAND2VERT },
+ { 0x080, TBL_STYLE_BAND1VERT },
+ { 0x100, TBL_STYLE_LASTCOL },
+ { 0x200, TBL_STYLE_FIRSTCOL },
+ { 0x400, TBL_STYLE_LASTROW },
+ { 0x800, TBL_STYLE_FIRSTROW },
+ { 0x001, TBL_STYLE_SWCELL },
+ { 0x002, TBL_STYLE_SECELL },
+ { 0x004, TBL_STYLE_NWCELL },
+ { 0x008, TBL_STYLE_NECELL }
+ };
+
+ // Get the properties applying according to the mask
+ PropertyMapPtr pProps( new PropertyMap( ) );
+ for (const TblStyleTypeAndMask & i : aOrderedStyleTable)
+ {
+ TblStylePrs::iterator pIt = m_aStyles.find( i.type );
+ if ( ( nMask & i.mask ) && ( pIt != m_aStyles.end( ) ) )
+ lcl_mergeProps( pProps, pIt->second, i.type );
+ }
+ return pProps;
+}
+
+namespace {
+
+struct ListCharStylePropertyMap_t
+{
+ OUString sCharStyleName;
+ PropertyValueVector_t aPropertyValues;
+
+ ListCharStylePropertyMap_t(const OUString& rCharStyleName, PropertyValueVector_t&& rPropertyValues):
+ sCharStyleName( rCharStyleName ),
+ aPropertyValues( std::move(rPropertyValues) )
+ {}
+};
+
+}
+
+struct StyleSheetTable_Impl
+{
+ DomainMapper& m_rDMapper;
+ uno::Reference< text::XTextDocument> m_xTextDocument;
+ uno::Reference< beans::XPropertySet> m_xTextDefaults;
+ std::vector< StyleSheetEntryPtr > m_aStyleSheetEntries;
+ std::map< OUString, StyleSheetEntryPtr > m_aStyleSheetEntriesMap;
+ StyleSheetEntryPtr m_pCurrentEntry;
+ PropertyMapPtr m_pDefaultParaProps, m_pDefaultCharProps;
+ OUString m_sDefaultParaStyleName; //WW8 name
+ std::vector< ListCharStylePropertyMap_t > m_aListCharStylePropertyVector;
+ bool m_bHasImportedDefaultParaProps;
+ bool m_bIsNewDoc;
+
+ StyleSheetTable_Impl(DomainMapper& rDMapper, uno::Reference< text::XTextDocument> const& xTextDocument, bool bIsNewDoc);
+
+ OUString HasListCharStyle( const PropertyValueVector_t& rCharProperties );
+
+ /// Appends the given key-value pair to the list of latent style properties of the current entry.
+ void AppendLatentStyleProperty(const OUString& aName, Value const & rValue);
+ /// Sets all properties of xStyle back to default.
+ static void SetPropertiesToDefault(const uno::Reference<style::XStyle>& xStyle);
+};
+
+
+StyleSheetTable_Impl::StyleSheetTable_Impl(DomainMapper& rDMapper,
+ uno::Reference< text::XTextDocument> const& xTextDocument,
+ bool const bIsNewDoc)
+ : m_rDMapper( rDMapper ),
+ m_xTextDocument( xTextDocument ),
+ m_pDefaultParaProps(new PropertyMap),
+ m_pDefaultCharProps(new PropertyMap),
+ m_sDefaultParaStyleName("Normal"),
+ m_bHasImportedDefaultParaProps(false),
+ m_bIsNewDoc(bIsNewDoc)
+{
+ //set font height default to 10pt
+ uno::Any aVal( 10.0 );
+ m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT, aVal );
+ m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT_ASIAN, aVal );
+ m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT_COMPLEX, aVal );
+
+ // See SwDoc::RemoveAllFormatLanguageDependencies(), internal filters
+ // disable kerning by default, do the same here.
+ m_pDefaultCharProps->Insert(PROP_CHAR_AUTO_KERNING, uno::Any(false));
+}
+
+
+OUString StyleSheetTable_Impl::HasListCharStyle( const PropertyValueVector_t& rPropValues )
+{
+ for( const auto& rListVector : m_aListCharStylePropertyVector )
+ {
+ const auto& rPropertyValues = rListVector.aPropertyValues;
+ //if size is identical
+ if( rPropertyValues.size() == rPropValues.size() )
+ {
+ bool bBreak = false;
+ //then search for all contained properties
+ for( const auto& rPropVal1 : rPropValues)
+ {
+ //find the property
+ auto aListIter = std::find_if(rPropertyValues.begin(), rPropertyValues.end(),
+ [&rPropVal1](const css::beans::PropertyValue& rPropVal2) { return rPropVal2.Name == rPropVal1.Name; });
+ //set break flag if property hasn't been found
+ bBreak = (aListIter == rPropertyValues.end()) || (aListIter->Value != rPropVal1.Value);
+ if( bBreak )
+ break;
+ }
+ if( !bBreak )
+ return rListVector.sCharStyleName;
+ }
+ }
+ return OUString();
+}
+
+void StyleSheetTable_Impl::AppendLatentStyleProperty(const OUString& aName, Value const & rValue)
+{
+ beans::PropertyValue aValue;
+ aValue.Name = aName;
+ aValue.Value <<= rValue.getString();
+ m_pCurrentEntry->aLatentStyles.push_back(aValue);
+}
+
+void StyleSheetTable_Impl::SetPropertiesToDefault(const uno::Reference<style::XStyle>& xStyle)
+{
+ // See if the existing style has any non-default properties. If so, reset them back to default.
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ const uno::Sequence<beans::Property> aProperties = xPropertySetInfo->getProperties();
+ std::vector<OUString> aPropertyNames;
+ aPropertyNames.reserve(aProperties.getLength());
+ std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aPropertyNames),
+ [](const beans::Property& rProp) { return rProp.Name; });
+
+ uno::Reference<beans::XPropertyState> xPropertyState(xStyle, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyState> aStates = xPropertyState->getPropertyStates(comphelper::containerToSequence(aPropertyNames));
+ for (sal_Int32 i = 0; i < aStates.getLength(); ++i)
+ {
+ if (aStates[i] == beans::PropertyState_DIRECT_VALUE)
+ {
+ try
+ {
+ xPropertyState->setPropertyToDefault(aPropertyNames[i]);
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter", "setPropertyToDefault(" << aPropertyNames[i] << ") failed");
+ }
+ }
+ }
+}
+
+StyleSheetTable::StyleSheetTable(DomainMapper& rDMapper,
+ uno::Reference< text::XTextDocument> const& xTextDocument,
+ bool const bIsNewDoc)
+: LoggedProperties("StyleSheetTable")
+, LoggedTable("StyleSheetTable")
+, m_pImpl( new StyleSheetTable_Impl(rDMapper, xTextDocument, bIsNewDoc) )
+{
+}
+
+
+StyleSheetTable::~StyleSheetTable()
+{
+}
+
+void StyleSheetTable::SetDefaultParaProps(PropertyIds eId, const css::uno::Any& rAny)
+{
+ m_pImpl->m_pDefaultParaProps->Insert(eId, rAny, /*bOverwrite=*/false, NO_GRAB_BAG, /*bDocDefault=*/true);
+}
+
+PropertyMapPtr const & StyleSheetTable::GetDefaultParaProps() const
+{
+ return m_pImpl->m_pDefaultParaProps;
+}
+
+PropertyMapPtr const & StyleSheetTable::GetDefaultCharProps() const
+{
+ return m_pImpl->m_pDefaultCharProps;
+}
+
+void StyleSheetTable::lcl_attribute(Id Name, Value & val)
+{
+ OSL_ENSURE( m_pImpl->m_pCurrentEntry, "current entry has to be set here");
+ if(!m_pImpl->m_pCurrentEntry)
+ return ;
+ int nIntValue = val.getInt();
+ OUString sValue = val.getString();
+
+ // The default type is paragraph, and it needs to be processed first,
+ // because the NS_ooxml::LN_CT_Style_type handling may set m_pImpl->m_pCurrentEntry
+ // to point to a different object.
+ if( m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_UNKNOWN )
+ {
+ if( Name != NS_ooxml::LN_CT_Style_type )
+ m_pImpl->m_pCurrentEntry->nStyleTypeCode = STYLE_TYPE_PARA;
+ }
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_Style_type:
+ {
+ SAL_WARN_IF( m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN,
+ "writerfilter", "Style type needs to be processed first" );
+ StyleType nType(STYLE_TYPE_UNKNOWN);
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_StyleType_paragraph:
+ nType = STYLE_TYPE_PARA;
+ break;
+ case NS_ooxml::LN_Value_ST_StyleType_character:
+ nType = STYLE_TYPE_CHAR;
+ break;
+ case NS_ooxml::LN_Value_ST_StyleType_table:
+ nType = STYLE_TYPE_TABLE;
+ break;
+ case NS_ooxml::LN_Value_ST_StyleType_numbering:
+ nType = STYLE_TYPE_LIST;
+ break;
+ default:
+ SAL_WARN("writerfilter", "unknown LN_CT_Style_type " << nType);
+ [[fallthrough]];
+ case 0: // explicit unknown set by tokenizer
+ break;
+
+ }
+ if ( nType == STYLE_TYPE_TABLE )
+ {
+ StyleSheetEntryPtr pEntry = m_pImpl->m_pCurrentEntry;
+ tools::SvRef<TableStyleSheetEntry> pTableEntry( new TableStyleSheetEntry( *pEntry ) );
+ m_pImpl->m_pCurrentEntry = pTableEntry.get();
+ }
+ else
+ m_pImpl->m_pCurrentEntry->nStyleTypeCode = nType;
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_default:
+ m_pImpl->m_pCurrentEntry->bIsDefaultStyle = (nIntValue != 0);
+
+ if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN)
+ {
+ // "If this attribute is specified by multiple styles, then the last instance shall be used."
+ if (m_pImpl->m_pCurrentEntry->bIsDefaultStyle
+ && m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_PARA
+ && !m_pImpl->m_pCurrentEntry->sStyleIdentifierD.isEmpty())
+ {
+ m_pImpl->m_sDefaultParaStyleName = m_pImpl->m_pCurrentEntry->sStyleIdentifierD;
+ }
+
+ beans::PropertyValue aValue;
+ aValue.Name = "default";
+ aValue.Value <<= m_pImpl->m_pCurrentEntry->bIsDefaultStyle;
+ m_pImpl->m_pCurrentEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_customStyle:
+ if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "customStyle";
+ aValue.Value <<= (nIntValue != 0);
+ m_pImpl->m_pCurrentEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_styleId:
+ m_pImpl->m_pCurrentEntry->sStyleIdentifierD = sValue;
+ if(m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get());
+ beans::PropertyValue aValue;
+ aValue.Name = "styleId";
+ aValue.Value <<= sValue;
+ pTableEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblWidth_w:
+ break;
+ case NS_ooxml::LN_CT_TblWidth_type:
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_defQFormat:
+ m_pImpl->AppendLatentStyleProperty("defQFormat", val);
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_defUnhideWhenUsed:
+ m_pImpl->AppendLatentStyleProperty("defUnhideWhenUsed", val);
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_defSemiHidden:
+ m_pImpl->AppendLatentStyleProperty("defSemiHidden", val);
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_count:
+ m_pImpl->AppendLatentStyleProperty("count", val);
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_defUIPriority:
+ m_pImpl->AppendLatentStyleProperty("defUIPriority", val);
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_defLockedState:
+ m_pImpl->AppendLatentStyleProperty("defLockedState", val);
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ break;
+ }
+}
+
+
+void StyleSheetTable::lcl_sprm(Sprm & rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = pValue ? pValue->getInt() : 0;
+ OUString sStringValue = pValue ? pValue->getString() : OUString();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_Style_name:
+ //this is only a UI name!
+ m_pImpl->m_pCurrentEntry->sStyleName = sStringValue;
+ if(m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get());
+ beans::PropertyValue aValue;
+ aValue.Name = "name";
+ aValue.Value <<= sStringValue;
+ pTableEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_basedOn:
+ m_pImpl->m_pCurrentEntry->sBaseStyleIdentifier = sStringValue;
+ if(m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get());
+ beans::PropertyValue aValue;
+ aValue.Name = "basedOn";
+ aValue.Value <<= sStringValue;
+ pTableEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_link:
+ m_pImpl->m_pCurrentEntry->sLinkStyleIdentifier = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_Style_next:
+ m_pImpl->m_pCurrentEntry->sNextStyleIdentifier = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_Style_aliases:
+ case NS_ooxml::LN_CT_Style_hidden:
+ case NS_ooxml::LN_CT_Style_personal:
+ case NS_ooxml::LN_CT_Style_personalCompose:
+ case NS_ooxml::LN_CT_Style_personalReply:
+ break;
+ case NS_ooxml::LN_CT_Style_autoRedefine:
+ m_pImpl->m_pCurrentEntry->bAutoRedefine = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Style_tcPr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties && m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ auto pTblStylePrHandler = std::make_shared<TblStylePrHandler>(m_pImpl->m_rDMapper);
+ pProperties->resolve(*pTblStylePrHandler);
+ StyleSheetEntry* pEntry = m_pImpl->m_pCurrentEntry.get();
+ TableStyleSheetEntry& rTableEntry = dynamic_cast<TableStyleSheetEntry&>(*pEntry);
+ rTableEntry.AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tcPr"));
+
+ // This is a <w:tcPr> directly under <w:style>, so it affects the whole table.
+ rTableEntry.pProperties->InsertProps(pTblStylePrHandler->getProperties());
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_trPr:
+ break;
+ case NS_ooxml::LN_CT_Style_rsid:
+ case NS_ooxml::LN_CT_Style_qFormat:
+ case NS_ooxml::LN_CT_Style_semiHidden:
+ case NS_ooxml::LN_CT_Style_unhideWhenUsed:
+ case NS_ooxml::LN_CT_Style_uiPriority:
+ case NS_ooxml::LN_CT_Style_locked:
+ if (m_pImpl->m_pCurrentEntry->nStyleTypeCode != STYLE_TYPE_UNKNOWN)
+ {
+ StyleSheetEntryPtr pEntry = m_pImpl->m_pCurrentEntry;
+ beans::PropertyValue aValue;
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_Style_rsid:
+ {
+ // We want the rsid as a hex string, but always with the length of 8.
+ OUStringBuffer aBuf = OUString::number(nIntValue, 16);
+ OUStringBuffer aStr;
+ comphelper::string::padToLength(aStr, 8 - aBuf.getLength(), '0');
+ aStr.append(aBuf.getStr());
+
+ aValue.Name = "rsid";
+ aValue.Value <<= aStr.makeStringAndClear();
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_qFormat:
+ aValue.Name = "qFormat";
+ break;
+ case NS_ooxml::LN_CT_Style_semiHidden:
+ aValue.Name = "semiHidden";
+ break;
+ case NS_ooxml::LN_CT_Style_unhideWhenUsed:
+ aValue.Name = "unhideWhenUsed";
+ break;
+ case NS_ooxml::LN_CT_Style_uiPriority:
+ {
+ aValue.Name = "uiPriority";
+ aValue.Value <<= OUString::number(nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_locked:
+ aValue.Name = "locked";
+ break;
+ }
+ pEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_tblPr: //contains table properties
+ case NS_ooxml::LN_CT_Style_tblStylePr: //contains to table properties
+ case NS_ooxml::LN_CT_TblPrBase_tblInd: //table properties - at least width value and type
+ case NS_ooxml::LN_EG_RPrBase_rFonts: //table fonts
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pTblStylePrHandler = std::make_shared<TblStylePrHandler>( m_pImpl->m_rDMapper );
+ pProperties->resolve( *pTblStylePrHandler );
+
+ // Add the properties to the table style
+ TblStyleType nType = pTblStylePrHandler->getType( );
+ PropertyMapPtr pProps = pTblStylePrHandler->getProperties( );
+ StyleSheetEntry * pEntry = m_pImpl->m_pCurrentEntry.get();
+
+ TableStyleSheetEntry * pTableEntry = dynamic_cast<TableStyleSheetEntry*>( pEntry );
+ if (nType == TBL_STYLE_UNKNOWN)
+ {
+ pEntry->pProperties->InsertProps(pProps);
+ }
+ else
+ {
+ if (pTableEntry != nullptr)
+ pTableEntry->AddTblStylePr( nType, pProps );
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_Style_tblPr)
+ {
+ if (pTableEntry != nullptr)
+ pTableEntry->AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tblPr"));
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_Style_tblStylePr)
+ {
+ pTblStylePrHandler->appendInteropGrabBag("type", pTblStylePrHandler->getTypeString());
+ if (pTableEntry != nullptr)
+ pTableEntry->AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tblStylePr"));
+ }
+ }
+ break;
+ }
+ case NS_ooxml::LN_CT_PPrDefault_pPr:
+ case NS_ooxml::LN_CT_DocDefaults_pPrDefault:
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(true);
+
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultParaProps );
+ resolveSprmProps( m_pImpl->m_rDMapper, rSprm );
+ if ( nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault && m_pImpl->m_pDefaultParaProps &&
+ !m_pImpl->m_pDefaultParaProps->isSet( PROP_PARA_TOP_MARGIN ) )
+ {
+ SetDefaultParaProps( PROP_PARA_TOP_MARGIN, uno::Any( sal_Int32(0) ) );
+ }
+ m_pImpl->m_rDMapper.PopStyleSheetProperties();
+ applyDefaults( true );
+ m_pImpl->m_bHasImportedDefaultParaProps = true;
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(false);
+ break;
+ case NS_ooxml::LN_CT_RPrDefault_rPr:
+ case NS_ooxml::LN_CT_DocDefaults_rPrDefault:
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_rPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(true);
+
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultCharProps );
+ resolveSprmProps( m_pImpl->m_rDMapper, rSprm );
+ m_pImpl->m_rDMapper.PopStyleSheetProperties();
+ applyDefaults( false );
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_rPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(false);
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_jc: //table alignment - row properties!
+ m_pImpl->m_pCurrentEntry->pProperties->Insert( PROP_HORI_ORIENT,
+ uno::Any( ConversionHelper::convertTableJustification( nIntValue )));
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_jc: //table alignment - row properties!
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblBorders: //table borders, might be defined in table style
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>(m_pImpl->m_rDMapper.IsOOXMLImport());
+ pProperties->resolve(*pBorderHandler);
+ m_pImpl->m_pCurrentEntry->pProperties->InsertProps(
+ pBorderHandler->getProperties());
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblStyleRowBandSize:
+ case NS_ooxml::LN_CT_TblPrBase_tblStyleColBandSize:
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar:
+ //no cell margins in styles
+ break;
+ case NS_ooxml::LN_CT_LatentStyles_lsdException:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ tools::SvRef<LatentStyleHandler> pLatentStyleHandler(new LatentStyleHandler());
+ pProperties->resolve(*pLatentStyleHandler);
+ beans::PropertyValue aValue;
+ aValue.Name = "lsdException";
+ aValue.Value <<= comphelper::containerToSequence(pLatentStyleHandler->getAttributes());
+ m_pImpl->m_pCurrentEntry->aLsdExceptions.push_back(aValue);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_pPr:
+ // no break
+ case NS_ooxml::LN_CT_Style_rPr:
+ // no break
+ default:
+ {
+ if (!m_pImpl->m_pCurrentEntry)
+ break;
+
+ tools::SvRef<TablePropertiesHandler> pTblHandler(new TablePropertiesHandler());
+ pTblHandler->SetProperties( m_pImpl->m_pCurrentEntry->pProperties.get() );
+ if ( !pTblHandler->sprm( rSprm ) )
+ {
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->pProperties.get() );
+
+ PropertyMapPtr pProps(new PropertyMap());
+ if (m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ if (nSprmId == NS_ooxml::LN_CT_Style_pPr)
+ m_pImpl->m_rDMapper.enableInteropGrabBag("pPr");
+ else if (nSprmId == NS_ooxml::LN_CT_Style_rPr)
+ m_pImpl->m_rDMapper.enableInteropGrabBag("rPr");
+ }
+ m_pImpl->m_rDMapper.sprmWithProps( rSprm, pProps );
+ if (m_pImpl->m_pCurrentEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ if (nSprmId == NS_ooxml::LN_CT_Style_pPr || nSprmId == NS_ooxml::LN_CT_Style_rPr)
+ {
+ TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get());
+ pTableEntry->AppendInteropGrabBag(m_pImpl->m_rDMapper.getInteropGrabBag());
+ }
+ }
+
+ m_pImpl->m_pCurrentEntry->pProperties->InsertProps(pProps);
+
+ m_pImpl->m_rDMapper.PopStyleSheetProperties( );
+ }
+ }
+ break;
+}
+}
+
+
+void StyleSheetTable::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+ //create a new style entry
+ OSL_ENSURE( !m_pImpl->m_pCurrentEntry, "current entry has to be NULL here");
+ StyleSheetEntryPtr pNewEntry( new StyleSheetEntry );
+ m_pImpl->m_pCurrentEntry = pNewEntry;
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->pProperties.get() );
+ ref->resolve(*this);
+ //append it to the table
+ m_pImpl->m_rDMapper.PopStyleSheetProperties();
+ if( !m_pImpl->m_rDMapper.IsOOXMLImport() || !m_pImpl->m_pCurrentEntry->sStyleName.isEmpty())
+ {
+ m_pImpl->m_pCurrentEntry->sConvertedStyleName = ConvertStyleName( m_pImpl->m_pCurrentEntry->sStyleName );
+ m_pImpl->m_aStyleSheetEntries.push_back( m_pImpl->m_pCurrentEntry );
+ m_pImpl->m_aStyleSheetEntriesMap.emplace( m_pImpl->m_pCurrentEntry->sStyleIdentifierD, m_pImpl->m_pCurrentEntry );
+ }
+ else
+ {
+ //TODO: this entry contains the default settings - they have to be added to the settings
+ }
+
+ if (!m_pImpl->m_pCurrentEntry->aLatentStyles.empty())
+ {
+ // We have latent styles for this entry, then process them.
+ std::vector<beans::PropertyValue>& rLatentStyles = m_pImpl->m_pCurrentEntry->aLatentStyles;
+
+ if (!m_pImpl->m_pCurrentEntry->aLsdExceptions.empty())
+ {
+ std::vector<beans::PropertyValue>& rLsdExceptions = m_pImpl->m_pCurrentEntry->aLsdExceptions;
+ beans::PropertyValue aValue;
+ aValue.Name = "lsdExceptions";
+ aValue.Value <<= comphelper::containerToSequence(rLsdExceptions);
+ rLatentStyles.push_back(aValue);
+ }
+
+ uno::Sequence<beans::PropertyValue> aLatentStyles( comphelper::containerToSequence(rLatentStyles) );
+
+ // We can put all latent style info directly to the document interop
+ // grab bag, as we can be sure that only a single style entry has
+ // latent style info.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_pImpl->m_xTextDocument, uno::UNO_QUERY);
+ auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(xPropertySet->getPropertyValue("InteropGrabBag").get< uno::Sequence<beans::PropertyValue> >());
+ beans::PropertyValue aValue;
+ aValue.Name = "latentStyles";
+ aValue.Value <<= aLatentStyles;
+ aGrabBag.push_back(aValue);
+ xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+
+ StyleSheetEntryPtr pEmptyEntry;
+ m_pImpl->m_pCurrentEntry = pEmptyEntry;
+}
+/*-------------------------------------------------------------------------
+ sorting helper
+ -----------------------------------------------------------------------*/
+namespace {
+
+class PropValVector
+{
+ std::vector<beans::PropertyValue> m_aValues;
+public:
+ PropValVector(){}
+
+ void Insert(const beans::PropertyValue& rVal);
+ uno::Sequence< uno::Any > getValues();
+ uno::Sequence< OUString > getNames();
+ const std::vector<beans::PropertyValue>& getProperties() const { return m_aValues; };
+};
+
+}
+
+void PropValVector::Insert(const beans::PropertyValue& rVal)
+{
+ auto aIt = std::find_if(m_aValues.begin(), m_aValues.end(),
+ [&rVal](beans::PropertyValue& rPropVal) { return rPropVal.Name > rVal.Name; });
+ if (aIt != m_aValues.end())
+ {
+ m_aValues.insert( aIt, rVal );
+ return;
+ }
+ m_aValues.push_back(rVal);
+}
+
+uno::Sequence< uno::Any > PropValVector::getValues()
+{
+ std::vector<uno::Any> aRet;
+ std::transform(m_aValues.begin(), m_aValues.end(), std::back_inserter(aRet), [](const beans::PropertyValue& rValue) { return rValue.Value; });
+ return comphelper::containerToSequence(aRet);
+}
+
+uno::Sequence< OUString > PropValVector::getNames()
+{
+ std::vector<OUString> aRet;
+ std::transform(m_aValues.begin(), m_aValues.end(), std::back_inserter(aRet), [](const beans::PropertyValue& rValue) { return rValue.Name; });
+ return comphelper::containerToSequence(aRet);
+}
+
+void StyleSheetTable::ApplyNumberingStyleNameToParaStyles()
+{
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xParaStyles;
+ xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xParaStyles;
+
+ if ( !xParaStyles.is() )
+ return;
+
+ for ( const auto& pEntry : m_pImpl->m_aStyleSheetEntries )
+ {
+ StyleSheetPropertyMap* pStyleSheetProperties = nullptr;
+ if ( pEntry->nStyleTypeCode == STYLE_TYPE_PARA && (pStyleSheetProperties = pEntry->pProperties.get()) )
+ {
+ // ListId 0 means turn off numbering - to cancel inheritance - so make sure that can be set.
+ if (pStyleSheetProperties->GetListId() > -1)
+ {
+ uno::Reference< style::XStyle > xStyle;
+ xParaStyles->getByName( ConvertStyleName(pEntry->sStyleName) ) >>= xStyle;
+
+ if ( !xStyle.is() )
+ break;
+
+ uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY_THROW );
+ const OUString sNumberingStyleName = m_pImpl->m_rDMapper.GetListStyleName( pStyleSheetProperties->GetListId() );
+ if ( !sNumberingStyleName.isEmpty() || !pStyleSheetProperties->GetListId() )
+ xPropertySet->setPropertyValue( getPropertyName(PROP_NUMBERING_STYLE_NAME), uno::Any(sNumberingStyleName) );
+
+ // Word 2010+ (not Word 2003, and Word 2007 is completely broken)
+ // does something rather strange. It does not allow two paragraph styles
+ // to share the same listLevel on a numbering rule.
+ // Consider this style to just be body level if already used previously.
+ m_pImpl->m_rDMapper.ValidateListLevel(pEntry->sStyleIdentifierD);
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying numbering style name to Paragraph styles");
+ }
+}
+
+/* Counteract the destructive tendencies of LibreOffice's Chapter Numbering
+ *
+ * Any assignment to Chapter Numbering will erase the numbering-like properties of inherited styles.
+ * So go through the list of styles and any that inherit from a Chapter Numbering style
+ * should have the Outline Level reapplied.
+ */
+void StyleSheetTable::ReApplyInheritedOutlineLevelFromChapterNumbering()
+{
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xParaStyles;
+ xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES)) >>= xParaStyles;
+
+ if (!xParaStyles.is())
+ return;
+
+ for (const auto& pEntry : m_pImpl->m_aStyleSheetEntries)
+ {
+ if (pEntry->nStyleTypeCode != STYLE_TYPE_PARA || pEntry->sBaseStyleIdentifier.isEmpty())
+ continue;
+
+ sal_Int16 nOutlineLevel = pEntry->pProperties->GetOutlineLevel();
+ if (nOutlineLevel != -1)
+ continue;
+
+ StyleSheetEntryPtr pParent = FindStyleSheetByISTD(pEntry->sBaseStyleIdentifier);
+ if (!pParent || !pParent->bAssignedAsChapterNumbering)
+ continue;
+
+ nOutlineLevel = pParent->pProperties->GetOutlineLevel();
+ assert(nOutlineLevel >= WW_OUTLINE_MIN && nOutlineLevel < WW_OUTLINE_MAX);
+
+ // convert MS level to LO equivalent outline level
+ ++nOutlineLevel;
+
+ uno::Reference< style::XStyle > xStyle;
+ xParaStyles->getByName(pEntry->sConvertedStyleName) >>= xStyle;
+ if ( !xStyle.is() )
+ break;
+
+ uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY_THROW );
+ xPropertySet->setPropertyValue(getPropertyName(PROP_OUTLINE_LEVEL), uno::Any(nOutlineLevel));
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying outlineLevel to Paragraph styles");
+ }
+}
+
+void StyleSheetTable::ApplyStyleSheets( const FontTablePtr& rFontTable )
+{
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xCharStyles;
+ uno::Reference<container::XNameContainer> xParaStyles;
+ uno::Reference<container::XNameContainer> xNumberingStyles;
+
+ xStyleFamilies->getByName(getPropertyName( PROP_CHARACTER_STYLES )) >>= xCharStyles;
+ xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xParaStyles;
+ xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles;
+ if(xCharStyles.is() && xParaStyles.is())
+ {
+ std::vector< ::std::pair<OUString, uno::Reference<style::XStyle>> > aMissingParent;
+ std::vector< ::std::pair<OUString, uno::Reference<style::XStyle>> > aMissingFollow;
+ std::vector<std::pair<OUString, uno::Reference<style::XStyle>>> aMissingLink;
+ std::vector<beans::PropertyValue> aTableStylesVec;
+ for( auto& pEntry : m_pImpl->m_aStyleSheetEntries )
+ {
+ if( pEntry->nStyleTypeCode == STYLE_TYPE_UNKNOWN && !pEntry->sStyleName.isEmpty() )
+ pEntry->nStyleTypeCode = STYLE_TYPE_PARA; // unspecified style types are considered paragraph styles
+
+ if( pEntry->nStyleTypeCode == STYLE_TYPE_CHAR || pEntry->nStyleTypeCode == STYLE_TYPE_PARA || pEntry->nStyleTypeCode == STYLE_TYPE_LIST )
+ {
+ bool bParaStyle = pEntry->nStyleTypeCode == STYLE_TYPE_PARA;
+ bool bCharStyle = pEntry->nStyleTypeCode == STYLE_TYPE_CHAR;
+ bool bListStyle = pEntry->nStyleTypeCode == STYLE_TYPE_LIST;
+ bool bInsert = false;
+ uno::Reference< container::XNameContainer > xStyles = bParaStyle ? xParaStyles : (bListStyle ? xNumberingStyles : xCharStyles);
+ uno::Reference< style::XStyle > xStyle;
+ const OUString sConvertedStyleName = ConvertStyleName( pEntry->sStyleName );
+
+ if(xStyles->hasByName( sConvertedStyleName ))
+ {
+ // When pasting, don't update existing styles.
+ if (!m_pImpl->m_bIsNewDoc)
+ {
+ continue;
+ }
+ xStyles->getByName( sConvertedStyleName ) >>= xStyle;
+
+ {
+ StyleSheetTable_Impl::SetPropertiesToDefault(xStyle);
+
+ // resolve import conflicts with built-in styles (only if defaults have been defined)
+ if ( m_pImpl->m_bHasImportedDefaultParaProps
+ && pEntry->sBaseStyleIdentifier.isEmpty() //imported style has no inheritance
+ && !xStyle->getParentStyle().isEmpty() ) //built-in style has a default inheritance
+ {
+ xStyle->setParentStyle( "" );
+ }
+ }
+ }
+ else
+ {
+ bInsert = true;
+ xStyle.set(xDocFactory->createInstance(
+ bParaStyle ?
+ getPropertyName( PROP_SERVICE_PARA_STYLE ) :
+ (bListStyle ? OUString("com.sun.star.style.NumberingStyle") : getPropertyName( PROP_SERVICE_CHAR_STYLE ))),
+ uno::UNO_QUERY_THROW);
+
+ // Numbering styles have to be inserted early, as e.g. the NumberingRules property is only available after insertion.
+ if (bListStyle)
+ {
+ xStyles->insertByName( sConvertedStyleName, uno::Any( xStyle ) );
+ xStyle.set(xStyles->getByName(sConvertedStyleName), uno::UNO_QUERY_THROW);
+
+ StyleSheetPropertyMap* pPropertyMap = pEntry->pProperties.get();
+ if (pPropertyMap && pPropertyMap->GetListId() == -1)
+ {
+ // No properties? Word default is 'none', Writer one is 'arabic', handle this.
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexReplace> xNumberingRules;
+ xPropertySet->getPropertyValue("NumberingRules") >>= xNumberingRules;
+ uno::Reference<container::XIndexAccess> xIndexAccess(xNumberingRules, uno::UNO_QUERY_THROW);
+ for (sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i)
+ {
+ uno::Sequence< beans::PropertyValue > aLvlProps{
+ comphelper::makePropertyValue(
+ "NumberingType", style::NumberingType::NUMBER_NONE)
+ };
+ xNumberingRules->replaceByIndex(i, uno::Any(aLvlProps));
+ xPropertySet->setPropertyValue("NumberingRules", uno::Any(xNumberingRules));
+ }
+ }
+ }
+ }
+ if( !pEntry->sBaseStyleIdentifier.isEmpty() )
+ {
+ try
+ {
+ //TODO: Handle cases where a paragraph <> character style relation is needed
+ StyleSheetEntryPtr pParent = FindStyleSheetByISTD( pEntry->sBaseStyleIdentifier );
+ // Writer core doesn't support numbering styles having a parent style, it seems
+ if (pParent && !bListStyle)
+ {
+ const OUString sParentStyleName = ConvertStyleName( pParent->sStyleName );
+ if ( !sParentStyleName.isEmpty() && !xStyles->hasByName( sParentStyleName ) )
+ aMissingParent.emplace_back( sParentStyleName, xStyle );
+ else
+ xStyle->setParentStyle( sParentStyleName );
+ }
+ }
+ catch( const uno::RuntimeException& )
+ {
+ OSL_FAIL( "Styles parent could not be set");
+ }
+ }
+ else if( bParaStyle )
+ {
+ // Paragraph styles that don't inherit from some parent need to apply the DocDefaults
+ pEntry->pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false );
+
+ //now it's time to set the default parameters - for paragraph styles
+ //Fonts: Western first entry in font table
+ //CJK: second entry
+ //CTL: third entry, if it exists
+
+ sal_uInt32 nFontCount = rFontTable->size();
+ if( !m_pImpl->m_rDMapper.IsOOXMLImport() && nFontCount > 2 )
+ {
+ uno::Any aTwoHundredFortyTwip(12.);
+
+ // font size to 240 twip (12 pts) for all if not set
+ pEntry->pProperties->Insert(PROP_CHAR_HEIGHT, aTwoHundredFortyTwip, false);
+
+ // western font not already set -> apply first font
+ const FontEntry::Pointer_t pWesternFontEntry(rFontTable->getFontEntry( 0 ));
+ OUString sWesternFontName = pWesternFontEntry->sFontName;
+ pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME, uno::Any( sWesternFontName ), false);
+
+ // CJK ... apply second font
+ const FontEntry::Pointer_t pCJKFontEntry(rFontTable->getFontEntry( 2 ));
+ pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::Any( pCJKFontEntry->sFontName ), false);
+ pEntry->pProperties->Insert(PROP_CHAR_HEIGHT_ASIAN, aTwoHundredFortyTwip, false);
+
+ // CTL ... apply third font, if available
+ if( nFontCount > 3 )
+ {
+ const FontEntry::Pointer_t pCTLFontEntry(rFontTable->getFontEntry( 3 ));
+ pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME_COMPLEX, uno::Any( pCTLFontEntry->sFontName ), false);
+ pEntry->pProperties->Insert(PROP_CHAR_HEIGHT_COMPLEX, aTwoHundredFortyTwip, false);
+ }
+ }
+ }
+
+ auto aPropValues = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pEntry->pProperties->GetPropertyValues());
+
+ if (bParaStyle || bCharStyle)
+ {
+ // delay adding LinkStyle property: all styles need to be created first
+ if (!pEntry->sLinkStyleIdentifier.isEmpty())
+ {
+ StyleSheetEntryPtr pLinkStyle
+ = FindStyleSheetByISTD(pEntry->sLinkStyleIdentifier);
+ if (pLinkStyle && !pLinkStyle->sStyleName.isEmpty())
+ aMissingLink.emplace_back(ConvertStyleName(pLinkStyle->sStyleName),
+ xStyle);
+ }
+ }
+
+ if( bParaStyle )
+ {
+ // delay adding FollowStyle property: all styles need to be created first
+ if ( !pEntry->sNextStyleIdentifier.isEmpty() )
+ {
+ StyleSheetEntryPtr pFollowStyle = FindStyleSheetByISTD( pEntry->sNextStyleIdentifier );
+ if ( pFollowStyle && !pFollowStyle->sStyleName.isEmpty() )
+ aMissingFollow.emplace_back( ConvertStyleName( pFollowStyle->sStyleName ), xStyle );
+ }
+
+ // Set the outline levels
+ StyleSheetPropertyMap* pStyleSheetProperties = pEntry ? pEntry->pProperties.get() : nullptr;
+
+ if ( pStyleSheetProperties )
+ {
+ sal_Int16 nLvl = pStyleSheetProperties->GetOutlineLevel();
+ // convert MS body Level (9) to LO body level (0) and equivalent outline levels
+ if (nLvl != -1)
+ {
+ if (nLvl == WW_OUTLINE_MAX)
+ nLvl = 0;
+ else
+ ++nLvl;
+
+ beans::PropertyValue aLvlVal(getPropertyName(PROP_OUTLINE_LEVEL), 0,
+ uno::Any(nLvl),
+ beans::PropertyState_DIRECT_VALUE);
+ aPropValues.push_back(aLvlVal);
+ }
+ }
+
+ uno::Reference< beans::XPropertyState >xState( xStyle, uno::UNO_QUERY_THROW );
+ if( sConvertedStyleName == "Contents Heading" ||
+ sConvertedStyleName == "User Index Heading" ||
+ sConvertedStyleName == "Index Heading" )
+ {
+ // remove Left/RightMargin values from TOX heading styles
+ //left margin is set to NULL by default
+ xState->setPropertyToDefault(getPropertyName( PROP_PARA_LEFT_MARGIN ));
+ }
+ else if ( sConvertedStyleName == "Text body" )
+ xState->setPropertyToDefault(getPropertyName( PROP_PARA_BOTTOM_MARGIN ));
+ else if ( sConvertedStyleName == "Heading 1" ||
+ sConvertedStyleName == "Heading 2" ||
+ sConvertedStyleName == "Heading 3" ||
+ sConvertedStyleName == "Heading 4" ||
+ sConvertedStyleName == "Heading 5" ||
+ sConvertedStyleName == "Heading 6" ||
+ sConvertedStyleName == "Heading 7" ||
+ sConvertedStyleName == "Heading 8" ||
+ sConvertedStyleName == "Heading 9" )
+ {
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT_ASIAN ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT_COMPLEX ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE_ASIAN ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE_COMPLEX ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_ASIAN ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_COMPLEX));
+
+ }
+ }
+
+ if ( !aPropValues.empty() )
+ {
+ PropValVector aSortedPropVals;
+ for (const beans::PropertyValue& rValue : aPropValues)
+ {
+ // Don't add the style name properties
+ bool bIsParaStyleName = rValue.Name == "ParaStyleName";
+ bool bIsCharStyleName = rValue.Name == "CharStyleName";
+ if ( !bIsParaStyleName && !bIsCharStyleName )
+ {
+ aSortedPropVals.Insert(rValue);
+ }
+ }
+
+ try
+ {
+ uno::Reference< beans::XMultiPropertySet > xMultiPropertySet( xStyle, uno::UNO_QUERY_THROW);
+ try
+ {
+ xMultiPropertySet->setPropertyValues( aSortedPropVals.getNames(), aSortedPropVals.getValues() );
+ }
+ catch ( const uno::Exception& )
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW);
+ for ( const beans::PropertyValue& rValue : aSortedPropVals.getProperties() )
+ {
+ try
+ {
+ xPropertySet->setPropertyValue( rValue.Name, rValue.Value );
+ }
+ catch ( const uno::Exception& )
+ {
+ SAL_WARN( "writerfilter", "StyleSheetTable::ApplyStyleSheets could not set property " << rValue.Name );
+ }
+ }
+ }
+ // Duplicate MSWord's single footnote reference into Footnote Characters and Footnote anchor
+ if( pEntry->sStyleName.equalsIgnoreAsciiCase("footnote reference")
+ || pEntry->sStyleName.equalsIgnoreAsciiCase("endnote reference") )
+ {
+ uno::Reference< style::XStyle > xCopyStyle;
+ if( pEntry->sStyleName.equalsIgnoreAsciiCase("footnote reference") )
+ xStyles->getByName( "Footnote anchor" ) >>= xCopyStyle;
+ else
+ xStyles->getByName( "Endnote anchor" ) >>= xCopyStyle;
+
+ xMultiPropertySet.set( xCopyStyle, uno::UNO_QUERY_THROW);
+ xMultiPropertySet->setPropertyValues( aSortedPropVals.getNames(), aSortedPropVals.getValues() );
+ }
+ }
+ catch( const lang::WrappedTargetException& rWrapped)
+ {
+#ifdef DBG_UTIL
+ OUString aMessage("StyleSheetTable::ApplyStyleSheets: Some style properties could not be set");
+ beans::UnknownPropertyException aUnknownPropertyException;
+
+ if (rWrapped.TargetException >>= aUnknownPropertyException)
+ aMessage += ": " + aUnknownPropertyException.Message;
+
+ SAL_WARN("writerfilter", aMessage);
+#else
+ (void) rWrapped;
+#endif
+ }
+ catch( const uno::Exception& )
+ {
+ OSL_FAIL( "Some style properties could not be set");
+ }
+ }
+ // Numbering style got inserted earlier.
+ if(bInsert && !bListStyle)
+ {
+ const OUString sParentStyle = xStyle->getParentStyle();
+ if( !sParentStyle.isEmpty() && !xStyles->hasByName( sParentStyle ) )
+ aMissingParent.emplace_back( sParentStyle, xStyle );
+
+ xStyles->insertByName( sConvertedStyleName, uno::Any( xStyle) );
+ }
+
+ beans::PropertyValues aGrabBag = pEntry->GetInteropGrabBagSeq();
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY);
+ if (aGrabBag.hasElements())
+ {
+ xPropertySet->setPropertyValue("StyleInteropGrabBag", uno::Any(aGrabBag));
+ }
+
+ // Only paragraph styles support automatic updates.
+ if (pEntry->bAutoRedefine && bParaStyle)
+ xPropertySet->setPropertyValue("IsAutoUpdate", uno::Any(true));
+ }
+ else if(pEntry->nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ // If this is a table style, save its contents as-is for roundtrip purposes.
+ TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(pEntry.get());
+ aTableStylesVec.push_back(pTableEntry->GetInteropGrabBag());
+
+ // if DocDefaults exist, MS Word includes these in the table style definition.
+ pEntry->pProperties->InsertProps( m_pImpl->m_pDefaultCharProps, /*bOverwrite=*/false );
+ pEntry->pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false );
+ }
+ }
+
+ // Update the styles that were created before their parents or next-styles
+ for( auto const & iter : aMissingParent )
+ {
+ iter.second->setParentStyle( iter.first );
+ }
+
+ for( auto const & iter : aMissingFollow )
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(iter.second, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue( "FollowStyle", uno::Any(iter.first) );
+ }
+ catch( uno::Exception & ) {}
+ }
+
+ // Update the styles that were created before their linked styles.
+ for (auto const& rLinked : aMissingLink)
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(rLinked.second,
+ uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("LinkStyle", uno::Any(rLinked.first));
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION(
+ "writerfilter",
+ "StyleSheetTable::ApplyStyleSheets: failed to set LinkStyle");
+ }
+ }
+
+ if (!aTableStylesVec.empty())
+ {
+ // If we had any table styles, add a new document-level InteropGrabBag entry for them.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_pImpl->m_xTextDocument, uno::UNO_QUERY);
+ uno::Any aAny = xPropertySet->getPropertyValue("InteropGrabBag");
+ auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
+ beans::PropertyValue aValue;
+ aValue.Name = "tableStyles";
+ aValue.Value <<= comphelper::containerToSequence(aTableStylesVec);
+ aGrabBag.push_back(aValue);
+ xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Styles could not be imported completely");
+ }
+}
+
+
+StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByISTD(const OUString& sIndex)
+{
+ auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(sIndex);
+ if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end())
+ return findIt->second;
+ return StyleSheetEntryPtr();
+}
+
+
+StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByConvertedStyleName(std::u16string_view sIndex)
+{
+ StyleSheetEntryPtr pRet;
+ for(const StyleSheetEntryPtr & rpEntry : m_pImpl->m_aStyleSheetEntries)
+ {
+ if( rpEntry->sConvertedStyleName == sIndex)
+ {
+ pRet = rpEntry;
+ break;
+ }
+ }
+ return pRet;
+}
+
+
+StyleSheetEntryPtr StyleSheetTable::FindDefaultParaStyle()
+{
+ return FindStyleSheetByISTD( m_pImpl->m_sDefaultParaStyleName );
+}
+
+const StyleSheetEntryPtr & StyleSheetTable::GetCurrentEntry() const
+{
+ return m_pImpl->m_pCurrentEntry;
+}
+
+OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExtendedSearch)
+{
+ OUString sRet( rWWName );
+ if( bExtendedSearch )
+ {
+ //search for the rWWName in the IdentifierD of the existing styles and convert the sStyleName member
+ auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(rWWName);
+ if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end())
+ sRet = findIt->second->sStyleName;
+ }
+
+ // create a map only once
+ static const std::map< OUString, OUString> StyleNameMap {
+ { "Normal", "Standard" },
+ { "heading 1", "Heading 1" },
+ { "heading 2", "Heading 2" },
+ { "heading 3", "Heading 3" },
+ { "heading 4", "Heading 4" },
+ { "heading 5", "Heading 5" },
+ { "heading 6", "Heading 6" },
+ { "heading 7", "Heading 7" },
+ { "heading 8", "Heading 8" },
+ { "heading 9", "Heading 9" },
+ { "Heading 1", "Heading 1" },
+ { "Heading 2", "Heading 2" },
+ { "Heading 3", "Heading 3" },
+ { "Heading 4", "Heading 4" },
+ { "Heading 5", "Heading 5" },
+ { "Heading 6", "Heading 6" },
+ { "Heading 7", "Heading 7" },
+ { "Heading 8", "Heading 8" },
+ { "Heading 9", "Heading 9" },
+ { "Index 1", "Index 1" },
+ { "Index 2", "Index 2" },
+ { "Index 3", "Index 3" },
+// { "Index 4", "" },
+// { "Index 5", "" },
+// { "Index 6", "" },
+// { "Index 7", "" },
+// { "Index 8", "" },
+// { "Index 9", "" },
+ { "TOC 1", "Contents 1" },
+ { "TOC 2", "Contents 2" },
+ { "TOC 3", "Contents 3" },
+ { "TOC 4", "Contents 4" },
+ { "TOC 5", "Contents 5" },
+ { "TOC 6", "Contents 6" },
+ { "TOC 7", "Contents 7" },
+ { "TOC 8", "Contents 8" },
+ { "TOC 9", "Contents 9" },
+ { "TOC Heading", "Contents Heading" },
+ { "TOCHeading", "Contents Heading" },
+ { "toc 1", "Contents 1" },
+ { "toc 2", "Contents 2" },
+ { "toc 3", "Contents 3" },
+ { "toc 4", "Contents 4" },
+ { "toc 5", "Contents 5" },
+ { "toc 6", "Contents 6" },
+ { "toc 7", "Contents 7" },
+ { "toc 8", "Contents 8" },
+ { "toc 9", "Contents 9" },
+ { "TOC1", "Contents 1" },
+ { "TOC2", "Contents 2" },
+ { "TOC3", "Contents 3" },
+ { "TOC4", "Contents 4" },
+ { "TOC5", "Contents 5" },
+ { "TOC6", "Contents 6" },
+ { "TOC7", "Contents 7" },
+ { "TOC8", "Contents 8" },
+ { "TOC9", "Contents 9" },
+// { "Normal Indent", "" },
+ { "footnote text", "Footnote" },
+ { "Footnote Text", "Footnote" },
+// { "Annotation Text", "" },
+ { "Header", "Header" },
+ { "header", "Header" },
+ { "Footer", "Footer" },
+ { "footer", "Footer" },
+ { "Index Heading", "Index Heading" },
+// { "Caption", "" },
+// { "Table of Figures", "" },
+ { "Envelope Address", "Addressee" },
+ { "Envelope Return", "Sender" },
+ { "footnote reference", "Footnote Symbol" },
+ { "Footnote Reference", "Footnote Symbol" },
+// { "Annotation Reference", "" },
+ { "Line Number", "Line numbering" },
+ { "Page Number", "Page Number" },
+ { "endnote reference", "Endnote Symbol" },
+ { "Endnote Reference", "Endnote Symbol" },
+ { "endnote text", "Endnote" },
+ { "Endnote Text", "Endnote" },
+// { "Table of Authorities", "" },
+// { "Macro Text", "" },
+// { "TOA Heading", "" },
+ { "List", "List" },
+// { "List 2", "" },
+// { "List 3", "" },
+// { "List 4", "" },
+// { "List 5", "" },
+// { "List Bullet", "" },
+// { "List Bullet 2", "" },
+// { "List Bullet 3", "" },
+// { "List Bullet 4", "" },
+// { "List Bullet 5", "" },
+// { "List Number", "" },
+// { "List Number 2", "" },
+// { "List Number 3", "" },
+// { "List Number 4", "" },
+// { "List Number 5", "" },
+ { "Title", "Title" },
+// { "Closing", "" },
+ { "Signature", "Signature" },
+// { "Default Paragraph Font", "" },
+ { "DefaultParagraphFont", "Default Paragraph Font" },
+ { "Body Text", "Text body" },
+ { "BodyText", "Text body" },
+ { "BodyTextIndentItalic", "Text body indent italic" },
+ { "Body Text Indent", "Text body indent" },
+ { "BodyTextIndent", "Text body indent" },
+ { "BodyTextIndent2", "Text body indent2" },
+// { "List Continue", "" },
+// { "List Continue 2", "" },
+// { "List Continue 3", "" },
+// { "List Continue 4", "" },
+// { "List Continue 5", "" },
+// { "Message Header", "" },
+ { "Subtitle", "Subtitle" },
+// { "Salutation", "" },
+// { "Date", "" },
+ { "Body Text First Indent", "Body Text Indent" },
+// { "Body Text First Indent 2", "" },
+// { "Note Heading", "" },
+// { "Body Text 2", "" },
+// { "Body Text 3", "" },
+// { "Body Text Indent 2", "" },
+// { "Body Text Indent 3", "" },
+// { "Block Text", "" },
+ { "Hyperlink", "Internet link" },
+ { "FollowedHyperlink", "Visited Internet Link" },
+ { "Emphasis", "Emphasis" },
+// { "Document Map", "" },
+// { "Plain Text", "" },
+ { "NoList", "No List" },
+ { "AbstractHeading", "Abstract Heading" },
+ { "AbstractBody", "Abstract Body" },
+ { "PageNumber", "page number" },
+ { "TableNormal", "Normal Table" },
+ { "DocumentMap", "Document Map" },
+ };
+
+ // find style-name using map
+ if (const auto aIt = StyleNameMap.find(sRet); aIt != StyleNameMap.end())
+ {
+ sRet = aIt->second;
+ }
+ else
+ {
+ // Style names which should not be used without a " (user)" suffix
+ static const o3tl::sorted_vector<OUString> ReservedStyleNames = [] {
+ o3tl::sorted_vector<OUString> set;
+ for (const auto& pair : StyleNameMap)
+ set.insert(pair.second);
+ return set;
+ }();
+ // SwStyleNameMapper doc says: If the UI style name equals a
+ // programmatic name, then it must append " (user)" to the end.
+ if (ReservedStyleNames.find(sRet) != ReservedStyleNames.end())
+ sRet += " (user)";
+ }
+
+ return sRet;
+}
+
+void StyleSheetTable::applyDefaults(bool bParaProperties)
+{
+ try{
+
+ if (!m_pImpl->m_bIsNewDoc)
+ {
+ // tdf#72942: do not corrupts original styles in master document
+ // during inserting of text from second document
+ return;
+ }
+
+ if(!m_pImpl->m_xTextDefaults.is())
+ {
+ m_pImpl->m_xTextDefaults.set(
+ m_pImpl->m_rDMapper.GetTextFactory()->createInstance("com.sun.star.text.Defaults"),
+ uno::UNO_QUERY_THROW );
+ }
+
+ // WARNING: these defaults only take effect IF there is a DocDefaults style section. Normally there is, but not always.
+ if( bParaProperties && m_pImpl->m_pDefaultParaProps)
+ {
+ // tdf#87533 LO will have different defaults here, depending on the locale. Import with documented defaults
+ SetDefaultParaProps(PROP_WRITING_MODE, uno::Any(sal_Int16(text::WritingMode_LR_TB)));
+ SetDefaultParaProps(PROP_PARA_ADJUST, uno::Any(sal_Int16(style::ParagraphAdjust_LEFT)));
+
+ // Widow/Orphan -> set both to two if not already set
+ uno::Any aTwo(sal_Int8(2));
+ SetDefaultParaProps(PROP_PARA_WIDOWS, aTwo);
+ SetDefaultParaProps(PROP_PARA_ORPHANS, aTwo);
+
+ uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(m_pImpl->m_xTextDocument, uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xParagraphStyles;
+ xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles;
+ uno::Reference<beans::XPropertySet> xDefault;
+ // This is the built-in default style that every style inherits from
+ xParagraphStyles->getByName("Paragraph style") >>= xDefault;
+
+ const uno::Sequence< beans::PropertyValue > aPropValues = m_pImpl->m_pDefaultParaProps->GetPropertyValues();
+ for( const auto& rPropValue : aPropValues )
+ {
+ try
+ {
+ xDefault->setPropertyValue(rPropValue.Name, rPropValue.Value);
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "setPropertyValue");
+ }
+ }
+ }
+ if( !bParaProperties && m_pImpl->m_pDefaultCharProps )
+ {
+ // tdf#108350: Earlier in DomainMapper for DOCX, Calibri/11pt was set to match MSWord 2007+,
+ // but that is valid only if DocDefaults_rPrDefault is omitted.
+ // Now that DocDefaults_rPrDefault is known, the defaults should be reset to Times New Roman/10pt.
+ if ( m_pImpl->m_rDMapper.IsOOXMLImport() )
+ m_pImpl->m_xTextDefaults->setPropertyValue( getPropertyName(PROP_CHAR_FONT_NAME), css::uno::Any(OUString("Times New Roman")) );
+
+ const uno::Sequence< beans::PropertyValue > aPropValues = m_pImpl->m_pDefaultCharProps->GetPropertyValues();
+ for( const auto& rPropValue : aPropValues )
+ {
+ try
+ {
+ m_pImpl->m_xTextDefaults->setPropertyValue( rPropValue.Name, rPropValue.Value );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "exception");
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+
+OUString StyleSheetTable::getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate )
+{
+ //find out if any of the styles already has the required properties then return its name
+ OUString sListLabel = m_pImpl->HasListCharStyle(rCharProperties);
+ // Don't try to reuse an existing character style if requested.
+ if( !sListLabel.isEmpty() && !bAlwaysCreate)
+ return sListLabel;
+
+ //create a new one otherwise
+ const uno::Reference< container::XNameContainer >& xCharStyles = m_pImpl->m_rDMapper.GetCharacterStyles();
+ sListLabel = m_pImpl->m_rDMapper.GetUnusedCharacterStyleName();
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ try
+ {
+ uno::Reference< style::XStyle > xStyle( xDocFactory->createInstance(
+ getPropertyName( PROP_SERVICE_CHAR_STYLE )), uno::UNO_QUERY_THROW);
+ uno::Reference< beans::XPropertySet > xStyleProps(xStyle, uno::UNO_QUERY_THROW );
+ for( const auto& rCharProp : rCharProperties)
+ {
+ try
+ {
+ xStyleProps->setPropertyValue( rCharProp.Name, rCharProp.Value );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "StyleSheetTable::getOrCreateCharStyle - Style::setPropertyValue");
+ }
+ }
+ xCharStyles->insertByName( sListLabel, uno::Any( xStyle) );
+ m_pImpl->m_aListCharStylePropertyVector.emplace_back( sListLabel, std::vector(rCharProperties) );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "StyleSheetTable::getOrCreateCharStyle");
+ }
+
+ return sListLabel;
+}
+
+}//namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/StyleSheetTable.hxx b/writerfilter/source/dmapper/StyleSheetTable.hxx
new file mode 100644
index 000000000..5dcf84b78
--- /dev/null
+++ b/writerfilter/source/dmapper/StyleSheetTable.hxx
@@ -0,0 +1,150 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include "TblStylePrHandler.hxx"
+
+#include "DomainMapper.hxx"
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include "PropertyMap.hxx"
+#include "FontTable.hxx"
+#include "LoggedResources.hxx"
+
+namespace com::sun::star::text { class XTextDocument; }
+
+
+namespace writerfilter::dmapper
+{
+
+
+enum StyleType
+{
+ STYLE_TYPE_UNKNOWN,
+ STYLE_TYPE_PARA,
+ STYLE_TYPE_CHAR,
+ STYLE_TYPE_TABLE,
+ STYLE_TYPE_LIST
+};
+class StyleSheetTable;
+typedef tools::SvRef<StyleSheetTable> StyleSheetTablePtr;
+
+struct StyleSheetTable_Impl;
+class StyleSheetEntry : public virtual SvRefBase
+{
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+public:
+ OUString sStyleIdentifierD; // WW8 name
+ bool bIsDefaultStyle;
+ bool bAssignedAsChapterNumbering;
+ bool bInvalidHeight;
+ bool bHasUPE; //universal property expansion
+ StyleType nStyleTypeCode; //sgc
+ OUString sBaseStyleIdentifier;
+ OUString sNextStyleIdentifier;
+ OUString sLinkStyleIdentifier;
+ OUString sStyleName;
+ const tools::SvRef<StyleSheetPropertyMap> pProperties;
+ OUString sConvertedStyleName;
+ std::vector<css::beans::PropertyValue> aLatentStyles; ///< Attributes of latentStyles
+ std::vector<css::beans::PropertyValue> aLsdExceptions; ///< List of lsdException attribute lists
+ bool bAutoRedefine; ///< Writer calls this auto-update.
+
+ void AppendInteropGrabBag(const css::beans::PropertyValue& rValue);
+ css::beans::PropertyValue GetInteropGrabBag(); ///< Used for table styles, has a name.
+ css::beans::PropertyValues GetInteropGrabBagSeq() const; ///< Used for existing styles, just a list of properties.
+
+ // Get all properties, merged with the all of the parent's properties
+ PropertyMapPtr GetMergedInheritedProperties(const StyleSheetTablePtr& pStyleSheetTable);
+
+ StyleSheetEntry();
+ virtual ~StyleSheetEntry() override;
+};
+
+typedef tools::SvRef<StyleSheetEntry> StyleSheetEntryPtr;
+
+class DomainMapper;
+class StyleSheetTable :
+ public LoggedProperties,
+ public LoggedTable
+{
+ std::unique_ptr<StyleSheetTable_Impl> m_pImpl;
+
+public:
+ StyleSheetTable(DomainMapper& rDMapper, css::uno::Reference<css::text::XTextDocument> const& xTextDocument, bool bIsNewDoc);
+ virtual ~StyleSheetTable() override;
+
+ void ReApplyInheritedOutlineLevelFromChapterNumbering();
+ void ApplyNumberingStyleNameToParaStyles();
+ void ApplyStyleSheets( const FontTablePtr& rFontTable );
+ StyleSheetEntryPtr FindStyleSheetByISTD(const OUString& sIndex);
+ StyleSheetEntryPtr FindStyleSheetByConvertedStyleName(std::u16string_view rIndex);
+ StyleSheetEntryPtr FindDefaultParaStyle();
+
+ OUString ConvertStyleName( const OUString& rWWName, bool bExtendedSearch = false );
+
+ OUString getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate );
+
+ void SetDefaultParaProps(PropertyIds eId, const css::uno::Any& rAny);
+ PropertyMapPtr const & GetDefaultParaProps() const;
+ /// Returns the default character properties.
+ PropertyMapPtr const & GetDefaultCharProps() const;
+
+ const StyleSheetEntryPtr & GetCurrentEntry() const;
+
+private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+ void applyDefaults(bool bParaProperties);
+};
+
+
+class TableStyleSheetEntry :
+ public StyleSheetEntry
+{
+public:
+ // Adds a new tblStylePr to the table style entry. This method
+ // fixes some possible properties conflicts, like borders ones.
+ void AddTblStylePr( TblStyleType nType, const PropertyMapPtr& pProps );
+
+ // Gets all the properties
+ // + corresponding to the mask,
+ // + from the parent styles
+
+ // @param mask mask describing which properties to return
+ PropertyMapPtr GetProperties( sal_Int32 nMask);
+
+ TableStyleSheetEntry( StyleSheetEntry const & aEntry );
+ virtual ~TableStyleSheetEntry( ) override;
+
+private:
+ typedef std::map<TblStyleType, PropertyMapPtr> TblStylePrs;
+ TblStylePrs m_aStyles;
+ PropertyMapPtr GetLocalPropertiesFromMask( sal_Int32 nMask );
+};
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TDefTableHandler.cxx b/writerfilter/source/dmapper/TDefTableHandler.cxx
new file mode 100644
index 000000000..c47ac7db8
--- /dev/null
+++ b/writerfilter/source/dmapper/TDefTableHandler.cxx
@@ -0,0 +1,458 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "TDefTableHandler.hxx"
+#include "PropertyMap.hxx"
+#include "ConversionHelper.hxx"
+#include <ooxml/resourceids.hxx>
+#include <filter/msfilter/util.hxx>
+#include <tools/color.hxx>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <comphelper/sequence.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+TDefTableHandler::TDefTableHandler() :
+LoggedProperties("TDefTableHandler"),
+m_nLineWidth(0),
+m_nLineType(0),
+m_nLineColor(0)
+{
+}
+
+
+TDefTableHandler::~TDefTableHandler()
+{
+}
+
+OUString TDefTableHandler::getBorderTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_Value_ST_Border_nil: return "nil";
+ case NS_ooxml::LN_Value_ST_Border_none: return "none";
+ case NS_ooxml::LN_Value_ST_Border_single: return "single";
+ case NS_ooxml::LN_Value_ST_Border_thick: return "thick";
+ case NS_ooxml::LN_Value_ST_Border_double: return "double";
+ case NS_ooxml::LN_Value_ST_Border_dotted: return "dotted";
+ case NS_ooxml::LN_Value_ST_Border_dashed: return "dashed";
+ case NS_ooxml::LN_Value_ST_Border_dotDash: return "dotDash";
+ case NS_ooxml::LN_Value_ST_Border_dotDotDash: return "dotDotDash";
+ case NS_ooxml::LN_Value_ST_Border_triple: return "triple";
+ case NS_ooxml::LN_Value_ST_Border_thinThickSmallGap: return "thinThickSmallGap";
+ case NS_ooxml::LN_Value_ST_Border_thickThinSmallGap: return "thickThinSmallGap";
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinSmallGap: return "thinThickThinSmallGap";
+ case NS_ooxml::LN_Value_ST_Border_thinThickMediumGap: return "thinThickMediumGap";
+ case NS_ooxml::LN_Value_ST_Border_thickThinMediumGap: return "thickThinMediumGap";
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinMediumGap: return "thinThickThinMediumGap";
+ case NS_ooxml::LN_Value_ST_Border_thinThickLargeGap: return "thinThickLargeGap";
+ case NS_ooxml::LN_Value_ST_Border_thickThinLargeGap: return "thickThinLargeGap";
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinLargeGap: return "thinThickThinLargeGap";
+ case NS_ooxml::LN_Value_ST_Border_wave: return "wave";
+ case NS_ooxml::LN_Value_ST_Border_doubleWave: return "doubleWave";
+ case NS_ooxml::LN_Value_ST_Border_dashSmallGap: return "dashSmallGap";
+ case NS_ooxml::LN_Value_ST_Border_dashDotStroked: return "dashDotStroked";
+ case NS_ooxml::LN_Value_ST_Border_threeDEmboss: return "threeDEmboss";
+ case NS_ooxml::LN_Value_ST_Border_threeDEngrave: return "threeDEngrave";
+ case NS_ooxml::LN_Value_ST_Border_outset: return "outset";
+ case NS_ooxml::LN_Value_ST_Border_inset: return "inset";
+ case NS_ooxml::LN_Value_ST_Border_apples: return "apples";
+ case NS_ooxml::LN_Value_ST_Border_archedScallops: return "archedScallops";
+ case NS_ooxml::LN_Value_ST_Border_babyPacifier: return "babyPacifier";
+ case NS_ooxml::LN_Value_ST_Border_babyRattle: return "babyRattle";
+ case NS_ooxml::LN_Value_ST_Border_balloons3Colors: return "balloons3Colors";
+ case NS_ooxml::LN_Value_ST_Border_balloonsHotAir: return "balloonsHotAir";
+ case NS_ooxml::LN_Value_ST_Border_basicBlackDashes: return "basicBlackDashes";
+ case NS_ooxml::LN_Value_ST_Border_basicBlackDots: return "basicBlackDots";
+ case NS_ooxml::LN_Value_ST_Border_basicBlackSquares: return "basicBlackSquares";
+ case NS_ooxml::LN_Value_ST_Border_basicThinLines: return "basicThinLines";
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteDashes: return "basicWhiteDashes";
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteDots: return "basicWhiteDots";
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteSquares: return "basicWhiteSquares";
+ case NS_ooxml::LN_Value_ST_Border_basicWideInline: return "basicWideInline";
+ case NS_ooxml::LN_Value_ST_Border_basicWideMidline: return "basicWideMidline";
+ case NS_ooxml::LN_Value_ST_Border_basicWideOutline: return "basicWideOutline";
+ case NS_ooxml::LN_Value_ST_Border_bats: return "bats";
+ case NS_ooxml::LN_Value_ST_Border_birds: return "birds";
+ case NS_ooxml::LN_Value_ST_Border_birdsFlight: return "birdsFlight";
+ case NS_ooxml::LN_Value_ST_Border_cabins: return "cabins";
+ case NS_ooxml::LN_Value_ST_Border_cakeSlice: return "cakeSlice";
+ case NS_ooxml::LN_Value_ST_Border_candyCorn: return "candyCorn";
+ case NS_ooxml::LN_Value_ST_Border_celticKnotwork: return "celticKnotwork";
+ case NS_ooxml::LN_Value_ST_Border_certificateBanner: return "certificateBanner";
+ case NS_ooxml::LN_Value_ST_Border_chainLink: return "chainLink";
+ case NS_ooxml::LN_Value_ST_Border_champagneBottle: return "champagneBottle";
+ case NS_ooxml::LN_Value_ST_Border_checkedBarBlack: return "checkedBarBlack";
+ case NS_ooxml::LN_Value_ST_Border_checkedBarColor: return "checkedBarColor";
+ case NS_ooxml::LN_Value_ST_Border_checkered: return "checkered";
+ case NS_ooxml::LN_Value_ST_Border_christmasTree: return "christmasTree";
+ case NS_ooxml::LN_Value_ST_Border_circlesLines: return "circlesLines";
+ case NS_ooxml::LN_Value_ST_Border_circlesRectangles: return "circlesRectangles";
+ case NS_ooxml::LN_Value_ST_Border_classicalWave: return "classicalWave";
+ case NS_ooxml::LN_Value_ST_Border_clocks: return "clocks";
+ case NS_ooxml::LN_Value_ST_Border_compass: return "compass";
+ case NS_ooxml::LN_Value_ST_Border_confetti: return "confetti";
+ case NS_ooxml::LN_Value_ST_Border_confettiGrays: return "confettiGrays";
+ case NS_ooxml::LN_Value_ST_Border_confettiOutline: return "confettiOutline";
+ case NS_ooxml::LN_Value_ST_Border_confettiStreamers: return "confettiStreamers";
+ case NS_ooxml::LN_Value_ST_Border_confettiWhite: return "confettiWhite";
+ case NS_ooxml::LN_Value_ST_Border_cornerTriangles: return "cornerTriangles";
+ case NS_ooxml::LN_Value_ST_Border_couponCutoutDashes: return "couponCutoutDashes";
+ case NS_ooxml::LN_Value_ST_Border_couponCutoutDots: return "couponCutoutDots";
+ case NS_ooxml::LN_Value_ST_Border_crazyMaze: return "crazyMaze";
+ case NS_ooxml::LN_Value_ST_Border_creaturesButterfly: return "creaturesButterfly";
+ case NS_ooxml::LN_Value_ST_Border_creaturesFish: return "creaturesFish";
+ case NS_ooxml::LN_Value_ST_Border_creaturesInsects: return "creaturesInsects";
+ case NS_ooxml::LN_Value_ST_Border_creaturesLadyBug: return "creaturesLadyBug";
+ case NS_ooxml::LN_Value_ST_Border_crossStitch: return "crossStitch";
+ case NS_ooxml::LN_Value_ST_Border_cup: return "cup";
+ case NS_ooxml::LN_Value_ST_Border_decoArch: return "decoArch";
+ case NS_ooxml::LN_Value_ST_Border_decoArchColor: return "decoArchColor";
+ case NS_ooxml::LN_Value_ST_Border_decoBlocks: return "decoBlocks";
+ case NS_ooxml::LN_Value_ST_Border_diamondsGray: return "diamondsGray";
+ case NS_ooxml::LN_Value_ST_Border_doubleD: return "doubleD";
+ case NS_ooxml::LN_Value_ST_Border_doubleDiamonds: return "doubleDiamonds";
+ case NS_ooxml::LN_Value_ST_Border_earth1: return "earth1";
+ case NS_ooxml::LN_Value_ST_Border_earth2: return "earth2";
+ case NS_ooxml::LN_Value_ST_Border_eclipsingSquares1: return "eclipsingSquares1";
+ case NS_ooxml::LN_Value_ST_Border_eclipsingSquares2: return "eclipsingSquares2";
+ case NS_ooxml::LN_Value_ST_Border_eggsBlack: return "eggsBlack";
+ case NS_ooxml::LN_Value_ST_Border_fans: return "fans";
+ case NS_ooxml::LN_Value_ST_Border_film: return "film";
+ case NS_ooxml::LN_Value_ST_Border_firecrackers: return "firecrackers";
+ case NS_ooxml::LN_Value_ST_Border_flowersBlockPrint: return "flowersBlockPrint";
+ case NS_ooxml::LN_Value_ST_Border_flowersDaisies: return "flowersDaisies";
+ case NS_ooxml::LN_Value_ST_Border_flowersModern1: return "flowersModern1";
+ case NS_ooxml::LN_Value_ST_Border_flowersModern2: return "flowersModern2";
+ case NS_ooxml::LN_Value_ST_Border_flowersPansy: return "flowersPansy";
+ case NS_ooxml::LN_Value_ST_Border_flowersRedRose: return "flowersRedRose";
+ case NS_ooxml::LN_Value_ST_Border_flowersRoses: return "flowersRoses";
+ case NS_ooxml::LN_Value_ST_Border_flowersTeacup: return "flowersTeacup";
+ case NS_ooxml::LN_Value_ST_Border_flowersTiny: return "flowersTiny";
+ case NS_ooxml::LN_Value_ST_Border_gems: return "gems";
+ case NS_ooxml::LN_Value_ST_Border_gingerbreadMan: return "gingerbreadMan";
+ case NS_ooxml::LN_Value_ST_Border_gradient: return "gradient";
+ case NS_ooxml::LN_Value_ST_Border_handmade1: return "handmade1";
+ case NS_ooxml::LN_Value_ST_Border_handmade2: return "handmade2";
+ case NS_ooxml::LN_Value_ST_Border_heartBalloon: return "heartBalloon";
+ case NS_ooxml::LN_Value_ST_Border_heartGray: return "heartGray";
+ case NS_ooxml::LN_Value_ST_Border_hearts: return "hearts";
+ case NS_ooxml::LN_Value_ST_Border_heebieJeebies: return "heebieJeebies";
+ case NS_ooxml::LN_Value_ST_Border_holly: return "holly";
+ case NS_ooxml::LN_Value_ST_Border_houseFunky: return "houseFunky";
+ case NS_ooxml::LN_Value_ST_Border_hypnotic: return "hypnotic";
+ case NS_ooxml::LN_Value_ST_Border_iceCreamCones: return "iceCreamCones";
+ case NS_ooxml::LN_Value_ST_Border_lightBulb: return "lightBulb";
+ case NS_ooxml::LN_Value_ST_Border_lightning1: return "lightning1";
+ case NS_ooxml::LN_Value_ST_Border_lightning2: return "lightning2";
+ case NS_ooxml::LN_Value_ST_Border_mapPins: return "mapPins";
+ case NS_ooxml::LN_Value_ST_Border_mapleLeaf: return "mapleLeaf";
+ case NS_ooxml::LN_Value_ST_Border_mapleMuffins: return "mapleMuffins";
+ case NS_ooxml::LN_Value_ST_Border_marquee: return "marquee";
+ case NS_ooxml::LN_Value_ST_Border_marqueeToothed: return "marqueeToothed";
+ case NS_ooxml::LN_Value_ST_Border_moons: return "moons";
+ case NS_ooxml::LN_Value_ST_Border_mosaic: return "mosaic";
+ case NS_ooxml::LN_Value_ST_Border_musicNotes: return "musicNotes";
+ case NS_ooxml::LN_Value_ST_Border_northwest: return "northwest";
+ case NS_ooxml::LN_Value_ST_Border_ovals: return "ovals";
+ case NS_ooxml::LN_Value_ST_Border_packages: return "packages";
+ case NS_ooxml::LN_Value_ST_Border_palmsBlack: return "palmsBlack";
+ case NS_ooxml::LN_Value_ST_Border_palmsColor: return "palmsColor";
+ case NS_ooxml::LN_Value_ST_Border_paperClips: return "paperClips";
+ case NS_ooxml::LN_Value_ST_Border_papyrus: return "papyrus";
+ case NS_ooxml::LN_Value_ST_Border_partyFavor: return "partyFavor";
+ case NS_ooxml::LN_Value_ST_Border_partyGlass: return "partyGlass";
+ case NS_ooxml::LN_Value_ST_Border_pencils: return "pencils";
+ case NS_ooxml::LN_Value_ST_Border_people: return "people";
+ case NS_ooxml::LN_Value_ST_Border_peopleWaving: return "peopleWaving";
+ case NS_ooxml::LN_Value_ST_Border_peopleHats: return "peopleHats";
+ case NS_ooxml::LN_Value_ST_Border_poinsettias: return "poinsettias";
+ case NS_ooxml::LN_Value_ST_Border_postageStamp: return "postageStamp";
+ case NS_ooxml::LN_Value_ST_Border_pumpkin1: return "pumpkin1";
+ case NS_ooxml::LN_Value_ST_Border_pushPinNote2: return "pushPinNote2";
+ case NS_ooxml::LN_Value_ST_Border_pushPinNote1: return "pushPinNote1";
+ case NS_ooxml::LN_Value_ST_Border_pyramids: return "pyramids";
+ case NS_ooxml::LN_Value_ST_Border_pyramidsAbove: return "pyramidsAbove";
+ case NS_ooxml::LN_Value_ST_Border_quadrants: return "quadrants";
+ case NS_ooxml::LN_Value_ST_Border_rings: return "rings";
+ case NS_ooxml::LN_Value_ST_Border_safari: return "safari";
+ case NS_ooxml::LN_Value_ST_Border_sawtooth: return "sawtooth";
+ case NS_ooxml::LN_Value_ST_Border_sawtoothGray: return "sawtoothGray";
+ case NS_ooxml::LN_Value_ST_Border_scaredCat: return "scaredCat";
+ case NS_ooxml::LN_Value_ST_Border_seattle: return "seattle";
+ case NS_ooxml::LN_Value_ST_Border_shadowedSquares: return "shadowedSquares";
+ case NS_ooxml::LN_Value_ST_Border_sharksTeeth: return "sharksTeeth";
+ case NS_ooxml::LN_Value_ST_Border_shorebirdTracks: return "shorebirdTracks";
+ case NS_ooxml::LN_Value_ST_Border_skyrocket: return "skyrocket";
+ case NS_ooxml::LN_Value_ST_Border_snowflakeFancy: return "snowflakeFancy";
+ case NS_ooxml::LN_Value_ST_Border_snowflakes: return "snowflakes";
+ case NS_ooxml::LN_Value_ST_Border_sombrero: return "sombrero";
+ case NS_ooxml::LN_Value_ST_Border_southwest: return "southwest";
+ case NS_ooxml::LN_Value_ST_Border_stars: return "stars";
+ case NS_ooxml::LN_Value_ST_Border_starsTop: return "starsTop";
+ case NS_ooxml::LN_Value_ST_Border_stars3d: return "stars3d";
+ case NS_ooxml::LN_Value_ST_Border_starsBlack: return "starsBlack";
+ case NS_ooxml::LN_Value_ST_Border_starsShadowed: return "starsShadowed";
+ case NS_ooxml::LN_Value_ST_Border_sun: return "sun";
+ case NS_ooxml::LN_Value_ST_Border_swirligig: return "swirligig";
+ case NS_ooxml::LN_Value_ST_Border_tornPaper: return "tornPaper";
+ case NS_ooxml::LN_Value_ST_Border_tornPaperBlack: return "tornPaperBlack";
+ case NS_ooxml::LN_Value_ST_Border_trees: return "trees";
+ case NS_ooxml::LN_Value_ST_Border_triangleParty: return "triangleParty";
+ case NS_ooxml::LN_Value_ST_Border_triangles: return "triangles";
+ case NS_ooxml::LN_Value_ST_Border_tribal1: return "tribal1";
+ case NS_ooxml::LN_Value_ST_Border_tribal2: return "tribal2";
+ case NS_ooxml::LN_Value_ST_Border_tribal3: return "tribal3";
+ case NS_ooxml::LN_Value_ST_Border_tribal4: return "tribal4";
+ case NS_ooxml::LN_Value_ST_Border_tribal5: return "tribal5";
+ case NS_ooxml::LN_Value_ST_Border_tribal6: return "tribal6";
+ case NS_ooxml::LN_Value_ST_Border_twistedLines1: return "twistedLines1";
+ case NS_ooxml::LN_Value_ST_Border_twistedLines2: return "twistedLines2";
+ case NS_ooxml::LN_Value_ST_Border_vine: return "vine";
+ case NS_ooxml::LN_Value_ST_Border_waveline: return "waveline";
+ case NS_ooxml::LN_Value_ST_Border_weavingAngles: return "weavingAngles";
+ case NS_ooxml::LN_Value_ST_Border_weavingBraid: return "weavingBraid";
+ case NS_ooxml::LN_Value_ST_Border_weavingRibbon: return "weavingRibbon";
+ case NS_ooxml::LN_Value_ST_Border_weavingStrips: return "weavingStrips";
+ case NS_ooxml::LN_Value_ST_Border_whiteFlowers: return "whiteFlowers";
+ case NS_ooxml::LN_Value_ST_Border_woodwork: return "woodwork";
+ case NS_ooxml::LN_Value_ST_Border_xIllusions: return "xIllusions";
+ case NS_ooxml::LN_Value_ST_Border_zanyTriangles: return "zanyTriangles";
+ case NS_ooxml::LN_Value_ST_Border_zigZag: return "zigZag";
+ case NS_ooxml::LN_Value_ST_Border_zigZagStitch: return "zigZagStitch";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TDefTableHandler::getThemeColorTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_Value_St_ThemeColor_dark1: return "dark1";
+ case NS_ooxml::LN_Value_St_ThemeColor_light1: return "light1";
+ case NS_ooxml::LN_Value_St_ThemeColor_dark2: return "dark2";
+ case NS_ooxml::LN_Value_St_ThemeColor_light2: return "light2";
+ case NS_ooxml::LN_Value_St_ThemeColor_accent1: return "accent1";
+ case NS_ooxml::LN_Value_St_ThemeColor_accent2: return "accent2";
+ case NS_ooxml::LN_Value_St_ThemeColor_accent3: return "accent3";
+ case NS_ooxml::LN_Value_St_ThemeColor_accent4: return "accent4";
+ case NS_ooxml::LN_Value_St_ThemeColor_accent5: return "accent5";
+ case NS_ooxml::LN_Value_St_ThemeColor_accent6: return "accent6";
+ case NS_ooxml::LN_Value_St_ThemeColor_hyperlink: return "hyperlink";
+ case NS_ooxml::LN_Value_St_ThemeColor_followedHyperlink: return "followedHyperlink";
+ case NS_ooxml::LN_Value_St_ThemeColor_none: return "none";
+ case NS_ooxml::LN_Value_St_ThemeColor_background1: return "background1";
+ case NS_ooxml::LN_Value_St_ThemeColor_text1: return "text1";
+ case NS_ooxml::LN_Value_St_ThemeColor_background2: return "background2";
+ case NS_ooxml::LN_Value_St_ThemeColor_text2: return "text2";
+ default: break;
+ }
+ return OUString();
+}
+
+void TDefTableHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_Border_sz:
+ // width of a single line in 1/8 pt, max of 32 pt -> twip * 5 / 2.
+ m_nLineWidth = nIntValue * 5 / 2;
+ appendGrabBag("sz", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ m_nLineType = nIntValue;
+ appendGrabBag("val", TDefTableHandler::getBorderTypeString(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_color:
+ appendGrabBag("color", msfilter::util::ConvertColorOU(Color(ColorTransparency,nIntValue)));
+ m_nLineColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Border_space:
+ appendGrabBag("space", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ //if 1 then line has shadow - unsupported
+ case NS_ooxml::LN_CT_Border_frame:
+ // ignored
+ break;
+ case NS_ooxml::LN_CT_Border_themeColor:
+ appendGrabBag("themeColor", TDefTableHandler::getThemeColorTypeString(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_themeTint:
+ case NS_ooxml::LN_CT_Border_themeShade:
+ // ignored
+ break;
+ default:
+ OSL_FAIL("unknown attribute");
+ }
+}
+
+
+void TDefTableHandler::localResolve(Id rName, const writerfilter::Reference<Properties>::Pointer_t& pProperties)
+{
+ if( !pProperties )
+ return;
+
+ m_nLineWidth = m_nLineType = m_nLineColor = 0;
+ std::vector<beans::PropertyValue> aSavedGrabBag;
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ aSavedGrabBag = m_aInteropGrabBag;
+ m_aInteropGrabBag.clear();
+ }
+ pProperties->resolve( *this );
+ table::BorderLine2 aBorderLine;
+ ConversionHelper::MakeBorderLine(m_nLineWidth, m_nLineType, m_nLineColor, aBorderLine, /*bIsOOXML=*/true);
+ const bool rtl = false; // TODO
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_TcBorders_top:
+ m_aTopBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("top"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_start:
+ if( rtl )
+ m_aRightBorderLines.push_back(aBorderLine);
+ else
+ m_aLeftBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("start"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_left:
+ m_aLeftBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("left"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_bottom:
+ m_aBottomBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("bottom"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_end:
+ if( rtl )
+ m_aLeftBorderLines.push_back(aBorderLine);
+ else
+ m_aRightBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("end"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_right:
+ m_aRightBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("right"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_insideH:
+ m_aInsideHBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("insideH"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_insideV:
+ m_aInsideVBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("insideV"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_tl2br:
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("tl2br"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_tr2bl:
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("tr2bl"));
+ break;
+ default:;
+ }
+ if (!m_aInteropGrabBagName.isEmpty())
+ m_aInteropGrabBag = aSavedGrabBag;
+}
+
+
+void TDefTableHandler::lcl_sprm(Sprm & rSprm)
+{
+ switch( rSprm.getId() )
+ {
+ case NS_ooxml::LN_CT_TcBorders_top:
+ case NS_ooxml::LN_CT_TcBorders_left:
+ case NS_ooxml::LN_CT_TcBorders_start:
+ case NS_ooxml::LN_CT_TcBorders_bottom:
+ case NS_ooxml::LN_CT_TcBorders_right:
+ case NS_ooxml::LN_CT_TcBorders_end:
+ case NS_ooxml::LN_CT_TcBorders_insideH:
+ case NS_ooxml::LN_CT_TcBorders_insideV:
+ case NS_ooxml::LN_CT_TcBorders_tl2br:
+ case NS_ooxml::LN_CT_TcBorders_tr2bl:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ localResolve( rSprm.getId(), pProperties );
+ }
+ break;
+ default:;
+ }
+}
+
+void TDefTableHandler::fillCellProperties( const ::tools::SvRef< TablePropertyMap >& pCellProperties ) const
+{
+ if( !m_aTopBorderLines.empty() )
+ pCellProperties->Insert( PROP_TOP_BORDER, uno::Any( m_aTopBorderLines[0] ) );
+ if( !m_aLeftBorderLines.empty() )
+ pCellProperties->Insert( PROP_LEFT_BORDER, uno::Any( m_aLeftBorderLines[0] ) );
+ if( !m_aBottomBorderLines.empty() )
+ pCellProperties->Insert( PROP_BOTTOM_BORDER, uno::Any( m_aBottomBorderLines[0] ) );
+ if( !m_aRightBorderLines.empty() )
+ pCellProperties->Insert( PROP_RIGHT_BORDER, uno::Any( m_aRightBorderLines[0] ) );
+ if( !m_aInsideHBorderLines.empty() )
+ pCellProperties->Insert( META_PROP_HORIZONTAL_BORDER, uno::Any( m_aInsideHBorderLines[0] ) );
+ if( !m_aInsideVBorderLines.empty() )
+ pCellProperties->Insert( META_PROP_VERTICAL_BORDER, uno::Any( m_aInsideVBorderLines[0] ) );
+}
+
+
+void TDefTableHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue TDefTableHandler::getInteropGrabBag(const OUString& aName)
+{
+ beans::PropertyValue aRet;
+ if (aName.isEmpty())
+ aRet.Name = m_aInteropGrabBagName;
+ else
+ aRet.Name = aName;
+
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ m_aInteropGrabBag.clear();
+ return aRet;
+}
+
+void TDefTableHandler::appendGrabBag(const OUString& aKey, const OUString& aValue)
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ m_aInteropGrabBag.push_back(aProperty);
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TDefTableHandler.hxx b/writerfilter/source/dmapper/TDefTableHandler.hxx
new file mode 100644
index 000000000..17e6f2ed4
--- /dev/null
+++ b/writerfilter/source/dmapper/TDefTableHandler.hxx
@@ -0,0 +1,72 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+namespace com::sun::star{
+ namespace table {
+ struct BorderLine2;
+ }
+ namespace beans {
+ struct PropertyValue;
+ }
+}
+
+namespace writerfilter::dmapper
+{
+class PropertyMap;
+class TablePropertyMap;
+class TDefTableHandler : public LoggedProperties
+{
+ std::vector<css::table::BorderLine2> m_aLeftBorderLines;
+ std::vector<css::table::BorderLine2> m_aRightBorderLines;
+ std::vector<css::table::BorderLine2> m_aTopBorderLines;
+ std::vector<css::table::BorderLine2> m_aBottomBorderLines;
+ std::vector<css::table::BorderLine2> m_aInsideHBorderLines;
+ std::vector<css::table::BorderLine2> m_aInsideVBorderLines;
+
+ //values of the current border
+ sal_Int32 m_nLineWidth;
+ sal_Int32 m_nLineType;
+ sal_Int32 m_nLineColor;
+
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+ void appendGrabBag(const OUString& aKey, const OUString& aValue);
+
+ void localResolve(Id Name, const writerfilter::Reference<Properties>::Pointer_t& pProperties);
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ TDefTableHandler();
+ virtual ~TDefTableHandler() override;
+
+ void fillCellProperties( const ::tools::SvRef< TablePropertyMap >& pCellProperties) const;
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag(const OUString& aName = OUString());
+ static OUString getBorderTypeString(sal_Int32 nType);
+ static OUString getThemeColorTypeString(sal_Int32 nType);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TableData.hxx b/writerfilter/source/dmapper/TableData.hxx
new file mode 100644
index 000000000..a863e9d9f
--- /dev/null
+++ b/writerfilter/source/dmapper/TableData.hxx
@@ -0,0 +1,390 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/text/XTextRange.hpp>
+
+#include "PropertyMap.hxx"
+
+#include <vector>
+
+namespace writerfilter::dmapper
+{
+
+/**
+ Class containing the data to describe a table cell.
+ */
+class CellData final : public virtual SvRefBase
+{
+ /**
+ Handle to start of cell.
+ */
+ css::uno::Reference<css::text::XTextRange> mStart;
+
+ /**
+ Handle to end of cell.
+ */
+ css::uno::Reference<css::text::XTextRange> mEnd;
+
+ /**
+ Pointer to properties of cell.
+ */
+ TablePropertyMapPtr mpProps;
+
+ bool mbOpen;
+
+ sal_uInt32 m_nGridSpan; ///< number of grid columns in the parent table's table grid which this cell defines
+
+public:
+ typedef tools::SvRef<CellData> Pointer_t;
+
+ CellData(css::uno::Reference<css::text::XTextRange> const & start, TablePropertyMapPtr pProps)
+ : mStart(start), mEnd(start), mpProps(pProps), mbOpen(true)
+ , m_nGridSpan(1)
+ {
+ }
+
+ /**
+ Set the end handle of a cell.
+
+ @param end the end handle of the cell
+ */
+ void setEnd(css::uno::Reference<css::text::XTextRange> const & end) { mEnd = end; mbOpen = false; }
+
+ /**
+ Adds properties to the cell.
+
+ @param pProps the properties to add
+ */
+ void insertProperties(TablePropertyMapPtr pProps)
+ {
+ if( mpProps )
+ mpProps->InsertProps(pProps.get());
+ else
+ mpProps = pProps;
+ }
+
+ /**
+ Return start handle of the cell.
+ */
+ const css::uno::Reference<css::text::XTextRange>& getStart() const { return mStart; }
+
+ /**
+ Return end handle of the cell.
+ */
+ const css::uno::Reference<css::text::XTextRange>& getEnd() const { return mEnd; }
+
+ /**
+ Return properties of the cell.
+ */
+ const TablePropertyMapPtr& getProperties() const { return mpProps; }
+
+ bool isOpen() const { return mbOpen; }
+
+ sal_uInt32 getGridSpan() const { return m_nGridSpan; }
+ void setGridSpan( sal_uInt32 nSpan ) { m_nGridSpan = nSpan; }
+};
+
+/**
+ Class to handle data of a table row.
+ */
+class RowData final : public virtual SvRefBase
+{
+ typedef ::std::vector<CellData::Pointer_t> Cells;
+
+ /**
+ the cell data of the row
+ */
+ Cells mCells;
+
+ /**
+ the properties of the row
+ */
+ mutable TablePropertyMapPtr mpProperties;
+
+ sal_uInt32 m_nGridBefore; ///< number of grid columns in the parent table's table grid which must be skipped before the contents of this table row are added to the parent table
+ sal_uInt32 m_nGridAfter; ///< number of grid columns in the parent table's table grid which shall be left after the last cell in the table row
+
+public:
+ typedef tools::SvRef<RowData> Pointer_t;
+
+ RowData()
+ : m_nGridBefore(0)
+ , m_nGridAfter(0)
+ {
+ }
+
+ RowData(const RowData& rRowData)
+ : SvRefBase(), mCells(rRowData.mCells), mpProperties(rRowData.mpProperties)
+ , m_nGridBefore(rRowData.m_nGridBefore)
+ , m_nGridAfter(rRowData.m_nGridAfter)
+ {
+ }
+
+ /**
+ Add a cell to the row.
+
+ @param start the start handle of the cell
+ @param end the end handle of the cell
+ @param pProps the properties of the cell
+ @param bAddBefore true: add an empty cell at beginning of the row for gridBefore
+ */
+ void addCell(const css::uno::Reference<css::text::XTextRange>& start, TablePropertyMapPtr pProps, bool bAddBefore = false)
+ {
+ CellData::Pointer_t pCellData(new CellData(start, pProps));
+ if (bAddBefore)
+ {
+ mCells.insert(mCells.begin(), pCellData);
+ mCells[0]->setEnd(start);
+ }
+ else
+ mCells.push_back(pCellData);
+ }
+
+ void endCell(const css::uno::Reference<css::text::XTextRange>& end)
+ {
+ if (mCells.size() > 0)
+ mCells.back()->setEnd(end);
+ }
+
+ bool isCellOpen() const
+ {
+ return mCells.size() > 0 && mCells.back()->isOpen();
+ }
+
+ /**
+ Add properties to the row.
+
+ @param pProperties the properties to set
+ */
+ void insertProperties(TablePropertyMapPtr pProperties)
+ {
+ if( pProperties )
+ {
+ if( !mpProperties )
+ mpProperties = pProperties;
+ else
+ mpProperties->InsertProps(pProperties.get());
+ }
+ }
+
+ /**
+ Add properties to the last cell of the row.
+ */
+ void insertCellProperties(TablePropertyMapPtr pProps)
+ {
+ if (!mCells.empty())
+ mCells.back()->insertProperties(pProps);
+ }
+
+ /**
+ Return number of cells in the row.
+ */
+ unsigned int getCellCount() const
+ {
+ return mCells.size();
+ }
+
+ /**
+ Return start handle of a cell in the row.
+
+ @param i index of the cell
+ */
+ const css::uno::Reference<css::text::XTextRange>& getCellStart(unsigned int i) const
+ {
+ return mCells[i]->getStart();
+ }
+
+ /**
+ Return end handle of a cell in the row.
+
+ @param i index of the cell
+ */
+ const css::uno::Reference<css::text::XTextRange>& getCellEnd(unsigned int i) const
+ {
+ return mCells[i]->getEnd();
+ }
+
+ /**
+ Return the properties of a cell in the row.
+
+ @param i index of the cell
+ */
+ TablePropertyMapPtr const & getCellProperties(unsigned int i) const
+ {
+ return mCells[i]->getProperties();
+ }
+
+ /**
+ Return properties of the row.
+ */
+ const TablePropertyMapPtr& getProperties() const
+ {
+ return mpProperties;
+ }
+
+ sal_uInt32 getGridBefore() const { return m_nGridBefore; }
+ void setGridBefore(sal_uInt32 nSkipGrids) { m_nGridBefore = nSkipGrids; }
+ sal_uInt32 getGridAfter() const { return m_nGridAfter; }
+ void setGridAfter(sal_uInt32 nSkipGrids) { m_nGridAfter = nSkipGrids; }
+ sal_uInt32 getGridSpan(sal_uInt32 i) { return mCells[i]->getGridSpan(); }
+ std::vector< sal_uInt32 > getGridSpans()
+ {
+ std::vector< sal_uInt32 > nRet;
+ for (auto const& aCell: mCells)
+ nRet.push_back(aCell->getGridSpan());
+ return nRet;
+ }
+ void setCurrentGridSpan(sal_uInt32 nSpan, bool bFirstCell = false)
+ {
+ if ( mCells.size() )
+ {
+ if ( bFirstCell )
+ mCells.front()->setGridSpan(nSpan);
+ else
+ mCells.back()->setGridSpan(nSpan);
+ }
+ }
+};
+
+/**
+ Class that holds the data of a table.
+ */
+class TableData : public virtual SvRefBase
+{
+ typedef RowData::Pointer_t RowPointer_t;
+ typedef ::std::vector<RowPointer_t> Rows;
+
+ /**
+ the data of the rows of the table
+ */
+ Rows mRows;
+
+ /**
+ pointer to the data of the current row (while building up the table data).
+ */
+ RowPointer_t mpRow;
+
+ /**
+ depth of the current table in a hierarchy of tables
+ */
+ unsigned int mnDepth;
+
+ /**
+ initialize mpRow
+ */
+ void newRow() { mpRow = RowPointer_t(new RowData()); }
+
+public:
+ typedef tools::SvRef<TableData> Pointer_t;
+
+ explicit TableData(unsigned int nDepth) : mnDepth(nDepth) { newRow(); }
+
+ /**
+ End the current row.
+
+ Sets properties of the current row and pushes the row to the
+ back of the rows currently contained in the table.
+
+ @param pProperties properties of the row to be ended
+ */
+ void endRow(TablePropertyMapPtr pProperties)
+ {
+ mpRow->insertProperties(pProperties);
+ mRows.push_back(mpRow);
+ newRow();
+ }
+
+ /**
+ Add a cell to the current row.
+
+ @param start start handle of the cell
+ @param end end handle of the cell
+ @param pProps properties of the cell
+ */
+ void addCell(const css::uno::Reference<css::text::XTextRange>& start, TablePropertyMapPtr pProps)
+ {
+ mpRow->addCell(start, pProps);
+ }
+
+ /**
+ End the current cell of the current row.
+
+ @parm end end handle of the cell
+ */
+ void endCell(const css::uno::Reference<css::text::XTextRange>& end)
+ {
+ mpRow->endCell(end);
+ }
+
+ /**
+ Return if the current cell of the current row is open.
+ */
+ bool isCellOpen() const
+ {
+ return mpRow->isCellOpen();
+ }
+
+ /**
+ Insert properties to the current cell of the current row.
+
+ @param pProps the properties to add
+ */
+ void insertCellProperties(TablePropertyMapPtr pProps)
+ {
+ mpRow->insertCellProperties(pProps);
+ }
+
+ /**
+ Return number of rows in the table.
+ */
+ unsigned int getRowCount() const
+ {
+ return mRows.size();
+ }
+
+ /**
+ Return depth of table in surrounding table hierarchy.
+ */
+ unsigned int getDepth() const
+ {
+ return mnDepth;
+ }
+
+ /**
+ Return row data of a certain row.
+
+ @param i index of the row
+ */
+ RowPointer_t const & getRow(unsigned int i) const
+ {
+ return mRows[i];
+ }
+
+ const RowPointer_t& getCurrentRow() const
+ {
+ return mpRow;
+ }
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TableManager.cxx b/writerfilter/source/dmapper/TableManager.cxx
new file mode 100644
index 000000000..17fc3085d
--- /dev/null
+++ b/writerfilter/source/dmapper/TableManager.cxx
@@ -0,0 +1,609 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TableManager.hxx"
+#include <ooxml/resourceids.hxx>
+#include "TagLogger.hxx"
+#include "DomainMapperTableHandler.hxx"
+#include "DomainMapper_Impl.hxx"
+#include "util.hxx"
+
+#include <tools/diagnose_ex.h>
+
+namespace writerfilter::dmapper
+{
+void TableManager::clearData() {}
+
+void TableManager::openCell(const css::uno::Reference<css::text::XTextRange>& rHandle,
+ const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.openCell");
+ TagLogger::getInstance().chars(XTextRangeToString(rHandle));
+ TagLogger::getInstance().endElement();
+#endif
+
+ if (!mTableDataStack.empty())
+ {
+ TableData::Pointer_t pTableData = mTableDataStack.top();
+
+ pTableData->addCell(rHandle, pProps);
+ }
+}
+
+bool TableManager::isIgnore() const { return isRowEnd(); }
+
+sal_uInt32 TableManager::getGridBefore(sal_uInt32 nRow)
+{
+ assert(isInTable());
+ if (nRow >= mTableDataStack.top()->getRowCount())
+ return 0;
+ return mTableDataStack.top()->getRow(nRow)->getGridBefore();
+}
+
+sal_uInt32 TableManager::getCurrentGridBefore()
+{
+ return mTableDataStack.top()->getCurrentRow()->getGridBefore();
+}
+
+void TableManager::setCurrentGridBefore(sal_uInt32 nSkipGrids)
+{
+ mTableDataStack.top()->getCurrentRow()->setGridBefore(nSkipGrids);
+}
+
+sal_uInt32 TableManager::getGridAfter(sal_uInt32 nRow)
+{
+ assert(isInTable());
+ if (nRow >= mTableDataStack.top()->getRowCount())
+ return 0;
+ return mTableDataStack.top()->getRow(nRow)->getGridAfter();
+}
+
+void TableManager::setCurrentGridAfter(sal_uInt32 nSkipGrids)
+{
+ assert(isInTable());
+ mTableDataStack.top()->getCurrentRow()->setGridAfter(nSkipGrids);
+}
+
+std::vector<sal_uInt32> TableManager::getCurrentGridSpans()
+{
+ return mTableDataStack.top()->getCurrentRow()->getGridSpans();
+}
+
+void TableManager::setCurrentGridSpan(sal_uInt32 nGridSpan, bool bFirstCell)
+{
+ mTableDataStack.top()->getCurrentRow()->setCurrentGridSpan(nGridSpan, bFirstCell);
+}
+
+sal_uInt32 TableManager::findColumn(const sal_uInt32 nRow, const sal_uInt32 nCell)
+{
+ if (nRow >= mTableDataStack.top()->getRowCount())
+ return SAL_MAX_UINT32;
+
+ RowData::Pointer_t pRow = mTableDataStack.top()->getRow(nRow);
+ if (!pRow || nCell < pRow->getGridBefore()
+ || nCell >= pRow->getCellCount() - pRow->getGridAfter())
+ {
+ return SAL_MAX_UINT32;
+ }
+
+ // The gridSpans provide a one-based index, so add up all the spans of the PREVIOUS columns,
+ // and that result will provide the first possible zero-based number for the desired column.
+ sal_uInt32 nColumn = 0;
+ for (sal_uInt32 n = 0; n < nCell; ++n)
+ nColumn += pRow->getGridSpan(n);
+ return nColumn;
+}
+
+sal_uInt32 TableManager::findColumnCell(const sal_uInt32 nRow, const sal_uInt32 nCol)
+{
+ if (nRow >= mTableDataStack.top()->getRowCount())
+ return SAL_MAX_UINT32;
+
+ RowData::Pointer_t pRow = mTableDataStack.top()->getRow(nRow);
+ if (!pRow || nCol < pRow->getGridBefore())
+ return SAL_MAX_UINT32;
+
+ sal_uInt32 nCell = 0;
+ sal_uInt32 nGrids = 0;
+ // The gridSpans give us a one-based index, but requested column is zero-based - so keep that in mind.
+ const sal_uInt32 nMaxCell = pRow->getCellCount() - pRow->getGridAfter() - 1;
+ for (const auto& rSpan : pRow->getGridSpans())
+ {
+ nGrids += rSpan;
+ if (nCol < nGrids)
+ return nCell;
+
+ ++nCell;
+ if (nCell > nMaxCell)
+ break;
+ }
+ return SAL_MAX_UINT32; // must be in gridAfter or invalid column request
+}
+
+void TableManager::endOfRowAction() {}
+
+void TableManager::endOfCellAction() {}
+
+void TableManager::insertTableProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.insertTableProps");
+#endif
+
+ if (getTableProps() && getTableProps() != pProps)
+ getTableProps()->InsertProps(pProps.get());
+ else
+ mState.setTableProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::insertRowProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.insertRowProps");
+#endif
+
+ if (getRowProps())
+ getRowProps()->InsertProps(pProps.get());
+ else
+ mState.setRowProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::cellProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.cellProps");
+#endif
+
+ if (getCellProps())
+ getCellProps()->InsertProps(pProps.get());
+ else
+ mState.setCellProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::tableExceptionProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.tableExceptionProps");
+#endif
+
+ if (getTableExceptionProps())
+ getTableExceptionProps()->InsertProps(pProps.get());
+ else
+ mState.setTableExceptionProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::utext(const sal_uInt8* data, std::size_t len)
+{
+ // optimization: cell/row end characters are the last characters in a run
+
+ if (len > 0)
+ {
+ sal_Unicode nChar = data[(len - 1) * 2] + (data[(len - 1) * 2 + 1] << 8);
+ if (nChar == 0x7)
+ handle0x7();
+ }
+}
+
+void TableManager::text(const sal_uInt8* data, std::size_t len)
+{
+ // optimization: cell/row end characters are the last characters in a run
+ if (len > 0 && data[len - 1] == 0x7)
+ handle0x7();
+}
+
+void TableManager::handle0x7()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.handle0x7");
+#endif
+
+ if (mnTableDepthNew < 1)
+ mnTableDepthNew = 1;
+
+ if (isInCell())
+ endCell();
+ else
+ endRow();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+bool TableManager::sprm(Sprm& rSprm)
+{
+ bool bRet = true;
+ switch (rSprm.getId())
+ {
+ case NS_ooxml::LN_tblDepth:
+ {
+ Value::Pointer_t pValue = rSprm.getValue();
+
+ cellDepth(pValue->getInt());
+ }
+ break;
+ case NS_ooxml::LN_inTbl:
+ inCell();
+ break;
+ case NS_ooxml::LN_tblCell:
+ endCell();
+ break;
+ case NS_ooxml::LN_tblRow:
+ endRow();
+ break;
+ default:
+ bRet = false;
+ }
+ return bRet;
+}
+
+void TableManager::closeCell(const css::uno::Reference<css::text::XTextRange>& rHandle)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.closeCell");
+ TagLogger::getInstance().chars(XTextRangeToString(rHandle));
+ TagLogger::getInstance().endElement();
+#endif
+
+ if (!mTableDataStack.empty())
+ {
+ TableData::Pointer_t pTableData = mTableDataStack.top();
+
+ pTableData->endCell(rHandle);
+
+ if (mpTableDataHandler)
+ mpTableDataHandler->getDomainMapperImpl().ClearPreviousParagraph();
+ }
+}
+
+void TableManager::ensureOpenCell(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.ensureOpenCell");
+#endif
+
+ if (!mTableDataStack.empty())
+ {
+ TableData::Pointer_t pTableData = mTableDataStack.top();
+
+ if (pTableData != nullptr)
+ {
+ if (!pTableData->isCellOpen())
+ openCell(getHandle(), pProps);
+ else
+ pTableData->insertCellProperties(pProps);
+ }
+ }
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::endParagraphGroup()
+{
+ sal_Int32 nTableDepthDifference = mnTableDepthNew - mnTableDepth;
+
+ TablePropertyMapPtr pEmptyProps;
+
+ while (nTableDepthDifference > 0)
+ {
+ ensureOpenCell(pEmptyProps);
+ startLevel();
+
+ --nTableDepthDifference;
+ }
+ while (nTableDepthDifference < 0)
+ {
+ endLevel();
+
+ ++nTableDepthDifference;
+ }
+
+ mnTableDepth = mnTableDepthNew;
+
+ if (mnTableDepth <= 0)
+ return;
+
+ if (isRowEnd())
+ {
+ endOfRowAction();
+ mTableDataStack.top()->endRow(getRowProps());
+ mState.resetRowProps();
+ }
+
+ else if (isInCell())
+ {
+ ensureOpenCell(getCellProps());
+
+ if (mState.isCellEnd())
+ {
+ endOfCellAction();
+ closeCell(getHandle());
+ }
+ }
+ mState.resetCellProps();
+}
+
+void TableManager::startParagraphGroup()
+{
+ mState.resetCellSpecifics();
+ mnTableDepthNew = 0;
+}
+
+void TableManager::resolveCurrentTable()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.resolveCurrentTable");
+#endif
+
+ if (mpTableDataHandler != nullptr)
+ {
+ try
+ {
+ TableData::Pointer_t pTableData = mTableDataStack.top();
+
+ unsigned int nRows = pTableData->getRowCount();
+
+ mpTableDataHandler->startTable(getTableProps());
+
+ for (unsigned int nRow = 0; nRow < nRows; ++nRow)
+ {
+ RowData::Pointer_t pRowData = pTableData->getRow(nRow);
+
+ unsigned int nCells = pRowData->getCellCount();
+
+ mpTableDataHandler->startRow(pRowData->getProperties());
+
+ for (unsigned int nCell = 0; nCell < nCells; ++nCell)
+ {
+ mpTableDataHandler->startCell(pRowData->getCellStart(nCell),
+ pRowData->getCellProperties(nCell));
+
+ mpTableDataHandler->endCell(pRowData->getCellEnd(nCell));
+ }
+
+ mpTableDataHandler->endRow();
+ }
+
+ mpTableDataHandler->endTable(mTableDataStack.size() - 1, m_bTableStartsAtCellStart);
+ }
+ catch (css::uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "resolving of current table failed");
+ }
+ }
+ mState.resetTableProps();
+ clearData();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::endLevel()
+{
+ if (mpTableDataHandler != nullptr)
+ resolveCurrentTable();
+
+ // Store the unfinished row as it will be used for the next table
+ if (mbKeepUnfinishedRow)
+ mpUnfinishedRow = mTableDataStack.top()->getCurrentRow();
+ mState.endLevel();
+ mTableDataStack.pop();
+
+#ifdef DBG_UTIL
+ TableData::Pointer_t pTableData;
+
+ if (!mTableDataStack.empty())
+ pTableData = mTableDataStack.top();
+
+ TagLogger::getInstance().startElement("tablemanager.endLevel");
+ TagLogger::getInstance().attribute("level", mTableDataStack.size());
+
+ if (pTableData != nullptr)
+ TagLogger::getInstance().attribute("openCell", pTableData->isCellOpen() ? "yes" : "no");
+
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::startLevel()
+{
+#ifdef DBG_UTIL
+ TableData::Pointer_t pTableData;
+
+ if (!mTableDataStack.empty())
+ pTableData = mTableDataStack.top();
+
+ TagLogger::getInstance().startElement("tablemanager.startLevel");
+ TagLogger::getInstance().attribute("level", mTableDataStack.size());
+
+ if (pTableData != nullptr)
+ TagLogger::getInstance().attribute("openCell", pTableData->isCellOpen() ? "yes" : "no");
+
+ TagLogger::getInstance().endElement();
+#endif
+
+ TableData::Pointer_t pTableData2(new TableData(mTableDataStack.size()));
+
+ // If we have an unfinished row stored here, then push it to the new TableData
+ if (mpUnfinishedRow)
+ {
+ for (unsigned int i = 0; i < mpUnfinishedRow->getCellCount(); ++i)
+ {
+ pTableData2->addCell(mpUnfinishedRow->getCellStart(i),
+ mpUnfinishedRow->getCellProperties(i));
+ pTableData2->endCell(mpUnfinishedRow->getCellEnd(i));
+ pTableData2->getCurrentRow()->setCurrentGridSpan(mpUnfinishedRow->getGridSpan(i));
+ }
+ pTableData2->getCurrentRow()->setGridBefore(mpUnfinishedRow->getGridBefore());
+ pTableData2->getCurrentRow()->setGridAfter(mpUnfinishedRow->getGridAfter());
+ mpUnfinishedRow.clear();
+ }
+
+ mTableDataStack.push(pTableData2);
+ mState.startLevel();
+}
+
+bool TableManager::isInTable()
+{
+ bool bInTable = false;
+ if (!mTableDataStack.empty())
+ bInTable = mTableDataStack.top()->getDepth() > 0;
+ return bInTable;
+}
+
+void TableManager::handle(const css::uno::Reference<css::text::XTextRange>& rHandle)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.handle");
+ TagLogger::getInstance().chars(XTextRangeToString(rHandle));
+ TagLogger::getInstance().endElement();
+#endif
+
+ setHandle(rHandle);
+}
+
+void TableManager::setHandler(const tools::SvRef<DomainMapperTableHandler>& pTableDataHandler)
+{
+ mpTableDataHandler = pTableDataHandler;
+}
+
+void TableManager::endRow()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("tablemanager.endRow");
+#endif
+ TableData::Pointer_t pTableData = mTableDataStack.top();
+
+ // Add borderless w:gridBefore cell(s) to the row
+ sal_uInt32 nGridBefore = getCurrentGridBefore();
+ if (pTableData && nGridBefore > 0 && pTableData->getCurrentRow()->getCellCount() > 0)
+ {
+ const css::uno::Reference<css::text::XTextRange>& xRowStart
+ = pTableData->getCurrentRow()->getCellStart(0);
+ if (xRowStart.is())
+ {
+ try
+ {
+ // valid TextRange for table creation (not a nested table)?
+ xRowStart->getText()->createTextCursorByRange(xRowStart);
+
+ for (unsigned int i = 0; i < nGridBefore; ++i)
+ {
+ css::table::BorderLine2 aBorderLine;
+ aBorderLine.Color = 0;
+ aBorderLine.InnerLineWidth = 0;
+ aBorderLine.OuterLineWidth = 0;
+ TablePropertyMapPtr pCellProperties(new TablePropertyMap);
+ pCellProperties->Insert(PROP_TOP_BORDER, css::uno::Any(aBorderLine));
+ pCellProperties->Insert(PROP_LEFT_BORDER, css::uno::Any(aBorderLine));
+ pCellProperties->Insert(PROP_BOTTOM_BORDER, css::uno::Any(aBorderLine));
+ pCellProperties->Insert(PROP_RIGHT_BORDER, css::uno::Any(aBorderLine));
+ pTableData->getCurrentRow()->addCell(xRowStart, pCellProperties,
+ /*bAddBefore=*/true);
+ }
+ }
+ catch (css::uno::Exception const&)
+ {
+ // don't add gridBefore cells in not valid TextRange
+ setCurrentGridBefore(0);
+ setCurrentGridSpan(getCurrentGridSpans().front() + nGridBefore,
+ /*bFirstCell=*/true);
+ }
+ }
+ }
+
+ setRowEnd(true);
+}
+
+void TableManager::endCell()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("tablemanager.endCell");
+#endif
+
+ setCellEnd(true);
+}
+
+void TableManager::inCell()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("tablemanager.inCell");
+#endif
+ setInCell(true);
+
+ if (mnTableDepthNew < 1)
+ mnTableDepthNew = 1;
+}
+
+void TableManager::cellDepth(sal_uInt32 nDepth)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.cellDepth");
+ TagLogger::getInstance().attribute("depth", nDepth);
+ TagLogger::getInstance().endElement();
+#endif
+
+ mnTableDepthNew = nDepth;
+}
+
+void TableManager::setTableStartsAtCellStart(bool bTableStartsAtCellStart)
+{
+ m_bTableStartsAtCellStart = bTableStartsAtCellStart;
+}
+
+void TableManager::setCellLastParaAfterAutospacing(bool bIsAfterAutospacing)
+{
+ m_bCellLastParaAfterAutospacing = bIsAfterAutospacing;
+}
+
+TableManager::TableManager()
+ : mnTableDepthNew(0)
+ , mnTableDepth(0)
+ , mbKeepUnfinishedRow(false)
+ , m_bTableStartsAtCellStart(false)
+{
+ setRowEnd(false);
+ setInCell(false);
+ setCellEnd(false);
+ m_bCellLastParaAfterAutospacing = false;
+}
+
+TableManager::~TableManager() = default;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TableManager.hxx b/writerfilter/source/dmapper/TableManager.hxx
new file mode 100644
index 000000000..e6600d357
--- /dev/null
+++ b/writerfilter/source/dmapper/TableManager.hxx
@@ -0,0 +1,530 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <stack>
+
+#include "PropertyMap.hxx"
+#include "TableData.hxx"
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::dmapper
+{
+
+class DomainMapperTableHandler;
+
+/**
+ The table manager.
+
+ This class gets forwarded events from the tokenizer. It gathers the
+ table data and after ending the table generates events for the
+ table structure. The events have to be handles by a TableDataHandler.
+
+ */
+class TableManager : public virtual SvRefBase
+{
+ class TableManagerState final
+ {
+ /**
+ properties of the current cell
+ */
+ TablePropertyMapPtr mpCellProps;
+
+ /**
+ properties of the current row
+ */
+ TablePropertyMapPtr mpRowProps;
+
+ /**
+ table exception properties of the current row
+ */
+ TablePropertyMapPtr mpTableExceptionProps;
+
+ /**
+ properties of the current table
+ */
+ std::stack<TablePropertyMapPtr> mTableProps;
+
+ /**
+ true if at the end of a row
+ */
+ bool mbRowEnd;
+
+ /**
+ true when in a cell
+ */
+ bool mbInCell;
+
+ /**
+ true when at the end of a cell
+ */
+ bool mbCellEnd;
+
+ public:
+ /**
+ Constructor
+ */
+ TableManagerState()
+ : mbRowEnd(false), mbInCell(false), mbCellEnd(false)
+ {
+ }
+
+ void startLevel()
+ {
+ TablePropertyMapPtr pProps;
+ mTableProps.push(pProps);
+ }
+
+ void endLevel()
+ {
+ mTableProps.pop();
+ }
+
+ /**
+ Reset to initial state at beginning of row.
+ */
+ void resetCellSpecifics()
+ {
+ mbRowEnd = false;
+ mbInCell = false;
+ mbCellEnd = false;
+ }
+
+ void resetCellProps()
+ {
+ // copy tblPrEx table exception properties, if they exist
+ if (getTableExceptionProps().is())
+ {
+ mpCellProps = new TablePropertyMap;
+ mpCellProps->InsertProps(getTableExceptionProps().get());
+ }
+ else
+ mpCellProps.clear();
+ }
+
+ void setCellProps(TablePropertyMapPtr pProps)
+ {
+ mpCellProps = pProps;
+ }
+
+ const TablePropertyMapPtr& getCellProps() const
+ {
+ return mpCellProps;
+ }
+
+ void resetRowProps()
+ {
+ // reset also table exception and
+ // its copy set by the previous resetCellProps()
+ mpTableExceptionProps.clear();
+ resetCellProps();
+ mpRowProps.clear();
+ }
+
+ void setRowProps(TablePropertyMapPtr pProps)
+ {
+ mpRowProps = pProps;
+ }
+
+ const TablePropertyMapPtr& getRowProps() const
+ {
+ return mpRowProps;
+ }
+
+ void setTableExceptionProps(TablePropertyMapPtr pProps)
+ {
+ mpTableExceptionProps = pProps;
+ // set table exception properties of the first cell
+ resetCellProps();
+ }
+
+ const TablePropertyMapPtr& getTableExceptionProps() const
+ {
+ return mpTableExceptionProps;
+ }
+
+ void resetTableProps()
+ {
+ if (mTableProps.size() > 0)
+ mTableProps.top().clear();
+ }
+
+ void setTableProps(TablePropertyMapPtr pProps)
+ {
+ if (mTableProps.size() > 0)
+ mTableProps.top() = pProps;
+ }
+
+ TablePropertyMapPtr getTableProps()
+ {
+ TablePropertyMapPtr pResult;
+
+ if (mTableProps.size() > 0)
+ pResult = mTableProps.top();
+
+ return pResult;
+ }
+
+ void setInCell(bool bInCell)
+ {
+ mbInCell = bInCell;
+ }
+
+ bool isInCell() const
+ {
+ return mbInCell;
+ }
+
+ void setCellEnd(bool bCellEnd)
+ {
+ mbCellEnd = bCellEnd;
+ }
+
+ bool isCellEnd() const
+ {
+ return mbCellEnd;
+ }
+
+ void setRowEnd(bool bRowEnd)
+ {
+ mbRowEnd = bRowEnd;
+ }
+
+ bool isRowEnd() const
+ {
+ return mbRowEnd;
+ }
+ };
+
+ /**
+ handle for the current position in document
+ */
+ css::uno::Reference<css::text::XTextRange> mCurHandle;
+
+ TableManagerState mState;
+
+protected:
+ TablePropertyMapPtr const & getCellProps() const
+ {
+ return mState.getCellProps();
+ }
+
+public:
+ TablePropertyMapPtr const & getRowProps() const
+ {
+ return mState.getRowProps();
+ }
+
+ TablePropertyMapPtr const & getTableExceptionProps() const
+ {
+ return mState.getTableExceptionProps();
+ }
+
+protected:
+ void setInCell(bool bInCell)
+ {
+ mState.setInCell(bInCell);
+ }
+
+ bool isInCell() const
+ {
+ return mState.isInCell();
+ }
+
+ void setCellEnd(bool bCellEnd)
+ {
+ mState.setCellEnd(bCellEnd);
+ }
+
+ void setRowEnd(bool bRowEnd)
+ {
+ mState.setRowEnd(bRowEnd);
+ }
+
+ bool isRowEnd() const
+ {
+ return mState.isRowEnd();
+ }
+
+ TablePropertyMapPtr getTableProps()
+ {
+ return mState.getTableProps();
+ }
+
+ const css::uno::Reference<css::text::XTextRange>& getHandle() const
+ {
+ return mCurHandle;
+ }
+
+ void setHandle(const css::uno::Reference<css::text::XTextRange>& rHandle)
+ {
+ mCurHandle = rHandle;
+ }
+
+private:
+ typedef tools::SvRef< css::uno::Reference<css::text::XTextRange> > T_p;
+
+ /**
+ depth of the current cell
+ */
+ sal_uInt32 mnTableDepthNew;
+
+ /**
+ depth of the previous cell
+ */
+ sal_uInt32 mnTableDepth;
+
+ /**
+ stack of table data
+
+ for each level of nested tables there is one frame in the stack
+ */
+ std::stack<TableData::Pointer_t> mTableDataStack;
+ RowData::Pointer_t mpUnfinishedRow;
+ bool mbKeepUnfinishedRow;
+ /// If this is a nested table, does it start at cell start?
+ bool m_bTableStartsAtCellStart;
+
+ bool m_bCellLastParaAfterAutospacing;
+
+ /**
+ handler for resolveCurrentTable
+ */
+ tools::SvRef<DomainMapperTableHandler> mpTableDataHandler;
+
+ /**
+ Set flag which indicates the current handle is in a cell.
+ */
+ void inCell();
+
+ /**
+ Set flag which indicate the current handle is at the end of a cell.
+ */
+ void endCell();
+
+ /**
+ Set the table depth of the current cell.
+
+ @param nDepth the cell depth
+ */
+ void cellDepth(sal_uInt32 nDepth);
+
+ /**
+ Set flag indication the current handle is at the end of a row.
+ */
+ void endRow();
+
+ /**
+ Resolve the current table to the TableDataHandler.
+ */
+ void resolveCurrentTable();
+
+ /**
+ Open a cell at current level.
+ */
+
+ void openCell(const css::uno::Reference<css::text::XTextRange>& rHandle, const TablePropertyMapPtr& pProps);
+
+ /**
+ Close a cell at current level.
+ */
+ void closeCell(const css::uno::Reference<css::text::XTextRange>& rHandle);
+
+ /**
+ Ensure a cell is open at the current level.
+ */
+ void ensureOpenCell(const TablePropertyMapPtr& pProps);
+
+protected:
+ /**
+ Return the current table difference, i.e. 1 if we are in the first cell of a new table, etc.
+ */
+ sal_Int32 getTableDepthDifference() const { return mnTableDepthNew - mnTableDepth; }
+
+ sal_uInt32 getTableDepth() const { return mnTableDepthNew; }
+
+ /**
+ Action to be carried out at the end of the last paragraph of a
+ cell.
+ */
+ virtual void endOfCellAction();
+
+ /**
+ Action to be carried out at the end of the "table row"
+ paragraph.
+ */
+ virtual void endOfRowAction();
+ /** let the derived class clear their table related data
+ */
+ virtual void clearData();
+
+ /** Should we keep the unfinished row in endLevel to initialize the table
+ data in the following startLevel.
+ */
+ void setKeepUnfinishedRow(bool bKeep)
+ {
+ mbKeepUnfinishedRow = bKeep;
+ }
+
+
+public:
+ TableManager();
+ ~TableManager();
+
+ /**
+ Set handler for resolveCurrentTable.
+
+ @param pTableDataHandler the handler
+ */
+ void setHandler(const tools::SvRef<DomainMapperTableHandler>& pTableDataHandler);
+
+ /**
+ Set the current handle.
+
+ @param rHandle the handle
+ */
+ void handle(const css::uno::Reference<css::text::XTextRange>& rHandle);
+
+ /**
+ Start a new table level.
+
+ A new context is pushed onto the table data stack,
+ */
+ virtual void startLevel();
+
+ /**
+ End a table level.
+
+ The current table is resolved and the context is popped from
+ the stack.
+ */
+ virtual void endLevel();
+
+ /**
+ * Signal that the next paragraph definitely won't be part of any table.
+ */
+ void endTable()
+ {
+ setRowEnd(false);
+ }
+
+ /**
+ Tells whether a table has been started or not
+ */
+ bool isInTable();
+
+ /**
+ Handle the start of a paragraph group.
+ */
+ void startParagraphGroup();
+
+ /**
+ Handle the end of a paragraph group.
+ */
+ void endParagraphGroup();
+
+ /**
+ Handle an SPRM at current handle.
+
+ @param rSprm the SPRM
+ */
+ virtual bool sprm(Sprm & rSprm);
+
+ /**
+ Handle occurrence of character 0x7.
+ */
+ void handle0x7();
+
+ /**
+ Handle 8 bit text at current handle.
+
+ @param data array of characters
+ @param len number of characters to handle
+ */
+ void text(const sal_uInt8 * data, size_t len);
+
+ /**
+ Handle 16 bit text at current handle.
+
+ @param data array of characters
+ @param len number of characters to handle
+ */
+ void utext(const sal_uInt8 * data, size_t len);
+
+ /**
+ Handle properties of the current cell.
+
+ @param pProps the properties
+ */
+ virtual void cellProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Handle properties of the current row.
+
+ @param pProps the properties
+ */
+ virtual void insertRowProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Handle table exception properties of the current row.
+
+ @param pProps the properties
+ */
+ virtual void tableExceptionProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Handle properties of the current table.
+
+ @param pProps the properties
+ */
+ virtual void insertTableProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Return if table manager has detected paragraph to ignore.
+
+ If this function returns true the current paragraph contains
+ only control information, e.g. end of row.
+ */
+ bool isIgnore() const;
+
+ sal_uInt32 getGridBefore(sal_uInt32 nRow);
+ sal_uInt32 getCurrentGridBefore();
+ void setCurrentGridBefore( sal_uInt32 nSkipGrids );
+ sal_uInt32 getGridAfter(sal_uInt32 nRow);
+ void setCurrentGridAfter( sal_uInt32 nSkipGrids );
+ std::vector<sal_uInt32> getCurrentGridSpans();
+ void setCurrentGridSpan( sal_uInt32 nGridSpan, bool bFirstCell = false );
+ /// Given a zero-based row/cell, return the zero-based grid it belongs to, or SAL_MAX_UINT16 for invalid.
+ sal_uInt32 findColumn( const sal_uInt32 nRow, const sal_uInt32 nCell );
+ /// Given a zero-based row/col, return the zero-based cell describing that grid, or SAL_MAX_UINT16 for invalid.
+ sal_uInt32 findColumnCell( const sal_uInt32 nRow, const sal_uInt32 nCol );
+
+ void setTableStartsAtCellStart(bool bTableStartsAtCellStart);
+ void setCellLastParaAfterAutospacing(bool bIsAfterAutospacing);
+ bool isCellLastParaAfterAutospacing() const {return m_bCellLastParaAfterAutospacing;}
+};
+
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TablePositionHandler.cxx b/writerfilter/source/dmapper/TablePositionHandler.cxx
new file mode 100644
index 000000000..5eea4a000
--- /dev/null
+++ b/writerfilter/source/dmapper/TablePositionHandler.cxx
@@ -0,0 +1,154 @@
+/* -*- 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 "TablePositionHandler.hxx"
+#include "ConversionHelper.hxx"
+#include "TagLogger.hxx"
+#include <ooxml/resourceids.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <comphelper/sequenceashashmap.hxx>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+TablePositionHandler::TablePositionHandler()
+ : LoggedProperties("TablePositionHandler")
+{
+}
+
+TablePositionHandler::~TablePositionHandler() = default;
+
+void TablePositionHandler::lcl_attribute(Id nId, Value& rVal)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_TblPPr_vertAnchor:
+ m_aVertAnchor = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpYSpec:
+ m_aYSpec = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_horzAnchor:
+ m_aHorzAnchor = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpXSpec:
+ m_aXSpec = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpY:
+ m_nY = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpX:
+ m_nX = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_leftFromText:
+ m_nLeftFromText = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_rightFromText:
+ m_nRightFromText = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_topFromText:
+ m_nTopFromText = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_bottomFromText:
+ m_nBottomFromText = rVal.getInt();
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+void TablePositionHandler::lcl_sprm(Sprm& /*rSprm*/) {}
+
+uno::Sequence<beans::PropertyValue> TablePositionHandler::getTablePosition() const
+{
+ comphelper::SequenceAsHashMap aFrameProperties;
+
+ aFrameProperties["LeftBorderDistance"] <<= sal_Int32(0);
+ aFrameProperties["RightBorderDistance"] <<= sal_Int32(0);
+ aFrameProperties["TopBorderDistance"] <<= sal_Int32(0);
+ aFrameProperties["BottomBorderDistance"] <<= sal_Int32(0);
+
+ aFrameProperties["LeftMargin"] <<= ConversionHelper::convertTwipToMM100(m_nLeftFromText);
+ aFrameProperties["RightMargin"] <<= ConversionHelper::convertTwipToMM100(m_nRightFromText);
+ aFrameProperties["TopMargin"] <<= ConversionHelper::convertTwipToMM100(m_nTopFromText);
+ aFrameProperties["BottomMargin"] <<= ConversionHelper::convertTwipToMM100(m_nBottomFromText);
+
+ table::BorderLine2 aEmptyBorder;
+ aFrameProperties["TopBorder"] <<= aEmptyBorder;
+ aFrameProperties["BottomBorder"] <<= aEmptyBorder;
+ aFrameProperties["LeftBorder"] <<= aEmptyBorder;
+ aFrameProperties["RightBorder"] <<= aEmptyBorder;
+
+ // Horizontal positioning
+ sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
+ if (m_aXSpec == "center")
+ nHoriOrient = text::HoriOrientation::CENTER;
+ else if (m_aXSpec == "inside")
+ nHoriOrient = text::HoriOrientation::INSIDE;
+ else if (m_aXSpec == "left")
+ nHoriOrient = text::HoriOrientation::LEFT;
+ else if (m_aXSpec == "outside")
+ nHoriOrient = text::HoriOrientation::OUTSIDE;
+ else if (m_aXSpec == "right")
+ nHoriOrient = text::HoriOrientation::RIGHT;
+
+ sal_Int16 nHoriOrientRelation;
+ if (m_aHorzAnchor == "margin")
+ nHoriOrientRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ else if (m_aHorzAnchor == "page")
+ nHoriOrientRelation = text::RelOrientation::PAGE_FRAME;
+ else if (m_aHorzAnchor == "text")
+ nHoriOrientRelation = text::RelOrientation::FRAME;
+
+ aFrameProperties["HoriOrient"] <<= nHoriOrient;
+ aFrameProperties["HoriOrientRelation"] <<= nHoriOrientRelation;
+ aFrameProperties["HoriOrientPosition"] <<= ConversionHelper::convertTwipToMM100(m_nX);
+
+ // Vertical positioning
+ sal_Int16 nVertOrient = text::VertOrientation::NONE;
+ if (m_aYSpec == "bottom")
+ nVertOrient = text::VertOrientation::BOTTOM;
+ else if (m_aYSpec == "center")
+ nVertOrient = text::VertOrientation::CENTER;
+ else if (m_aYSpec == "top")
+ nVertOrient = text::VertOrientation::TOP;
+ // TODO There are a few cases we can't map ATM.
+
+ sal_Int16 nVertOrientRelation;
+ if (m_aVertAnchor == "margin")
+ nVertOrientRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ else if (m_aVertAnchor == "page")
+ nVertOrientRelation = text::RelOrientation::PAGE_FRAME;
+ else if (m_aVertAnchor == "text")
+ nVertOrientRelation = text::RelOrientation::FRAME;
+
+ aFrameProperties["VertOrient"] <<= nVertOrient;
+ aFrameProperties["VertOrientRelation"] <<= nVertOrientRelation;
+ aFrameProperties["VertOrientPosition"] <<= ConversionHelper::convertTwipToMM100(m_nY);
+ aFrameProperties["FillTransparence"] <<= sal_Int32(100);
+
+ return aFrameProperties.getAsConstPropertyValueList();
+}
+
+bool TablePositionHandler::operator==(const TablePositionHandler& rHandler) const
+{
+ return m_aVertAnchor == rHandler.m_aVertAnchor && m_aYSpec == rHandler.m_aYSpec
+ && m_aHorzAnchor == rHandler.m_aHorzAnchor && m_aXSpec == rHandler.m_aXSpec
+ && m_nY == rHandler.m_nY && m_nX == rHandler.m_nX;
+}
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TablePositionHandler.hxx b/writerfilter/source/dmapper/TablePositionHandler.hxx
new file mode 100644
index 000000000..23d042b69
--- /dev/null
+++ b/writerfilter/source/dmapper/TablePositionHandler.hxx
@@ -0,0 +1,68 @@
+/* -*- 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/.
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+
+namespace com::sun::star::beans
+{
+struct PropertyValue;
+}
+
+namespace writerfilter::dmapper
+{
+/// Handler for floating table positioning
+class TablePositionHandler : public LoggedProperties
+{
+ OUString m_aVertAnchor{ "margin" };
+ OUString m_aYSpec;
+ OUString m_aHorzAnchor{ "text" };
+ OUString m_aXSpec;
+ sal_Int32 m_nY = 0;
+ sal_Int32 m_nX = 0;
+ sal_Int32 m_nLeftFromText = 0;
+ sal_Int32 m_nRightFromText = 0;
+ sal_Int32 m_nTopFromText = 0;
+ sal_Int32 m_nBottomFromText = 0;
+
+ // Properties
+ void lcl_attribute(Id nId, Value& rVal) override;
+ void lcl_sprm(Sprm& sprm) override;
+
+public:
+ sal_Int32 getY() const { return m_nY; }
+ sal_Int32 getX() const { return m_nX; }
+ sal_Int32 getLeftFromText() const { return m_nLeftFromText; }
+ sal_Int32 getRightFromText() const { return m_nRightFromText; }
+ sal_Int32 getTopFromText() const { return m_nTopFromText; }
+ sal_Int32 getBottomFromText() const { return m_nBottomFromText; }
+
+ const OUString& getVertAnchor() const { return m_aVertAnchor; }
+ const OUString& getYSpec() const { return m_aYSpec; }
+ const OUString& getHorzAnchor() const { return m_aHorzAnchor; }
+ const OUString& getXSpec() const { return m_aXSpec; }
+
+ TablePositionHandler();
+ ~TablePositionHandler() override;
+
+ /** Compute the UNO properties for the frame containing the table based
+ on the received tokens.
+
+ Note that the properties will need to be adjusted with the table
+ properties before actually using them.
+ */
+ css::uno::Sequence<css::beans::PropertyValue> getTablePosition() const;
+
+ bool operator==(const TablePositionHandler& rHandler) const;
+};
+
+using TablePositionHandlerPtr = tools::SvRef<TablePositionHandler>;
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TablePropertiesHandler.cxx b/writerfilter/source/dmapper/TablePropertiesHandler.cxx
new file mode 100644
index 000000000..8ea3eae5c
--- /dev/null
+++ b/writerfilter/source/dmapper/TablePropertiesHandler.cxx
@@ -0,0 +1,398 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "BorderHandler.hxx"
+#include "CellColorHandler.hxx"
+#include "CellMarginHandler.hxx"
+#include "ConversionHelper.hxx"
+#include "MeasureHandler.hxx"
+#include "TrackChangesHandler.hxx"
+#include "TablePropertiesHandler.hxx"
+#include "TagLogger.hxx"
+#include "TDefTableHandler.hxx"
+#include "DomainMapperTableManager.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <oox/token/tokens.hxx>
+
+using namespace com::sun::star;
+using namespace oox;
+
+namespace writerfilter::dmapper {
+
+ TablePropertiesHandler::TablePropertiesHandler() :
+ m_pCurrentInteropGrabBag(nullptr),
+ m_pTableManager( nullptr )
+ {
+ }
+
+ bool TablePropertiesHandler::sprm(Sprm & rSprm)
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TablePropertiesHandler.sprm");
+ TagLogger::getInstance().attribute("sprm", rSprm.toString());
+#endif
+
+ bool bRet = true;
+ sal_uInt32 nSprmId = rSprm.getId();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = (pValue ? pValue->getInt() : 0);
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TrPrBase_jc:
+ case NS_ooxml::LN_CT_TblPrBase_jc:
+ {
+ sal_Int16 nOrient = ConversionHelper::convertTableJustification( nIntValue );
+ TablePropertyMapPtr pTableMap( new TablePropertyMap );
+ pTableMap->setValue( TablePropertyMap::HORI_ORIENT, nOrient );
+ insertTableProps( pTableMap );
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_trHeight:
+ {
+ //contains unit and value
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ { //contains attributes x2902 (LN_unit) and x17e2 (LN_trleft)
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ pPropMap->Insert( PROP_SIZE_TYPE, uno::Any( pMeasureHandler->GetRowHeightSizeType() ), false);
+ pPropMap->Insert( PROP_HEIGHT, uno::Any(pMeasureHandler->getMeasureValue() ));
+
+ insertRowProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPr_ins:
+ case NS_ooxml::LN_CT_TrPr_del:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ sal_Int32 nToken = sal_Int32();
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TrPr_ins:
+ nToken = XML_tableRowInsert;
+ break;
+ case NS_ooxml::LN_CT_TrPr_del:
+ nToken = XML_tableRowDelete;
+ break;
+ }
+ auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>( nToken );
+ pProperties->resolve(*pTrackChangesHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ // Add the 'track changes' properties to the 'table row' via UNO.
+ // This way - in the SW core - when it receives this - it will create a new 'Table Redline' object for that row
+ uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties();
+ pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::Any( aTableRedlineProperties ));
+ insertRowProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_cellIns:
+ case NS_ooxml::LN_CT_TcPrBase_cellDel:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ sal_Int32 nToken;
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TcPrBase_cellIns:
+ nToken = XML_tableCellInsert;
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_cellDel:
+ nToken = XML_tableCellDelete;
+ break;
+ default:
+ throw lang::IllegalArgumentException("illegal redline token type", nullptr, 0);
+ break;
+ }
+ auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>( nToken );
+ pProperties->resolve(*pTrackChangesHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ // Add the 'track changes' properties to the 'table row' via UNO.
+ // This way - in the SW core - when it receives this - it will create a new 'Table Redline' object for that row
+ uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties();
+ pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::Any( aTableRedlineProperties ));
+ cellProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_cantSplit:
+ {
+ //row can't break across pages if nIntValue == 1
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_IS_SPLIT_ALLOWED, uno::Any( nIntValue != 1 ) );
+ insertRowProps(pPropMap);
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_vAlign:
+ {
+ sal_Int16 nVertOrient = text::VertOrientation::NONE;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_VerticalJc_center: nVertOrient = text::VertOrientation::CENTER; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_bottom: nVertOrient = text::VertOrientation::BOTTOM; break;
+ default:;
+ }
+ TablePropertyMapPtr pCellPropMap( new TablePropertyMap() );
+ pCellPropMap->Insert( PROP_VERT_ORIENT, uno::Any( nVertOrient ) );
+ //todo: in ooxml import the value of m_ncell is wrong
+ cellProps( pCellPropMap );
+ if (m_pCurrentInteropGrabBag)
+ {
+ OUString aVertOrient;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_VerticalJc_top: aVertOrient = "top"; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_center: aVertOrient = "center"; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_both: aVertOrient = "both"; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_bottom: aVertOrient = "bottom"; break;
+ }
+ if (!aVertOrient.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "vAlign";
+ aValue.Value <<= aVertOrient;
+ m_pCurrentInteropGrabBag->push_back(aValue);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblBorders: //table borders, might be defined in table style
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>(true);
+ if (m_pCurrentInteropGrabBag)
+ pBorderHandler->enableInteropGrabBag("tblBorders");
+ pProperties->resolve(*pBorderHandler);
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pBorderHandler->getInteropGrabBag());
+ TablePropertyMapPtr pTablePropMap( new TablePropertyMap );
+ pTablePropMap->InsertProps(pBorderHandler->getProperties());
+
+#ifdef DBG_UTIL
+ pTablePropMap->dumpXml();
+#endif
+ insertTableProps( pTablePropMap );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblLayout:
+ {
+ DomainMapperTableManager* pManager = dynamic_cast<DomainMapperTableManager*>(m_pTableManager);
+ if (pManager)
+ pManager->SetLayoutType(static_cast<sal_uInt32>(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrEx_tblBorders:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties)
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>(true);
+ pProperties->resolve(*pBorderHandler);
+ TablePropertyMapPtr pTablePropMap( new TablePropertyMap );
+ pTablePropMap->InsertProps(pBorderHandler->getProperties());
+
+#ifdef DBG_UTIL
+ pTablePropMap->dumpXml();
+#endif
+ tableExceptionProps( pTablePropMap );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_tcBorders ://cell borders
+ //contains CT_TcBorders_left, right, top, bottom
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ //in OOXML there's one set of borders at each cell (if there is any)
+ tools::SvRef< TDefTableHandler > pTDefTableHandler( new TDefTableHandler());
+ if (m_pCurrentInteropGrabBag)
+ pTDefTableHandler->enableInteropGrabBag("tcBorders");
+ pProperties->resolve( *pTDefTableHandler );
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pTDefTableHandler->getInteropGrabBag());
+ TablePropertyMapPtr pCellPropMap( new TablePropertyMap );
+ pTDefTableHandler->fillCellProperties( pCellPropMap );
+ cellProps( pCellPropMap );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_tcMar:
+
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ auto pCellMarginHandler = std::make_shared<CellMarginHandler>();
+ if (m_pCurrentInteropGrabBag)
+ pCellMarginHandler->enableInteropGrabBag("tcMar");
+ pProperties->resolve(*pCellMarginHandler);
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pCellMarginHandler->getInteropGrabBag());
+ TablePropertyMapPtr pCellProperties(new TablePropertyMap);
+ if (pCellMarginHandler->m_bTopMarginValid)
+ pCellProperties->Insert(PROP_TOP_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nTopMargin));
+ if (pCellMarginHandler->m_bLeftMarginValid)
+ pCellProperties->Insert(PROP_LEFT_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nLeftMargin));
+ if (pCellMarginHandler->m_bBottomMarginValid)
+ pCellProperties->Insert(PROP_BOTTOM_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nBottomMargin));
+ if (pCellMarginHandler->m_bRightMarginValid)
+ pCellProperties->Insert(PROP_RIGHT_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nRightMargin));
+ cellProps(pCellProperties);
+ }
+ }
+ break;
+/* // tdf#123189 skip to keep MSO interoperability
+ case NS_ooxml::LN_CT_TblPrBase_shd:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties.get())
+ {
+ std::shared_ptr<CellColorHandler> pCellColorHandler( new CellColorHandler);
+ pProperties->resolve( *pCellColorHandler );
+ TablePropertyMapPtr pTablePropMap( new TablePropertyMap );
+ insertTableProps( pCellColorHandler->getProperties() );
+ }
+ }
+*/
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_shd:
+ {
+ // each color sprm contains as much colors as cells are in a row
+ //LN_CT_TcPrBase_shd: cell shading contains: LN_CT_Shd_val, LN_CT_Shd_fill, LN_CT_Shd_color
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellColorHandler = std::make_shared<CellColorHandler>();
+ pCellColorHandler->enableInteropGrabBag("shd"); //enable to store shd unsupported props in grab bag
+ pProperties->resolve( *pCellColorHandler );
+ TablePropertyMapPtr pPropertyMap = pCellColorHandler->getProperties();
+ beans::PropertyValue aGrabBag = pCellColorHandler->getInteropGrabBag();
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(aGrabBag);
+ pPropertyMap->Insert( PROP_CELL_INTEROP_GRAB_BAG, aGrabBag.Value );
+ cellProps( pPropertyMap );
+ }
+ }
+ break;
+//OOXML table properties
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar: //cell margins
+ {
+ //contains LN_CT_TblCellMar_top, LN_CT_TblCellMar_left, LN_CT_TblCellMar_bottom, LN_CT_TblCellMar_right
+ // LN_CT_TblCellMar_start, LN_CT_TblCellMar_end
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellMarginHandler = std::make_shared<CellMarginHandler>();
+ if (m_pCurrentInteropGrabBag)
+ pCellMarginHandler->enableInteropGrabBag("tblCellMar");
+ pProperties->resolve( *pCellMarginHandler );
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pCellMarginHandler->getInteropGrabBag());
+ TablePropertyMapPtr pMarginProps( new TablePropertyMap );
+ if( pCellMarginHandler->m_bTopMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_TOP, pCellMarginHandler->m_nTopMargin );
+ if( pCellMarginHandler->m_bBottomMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_BOTTOM, pCellMarginHandler->m_nBottomMargin );
+ if( pCellMarginHandler->m_bLeftMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_LEFT, pCellMarginHandler->m_nLeftMargin );
+ if( pCellMarginHandler->m_bRightMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_RIGHT, pCellMarginHandler->m_nRightMargin );
+ insertTableProps(pMarginProps);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblInd:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ MeasureHandlerPtr pHandler(new MeasureHandler);
+ if (m_pCurrentInteropGrabBag)
+ pHandler->enableInteropGrabBag("tblInd");
+ pProperties->resolve( *pHandler );
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pHandler->getInteropGrabBag());
+ TablePropertyMapPtr pTblIndMap(new TablePropertyMap);
+ sal_uInt32 nTblInd = pHandler->getMeasureValue();
+ pTblIndMap->setValue( TablePropertyMap::LEFT_MARGIN, nTblInd);
+ insertTableProps(pTblIndMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_hideMark:
+ if (nIntValue)
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_CELL_HIDE_MARK, uno::Any(nIntValue));
+ cellProps(pPropMap);
+ }
+ break;
+ default:
+ // Not handled here, give the next handler a chance.
+ bRet = false;
+ // However, these logically belong here, so save the value if necessary.
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_TblPrBase_tblStyleRowBandSize:
+ case NS_ooxml::LN_CT_TblPrBase_tblStyleColBandSize:
+ if (m_pCurrentInteropGrabBag)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = (nSprmId == NS_ooxml::LN_CT_TblPrBase_tblStyleRowBandSize ? std::u16string_view(u"tblStyleRowBandSize") : std::u16string_view(u"tblStyleColBandSize"));
+ aValue.Value <<= nIntValue;
+ m_pCurrentInteropGrabBag->push_back(aValue);
+ }
+ break;
+ }
+ break;
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+ return bRet;
+ }
+
+ void TablePropertiesHandler::SetInteropGrabBag(std::vector<beans::PropertyValue>& rValue)
+ {
+ m_pCurrentInteropGrabBag = &rValue;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TablePropertiesHandler.hxx b/writerfilter/source/dmapper/TablePropertiesHandler.hxx
new file mode 100644
index 000000000..bd0901356
--- /dev/null
+++ b/writerfilter/source/dmapper/TablePropertiesHandler.hxx
@@ -0,0 +1,94 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "PropertyMap.hxx"
+
+#include "TableManager.hxx"
+#include <dmapper/resourcemodel.hxx>
+
+#include <vector>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+
+class TablePropertiesHandler final : public virtual SvRefBase
+{
+private:
+ PropertyMapPtr m_pCurrentProperties;
+ std::vector<css::beans::PropertyValue>* m_pCurrentInteropGrabBag;
+ TableManager* m_pTableManager;
+
+public:
+ TablePropertiesHandler();
+
+ bool sprm(Sprm & sprm);
+
+ void SetTableManager( TableManager* pTableManager )
+ {
+ m_pTableManager = pTableManager;
+ };
+
+ void SetProperties( PropertyMapPtr pProperties )
+ {
+ m_pCurrentProperties = pProperties;
+ };
+
+ void SetInteropGrabBag(std::vector<css::beans::PropertyValue>& rValue);
+
+private:
+
+ void cellProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->cellProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+
+ void insertRowProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->insertRowProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+
+ void tableExceptionProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->tableExceptionProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+
+ void insertTableProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->insertTableProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TagLogger.cxx b/writerfilter/source/dmapper/TagLogger.cxx
new file mode 100644
index 000000000..607f01aaf
--- /dev/null
+++ b/writerfilter/source/dmapper/TagLogger.cxx
@@ -0,0 +1,230 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+#include "TagLogger.hxx"
+#ifdef DBG_UTIL
+#include <unotools/pathoptions.hxx>
+#endif
+
+using namespace css;
+
+namespace writerfilter
+{
+ TagLogger::TagLogger()
+ : pWriter( nullptr ), pName( "DOMAINMAPPER" )
+ {
+ }
+
+ TagLogger::~TagLogger()
+ {
+ pWriter = nullptr;
+ pName = nullptr;
+ }
+
+#ifdef DBG_UTIL
+ void TagLogger::setFileName( const std::string & filename )
+ {
+ if ( pWriter )
+ endDocument();
+
+ std::string fileName;
+ char * temp = getenv("TAGLOGGERTMP");
+
+ if (temp != nullptr)
+ fileName += temp;
+ else
+ fileName += SvtPathOptions().GetTempPath().toUtf8().getStr();
+
+ std::string sPrefix = filename;
+ size_t nLastSlash = sPrefix.find_last_of('/');
+ size_t nLastBackslash = sPrefix.find_last_of('\\');
+ size_t nCutPos = nLastSlash;
+ if (nLastBackslash < nCutPos)
+ nCutPos = nLastBackslash;
+ if (nCutPos < sPrefix.size())
+ sPrefix = sPrefix.substr(nCutPos + 1);
+
+ fileName += "/";
+ fileName += sPrefix;
+ fileName += ".";
+ fileName += pName;
+ fileName += ".xml";
+
+ pWriter = xmlNewTextWriterFilename( fileName.c_str(), 0 );
+ xmlTextWriterSetIndent(pWriter,1);
+ (void)xmlTextWriterSetIndentString(pWriter, BAD_CAST(" "));
+ xmlTextWriterSetIndent( pWriter, 4 );
+ }
+
+ void TagLogger::startDocument()
+ {
+ if (!pWriter)
+ return;
+ (void)xmlTextWriterStartDocument( pWriter, nullptr, nullptr, nullptr );
+ (void)xmlTextWriterStartElement( pWriter, BAD_CAST( "root" ) );
+ }
+
+ void TagLogger::endDocument()
+ {
+ if (!pWriter)
+ return;
+ (void)xmlTextWriterEndDocument( pWriter );
+ xmlFreeTextWriter( pWriter );
+ pWriter = nullptr;
+ }
+
+#endif
+
+ TagLogger& TagLogger::getInstance()
+ {
+ static TagLogger theTagLogger;
+ return theTagLogger;
+ }
+
+#ifdef DBG_UTIL
+ void TagLogger::element(const std::string & name)
+ {
+ startElement(name);
+ endElement();
+ }
+
+ void TagLogger::unoPropertySet(const uno::Reference<beans::XPropertySet>& rPropSet)
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropSetInfo(rPropSet->getPropertySetInfo());
+ const uno::Sequence<beans::Property> aProps(xPropSetInfo->getProperties());
+
+ startElement( "unoPropertySet" );
+
+ for (beans::Property const & prop : aProps)
+ {
+ startElement( "property" );
+ OUString sName(prop.Name);
+
+ attribute( "name", sName );
+ try
+ {
+ attribute( "value", rPropSet->getPropertyValue( sName ) );
+ }
+ catch (const uno::Exception &)
+ {
+ startElement( "exception" );
+
+ chars(std::string("getPropertyValue(\""));
+ chars(sName);
+ chars(std::string("\")"));
+
+ endElement( );
+ }
+ endElement( );
+ }
+ endElement( );
+ }
+
+ void TagLogger::startElement(const std::string & name)
+ {
+ if (!pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ (void)xmlTextWriterStartElement( pWriter, xmlName );
+ xmlFree( xmlName );
+ }
+#endif
+
+ void TagLogger::attribute(const std::string & name, const std::string & value)
+ {
+ if (!pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ xmlChar* xmlValue = xmlCharStrdup( value.c_str() );
+ (void)xmlTextWriterWriteAttribute( pWriter, xmlName, xmlValue );
+
+ xmlFree( xmlValue );
+ xmlFree( xmlName );
+ }
+
+#ifdef DBG_UTIL
+ void TagLogger::attribute(const std::string & name, std::u16string_view value)
+ {
+ attribute( name, OUStringToOString( value, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ }
+
+ void TagLogger::attribute(const std::string & name, sal_uInt32 value)
+ {
+ if (!pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ (void)xmlTextWriterWriteFormatAttribute( pWriter, xmlName,
+ "%" SAL_PRIuUINT32, value );
+ xmlFree( xmlName );
+ }
+
+ void TagLogger::attribute(const std::string & name, const uno::Any& aAny)
+ {
+ if (!pWriter)
+ return;
+
+ sal_Int32 nInt = 0;
+ float nFloat = 0.0;
+ OUString aStr;
+
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ if ( aAny >>= nInt )
+ {
+ (void)xmlTextWriterWriteFormatAttribute( pWriter, xmlName,
+ "%" SAL_PRIdINT32, nInt );
+ }
+ else if ( aAny >>= nFloat )
+ {
+ (void)xmlTextWriterWriteFormatAttribute( pWriter, xmlName,
+ "%f", nFloat );
+ }
+ else if ( aAny >>= aStr )
+ {
+ attribute( name, aStr );
+ }
+ xmlFree( xmlName );
+ }
+
+ void TagLogger::chars(const std::string & rChars)
+ {
+ if (!pWriter)
+ return;
+ xmlChar* xmlChars = xmlCharStrdup( rChars.c_str() );
+ (void)xmlTextWriterWriteString( pWriter, xmlChars );
+ xmlFree( xmlChars );
+ }
+
+ void TagLogger::chars(std::u16string_view rChars)
+ {
+ chars(OUStringToOString(rChars, RTL_TEXTENCODING_ASCII_US).getStr());
+ }
+
+ void TagLogger::endElement()
+ {
+ if (!pWriter)
+ return;
+ (void)xmlTextWriterEndElement( pWriter );
+ }
+
+#endif
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TagLogger.hxx b/writerfilter/source/dmapper/TagLogger.hxx
new file mode 100644
index 000000000..33da346ee
--- /dev/null
+++ b/writerfilter/source/dmapper/TagLogger.hxx
@@ -0,0 +1,65 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <string>
+#include <string_view>
+#include <libxml/xmlwriter.h>
+
+namespace writerfilter
+{
+
+ class TagLogger
+ {
+ private:
+ xmlTextWriterPtr pWriter;
+ const char* pName;
+
+ public:
+ explicit TagLogger();
+ ~TagLogger();
+
+ static TagLogger& getInstance();
+
+#ifdef DBG_UTIL
+ void setFileName(const std::string & filename);
+ void startDocument();
+ void endDocument();
+
+ void element(const std::string & name);
+ void unoPropertySet(const css::uno::Reference<css::beans::XPropertySet>& rPropSet);
+ void startElement(const std::string & name);
+#endif
+ void attribute(const std::string & name, const std::string & value);
+#ifdef DBG_UTIL
+ void attribute(const std::string & name, std::u16string_view value);
+ void attribute(const std::string & name, sal_uInt32 value);
+ void attribute(const std::string & name, const css::uno::Any& aAny);
+ void chars(const std::string & chars);
+ void chars(std::u16string_view chars);
+ void endElement();
+#endif
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TblStylePrHandler.cxx b/writerfilter/source/dmapper/TblStylePrHandler.cxx
new file mode 100644
index 000000000..13656e169
--- /dev/null
+++ b/writerfilter/source/dmapper/TblStylePrHandler.cxx
@@ -0,0 +1,259 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TblStylePrHandler.hxx"
+#include "TagLogger.hxx"
+#include "CellMarginHandler.hxx"
+#include "PropertyMap.hxx"
+#include "MeasureHandler.hxx"
+#include <ooxml/resourceids.hxx>
+#include <comphelper/sequence.hxx>
+
+
+using namespace css;
+
+namespace writerfilter::dmapper {
+
+TblStylePrHandler::TblStylePrHandler( DomainMapper & rDMapper ) :
+LoggedProperties("TblStylePrHandler"),
+m_rDMapper( rDMapper ),
+m_pTablePropsHandler(new TablePropertiesHandler()),
+m_nType( TBL_STYLE_UNKNOWN ),
+m_pProperties( new PropertyMap )
+{
+}
+
+TblStylePrHandler::~TblStylePrHandler( )
+{
+}
+
+OUString TblStylePrHandler::getTypeString() const
+{
+ switch (m_nType)
+ {
+ case TBL_STYLE_WHOLETABLE: return "wholeTable";
+ case TBL_STYLE_FIRSTROW: return "firstRow";
+ case TBL_STYLE_LASTROW: return "lastRow";
+ case TBL_STYLE_FIRSTCOL: return "firstCol";
+ case TBL_STYLE_LASTCOL: return "lastCol";
+ case TBL_STYLE_BAND1VERT: return "band1Vert";
+ case TBL_STYLE_BAND2VERT: return "band2Vert";
+ case TBL_STYLE_BAND1HORZ: return "band1Horz";
+ case TBL_STYLE_BAND2HORZ: return "band2Horz";
+ case TBL_STYLE_NECELL: return "neCell";
+ case TBL_STYLE_NWCELL: return "nwCell";
+ case TBL_STYLE_SECELL: return "seCell";
+ case TBL_STYLE_SWCELL: return "swCell";
+ default: break;
+ }
+ return OUString();
+}
+
+void TblStylePrHandler::lcl_attribute(Id rName, Value & rVal)
+{
+
+ switch ( rName )
+ {
+ case NS_ooxml::LN_CT_TblStyleOverrideType:
+ {
+ switch (rVal.getInt())
+ {
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_wholeTable:
+ m_nType = TBL_STYLE_WHOLETABLE;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_firstRow:
+ m_nType = TBL_STYLE_FIRSTROW;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_lastRow:
+ m_nType = TBL_STYLE_LASTROW;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_firstCol:
+ m_nType = TBL_STYLE_FIRSTCOL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_lastCol:
+ m_nType = TBL_STYLE_LASTCOL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band1Vert:
+ m_nType = TBL_STYLE_BAND1VERT;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band2Vert:
+ m_nType = TBL_STYLE_BAND2VERT;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band1Horz:
+ m_nType = TBL_STYLE_BAND1HORZ;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band2Horz:
+ m_nType = TBL_STYLE_BAND2HORZ;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_neCell:
+ m_nType = TBL_STYLE_NECELL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_nwCell:
+ m_nType = TBL_STYLE_NWCELL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_seCell:
+ m_nType = TBL_STYLE_SECELL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_swCell:
+ m_nType = TBL_STYLE_SWCELL;
+ break;
+ }
+ }
+ break;
+ }
+}
+
+void TblStylePrHandler::lcl_sprm(Sprm & rSprm)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TblStylePrHandler.sprm");
+ TagLogger::getInstance().attribute("sprm", rSprm.toString());
+#endif
+
+ switch ( rSprm.getId( ) )
+ {
+ case NS_ooxml::LN_CT_PPrBase:
+ case NS_ooxml::LN_EG_RPrBase:
+ case NS_ooxml::LN_CT_TblPrBase:
+ case NS_ooxml::LN_CT_TrPrBase:
+ case NS_ooxml::LN_CT_TcPrBase:
+ {
+ std::vector<beans::PropertyValue> aSavedGrabBag;
+ bool bGrabBag = rSprm.getId() == NS_ooxml::LN_CT_PPrBase ||
+ rSprm.getId() == NS_ooxml::LN_EG_RPrBase ||
+ rSprm.getId() == NS_ooxml::LN_CT_TblPrBase ||
+ rSprm.getId() == NS_ooxml::LN_CT_TrPrBase ||
+ rSprm.getId() == NS_ooxml::LN_CT_TcPrBase;
+ if (bGrabBag)
+ {
+ std::swap(aSavedGrabBag, m_aInteropGrabBag);
+ }
+ resolveSprmProps( rSprm );
+ if (bGrabBag)
+ {
+ if (rSprm.getId() == NS_ooxml::LN_CT_PPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("pPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_EG_RPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("rPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_CT_TblPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("tblPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_CT_TrPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("trPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_CT_TcPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("tcPr"));
+ std::swap(m_aInteropGrabBag, aSavedGrabBag);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_tblHeader:
+ {
+ m_pProperties->Insert( PROP_HEADER_ROW_COUNT, uno::Any(sal_Int32(1)));
+ beans::PropertyValue aValue;
+ aValue.Name = "tblHeader";
+ aValue.Value <<= true;
+ m_aInteropGrabBag.push_back(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblInd:
+ {
+ //contains unit and value
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->setValue( TablePropertyMap::LEFT_MARGIN, pMeasureHandler->getMeasureValue() );
+ m_pProperties->Insert( PROP_LEFT_MARGIN, uno::Any(pMeasureHandler->getMeasureValue()) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if ( pProperties )
+ {
+ auto pCellMarginHandler = std::make_shared<CellMarginHandler>();
+ pCellMarginHandler->enableInteropGrabBag("tblCellMar");
+ pProperties->resolve( *pCellMarginHandler );
+ m_aInteropGrabBag.push_back(pCellMarginHandler->getInteropGrabBag());
+
+ if( pCellMarginHandler->m_bTopMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_TOP, uno::Any(pCellMarginHandler->m_nTopMargin) );
+ if( pCellMarginHandler->m_bBottomMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_BOTTOM, uno::Any(pCellMarginHandler->m_nBottomMargin) );
+ if( pCellMarginHandler->m_bLeftMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_LEFT, uno::Any(pCellMarginHandler->m_nLeftMargin) );
+ if( pCellMarginHandler->m_bRightMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_RIGHT, uno::Any(pCellMarginHandler->m_nRightMargin) );
+ }
+ }
+ break;
+ default:
+ // Tables specific properties have to handled here
+ m_pTablePropsHandler->SetProperties( m_pProperties );
+ m_pTablePropsHandler->SetInteropGrabBag(m_aInteropGrabBag);
+ bool bRet = m_pTablePropsHandler->sprm( rSprm );
+
+ if ( !bRet )
+ {
+ // The DomainMapper can handle some of the properties
+ m_rDMapper.PushStyleSheetProperties( m_pProperties, true );
+ // Just pass a non-empty string, the array will have a single element anyway.
+ m_rDMapper.enableInteropGrabBag("TblStylePrHandler");
+ m_rDMapper.sprm( rSprm );
+ uno::Sequence<beans::PropertyValue> aGrabBag = m_rDMapper.getInteropGrabBag().Value.get< uno::Sequence<beans::PropertyValue> >();
+ if (aGrabBag.hasElements())
+ m_aInteropGrabBag.push_back(aGrabBag[0]);
+ m_rDMapper.PopStyleSheetProperties( true );
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TblStylePrHandler::resolveSprmProps(Sprm & rSprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+}
+
+void TblStylePrHandler::appendInteropGrabBag(const OUString& aKey, const OUString& aValue)
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ m_aInteropGrabBag.push_back(aProperty);
+}
+
+beans::PropertyValue TblStylePrHandler::getInteropGrabBag(const OUString& aName)
+{
+ beans::PropertyValue aRet;
+ aRet.Name = aName;
+
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TblStylePrHandler.hxx b/writerfilter/source/dmapper/TblStylePrHandler.hxx
new file mode 100644
index 000000000..4be7d379a
--- /dev/null
+++ b/writerfilter/source/dmapper/TblStylePrHandler.hxx
@@ -0,0 +1,82 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "TablePropertiesHandler.hxx"
+
+#include "DomainMapper.hxx"
+#include "LoggedResources.hxx"
+#include <memory>
+#include <vector>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+
+enum TblStyleType
+{
+ TBL_STYLE_UNKNOWN,
+ TBL_STYLE_WHOLETABLE,
+ TBL_STYLE_FIRSTROW,
+ TBL_STYLE_LASTROW,
+ TBL_STYLE_FIRSTCOL,
+ TBL_STYLE_LASTCOL,
+ TBL_STYLE_BAND1VERT,
+ TBL_STYLE_BAND2VERT,
+ TBL_STYLE_BAND1HORZ,
+ TBL_STYLE_BAND2HORZ,
+ TBL_STYLE_NECELL,
+ TBL_STYLE_NWCELL,
+ TBL_STYLE_SECELL,
+ TBL_STYLE_SWCELL
+};
+
+class TblStylePrHandler : public LoggedProperties
+{
+private:
+ DomainMapper & m_rDMapper;
+ std::unique_ptr<TablePropertiesHandler> m_pTablePropsHandler;
+
+ TblStyleType m_nType;
+ PropertyMapPtr m_pProperties;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ explicit TblStylePrHandler( DomainMapper & rDMapper );
+ virtual ~TblStylePrHandler( ) override;
+
+ const PropertyMapPtr& getProperties() const { return m_pProperties; };
+ TblStyleType getType() const { return m_nType; };
+ OUString getTypeString() const;
+ void appendInteropGrabBag(const OUString& aKey, const OUString& aValue);
+ css::beans::PropertyValue getInteropGrabBag(const OUString& aName);
+
+private:
+
+ void resolveSprmProps(Sprm & rSprm);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TextEffectsHandler.cxx b/writerfilter/source/dmapper/TextEffectsHandler.cxx
new file mode 100644
index 000000000..cce02393c
--- /dev/null
+++ b/writerfilter/source/dmapper/TextEffectsHandler.cxx
@@ -0,0 +1,804 @@
+/* -*- 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 <sal/config.h>
+
+#include <map>
+
+#include "TextEffectsHandler.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/string.hxx>
+#include <ooxml/resourceids.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+
+namespace writerfilter::dmapper
+{
+
+using namespace com::sun::star;
+
+namespace
+{
+
+OUString lclGetNameForElementId(sal_uInt32 aId)
+{
+ static std::map<sal_uInt32, OUString> aIdMap;
+ if(aIdMap.empty())
+ {
+ aIdMap[NS_ooxml::LN_EG_ColorChoice_srgbClr] = "srgbClr";
+ aIdMap[NS_ooxml::LN_EG_ColorChoice_schemeClr] = "schemeClr";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_tint] = "tint";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_shade] = "shade";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_alpha] = "alpha";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_hueMod] = "hueMod";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_sat] = "sat";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_satOff] = "satOff";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_satMod] = "satMod";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_lum] = "lum";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_lumOff] = "lumOff";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_lumMod] = "lumMod";
+ aIdMap[NS_ooxml::LN_EG_FillProperties_noFill] = "noFill";
+ aIdMap[NS_ooxml::LN_EG_FillProperties_solidFill] = "solidFill";
+ aIdMap[NS_ooxml::LN_EG_FillProperties_gradFill] = "gradFill";
+ aIdMap[NS_ooxml::LN_CT_GradientFillProperties_gsLst] = "gsLst";
+ aIdMap[NS_ooxml::LN_CT_GradientStopList_gs] = "gs";
+ aIdMap[NS_ooxml::LN_CT_GradientStop_pos] = "pos";
+ aIdMap[NS_ooxml::LN_EG_ShadeProperties_lin] = "lin";
+ aIdMap[NS_ooxml::LN_EG_ShadeProperties_path] = "path";
+ aIdMap[NS_ooxml::LN_CT_PathShadeProperties_fillToRect] = "fillToRect";
+ aIdMap[NS_ooxml::LN_EG_LineDashProperties_prstDash] = "prstDash";
+ aIdMap[NS_ooxml::LN_EG_LineJoinProperties_round] = "round";
+ aIdMap[NS_ooxml::LN_EG_LineJoinProperties_bevel] = "bevel";
+ aIdMap[NS_ooxml::LN_EG_LineJoinProperties_miter] = "miter";
+ aIdMap[NS_ooxml::LN_CT_Scene3D_camera] = "camera";
+ aIdMap[NS_ooxml::LN_CT_Scene3D_lightRig] = "lightRig";
+ aIdMap[NS_ooxml::LN_CT_LightRig_rot] = "rot";
+ aIdMap[NS_ooxml::LN_CT_Props3D_bevelT] = "bevelT";
+ aIdMap[NS_ooxml::LN_CT_Props3D_bevelB] = "bevelB";
+ aIdMap[NS_ooxml::LN_CT_Props3D_extrusionClr] = "extrusionClr";
+ aIdMap[NS_ooxml::LN_CT_Props3D_contourClr] = "contourClr";
+ aIdMap[NS_ooxml::LN_CT_StylisticSets_styleSet] = "styleSet";
+ aIdMap[NS_ooxml::LN_cntxtAlts_cntxtAlts] = "cntxtAlts";
+ }
+ return aIdMap[aId];
+}
+
+constexpr OUStringLiteral constAttributesSequenceName = u"attributes";
+
+}
+
+OUString TextEffectsHandler::getSchemeColorValTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_SchemeColorVal_bg1: return "bg1";
+ case NS_ooxml::LN_ST_SchemeColorVal_tx1: return "tx1";
+ case NS_ooxml::LN_ST_SchemeColorVal_bg2: return "bg2";
+ case NS_ooxml::LN_ST_SchemeColorVal_tx2: return "tx2";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent1: return "accent1";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent2: return "accent2";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent3: return "accent3";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent4: return "accent4";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent5: return "accent5";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent6: return "accent6";
+ case NS_ooxml::LN_ST_SchemeColorVal_hlink: return "hlink";
+ case NS_ooxml::LN_ST_SchemeColorVal_folHlink: return "folHlink";
+ case NS_ooxml::LN_ST_SchemeColorVal_dk1: return "dk1";
+ case NS_ooxml::LN_ST_SchemeColorVal_lt1: return "lt1";
+ case NS_ooxml::LN_ST_SchemeColorVal_dk2: return "dk2";
+ case NS_ooxml::LN_ST_SchemeColorVal_lt2: return "lt2";
+ case NS_ooxml::LN_ST_SchemeColorVal_phClr: return "phClr";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getRectAlignmentString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_RectAlignment_none: return "none";
+ case NS_ooxml::LN_ST_RectAlignment_tl: return "tl";
+ case NS_ooxml::LN_ST_RectAlignment_t: return "t";
+ case NS_ooxml::LN_ST_RectAlignment_tr: return "tr";
+ case NS_ooxml::LN_ST_RectAlignment_l: return "l";
+ case NS_ooxml::LN_ST_RectAlignment_ctr: return "ctr";
+ case NS_ooxml::LN_ST_RectAlignment_r: return "r";
+ case NS_ooxml::LN_ST_RectAlignment_bl: return "bl";
+ case NS_ooxml::LN_ST_RectAlignment_b: return "b";
+ case NS_ooxml::LN_ST_RectAlignment_br: return "br";
+
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getLineCapString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_LineCap_rnd: return "rnd";
+ case NS_ooxml::LN_ST_LineCap_sq: return "sq";
+ case NS_ooxml::LN_ST_LineCap_flat: return "flat";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getCompoundLineString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_CompoundLine_sng: return "sng";
+ case NS_ooxml::LN_ST_CompoundLine_dbl: return "dbl";
+ case NS_ooxml::LN_ST_CompoundLine_thickThin: return "thickThin";
+ case NS_ooxml::LN_ST_CompoundLine_thinThick: return "thinThick";
+ case NS_ooxml::LN_ST_CompoundLine_tri: return "tri";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPenAlignmentString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PenAlignment_ctr: return "ctr";
+ case NS_ooxml::LN_ST_PenAlignment_in: return "in";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getOnOffString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_OnOff_true: return "true";
+ case NS_ooxml::LN_ST_OnOff_false: return "false";
+ case NS_ooxml::LN_ST_OnOff_1: return "1";
+ case NS_ooxml::LN_ST_OnOff_0: return "0";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPathShadeTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PathShadeType_shape: return "shape";
+ case NS_ooxml::LN_ST_PathShadeType_circle: return "circle";
+ case NS_ooxml::LN_ST_PathShadeType_rect: return "rect";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPresetLineDashValString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PresetLineDashVal_solid: return "solid";
+ case NS_ooxml::LN_ST_PresetLineDashVal_dot: return "dot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDot: return "sysDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_dash: return "dash";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDash: return "sysDash";
+ case NS_ooxml::LN_ST_PresetLineDashVal_lgDash: return "lgDash";
+ case NS_ooxml::LN_ST_PresetLineDashVal_dashDot: return "dashDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDashDot: return "sysDashDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_lgDashDot: return "lgDashDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_lgDashDotDot: return "lgDashDotDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDashDotDot: return "sysDashDotDot";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPresetCameraTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueTopLeft: return "legacyObliqueTopLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueTop: return "legacyObliqueTop";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueTopRight: return "legacyObliqueTopRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueLeft: return "legacyObliqueLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueFront: return "legacyObliqueFront";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueRight: return "legacyObliqueRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueBottomLeft: return "legacyObliqueBottomLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueBottom: return "legacyObliqueBottom";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueBottomRight: return "legacyObliqueBottomRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveTopLeft: return "legacyPerspectiveTopLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveTop: return "legacyPerspectiveTop";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveTopRight: return "legacyPerspectiveTopRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveLeft: return "legacyPerspectiveLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveFront: return "legacyPerspectiveFront";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveRight: return "legacyPerspectiveRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveBottomLeft: return "legacyPerspectiveBottomLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveBottom: return "legacyPerspectiveBottom";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveBottomRight: return "legacyPerspectiveBottomRight";
+ case NS_ooxml::LN_ST_PresetCameraType_orthographicFront: return "orthographicFront";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricTopUp: return "isometricTopUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricTopDown: return "isometricTopDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricBottomUp: return "isometricBottomUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricBottomDown: return "isometricBottomDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricLeftUp: return "isometricLeftUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricLeftDown: return "isometricLeftDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricRightUp: return "isometricRightUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricRightDown: return "isometricRightDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis1Left: return "isometricOffAxis1Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis1Right: return "isometricOffAxis1Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis1Top: return "isometricOffAxis1Top";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis2Left: return "isometricOffAxis2Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis2Right: return "isometricOffAxis2Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis2Top: return "isometricOffAxis2Top";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis3Left: return "isometricOffAxis3Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis3Right: return "isometricOffAxis3Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis3Bottom: return "isometricOffAxis3Bottom";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis4Left: return "isometricOffAxis4Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis4Right: return "isometricOffAxis4Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis4Bottom: return "isometricOffAxis4Bottom";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueTopLeft: return "obliqueTopLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueTop: return "obliqueTop";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueTopRight: return "obliqueTopRight";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueLeft: return "obliqueLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueRight: return "obliqueRight";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueBottomLeft: return "obliqueBottomLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueBottom: return "obliqueBottom";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueBottomRight: return "obliqueBottomRight";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveFront: return "perspectiveFront";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveLeft: return "perspectiveLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveRight: return "perspectiveRight";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveAbove: return "perspectiveAbove";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveBelow: return "perspectiveBelow";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveAboveLeftFacing: return "perspectiveAboveLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveAboveRightFacing: return "perspectiveAboveRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveContrastingLeftFacing: return "perspectiveContrastingLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveContrastingRightFacing: return "perspectiveContrastingRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicLeftFacing: return "perspectiveHeroicLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicRightFacing: return "perspectiveHeroicRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicExtremeLeftFacing: return "perspectiveHeroicExtremeLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicExtremeRightFacing: return "perspectiveHeroicExtremeRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveRelaxed: return "perspectiveRelaxed";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveRelaxedModerately: return "perspectiveRelaxedModerately";
+ default: break;
+ }
+ return OUString();
+}
+
+
+OUString TextEffectsHandler::getLightRigTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat1: return "legacyFlat1";
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat2: return "legacyFlat2";
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat3: return "legacyFlat3";
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat4: return "legacyFlat4";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal1: return "legacyNormal1";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal2: return "legacyNormal2";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal3: return "legacyNormal3";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal4: return "legacyNormal4";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh1: return "legacyHarsh1";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh2: return "legacyHarsh2";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh3: return "legacyHarsh3";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh4: return "legacyHarsh4";
+ case NS_ooxml::LN_ST_LightRigType_threePt: return "threePt";
+ case NS_ooxml::LN_ST_LightRigType_balanced: return "balanced";
+ case NS_ooxml::LN_ST_LightRigType_soft: return "soft";
+ case NS_ooxml::LN_ST_LightRigType_harsh: return "harsh";
+ case NS_ooxml::LN_ST_LightRigType_flood: return "flood";
+ case NS_ooxml::LN_ST_LightRigType_contrasting: return "contrasting";
+ case NS_ooxml::LN_ST_LightRigType_morning: return "morning";
+ case NS_ooxml::LN_ST_LightRigType_sunrise: return "sunrise";
+ case NS_ooxml::LN_ST_LightRigType_sunset: return "sunset";
+ case NS_ooxml::LN_ST_LightRigType_chilly: return "chilly";
+ case NS_ooxml::LN_ST_LightRigType_freezing: return "freezing";
+ case NS_ooxml::LN_ST_LightRigType_flat: return "flat";
+ case NS_ooxml::LN_ST_LightRigType_twoPt: return "twoPt";
+ case NS_ooxml::LN_ST_LightRigType_glow: return "glow";
+ case NS_ooxml::LN_ST_LightRigType_brightRoom: return "brightRoom";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getLightRigDirectionString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_LightRigDirection_tl: return "tl";
+ case NS_ooxml::LN_ST_LightRigDirection_t: return "t";
+ case NS_ooxml::LN_ST_LightRigDirection_tr: return "tr";
+ case NS_ooxml::LN_ST_LightRigDirection_l: return "l";
+ case NS_ooxml::LN_ST_LightRigDirection_r: return "r";
+ case NS_ooxml::LN_ST_LightRigDirection_bl: return "bl";
+ case NS_ooxml::LN_ST_LightRigDirection_b: return "b";
+ case NS_ooxml::LN_ST_LightRigDirection_br: return "br";
+
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getBevelPresetTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_BevelPresetType_relaxedInset: return "relaxedInset";
+ case NS_ooxml::LN_ST_BevelPresetType_circle: return "circle";
+ case NS_ooxml::LN_ST_BevelPresetType_slope: return "slope";
+ case NS_ooxml::LN_ST_BevelPresetType_cross: return "cross";
+ case NS_ooxml::LN_ST_BevelPresetType_angle: return "angle";
+ case NS_ooxml::LN_ST_BevelPresetType_softRound: return "softRound";
+ case NS_ooxml::LN_ST_BevelPresetType_convex: return "convex";
+ case NS_ooxml::LN_ST_BevelPresetType_coolSlant: return "coolSlant";
+ case NS_ooxml::LN_ST_BevelPresetType_divot: return "divot";
+ case NS_ooxml::LN_ST_BevelPresetType_riblet: return "riblet";
+ case NS_ooxml::LN_ST_BevelPresetType_hardEdge: return "hardEdge";
+ case NS_ooxml::LN_ST_BevelPresetType_artDeco: return "artDeco";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPresetMaterialTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyMatte: return "legacyMatte";
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyPlastic: return "legacyPlastic";
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyMetal: return "legacyMetal";
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyWireframe: return "legacyWireframe";
+ case NS_ooxml::LN_ST_PresetMaterialType_matte: return "matte";
+ case NS_ooxml::LN_ST_PresetMaterialType_plastic: return "plastic";
+ case NS_ooxml::LN_ST_PresetMaterialType_metal: return "metal";
+ case NS_ooxml::LN_ST_PresetMaterialType_warmMatte: return "warmMatte";
+ case NS_ooxml::LN_ST_PresetMaterialType_translucentPowder: return "translucentPowder";
+ case NS_ooxml::LN_ST_PresetMaterialType_powder: return "powder";
+ case NS_ooxml::LN_ST_PresetMaterialType_dkEdge: return "dkEdge";
+ case NS_ooxml::LN_ST_PresetMaterialType_softEdge: return "softEdge";
+ case NS_ooxml::LN_ST_PresetMaterialType_clear: return "clear";
+ case NS_ooxml::LN_ST_PresetMaterialType_flat: return "flat";
+ case NS_ooxml::LN_ST_PresetMaterialType_softmetal: return "softmetal";
+ case NS_ooxml::LN_ST_PresetMaterialType_none: return "none";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getLigaturesString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_Ligatures_none: return "none";
+ case NS_ooxml::LN_ST_Ligatures_standard: return "standard";
+ case NS_ooxml::LN_ST_Ligatures_contextual: return "contextual";
+ case NS_ooxml::LN_ST_Ligatures_historical: return "historical";
+ case NS_ooxml::LN_ST_Ligatures_discretional: return "discretional";
+ case NS_ooxml::LN_ST_Ligatures_standardContextual: return "standardContextual";
+ case NS_ooxml::LN_ST_Ligatures_standardHistorical: return "standardHistorical";
+ case NS_ooxml::LN_ST_Ligatures_contextualHistorical: return "contextualHistorical";
+ case NS_ooxml::LN_ST_Ligatures_standardDiscretional: return "standardDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_contextualDiscretional: return "contextualDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_historicalDiscretional: return "historicalDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_standardContextualHistorical: return "standardContextualHistorical";
+ case NS_ooxml::LN_ST_Ligatures_standardContextualDiscretional: return "standardContextualDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_standardHistoricalDiscretional: return "standardHistoricalDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_contextualHistoricalDiscretional: return "contextualHistoricalDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_all: return "all";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getNumFormString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_NumForm_default: return "default";
+ case NS_ooxml::LN_ST_NumForm_lining: return "lining";
+ case NS_ooxml::LN_ST_NumForm_oldStyle: return "oldStyle";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getNumSpacingString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_NumSpacing_default: return "default";
+ case NS_ooxml::LN_ST_NumSpacing_proportional: return "proportional";
+ case NS_ooxml::LN_ST_NumSpacing_tabular: return "tabular";
+ default: break;
+ }
+ return OUString();
+}
+
+void TextEffectsHandler::convertElementIdToPropertyId(sal_Int32 aElementId)
+{
+ switch(aElementId)
+ {
+ case NS_ooxml::LN_glow_glow:
+ maPropertyId = PROP_CHAR_GLOW_TEXT_EFFECT;
+ maElementName = "glow";
+ break;
+ case NS_ooxml::LN_shadow_shadow:
+ maPropertyId = PROP_CHAR_SHADOW_TEXT_EFFECT;
+ maElementName = "shadow";
+ break;
+ case NS_ooxml::LN_reflection_reflection:
+ maPropertyId = PROP_CHAR_REFLECTION_TEXT_EFFECT;
+ maElementName = "reflection";
+ break;
+ case NS_ooxml::LN_textOutline_textOutline:
+ maPropertyId = PROP_CHAR_TEXTOUTLINE_TEXT_EFFECT;
+ maElementName = "textOutline";
+ break;
+ case NS_ooxml::LN_textFill_textFill:
+ maPropertyId = PROP_CHAR_TEXTFILL_TEXT_EFFECT;
+ maElementName = "textFill";
+ break;
+ case NS_ooxml::LN_scene3d_scene3d:
+ maPropertyId = PROP_CHAR_SCENE3D_TEXT_EFFECT;
+ maElementName = "scene3d";
+ break;
+ case NS_ooxml::LN_props3d_props3d:
+ maPropertyId = PROP_CHAR_PROPS3D_TEXT_EFFECT;
+ maElementName = "props3d";
+ break;
+ case NS_ooxml::LN_ligatures_ligatures:
+ maPropertyId = PROP_CHAR_LIGATURES_TEXT_EFFECT;
+ maElementName = "ligatures";
+ break;
+ case NS_ooxml::LN_numForm_numForm:
+ maPropertyId = PROP_CHAR_NUMFORM_TEXT_EFFECT;
+ maElementName = "numForm";
+ break;
+ case NS_ooxml::LN_numSpacing_numSpacing:
+ maPropertyId = PROP_CHAR_NUMSPACING_TEXT_EFFECT;
+ maElementName = "numSpacing";
+ break;
+ case NS_ooxml::LN_stylisticSets_stylisticSets:
+ maPropertyId = PROP_CHAR_STYLISTICSETS_TEXT_EFFECT;
+ maElementName = "stylisticSets";
+ break;
+ case NS_ooxml::LN_cntxtAlts_cntxtAlts:
+ maPropertyId = PROP_CHAR_CNTXTALTS_TEXT_EFFECT;
+ maElementName = "cntxtAlts";
+ break;
+ default:
+ break;
+ }
+}
+
+TextEffectsHandler::TextEffectsHandler(sal_uInt32 aElementId) :
+ LoggedProperties("TextEffectsHandler")
+{
+ convertElementIdToPropertyId(aElementId);
+ mpGrabBagStack.reset(new oox::GrabBagStack(maElementName));
+}
+
+TextEffectsHandler::~TextEffectsHandler()
+{
+}
+
+
+void TextEffectsHandler::lcl_attribute(Id aName, Value& aValue)
+{
+ if (mpGrabBagStack->getCurrentName() != constAttributesSequenceName)
+ mpGrabBagStack->push(constAttributesSequenceName);
+
+ switch(aName)
+ {
+ case NS_ooxml::LN_CT_Percentage_val:
+ case NS_ooxml::LN_CT_PositiveFixedPercentage_val:
+ case NS_ooxml::LN_CT_PositivePercentage_val:
+ mpGrabBagStack->addInt32("val", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Glow_rad:
+ mpGrabBagStack->addInt32("rad", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_SchemeColor_val:
+ {
+ OUString aString = getSchemeColorValTypeString(sal_Int32(aValue.getInt()));
+ mpGrabBagStack->addString("val", aString);
+ }
+ break;
+ case NS_ooxml::LN_CT_SRgbColor_val:
+ {
+ OUString aBuffer = OUString::number(aValue.getInt(), 16);
+ OUStringBuffer aString;
+ comphelper::string::padToLength(aString, 6 - aBuffer.getLength(), '0');
+ aString.append(aBuffer.getStr());
+ mpGrabBagStack->addString("val", aString.makeStringAndClear().toAsciiUpperCase());
+ }
+ break;
+ case NS_ooxml::LN_CT_Shadow_blurRad:
+ case NS_ooxml::LN_CT_Reflection_blurRad:
+ mpGrabBagStack->addInt32("blurRad", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_stA:
+ mpGrabBagStack->addInt32("stA", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_stPos:
+ mpGrabBagStack->addInt32("stPos", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_endA:
+ mpGrabBagStack->addInt32("endA", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_endPos:
+ mpGrabBagStack->addInt32("endPos", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_dist:
+ case NS_ooxml::LN_CT_Reflection_dist:
+ mpGrabBagStack->addInt32("dist", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_dir:
+ case NS_ooxml::LN_CT_Reflection_dir:
+ mpGrabBagStack->addInt32("dir", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_fadeDir:
+ mpGrabBagStack->addInt32("fadeDir", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_sx:
+ case NS_ooxml::LN_CT_Reflection_sx:
+ mpGrabBagStack->addInt32("sx", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_sy:
+ case NS_ooxml::LN_CT_Reflection_sy:
+ mpGrabBagStack->addInt32("sy", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_kx:
+ case NS_ooxml::LN_CT_Reflection_kx:
+ mpGrabBagStack->addInt32("kx", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_ky:
+ case NS_ooxml::LN_CT_Reflection_ky:
+ mpGrabBagStack->addInt32("ky", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_algn:
+ case NS_ooxml::LN_CT_Reflection_algn:
+ {
+ uno::Any aAny(getRectAlignmentString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("algn", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_w:
+ mpGrabBagStack->addInt32("w", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_cap:
+ {
+ uno::Any aAny(getLineCapString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("cap", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_cmpd:
+ {
+ uno::Any aAny(getCompoundLineString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("cmpd", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_algn:
+ {
+ uno::Any aAny(getPenAlignmentString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("algn", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_GradientStop_pos:
+ mpGrabBagStack->addInt32("pos", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_LinearShadeProperties_ang:
+ mpGrabBagStack->addInt32("ang", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_LinearShadeProperties_scaled:
+ {
+ uno::Any aAny(getOnOffString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("scaled", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_PathShadeProperties_path:
+ {
+ uno::Any aAny(getPathShadeTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("path", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_l:
+ mpGrabBagStack->addInt32("l", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_t:
+ mpGrabBagStack->addInt32("t", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_r:
+ mpGrabBagStack->addInt32("r", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_b:
+ mpGrabBagStack->addInt32("b", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_PresetLineDashProperties_val:
+ {
+ uno::Any aAny(getPresetLineDashValString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_LineJoinMiterProperties_lim:
+ mpGrabBagStack->addInt32("lim", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Camera_prst:
+ {
+ uno::Any aAny(getPresetCameraTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("prst", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_LightRig_rig:
+ {
+ uno::Any aAny(getLightRigTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("rig", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_LightRig_dir:
+ {
+ uno::Any aAny(getLightRigDirectionString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("dir", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_SphereCoords_lat:
+ mpGrabBagStack->addInt32("lat", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_SphereCoords_lon:
+ mpGrabBagStack->addInt32("lon", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_SphereCoords_rev:
+ mpGrabBagStack->addInt32("rev", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Props3D_extrusionH:
+ mpGrabBagStack->addInt32("extrusionH", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Props3D_contourW:
+ mpGrabBagStack->addInt32("contourW", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Props3D_prstMaterial:
+ {
+ uno::Any aAny(getPresetMaterialTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("prstMaterial", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_Bevel_w:
+ mpGrabBagStack->addInt32("w", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Bevel_h:
+ mpGrabBagStack->addInt32("h", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Bevel_prst:
+ {
+ uno::Any aAny(getBevelPresetTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("prst", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_Ligatures_val:
+ {
+ uno::Any aAny(getLigaturesString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumForm_val:
+ {
+ uno::Any aAny(getNumFormString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumSpacing_val:
+ {
+ uno::Any aAny(getNumSpacingString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_StyleSet_id:
+ mpGrabBagStack->addInt32("id", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_StyleSet_val:
+ case NS_ooxml::LN_CT_OnOff_val:
+ {
+ uno::Any aAny(getOnOffString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void TextEffectsHandler::lcl_sprm(Sprm& rSprm)
+{
+ if (mpGrabBagStack->getCurrentName() == constAttributesSequenceName)
+ mpGrabBagStack->pop();
+
+ sal_uInt32 nSprmId = rSprm.getId();
+ OUString aElementName = lclGetNameForElementId(nSprmId);
+ if(aElementName.isEmpty())
+ {
+ // Element is unknown -> leave.
+ return;
+ }
+
+ mpGrabBagStack->push(aElementName);
+
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( !pProperties )
+ return;
+
+ pProperties->resolve( *this );
+
+ if (mpGrabBagStack->getCurrentName() == constAttributesSequenceName)
+ mpGrabBagStack->pop();
+
+ mpGrabBagStack->pop();
+}
+
+beans::PropertyValue TextEffectsHandler::getInteropGrabBag()
+{
+ beans::PropertyValue aReturn = mpGrabBagStack->getRootProperty();
+ mpGrabBagStack.reset();
+ return aReturn;
+}
+
+sal_uInt8 TextEffectsHandler::GetTextFillSolidFillAlpha(const css::beans::PropertyValue& rValue)
+{
+ if (rValue.Name != "textFill")
+ {
+ return 0;
+ }
+
+ uno::Sequence<beans::PropertyValue> aPropertyValues;
+ rValue.Value >>= aPropertyValues;
+ comphelper::SequenceAsHashMap aMap(aPropertyValues);
+ auto it = aMap.find("solidFill");
+ if (it == aMap.end())
+ {
+ return 0;
+ }
+
+ comphelper::SequenceAsHashMap aSolidFillMap(it->second);
+ it = aSolidFillMap.find("srgbClr");
+ if (it == aSolidFillMap.end())
+ {
+ return 0;
+ }
+
+ comphelper::SequenceAsHashMap aSrgbClrMap(it->second);
+ it = aSrgbClrMap.find("alpha");
+ if (it == aSrgbClrMap.end())
+ {
+ return 0;
+ }
+
+ comphelper::SequenceAsHashMap aAlphaMap(it->second);
+ it = aAlphaMap.find("attributes");
+ if (it == aAlphaMap.end())
+ {
+ return 0;
+ }
+
+ comphelper::SequenceAsHashMap aAttributesMap(it->second);
+ it = aAttributesMap.find("val");
+ if (it == aAttributesMap.end())
+ {
+ return 0;
+ }
+ sal_Int32 nVal = 0;
+ it->second >>= nVal;
+ return nVal / oox::drawingml::PER_PERCENT;
+}
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TextEffectsHandler.hxx b/writerfilter/source/dmapper/TextEffectsHandler.hxx
new file mode 100644
index 000000000..30a8435b2
--- /dev/null
+++ b/writerfilter/source/dmapper/TextEffectsHandler.hxx
@@ -0,0 +1,69 @@
+/* -*- 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/.
+ *
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include "PropertyIds.hxx"
+
+#include <oox/helper/grabbagstack.hxx>
+
+#include <memory>
+#include <optional>
+
+namespace writerfilter::dmapper
+{
+/// Class to process all text effects like glow, textOutline, ...
+class TextEffectsHandler : public LoggedProperties
+{
+private:
+ std::optional<PropertyIds> maPropertyId;
+ OUString maElementName;
+ std::unique_ptr<oox::GrabBagStack> mpGrabBagStack;
+
+ void convertElementIdToPropertyId(sal_Int32 aElementId);
+
+public:
+ explicit TextEffectsHandler(sal_uInt32 aElementId);
+ virtual ~TextEffectsHandler() override;
+
+ const std::optional<PropertyIds>& getGrabBagPropertyId() const { return maPropertyId; }
+
+ css::beans::PropertyValue getInteropGrabBag();
+
+ static OUString getSchemeColorValTypeString(sal_Int32 nType);
+ static OUString getRectAlignmentString(sal_Int32 nType);
+ static OUString getLineCapString(sal_Int32 nType);
+ static OUString getCompoundLineString(sal_Int32 nType);
+ static OUString getPenAlignmentString(sal_Int32 nType);
+ static OUString getOnOffString(sal_Int32 nType);
+ static OUString getPathShadeTypeString(sal_Int32 nType);
+ static OUString getPresetLineDashValString(sal_Int32 nType);
+ static OUString getPresetCameraTypeString(sal_Int32 nType);
+ static OUString getLightRigTypeString(sal_Int32 nType);
+ static OUString getLightRigDirectionString(sal_Int32 nType);
+ static OUString getBevelPresetTypeString(sal_Int32 nType);
+ static OUString getPresetMaterialTypeString(sal_Int32 nType);
+ static OUString getLigaturesString(sal_Int32 nType);
+ static OUString getNumFormString(sal_Int32 nType);
+ static OUString getNumSpacingString(sal_Int32 nType);
+
+ static sal_uInt8 GetTextFillSolidFillAlpha(const css::beans::PropertyValue& rValue);
+
+ // LoggedProperties
+ virtual void lcl_attribute(Id aName, Value& aValue) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ThemeTable.cxx b/writerfilter/source/dmapper/ThemeTable.cxx
new file mode 100644
index 000000000..4d6ed2b3b
--- /dev/null
+++ b/writerfilter/source/dmapper/ThemeTable.cxx
@@ -0,0 +1,563 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TagLogger.hxx"
+#include "ThemeTable.hxx"
+#include <i18nlangtag/languagetag.hxx>
+#include <ooxml/resourceids.hxx>
+
+#include <map>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+
+struct ThemeTable_Impl
+{
+ ThemeTable_Impl() :
+ m_currentThemeFontId(0),
+ m_supplementalFontId(0)
+ {}
+ std::map<sal_uInt32, std::map<sal_uInt32, OUString> > m_themeFontMap;
+ sal_uInt32 m_currentThemeFontId;
+ std::map<sal_uInt32, OUString> m_currentFontThemeEntry;
+ OUString m_supplementalFontName;
+ sal_uInt32 m_supplementalFontId;
+ OUString m_themeFontLangEastAsia;
+ OUString m_themeFontLangBidi;
+};
+
+ThemeTable::ThemeTable()
+: LoggedProperties("ThemeTable")
+, LoggedTable("ThemeTable")
+, m_pImpl( new ThemeTable_Impl )
+{
+
+}
+
+ThemeTable::~ThemeTable()
+{
+}
+
+void ThemeTable::lcl_attribute(Id Name, Value & val)
+{
+ OUString sValue = val.getString();
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_TextFont_typeface:
+ if (!sValue.isEmpty())
+ m_pImpl->m_currentFontThemeEntry[m_pImpl->m_currentThemeFontId] = sValue;
+ break;
+ case NS_ooxml::LN_CT_SupplementalFont_script:
+ if (!sValue.isEmpty())
+ {
+ if (sValue == m_pImpl->m_themeFontLangBidi)
+ m_pImpl->m_supplementalFontId = NS_ooxml::LN_CT_FontCollection_cs;
+ else if (sValue == m_pImpl->m_themeFontLangEastAsia)
+ m_pImpl->m_supplementalFontId = NS_ooxml::LN_CT_FontCollection_ea;
+ }
+ break;
+ case NS_ooxml::LN_CT_SupplementalFont_typeface:
+ if (!sValue.isEmpty())
+ m_pImpl->m_supplementalFontName = sValue;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+ if(m_pImpl->m_supplementalFontId && m_pImpl->m_supplementalFontName.getLength() > 0)
+ {
+ m_pImpl->m_currentFontThemeEntry[m_pImpl->m_supplementalFontId] = m_pImpl->m_supplementalFontName;
+ m_pImpl->m_supplementalFontName.clear();
+ m_pImpl->m_supplementalFontId = 0;
+ }
+}
+
+void ThemeTable::lcl_sprm(Sprm& rSprm)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("ThemeTable.sprm");
+ TagLogger::getInstance().chars(rSprm.toString());
+#endif
+
+ m_pImpl->m_supplementalFontName.clear();
+ m_pImpl->m_supplementalFontId = 0;
+
+ sal_uInt32 nSprmId = rSprm.getId();
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_BaseStyles_fontScheme:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_FontScheme_majorFont:
+ case NS_ooxml::LN_CT_FontScheme_minorFont:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ m_pImpl->m_currentFontThemeEntry = std::map<sal_uInt32, OUString>();
+ if( pProperties )
+ pProperties->resolve(*this);
+ m_pImpl->m_themeFontMap[nSprmId] = m_pImpl->m_currentFontThemeEntry;
+ }
+ break;
+ case NS_ooxml::LN_CT_FontCollection_latin:
+ case NS_ooxml::LN_CT_FontCollection_ea:
+ case NS_ooxml::LN_CT_FontCollection_cs:
+ {
+ m_pImpl->m_currentThemeFontId = nSprmId;
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_FontCollection_font:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties )
+ pProperties->resolve(*this);
+ }
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void ThemeTable::lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("ThemeTable.entry");
+#endif
+
+ ref->resolve(*this);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+OUString ThemeTable::getStringForTheme(const Id id)
+{
+ switch (id)
+ {
+ case NS_ooxml::LN_Value_ST_Theme_majorEastAsia:
+ return "majorEastAsia";
+ case NS_ooxml::LN_Value_ST_Theme_majorBidi:
+ return "majorBidi";
+ case NS_ooxml::LN_Value_ST_Theme_majorAscii:
+ return "majorAscii";
+ case NS_ooxml::LN_Value_ST_Theme_majorHAnsi:
+ return "majorHAnsi";
+ case NS_ooxml::LN_Value_ST_Theme_minorEastAsia:
+ return "minorEastAsia";
+ case NS_ooxml::LN_Value_ST_Theme_minorBidi:
+ return "minorBidi";
+ case NS_ooxml::LN_Value_ST_Theme_minorAscii:
+ return "minorAscii";
+ case NS_ooxml::LN_Value_ST_Theme_minorHAnsi:
+ return "minorHAnsi";
+ }
+ return OUString();
+}
+OUString ThemeTable::getFontNameForTheme(const Id id) const
+{
+ std::map<sal_uInt32, OUString> tmpThemeFontMap;
+ switch (id)
+ {
+ case NS_ooxml::LN_Value_ST_Theme_majorEastAsia:
+ case NS_ooxml::LN_Value_ST_Theme_majorBidi:
+ case NS_ooxml::LN_Value_ST_Theme_majorAscii:
+ case NS_ooxml::LN_Value_ST_Theme_majorHAnsi:
+ tmpThemeFontMap = m_pImpl->m_themeFontMap[NS_ooxml::LN_CT_FontScheme_majorFont];
+ break;
+ case NS_ooxml::LN_Value_ST_Theme_minorEastAsia:
+ case NS_ooxml::LN_Value_ST_Theme_minorBidi:
+ case NS_ooxml::LN_Value_ST_Theme_minorAscii:
+ case NS_ooxml::LN_Value_ST_Theme_minorHAnsi:
+ tmpThemeFontMap = m_pImpl->m_themeFontMap[NS_ooxml::LN_CT_FontScheme_minorFont];
+ break;
+ default:
+ return OUString();
+ }
+
+ switch (id)
+ {
+ case NS_ooxml::LN_Value_ST_Theme_majorAscii:
+ case NS_ooxml::LN_Value_ST_Theme_majorHAnsi:
+ case NS_ooxml::LN_Value_ST_Theme_minorAscii:
+ case NS_ooxml::LN_Value_ST_Theme_minorHAnsi:
+ {
+ std::map<sal_uInt32, OUString>::const_iterator Iter = tmpThemeFontMap.find(NS_ooxml::LN_CT_FontCollection_latin);
+ if (Iter != tmpThemeFontMap.end())
+ return Iter->second;
+ return OUString();
+ }
+ case NS_ooxml::LN_Value_ST_Theme_majorBidi:
+ case NS_ooxml::LN_Value_ST_Theme_minorBidi:
+ {
+ std::map<sal_uInt32, OUString>::const_iterator Iter = tmpThemeFontMap.find(NS_ooxml::LN_CT_FontCollection_cs);
+ if (Iter != tmpThemeFontMap.end())
+ return Iter->second;
+ return OUString();
+ }
+ case NS_ooxml::LN_Value_ST_Theme_majorEastAsia:
+ case NS_ooxml::LN_Value_ST_Theme_minorEastAsia:
+ {
+ std::map<sal_uInt32, OUString>::const_iterator Iter = tmpThemeFontMap.find(NS_ooxml::LN_CT_FontCollection_ea);
+ if (Iter != tmpThemeFontMap.end())
+ return Iter->second;
+ return OUString();
+ }
+ default:
+ return OUString();
+ }
+}
+
+void ThemeTable::setThemeFontLangProperties(const uno::Sequence<beans::PropertyValue>& aPropSeq)
+{
+ for (const auto& rProp : aPropSeq)
+ {
+ OUString sLocaleName;
+ rProp.Value >>= sLocaleName;
+ if (rProp.Name == "eastAsia")
+ m_pImpl->m_themeFontLangEastAsia = fromLocaleToScriptTag(sLocaleName);
+ if (rProp.Name == "bidi")
+ m_pImpl->m_themeFontLangBidi = fromLocaleToScriptTag(sLocaleName);
+
+ }
+}
+
+OUString ThemeTable::fromLocaleToScriptTag(const OUString& sLocale)
+{
+ return fromLCIDToScriptTag(LanguageTag::convertToLanguageType(sLocale));
+}
+
+OUString ThemeTable::fromLCIDToScriptTag(LanguageType lang)
+{
+ // conversion list from:
+ // http://blogs.msdn.com/b/officeinteroperability/archive/2013/04/22/office-open-xml-themes-schemes-and-fonts.aspx
+ switch (static_cast<sal_uInt16>(lang))
+ {
+ case 0x429 : // lidFarsi
+ case 0x401 : // lidArabic
+ case 0x801 : // lidIraq
+ case 0xc01 : // lidEgyptian
+ case 0x1001 : // lidLibya
+ case 0x1401 : // lidAlgerian
+ case 0x1801 : // lidMorocco
+ case 0x1c01 : // lidTunisia
+ case 0x2001 : // lidOman
+ case 0x2401 : // lidYemen
+ case 0x2801 : // lidSyria
+ case 0x2c01 : // lidJordan
+ case 0x3001 : // lidLebanon
+ case 0x3401 : // lidKuwait
+ case 0x3801 : // lidUAE
+ case 0x3c01 : // lidBahrain
+ case 0x4001 : // lidQatar
+ case 0x420 : // lidUrdu
+ case 0x846 : // lidPunjabiPakistan
+ case 0x859 : // lidSindhiPakistan
+ case 0x45f : // lidTamazight
+ case 0x460 : // lidKashmiri
+ case 0x463 : // lidPashto
+ case 0x48c : // lidDari
+ return "Arab";
+ case 0x42b : // lidArmenian
+ return "Armn";
+ case 0x445 : // lidBengali
+ case 0x845 : // lidBengaliBangladesh
+ case 0x44d : // lidAssamese
+ case 0x458 : // lidManipuri
+ return "Beng";
+ case 0x45d : // lidInuktitut
+ return "Cans";
+ case 0x45c : // lidCherokee
+ return "Cher";
+ case 0x419 : // lidRussian
+ case 0x402 : // lidBulgarian
+ case 0x281a : // lidSerbianCyrillic
+ case 0x422 : // lidUkranian
+ case 0x819 : // lidRussianMoldavia
+ case 0xc1a : // lidSerbianCyrillicSerbMont
+ case 0x1c1a : // lidSerbianBosniaHerzegovinaCyrillic
+ case 0x201a : // lidBosnianBosniaHerzegovinaCyrillic
+ case 0x301a : // lidSerbianMontenegroCyrillic
+ case 0x423 : // lidByelorussian
+ case 0x428 : // lidTajik
+ case 0x82c : // lidAzeriCyrillic
+ case 0x42f : // lidMacedonian
+ case 0x43f : // lidKazakh
+ case 0x440 : // lidKyrgyz
+ case 0x843 : // lidUzbekCyrillic
+ case 0x444 : // lidTatar
+ case 0x450 : // lidMongolian
+ case 0x46d : // lidBashkir
+ case 0x485 : // lidSakha
+ return "Cyrl";
+ case 0x439 : // lidHindi
+ case 0x44e : // lidMarathi
+ case 0x44f : // lidSanskrit
+ case 0x457 : // lidKonkani
+ case 0x459 : // lidSindhi
+ case 0x860 : // lidKashmiriIndia
+ case 0x461 : // lidNepali
+ case 0x861 : // lidNepaliIndia
+ return "Deva";
+ case 0x45e : // lidAmharic
+ case 0x473 : // lidTigrignaEthiopic
+ case 0x873 : // lidTigrignaEritrea
+ return "Ethi";
+ case 0x437 : // lidGeorgian
+ return "Geor";
+ case 0x408 : // lidGreek
+ return "Grek";
+ case 0x447 : // lidGujarati
+ return "Gujr";
+ case 0x446 : // lidPunjabi
+ return "Guru";
+ case 0x412 : // lidKoreanExtWansung
+ return "Hang";
+ case 0x804 : // lidChineseSimp
+ case 0x1004 : // lidSingapore
+ return "Hans";
+ case 0x404 : // lidChineseTrad
+ case 0xc04 : // lidHongkong
+ case 0x1404 : // lidMacau
+ return "Hant";
+ case 0x40d : // lidHebrew
+ case 0x43d : // lidYiddish
+ return "Hebr";
+ case 0x411 : // lidJapanese
+ return "Jpan";
+ case 0x453 : // lidKhmer
+ return "Khmr";
+ case 0x44b : // lidKannada
+ return "Knda";
+ case 0x454 : // lidLao
+ return "Laoo";
+ case 0x409 : // lidAmerican
+ case 0xc09 : // lidAustralian
+ case 0x809 : // lidBritish
+ case 0x1009 : // lidEnglishCanadian
+ case 0x403 : // lidCatalan
+ case 0x406 : // lidDanish
+ case 0x413 : // lidDutch
+ case 0x813 : // lidDutchBelgian
+ case 0x479 : // lidPapiamentu
+ case 0x40b : // lidFinnish
+ case 0x40c : // lidFrench
+ case 0xc0c : // lidFrenchCanadian
+ case 0x407 : // lidGerman
+ case 0x807 : // lidSwissGerman
+ case 0xc07 : // lidAustrianGerman
+ case 0x1007 : // lidGermanLuxembourg
+ case 0x1407 : // lidGermanLiechtenstein
+ case 0x410 : // lidItalian
+ case 0x414 : // lidNorskBokmal
+ case 0x814 : // lidNorskNynorsk
+ case 0x416 : // lidPortBrazil
+ case 0x816 : // lidPortIberian
+ case 0x40a : // lidSpanish
+ case 0x41d : // lidSwedish
+ case 0x405 : // lidCzech
+ case 0x40e : // lidHungarian
+ case 0x415 : // lidPolish
+ case 0x41f : // lidTurkish
+ case 0x42d : // lidBasque
+ case 0x424 : // lidSlovenian
+ case 0x426 : // lidLatvian
+ case 0x427 : // lidLithuanian
+ case 0x418 : // lidRomanian
+ case 0x818 : // lidRomanianMoldavia
+ case 0x241a : // lidSerbianLatin
+ case 0x41a : // lidCroatian, lidCroat
+ case 0x491 : // lidGaelicScots
+ case 0x83c : // lidGaelicIrish
+ case 0x430 : // lidSutu
+ case 0x431 : // lidTsonga
+ case 0x432 : // lidTswana
+ case 0x433 : // lidVenda
+ case 0x434 : // lidXhosa
+ case 0x435 : // lidZulu
+ case 0x436 : // lidAfrikaans
+ case 0x425 : // lidEstonian
+ case 0x456 : // lidGalician
+ case 0x41b : // lidSlovak
+ case 0x1409 : // lidEnglishNewZealand
+ case 0x1809 : // lidEnglishIreland
+ case 0x1c09 : // lidEnglishSouthAfrica
+ case 0x2009 : // lidEnglishJamaica
+ case 0x2409 : // lidEnglishCaribbean
+ case 0x2809 : // lidEnglishBelize
+ case 0x2c09 : // lidEnglishTrinidad
+ case 0x3009 : // lidEnglishZimbabwe
+ case 0x3409 : // lidEnglishPhilippines
+ case 0x3809 : // lidEnglishIndonesia
+ case 0x3c09 : // lidEnglishHongKong
+ case 0x4009 : // lidEnglishIndia
+ case 0x4409 : // lidEnglishMalaysia
+ case 0x4809 : // lidEnglishSingapore
+ case 0x80a : // lidSpanishMexican, lidMexican
+ case 0xc0a : // lidSpanishModern
+ case 0x100a : // lidGuatemala
+ case 0x140a : // lidCostaRica
+ case 0x180a : // lidPanama
+ case 0x1c0a : // lidDominicanRepublic
+ case 0x200a : // lidSpanishSA, lidVenezuela
+ case 0x240a : // lidColombia
+ case 0x280a : // lidPeru
+ case 0x2c0a : // lidArgentina
+ case 0x300a : // lidEcuador
+ case 0x340a : // lidChile
+ case 0x380a : // lidUruguay
+ case 0x3c0a : // lidParguay
+ case 0x400a : // lidBolivia
+ case 0x440a : // lidElSalvador
+ case 0x480a : // lidHonduras
+ case 0x4c0a : // lidNicaragua
+ case 0x500a : // lidPuertoRico
+ case 0x540a : // lidSpanishUS
+ case 0x80c : // lidFrenchBelgian
+ case 0x100c : // lidFrenchSwiss
+ case 0x140c : // lidFrenchLuxembourg
+ case 0x180c : // lidFrenchMonaco
+ case 0x1c0c : // lidFrenchWestIndies
+ case 0x200c : // lidFrenchReunion
+ case 0x240c : // lidFrenchCongoDRC, lidFrenchZaire
+ case 0x280c : // lidFrenchSenegal
+ case 0x2c0c : // lidFrenchCameroon
+ case 0x300c : // lidFrenchCotedIvoire
+ case 0x340c : // lidFrenchMali
+ case 0x3c0c : // lidFrenchHaiti
+ case 0x380c : // lidFrenchMorocco
+ case 0x40f : // lidIcelandic
+ case 0x810 : // lidItalianSwiss
+ case 0x417 : // lidRhaetoRomanic, lidRomanic
+ case 0x81a : // lidSerbianLatinSerbMont, lidCroatSerbo
+ case 0x101a : // lidBosniaHerzegovina
+ case 0x141a : // lidBosnianBosniaHerzegovinaLatin
+ case 0x181a : // lidSerbianBosniaHerzegovinaLatin
+ case 0x2c1a : // lidSerbianMontenegroLatin
+ case 0x41c : // lidAlbanian
+ case 0x81d : // lidSwedishFinland
+ case 0x421 : // lidBahasa, lidIndonesian
+ case 0x42c : // lidAzeriLatin
+ case 0x42e : // lidSorbian
+ case 0x82e : // lidLowerSorbian
+ case 0x438 : // lidFaeroese
+ case 0x43a : // lidMaltese
+ case 0x43b : // lidSamiLappish
+ case 0x83b : // lidNorthSamiSwe
+ case 0xc3b : // lidNorthernSamiFi
+ case 0x103b : // lidLuleSamiNor
+ case 0x143b : // lidLuleSamiSwe
+ case 0x183b : // lidSouthSamiNor
+ case 0x1c3b : // lidSouthSamiSwe
+ case 0x203b : // lidSkoltSami
+ case 0x243b : // lidInariSami
+ case 0x43e : // lidMalaysian
+ case 0x83e : // lidMalayBrunei
+ case 0x441 : // lidSwahili
+ case 0x442 : // lidTurkmen
+ case 0x443 : // lidUzbekLatin
+ case 0x452 : // lidWelsh
+ case 0x85d : // lidInuktitutLatin
+ case 0x85f : // lidTamazightLatin
+ case 0x462 : // lidFrisian
+ case 0x464 : // lidFilipino
+ case 0x466 : // lidEdo
+ case 0x467 : // lidFulfulde
+ case 0x468 : // lidHausa
+ case 0x469 : // lidIbibio
+ case 0x46a : // lidYoruba
+ case 0x46b : // lidQuechuaBol
+ case 0x86b : // lidQuechuaEcu
+ case 0xc6b : // lidQuechuaPe
+ case 0x46c : // lidSesothoSaLeboa
+ case 0x46e : // lidLuxembourgish
+ case 0x46f : // lidGreenlandic
+ case 0x470 : // lidIgbo
+ case 0x471 : // lidKanuri
+ case 0x472 : // lidOromo
+ case 0x474 : // lidGuarani
+ case 0x475 : // lidHawaiian
+ case 0x476 : // lidLatin
+ case 0x477 : // lidSomali
+ case 0x47a : // lidMapudungun
+ case 0x47c : // lidMohawk
+ case 0x47e : // lidBreton
+ case 0x481 : // lidMaori
+ case 0x482 : // lidOccitan
+ case 0x483 : // lidCorsican
+ case 0x484 : // lidAlsatian
+ case 0x486 : // lidKiche
+ case 0x487 : // lidKinyarwanda
+ case 0x488 : // lidWolof
+ return "Latn";
+ case 0x44c : // lidMalayalam
+ return "Mlym";
+ case 0x850 : // lidMongolianMongo
+ return "Mong";
+ case 0x455 : // lidBurmese
+ return "Mymr";
+ case 0x448 : // lidOriya
+ return "Orya";
+ case 0x45b : // lidSinhalese
+ return "Sinh";
+ case 0x45a : // lidSyriac
+ return "Syrc";
+ case 0x449 : // lidTamil
+ return "Taml";
+ case 0x44a : // lidTelugu
+ return "Telu";
+ case 0x465 : // lidMaldivian
+ return "Thaa";
+ case 0x41e : // lidThai
+ return "Thai";
+ case 0x451 : // lidTibetan
+ case 0x851 : // lidBhutanese
+ return "Tibt";
+ case 0x480 : // lidUighur
+ return "Uigh";
+ case 0x42a : // lidVietnamese
+ return "Viet";
+ case 0x478 : // lidYi
+ return "Yiii";
+ default:
+ return OUString();
+ }
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/ThemeTable.hxx b/writerfilter/source/dmapper/ThemeTable.hxx
new file mode 100644
index 000000000..164f083c9
--- /dev/null
+++ b/writerfilter/source/dmapper/ThemeTable.hxx
@@ -0,0 +1,58 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <i18nlangtag/lang.h>
+#include <memory>
+
+namespace writerfilter::dmapper
+{
+struct ThemeTable_Impl;
+
+class ThemeTable : public LoggedProperties, public LoggedTable
+{
+ std::unique_ptr<ThemeTable_Impl> m_pImpl;
+
+public:
+ ThemeTable();
+ virtual ~ThemeTable() override;
+
+ OUString getFontNameForTheme(const Id id) const;
+ static OUString getStringForTheme(const Id id);
+ void setThemeFontLangProperties(const css::uno::Sequence<css::beans::PropertyValue>& aPropSeq);
+
+private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+ // Table
+ virtual void lcl_entry(writerfilter::Reference<Properties>::Pointer_t ref) override;
+
+ // Helper methods
+ static OUString fromLocaleToScriptTag(const OUString& sLocale);
+ static OUString fromLCIDToScriptTag(LanguageType lang);
+};
+typedef tools::SvRef<ThemeTable> ThemeTablePtr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TrackChangesHandler.cxx b/writerfilter/source/dmapper/TrackChangesHandler.cxx
new file mode 100644
index 000000000..212f88261
--- /dev/null
+++ b/writerfilter/source/dmapper/TrackChangesHandler.cxx
@@ -0,0 +1,95 @@
+/* -*- 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 "TrackChangesHandler.hxx"
+#include "PropertyMap.hxx"
+#include "ConversionHelper.hxx"
+#include <ooxml/resourceids.hxx>
+#include <oox/token/tokens.hxx>
+#include <osl/diagnose.h>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+using namespace oox;
+
+
+TrackChangesHandler::TrackChangesHandler( sal_Int32 nToken ) :
+ LoggedProperties("TrackChangesHandler"),
+ m_pRedlineParams(new RedlineParams)
+{
+ m_pRedlineParams->m_nToken = nToken;
+}
+
+
+TrackChangesHandler::~TrackChangesHandler()
+{
+}
+
+
+void TrackChangesHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ OUString sStringValue = rVal.getString();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_TrackChange_author:
+ {
+ m_pRedlineParams->m_sAuthor = sStringValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_TrackChange_date:
+ {
+ m_pRedlineParams->m_sDate = sStringValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_Markup_id:
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+uno::Sequence<beans::PropertyValue> TrackChangesHandler::getRedlineProperties() const
+{
+ uno::Sequence< beans::PropertyValue > aRedlineProperties(3);
+ beans::PropertyValue* pRedlineProperties = aRedlineProperties.getArray();
+
+ OUString sType;
+ switch ( m_pRedlineParams->m_nToken & 0xffff )
+ {
+ case XML_tableRowInsert:
+ sType = getPropertyName( PROP_TABLE_ROW_INSERT );
+ break;
+ case XML_tableRowDelete:
+ sType = getPropertyName( PROP_TABLE_ROW_DELETE );
+ break;
+ case XML_tableCellInsert:
+ sType = getPropertyName( PROP_TABLE_CELL_INSERT );
+ break;
+ case XML_tableCellDelete:
+ sType = getPropertyName( PROP_TABLE_CELL_DELETE );
+ break;
+ }
+
+ pRedlineProperties[0].Name = getPropertyName( PROP_REDLINE_TYPE );
+ pRedlineProperties[0].Value <<= sType;
+ pRedlineProperties[1].Name = getPropertyName( PROP_REDLINE_AUTHOR );
+ pRedlineProperties[1].Value <<= m_pRedlineParams->m_sAuthor;
+ pRedlineProperties[2].Name = getPropertyName( PROP_REDLINE_DATE_TIME );
+ pRedlineProperties[2].Value <<= ConversionHelper::ConvertDateStringToDateTime( m_pRedlineParams->m_sDate );
+ //pRedlineProperties[3].Name = getPropertyName( PROP_REDLINE_REVERT_PROPERTIES );
+ //pRedlineProperties[3].Value <<= pRedline->m_aRevertProperties;
+
+ return aRedlineProperties;
+}
+
+void TrackChangesHandler::lcl_sprm(Sprm &) {}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/TrackChangesHandler.hxx b/writerfilter/source/dmapper/TrackChangesHandler.hxx
new file mode 100644
index 000000000..b3417ccce
--- /dev/null
+++ b/writerfilter/source/dmapper/TrackChangesHandler.hxx
@@ -0,0 +1,40 @@
+/* -*- 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/.
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <dmapper/PropertyMap.hxx>
+
+namespace writerfilter::dmapper
+{
+/** Handler for sprms that contain 'track changes' attributes
+ - Author
+ - Date
+ - ID
+ (This class is based on work done in 'MeasureHandler')
+ */
+class TrackChangesHandler : public LoggedProperties
+{
+ RedlineParamsPtr m_pRedlineParams;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+public:
+ explicit TrackChangesHandler(sal_Int32 nToken);
+ virtual ~TrackChangesHandler() override;
+
+ /// Compute the UNO properties for the track changes object based on the received tokens.
+ css::uno::Sequence<css::beans::PropertyValue> getRedlineProperties() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/WrapPolygonHandler.cxx b/writerfilter/source/dmapper/WrapPolygonHandler.cxx
new file mode 100644
index 000000000..319fae5c4
--- /dev/null
+++ b/writerfilter/source/dmapper/WrapPolygonHandler.cxx
@@ -0,0 +1,214 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <comphelper/sequence.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include "WrapPolygonHandler.hxx"
+#include "util.hxx"
+
+#include <sal/log.hxx>
+
+namespace writerfilter {
+
+using namespace com::sun::star;
+
+namespace dmapper {
+
+WrapPolygon::WrapPolygon()
+{
+}
+
+WrapPolygon::~WrapPolygon()
+{
+}
+
+void WrapPolygon::addPoint(const awt::Point & rPoint)
+{
+ mPoints.push_back(rPoint);
+}
+
+WrapPolygon::Points_t::const_iterator WrapPolygon::begin() const
+{
+ return mPoints.begin();
+}
+
+WrapPolygon::Points_t::const_iterator WrapPolygon::end() const
+{
+ return mPoints.end();
+}
+
+WrapPolygon::Pointer_t WrapPolygon::move(const awt::Point & rPoint) const
+{
+ WrapPolygon::Pointer_t pResult(new WrapPolygon);
+
+ Points_t::const_iterator aIt = begin();
+ Points_t::const_iterator aItEnd = end();
+
+ while (aIt != aItEnd)
+ {
+ awt::Point aPoint(aIt->X + rPoint.X, aIt->Y + rPoint.Y);
+ pResult->addPoint(aPoint);
+ ++aIt;
+ }
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::scale(const Fraction & rFractionX, const Fraction & rFractionY) const
+{
+ WrapPolygon::Pointer_t pResult(new WrapPolygon);
+
+ Points_t::const_iterator aIt = begin();
+ Points_t::const_iterator aItEnd = end();
+
+ while (aIt != aItEnd)
+ {
+ awt::Point aPoint((Fraction(tools::Long(aIt->X)) * rFractionX).operator long(), (Fraction(tools::Long(aIt->Y)) * rFractionY).operator long());
+ pResult->addPoint(aPoint);
+ ++aIt;
+ }
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::correctWordWrapPolygon(const awt::Size & rSrcSize) const
+{
+ WrapPolygon::Pointer_t pResult;
+
+ const tools::Long nWrap100Percent = 21600;
+
+ Fraction aMove(nWrap100Percent, rSrcSize.Width);
+ aMove = aMove * Fraction(convertTwipToMm100(15), 1);
+ awt::Point aMovePoint(aMove.operator long(), 0);
+ pResult = move(aMovePoint);
+
+ Fraction aScaleX = nWrap100Percent / (nWrap100Percent + aMove);
+ Fraction aScaleY = nWrap100Percent / (nWrap100Percent - aMove);
+ pResult = pResult->scale(aScaleX, aScaleY);
+
+ Fraction aScaleSrcX(rSrcSize.Width, nWrap100Percent);
+ Fraction aScaleSrcY(rSrcSize.Height, nWrap100Percent);
+ pResult = pResult->scale(aScaleSrcX, aScaleSrcY);
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::correctWordWrapPolygonPixel(const awt::Size & rSrcSize) const
+{
+ WrapPolygon::Pointer_t pResult;
+
+ /*
+ * https://msdn.microsoft.com/en-us/library/ee342530.aspx
+ *
+ * Image wrapping polygons in Microsoft Word use a fixed coordinate space
+ * that is 21600 units x 21600 units. Coordinate (0,0) is the upper left
+ * corner of the image and coordinate (21600,21600) is the lower right
+ * corner of the image. Microsoft Word scales the size of the wrapping
+ * polygon units to fit the size of the image. The 21600 value is a legacy
+ * artifact from the drawing layer of early versions of Microsoft Office.
+ */
+ const tools::Long nWrap100Percent = 21600;
+
+ Fraction aScaleX(rSrcSize.Width, nWrap100Percent);
+ Fraction aScaleY(rSrcSize.Height, nWrap100Percent);
+ pResult = scale(aScaleX, aScaleY);
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::correctCrop(const awt::Size& rGraphicSize,
+ const text::GraphicCrop& rGraphicCrop) const
+{
+ WrapPolygon::Pointer_t pResult;
+
+ Fraction aScaleX(rGraphicSize.Width - rGraphicCrop.Left - rGraphicCrop.Right,
+ rGraphicSize.Width);
+ Fraction aScaleY(rGraphicSize.Height - rGraphicCrop.Top - rGraphicCrop.Bottom,
+ rGraphicSize.Height);
+ pResult = scale(aScaleX, aScaleY);
+
+ awt::Point aMove(rGraphicCrop.Left, rGraphicCrop.Top);
+ pResult = pResult->move(aMove);
+
+ return pResult;
+}
+
+drawing::PointSequenceSequence WrapPolygon::getPointSequenceSequence() const
+{
+ return { comphelper::containerToSequence(mPoints) };
+}
+
+WrapPolygonHandler::WrapPolygonHandler()
+ : LoggedProperties("WrapPolygonHandler")
+ , mpPolygon(new WrapPolygon)
+ , mnX(0)
+ , mnY(0)
+{
+}
+
+WrapPolygonHandler::~WrapPolygonHandler()
+{
+}
+
+void WrapPolygonHandler::lcl_attribute(Id Name, Value & val)
+{
+ sal_Int32 nIntValue = val.getInt();
+
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_Point2D_x:
+ mnX = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Point2D_y:
+ mnY = nIntValue;
+ break;
+ default:
+ SAL_WARN("writerfilter", "WrapPolygonHandler::lcl_attribute: unhandled token: " << Name);
+ break;
+ }
+}
+
+void WrapPolygonHandler::lcl_sprm(Sprm & _sprm)
+{
+ switch (_sprm.getId())
+ {
+ case NS_ooxml::LN_CT_WrapPath_lineTo:
+ case NS_ooxml::LN_CT_WrapPath_start:
+ {
+ resolveSprmProps(*this, _sprm);
+
+ awt::Point aPoint(mnX, mnY);
+ mpPolygon->addPoint(aPoint);
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "WrapPolygonHandler::lcl_sprm: unhandled token: " << _sprm.getId());
+ break;
+ }
+}
+
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/WrapPolygonHandler.hxx b/writerfilter/source/dmapper/WrapPolygonHandler.hxx
new file mode 100644
index 000000000..8d3e1a3d8
--- /dev/null
+++ b/writerfilter/source/dmapper/WrapPolygonHandler.hxx
@@ -0,0 +1,82 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include "LoggedResources.hxx"
+#include <tools/fract.hxx>
+#include <vector>
+
+namespace com::sun::star::text
+{
+struct GraphicCrop;
+}
+
+namespace writerfilter::dmapper
+{
+/// Handles <wp:wrapPolygon> from DOCX and the pWrapPolygonVertices shape property from RTF.
+class WrapPolygon final : public virtual SvRefBase
+{
+public:
+ typedef std::vector<css::awt::Point> Points_t;
+ typedef ::tools::SvRef<WrapPolygon> Pointer_t;
+
+private:
+ Points_t mPoints;
+
+public:
+ WrapPolygon();
+ ~WrapPolygon() override;
+
+ void addPoint(const css::awt::Point& rPoint);
+
+ Points_t::const_iterator begin() const;
+ Points_t::const_iterator end() const;
+
+ WrapPolygon::Pointer_t move(const css::awt::Point& rMove) const;
+ WrapPolygon::Pointer_t scale(const Fraction& rFractionX, const Fraction& rFractionY) const;
+ WrapPolygon::Pointer_t correctWordWrapPolygon(const css::awt::Size& rSrcSize) const;
+ WrapPolygon::Pointer_t correctWordWrapPolygonPixel(const css::awt::Size& rSrcSize) const;
+ WrapPolygon::Pointer_t correctCrop(const css::awt::Size& rGraphicSize,
+ const css::text::GraphicCrop& rGraphicCrop) const;
+ css::drawing::PointSequenceSequence getPointSequenceSequence() const;
+};
+
+class WrapPolygonHandler : public LoggedProperties
+{
+public:
+ WrapPolygonHandler();
+ virtual ~WrapPolygonHandler() override;
+
+ const WrapPolygon::Pointer_t& getPolygon() const { return mpPolygon; }
+
+private:
+ WrapPolygon::Pointer_t mpPolygon;
+
+ sal_Int32 mnX;
+ sal_Int32 mnY;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/WriteProtection.cxx b/writerfilter/source/dmapper/WriteProtection.cxx
new file mode 100644
index 000000000..c300ab09e
--- /dev/null
+++ b/writerfilter/source/dmapper/WriteProtection.cxx
@@ -0,0 +1,140 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "WriteProtection.hxx"
+#include "TagLogger.hxx"
+
+#include <comphelper/propertyvalue.hxx>
+#include <ooxml/resourceids.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+WriteProtection::WriteProtection()
+ : LoggedProperties("WriteProtection")
+ , m_nCryptProviderType(NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+ , m_CryptSpinCount(0)
+ , m_bRecommended(false)
+{
+}
+
+WriteProtection::~WriteProtection() {}
+
+void WriteProtection::lcl_attribute(Id nName, Value& val)
+{
+ int nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ switch (nName)
+ {
+ case NS_ooxml::LN_AG_Password_cryptProviderType: // 92025
+ m_nCryptProviderType = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmClass: // 92026
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgClass_hash) // 92023
+ m_sCryptAlgorithmClass = "hash";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmType: // 92027
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgType_typeAny) // 92024
+ m_sCryptAlgorithmType = "typeAny";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmSid: // 92028
+ {
+ sal_Int32 nCryptAlgorithmSid = sStringValue.toInt32();
+ switch (nCryptAlgorithmSid)
+ {
+ case 1:
+ m_sAlgorithmName = "MD2";
+ break;
+ case 2:
+ m_sAlgorithmName = "MD4";
+ break;
+ case 3:
+ m_sAlgorithmName = "MD5";
+ break;
+ case 4:
+ m_sAlgorithmName = "SHA-1";
+ break;
+ case 5:
+ m_sAlgorithmName = "MAC";
+ break;
+ case 6:
+ m_sAlgorithmName = "RIPEMD";
+ break;
+ case 7:
+ m_sAlgorithmName = "RIPEMD-160";
+ break;
+ case 9:
+ m_sAlgorithmName = "HMAC";
+ break;
+ case 12:
+ m_sAlgorithmName = "SHA-256";
+ break;
+ case 13:
+ m_sAlgorithmName = "SHA-384";
+ break;
+ case 14:
+ m_sAlgorithmName = "SHA-512";
+ break;
+ default:; // 8, 10, 11, any other value: Undefined.
+ }
+ }
+ break;
+ case NS_ooxml::LN_AG_Password_cryptSpinCount: // 92029
+ m_CryptSpinCount = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_hash: // 92035
+ m_sHash = sStringValue;
+ break;
+ case NS_ooxml::LN_AG_Password_salt: // 92036
+ m_sSalt = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_WriteProtection_recommended:
+ m_bRecommended = nIntValue;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void WriteProtection::lcl_sprm(Sprm& /*rSprm*/) {}
+
+uno::Sequence<beans::PropertyValue> WriteProtection::toSequence() const
+{
+ uno::Sequence<beans::PropertyValue> aResult;
+ if (!m_sAlgorithmName.isEmpty() && !m_sSalt.isEmpty() && !m_sHash.isEmpty()
+ && m_sCryptAlgorithmClass == "hash" && m_sCryptAlgorithmType == "typeAny")
+ {
+ aResult = { comphelper::makePropertyValue("algorithm-name", m_sAlgorithmName),
+ comphelper::makePropertyValue("salt", m_sSalt),
+ comphelper::makePropertyValue("iteration-count", m_CryptSpinCount),
+ comphelper::makePropertyValue("hash", m_sHash) };
+ }
+
+ return aResult;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/WriteProtection.hxx b/writerfilter/source/dmapper/WriteProtection.hxx
new file mode 100644
index 000000000..21b420b4b
--- /dev/null
+++ b/writerfilter/source/dmapper/WriteProtection.hxx
@@ -0,0 +1,58 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+class WriteProtection : public LoggedProperties
+{
+private:
+ /** Provider type
+ *
+ * Possible values:
+ * "rsaAES" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES
+ * "rsaFull" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull
+ */
+ sal_Int32 m_nCryptProviderType;
+ OUString m_sCryptAlgorithmClass;
+ OUString m_sCryptAlgorithmType;
+ sal_Int32 m_CryptSpinCount;
+ OUString m_sAlgorithmName;
+ OUString m_sHash;
+ OUString m_sSalt;
+ bool m_bRecommended;
+
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+public:
+ WriteProtection();
+ virtual ~WriteProtection() override;
+
+ css::uno::Sequence<css::beans::PropertyValue> toSequence() const;
+
+ bool getRecommended() const { return m_bRecommended; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/domainmapperfactory.cxx b/writerfilter/source/dmapper/domainmapperfactory.cxx
new file mode 100644
index 000000000..eab017c57
--- /dev/null
+++ b/writerfilter/source/dmapper/domainmapperfactory.cxx
@@ -0,0 +1,39 @@
+/* -*- 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 "DomainMapper.hxx"
+#include "TagLogger.hxx"
+#include <unotools/mediadescriptor.hxx>
+
+namespace writerfilter::dmapper
+{
+Stream::Pointer_t
+DomainMapperFactory::createMapper(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xModel,
+ bool bRepairStorage, SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const& rMediaDesc)
+{
+#ifdef DBG_UTIL
+ OUString sURL
+ = rMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_URL, OUString());
+ ::std::string sURLc = OUStringToOString(sURL, RTL_TEXTENCODING_ASCII_US).getStr();
+
+ if (getenv("SW_DEBUG_WRITERFILTER"))
+ TagLogger::getInstance().setFileName(sURLc);
+ TagLogger::getInstance().startDocument();
+#endif
+
+ return { new DomainMapper(xContext, xInputStream, xModel, bRepairStorage, eDocumentType,
+ rMediaDesc) };
+}
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/util.cxx b/writerfilter/source/dmapper/util.cxx
new file mode 100644
index 000000000..d5b23a3d4
--- /dev/null
+++ b/writerfilter/source/dmapper/util.cxx
@@ -0,0 +1,70 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string>
+#include "util.hxx"
+
+namespace writerfilter::dmapper
+{
+using namespace com::sun::star;
+
+std::string XTextRangeToString(uno::Reference<text::XTextRange> const& textRange)
+{
+ std::string result;
+
+#ifdef DBG_UTIL
+ if (textRange)
+ {
+ OUString aOUStr;
+
+ try
+ {
+ aOUStr = textRange->getString();
+ }
+ catch (const uno::Exception& rException)
+ {
+ result += "(exception: ";
+ result += rException.Message.toUtf8().getStr();
+ result += ")";
+ }
+
+ OString aOStr(aOUStr.getStr(), aOUStr.getLength(), RTL_TEXTENCODING_ASCII_US);
+
+ result = aOStr.getStr();
+ }
+ else
+ {
+ result = "(nil)";
+ }
+#else
+ (void)textRange;
+#endif
+
+ return result;
+}
+
+void resolveSprmProps(Properties& rHandler, Sprm& rSprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(rHandler);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/util.hxx b/writerfilter/source/dmapper/util.hxx
new file mode 100644
index 000000000..9d172331a
--- /dev/null
+++ b/writerfilter/source/dmapper/util.hxx
@@ -0,0 +1,32 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/text/XTextRange.hpp>
+#include <string>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::dmapper
+{
+std::string XTextRangeToString(css::uno::Reference<css::text::XTextRange> const& textRange);
+void resolveSprmProps(Properties& rHandler, Sprm& rSprm);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/filter/RtfFilter.cxx b/writerfilter/source/filter/RtfFilter.cxx
new file mode 100644
index 000000000..ef680155c
--- /dev/null
+++ b/writerfilter/source/filter/RtfFilter.cxx
@@ -0,0 +1,220 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/file.hxx>
+#include <tools/diagnose_ex.h>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/scopeguard.hxx>
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include <rtftok/RTFDocument.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Invokes the RTF tokenizer + dmapper or RtfExportFilter in sw via UNO.
+class RtfFilter
+ : public cppu::WeakImplHelper<document::XFilter, document::XImporter, document::XExporter,
+ lang::XInitialization, lang::XServiceInfo>
+{
+ uno::Reference<uno::XComponentContext> m_xContext;
+ uno::Reference<lang::XComponent> m_xSrcDoc, m_xDstDoc;
+
+public:
+ explicit RtfFilter(uno::Reference<uno::XComponentContext> xContext);
+
+ // XFilter
+ sal_Bool SAL_CALL filter(const uno::Sequence<beans::PropertyValue>& rDescriptor) override;
+ void SAL_CALL cancel() override;
+
+ // XImporter
+ void SAL_CALL setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XExporter
+ void SAL_CALL setSourceDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XInitialization
+ void SAL_CALL initialize(const uno::Sequence<uno::Any>& rArguments) override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+}
+
+RtfFilter::RtfFilter(uno::Reference<uno::XComponentContext> xContext)
+ : m_xContext(std::move(xContext))
+{
+}
+
+sal_Bool RtfFilter::filter(const uno::Sequence<beans::PropertyValue>& rDescriptor)
+{
+ if (m_xSrcDoc.is())
+ {
+ uno::Reference<lang::XMultiServiceFactory> xMSF(m_xContext->getServiceManager(),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<uno::XInterface> xIfc(
+ xMSF->createInstance("com.sun.star.comp.Writer.RtfExport"), uno::UNO_SET_THROW);
+ uno::Reference<document::XExporter> xExporter(xIfc, uno::UNO_QUERY_THROW);
+ uno::Reference<document::XFilter> xFilter(xIfc, uno::UNO_QUERY_THROW);
+ xExporter->setSourceDocument(m_xSrcDoc);
+ return xFilter->filter(rDescriptor);
+ }
+
+ bool bResult(false);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+
+ uno::Reference<beans::XPropertySet> xDocProps;
+ if (m_xDstDoc.is()) // not in cppunittest?
+ {
+ xDocProps.set(m_xDstDoc, uno::UNO_QUERY);
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(true));
+ }
+ comphelper::ScopeGuard g([xDocProps] {
+ if (xDocProps.is()) // not in cppunittest?
+ {
+ // note: pStream.clear calls RemoveLastParagraph()
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(false));
+ }
+ });
+
+ try
+ {
+ utl::MediaDescriptor aMediaDesc(rDescriptor);
+ bool bRepairStorage = aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
+ bool bIsNewDoc = !aMediaDesc.getUnpackedValueOrDefault("InsertMode", false);
+ uno::Reference<io::XInputStream> xInputStream;
+
+ aMediaDesc.addInputStream();
+ aMediaDesc[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
+
+ // If this is set, write to this file, instead of the real document during paste.
+ char* pEnv = getenv("SW_DEBUG_RTF_PASTE_TO");
+ OUString aOutStr;
+ if (!bIsNewDoc && pEnv
+ && osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pEnv), aOutStr)
+ == osl::FileBase::E_None)
+ {
+ std::unique_ptr<SvStream> pOut(
+ utl::UcbStreamHelper::CreateStream(aOutStr, StreamMode::WRITE));
+ std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xInputStream));
+ pOut->WriteStream(*pIn);
+ return true;
+ }
+
+ // If this is set, read from this file, instead of the real clipboard during paste.
+ pEnv = getenv("SW_DEBUG_RTF_PASTE_FROM");
+ if (!bIsNewDoc && pEnv)
+ {
+ OUString aInStr;
+ osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pEnv), aInStr);
+ std::unique_ptr<SvStream> pStream
+ = utl::UcbStreamHelper::CreateStream(aInStr, StreamMode::READ);
+ uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(std::move(pStream)));
+ xInputStream.set(xStream, uno::UNO_QUERY);
+ }
+
+ uno::Reference<frame::XFrame> xFrame = aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_FRAME, uno::Reference<frame::XFrame>());
+
+ xStatusIndicator = aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_STATUSINDICATOR, uno::Reference<task::XStatusIndicator>());
+
+ writerfilter::Stream::Pointer_t pStream(
+ writerfilter::dmapper::DomainMapperFactory::createMapper(
+ m_xContext, xInputStream, m_xDstDoc, bRepairStorage,
+ writerfilter::dmapper::SourceDocumentType::RTF, aMediaDesc));
+ writerfilter::rtftok::RTFDocument::Pointer_t pDocument(
+ writerfilter::rtftok::RTFDocumentFactory::createDocument(
+ m_xContext, xInputStream, m_xDstDoc, xFrame, xStatusIndicator, aMediaDesc));
+ pDocument->resolve(*pStream);
+ bResult = true;
+ }
+ catch (const io::WrongFormatException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ // cannot throw WrongFormatException directly :(
+ throw lang::WrappedTargetRuntimeException("", static_cast<OWeakObject*>(this), anyEx);
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter", "Exception caught");
+ }
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->end();
+ return bResult;
+}
+
+void RtfFilter::cancel() {}
+
+void RtfFilter::setSourceDocument(const uno::Reference<lang::XComponent>& xDoc)
+{
+ m_xSrcDoc = xDoc;
+}
+
+void RtfFilter::setTargetDocument(const uno::Reference<lang::XComponent>& xDoc)
+{
+ m_xDstDoc = xDoc;
+}
+
+void RtfFilter::initialize(const uno::Sequence<uno::Any>& /*aArguments*/)
+{
+ // The DOCX exporter here extracts 'type' of the filter, ie 'Word' or
+ // 'Word Template' but we don't need it for RTF.
+}
+
+OUString RtfFilter::getImplementationName() { return "com.sun.star.comp.Writer.RtfFilter"; }
+
+sal_Bool RtfFilter::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> RtfFilter::getSupportedServiceNames()
+{
+ uno::Sequence<OUString> aRet = { OUString("com.sun.star.document.ImportFilter"),
+ OUString("com.sun.star.document.ExportFilter") };
+ return aRet;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_comp_Writer_RtfFilter_get_implementation(uno::XComponentContext* pComponent,
+ uno::Sequence<uno::Any> const& /*rSequence*/)
+{
+ return cppu::acquire(new RtfFilter(pComponent));
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/filter/WriterFilter.cxx b/writerfilter/source/filter/WriterFilter.cxx
new file mode 100644
index 000000000..f65df20f0
--- /dev/null
+++ b/writerfilter/source/filter/WriterFilter.cxx
@@ -0,0 +1,368 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef DBG_UTIL
+#include <iostream>
+#endif
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <dmapper/DomainMapperFactory.hxx>
+#include <oox/core/filterdetect.hxx>
+#include <oox/core/xmlfilterbase.hxx>
+#include <oox/helper/graphichelper.hxx>
+#include <oox/ole/olestorage.hxx>
+#include <oox/ole/vbaproject.hxx>
+#include <ooxml/OOXMLDocument.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <rtl/ref.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <comphelper/scopeguard.hxx>
+
+using namespace ::com::sun::star;
+
+static OUString lcl_GetExceptionMessageRec(xml::sax::SAXException const& e);
+
+static OUString lcl_GetExceptionMessage(xml::sax::SAXException const& e)
+{
+ OUString const thisMessage("SAXParseException: \"" + e.Message + "\"");
+ OUString const restMessage(lcl_GetExceptionMessageRec(e));
+ return restMessage + "\n" + thisMessage;
+}
+static OUString lcl_GetExceptionMessage(xml::sax::SAXParseException const& e)
+{
+ OUString const thisMessage("SAXParseException: '" + e.Message + "', Stream '" + e.SystemId
+ + "', Line " + OUString::number(e.LineNumber) + ", Column "
+ + OUString::number(e.ColumnNumber));
+ OUString const restMessage(lcl_GetExceptionMessageRec(e));
+ return restMessage + "\n" + thisMessage;
+}
+
+static OUString lcl_GetExceptionMessageRec(xml::sax::SAXException const& e)
+{
+ xml::sax::SAXParseException saxpe;
+ if (e.WrappedException >>= saxpe)
+ {
+ return lcl_GetExceptionMessage(saxpe);
+ }
+ xml::sax::SAXException saxe;
+ if (e.WrappedException >>= saxe)
+ {
+ return lcl_GetExceptionMessage(saxe);
+ }
+ uno::Exception ue;
+ if (e.WrappedException >>= ue)
+ {
+ return ue.Message;
+ }
+ return {};
+}
+
+namespace
+{
+/// Common DOCX filter, calls DocxExportFilter via UNO or does the DOCX import.
+class WriterFilter
+ : public cppu::WeakImplHelper<document::XFilter, document::XImporter, document::XExporter,
+ lang::XInitialization, lang::XServiceInfo>
+{
+ uno::Reference<uno::XComponentContext> m_xContext;
+ uno::Reference<lang::XComponent> m_xSrcDoc, m_xDstDoc;
+ uno::Sequence<uno::Any> m_xInitializationArguments;
+
+public:
+ explicit WriterFilter(uno::Reference<uno::XComponentContext> xContext)
+ : m_xContext(std::move(xContext))
+ {
+ }
+
+ // XFilter
+ sal_Bool SAL_CALL filter(const uno::Sequence<beans::PropertyValue>& rDescriptor) override;
+ void SAL_CALL cancel() override;
+
+ // XImporter
+ void SAL_CALL setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XExporter
+ void SAL_CALL setSourceDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XInitialization
+ void SAL_CALL initialize(const uno::Sequence<uno::Any>& rArguments) override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+}
+
+sal_Bool WriterFilter::filter(const uno::Sequence<beans::PropertyValue>& rDescriptor)
+{
+ if (m_xSrcDoc.is())
+ {
+ uno::Reference<lang::XMultiServiceFactory> xMSF(m_xContext->getServiceManager(),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<uno::XInterface> xIfc;
+ try
+ {
+ xIfc.set(xMSF->createInstance("com.sun.star.comp.Writer.DocxExport"),
+ uno::UNO_SET_THROW);
+ }
+ catch (uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (uno::Exception& e)
+ {
+ uno::Any a(cppu::getCaughtException());
+ throw lang::WrappedTargetRuntimeException("wrapped " + a.getValueTypeName() + ": "
+ + e.Message,
+ uno::Reference<uno::XInterface>(), a);
+ }
+
+ uno::Reference<lang::XInitialization> xInit(xIfc, uno::UNO_QUERY_THROW);
+ xInit->initialize(m_xInitializationArguments);
+
+ uno::Reference<document::XExporter> xExprtr(xIfc, uno::UNO_QUERY_THROW);
+ uno::Reference<document::XFilter> xFltr(xIfc, uno::UNO_QUERY_THROW);
+ xExprtr->setSourceDocument(m_xSrcDoc);
+ return xFltr->filter(rDescriptor);
+ }
+ if (m_xDstDoc.is())
+ {
+ uno::Reference<beans::XPropertySet> const xDocProps(m_xDstDoc, uno::UNO_QUERY);
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(true));
+ comphelper::ScopeGuard g([xDocProps] {
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(false));
+ });
+ utl::MediaDescriptor aMediaDesc(rDescriptor);
+ bool bRepairStorage = aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
+ bool bSkipImages
+ = aMediaDesc.getUnpackedValueOrDefault("FilterOptions", OUString()) == "SkipImages";
+
+ uno::Reference<io::XInputStream> xInputStream;
+ try
+ {
+ // use the oox.core.FilterDetect implementation to extract the decrypted ZIP package
+ rtl::Reference<::oox::core::FilterDetect> xDetector(
+ new ::oox::core::FilterDetect(m_xContext));
+ xInputStream = xDetector->extractUnencryptedPackage(aMediaDesc);
+ }
+ catch (uno::Exception&)
+ {
+ }
+
+ if (!xInputStream.is())
+ return false;
+
+ writerfilter::Stream::Pointer_t pStream(
+ writerfilter::dmapper::DomainMapperFactory::createMapper(
+ m_xContext, xInputStream, m_xDstDoc, bRepairStorage,
+ writerfilter::dmapper::SourceDocumentType::OOXML, aMediaDesc));
+ //create the tokenizer and domain mapper
+ writerfilter::ooxml::OOXMLStream::Pointer_t pDocStream
+ = writerfilter::ooxml::OOXMLDocumentFactory::createStream(m_xContext, xInputStream,
+ bRepairStorage);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator
+ = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR,
+ uno::Reference<task::XStatusIndicator>());
+ writerfilter::ooxml::OOXMLDocument::Pointer_t pDocument(
+ writerfilter::ooxml::OOXMLDocumentFactory::createDocument(pDocStream, xStatusIndicator,
+ bSkipImages, rDescriptor));
+
+ uno::Reference<frame::XModel> xModel(m_xDstDoc, uno::UNO_QUERY_THROW);
+ pDocument->setModel(xModel);
+
+ uno::Reference<drawing::XDrawPageSupplier> xDrawings(m_xDstDoc, uno::UNO_QUERY_THROW);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawings->getDrawPage(), uno::UNO_SET_THROW);
+ pDocument->setDrawPage(xDrawPage);
+
+ try
+ {
+ pDocument->resolve(*pStream);
+ }
+ catch (xml::sax::SAXParseException const& e)
+ {
+ // note: SfxObjectShell checks for WrongFormatException
+ io::WrongFormatException wfe(lcl_GetExceptionMessage(e));
+ throw lang::WrappedTargetRuntimeException("", static_cast<OWeakObject*>(this),
+ uno::Any(wfe));
+ }
+ catch (xml::sax::SAXException const& e)
+ {
+ // note: SfxObjectShell checks for WrongFormatException
+ io::WrongFormatException wfe(lcl_GetExceptionMessage(e));
+ throw lang::WrappedTargetRuntimeException("", static_cast<OWeakObject*>(this),
+ uno::Any(wfe));
+ }
+ catch (uno::RuntimeException const&)
+ {
+ throw;
+ }
+ catch (uno::Exception const&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ SAL_WARN("writerfilter",
+ "WriterFilter::filter(): failed with " << exceptionToString(anyEx));
+ throw lang::WrappedTargetRuntimeException("", static_cast<OWeakObject*>(this), anyEx);
+ }
+
+ // Adding some properties to the document's grab bag for interoperability purposes:
+ comphelper::SequenceAsHashMap aGrabBagProperties;
+
+ // Adding the saved Theme DOM
+ aGrabBagProperties["OOXTheme"] <<= pDocument->getThemeDom();
+
+ // Adding the saved custom xml DOM
+ aGrabBagProperties["OOXCustomXml"] <<= pDocument->getCustomXmlDomList();
+ aGrabBagProperties["OOXCustomXmlProps"] <<= pDocument->getCustomXmlDomPropsList();
+
+ // Adding the saved Glossary Document DOM to the document's grab bag
+ aGrabBagProperties["OOXGlossary"] <<= pDocument->getGlossaryDocDom();
+ aGrabBagProperties["OOXGlossaryDom"] <<= pDocument->getGlossaryDomList();
+
+ // Adding the saved embedding document to document's grab bag
+ aGrabBagProperties["OOXEmbeddings"] <<= pDocument->getEmbeddingsList();
+
+ oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(m_xDstDoc, aGrabBagProperties);
+
+ writerfilter::ooxml::OOXMLStream::Pointer_t pVBAProjectStream(
+ writerfilter::ooxml::OOXMLDocumentFactory::createStream(
+ pDocStream, writerfilter::ooxml::OOXMLStream::VBAPROJECT));
+ oox::StorageRef xVbaPrjStrg = std::make_shared<::oox::ole::OleStorage>(
+ m_xContext, pVBAProjectStream->getDocumentStream(), false);
+ if (xVbaPrjStrg && xVbaPrjStrg->isStorage())
+ {
+ ::oox::ole::VbaProject aVbaProject(m_xContext, xModel, u"Writer");
+ uno::Reference<frame::XFrame> xFrame = aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_FRAME, uno::Reference<frame::XFrame>());
+
+ // if no XFrame try fallback to what we can glean from the Model
+ if (!xFrame.is())
+ {
+ uno::Reference<frame::XController> xController = xModel->getCurrentController();
+ xFrame = xController.is() ? xController->getFrame() : nullptr;
+ }
+
+ oox::GraphicHelper gHelper(m_xContext, xFrame, xVbaPrjStrg);
+ aVbaProject.importVbaProject(*xVbaPrjStrg, gHelper);
+
+ writerfilter::ooxml::OOXMLStream::Pointer_t pVBADataStream(
+ writerfilter::ooxml::OOXMLDocumentFactory::createStream(
+ pDocStream, writerfilter::ooxml::OOXMLStream::VBADATA));
+ if (pVBADataStream)
+ {
+ uno::Reference<io::XInputStream> xDataStream = pVBADataStream->getDocumentStream();
+ if (xDataStream.is())
+ aVbaProject.importVbaData(xDataStream);
+ }
+ }
+
+ pStream.clear();
+
+ // note: pStream.clear calls RemoveLastParagraph()
+
+ return true;
+ }
+ return false;
+}
+
+void WriterFilter::cancel() {}
+
+void WriterFilter::setTargetDocument(const uno::Reference<lang::XComponent>& xDoc)
+{
+ m_xDstDoc = xDoc;
+
+ // Set some compatibility options that are valid for the DOCX format
+ uno::Reference<lang::XMultiServiceFactory> xFactory(xDoc, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xSettings(
+ xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+
+ xSettings->setPropertyValue("AddVerticalFrameOffsets", uno::Any(true));
+ xSettings->setPropertyValue("UseOldNumbering", uno::Any(false));
+ xSettings->setPropertyValue("IgnoreFirstLineIndentInNumbering", uno::Any(false));
+ xSettings->setPropertyValue("DoNotResetParaAttrsForNumFont", uno::Any(false));
+ xSettings->setPropertyValue("UseFormerLineSpacing", uno::Any(false));
+ xSettings->setPropertyValue("AddParaSpacingToTableCells", uno::Any(true));
+ xSettings->setPropertyValue("AddParaLineSpacingToTableCells", uno::Any(true));
+ xSettings->setPropertyValue("UseFormerObjectPositioning", uno::Any(false));
+ xSettings->setPropertyValue("ConsiderTextWrapOnObjPos", uno::Any(true));
+ xSettings->setPropertyValue("UseFormerTextWrapping", uno::Any(false));
+ xSettings->setPropertyValue("IgnoreTabsAndBlanksForLineCalculation", uno::Any(true));
+ xSettings->setPropertyValue("InvertBorderSpacing", uno::Any(true));
+ xSettings->setPropertyValue("CollapseEmptyCellPara", uno::Any(true));
+ // tdf#142404 TabOverSpacing (new for compatibilityMode15/Word2013+) is a subset of TabOverMargin
+ // (which applied to DOCX <= compatibilityMode14).
+ // TabOverMargin looks at tabs beyond the normal text area,
+ // while TabOverSpacing only refers to a tab beyond the paragraph margin.
+ xSettings->setPropertyValue("TabOverSpacing", uno::Any(true));
+ xSettings->setPropertyValue("UnbreakableNumberings", uno::Any(true));
+
+ xSettings->setPropertyValue("FloattableNomargins", uno::Any(true));
+ xSettings->setPropertyValue("ClippedPictures", uno::Any(true));
+ xSettings->setPropertyValue("BackgroundParaOverDrawings", uno::Any(true));
+ xSettings->setPropertyValue("TreatSingleColumnBreakAsPageBreak", uno::Any(true));
+ xSettings->setPropertyValue("PropLineSpacingShrinksFirstLine", uno::Any(true));
+ xSettings->setPropertyValue("DoNotCaptureDrawObjsOnPage", uno::Any(true));
+ xSettings->setPropertyValue("DisableOffPagePositioning", uno::Any(true));
+ xSettings->setPropertyValue("WordLikeWrapForAsCharFlys", uno::Any(true));
+}
+
+void WriterFilter::setSourceDocument(const uno::Reference<lang::XComponent>& xDoc)
+{
+ m_xSrcDoc = xDoc;
+}
+
+void WriterFilter::initialize(const uno::Sequence<uno::Any>& rArguments)
+{
+ m_xInitializationArguments = rArguments;
+}
+
+OUString WriterFilter::getImplementationName() { return "com.sun.star.comp.Writer.WriterFilter"; }
+
+sal_Bool WriterFilter::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> WriterFilter::getSupportedServiceNames()
+{
+ uno::Sequence<OUString> aRet = { OUString("com.sun.star.document.ImportFilter"),
+ OUString("com.sun.star.document.ExportFilter") };
+ return aRet;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
+com_sun_star_comp_Writer_WriterFilter_get_implementation(
+ uno::XComponentContext* component, uno::Sequence<uno::Any> const& /*rSequence*/)
+{
+ return cppu::acquire(new WriterFilter(component));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/Handler.cxx b/writerfilter/source/ooxml/Handler.cxx
new file mode 100644
index 000000000..7cbd9b6bf
--- /dev/null
+++ b/writerfilter/source/ooxml/Handler.cxx
@@ -0,0 +1,435 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ooxml/resourceids.hxx>
+#include "Handler.hxx"
+
+#include <sal/log.hxx>
+
+namespace writerfilter::ooxml
+{
+
+/*
+ class OOXMLFootnoteHandler
+ */
+OOXMLFootnoteHandler::OOXMLFootnoteHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLFootnoteHandler::~OOXMLFootnoteHandler()
+{
+}
+
+void OOXMLFootnoteHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_FtnEdnRef_id:
+ mpFastContext->resolveFootnote(sal_Int32(val.getInt()));
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFootnoteHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLEndnoteHandler
+ */
+OOXMLEndnoteHandler::OOXMLEndnoteHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLEndnoteHandler::~OOXMLEndnoteHandler()
+{
+}
+
+void OOXMLEndnoteHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_FtnEdnRef_id:
+ mpFastContext->resolveEndnote(sal_Int32(val.getInt()));
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLEndnoteHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLCommentHandler
+*/
+OOXMLCommentHandler::OOXMLCommentHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLCommentHandler::~OOXMLCommentHandler()
+{
+}
+
+void OOXMLCommentHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Markup_id:
+ mpFastContext->resolveComment(val.getInt());
+ break;
+ default:
+ ;
+ }
+}
+
+void OOXMLCommentHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLOLEHandler
+*/
+OOXMLOLEHandler::OOXMLOLEHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLOLEHandler::~OOXMLOLEHandler()
+{
+}
+
+void OOXMLOLEHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_OLEObject_r_id:
+ try {
+ mpFastContext->resolveData(val.getString());
+ }
+ catch (const ::css::uno::Exception&)
+ {
+ // Can't resolve OLE stream
+ SAL_WARN("writerfilter.ooxml", "Failed to open OLE stream!");
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+void OOXMLOLEHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+OOXMLEmbeddedFontHandler::OOXMLEmbeddedFontHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLEmbeddedFontHandler::~OOXMLEmbeddedFontHandler()
+{
+}
+
+void OOXMLEmbeddedFontHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Rel_id:
+ mpFastContext->resolveData(val.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLEmbeddedFontHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLFooterHandler
+ */
+OOXMLFooterHandler::OOXMLFooterHandler(OOXMLFastContextHandler * pContext)
+ : mpFastContext(pContext), mnType(0)
+{
+}
+
+void OOXMLFooterHandler::finalize()
+{
+ mpFastContext->resolveFooter(mnType, msStreamId);
+}
+
+void OOXMLFooterHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_HdrFtrRef_id:
+ msStreamId = val.getString();
+ break;
+ case NS_ooxml::LN_CT_HdrFtrRef_type:
+ mnType = val.getInt();
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFooterHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLHeaderHandler
+ */
+OOXMLHeaderHandler::OOXMLHeaderHandler(OOXMLFastContextHandler * pContext)
+ : mpFastContext(pContext), mnType(0)
+{
+}
+
+void OOXMLHeaderHandler::finalize()
+{
+ mpFastContext->resolveHeader(mnType, msStreamId);
+}
+
+void OOXMLHeaderHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_HdrFtrRef_id:
+ msStreamId = val.getString();
+ break;
+ case NS_ooxml::LN_CT_HdrFtrRef_type:
+ mnType = val.getInt();
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLHeaderHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLBreakHandler
+ */
+OOXMLBreakHandler::OOXMLBreakHandler(OOXMLFastContextHandler* pContext, Stream &rStream)
+: mnType(0),
+ mpFastContext(pContext),
+ mrStream(rStream)
+{
+}
+
+OOXMLBreakHandler::~OOXMLBreakHandler()
+{
+ if (mpFastContext)
+ {
+ mrStream.props(mpFastContext->getPropertySet().get());
+ mpFastContext->clearProps();
+ }
+
+ sal_uInt8 tmpBreak[1];
+ switch (mnType)
+ {
+ case NS_ooxml::LN_Value_ST_BrType_column:
+ tmpBreak[0] = 0x0E;
+ break;
+ case NS_ooxml::LN_Value_ST_BrType_page:
+ tmpBreak[0] = 0x0C;
+ break;
+ case NS_ooxml::LN_Value_ST_BrType_textWrapping:
+ default: // when no attribute type is present, the spec assume textWrapping
+ tmpBreak[0] = 0x0A;
+ break;
+ }
+ mrStream.text(&tmpBreak[0], 1);
+}
+
+void OOXMLBreakHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Br_type:
+ mnType = val.getInt();
+ break;
+ case NS_ooxml::LN_CT_Br_clear:
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLBreakHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLPictureHandler
+ */
+OOXMLPictureHandler::OOXMLPictureHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLPictureHandler::~OOXMLPictureHandler()
+{
+}
+
+void OOXMLPictureHandler::attribute(Id name, Value & val)
+{
+ if (name == NS_ooxml::LN_AG_Blob_r_embed)
+ mpFastContext->resolvePicture(val.getString());
+ else
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProps
+ (val.getProperties());
+ if (pProps)
+ pProps->resolve(*this);
+ }
+}
+
+void OOXMLPictureHandler::sprm(Sprm & rSprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProps
+ (rSprm.getProps());
+
+ if (pProps)
+ pProps->resolve(*this);
+}
+
+/**
+ class OOXMLHyperlinkHandler
+ */
+
+OOXMLHyperlinkHandler::OOXMLHyperlinkHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLHyperlinkHandler::~OOXMLHyperlinkHandler()
+{
+}
+
+void OOXMLHyperlinkHandler::writetext()
+{
+ OUString sReturn = " HYPERLINK \"" + mURL + "\"" + mFieldCode;
+ mpFastContext->text(sReturn);
+}
+
+void OOXMLHyperlinkHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Hyperlink_tgtFrame:
+ mFieldCode += " \\t \"";
+ mFieldCode += val.getString();
+ mFieldCode += "\"";
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_tooltip:
+ mFieldCode += " \\o \"";
+ mFieldCode += val.getString();
+ mFieldCode += "\"";
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_docLocation:
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_history:
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_anchor:
+ mFieldCode += " \\l \"";
+ mFieldCode += val.getString();
+ mFieldCode += "\"";
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_r_id:
+ mURL = mpFastContext->getTargetForId(val.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLHyperlinkHandler::sprm(Sprm & /*rSprm*/)
+{
+}
+
+/**
+ class OOXMLHyperlinkURLHandler
+ */
+
+OOXMLHyperlinkURLHandler::OOXMLHyperlinkURLHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLHyperlinkURLHandler::~OOXMLHyperlinkURLHandler()
+{
+ mpFastContext->clearProps();
+ mpFastContext->newProperty(NS_ooxml::LN_CT_Hyperlink_URL, OOXMLValue::Pointer_t(new OOXMLStringValue(mURL)));
+}
+
+void OOXMLHyperlinkURLHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Hyperlink_URL:
+ mURL = mpFastContext->getTargetForId(val.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLHyperlinkURLHandler::sprm(Sprm & /*rSprm*/)
+{
+}
+
+OOXMLAltChunkHandler::OOXMLAltChunkHandler(OOXMLFastContextHandler* pContext)
+ : mpFastContext(pContext)
+{
+}
+
+OOXMLAltChunkHandler::~OOXMLAltChunkHandler()
+{
+ mpFastContext->clearProps();
+ mpFastContext->newProperty(NS_ooxml::LN_CT_AltChunk,
+ OOXMLValue::Pointer_t(new OOXMLStringValue(m_aStreamName)));
+}
+
+void OOXMLAltChunkHandler::attribute(Id nName, Value& rValue)
+{
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_AltChunk:
+ m_aStreamName = mpFastContext->getTargetForId(rValue.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLAltChunkHandler::sprm(Sprm& /*rSprm*/) {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/Handler.hxx b/writerfilter/source/ooxml/Handler.hxx
new file mode 100644
index 000000000..df6673d44
--- /dev/null
+++ b/writerfilter/source/ooxml/Handler.hxx
@@ -0,0 +1,179 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+#include "OOXMLFastContextHandler.hxx"
+
+namespace writerfilter::ooxml
+{
+class OOXMLFootnoteHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLFootnoteHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLFootnoteHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLEndnoteHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLEndnoteHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLEndnoteHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLFooterHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString msStreamId;
+ sal_Int32 mnType;
+
+public:
+ explicit OOXMLFooterHandler(OOXMLFastContextHandler* pContext);
+ void finalize();
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLHeaderHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString msStreamId;
+ sal_Int32 mnType;
+
+public:
+ explicit OOXMLHeaderHandler(OOXMLFastContextHandler* pContext);
+ void finalize();
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLCommentHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLCommentHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLCommentHandler() override;
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLOLEHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLOLEHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLOLEHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLEmbeddedFontHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLEmbeddedFontHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLEmbeddedFontHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLBreakHandler : public Properties
+{
+ sal_Int32 mnType;
+ OOXMLFastContextHandler* mpFastContext;
+ Stream& mrStream;
+
+public:
+ explicit OOXMLBreakHandler(OOXMLFastContextHandler* pContext, Stream& rStream);
+ virtual ~OOXMLBreakHandler() override;
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLPictureHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLPictureHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLPictureHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLHyperlinkHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString mFieldCode;
+ OUString mURL;
+
+public:
+ explicit OOXMLHyperlinkHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLHyperlinkHandler() override;
+ void writetext();
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLHyperlinkURLHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString mURL;
+
+public:
+ explicit OOXMLHyperlinkURLHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLHyperlinkURLHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+/// Looks up the stream name for a '<w:altChunk r:id="..."/>' reference.
+class OOXMLAltChunkHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString m_aStreamName;
+
+public:
+ explicit OOXMLAltChunkHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLAltChunkHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLBinaryObjectReference.cxx b/writerfilter/source/ooxml/OOXMLBinaryObjectReference.cxx
new file mode 100644
index 000000000..1cf7ba7d0
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLBinaryObjectReference.cxx
@@ -0,0 +1,71 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "OOXMLBinaryObjectReference.hxx"
+#include <string.h>
+
+namespace writerfilter::ooxml
+{
+
+using namespace ::com::sun::star;
+
+OOXMLBinaryObjectReference::OOXMLBinaryObjectReference
+(OOXMLStream::Pointer_t const & pStream)
+: mpStream(pStream), mbRead(false)
+{
+}
+
+OOXMLBinaryObjectReference::~OOXMLBinaryObjectReference()
+{
+}
+
+void OOXMLBinaryObjectReference::read()
+{
+ sal_uInt32 nMaxReadBytes = 1024*1024;
+ uno::Sequence<sal_Int8> aSeq(nMaxReadBytes);
+ uno::Reference<io::XInputStream> xInputStream =
+ mpStream->getDocumentStream();
+
+ sal_uInt32 nSize = 0;
+ sal_uInt32 nOldSize = 0;
+ sal_uInt32 nBytesRead = 0;
+
+ while ((nBytesRead = xInputStream->readSomeBytes(aSeq, nMaxReadBytes)) > 0)
+ {
+ nOldSize = nSize;
+ nSize += nBytesRead;
+ mSequence.resize(nSize);
+
+ memcpy(&mSequence[nOldSize], aSeq.getArray(), nBytesRead);
+ }
+
+ mbRead = true;
+}
+
+void OOXMLBinaryObjectReference::resolve(BinaryObj & rHandler)
+{
+ if (! mbRead)
+ read();
+
+ rHandler.data(reinterpret_cast<sal_uInt8 *>(mSequence.data()),
+ mSequence.size());
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLBinaryObjectReference.hxx b/writerfilter/source/ooxml/OOXMLBinaryObjectReference.hxx
new file mode 100644
index 000000000..84940b625
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLBinaryObjectReference.hxx
@@ -0,0 +1,43 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+#include <ooxml/OOXMLDocument.hxx>
+#include <vector>
+
+namespace writerfilter::ooxml
+{
+class OOXMLBinaryObjectReference : public writerfilter::Reference<BinaryObj>
+{
+ OOXMLStream::Pointer_t mpStream;
+ std::vector<sal_Int8> mSequence;
+ bool mbRead;
+
+ void read();
+
+public:
+ explicit OOXMLBinaryObjectReference(OOXMLStream::Pointer_t const& pStream);
+ virtual ~OOXMLBinaryObjectReference() override;
+
+ virtual void resolve(BinaryObj& rHandler) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
new file mode 100644
index 000000000..0abd516a4
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
@@ -0,0 +1,898 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/sequenceashashmap.hxx>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/graphic/GraphicMapper.hpp>
+#include <ooxml/resourceids.hxx>
+#include <oox/shape/ShapeFilterBase.hxx>
+#include "OOXMLStreamImpl.hxx"
+#include "OOXMLDocumentImpl.hxx"
+#include "OOXMLBinaryObjectReference.hxx"
+#include "OOXMLFastDocumentHandler.hxx"
+#include "OOXMLPropertySet.hxx"
+
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <comphelper/sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include <iostream>
+#include <sfx2/objsh.hxx>
+
+// this extern variable is declared in OOXMLStreamImpl.hxx
+OUString customTarget;
+OUString embeddingsTarget;
+using namespace ::com::sun::star;
+namespace writerfilter::ooxml
+{
+
+OOXMLDocumentImpl::OOXMLDocumentImpl(OOXMLStream::Pointer_t const & pStream, const uno::Reference<task::XStatusIndicator>& xStatusIndicator, bool bSkipImages, const uno::Sequence<beans::PropertyValue>& rDescriptor)
+ : mpStream(pStream)
+ , mxStatusIndicator(xStatusIndicator)
+ , mnXNoteId(0)
+ , mbIsSubstream(false)
+ , mbSkipImages(bSkipImages)
+ , mnPercentSize(0)
+ , mnProgressLastPos(0)
+ , mnProgressCurrentPos(0)
+ , mnProgressEndPos(0)
+ , m_rBaseURL(utl::MediaDescriptor(rDescriptor).getUnpackedValueOrDefault("DocumentBaseURL", OUString()))
+ , maMediaDescriptor(rDescriptor)
+ , mxGraphicMapper(graphic::GraphicMapper::create(mpStream->getContext()))
+{
+ pushShapeContext();
+}
+
+OOXMLDocumentImpl::~OOXMLDocumentImpl()
+{
+}
+
+void OOXMLDocumentImpl::resolveFastSubStream(Stream & rStreamHandler,
+ OOXMLStream::StreamType_t nType)
+{
+ OOXMLStream::Pointer_t pStream;
+ try
+ {
+ pStream = OOXMLDocumentFactory::createStream(mpStream, nType);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "resolveFastSubStream: exception while "
+ "resolving stream " << nType);
+ return;
+ }
+ OOXMLStream::Pointer_t savedStream = mpStream;
+ mpStream = pStream;
+
+ uno::Reference<xml::sax::XFastParser> xParser(mpStream->getFastParser());
+
+ if (xParser.is())
+ {
+ uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+ rtl::Reference<OOXMLFastDocumentHandler> pDocHandler =
+ new OOXMLFastDocumentHandler(xContext, &rStreamHandler, this, mnXNoteId);
+
+ uno::Reference<xml::sax::XFastTokenHandler> xTokenHandler(mpStream->getFastTokenHandler());
+
+ xParser->setFastDocumentHandler(pDocHandler);
+ xParser->setTokenHandler(xTokenHandler);
+
+ uno::Reference<io::XInputStream> xInputStream = mpStream->getDocumentStream();
+
+ if (xInputStream.is())
+ {
+ struct xml::sax::InputSource oInputSource;
+ oInputSource.aInputStream = xInputStream;
+ xParser->parseStream(oInputSource);
+
+ xInputStream->closeInput();
+ }
+ }
+
+ mpStream = savedStream;
+}
+
+void OOXMLDocumentImpl::resolveFastSubStreamWithId(Stream & rStream,
+ const writerfilter::Reference<Stream>::Pointer_t& pStream,
+ sal_uInt32 nId)
+{
+ rStream.substream(nId, pStream);
+}
+
+uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::importSubStream(OOXMLStream::StreamType_t nType)
+{
+ uno::Reference<xml::dom::XDocument> xRet;
+
+ OOXMLStream::Pointer_t pStream;
+ try
+ {
+ pStream = OOXMLDocumentFactory::createStream(mpStream, nType);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "importing stream " << nType);
+ return xRet;
+ }
+
+ uno::Reference<io::XInputStream> xInputStream = pStream->getDocumentStream();
+ if (xInputStream.is())
+ {
+ try
+ {
+ uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(xml::dom::DocumentBuilder::create(xContext));
+ xRet = xDomBuilder->parse(xInputStream);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "parsing stream " << nType);
+ return xRet;
+ }
+ }
+
+ if (OOXMLStream::CUSTOMXML == nType)
+ {
+ importSubStreamRelations(pStream, OOXMLStream::CUSTOMXMLPROPS);
+ }
+ else if (OOXMLStream::CHARTS == nType)
+ {
+ importSubStreamRelations(pStream, OOXMLStream::EMBEDDINGS);
+ }
+
+ return xRet;
+}
+
+
+void OOXMLDocumentImpl::importSubStreamRelations(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nType)
+{
+ uno::Reference<xml::dom::XDocument> xRelation;
+ OOXMLStream::Pointer_t cStream;
+ try
+ {
+ cStream = OOXMLDocumentFactory::createStream(pStream, nType);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.ooxml", "importSubStreamRelations: exception while "
+ "importing stream " << nType);
+ return;
+ }
+
+ uno::Reference<io::XInputStream> xcpInputStream = cStream->getDocumentStream();
+
+ if (!xcpInputStream.is())
+ return;
+
+ // importing itemprops files for item.xml from customXml.
+ if (OOXMLStream::CUSTOMXMLPROPS == nType)
+ {
+ try
+ {
+ uno::Reference<uno::XComponentContext> xcpContext(pStream->getContext());
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(xml::dom::DocumentBuilder::create(xcpContext));
+ xRelation = xDomBuilder->parse(xcpInputStream);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "parsing stream " << nType);
+ mxCustomXmlProsDom = xRelation;
+ }
+
+ if(xRelation.is())
+ {
+ mxCustomXmlProsDom = xRelation;
+ }
+ }
+ else if(OOXMLStream::EMBEDDINGS == nType)
+ {
+ mxEmbeddings = xcpInputStream;
+ }
+ else if(OOXMLStream::CHARTS == nType)
+ {
+ importSubStreamRelations(cStream, OOXMLStream::EMBEDDINGS);
+ }
+
+
+}
+
+void OOXMLDocumentImpl::setXNoteId(const sal_Int32 nId)
+{
+ mnXNoteId = nId;
+}
+
+sal_Int32 OOXMLDocumentImpl::getXNoteId() const
+{
+ return mnXNoteId;
+}
+
+const OUString & OOXMLDocumentImpl::getTarget() const
+{
+ return mpStream->getTarget();
+}
+
+writerfilter::Reference<Stream>::Pointer_t
+OOXMLDocumentImpl::getSubStream(const OUString & rId)
+{
+ OOXMLStream::Pointer_t pStream
+ (OOXMLDocumentFactory::createStream(mpStream, rId));
+
+ OOXMLDocumentImpl * pTemp;
+ // Do not pass status indicator to sub-streams: they are typically marginal in size, so we just track the main document for now.
+ writerfilter::Reference<Stream>::Pointer_t pRet( pTemp = new OOXMLDocumentImpl(pStream, uno::Reference<task::XStatusIndicator>(), mbSkipImages, maMediaDescriptor));
+ pTemp->setModel(mxModel);
+ pTemp->setDrawPage(mxDrawPage);
+ pTemp->mbIsSubstream = true;
+ return pRet;
+}
+
+writerfilter::Reference<Stream>::Pointer_t
+OOXMLDocumentImpl::getXNoteStream(OOXMLStream::StreamType_t nType, const sal_Int32 nId)
+{
+ OOXMLStream::Pointer_t pStream =
+ OOXMLDocumentFactory::createStream(mpStream, nType);
+ // See above, no status indicator for the note stream, either.
+ OOXMLDocumentImpl * pDocument = new OOXMLDocumentImpl(pStream, uno::Reference<task::XStatusIndicator>(), mbSkipImages, maMediaDescriptor);
+ pDocument->setXNoteId(nId);
+ pDocument->setModel(getModel());
+ pDocument->setDrawPage(getDrawPage());
+
+ return writerfilter::Reference<Stream>::Pointer_t(pDocument);
+}
+
+void OOXMLDocumentImpl::resolveFootnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId)
+{
+ if (!mpXFootnoteStream)
+ mpXFootnoteStream = getXNoteStream(OOXMLStream::FOOTNOTES, nNoteId);
+
+ Id nId;
+ switch (aType)
+ {
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_separator:
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_continuationSeparator:
+ nId = aType;
+ break;
+ default:
+ nId = NS_ooxml::LN_footnote;
+ break;
+ }
+
+ resolveFastSubStreamWithId(rStream, mpXFootnoteStream, nId);
+}
+
+void OOXMLDocumentImpl::resolveEndnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId)
+{
+ if (!mpXEndnoteStream)
+ mpXEndnoteStream = getXNoteStream(OOXMLStream::ENDNOTES, nNoteId);
+
+ Id nId;
+ switch (aType)
+ {
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_separator:
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_continuationSeparator:
+ nId = aType;
+ break;
+ default:
+ nId = NS_ooxml::LN_endnote;
+ break;
+ }
+
+ resolveFastSubStreamWithId(rStream, mpXEndnoteStream, nId);
+}
+
+void OOXMLDocumentImpl::resolveCommentsExtendedStream(Stream& rStream)
+{
+ resolveFastSubStream(rStream, OOXMLStream::COMMENTS_EXTENDED);
+}
+
+void OOXMLDocumentImpl::resolveComment(Stream & rStream,
+ const sal_Int32 nId)
+{
+ if (!mbCommentsExtendedResolved)
+ {
+ resolveCommentsExtendedStream(rStream);
+ mbCommentsExtendedResolved = true;
+ }
+
+ writerfilter::Reference<Stream>::Pointer_t pStream =
+ getXNoteStream(OOXMLStream::COMMENTS, nId);
+
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_annotation);
+}
+
+OOXMLPropertySet * OOXMLDocumentImpl::getPicturePropSet
+(const OUString & rId)
+{
+ OOXMLStream::Pointer_t pStream
+ (OOXMLDocumentFactory::createStream(mpStream, rId));
+
+ writerfilter::Reference<BinaryObj>::Pointer_t pPicture
+ (new OOXMLBinaryObjectReference(pStream));
+
+ OOXMLValue::Pointer_t pPayloadValue(new OOXMLBinaryValue(pPicture));
+
+ OOXMLPropertySet::Pointer_t pBlipSet(new OOXMLPropertySet);
+
+ pBlipSet->add(NS_ooxml::LN_payload, pPayloadValue, OOXMLProperty::ATTRIBUTE);
+
+ OOXMLValue::Pointer_t pBlipValue(new OOXMLPropertySetValue(pBlipSet));
+
+ OOXMLPropertySet * pProps = new OOXMLPropertySet;
+
+ pProps->add(NS_ooxml::LN_blip, pBlipValue, OOXMLProperty::ATTRIBUTE);
+
+ return pProps;
+}
+
+void OOXMLDocumentImpl::resolvePicture(Stream & rStream,
+ const OUString & rId)
+{
+ OOXMLPropertySet::Pointer_t pProps(getPicturePropSet(rId));
+
+ rStream.props(pProps.get());
+}
+
+OUString OOXMLDocumentImpl::getTargetForId(const OUString & rId)
+{
+ return mpStream->getTargetForId(rId);
+}
+
+void OOXMLDocumentImpl::resolveHeader(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId)
+{
+ writerfilter::Reference<Stream>::Pointer_t pStream =
+ getSubStream(rId);
+ switch (type)
+ {
+ case NS_ooxml::LN_Value_ST_HdrFtr_even:
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_headerl);
+ break;
+ case NS_ooxml::LN_Value_ST_HdrFtr_default: // here we assume that default is right, but not necessarily true :-(
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_headerr);
+ break;
+ case NS_ooxml::LN_Value_ST_HdrFtr_first:
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_headerf);
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLDocumentImpl::resolveFooter(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId)
+{
+ writerfilter::Reference<Stream>::Pointer_t pStream =
+ getSubStream(rId);
+
+ switch (type)
+ {
+ case NS_ooxml::LN_Value_ST_HdrFtr_even:
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_footerl);
+ break;
+ case NS_ooxml::LN_Value_ST_HdrFtr_default: // here we assume that default is right, but not necessarily true :-(
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_footerr);
+ break;
+ case NS_ooxml::LN_Value_ST_HdrFtr_first:
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_footerf);
+ break;
+ default:
+ break;
+ }
+}
+
+namespace {
+// Ensures that the indicator is reset after exiting OOXMLDocumentImpl::resolve
+class StatusIndicatorGuard{
+public:
+ explicit StatusIndicatorGuard(css::uno::Reference<css::task::XStatusIndicator> const & xStatusIndicator)
+ :mxStatusIndicator(xStatusIndicator)
+ {
+ }
+
+ ~StatusIndicatorGuard()
+ {
+ if (mxStatusIndicator.is())
+ mxStatusIndicator->end();
+ }
+
+private:
+ css::uno::Reference<css::task::XStatusIndicator> mxStatusIndicator;
+};
+}
+
+void OOXMLDocumentImpl::resolve(Stream & rStream)
+{
+ StatusIndicatorGuard aStatusIndicatorGuard(mxStatusIndicator);
+
+ if (utl::MediaDescriptor(maMediaDescriptor).getUnpackedValueOrDefault("ReadGlossaries", false))
+ {
+ resolveFastSubStream(rStream, OOXMLStream::GLOSSARY);
+ return;
+ }
+
+ uno::Reference<xml::sax::XFastParser> xParser(mpStream->getFastParser());
+
+ if (mxModel.is())
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxModel, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+ comphelper::SequenceAsHashMap aMap(xDocumentProperties->getDocumentStatistics());
+ if (aMap.find("ParagraphCount") != aMap.end())
+ {
+ sal_Int32 nValue;
+ if (aMap["ParagraphCount"] >>= nValue)
+ {
+ if (mxStatusIndicator.is())
+ {
+ // We want to care about the progress if we know the estimated paragraph count and we have given a status indicator as well.
+ // Set the end position only here, so later it's enough to check if that is non-zero in incrementProgress().
+ mnProgressEndPos = nValue;
+ OUString aDocLoad(SvxResId(RID_SVXSTR_DOC_LOAD));
+ mxStatusIndicator->start(aDocLoad, mnProgressEndPos);
+ mnPercentSize = mnProgressEndPos / 100;
+ }
+ }
+ }
+ }
+
+ if (!xParser.is())
+ return;
+
+ uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+
+ rStream.setDocumentReference(this);
+
+ rtl::Reference<OOXMLFastDocumentHandler> pDocHandler =
+ new OOXMLFastDocumentHandler(xContext, &rStream, this, mnXNoteId);
+ pDocHandler->setIsSubstream( mbIsSubstream );
+ uno::Reference < xml::sax::XFastTokenHandler > xTokenHandler(mpStream->getFastTokenHandler());
+
+ resolveFastSubStream(rStream, OOXMLStream::SETTINGS);
+ mxThemeDom = importSubStream(OOXMLStream::THEME);
+ resolveFastSubStream(rStream, OOXMLStream::THEME);
+ mxGlossaryDocDom = importSubStream(OOXMLStream::GLOSSARY);
+ if (mxGlossaryDocDom.is())
+ resolveGlossaryStream(rStream);
+
+ resolveEmbeddingsStream(mpStream);
+
+ // Custom xml's are handled as part of grab bag.
+ resolveCustomXmlStream(rStream);
+
+ resolveFastSubStream(rStream, OOXMLStream::FONTTABLE);
+ resolveFastSubStream(rStream, OOXMLStream::STYLES);
+ resolveFastSubStream(rStream, OOXMLStream::NUMBERING);
+
+ xParser->setFastDocumentHandler( pDocHandler );
+ xParser->setTokenHandler( xTokenHandler );
+
+ xml::sax::InputSource aParserInput;
+ aParserInput.sSystemId = mpStream->getTarget();
+ aParserInput.aInputStream = mpStream->getDocumentStream();
+ try
+ {
+ xParser->parseStream(aParserInput);
+ }
+ catch (xml::sax::SAXException const& rErr)
+ {
+ // don't silently swallow these - handlers may not have been executed,
+ // and the domain mapper is likely in an inconsistent state
+ // In case user chooses to try to continue loading, don't ask again for this file
+ SfxObjectShell* rShell = SfxObjectShell::GetShellFromComponent(mxModel);
+ if (!rShell
+ || !rShell->IsContinueImportOnFilterExceptions(
+ OUStringConcatenation("SAXException: " + rErr.Message)))
+ throw;
+ }
+ catch (uno::RuntimeException const&)
+ {
+ throw;
+ }
+ // note: cannot throw anything other than SAXException out of here?
+ catch (uno::Exception const&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ SAL_WARN("writerfilter.ooxml", "OOXMLDocumentImpl::resolve(): " << exceptionToString(anyEx));
+ throw lang::WrappedTargetRuntimeException("", nullptr, anyEx);
+ }
+ catch (...)
+ {
+ SAL_WARN("writerfilter.ooxml",
+ "OOXMLDocumentImpl::resolve(): non-UNO exception");
+ }
+}
+
+void OOXMLDocumentImpl::incrementProgress()
+{
+ mnProgressCurrentPos++;
+ // 1) If we know the end
+ // 2) We progressed enough that updating makes sense
+ // 3) We did not reach the end yet (possible in case the doc stat is misleading)
+ if (mnProgressEndPos && mnProgressCurrentPos > (mnProgressLastPos + mnPercentSize) && mnProgressLastPos < mnProgressEndPos)
+ {
+ mnProgressLastPos = mnProgressCurrentPos;
+ if (mxStatusIndicator.is())
+ mxStatusIndicator->setValue(mnProgressLastPos);
+ }
+}
+
+void OOXMLDocumentImpl::resolveCustomXmlStream(Stream & rStream)
+{
+ // Resolving all item[n].xml files from CustomXml folder.
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess;
+ xRelationshipAccess.set(dynamic_cast<OOXMLStreamImpl&>(*mpStream).accessDocumentStream(), uno::UNO_QUERY);
+ if (!xRelationshipAccess.is())
+ return;
+
+ static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
+ static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
+ bool bFound = false;
+ const uno::Sequence<uno::Sequence< beans::StringPair>> aSeqs = xRelationshipAccess->getAllRelationships();
+ std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomList;
+ std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList;
+ for (const uno::Sequence<beans::StringPair>& aSeq : aSeqs)
+ {
+ for (const beans::StringPair& aPair : aSeq)
+ {
+ // Need to resolve only customxml files from document relationships.
+ // Skipping other files.
+ if (aPair.Second == sCustomType ||
+ aPair.Second == sCustomTypeStrict)
+ bFound = true;
+ else if (aPair.First == "Target" && bFound)
+ {
+ // Adding value to extern variable customTarget. It will be used in ooxmlstreamimpl
+ // to ensure customxml target is visited in lcl_getTarget.
+ customTarget = aPair.Second;
+ }
+ }
+
+ if (bFound)
+ {
+ uno::Reference<xml::dom::XDocument> customXmlTemp = importSubStream(OOXMLStream::CUSTOMXML);
+ // This will add all item[n].xml with its relationship file i.e itemprops.xml to
+ // grabbag list.
+ if (mxCustomXmlProsDom.is() && customXmlTemp.is())
+ {
+ aCustomXmlDomList.push_back(customXmlTemp);
+ aCustomXmlDomPropsList.push_back(mxCustomXmlProsDom);
+ resolveFastSubStream(rStream, OOXMLStream::CUSTOMXML);
+ }
+
+ bFound = false;
+ }
+ }
+
+ mxCustomXmlDomList = comphelper::containerToSequence(aCustomXmlDomList);
+ mxCustomXmlDomPropsList = comphelper::containerToSequence(aCustomXmlDomPropsList);
+}
+
+namespace
+{
+const char sSettingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
+const char sStylesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+const char sFonttableType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
+const char sWebSettings[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
+const char sSettingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
+const char sStylesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
+const char sFonttableTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
+const char sWebSettingsStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
+
+constexpr OUStringLiteral sId = u"Id";
+constexpr OUStringLiteral sType = u"Type";
+constexpr OUStringLiteral sTarget = u"Target";
+constexpr OUStringLiteral sTargetMode = u"TargetMode";
+constexpr OUStringLiteral sContentType = u"_contentType";
+constexpr OUStringLiteral sRelDom = u"_relDom";
+constexpr OUStringLiteral sSettingsContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
+constexpr OUStringLiteral sStylesContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
+constexpr OUStringLiteral sWebsettingsContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml";
+constexpr OUStringLiteral sFonttableContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
+}
+
+// See DocxExport::WriteGlossary
+void OOXMLDocumentImpl::resolveGlossaryStream(Stream & /*rStream*/)
+{
+ OOXMLStream::Pointer_t pStream;
+ try
+ {
+ pStream = OOXMLDocumentFactory::createStream(mpStream, OOXMLStream::GLOSSARY);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "resolveGlossaryStream: exception while "
+ "createStream for glossary" << OOXMLStream::GLOSSARY);
+ return;
+ }
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess;
+ xRelationshipAccess.set(dynamic_cast<OOXMLStreamImpl&>(*pStream).accessDocumentStream(), uno::UNO_QUERY);
+ if (!xRelationshipAccess.is())
+ return;
+
+
+ const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs = xRelationshipAccess->getAllRelationships();
+ std::vector< uno::Sequence<beans::NamedValue> > aGlossaryDomList;
+ for (const uno::Sequence< beans::StringPair >& aSeq : aSeqs)
+ {
+ comphelper::NamedValueCollection aRelDefinition;
+ for (const auto& [name, value] : aSeq)
+ aRelDefinition.put(name, value);
+
+ const OUString gType = aRelDefinition.getOrDefault(sType, OUString{});
+ OOXMLStream::StreamType_t nType(OOXMLStream::UNKNOWN);
+ if (gType == sSettingsType || gType == sSettingsTypeStrict)
+ {
+ nType = OOXMLStream::SETTINGS;
+ aRelDefinition.put(sContentType, sSettingsContentType);
+ }
+ else if (gType == sStylesType || gType == sStylesTypeStrict)
+ {
+ nType = OOXMLStream::STYLES;
+ aRelDefinition.put(sContentType, sStylesContentType);
+ }
+ else if (gType == sWebSettings || gType == sWebSettingsStrict)
+ {
+ nType = OOXMLStream::WEBSETTINGS;
+ aRelDefinition.put(sContentType, sWebsettingsContentType);
+ }
+ else if (gType == sFonttableType || gType == sFonttableTypeStrict)
+ {
+ nType = OOXMLStream::FONTTABLE;
+ aRelDefinition.put(sContentType, sFonttableContentType);
+ }
+ else if (aRelDefinition.getOrDefault(sTargetMode, OUString{}) != "External")
+ {
+ // Some internal relation, but we don't create a DOM for it here yet?
+ SAL_WARN("writerfilter.ooxml", "Unknown type of glossary internal relation: "
+ "Id=\"" + aRelDefinition.getOrDefault<OUString>(sId, {}) + "\" "
+ "Type=\"" + gType + "\" "
+ "Target=\"" + aRelDefinition.getOrDefault<OUString>(sTarget, {}) + "\"");
+ continue;
+ }
+
+ if (nType != OOXMLStream::UNKNOWN)
+ {
+ try
+ {
+ auto gStream = OOXMLDocumentFactory::createStream(pStream, nType);
+ uno::Reference xInputStream = gStream->getDocumentStream();
+ uno::Reference xContext(pStream->getContext());
+ uno::Reference xDomBuilder(xml::dom::DocumentBuilder::create(xContext));
+ uno::Reference xDom = xDomBuilder->parse(xInputStream);
+ aRelDefinition.put(sRelDom, xDom);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "parsing stream of Type" << nType);
+ }
+ }
+ aGlossaryDomList.push_back(aRelDefinition.getNamedValues());
+ }
+ mxGlossaryDomList = comphelper::containerToSequence(aGlossaryDomList);
+}
+
+void OOXMLDocumentImpl::resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream)
+{
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess;
+ xRelationshipAccess.set(dynamic_cast<OOXMLStreamImpl&>(*pStream).accessDocumentStream(), uno::UNO_QUERY);
+ if (xRelationshipAccess.is())
+ {
+ OUString const sChartType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart");
+ OUString const sChartTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/chart");
+ OUString const sFootersType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer");
+ OUString const sFootersTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footer");
+ OUString const sHeaderType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/header");
+ OUString const sHeaderTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/header");
+
+ bool bFound = false;
+ bool bHeaderFooterFound = false;
+ OOXMLStream::StreamType_t streamType = OOXMLStream::UNKNOWN;
+ const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs = xRelationshipAccess->getAllRelationships();
+ for (const uno::Sequence< beans::StringPair >& aSeq : aSeqs)
+ {
+ for (const beans::StringPair& aPair : aSeq)
+ {
+ if (aPair.Second == sChartType ||
+ aPair.Second == sChartTypeStrict)
+ {
+ bFound = true;
+ }
+ else if(aPair.Second == sFootersType ||
+ aPair.Second == sFootersTypeStrict)
+ {
+ bHeaderFooterFound = true;
+ streamType = OOXMLStream::FOOTER;
+ }
+ else if(aPair.Second == sHeaderType ||
+ aPair.Second == sHeaderTypeStrict)
+ {
+ bHeaderFooterFound = true;
+ streamType = OOXMLStream::HEADER;
+ }
+ else if(aPair.First == "Target" && ( bFound || bHeaderFooterFound ))
+ {
+ // Adding value to extern variable customTarget. It will be used in ooxmlstreamimpl
+ // to ensure chart.xml target is visited in lcl_getTarget.
+ customTarget = aPair.Second;
+ }
+ }
+ if( bFound || bHeaderFooterFound)
+ {
+ if(bFound)
+ {
+ importSubStreamRelations(pStream, OOXMLStream::CHARTS);
+ }
+ if(bHeaderFooterFound)
+ {
+ try
+ {
+ OOXMLStream::Pointer_t Stream = OOXMLDocumentFactory::createStream(pStream, streamType);
+ if (Stream)
+ resolveEmbeddingsStream(Stream);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "resolveEmbeddingsStream: can't find header/footer whilst "
+ "resolving stream " << streamType);
+ return;
+ }
+ }
+
+ beans::PropertyValue embeddingsTemp;
+ // This will add all .xlsx and .bin to grabbag list.
+ if(bFound && mxEmbeddings.is())
+ {
+ embeddingsTemp.Name = embeddingsTarget;
+ embeddingsTemp.Value <<= mxEmbeddings;
+ aEmbeddings.push_back(embeddingsTemp);
+ mxEmbeddings.clear();
+ }
+ bFound = false;
+ bHeaderFooterFound = false;
+ }
+ }
+ }
+ if (!aEmbeddings.empty())
+ mxEmbeddingsList = comphelper::containerToSequence(aEmbeddings);
+}
+
+uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::getGlossaryDocDom( )
+{
+ return mxGlossaryDocDom;
+}
+
+uno::Sequence<uno::Sequence< beans::NamedValue> > OOXMLDocumentImpl::getGlossaryDomList()
+{
+ return mxGlossaryDomList;
+}
+
+uno::Reference<io::XInputStream> OOXMLDocumentImpl::getInputStreamForId(const OUString & rId)
+{
+ OOXMLStream::Pointer_t pStream(OOXMLDocumentFactory::createStream(mpStream, rId));
+
+ return pStream->getDocumentStream();
+}
+
+void OOXMLDocumentImpl::setModel(uno::Reference<frame::XModel> xModel)
+{
+ mxModel.set(xModel);
+}
+
+uno::Reference<frame::XModel> OOXMLDocumentImpl::getModel()
+{
+ return mxModel;
+}
+
+void OOXMLDocumentImpl::setDrawPage(uno::Reference<drawing::XDrawPage> xDrawPage)
+{
+ mxDrawPage.set(xDrawPage);
+}
+
+uno::Reference<drawing::XDrawPage> OOXMLDocumentImpl::getDrawPage()
+{
+ return mxDrawPage;
+}
+
+const uno::Sequence<beans::PropertyValue>& OOXMLDocumentImpl::getMediaDescriptor() const
+{
+ return maMediaDescriptor;
+}
+
+void OOXMLDocumentImpl::setShapeContext( rtl::Reference<oox::shape::ShapeContextHandler> xContext )
+{
+ if (!maShapeContexts.empty())
+ maShapeContexts.top() = xContext;
+}
+
+rtl::Reference<oox::shape::ShapeContextHandler> OOXMLDocumentImpl::getShapeContext( )
+{
+ if (!maShapeContexts.empty())
+ return maShapeContexts.top();
+ else
+ return {};
+}
+
+void OOXMLDocumentImpl::pushShapeContext()
+{
+ maShapeContexts.push({});
+}
+
+void OOXMLDocumentImpl::popShapeContext()
+{
+ if (!maShapeContexts.empty())
+ maShapeContexts.pop();
+}
+
+uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::getThemeDom( )
+{
+ return mxThemeDom;
+}
+
+uno::Sequence<uno::Reference<xml::dom::XDocument> > OOXMLDocumentImpl::getCustomXmlDomList( )
+{
+ return mxCustomXmlDomList;
+}
+
+uno::Sequence<uno::Reference<xml::dom::XDocument> > OOXMLDocumentImpl::getCustomXmlDomPropsList( )
+{
+ return mxCustomXmlDomPropsList;
+}
+
+uno::Sequence<beans::PropertyValue > OOXMLDocumentImpl::getEmbeddingsList( )
+{
+ return mxEmbeddingsList;
+}
+
+const rtl::Reference<oox::shape::ShapeFilterBase>& OOXMLDocumentImpl::getShapeFilterBase()
+{
+ if (!mxShapeFilterBase)
+ mxShapeFilterBase = new oox::shape::ShapeFilterBase(mpStream->getContext());
+ return mxShapeFilterBase;
+}
+
+OOXMLDocument *
+OOXMLDocumentFactory::createDocument
+(const OOXMLStream::Pointer_t& pStream,
+ const uno::Reference<task::XStatusIndicator>& xStatusIndicator,
+ bool mbSkipImages, const uno::Sequence<beans::PropertyValue>& rDescriptor)
+{
+ return new OOXMLDocumentImpl(pStream, xStatusIndicator, mbSkipImages, rDescriptor);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
new file mode 100644
index 000000000..eedf1eb12
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
@@ -0,0 +1,166 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <ooxml/OOXMLDocument.hxx>
+
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/graphic/XGraphicMapper.hpp>
+
+#include <oox/drawingml/drawingmltypes.hxx>
+
+#include "OOXMLPropertySet.hxx"
+
+#include <vector>
+#include <stack>
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLDocumentImpl : public OOXMLDocument
+{
+ OOXMLStream::Pointer_t mpStream;
+ css::uno::Reference<css::task::XStatusIndicator> mxStatusIndicator;
+ writerfilter::Reference<Stream>::Pointer_t mpXFootnoteStream;
+ writerfilter::Reference<Stream>::Pointer_t mpXEndnoteStream;
+ sal_Int32 mnXNoteId;
+
+ css::uno::Reference<css::frame::XModel> mxModel;
+ css::uno::Reference<css::drawing::XDrawPage> mxDrawPage;
+ css::uno::Reference<css::xml::dom::XDocument> mxGlossaryDocDom;
+ css::uno::Sequence < css::uno::Sequence< css::beans::NamedValue > > mxGlossaryDomList;
+ /// Stack of shape contexts, 1 element for VML, 1 element / nesting level for drawingML.
+ std::stack< rtl::Reference<oox::shape::ShapeContextHandler> > maShapeContexts;
+ css::uno::Reference<css::xml::dom::XDocument> mxThemeDom;
+ css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxCustomXmlDomList;
+ css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxCustomXmlDomPropsList;
+ css::uno::Reference<css::xml::dom::XDocument> mxCustomXmlProsDom;
+ css::uno::Reference<css::io::XInputStream> mxEmbeddings;
+ css::uno::Sequence < css::beans::PropertyValue > mxEmbeddingsList;
+ std::vector<css::beans::PropertyValue> aEmbeddings;
+ bool mbIsSubstream;
+ bool mbSkipImages;
+ /// How many paragraphs equal to 1 percent?
+ sal_Int32 mnPercentSize;
+ /// Position progress when it was last updated, possibly not after every paragraph in case of large documents.
+ sal_Int32 mnProgressLastPos;
+ /// Current position progress, updated after every paragraph.
+ sal_Int32 mnProgressCurrentPos;
+ /// End position, i.e. the estimated number of paragraphs.
+ sal_Int32 mnProgressEndPos;
+ /// DocumentBaseURL
+ OUString m_rBaseURL;
+ css::uno::Sequence<css::beans::PropertyValue> maMediaDescriptor;
+ /// Graphic mapper
+ css::uno::Reference<css::graphic::XGraphicMapper> mxGraphicMapper;
+ // For a document there is a single theme in document.xml.rels
+ // and the same is used by header and footer as well.
+ oox::drawingml::ThemePtr mpTheme;
+ rtl::Reference<oox::shape::ShapeFilterBase> mxShapeFilterBase;
+
+ bool mbCommentsExtendedResolved = false;
+
+private:
+ void resolveFastSubStream(Stream & rStream,
+ OOXMLStream::StreamType_t nType);
+
+ static void resolveFastSubStreamWithId(Stream & rStream,
+ const writerfilter::Reference<Stream>::Pointer_t& pStream,
+ sal_uInt32 nId);
+
+ css::uno::Reference<css::xml::dom::XDocument> importSubStream(OOXMLStream::StreamType_t nType);
+
+ void importSubStreamRelations(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nType);
+
+ writerfilter::Reference<Stream>::Pointer_t
+ getSubStream(const OUString & rId);
+
+ writerfilter::Reference<Stream>::Pointer_t
+ getXNoteStream(OOXMLStream::StreamType_t nType, const sal_Int32 nNoteId);
+
+ void resolveCustomXmlStream(Stream & rStream);
+ void resolveGlossaryStream(Stream & rStream);
+ void resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream);
+ void resolveCommentsExtendedStream(Stream & rStream);
+
+public:
+ OOXMLDocumentImpl(OOXMLStream::Pointer_t const & pStream, const css::uno::Reference<css::task::XStatusIndicator>& xStatusIndicator, bool bSkipImages, const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor);
+ virtual ~OOXMLDocumentImpl() override;
+
+ virtual void resolve(Stream & rStream) override;
+
+ virtual void resolveFootnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId) override;
+ virtual void resolveEndnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId) override;
+ virtual void resolveHeader(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) override;
+ virtual void resolveFooter(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) override;
+
+ virtual void resolveComment(Stream & rStream, const sal_Int32 nId) override;
+
+ OOXMLPropertySet * getPicturePropSet(const OUString & rId);
+ virtual void resolvePicture(Stream & rStream, const OUString & rId) override;
+
+ virtual OUString getTargetForId(const OUString & rId) override;
+
+ virtual void setModel(css::uno::Reference<css::frame::XModel> xModel) override;
+ virtual css::uno::Reference<css::frame::XModel> getModel() override;
+ virtual void setDrawPage(css::uno::Reference<css::drawing::XDrawPage> xDrawPage) override;
+ virtual css::uno::Reference<css::drawing::XDrawPage> getDrawPage() override;
+ virtual css::uno::Reference<css::io::XInputStream> getInputStreamForId(const OUString & rId) override;
+ virtual void setXNoteId(const sal_Int32 nId) override;
+ virtual sal_Int32 getXNoteId() const override;
+ virtual const OUString & getTarget() const override;
+ virtual rtl::Reference<oox::shape::ShapeContextHandler> getShapeContext( ) override;
+ virtual void setShapeContext( rtl::Reference<oox::shape::ShapeContextHandler> xContext ) override;
+ void pushShapeContext() override;
+ void popShapeContext() override;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getThemeDom() override;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomList() override;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomPropsList() override;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom() override;
+ virtual css::uno::Sequence<css::uno::Sequence< css::beans::NamedValue> > getGlossaryDomList() override;
+ virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() override;
+
+ void incrementProgress();
+ bool IsSkipImages() const { return mbSkipImages; };
+ OUString const& GetDocumentBaseURL() const { return m_rBaseURL; };
+ const css::uno::Sequence<css::beans::PropertyValue>& getMediaDescriptor() const;
+
+ const css::uno::Reference<css::graphic::XGraphicMapper>& getGraphicMapper() const
+ {
+ return mxGraphicMapper;
+ }
+
+ const oox::drawingml::ThemePtr & getTheme() const { return mpTheme; }
+ void setTheme(const oox::drawingml::ThemePtr& pTheme) { mpTheme = pTheme; }
+
+ const rtl::Reference<oox::shape::ShapeFilterBase> & getShapeFilterBase();
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFactory.cxx b/writerfilter/source/ooxml/OOXMLFactory.cxx
new file mode 100644
index 000000000..9e52c2b4c
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFactory.cxx
@@ -0,0 +1,179 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sax/fastattribs.hxx>
+#include "OOXMLFactory.hxx"
+
+namespace writerfilter::ooxml {
+
+using namespace com::sun::star;
+
+
+OOXMLFactory_ns::~OOXMLFactory_ns()
+{
+}
+
+
+void OOXMLFactory::attributes(OOXMLFastContextHandler * pHandler,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttribs)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (!pFactory)
+ return;
+
+ sax_fastparser::FastAttributeList& rAttribs =
+ sax_fastparser::castToFastAttributeList( xAttribs );
+
+ const AttributeInfo *pAttr = pFactory->getAttributeInfoArray(nDefine);
+ if (!pAttr)
+ return;
+
+ for (; pAttr->m_nToken != -1; ++pAttr)
+ {
+ sal_Int32 nToken = pAttr->m_nToken;
+ sal_Int32 nAttrIndex = rAttribs.getAttributeIndex(nToken);
+ if (nAttrIndex == -1)
+ continue;
+
+ Id nId = pFactory->getResourceId(nDefine, nToken);
+
+ OOXMLValue::Pointer_t xValue;
+ switch (pAttr->m_nResource)
+ {
+ case ResourceType::Boolean:
+ xValue = OOXMLBooleanValue::Create(rAttribs.getAsCharByIndex(nAttrIndex));
+ break;
+ case ResourceType::String:
+ xValue = new OOXMLStringValue(rAttribs.getValueByIndex(nAttrIndex));
+ break;
+ case ResourceType::Integer:
+ xValue = OOXMLIntegerValue::Create(rAttribs.getAsIntegerByIndex(nAttrIndex));
+ break;
+ case ResourceType::Hex:
+ xValue = new OOXMLHexValue(rAttribs.getAsCharByIndex(nAttrIndex));
+ break;
+ case ResourceType::HexColor:
+ xValue = new OOXMLHexColorValue(rAttribs.getAsCharByIndex(nAttrIndex));
+ break;
+ case ResourceType::TwipsMeasure_asSigned:
+ case ResourceType::TwipsMeasure_asZero:
+ xValue = new OOXMLTwipsMeasureValue(rAttribs.getAsCharByIndex(nAttrIndex));
+ if (xValue->getInt() < 0)
+ {
+ if (pAttr->m_nResource == ResourceType::TwipsMeasure_asZero)
+ xValue = OOXMLIntegerValue::Create(0);
+ }
+ break;
+ case ResourceType::HpsMeasure:
+ xValue = new OOXMLHpsMeasureValue(rAttribs.getAsCharByIndex(nAttrIndex));
+ break;
+ case ResourceType::MeasurementOrPercent:
+ xValue = new OOXMLMeasurementOrPercentValue(rAttribs.getAsCharByIndex(nAttrIndex));
+ break;
+ case ResourceType::List:
+ if (sal_uInt32 nValue;
+ pFactory->getListValue(pAttr->m_nRef, rAttribs.getValueByIndex(nAttrIndex), nValue))
+ {
+ xValue = OOXMLIntegerValue::Create(nValue);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (xValue)
+ {
+ pHandler->newProperty(nId, xValue);
+ pFactory->attributeAction(pHandler, nToken, xValue);
+ }
+ }
+}
+
+uno::Reference< xml::sax::XFastContextHandler>
+OOXMLFactory::createFastChildContext(OOXMLFastContextHandler * pHandler,
+ Token_t Element)
+{
+ Id nDefine = pHandler->getDefine();
+
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ uno::Reference< xml::sax::XFastContextHandler> ret;
+
+ //Avoid handling unknown tokens and recursing to death
+ if ((Element & 0xffff) < oox::XML_TOKEN_COUNT)
+ ret = createFastChildContextFromFactory(pHandler, pFactory, Element);
+
+ return ret;
+}
+
+void OOXMLFactory::characters(OOXMLFastContextHandler * pHandler,
+ const OUString & rString)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (pFactory)
+ {
+ pFactory->charactersAction(pHandler, rString);
+ }
+}
+
+void OOXMLFactory::startAction(OOXMLFastContextHandler * pHandler)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (pFactory)
+ {
+ pFactory->startAction(pHandler);
+ }
+}
+
+void OOXMLFactory::endAction(OOXMLFastContextHandler * pHandler)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (pFactory)
+ {
+ pFactory->endAction(pHandler);
+ }
+}
+
+void OOXMLFactory_ns::startAction(OOXMLFastContextHandler *)
+{
+}
+
+void OOXMLFactory_ns::endAction(OOXMLFastContextHandler *)
+{
+}
+
+void OOXMLFactory_ns::charactersAction(OOXMLFastContextHandler *, const OUString &)
+{
+}
+
+void OOXMLFactory_ns::attributeAction(OOXMLFastContextHandler *, Token_t, const OOXMLValue::Pointer_t&)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFactory.hxx b/writerfilter/source/ooxml/OOXMLFactory.hxx
new file mode 100644
index 000000000..4f3c82f1b
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFactory.hxx
@@ -0,0 +1,106 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+
+#include "OOXMLFastContextHandler.hxx"
+
+namespace writerfilter::ooxml {
+
+enum class ResourceType {
+ NoResource,
+ Table,
+ Stream,
+ List,
+ Integer,
+ Properties,
+ Hex,
+ HexColor,
+ String,
+ Shape,
+ Boolean,
+ Value,
+ XNote,
+ TextTableCell,
+ TextTableRow,
+ TextTable,
+ PropertyTable,
+ Math,
+ Any,
+ TwipsMeasure_asSigned,
+ TwipsMeasure_asZero,
+ HpsMeasure,
+ MeasurementOrPercent,
+ CommentEx,
+};
+
+struct AttributeInfo
+{
+ Token_t m_nToken;
+ ResourceType m_nResource;
+ Id m_nRef;
+};
+
+class OOXMLFactory_ns : public virtual SvRefBase {
+public:
+ typedef tools::SvRef<OOXMLFactory_ns> Pointer_t;
+
+ virtual void startAction(OOXMLFastContextHandler * pHandler);
+ virtual void charactersAction(OOXMLFastContextHandler * pHandler, const OUString & rString);
+ virtual void endAction(OOXMLFastContextHandler * pHandler);
+ virtual void attributeAction(OOXMLFastContextHandler * pHandler, Token_t nToken, const OOXMLValue::Pointer_t& pValue);
+
+protected:
+ virtual ~OOXMLFactory_ns() override;
+
+public:
+ virtual bool getListValue(Id nId, const OUString& rValue, sal_uInt32& rOutValue) = 0;
+ virtual Id getResourceId(Id nDefine, sal_Int32 nToken) = 0;
+ virtual const AttributeInfo* getAttributeInfoArray(Id nId) = 0;
+ virtual bool getElementId(Id nDefine, Id nId, ResourceType& rOutResource, Id& rOutElement) = 0;
+};
+
+class OOXMLFactory
+{
+public:
+
+ static css::uno::Reference< css::xml::sax::XFastContextHandler> createFastChildContext(OOXMLFastContextHandler * pHandler, Token_t Element);
+
+ static css::uno::Reference< css::xml::sax::XFastContextHandler> createFastChildContextFromStart(OOXMLFastContextHandler * pHandler, Token_t Element);
+
+ static void attributes(OOXMLFastContextHandler * pHandler, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ static void characters(OOXMLFastContextHandler * pHandler, const OUString & rString);
+
+ static void startAction(OOXMLFastContextHandler * pHandler);
+ static void endAction(OOXMLFastContextHandler * pHandler);
+
+private:
+ OOXMLFactory() = delete;
+ static OOXMLFactory_ns::Pointer_t getFactoryForNamespace(Id id);
+
+ static css::uno::Reference< css::xml::sax::XFastContextHandler> createFastChildContextFromFactory(OOXMLFastContextHandler * pHandler, OOXMLFactory_ns::Pointer_t pFactory, Token_t Element);
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
new file mode 100644
index 000000000..c4ee2c048
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx
@@ -0,0 +1,2307 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <ooxml/resourceids.hxx>
+#include <oox/mathml/import.hxx>
+#include <oox/token/namespaces.hxx>
+#include <sal/log.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <tools/globname.hxx>
+#include <comphelper/classids.hxx>
+#include <sfx2/sfxbasemodel.hxx>
+#include "OOXMLFastContextHandler.hxx"
+#include "OOXMLFactory.hxx"
+#include "Handler.hxx"
+#include <dmapper/CommentProperties.hxx>
+#include <dmapper/PropertyIds.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+
+const sal_Unicode uCR = 0xd;
+const sal_Unicode uFtnEdnRef = 0x2;
+const sal_Unicode uFtnEdnSep = 0x3;
+const sal_Unicode uFtnSep = 0x5;
+const sal_Unicode uTab = 0x9;
+const sal_Unicode uPgNum = 0x0;
+const sal_Unicode uNoBreakHyphen = 0x2011;
+const sal_Unicode uSoftHyphen = 0xAD;
+
+const sal_uInt8 cFtnEdnCont = 0x4;
+
+namespace writerfilter::ooxml
+{
+using namespace ::com::sun::star;
+using namespace oox;
+using namespace ::std;
+using namespace ::com::sun::star::xml::sax;
+
+/*
+ class OOXMLFastContextHandler
+ */
+
+OOXMLFastContextHandler::OOXMLFastContextHandler
+(uno::Reference< uno::XComponentContext > const & context)
+: mpParent(nullptr),
+ mId(0),
+ mnDefine(0),
+ mnToken(oox::XML_TOKEN_COUNT),
+ mnMathJcVal(0),
+ mbIsMathPara(false),
+ mpStream(nullptr),
+ mnTableDepth(0),
+ inPositionV(false),
+ mbAllowInCell(true),
+ mbIsVMLfound(false),
+ m_xContext(context),
+ m_bDiscardChildren(false),
+ m_bTookChoice(false)
+{
+ if (!mpParserState)
+ mpParserState = new OOXMLParserState();
+
+ mpParserState->incContextCount();
+}
+
+OOXMLFastContextHandler::OOXMLFastContextHandler(OOXMLFastContextHandler * pContext)
+: mpParent(pContext),
+ mId(0),
+ mnDefine(0),
+ mnToken(oox::XML_TOKEN_COUNT),
+ mnMathJcVal(pContext->mnMathJcVal),
+ mbIsMathPara(pContext->mbIsMathPara),
+ mpStream(pContext->mpStream),
+ mpParserState(pContext->mpParserState),
+ mnTableDepth(pContext->mnTableDepth),
+ inPositionV(pContext->inPositionV),
+ mbAllowInCell(pContext->mbAllowInCell),
+ mbIsVMLfound(pContext->mbIsVMLfound),
+ m_xContext(pContext->m_xContext),
+ m_bDiscardChildren(pContext->m_bDiscardChildren),
+ m_bTookChoice(pContext->m_bTookChoice)
+{
+ if (!mpParserState)
+ mpParserState = new OOXMLParserState();
+
+ mpParserState->incContextCount();
+}
+
+OOXMLFastContextHandler::~OOXMLFastContextHandler()
+{
+}
+
+bool OOXMLFastContextHandler::prepareMceContext(Token_t nElement, const uno::Reference<xml::sax::XFastAttributeList>& rAttribs)
+{
+ switch (oox::getBaseToken(nElement))
+ {
+ case XML_AlternateContent:
+ {
+ SavedAlternateState aState;
+ aState.m_bDiscardChildren = m_bDiscardChildren;
+ m_bDiscardChildren = false;
+ aState.m_bTookChoice = m_bTookChoice;
+ m_bTookChoice = false;
+ mpParserState->getSavedAlternateStates().push_back(aState);
+ }
+ break;
+ case XML_Choice:
+ {
+ OUString aRequires = rAttribs->getOptionalValue(XML_Requires);
+ static const char* aFeatures[] = {
+ "wps",
+ "wpg",
+ "w14",
+ };
+ for (const char *p : aFeatures)
+ {
+ if (aRequires.equalsAscii(p))
+ {
+ m_bTookChoice = true;
+ return false;
+ }
+ }
+ return true;
+ }
+ break;
+ case XML_Fallback:
+ // If Choice is already taken, then let's ignore the Fallback.
+ return m_bTookChoice;
+ default:
+ SAL_WARN("writerfilter", "OOXMLFastContextHandler::prepareMceContext: unhandled element:" << oox::getBaseToken(nElement));
+ break;
+ }
+ return false;
+}
+
+// xml::sax::XFastContextHandler:
+void SAL_CALL OOXMLFastContextHandler::startFastElement
+(sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ // Set xml:space value early, to allow child contexts use it when dealing with strings.
+ if (Attribs && Attribs->hasAttribute(oox::NMSP_xml | oox::XML_space))
+ {
+ mbPreserveSpace = Attribs->getValue(oox::NMSP_xml | oox::XML_space) == "preserve";
+ mbPreserveSpaceSet = true;
+ }
+ if (Element == W_TOKEN(footnote) || Element == W_TOKEN(endnote))
+ {
+ // send uFtnSep to sign new footnote content, but skip footnote separators
+ if (!Attribs->hasAttribute(W_TOKEN(type)) ||
+ ( Attribs->getValue(W_TOKEN(type)) != "separator" &&
+ Attribs->getValue(W_TOKEN(type)) != "continuationSeparator" &&
+ Attribs->getValue(W_TOKEN(type)) != "continuationNotice" ))
+ {
+ mpParserState->setStartFootnote(true);
+ }
+ }
+ else if (Element == (NMSP_officeMath | XML_oMathPara))
+ {
+ mnMathJcVal = eMathParaJc::CENTER;
+ mbIsMathPara = true;
+ }
+ else if (Element == (NMSP_officeMath | XML_jc) && mpParent && mpParent->mpParent )
+ {
+ mbIsMathPara = true;
+ auto aAttrLst = Attribs->getFastAttributes();
+ if (aAttrLst[0].Value == "center") mpParent->mpParent->mnMathJcVal = eMathParaJc::CENTER;
+ if (aAttrLst[0].Value == "left") mpParent->mpParent->mnMathJcVal = eMathParaJc::LEFT;
+ if (aAttrLst[0].Value == "right") mpParent->mpParent->mnMathJcVal = eMathParaJc::RIGHT;
+ }
+
+ if (oox::getNamespace(Element) == NMSP_mce)
+ m_bDiscardChildren = prepareMceContext(Element, Attribs);
+
+ else if (!m_bDiscardChildren)
+ {
+ attributes(Attribs);
+ lcl_startFastElement(Element, Attribs);
+ }
+}
+
+void SAL_CALL OOXMLFastContextHandler::startUnknownElement
+(const OUString & /*Namespace*/, const OUString & /*Name*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+}
+
+void SAL_CALL OOXMLFastContextHandler::endFastElement(sal_Int32 Element)
+{
+ if (Element == (NMSP_mce | XML_Choice) || Element == (NMSP_mce | XML_Fallback))
+ m_bDiscardChildren = false;
+ else if (Element == (NMSP_mce | XML_AlternateContent))
+ {
+ SavedAlternateState aState(mpParserState->getSavedAlternateStates().back());
+ mpParserState->getSavedAlternateStates().pop_back();
+ m_bDiscardChildren = aState.m_bDiscardChildren;
+ m_bTookChoice = aState.m_bTookChoice;
+ }
+ else if (!m_bDiscardChildren)
+ lcl_endFastElement(Element);
+}
+
+void OOXMLFastContextHandler::lcl_startFastElement
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ OOXMLFactory::startAction(this);
+ if( Element == (NMSP_dmlWordDr|XML_positionV) )
+ inPositionV = true;
+ else if( Element == (NMSP_dmlWordDr|XML_positionH) )
+ inPositionV = false;
+
+}
+
+void OOXMLFastContextHandler::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ OOXMLFactory::endAction(this);
+}
+
+void SAL_CALL OOXMLFastContextHandler::endUnknownElement
+(const OUString & , const OUString & )
+{
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+ OOXMLFastContextHandler::createFastChildContext
+(sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+ if (oox::getNamespace(Element) != NMSP_mce && !m_bDiscardChildren)
+ xResult.set(lcl_createFastChildContext(Element, Attribs));
+ else if (oox::getNamespace(Element) == NMSP_mce)
+ xResult = this;
+
+ return xResult;
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+ OOXMLFastContextHandler::lcl_createFastChildContext
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ return OOXMLFactory::createFastChildContext(this, Element);
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandler::createUnknownChildContext
+(const OUString &,
+ const OUString &,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ return uno::Reference< xml::sax::XFastContextHandler >
+ (new OOXMLFastContextHandler(*const_cast<const OOXMLFastContextHandler *>(this)));
+}
+
+void SAL_CALL OOXMLFastContextHandler::characters
+(const OUString & aChars)
+{
+ lcl_characters(aChars);
+}
+
+void OOXMLFastContextHandler::lcl_characters
+(const OUString & rString)
+{
+ if (!m_bDiscardChildren)
+ OOXMLFactory::characters(this, rString);
+}
+
+void OOXMLFastContextHandler::setStream(Stream * pStream)
+{
+ mpStream = pStream;
+}
+
+OOXMLValue::Pointer_t OOXMLFastContextHandler::getValue() const
+{
+ return OOXMLValue::Pointer_t();
+}
+
+void OOXMLFastContextHandler::attributes
+(const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ OOXMLFactory::attributes(this, Attribs);
+}
+
+void OOXMLFastContextHandler::startAction()
+{
+ OOXMLFactory::startAction(this);
+}
+
+void OOXMLFastContextHandler::endAction()
+{
+ OOXMLFactory::endAction(this);
+}
+
+void OOXMLFastContextHandler::setId(Id rId)
+{
+ mId = rId;
+}
+
+Id OOXMLFastContextHandler::getId() const
+{
+ return mId;
+}
+
+void OOXMLFastContextHandler::setDefine(Id nDefine)
+{
+ mnDefine = nDefine;
+}
+
+
+void OOXMLFastContextHandler::setToken(Token_t nToken)
+{
+ mnToken = nToken;
+}
+
+Token_t OOXMLFastContextHandler::getToken() const
+{
+ return mnToken;
+}
+
+void OOXMLFastContextHandler::sendTableDepth() const
+{
+ if (mnTableDepth <= 0)
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::setHandle()
+{
+ mpParserState->setHandle();
+ mpStream->info(mpParserState->getHandle());
+}
+
+void OOXMLFastContextHandler::startCharacterGroup()
+{
+ if (!isForwardEvents())
+ return;
+
+ if (mpParserState->isInCharacterGroup())
+ endCharacterGroup();
+
+ if (! mpParserState->isInParagraphGroup())
+ startParagraphGroup();
+
+ if (! mpParserState->isInCharacterGroup())
+ {
+ mpStream->startCharacterGroup();
+ mpParserState->setInCharacterGroup(true);
+ mpParserState->resolveCharacterProperties(*mpStream);
+ if (mpParserState->isStartFootnote())
+ {
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uFtnSep), 1);
+ mpParserState->setStartFootnote(false);
+ }
+ }
+
+ // tdf#108714 : if we have a postponed break information,
+ // then apply it now, before any other paragraph content.
+ mpParserState->resolvePostponedBreak(*mpStream);
+}
+
+void OOXMLFastContextHandler::endCharacterGroup()
+{
+ if (isForwardEvents() && mpParserState->isInCharacterGroup())
+ {
+ mpStream->endCharacterGroup();
+ mpParserState->setInCharacterGroup(false);
+ }
+}
+
+void OOXMLFastContextHandler::pushBiDiEmbedLevel() {}
+
+void OOXMLFastContextHandler::popBiDiEmbedLevel() {}
+
+void OOXMLFastContextHandler::startParagraphGroup()
+{
+ if (!isForwardEvents())
+ return;
+
+ if (mpParserState->isInParagraphGroup())
+ endParagraphGroup();
+
+ if (! mpParserState->isInSectionGroup())
+ startSectionGroup();
+
+ if ( mpParserState->isInParagraphGroup())
+ return;
+
+ mpStream->startParagraphGroup();
+ mpParserState->setInParagraphGroup(true);
+
+ if (const auto& pPropSet = getPropertySet())
+ {
+ OOXMLPropertySetEntryToString aHandler(NS_ooxml::LN_AG_Parids_paraId);
+ pPropSet->resolve(aHandler);
+ if (const OUString& sText = aHandler.getString(); !sText.isEmpty())
+ {
+ OOXMLStringValue::Pointer_t pVal = new OOXMLStringValue(sText);
+ OOXMLPropertySet::Pointer_t pPropertySet(new OOXMLPropertySet);
+ pPropertySet->add(NS_ooxml::LN_AG_Parids_paraId, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pPropertySet.get());
+ }
+ }
+}
+
+void OOXMLFastContextHandler::endParagraphGroup()
+{
+ if (isForwardEvents())
+ {
+ if (mpParserState->isInCharacterGroup())
+ endCharacterGroup();
+
+ if (mpParserState->isInParagraphGroup())
+ {
+ mpStream->endParagraphGroup();
+ mpParserState->setInParagraphGroup(false);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::startSdt()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtBlock_sdtContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::endSdt()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtBlock_sdtEndContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::startSdtRun()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtRun_sdtContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::endSdtRun()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtRun_sdtEndContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::startSectionGroup()
+{
+ if (isForwardEvents())
+ {
+ if (mpParserState->isInSectionGroup())
+ endSectionGroup();
+
+ if (! mpParserState->isInSectionGroup())
+ {
+ mpStream->info(mpParserState->getHandle());
+ mpStream->startSectionGroup();
+ mpParserState->setInSectionGroup(true);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::endSectionGroup()
+{
+ if (isForwardEvents())
+ {
+ if (mpParserState->isInParagraphGroup())
+ endParagraphGroup();
+
+ if (mpParserState->isInSectionGroup())
+ {
+ mpStream->endSectionGroup();
+ mpParserState->setInSectionGroup(false);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::setLastParagraphInSection()
+{
+ mpParserState->setLastParagraphInSection(true);
+ mpStream->markLastParagraphInSection( );
+}
+
+void OOXMLFastContextHandler::setLastSectionGroup()
+{
+ mpStream->markLastSectionGroup( );
+}
+
+void OOXMLFastContextHandler::newProperty
+(Id /*nId*/, const OOXMLValue::Pointer_t& /*pVal*/)
+{
+}
+
+void OOXMLFastContextHandler::setPropertySet
+(const OOXMLPropertySet::Pointer_t& /* pPropertySet */)
+{
+}
+
+OOXMLPropertySet::Pointer_t OOXMLFastContextHandler::getPropertySet() const
+{
+ return OOXMLPropertySet::Pointer_t();
+}
+
+void OOXMLFastContextHandler::startField()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldStart, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::fieldSeparator()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldSep, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::endField()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldEnd, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::lockField()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldLock, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::ftnednref()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uFtnEdnRef), 1);
+}
+
+void OOXMLFastContextHandler::ftnednsep()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uFtnEdnSep), 1);
+}
+
+void OOXMLFastContextHandler::ftnedncont()
+{
+ if (isForwardEvents())
+ mpStream->text(&cFtnEdnCont, 1);
+}
+
+void OOXMLFastContextHandler::pgNum()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uPgNum), 1);
+}
+
+void OOXMLFastContextHandler::tab()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uTab), 1);
+}
+
+void OOXMLFastContextHandler::symbol()
+{
+ if (isForwardEvents())
+ sendPropertiesWithId(NS_ooxml::LN_EG_RunInnerContent_sym);
+}
+
+void OOXMLFastContextHandler::cr()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uCR), 1);
+}
+
+void OOXMLFastContextHandler::noBreakHyphen()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uNoBreakHyphen), 1);
+}
+
+void OOXMLFastContextHandler::softHyphen()
+{
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uSoftHyphen), 1);
+}
+
+void OOXMLFastContextHandler::handleLastParagraphInSection()
+{
+ if (mpParserState->isLastParagraphInSection())
+ {
+ mpParserState->setLastParagraphInSection(false);
+ startSectionGroup();
+ }
+}
+
+void OOXMLFastContextHandler::endOfParagraph()
+{
+ if (! mpParserState->isInCharacterGroup())
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uCR), 1);
+
+ mpParserState->getDocument()->incrementProgress();
+}
+
+void OOXMLFastContextHandler::startTxbxContent()
+{
+/*
+ This usually means there are recursive <w:p> elements, and the ones
+ inside and outside of w:txbxContent should not interfere (e.g.
+ the lastParagraphInSection setting). So save the whole state
+ and possibly start new groups for the nested content (not section
+ group though, as that'd cause the txbxContent to be moved onto
+ another page, I'm not sure how that should work exactly).
+*/
+ mpParserState->startTxbxContent();
+ startParagraphGroup();
+}
+
+void OOXMLFastContextHandler::endTxbxContent()
+{
+ endParagraphGroup();
+ mpParserState->endTxbxContent();
+}
+
+namespace {
+// XML schema defines white space as one of four characters:
+// #x9 (tab), #xA (line feed), #xD (carriage return), and #x20 (space)
+bool IsXMLWhitespace(sal_Unicode cChar)
+{
+ return cChar == 0x9 || cChar == 0xA || cChar == 0xD || cChar == 0x20;
+}
+
+OUString TrimXMLWhitespace(const OUString & sText)
+{
+ sal_Int32 nTrimmedStart = 0;
+ const sal_Int32 nLen = sText.getLength();
+ sal_Int32 nTrimmedEnd = nLen - 1;
+ while (nTrimmedStart < nLen && IsXMLWhitespace(sText[nTrimmedStart]))
+ ++nTrimmedStart;
+ while (nTrimmedStart <= nTrimmedEnd && IsXMLWhitespace(sText[nTrimmedEnd]))
+ --nTrimmedEnd;
+ if ((nTrimmedStart == 0) && (nTrimmedEnd == nLen - 1))
+ return sText;
+ else if (nTrimmedStart > nTrimmedEnd)
+ return OUString();
+ else
+ return sText.copy(nTrimmedStart, nTrimmedEnd-nTrimmedStart+1);
+}
+}
+
+void OOXMLFastContextHandler::text(const OUString & sText)
+{
+ if (!isForwardEvents())
+ return;
+
+ // tdf#108806: CRLFs in XML were converted to \n before this point.
+ // These must be converted to spaces before further processing.
+ OUString sNormalizedText = sText.replaceAll("\n", " ");
+ // tdf#108995: by default, leading and trailing white space is ignored;
+ // tabs are converted to spaces
+ if (!IsPreserveSpace())
+ {
+ sNormalizedText = TrimXMLWhitespace(sNormalizedText).replaceAll("\t", " ");
+ }
+ mpStream->utext(reinterpret_cast < const sal_uInt8 * >
+ (sNormalizedText.getStr()),
+ sNormalizedText.getLength());
+}
+
+void OOXMLFastContextHandler::positionOffset(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->positionOffset(rText, inPositionV);
+}
+
+void OOXMLFastContextHandler::ignore()
+{
+}
+
+void OOXMLFastContextHandler::alignH(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->align(rText, /*bVertical=*/false);
+}
+
+void OOXMLFastContextHandler::alignV(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->align(rText, /*bVertical=*/true);
+}
+
+void OOXMLFastContextHandler::positivePercentage(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->positivePercentage(rText);
+}
+
+void OOXMLFastContextHandler::startGlossaryEntry()
+{
+ if (isForwardEvents())
+ mpStream->startGlossaryEntry();
+}
+
+void OOXMLFastContextHandler::endGlossaryEntry()
+{
+ if (isForwardEvents())
+ mpStream->endGlossaryEntry();
+}
+
+void OOXMLFastContextHandler::propagateCharacterProperties()
+{
+ mpParserState->setCharacterProperties(getPropertySet());
+}
+
+void OOXMLFastContextHandler::propagateCellProperties()
+{
+ mpParserState->setCellProperties(getPropertySet());
+}
+
+void OOXMLFastContextHandler::propagateRowProperties()
+{
+ mpParserState->setRowProperties(getPropertySet());
+}
+
+void OOXMLFastContextHandler::propagateTableProperties()
+{
+ OOXMLPropertySet::Pointer_t pProps = getPropertySet();
+
+ mpParserState->setTableProperties(pProps);
+}
+
+void OOXMLFastContextHandler::sendCellProperties()
+{
+ mpParserState->resolveCellProperties(*mpStream);
+}
+
+void OOXMLFastContextHandler::sendRowProperties()
+{
+ mpParserState->resolveRowProperties(*mpStream);
+}
+
+void OOXMLFastContextHandler::sendTableProperties()
+{
+ mpParserState->resolveTableProperties(*mpStream);
+}
+
+void OOXMLFastContextHandler::clearTableProps()
+{
+ mpParserState->setTableProperties(new OOXMLPropertySet());
+}
+
+void OOXMLFastContextHandler::sendPropertiesWithId(Id nId)
+{
+ OOXMLValue::Pointer_t pValue(new OOXMLPropertySetValue(getPropertySet()));
+ OOXMLPropertySet::Pointer_t pPropertySet(new OOXMLPropertySet);
+
+ pPropertySet->add(nId, pValue, OOXMLProperty::SPRM);
+ mpStream->props(pPropertySet.get());
+}
+
+void OOXMLFastContextHandler::clearProps()
+{
+ setPropertySet(new OOXMLPropertySet());
+}
+
+void OOXMLFastContextHandler::setDefaultBooleanValue()
+{
+}
+
+void OOXMLFastContextHandler::setDefaultIntegerValue()
+{
+}
+
+void OOXMLFastContextHandler::setDefaultHexValue()
+{
+}
+
+void OOXMLFastContextHandler::setDefaultStringValue()
+{
+}
+
+void OOXMLFastContextHandler::setDocument(OOXMLDocumentImpl* pDocument)
+{
+ mpParserState->setDocument(pDocument);
+}
+
+OOXMLDocumentImpl* OOXMLFastContextHandler::getDocument()
+{
+ return mpParserState->getDocument();
+}
+
+void OOXMLFastContextHandler::setForwardEvents(bool bForwardEvents)
+{
+ mpParserState->setForwardEvents(bForwardEvents);
+}
+
+bool OOXMLFastContextHandler::isForwardEvents() const
+{
+ return mpParserState->isForwardEvents();
+}
+
+void OOXMLFastContextHandler::setXNoteId(const sal_Int32 nId)
+{
+ mpParserState->setXNoteId(nId);
+}
+
+void OOXMLFastContextHandler::setXNoteId(const OOXMLValue::Pointer_t& pValue)
+{
+ mpParserState->setXNoteId(sal_Int32(pValue->getInt()));
+}
+
+sal_Int32 OOXMLFastContextHandler::getXNoteId() const
+{
+ return mpParserState->getXNoteId();
+}
+
+void OOXMLFastContextHandler::resolveFootnote
+(const sal_Int32 nId)
+{
+ mpParserState->getDocument()->resolveFootnote
+ (*mpStream, 0, nId);
+}
+
+void OOXMLFastContextHandler::resolveEndnote(const sal_Int32 nId)
+{
+ mpParserState->getDocument()->resolveEndnote
+ (*mpStream, 0, nId);
+}
+
+void OOXMLFastContextHandler::resolveComment(const sal_Int32 nId)
+{
+ mpParserState->getDocument()->resolveComment(*mpStream, nId);
+}
+
+void OOXMLFastContextHandler::resolvePicture(const OUString & rId)
+{
+ mpParserState->getDocument()->resolvePicture(*mpStream, rId);
+}
+
+void OOXMLFastContextHandler::resolveHeader
+(const sal_Int32 type, const OUString & rId)
+{
+ mpParserState->getDocument()->resolveHeader(*mpStream, type, rId);
+}
+
+void OOXMLFastContextHandler::resolveFooter
+(const sal_Int32 type, const OUString & rId)
+{
+ mpParserState->getDocument()->resolveFooter(*mpStream, type, rId);
+}
+
+// Add the data pointed to by the reference as another property.
+void OOXMLFastContextHandler::resolveData(const OUString & rId)
+{
+ OOXMLDocument * objDocument = getDocument();
+ SAL_WARN_IF(!objDocument, "writerfilter", "no document to resolveData");
+ if (!objDocument)
+ return;
+
+ uno::Reference<io::XInputStream> xInputStream
+ (objDocument->getInputStreamForId(rId));
+
+ OOXMLValue::Pointer_t aValue(new OOXMLInputStreamValue(xInputStream));
+
+ newProperty(NS_ooxml::LN_inputstream, aValue);
+}
+
+OUString OOXMLFastContextHandler::getTargetForId
+(const OUString & rId)
+{
+ return mpParserState->getDocument()->getTargetForId(rId);
+}
+
+void OOXMLFastContextHandler::sendPropertyToParent()
+{
+ if (mpParent != nullptr)
+ {
+ OOXMLPropertySet::Pointer_t pProps(mpParent->getPropertySet());
+
+ if (pProps)
+ {
+ pProps->add(mId, getValue(), OOXMLProperty::SPRM);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::sendPropertiesToParent()
+{
+ if (mpParent == nullptr)
+ return;
+
+ OOXMLPropertySet::Pointer_t pParentProps(mpParent->getPropertySet());
+
+ if (!pParentProps)
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(getPropertySet());
+
+ if (pProps)
+ {
+ OOXMLValue::Pointer_t pValue
+ (new OOXMLPropertySetValue(getPropertySet()));
+
+ pParentProps->add(getId(), pValue, OOXMLProperty::SPRM);
+
+ }
+}
+
+bool OOXMLFastContextHandler::IsPreserveSpace() const
+{
+ // xml:space attribute applies to all elements within the content of the element where it is specified,
+ // unless overridden with another instance of the xml:space attribute
+ if (mbPreserveSpaceSet)
+ return mbPreserveSpace;
+ if (mpParent)
+ return mpParent->IsPreserveSpace();
+ return false; // default value
+}
+
+/*
+ class OOXMLFastContextHandlerStream
+ */
+
+OOXMLFastContextHandlerStream::OOXMLFastContextHandlerStream
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext),
+ mpPropertySetAttrs(new OOXMLPropertySet)
+{
+}
+
+OOXMLFastContextHandlerStream::~OOXMLFastContextHandlerStream()
+{
+}
+
+void OOXMLFastContextHandlerStream::newProperty(Id nId,
+ const OOXMLValue::Pointer_t& pVal)
+{
+ if (nId != 0x0)
+ {
+ mpPropertySetAttrs->add(nId, pVal, OOXMLProperty::ATTRIBUTE);
+ }
+}
+
+void OOXMLFastContextHandlerStream::sendProperty(Id nId)
+{
+ OOXMLPropertySetEntryToString aHandler(nId);
+ getPropertySetAttrs()->resolve(aHandler);
+ const OUString & sText = aHandler.getString();
+ mpStream->utext(reinterpret_cast < const sal_uInt8 * >
+ (sText.getStr()),
+ sText.getLength());
+}
+
+
+OOXMLPropertySet::Pointer_t OOXMLFastContextHandlerStream::getPropertySet()
+ const
+{
+ return getPropertySetAttrs();
+}
+
+void OOXMLFastContextHandlerStream::handleHyperlink()
+{
+ OOXMLHyperlinkHandler aHyperlinkHandler(this);
+ getPropertySetAttrs()->resolve(aHyperlinkHandler);
+ aHyperlinkHandler.writetext();
+}
+
+/*
+ class OOXMLFastContextHandlerProperties
+ */
+OOXMLFastContextHandlerProperties::OOXMLFastContextHandlerProperties
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext), mpPropertySet(new OOXMLPropertySet),
+ mbResolve(false)
+{
+ if (pContext->getResource() == STREAM)
+ mbResolve = true;
+}
+
+OOXMLFastContextHandlerProperties::~OOXMLFastContextHandlerProperties()
+{
+}
+
+void OOXMLFastContextHandlerProperties::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ try
+ {
+ endAction();
+
+ if (mbResolve)
+ {
+ if (isForwardEvents())
+ {
+ mpStream->props(mpPropertySet.get());
+ }
+ }
+ else
+ {
+ sendPropertiesToParent();
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const xml::sax::SAXException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception& e)
+ {
+ auto a = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(e.Message, e.Context, a);
+ }
+}
+
+OOXMLValue::Pointer_t OOXMLFastContextHandlerProperties::getValue() const
+{
+ return OOXMLValue::Pointer_t(new OOXMLPropertySetValue(mpPropertySet));
+}
+
+void OOXMLFastContextHandlerProperties::newProperty
+(Id nId, const OOXMLValue::Pointer_t& pVal)
+{
+ if (nId != 0x0)
+ {
+ mpPropertySet->add(nId, pVal, OOXMLProperty::ATTRIBUTE);
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleXNotes()
+{
+ switch (mnToken)
+ {
+ case W_TOKEN(footnoteReference):
+ {
+ OOXMLFootnoteHandler aFootnoteHandler(this);
+ mpPropertySet->resolve(aFootnoteHandler);
+ }
+ break;
+ case W_TOKEN(endnoteReference):
+ {
+ OOXMLEndnoteHandler aEndnoteHandler(this);
+ mpPropertySet->resolve(aEndnoteHandler);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleHdrFtr()
+{
+ switch (mnToken)
+ {
+ case W_TOKEN(footerReference):
+ {
+ OOXMLFooterHandler aFooterHandler(this);
+ mpPropertySet->resolve(aFooterHandler);
+ aFooterHandler.finalize();
+ }
+ break;
+ case W_TOKEN(headerReference):
+ {
+ OOXMLHeaderHandler aHeaderHandler(this);
+ mpPropertySet->resolve(aHeaderHandler);
+ aHeaderHandler.finalize();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleComment()
+{
+ OOXMLCommentHandler aCommentHandler(this);
+ getPropertySet()->resolve(aCommentHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handlePicture()
+{
+ OOXMLPictureHandler aPictureHandler(this);
+ getPropertySet()->resolve(aPictureHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handleBreak()
+{
+ if(isForwardEvents())
+ {
+ OOXMLBreakHandler aBreakHandler(this, *mpStream);
+ getPropertySet()->resolve(aBreakHandler);
+ }
+}
+
+// tdf#108714 : allow <w:br> at block level (despite this is illegal according to ECMA-376-1:2016)
+void OOXMLFastContextHandlerProperties::handleOutOfOrderBreak()
+{
+ if(isForwardEvents())
+ {
+ mpParserState->setPostponedBreak(getPropertySet());
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleOLE()
+{
+ OOXMLOLEHandler aOLEHandler(this);
+ getPropertySet()->resolve(aOLEHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handleFontRel()
+{
+ OOXMLEmbeddedFontHandler handler(this);
+ getPropertySet()->resolve(handler);
+}
+
+void OOXMLFastContextHandlerProperties::handleHyperlinkURL() {
+ OOXMLHyperlinkURLHandler aHyperlinkURLHandler(this);
+ getPropertySet()->resolve(aHyperlinkURLHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handleAltChunk()
+{
+ OOXMLAltChunkHandler aHandler(this);
+ getPropertySet()->resolve(aHandler);
+}
+
+void OOXMLFastContextHandlerProperties::setPropertySet
+(const OOXMLPropertySet::Pointer_t& pPropertySet)
+{
+ if (pPropertySet)
+ mpPropertySet = pPropertySet;
+}
+
+OOXMLPropertySet::Pointer_t
+OOXMLFastContextHandlerProperties::getPropertySet() const
+{
+ return mpPropertySet;
+}
+
+/*
+ * class OOXMLFasContextHandlerPropertyTable
+ */
+
+OOXMLFastContextHandlerPropertyTable::OOXMLFastContextHandlerPropertyTable
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandlerProperties(pContext)
+{
+}
+
+OOXMLFastContextHandlerPropertyTable::~OOXMLFastContextHandlerPropertyTable()
+{
+}
+
+void OOXMLFastContextHandlerPropertyTable::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ OOXMLPropertySet::Pointer_t pPropSet(mpPropertySet->clone());
+ OOXMLTable::ValuePointer_t pTmpVal
+ (new OOXMLPropertySetValue(pPropSet));
+
+ mTable.add(pTmpVal);
+
+ writerfilter::Reference<Table>::Pointer_t pTable(mTable.clone());
+
+ mpStream->table(mId, pTable);
+
+ endAction();
+}
+
+/*
+ class OOXMLFastContextHandlerValue
+*/
+
+OOXMLFastContextHandlerValue::OOXMLFastContextHandlerValue
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerValue::~OOXMLFastContextHandlerValue()
+{
+}
+
+void OOXMLFastContextHandlerValue::setValue(const OOXMLValue::Pointer_t& pValue)
+{
+ mpValue = pValue;
+}
+
+OOXMLValue::Pointer_t OOXMLFastContextHandlerValue::getValue() const
+{
+ return mpValue;
+}
+
+void OOXMLFastContextHandlerValue::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ sendPropertyToParent();
+
+ endAction();
+}
+
+void OOXMLFastContextHandlerValue::setDefaultBooleanValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue = OOXMLBooleanValue::Create(true);
+ setValue(pValue);
+ }
+}
+
+void OOXMLFastContextHandlerValue::setDefaultIntegerValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue = OOXMLIntegerValue::Create(0);
+ setValue(pValue);
+ }
+}
+
+void OOXMLFastContextHandlerValue::setDefaultHexValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue(new OOXMLHexValue(sal_uInt32(0)));
+ setValue(pValue);
+ }
+}
+
+void OOXMLFastContextHandlerValue::setDefaultStringValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue(new OOXMLStringValue(OUString()));
+ setValue(pValue);
+ }
+}
+
+// ECMA-376-1:2016 17.3.2.8; https://www.unicode.org/reports/tr9/#Explicit_Directional_Embeddings
+void OOXMLFastContextHandlerValue::pushBiDiEmbedLevel()
+{
+ const bool bRtl
+ = mpValue && mpValue->getInt() == NS_ooxml::LN_Value_ST_Direction_rtl;
+ OOXMLFactory::characters(this, bRtl ? OUString(u"\u202B") : OUString(u"\u202A")); // RLE / LRE
+}
+
+void OOXMLFastContextHandlerValue::popBiDiEmbedLevel()
+{
+ OOXMLFactory::characters(this, u"\u202C"); // PDF (POP DIRECTIONAL FORMATTING)
+}
+
+void OOXMLFastContextHandlerValue::handleGridAfter()
+{
+ if (!getValue())
+ return;
+
+ if (OOXMLFastContextHandler* pTableRowProperties = getParent())
+ {
+ if (OOXMLFastContextHandler* pTableRow = pTableRowProperties->getParent())
+ // Save the value into the table row context, so it can be handled
+ // right before the end of the row.
+ pTableRow->setGridAfter(getValue());
+ }
+}
+
+/*
+ class OOXMLFastContextHandlerTable
+*/
+
+OOXMLFastContextHandlerTable::OOXMLFastContextHandlerTable
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTable::~OOXMLFastContextHandlerTable()
+{
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandlerTable::createFastChildContext
+(sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ addCurrentChild();
+
+ mCurrentChild.set(OOXMLFastContextHandler::createFastChildContext(Element, Attribs));
+
+ return mCurrentChild;
+}
+
+void OOXMLFastContextHandlerTable::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ addCurrentChild();
+
+ writerfilter::Reference<Table>::Pointer_t pTable(mTable.clone());
+ if (isForwardEvents() && mId != 0x0)
+ {
+ mpStream->table(mId, pTable);
+ }
+}
+
+void OOXMLFastContextHandlerTable::addCurrentChild()
+{
+ OOXMLFastContextHandler * pHandler = dynamic_cast<OOXMLFastContextHandler*>(mCurrentChild.get());
+ if (pHandler != nullptr)
+ {
+ OOXMLValue::Pointer_t pValue(pHandler->getValue());
+
+ if (pValue)
+ {
+ OOXMLTable::ValuePointer_t pTmpVal(pValue->clone());
+ mTable.add(pTmpVal);
+ }
+ }
+}
+
+/*
+ class OOXMLFastContextHandlerXNote
+ */
+
+OOXMLFastContextHandlerXNote::OOXMLFastContextHandlerXNote
+ (OOXMLFastContextHandler * pContext)
+ : OOXMLFastContextHandlerProperties(pContext)
+ , mbForwardEventsSaved(false)
+ , mnMyXNoteId(0)
+ , mnMyXNoteType(0)
+{
+}
+
+OOXMLFastContextHandlerXNote::~OOXMLFastContextHandlerXNote()
+{
+}
+
+void OOXMLFastContextHandlerXNote::lcl_startFastElement
+(Token_t /*Element*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ mbForwardEventsSaved = isForwardEvents();
+
+ // If this is the note we're looking for or this is the footnote separator one.
+ if (mnMyXNoteId == getXNoteId() ||
+ static_cast<sal_uInt32>(mnMyXNoteType) == NS_ooxml::LN_Value_doc_ST_FtnEdn_separator ||
+ mpParserState->isStartFootnote())
+ setForwardEvents(true);
+ else
+ setForwardEvents(false);
+
+ startAction();
+}
+
+void OOXMLFastContextHandlerXNote::lcl_endFastElement
+(Token_t Element)
+{
+ endAction();
+
+ OOXMLFastContextHandlerProperties::lcl_endFastElement(Element);
+
+ setForwardEvents(mbForwardEventsSaved);
+}
+
+void OOXMLFastContextHandlerXNote::checkId(const OOXMLValue::Pointer_t& pValue)
+{
+ mnMyXNoteId = sal_Int32(pValue->getInt());
+ mpStream->checkId(mnMyXNoteId);
+}
+
+void OOXMLFastContextHandlerXNote::checkType(const OOXMLValue::Pointer_t& pValue)
+{
+ mnMyXNoteType = pValue->getInt();
+}
+
+/*
+ class OOXMLFastContextHandlerTextTableCell
+ */
+
+OOXMLFastContextHandlerTextTableCell::OOXMLFastContextHandlerTextTableCell
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTextTableCell::~OOXMLFastContextHandlerTextTableCell()
+{
+}
+
+void OOXMLFastContextHandlerTextTableCell::startCell()
+{
+ if (isForwardEvents())
+ {
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tcStart, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+ }
+}
+
+void OOXMLFastContextHandlerTextTableCell::endCell()
+{
+ if (!isForwardEvents())
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tblCell, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tcEnd, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+}
+
+/*
+ class OOXMLFastContextHandlerTextTableRow
+ */
+
+OOXMLFastContextHandlerTextTableRow::OOXMLFastContextHandlerTextTableRow
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTextTableRow::~OOXMLFastContextHandlerTextTableRow()
+{
+}
+
+void OOXMLFastContextHandlerTextTableRow::startRow()
+{
+}
+
+void OOXMLFastContextHandlerTextTableRow::endRow()
+{
+ if (mpGridAfter)
+ {
+ // Grid after is the same as grid before, the empty cells are just
+ // inserted after the real ones, not before.
+ handleGridBefore(mpGridAfter);
+ mpGridAfter = nullptr;
+ }
+
+ startParagraphGroup();
+
+ if (isForwardEvents())
+ {
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_tblRow, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+ }
+
+ startCharacterGroup();
+
+ if (isForwardEvents())
+ mpStream->utext(reinterpret_cast<const sal_uInt8*>(&uCR), 1);
+
+ endCharacterGroup();
+ endParagraphGroup();
+}
+
+namespace {
+OOXMLValue::Pointer_t fakeNoBorder()
+{
+ OOXMLPropertySet::Pointer_t pProps( new OOXMLPropertySet );
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(0);
+ pProps->add(NS_ooxml::LN_CT_Border_val, pVal, OOXMLProperty::ATTRIBUTE);
+ OOXMLValue::Pointer_t pValue( new OOXMLPropertySetValue( pProps ));
+ return pValue;
+}
+}
+
+// Handle w:gridBefore here by faking necessary input that'll fake cells. I'm apparently
+// not insane enough to find out how to add cells in dmapper.
+void OOXMLFastContextHandlerTextTableRow::handleGridBefore( const OOXMLValue::Pointer_t& val )
+{
+ // start removing: disable for w:gridBefore
+ if (!mpGridAfter)
+ return;
+
+ int count = val->getInt();
+ for( int i = 0;
+ i < count;
+ ++i )
+ {
+ endOfParagraph();
+
+ if (isForwardEvents())
+ {
+ // This whole part is OOXMLFastContextHandlerTextTableCell::endCell() .
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tblCell, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+
+ // fake <w:tcBorders> with no border
+ OOXMLPropertySet::Pointer_t pCellProps( new OOXMLPropertySet );
+ {
+ OOXMLPropertySet::Pointer_t pBorderProps( new OOXMLPropertySet );
+ static Id borders[] = { NS_ooxml::LN_CT_TcBorders_top, NS_ooxml::LN_CT_TcBorders_bottom,
+ NS_ooxml::LN_CT_TcBorders_start, NS_ooxml::LN_CT_TcBorders_end };
+ for(sal_uInt32 border : borders)
+ pBorderProps->add(border, fakeNoBorder(), OOXMLProperty::SPRM);
+ OOXMLValue::Pointer_t pValue( new OOXMLPropertySetValue( pBorderProps ));
+ pCellProps->add(NS_ooxml::LN_CT_TcPrBase_tcBorders, pValue, OOXMLProperty::SPRM);
+ mpParserState->setCellProperties(pCellProps);
+ }
+ }
+
+ sendCellProperties();
+ endParagraphGroup();
+ }
+}
+
+/*
+ class OOXMLFastContextHandlerTextTable
+ */
+
+OOXMLFastContextHandlerTextTable::OOXMLFastContextHandlerTextTable
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTextTable::~OOXMLFastContextHandlerTextTable()
+{
+ clearTableProps();
+}
+
+void OOXMLFastContextHandlerTextTable::lcl_startFastElement
+(Token_t /*Element*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ mpParserState->startTable();
+ mnTableDepth++;
+
+ OOXMLPropertySet::Pointer_t pProps( new OOXMLPropertySet );
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblStart, pVal, OOXMLProperty::SPRM);
+ }
+ mpParserState->setCharacterProperties(pProps);
+
+ startAction();
+}
+
+void OOXMLFastContextHandlerTextTable::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ endAction();
+
+ OOXMLPropertySet::Pointer_t pProps( new OOXMLPropertySet );
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblEnd, pVal, OOXMLProperty::SPRM);
+ }
+ mpParserState->setCharacterProperties(pProps);
+
+ mnTableDepth--;
+ mpParserState->endTable();
+}
+
+// tdf#111550
+void OOXMLFastContextHandlerTextTable::start_P_Tbl()
+{
+ // Normally, when one paragraph ends, and another begins,
+ // in OOXMLFactory_wml::endAction handler for <w:p>,
+ // pHandler->endOfParagraph() is called, which (among other things)
+ // calls TableManager::setHandle() to update current cell's starting point.
+ // Then, in OOXMLFactory_wml::startAction for next <w:p>,
+ // pHandler->startParagraphGroup() is called, which ends previous group,
+ // and there, it pushes cells to row in TableManager::endParagraphGroup()
+ // (cells have correct bounds defined by mCurHandle).
+ // When a table is child of a <w:p>, that paragraph doesn't end before nested
+ // paragraph begins. So, pHandler->endOfParagraph() was not (and should not be)
+ // called. But as next paragraph starts, is the previous group is closed, then
+ // cells will have wrong boundings. Here, we know that we *are* in paragraph
+ // group, but it should not be finished.
+ mpParserState->setInParagraphGroup(false);
+}
+
+/*
+ class OOXMLFastContextHandlerShape
+ */
+
+OOXMLFastContextHandlerShape::OOXMLFastContextHandlerShape
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandlerProperties(pContext), m_bShapeSent( false ),
+ m_bShapeStarted(false), m_bShapeContextPushed(false)
+{
+}
+
+OOXMLFastContextHandlerShape::~OOXMLFastContextHandlerShape()
+{
+ if (m_bShapeContextPushed)
+ getDocument()->popShapeContext();
+}
+
+void OOXMLFastContextHandlerShape::lcl_startFastElement
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ startAction();
+
+ if (mrShapeContext.is())
+ {
+ mrShapeContext->startFastElement(Element, Attribs);
+ }
+}
+
+void SAL_CALL OOXMLFastContextHandlerShape::startUnknownElement
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mrShapeContext.is())
+ mrShapeContext->startUnknownElement(Namespace, Name, Attribs);
+}
+
+void OOXMLFastContextHandlerShape::setToken(Token_t nToken)
+{
+ if (nToken == Token_t(NMSP_wps | XML_wsp) || nToken == Token_t(NMSP_dmlPicture | XML_pic))
+ {
+ // drawingML shapes are independent, <wps:bodyPr> is not parsed after
+ // shape contents without pushing/popping the stack.
+ m_bShapeContextPushed = true;
+ getDocument()->pushShapeContext();
+ }
+
+ mrShapeContext = getDocument()->getShapeContext();
+ if (!mrShapeContext.is())
+ {
+ // Define the shape context for the whole document
+ mrShapeContext = new oox::shape::ShapeContextHandler(getDocument()->getShapeFilterBase());
+ getDocument()->setShapeContext(mrShapeContext);
+ auto pThemePtr = getDocument()->getTheme();
+ if (pThemePtr)
+ mrShapeContext->setTheme(pThemePtr);
+ }
+
+ mrShapeContext->setModel(getDocument()->getModel());
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocSupplier(getDocument()->getModel(), uno::UNO_QUERY_THROW);
+ mrShapeContext->setDocumentProperties(xDocSupplier->getDocumentProperties());
+ mrShapeContext->setDrawPage(getDocument()->getDrawPage());
+ mrShapeContext->setMediaDescriptor(getDocument()->getMediaDescriptor());
+
+ mrShapeContext->setRelationFragmentPath(mpParserState->getTarget());
+
+ // Floating tables (table inside a textframe) have issues with fullWPG,
+ // so disable the fullWPGsupport in tables until that issue is not fixed.
+ mrShapeContext->setFullWPGSupport(!mnTableDepth);
+
+ auto xGraphicMapper = getDocument()->getGraphicMapper();
+
+ if (xGraphicMapper.is())
+ mrShapeContext->setGraphicMapper(xGraphicMapper);
+
+ OOXMLFastContextHandler::setToken(nToken);
+
+ if (mrShapeContext.is())
+ mrShapeContext->pushStartToken(nToken);
+}
+
+void OOXMLFastContextHandlerShape::sendShape( Token_t Element )
+{
+ if ( !mrShapeContext.is() || m_bShapeSent )
+ return;
+
+ awt::Point aPosition = mpStream->getPositionOffset();
+ mrShapeContext->setPosition(aPosition);
+ uno::Reference<drawing::XShape> xShape(mrShapeContext->getShape());
+ m_bShapeSent = true;
+ if (!xShape.is())
+ return;
+
+ OOXMLValue::Pointer_t
+ pValue(new OOXMLShapeValue(xShape));
+ newProperty(NS_ooxml::LN_shape, pValue);
+
+ bool bIsPicture = Element == ( NMSP_dmlPicture | XML_pic );
+
+ //tdf#87569: Fix table layout with correcting anchoring
+ //If anchored object is in table, Word calculates its position from cell border
+ //instead of page (what is set in the sample document)
+ uno::Reference<beans::XPropertySet> xShapePropSet(xShape, uno::UNO_QUERY);
+ if (mnTableDepth > 0 && xShapePropSet.is() && mbIsVMLfound) //if we had a table
+ {
+ xShapePropSet->setPropertyValue(dmapper::getPropertyName(dmapper::PROP_FOLLOW_TEXT_FLOW),
+ uno::Any(mbAllowInCell));
+ }
+ // Notify the dmapper that the shape is ready to use
+ if ( !bIsPicture )
+ {
+ mpStream->startShape( xShape );
+ m_bShapeStarted = true;
+ }
+}
+
+bool OOXMLFastContextHandlerShape::isDMLGroupShape() const
+{
+ return (mrShapeContext->getFullWPGSupport() && mrShapeContext->isWordProcessingGroupShape());
+};
+
+void OOXMLFastContextHandlerShape::lcl_endFastElement
+(Token_t Element)
+{
+ if (!isForwardEvents())
+ return;
+
+ if (mrShapeContext.is())
+ {
+ mrShapeContext->endFastElement(Element);
+ sendShape( Element );
+ }
+
+ OOXMLFastContextHandlerProperties::lcl_endFastElement(Element);
+
+ // Ending the shape should be the last thing to do
+ bool bIsPicture = Element == ( NMSP_dmlPicture | XML_pic );
+ if ( !bIsPicture && m_bShapeStarted)
+ mpStream->endShape( );
+}
+
+void SAL_CALL OOXMLFastContextHandlerShape::endUnknownElement
+(const OUString & Namespace,
+ const OUString & Name)
+{
+ if (mrShapeContext.is())
+ mrShapeContext->endUnknownElement(Namespace, Name);
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+OOXMLFastContextHandlerShape::lcl_createFastChildContext
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ // we need to share a single theme across all the shapes, but we parse it
+ // in ShapeContextHandler. So if it has been parsed there, propagate it to
+ // the document.
+ if (mrShapeContext && mrShapeContext->getTheme() && !getDocument()->getTheme())
+ {
+ auto pThemePtr = mrShapeContext->getTheme();
+ getDocument()->setTheme(pThemePtr);
+ }
+
+ uno::Reference< xml::sax::XFastContextHandler > xContextHandler;
+
+ bool bGroupShape = Element == Token_t(NMSP_vml | XML_group);
+ // drawingML version also counts as a group shape.
+ if (!mrShapeContext->getFullWPGSupport())
+ bGroupShape |= mrShapeContext->getStartToken() == Token_t(NMSP_wpg | XML_wgp);
+ mbIsVMLfound = (getNamespace(Element) == NMSP_vmlOffice) || (getNamespace(Element) == NMSP_vml);
+ switch (oox::getNamespace(Element))
+ {
+ case NMSP_doc:
+ case NMSP_vmlWord:
+ case NMSP_vmlOffice:
+ if (!bGroupShape)
+ xContextHandler.set(OOXMLFactory::createFastChildContextFromStart(this, Element));
+ [[fallthrough]];
+ default:
+ if (!xContextHandler.is())
+ {
+ if (mrShapeContext.is())
+ {
+ uno::Reference<XFastContextHandler> pChildContext =
+ mrShapeContext->createFastChildContext(Element, Attribs);
+
+ rtl::Reference<OOXMLFastContextHandlerWrapper> pWrapper =
+ new OOXMLFastContextHandlerWrapper(this,
+ pChildContext,
+ this);
+
+ //tdf129888 store allowincell attribute of the VML shape
+ if (Attribs->hasAttribute(NMSP_vmlOffice | XML_allowincell))
+ mbAllowInCell
+ = !(Attribs->getValue(NMSP_vmlOffice | XML_allowincell) == "f");
+
+ if (!bGroupShape)
+ {
+ pWrapper->addNamespace(NMSP_doc);
+ pWrapper->addNamespace(NMSP_vmlWord);
+ pWrapper->addNamespace(NMSP_vmlOffice);
+ pWrapper->addToken( NMSP_vml|XML_textbox );
+ }
+ xContextHandler.set(pWrapper);
+ }
+ else
+ xContextHandler.set(this);
+ }
+ break;
+ }
+
+ // VML import of shape text is already handled by
+ // OOXMLFastContextHandlerWrapper::lcl_createFastChildContext(), here we
+ // handle the WPS import of shape text, as there the parent context is a
+ // Shape one, so a different situation.
+ if (Element == static_cast<sal_Int32>(NMSP_wps | XML_txbx) ||
+ Element == static_cast<sal_Int32>(NMSP_wps | XML_linkedTxbx) )
+ sendShape(Element);
+
+ return xContextHandler;
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandlerShape::createUnknownChildContext
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+
+ if (mrShapeContext.is())
+ xResult.set(mrShapeContext->createUnknownChildContext
+ (Namespace, Name, Attribs));
+
+ return xResult;
+}
+
+void OOXMLFastContextHandlerShape::lcl_characters
+(const OUString & aChars)
+{
+ if (mrShapeContext.is())
+ mrShapeContext->characters(aChars);
+}
+
+/*
+ class OOXMLFastContextHandlerWrapper
+*/
+
+OOXMLFastContextHandlerWrapper::OOXMLFastContextHandlerWrapper
+(OOXMLFastContextHandler * pParent,
+ uno::Reference<XFastContextHandler> const & xContext,
+ rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler)
+ : OOXMLFastContextHandler(pParent),
+ mxWrappedContext(xContext),
+ mxShapeHandler(xShapeHandler)
+{
+ setId(pParent->getId());
+ setToken(pParent->getToken());
+ setPropertySet(pParent->getPropertySet());
+}
+
+OOXMLFastContextHandlerWrapper::~OOXMLFastContextHandlerWrapper()
+{
+}
+
+void SAL_CALL OOXMLFastContextHandlerWrapper::startUnknownElement
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->startUnknownElement(Namespace, Name, Attribs);
+}
+
+void SAL_CALL OOXMLFastContextHandlerWrapper::endUnknownElement
+(const OUString & Namespace,
+ const OUString & Name)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->endUnknownElement(Namespace, Name);
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandlerWrapper::createUnknownChildContext
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+
+ if (mxWrappedContext.is())
+ xResult = mxWrappedContext->createUnknownChildContext
+ (Namespace, Name, Attribs);
+ else
+ xResult.set(this);
+
+ return xResult;
+}
+
+void OOXMLFastContextHandlerWrapper::attributes
+(const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->attributes(Attribs);
+ }
+}
+
+OOXMLFastContextHandler::ResourceEnum_t
+OOXMLFastContextHandlerWrapper::getResource() const
+{
+ return UNKNOWN;
+}
+
+void OOXMLFastContextHandlerWrapper::addNamespace(Id nId)
+{
+ mMyNamespaces.insert(nId);
+}
+
+void OOXMLFastContextHandlerWrapper::addToken( Token_t Token )
+{
+ mMyTokens.insert( Token );
+}
+
+void OOXMLFastContextHandlerWrapper::lcl_startFastElement
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->startFastElement(Element, Attribs);
+
+ if (mxShapeHandler->isDMLGroupShape()
+ && (Element == Token_t(NMSP_wps | XML_txbx)
+ || Element == Token_t(NMSP_wps | XML_linkedTxbx)))
+ {
+ mpStream->startTextBoxContent();
+ }
+}
+
+void OOXMLFastContextHandlerWrapper::lcl_endFastElement
+(Token_t Element)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->endFastElement(Element);
+
+ if (mxShapeHandler->isDMLGroupShape()
+ && (Element == Token_t(NMSP_wps | XML_txbx)
+ || Element == Token_t(NMSP_wps | XML_linkedTxbx)))
+ {
+ mpStream->endTextBoxContent();
+ }
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+OOXMLFastContextHandlerWrapper::lcl_createFastChildContext
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+
+ bool bInNamespaces = mMyNamespaces.find(oox::getNamespace(Element)) != mMyNamespaces.end();
+ bool bInTokens = mMyTokens.find( Element ) != mMyTokens.end( );
+
+ // We have methods to _add_ individual tokens or whole namespaces to be
+ // processed by writerfilter (instead of oox), but we have no method to
+ // filter out a single token. Just hardwire the 'wrap' and 'signatureline' tokens
+ // here until we need a more generic solution.
+ bool bIsWrap = Element == static_cast<sal_Int32>(NMSP_vmlWord | XML_wrap);
+ bool bIsSignatureLine = Element == static_cast<sal_Int32>(NMSP_vmlOffice | XML_signatureline);
+ bool bSkipImages = getDocument()->IsSkipImages() && oox::getNamespace(Element) == NMSP_dml &&
+ (oox::getBaseToken(Element) != XML_linkedTxbx) && (oox::getBaseToken(Element) != XML_txbx);
+
+ if ( bInNamespaces && ((!bIsWrap && !bIsSignatureLine)
+ || mxShapeHandler->isShapeSent()) )
+ {
+ xResult.set(OOXMLFactory::createFastChildContextFromStart(this, Element));
+ }
+ else if (mxWrappedContext.is() && !bSkipImages)
+ {
+ rtl::Reference<OOXMLFastContextHandlerWrapper> pWrapper =
+ new OOXMLFastContextHandlerWrapper
+ (this, mxWrappedContext->createFastChildContext(Element, Attribs),
+ mxShapeHandler);
+ pWrapper->mMyNamespaces = mMyNamespaces;
+ pWrapper->mMyTokens = mMyTokens;
+ pWrapper->setPropertySet(getPropertySet());
+ xResult.set(pWrapper);
+ }
+ else
+ {
+ xResult.set(this);
+ }
+
+ if ( bInTokens )
+ mxShapeHandler->sendShape( Element );
+
+ return xResult;
+}
+
+void OOXMLFastContextHandlerWrapper::lcl_characters
+(const OUString & aChars)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->characters(aChars);
+}
+
+OOXMLFastContextHandler *
+OOXMLFastContextHandlerWrapper::getFastContextHandler() const
+{
+ if (mxWrappedContext.is())
+ return dynamic_cast<OOXMLFastContextHandler *>(mxWrappedContext.get());
+
+ return nullptr;
+}
+
+void OOXMLFastContextHandlerWrapper::newProperty
+(Id nId, const OOXMLValue::Pointer_t& pVal)
+{
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->newProperty(nId, pVal);
+ }
+}
+
+void OOXMLFastContextHandlerWrapper::setPropertySet
+(const OOXMLPropertySet::Pointer_t& pPropertySet)
+{
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->setPropertySet(pPropertySet);
+ }
+
+ mpPropertySet = pPropertySet;
+}
+
+OOXMLPropertySet::Pointer_t OOXMLFastContextHandlerWrapper::getPropertySet()
+ const
+{
+ OOXMLPropertySet::Pointer_t pResult(mpPropertySet);
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pResult = pHandler->getPropertySet();
+ }
+
+ return pResult;
+}
+
+string OOXMLFastContextHandlerWrapper::getType() const
+{
+ string sResult = "Wrapper(";
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ sResult += pHandler->getType();
+ }
+
+ sResult += ")";
+
+ return sResult;
+}
+
+void OOXMLFastContextHandlerWrapper::setId(Id rId)
+{
+ OOXMLFastContextHandler::setId(rId);
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->setId(rId);
+ }
+}
+
+Id OOXMLFastContextHandlerWrapper::getId() const
+{
+ Id nResult = OOXMLFastContextHandler::getId();
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr && pHandler->getId() != 0)
+ nResult = pHandler->getId();
+ }
+
+ return nResult;
+}
+
+void OOXMLFastContextHandlerWrapper::setToken(Token_t nToken)
+{
+ OOXMLFastContextHandler::setToken(nToken);
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->setToken(nToken);
+ }
+}
+
+Token_t OOXMLFastContextHandlerWrapper::getToken() const
+{
+ Token_t nResult = OOXMLFastContextHandler::getToken();
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ nResult = pHandler->getToken();
+ }
+
+ return nResult;
+}
+
+
+/*
+ class OOXMLFastContextHandlerLinear
+ */
+
+OOXMLFastContextHandlerLinear::OOXMLFastContextHandlerLinear(OOXMLFastContextHandler* pContext)
+ : OOXMLFastContextHandlerProperties(pContext)
+ , depthCount( 0 )
+{
+}
+
+void OOXMLFastContextHandlerLinear::lcl_startFastElement(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList >& Attribs)
+{
+ buffer.appendOpeningTag( Element, Attribs );
+ ++depthCount;
+}
+
+void OOXMLFastContextHandlerLinear::lcl_endFastElement(Token_t Element)
+{
+ buffer.appendClosingTag( Element );
+ if( --depthCount == 0 )
+ process();
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+OOXMLFastContextHandlerLinear::lcl_createFastChildContext(Token_t,
+ const uno::Reference< xml::sax::XFastAttributeList >&)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xContextHandler;
+ xContextHandler.set( this );
+ return xContextHandler;
+}
+
+void OOXMLFastContextHandlerLinear::lcl_characters(const OUString& aChars)
+{
+ buffer.appendCharacters( aChars );
+}
+
+/*
+ class OOXMLFastContextHandlerLinear
+ */
+
+OOXMLFastContextHandlerMath::OOXMLFastContextHandlerMath(OOXMLFastContextHandler* pContext)
+ : OOXMLFastContextHandlerLinear(pContext)
+{
+}
+
+void OOXMLFastContextHandlerMath::process()
+{
+ SvGlobalName name( SO3_SM_CLASSID );
+ comphelper::EmbeddedObjectContainer container;
+ OUString aName;
+ uno::Sequence<beans::PropertyValue> objArgs{ comphelper::makePropertyValue(
+ "DefaultParentBaseURL", getDocument()->GetDocumentBaseURL()) };
+ uno::Reference<embed::XEmbeddedObject> ref =
+ container.CreateEmbeddedObject(name.GetByteSequence(), objArgs, aName);
+ assert(ref.is());
+ if (!ref.is())
+ return;
+ uno::Reference< uno::XInterface > component(ref->getComponent(), uno::UNO_QUERY_THROW);
+// gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
+// so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
+// to RTLD_GLOBAL, so most probably a gcc bug.
+ oox::FormulaImportBase& import = dynamic_cast<oox::FormulaImportBase&>(dynamic_cast<SfxBaseModel&>(*component));
+ import.readFormulaOoxml(buffer);
+ if (!isForwardEvents())
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal( new OOXMLStarMathValue( ref ));
+ if (mbIsMathPara)
+ {
+ switch (mnMathJcVal)
+ {
+ case eMathParaJc::CENTER:
+ pProps->add(NS_ooxml::LN_Value_math_ST_Jc_centerGroup, pVal,
+ OOXMLProperty::ATTRIBUTE);
+ break;
+ case eMathParaJc::LEFT:
+ pProps->add(NS_ooxml::LN_Value_math_ST_Jc_left, pVal,
+ OOXMLProperty::ATTRIBUTE);
+ break;
+ case eMathParaJc::RIGHT:
+ pProps->add(NS_ooxml::LN_Value_math_ST_Jc_right, pVal,
+ OOXMLProperty::ATTRIBUTE);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ pProps->add(NS_ooxml::LN_starmath, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props( pProps.get() );
+}
+
+OOXMLFastContextHandlerCommentEx::OOXMLFastContextHandlerCommentEx(
+ OOXMLFastContextHandler* pContext)
+ : OOXMLFastContextHandler(pContext)
+{
+}
+
+void OOXMLFastContextHandlerCommentEx::lcl_endFastElement(Token_t /*Element*/)
+{
+ mpStream->commentProps(m_sParaId, { m_bDone });
+}
+
+void OOXMLFastContextHandlerCommentEx::att_paraId(const OOXMLValue::Pointer_t& pValue)
+{
+ m_sParaId = pValue->getString();
+}
+
+void OOXMLFastContextHandlerCommentEx::att_done(const OOXMLValue::Pointer_t& pValue)
+{
+ if (pValue->getInt())
+ m_bDone = true;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
new file mode 100644
index 000000000..30491f08d
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx
@@ -0,0 +1,632 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <set>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XFastContextHandler.hpp>
+#include <oox/mathml/importutils.hxx>
+#include <rtl/ref.hxx>
+#include "OOXMLParserState.hxx"
+#include "OOXMLPropertySet.hxx"
+
+namespace writerfilter::ooxml
+{
+class OOXMLDocumentImpl;
+
+class OOXMLFastContextHandler: public ::cppu::WeakImplHelper<css::xml::sax::XFastContextHandler>
+{
+public:
+ typedef tools::SvRef<OOXMLFastContextHandler> Pointer_t;
+
+ enum ResourceEnum_t { UNKNOWN, STREAM, PROPERTIES, TABLE, SHAPE };
+
+ explicit OOXMLFastContextHandler(css::uno::Reference< css::uno::XComponentContext > const & context);
+
+ explicit OOXMLFastContextHandler(OOXMLFastContextHandler * pContext);
+
+ OOXMLFastContextHandler(OOXMLFastContextHandler const &) = default;
+
+ virtual ~OOXMLFastContextHandler() override;
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startFastElement (sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override final;
+
+ virtual void SAL_CALL startUnknownElement(const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 Element) override;
+
+ virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override;
+
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(sal_Int32 Element,
+ const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext(const OUString & Namespace, const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL characters(const OUString & aChars) override;
+
+ // local
+
+ void setStream(Stream * pStream);
+
+ /**
+ Return value of this context(element).
+
+ @return the value
+ */
+ virtual OOXMLValue::Pointer_t getValue() const;
+
+ /**
+ Returns a string describing the type of the context.
+
+ This is the name of the define normally.
+
+ @return type string
+ */
+ virtual std::string getType() const { return "??"; }
+
+ virtual ResourceEnum_t getResource() const { return STREAM; }
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void attributes(const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ virtual void newProperty(Id aId, const OOXMLValue::Pointer_t& pVal);
+ virtual void setPropertySet(const OOXMLPropertySet::Pointer_t& pPropertySet);
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const;
+
+ virtual void setToken(Token_t nToken);
+ virtual Token_t getToken() const;
+
+ void resolveFootnote(const sal_Int32 nId);
+ void resolveEndnote(const sal_Int32 nId);
+ void resolveComment(const sal_Int32 nId);
+ void resolvePicture(const OUString & rId);
+ void resolveHeader(const sal_Int32 type,
+ const OUString & rId);
+ void resolveFooter(const sal_Int32 type,
+ const OUString & rId);
+ void resolveData(const OUString & rId);
+
+ OUString getTargetForId(const OUString & rId);
+
+ void setDocument(OOXMLDocumentImpl* pDocument);
+ OOXMLDocumentImpl* getDocument();
+ void setXNoteId(const OOXMLValue::Pointer_t& pValue);
+ void setXNoteId(const sal_Int32 nId);
+ sal_Int32 getXNoteId() const;
+ void setForwardEvents(bool bForwardEvents);
+ bool isForwardEvents() const;
+ virtual void setId(Id nId);
+ virtual Id getId() const;
+
+ void setDefine(Id nDefine);
+ Id getDefine() const { return mnDefine;}
+
+ const OOXMLParserState::Pointer_t& getParserState() const { return mpParserState;}
+
+ void sendTableDepth() const;
+ void setHandle();
+
+ void startSectionGroup();
+ void setLastParagraphInSection();
+ void setLastSectionGroup();
+ void endSectionGroup();
+ void startParagraphGroup();
+ void endParagraphGroup();
+ void startCharacterGroup();
+ void endCharacterGroup();
+ virtual void pushBiDiEmbedLevel();
+ virtual void popBiDiEmbedLevel();
+ void startSdt();
+ void endSdt();
+ void startSdtRun();
+ void endSdtRun();
+
+ void startField();
+ void fieldSeparator();
+ void endField();
+ void lockField();
+ void ftnednref();
+ void ftnedncont();
+ void ftnednsep();
+ void pgNum();
+ void tab();
+ void symbol();
+ void cr();
+ void noBreakHyphen();
+ void softHyphen();
+ void handleLastParagraphInSection();
+ void endOfParagraph();
+ void text(const OUString & sText);
+ void positionOffset(const OUString & sText);
+ static void ignore();
+ void alignH(const OUString & sText);
+ void alignV(const OUString & sText);
+ void positivePercentage(const OUString& rText);
+ void startGlossaryEntry();
+ void endGlossaryEntry();
+ void startTxbxContent();
+ void endTxbxContent();
+ void propagateCharacterProperties();
+ void propagateTableProperties();
+ void propagateRowProperties();
+ void propagateCellProperties();
+ void sendPropertiesWithId(Id nId);
+ void sendPropertiesToParent();
+ void sendCellProperties();
+ void sendRowProperties();
+ void sendTableProperties();
+ void clearTableProps();
+ void clearProps();
+
+ virtual void setDefaultBooleanValue();
+ virtual void setDefaultIntegerValue();
+ virtual void setDefaultHexValue();
+ virtual void setDefaultStringValue();
+
+ void sendPropertyToParent();
+ OOXMLFastContextHandler* getParent() const { return mpParent; }
+ void setGridAfter(const OOXMLValue::Pointer_t& pGridAfter) { mpGridAfter = pGridAfter; }
+
+protected:
+ OOXMLFastContextHandler * mpParent;
+ Id mId;
+ Id mnDefine;
+ Token_t mnToken;
+
+ // the formula insertion mode: inline/newline(left, center, right)
+ sal_Int8 mnMathJcVal;
+ bool mbIsMathPara;
+ enum eMathParaJc
+ {
+ INLINE, //The equation is anchored as inline to the text
+ CENTER, //The equation is center aligned
+ LEFT, //The equation is left aligned
+ RIGHT //The equation is right aligned
+ };
+ // the stream to send the stream events to.
+ Stream * mpStream;
+
+ // the current global parser state
+ OOXMLParserState::Pointer_t mpParserState;
+
+ // the table depth of this context
+ unsigned int mnTableDepth;
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void lcl_endFastElement(Token_t Element);
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void lcl_characters(const OUString & aChars);
+
+ void startAction();
+ void endAction();
+
+ bool inPositionV;
+ bool mbAllowInCell; // o:allowincell
+ bool mbIsVMLfound;
+ OOXMLValue::Pointer_t mpGridAfter;
+
+private:
+ void operator =(OOXMLFastContextHandler const &) = delete;
+ /// Handles AlternateContent. Returns true, if children of the current element should be ignored.
+ bool prepareMceContext(Token_t nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs);
+
+ // 2.10 of XML 1.0 specification
+ bool IsPreserveSpace() const;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ bool m_bDiscardChildren;
+ bool m_bTookChoice; ///< Did we take the Choice or want Fallback instead?
+ bool mbPreserveSpace = false;
+ bool mbPreserveSpaceSet = false;
+
+};
+
+class OOXMLFastContextHandlerStream : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerStream(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerStream() override;
+
+ virtual ResourceEnum_t getResource() const override { return STREAM; }
+
+ const OOXMLPropertySet::Pointer_t& getPropertySetAttrs() const { return mpPropertySetAttrs;}
+
+ virtual void newProperty(Id aId, const OOXMLValue::Pointer_t& pVal) override;
+ void sendProperty(Id nId);
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const override;
+
+ void handleHyperlink();
+
+private:
+ mutable OOXMLPropertySet::Pointer_t mpPropertySetAttrs;
+};
+
+class OOXMLFastContextHandlerProperties : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerProperties(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerProperties() override;
+
+ virtual OOXMLValue::Pointer_t getValue() const override;
+ virtual ResourceEnum_t getResource() const override { return PROPERTIES; }
+
+ virtual void newProperty(Id nId, const OOXMLValue::Pointer_t& pVal) override;
+
+ void handleXNotes();
+ void handleHdrFtr();
+ void handleComment();
+ void handlePicture();
+ void handleBreak();
+ void handleOutOfOrderBreak();
+ void handleOLE();
+ void handleFontRel();
+ void handleHyperlinkURL();
+ void handleAltChunk();
+
+ virtual void setPropertySet(const OOXMLPropertySet::Pointer_t& pPropertySet) override;
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const override;
+
+protected:
+ /// the properties
+ OOXMLPropertySet::Pointer_t mpPropertySet;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+private:
+
+ bool mbResolve;
+};
+
+class OOXMLFastContextHandlerPropertyTable :
+ public OOXMLFastContextHandlerProperties
+{
+public:
+ explicit OOXMLFastContextHandlerPropertyTable(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerPropertyTable() override;
+
+private:
+ OOXMLTable mTable;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+};
+
+class OOXMLFastContextHandlerValue :
+ public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerValue(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerValue() override;
+
+ void setValue(const OOXMLValue::Pointer_t& pValue);
+ virtual OOXMLValue::Pointer_t getValue() const override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual std::string getType() const override { return "Value"; }
+
+ virtual void setDefaultBooleanValue() override;
+ virtual void setDefaultIntegerValue() override;
+ virtual void setDefaultHexValue() override;
+ virtual void setDefaultStringValue() override;
+
+ virtual void pushBiDiEmbedLevel() override;
+ virtual void popBiDiEmbedLevel() override;
+
+ void handleGridAfter();
+
+private:
+ OOXMLValue::Pointer_t mpValue;
+};
+
+class OOXMLFastContextHandlerTable : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTable(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerTable() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext (sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+private:
+ OOXMLTable mTable;
+
+ css::uno::Reference<css::xml::sax::XFastContextHandler> mCurrentChild;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual ResourceEnum_t getResource() const override { return TABLE; }
+
+ virtual std::string getType() const override { return "Table"; }
+
+ void addCurrentChild();
+};
+
+class OOXMLFastContextHandlerXNote : public OOXMLFastContextHandlerProperties
+{
+public:
+ explicit OOXMLFastContextHandlerXNote(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerXNote() override;
+
+ void checkId(const OOXMLValue::Pointer_t& pValue);
+
+ void checkType(const OOXMLValue::Pointer_t& pValue);
+
+ virtual std::string getType() const override { return "XNote"; }
+
+private:
+ bool mbForwardEventsSaved;
+ sal_Int32 mnMyXNoteId;
+ sal_Int32 mnMyXNoteType;
+
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual ResourceEnum_t getResource() const override { return STREAM; }
+};
+
+class OOXMLFastContextHandlerTextTableCell : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTextTableCell(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerTextTableCell() override;
+
+ virtual std::string getType() const override { return "TextTableCell"; }
+
+ void startCell();
+ void endCell();
+};
+
+class OOXMLFastContextHandlerTextTableRow : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTextTableRow(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerTextTableRow() override;
+
+ virtual std::string getType() const override { return "TextTableRow"; }
+
+ static void startRow();
+ void endRow();
+ void handleGridBefore( const OOXMLValue::Pointer_t& val );
+};
+
+class OOXMLFastContextHandlerTextTable : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTextTable(OOXMLFastContextHandler * pContext);
+
+ virtual ~OOXMLFastContextHandlerTextTable() override;
+
+ virtual std::string getType() const override { return "TextTable"; }
+
+ // tdf#111550
+ // when <w:tbl> appears as direct child of <w:p>, we need to rearrange this paragraph
+ // to merge with the table's first paragraph (that's what Word does in this case)
+ void start_P_Tbl();
+protected:
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+};
+
+class OOXMLFastContextHandlerShape: public OOXMLFastContextHandlerProperties
+{
+ bool m_bShapeSent;
+ bool m_bShapeStarted;
+ /// Is it necessary to pop the stack in the dtor?
+ bool m_bShapeContextPushed;
+ rtl::Reference<oox::shape::ShapeContextHandler> mrShapeContext;
+
+public:
+ explicit OOXMLFastContextHandlerShape(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerShape() override;
+
+ virtual std::string getType() const override { return "Shape"; }
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startUnknownElement (const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext(const OUString & Namespace, const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void setToken(Token_t nToken) override;
+
+ virtual ResourceEnum_t getResource() const override { return SHAPE; }
+
+ void sendShape( Token_t Element );
+ bool isShapeSent( ) const { return m_bShapeSent; }
+ bool isDMLGroupShape() const;
+
+protected:
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext (Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_characters(const OUString & aChars) override;
+
+};
+
+/**
+ OOXMLFastContextHandlerWrapper wraps an OOXMLFastContextHandler.
+
+ The method calls for the interface css::xml::sax::XFastContextHandler are
+ forwarded to the wrapped OOXMLFastContextHandler.
+ */
+class OOXMLFastContextHandlerWrapper : public OOXMLFastContextHandler
+{
+public:
+ OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent,
+ css::uno::Reference<css::xml::sax::XFastContextHandler> const & xContext,
+ rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler);
+ virtual ~OOXMLFastContextHandlerWrapper() override;
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startUnknownElement(const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext (const OUString & Namespace, const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void attributes(const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual ResourceEnum_t getResource() const override;
+
+ void addNamespace(Id nId);
+ void addToken( Token_t Element );
+
+ virtual void newProperty(Id nId, const OOXMLValue::Pointer_t& pVal) override;
+ virtual void setPropertySet(const OOXMLPropertySet::Pointer_t& pPropertySet) override;
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const override;
+
+ virtual std::string getType() const override;
+
+protected:
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_characters(const OUString & aChars) override;
+
+ virtual void setId(Id nId) override;
+ virtual Id getId() const override;
+
+ virtual void setToken(Token_t nToken) override;
+ virtual Token_t getToken() const override;
+
+private:
+ css::uno::Reference<css::xml::sax::XFastContextHandler> mxWrappedContext;
+ rtl::Reference<OOXMLFastContextHandlerShape> mxShapeHandler;
+ std::set<Id> mMyNamespaces;
+ std::set<Token_t> mMyTokens;
+ OOXMLPropertySet::Pointer_t mpPropertySet;
+
+ OOXMLFastContextHandler * getFastContextHandler() const;
+};
+
+/**
+ A class that converts from XFastParser/XFastContextHandler usage to a liner XML stream of data.
+
+ The purpose of this class is to convert the rather complex XFastContextHandler-based XML
+ processing that requires context subclasses, callbacks, etc. into a linear stream of XML tokens
+ that can be handled simply by reading the tokens one by one and directly processing them.
+ See the oox::formulaimport::XmlStream class documentation for more information.
+
+ Usage: Create a subclass of OOXMLFastContextHandlerLinear, reimplemented getType() to provide
+ type of the subclass and process() to actually process the XML stream. Also make sure to
+ add a line like the following to model.xml (for class OOXMLFastContextHandlerMath):
+
+ <resource name="CT_OMath" resource="Math"/>
+
+ @since 3.5
+*/
+class OOXMLFastContextHandlerLinear: public OOXMLFastContextHandlerProperties
+{
+public:
+ explicit OOXMLFastContextHandlerLinear(OOXMLFastContextHandler * pContext);
+ /**
+ Return the type of the class, as written in model.xml .
+ */
+ virtual std::string getType() const override = 0;
+
+protected:
+ /**
+ Called when the tokens for the element, its content and sub-elements have been linearized
+ and should be processed. The data member @ref buffer contains the converted data.
+ */
+ virtual void process() = 0;
+
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext(Token_t Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_characters(const OUString & aChars) override;
+
+ // should be private, but not much point in making deep copies of it
+ oox::formulaimport::XmlStreamBuilder buffer;
+
+private:
+ int depthCount;
+};
+
+class OOXMLFastContextHandlerMath: public OOXMLFastContextHandlerLinear
+{
+public:
+ explicit OOXMLFastContextHandlerMath(OOXMLFastContextHandler * pContext);
+ virtual std::string getType() const override { return "Math"; }
+protected:
+ virtual void process() override;
+};
+
+/**
+ A class that reads individual w15:commentEx elements from commentsExtended stream [MS-DOCX].
+
+ It is used to pre-populate the extended comment properties in domain mapper. The stream
+ contains information about resolved state of the comments ("done" attribute) and the parent
+ comment (the one that this comment answers to).
+
+ Note that the data is linked to paraId identifiers (also introduced in [MS-DOCX]), which
+ correspond to paragraphs, not directly to comment ids.
+
+ @since 7.2
+*/
+class OOXMLFastContextHandlerCommentEx : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerCommentEx(OOXMLFastContextHandler* pContext);
+
+ virtual std::string getType() const override { return "CommentEx"; }
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ void att_paraId(const OOXMLValue::Pointer_t& pValue);
+ void att_done(const OOXMLValue::Pointer_t& pValue);
+
+private:
+ OUString m_sParaId;
+ bool m_bDone = false;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFastDocumentHandler.cxx b/writerfilter/source/ooxml/OOXMLFastDocumentHandler.cxx
new file mode 100644
index 000000000..aba5ec0ac
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFastDocumentHandler.cxx
@@ -0,0 +1,146 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "OOXMLFastDocumentHandler.hxx"
+#include "OOXMLFastContextHandler.hxx"
+#include "OOXMLFactory.hxx"
+#include <sal/log.hxx>
+
+namespace writerfilter::ooxml
+{
+using namespace ::com::sun::star;
+using namespace ::std;
+
+
+OOXMLFastDocumentHandler::OOXMLFastDocumentHandler(
+ uno::Reference< uno::XComponentContext > const & context,
+ Stream* pStream,
+ OOXMLDocumentImpl* pDocument,
+ sal_Int32 nXNoteId )
+ : m_xContext(context)
+ , mpStream( pStream )
+ , mpDocument( pDocument )
+ , mnXNoteId( nXNoteId )
+{
+}
+
+OOXMLFastDocumentHandler::~OOXMLFastDocumentHandler() {}
+
+// css::xml::sax::XFastContextHandler:
+void SAL_CALL OOXMLFastDocumentHandler::startFastElement(sal_Int32 Element
+, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ SAL_INFO("writerfilter", "start element:" << fastTokenToId(Element));
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::startUnknownElement
+(const OUString & Namespace
+, const OUString & Name
+, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ SAL_INFO("writerfilter", "start unknown element:" << Namespace << ":" << Name);
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::endFastElement(sal_Int32 Element)
+{
+ SAL_INFO("writerfilter", "end element:" << fastTokenToId(Element));
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::endUnknownElement
+(const OUString & Namespace
+, const OUString & Name)
+{
+ SAL_INFO("writerfilter", "end unknown element:" << Namespace << ":" << Name);
+}
+
+rtl::Reference< OOXMLFastContextHandler > const &
+OOXMLFastDocumentHandler::getContextHandler() const
+{
+ if (!mxContextHandler.is())
+ {
+ mxContextHandler = new OOXMLFastContextHandler(m_xContext);
+ mxContextHandler->setStream(mpStream);
+ mxContextHandler->setDocument(mpDocument);
+ mxContextHandler->setXNoteId(mnXNoteId);
+ mxContextHandler->setForwardEvents(true);
+ }
+
+ return mxContextHandler;
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+ OOXMLFastDocumentHandler::createFastChildContext
+(::sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ if ( mpStream == nullptr && mpDocument == nullptr )
+ {
+ // document handler has been created as unknown child - see <OOXMLFastDocumentHandler::createUnknownChildContext(..)>
+ // --> do not provide a child context
+ return nullptr;
+ }
+
+ return OOXMLFactory::createFastChildContextFromStart(getContextHandler().get(), Element);
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastDocumentHandler::createUnknownChildContext
+(const OUString & Namespace
+, const OUString & Name
+, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ SAL_INFO("writerfilter", "createUnknownChildContext:" << Namespace << ":"<< Name);
+
+ return uno::Reference< xml::sax::XFastContextHandler >
+ ( new OOXMLFastDocumentHandler( m_xContext, nullptr, nullptr, 0 ) );
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::characters(const OUString & /*aChars*/)
+{
+}
+
+// css::xml::sax::XFastDocumentHandler:
+void SAL_CALL OOXMLFastDocumentHandler::startDocument()
+{
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::endDocument()
+{
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::processingInstruction( const OUString& /*rTarget*/, const OUString& /*rData*/ )
+{
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::setDocumentLocator
+(const uno::Reference< xml::sax::XLocator > & /*xLocator*/)
+{
+}
+
+void OOXMLFastDocumentHandler::setIsSubstream( bool bSubstream )
+{
+ if ( mpStream != nullptr && mpDocument != nullptr )
+ {
+ getContextHandler( )->getParserState( )->setInSectionGroup( bSubstream );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFastDocumentHandler.hxx b/writerfilter/source/ooxml/OOXMLFastDocumentHandler.hxx
new file mode 100644
index 000000000..8bcbdb68f
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFastDocumentHandler.hxx
@@ -0,0 +1,90 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
+#include <dmapper/resourcemodel.hxx>
+#include <ooxml/OOXMLDocumentImpl.hxx>
+#include <rtl/ref.hxx>
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLFastContextHandler;
+
+class OOXMLFastDocumentHandler : public cppu::WeakImplHelper<css::xml::sax::XFastDocumentHandler>
+{
+public:
+ OOXMLFastDocumentHandler(
+ css::uno::Reference< css::uno::XComponentContext > const & context,
+ Stream* pStream,
+ OOXMLDocumentImpl* pDocument,
+ sal_Int32 nXNoteId );
+ virtual ~OOXMLFastDocumentHandler() override;
+
+ // css::xml::sax::XFastDocumentHandler:
+ virtual void SAL_CALL startDocument() override;
+ virtual void SAL_CALL endDocument() override;
+ virtual void SAL_CALL processingInstruction( const OUString& rTarget, const OUString& rData ) override;
+ virtual void SAL_CALL setDocumentLocator
+ (const css::uno::Reference< css::xml::sax::XLocator > & xLocator) override;
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startFastElement
+ (::sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual void SAL_CALL startUnknownElement
+ (const OUString & Namespace,
+ const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual void SAL_CALL endFastElement(::sal_Int32 Element) override;
+ virtual void SAL_CALL endUnknownElement
+ (const OUString & Namespace,
+ const OUString & Name) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
+ createFastChildContext
+ (::sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
+ createUnknownChildContext
+ (const OUString & Namespace,
+ const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual void SAL_CALL characters(const OUString & aChars) override;
+
+ void setIsSubstream( bool bSubstream );
+
+private:
+ OOXMLFastDocumentHandler(OOXMLFastDocumentHandler const &) = delete;
+ void operator =(OOXMLFastDocumentHandler const &) = delete;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ Stream * mpStream;
+ OOXMLDocumentImpl* mpDocument;
+ sal_Int32 mnXNoteId;
+ mutable rtl::Reference<OOXMLFastContextHandler> mxContextHandler;
+ rtl::Reference<OOXMLFastContextHandler> const & getContextHandler() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLFastHelper.hxx b/writerfilter/source/ooxml/OOXMLFastHelper.hxx
new file mode 100644
index 000000000..ecb8b6943
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLFastHelper.hxx
@@ -0,0 +1,61 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "OOXMLFastContextHandler.hxx"
+
+namespace writerfilter::ooxml
+{
+
+template <class T>
+class OOXMLFastHelper
+{
+public:
+ static rtl::Reference<OOXMLFastContextHandler> createAndSetParentAndDefine
+ (OOXMLFastContextHandler * pHandler, sal_uInt32 nToken, Id nId, Id nDefine);
+
+ static void newProperty(OOXMLFastContextHandler * pHandler,
+ Id nId, sal_Int32 nValue);
+};
+
+template <class T>
+rtl::Reference<OOXMLFastContextHandler> OOXMLFastHelper<T>::createAndSetParentAndDefine (OOXMLFastContextHandler * pHandler, sal_uInt32 nToken, Id nId, Id nDefine)
+{
+ rtl::Reference<OOXMLFastContextHandler> pTmp = new T(pHandler);
+
+ pTmp->setToken(nToken);
+ pTmp->setId(nId);
+ pTmp->setDefine(nDefine);
+
+ return pTmp;
+}
+
+template <class T>
+void OOXMLFastHelper<T>::newProperty(OOXMLFastContextHandler * pHandler,
+ Id nId,
+ sal_Int32 nVal)
+{
+ OOXMLValue::Pointer_t pVal(T::Create(nVal));
+
+ pHandler->newProperty(nId, pVal);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLParserState.cxx b/writerfilter/source/ooxml/OOXMLParserState.cxx
new file mode 100644
index 000000000..a11afde8f
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLParserState.cxx
@@ -0,0 +1,286 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "OOXMLParserState.hxx"
+#include "Handler.hxx"
+
+#include <sal/log.hxx>
+
+namespace writerfilter::ooxml
+{
+/*
+ class OOXMLParserState
+*/
+
+OOXMLParserState::OOXMLParserState() :
+ mbInSectionGroup(false),
+ mbInParagraphGroup(false),
+ mbInCharacterGroup(false),
+ mbLastParagraphInSection(false),
+ mbForwardEvents(true),
+ mnContexts(0),
+ mnHandle(0),
+ mpDocument(nullptr),
+ inTxbxContent(false),
+ savedInParagraphGroup(false),
+ savedInCharacterGroup(false),
+ savedLastParagraphInSection(false),
+ mbStartFootnote(false)
+{
+}
+
+OOXMLParserState::~OOXMLParserState()
+{
+}
+
+void OOXMLParserState::setLastParagraphInSection(bool bLastParagraphInSection)
+{
+ mbLastParagraphInSection = bLastParagraphInSection;
+}
+
+
+void OOXMLParserState::setInSectionGroup(bool bInSectionGroup)
+{
+ mbInSectionGroup = bInSectionGroup;
+}
+
+
+void OOXMLParserState::setInParagraphGroup(bool bInParagraphGroup)
+{
+ mbInParagraphGroup = bInParagraphGroup;
+}
+
+
+void OOXMLParserState::setInCharacterGroup(bool bInCharacterGroup)
+{
+ mbInCharacterGroup = bInCharacterGroup;
+}
+
+void OOXMLParserState::setForwardEvents(bool bForwardEvents)
+{
+ mbForwardEvents = bForwardEvents;
+}
+
+
+std::string OOXMLParserState::getHandle() const
+{
+ return std::to_string(mnHandle);
+}
+
+void OOXMLParserState::setHandle()
+{
+ mnHandle = mnContexts;
+}
+
+void OOXMLParserState::setDocument(OOXMLDocumentImpl* pDocument)
+{
+ mpDocument = pDocument;
+}
+
+
+void OOXMLParserState::setXNoteId(const sal_Int32 nId)
+{
+ mpDocument->setXNoteId(nId);
+}
+
+sal_Int32 OOXMLParserState::getXNoteId() const
+{
+ return mpDocument->getXNoteId();
+}
+
+const OUString & OOXMLParserState::getTarget() const
+{
+ return mpDocument->getTarget();
+}
+
+void OOXMLParserState::resolveCharacterProperties(Stream & rStream)
+{
+ if (mpCharacterProps)
+ {
+ rStream.props(mpCharacterProps.get());
+ mpCharacterProps = new OOXMLPropertySet;
+ }
+}
+
+void OOXMLParserState::setCharacterProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mpCharacterProps)
+ mpCharacterProps = pProps;
+ else
+ mpCharacterProps->add(pProps);
+}
+
+void OOXMLParserState::setCellProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mCellProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rCellProps = mCellProps.top();
+
+ if (!rCellProps)
+ rCellProps = pProps;
+ else
+ rCellProps->add(pProps);
+ }
+}
+
+void OOXMLParserState::setRowProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mRowProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rRowProps = mRowProps.top();
+
+ if (!rRowProps)
+ rRowProps = pProps;
+ else
+ rRowProps->add(pProps);
+ }
+}
+
+void OOXMLParserState::resolveCellProperties(Stream & rStream)
+{
+ if (!mCellProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rCellProps = mCellProps.top();
+
+ if (rCellProps)
+ {
+ rStream.props(rCellProps.get());
+ rCellProps = new OOXMLPropertySet;
+ }
+ }
+}
+
+void OOXMLParserState::resolveRowProperties(Stream & rStream)
+{
+ if (!mRowProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rRowProps = mRowProps.top();
+
+ if (rRowProps)
+ {
+ rStream.props(rRowProps.get());
+ rRowProps = new OOXMLPropertySet;
+ }
+ }
+}
+
+void OOXMLParserState::resolveTableProperties(Stream & rStream)
+{
+ if (!mTableProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rTableProps = mTableProps.top();
+
+ if (rTableProps)
+ {
+ rStream.props(rTableProps.get());
+ // Don't clean the table props to send them again for each row
+ // This mimics the behaviour from RTF tokenizer.
+ }
+ }
+}
+
+void OOXMLParserState::setTableProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mTableProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rTableProps = mTableProps.top();
+ if (!rTableProps)
+ rTableProps = pProps;
+ else
+ rTableProps->add(pProps);
+ }
+}
+
+// tdf#108714
+void OOXMLParserState::resolvePostponedBreak(Stream & rStream)
+{
+ for (const auto & rBreak: mvPostponedBreaks)
+ {
+ OOXMLBreakHandler aBreakHandler(nullptr, rStream);
+ rBreak->resolve(aBreakHandler);
+ }
+ mvPostponedBreaks.clear();
+}
+
+void OOXMLParserState::setPostponedBreak(const OOXMLPropertySet::Pointer_t & pProps)
+{
+ mvPostponedBreaks.push_back(pProps);
+}
+
+void OOXMLParserState::startTable()
+{
+ OOXMLPropertySet::Pointer_t pCellProps;
+ OOXMLPropertySet::Pointer_t pRowProps;
+ OOXMLPropertySet::Pointer_t pTableProps;
+
+ mCellProps.push(pCellProps);
+ mRowProps.push(pRowProps);
+ mTableProps.push(pTableProps);
+}
+
+void OOXMLParserState::endTable()
+{
+ mCellProps.pop();
+ mRowProps.pop();
+ mTableProps.pop();
+}
+
+void OOXMLParserState::incContextCount()
+{
+ mnContexts++;
+}
+
+void OOXMLParserState::startTxbxContent()
+{
+ SAL_WARN_IF(inTxbxContent, "writerfilter", "Nested w:txbxContent");
+
+ inTxbxContent = true;
+ // Do not save and reset section group state, it'd cause a new page.
+// savedInSectionGroup = mbInSectionGroup;
+ savedInParagraphGroup = mbInParagraphGroup;
+ savedInCharacterGroup = mbInCharacterGroup;
+ savedLastParagraphInSection = mbLastParagraphInSection;
+// mbInSectionGroup = false;
+ mbInParagraphGroup = false;
+ mbInCharacterGroup = false;
+ mbLastParagraphInSection = false;
+}
+
+void OOXMLParserState::endTxbxContent()
+{
+ if( !inTxbxContent )
+ {
+ SAL_WARN( "writerfilter", "Non-matching closing w:txbxContent" );
+ return;
+ }
+// mbInSectionGroup = savedInSectionGroup;
+ mbInParagraphGroup = savedInParagraphGroup;
+ mbInCharacterGroup = savedInCharacterGroup;
+ mbLastParagraphInSection = savedLastParagraphInSection;
+ inTxbxContent = false;
+}
+
+void OOXMLParserState::setStartFootnote(bool bStartFootnote)
+{
+ mbStartFootnote = bStartFootnote;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLParserState.hxx b/writerfilter/source/ooxml/OOXMLParserState.hxx
new file mode 100644
index 000000000..5bb9a7dc7
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLParserState.hxx
@@ -0,0 +1,121 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <stack>
+#include "OOXMLDocumentImpl.hxx"
+#include "OOXMLPropertySet.hxx"
+
+namespace writerfilter::ooxml
+{
+/**
+ * Struct to store our 'alternate state'. If multiple mc:AlternateContent
+ * elements arrive, then while the inner ones are active, the original state is
+ * saved away, and once they inner goes out of scope, the original state is
+ * restored.
+ */
+struct SavedAlternateState
+{
+ bool m_bDiscardChildren;
+ bool m_bTookChoice; ///< Did we take the Choice or want Fallback instead?
+};
+
+class OOXMLParserState final : public virtual SvRefBase
+{
+ bool mbInSectionGroup;
+ bool mbInParagraphGroup;
+ bool mbInCharacterGroup;
+ bool mbLastParagraphInSection;
+ bool mbForwardEvents;
+ unsigned int mnContexts;
+ unsigned int mnHandle;
+ OOXMLDocumentImpl* mpDocument;
+ OOXMLPropertySet::Pointer_t mpCharacterProps;
+ std::stack<OOXMLPropertySet::Pointer_t> mCellProps;
+ std::stack<OOXMLPropertySet::Pointer_t> mRowProps;
+ std::stack<OOXMLPropertySet::Pointer_t> mTableProps;
+ bool inTxbxContent;
+ // these 4 save when inTxbxContent
+ bool savedInParagraphGroup;
+ bool savedInCharacterGroup;
+ bool savedLastParagraphInSection;
+ std::vector<SavedAlternateState> maSavedAlternateStates;
+ std::vector<OOXMLPropertySet::Pointer_t> mvPostponedBreaks;
+ bool mbStartFootnote;
+
+public:
+ typedef tools::SvRef<OOXMLParserState> Pointer_t;
+
+ OOXMLParserState();
+ ~OOXMLParserState() override;
+
+ bool isInSectionGroup() const { return mbInSectionGroup; }
+ void setInSectionGroup(bool bInSectionGroup);
+
+ void setLastParagraphInSection(bool bLastParagraphInSection);
+ bool isLastParagraphInSection() const { return mbLastParagraphInSection; }
+
+ std::vector<SavedAlternateState>& getSavedAlternateStates() { return maSavedAlternateStates; }
+
+ bool isInParagraphGroup() const { return mbInParagraphGroup; }
+ void setInParagraphGroup(bool bInParagraphGroup);
+
+ bool isInCharacterGroup() const { return mbInCharacterGroup; }
+ void setInCharacterGroup(bool bInCharacterGroup);
+
+ void setForwardEvents(bool bForwardEvents);
+ bool isForwardEvents() const { return mbForwardEvents; }
+
+ std::string getHandle() const;
+ void setHandle();
+
+ void setDocument(OOXMLDocumentImpl* pDocument);
+ OOXMLDocumentImpl* getDocument() const { return mpDocument; }
+
+ void setXNoteId(const sal_Int32 rId);
+ sal_Int32 getXNoteId() const;
+
+ const OUString& getTarget() const;
+
+ void resolveCharacterProperties(Stream& rStream);
+ void setCharacterProperties(const OOXMLPropertySet::Pointer_t& pProps);
+ void resolveCellProperties(Stream& rStream);
+ void setCellProperties(const OOXMLPropertySet::Pointer_t& pProps);
+ void resolveRowProperties(Stream& rStream);
+ void setRowProperties(const OOXMLPropertySet::Pointer_t& pProps);
+ void resolveTableProperties(Stream& rStream);
+ void setTableProperties(const OOXMLPropertySet::Pointer_t& pProps);
+ // tdf#108714
+ void resolvePostponedBreak(Stream& rStream);
+ void setPostponedBreak(const OOXMLPropertySet::Pointer_t& pProps);
+
+ void startTable();
+ void endTable();
+
+ void incContextCount();
+
+ void startTxbxContent();
+ void endTxbxContent();
+
+ void setStartFootnote(bool bStartFootnote);
+ bool isStartFootnote() const { return mbStartFootnote; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLPropertySet.cxx b/writerfilter/source/ooxml/OOXMLPropertySet.cxx
new file mode 100644
index 000000000..1d1724c9c
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLPropertySet.cxx
@@ -0,0 +1,857 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "OOXMLPropertySet.hxx"
+#include <stdio.h>
+#include <iostream>
+#include <ooxml/QNameToString.hxx>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <sax/tools/converter.hxx>
+#include <tools/color.hxx>
+
+namespace writerfilter::ooxml
+{
+using namespace ::std;
+using namespace com::sun::star;
+
+OOXMLProperty::OOXMLProperty(Id id, const OOXMLValue::Pointer_t& pValue,
+ OOXMLProperty::Type_t eType)
+ : mId(id), mpValue(pValue), meType(eType)
+{
+}
+
+OOXMLProperty::~OOXMLProperty()
+{
+}
+
+sal_uInt32 OOXMLProperty::getId() const
+{
+ return mId;
+}
+
+Value::Pointer_t OOXMLProperty::getValue()
+{
+ Value::Pointer_t pResult;
+
+ if (mpValue)
+ pResult = Value::Pointer_t(mpValue->clone());
+ else
+ pResult = Value::Pointer_t(new OOXMLValue());
+
+ return pResult;
+}
+
+writerfilter::Reference<Properties>::Pointer_t OOXMLProperty::getProps()
+{
+ writerfilter::Reference<Properties>::Pointer_t pResult;
+
+ if (mpValue)
+ pResult = mpValue->getProperties();
+
+ return pResult;
+}
+
+#ifdef DBG_UTIL
+string OOXMLProperty::getName() const
+{
+ string sResult(QNameToString(mId));
+
+ if (sResult.length() == 0)
+ sResult = fastTokenToId(mId);
+
+ if (sResult.length() == 0)
+ {
+ static char sBuffer[256];
+
+ snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32, mId);
+ sResult = sBuffer;
+ }
+
+ return sResult;
+}
+#endif
+
+#ifdef DBG_UTIL
+string OOXMLProperty::toString() const
+{
+ string sResult = "(";
+
+ sResult += getName();
+ sResult += ", ";
+ if (mpValue)
+ sResult += mpValue->toString();
+ else
+ sResult +="(null)";
+ sResult +=")";
+
+ return sResult;
+}
+#endif
+
+void OOXMLProperty::resolve(writerfilter::Properties & rProperties)
+{
+ switch (meType)
+ {
+ case SPRM:
+ if (mId != 0x0)
+ rProperties.sprm(*this);
+ break;
+ case ATTRIBUTE:
+ rProperties.attribute(mId, *getValue());
+ break;
+ }
+}
+
+/*
+ class OOXMLValue
+*/
+
+OOXMLValue::OOXMLValue()
+{
+}
+
+OOXMLValue::~OOXMLValue()
+{
+}
+
+int OOXMLValue::getInt() const
+{
+ return 0;
+}
+
+OUString OOXMLValue::getString() const
+{
+ return OUString();
+}
+
+uno::Any OOXMLValue::getAny() const
+{
+ return uno::Any();
+}
+
+writerfilter::Reference<Properties>::Pointer_t OOXMLValue::getProperties()
+{
+ return writerfilter::Reference<Properties>::Pointer_t();
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t OOXMLValue::getBinary()
+{
+ return writerfilter::Reference<BinaryObj>::Pointer_t();
+}
+
+#ifdef DBG_UTIL
+string OOXMLValue::toString() const
+{
+ return "OOXMLValue";
+}
+#endif
+
+OOXMLValue * OOXMLValue::clone() const
+{
+ return new OOXMLValue(*this);
+}
+
+/*
+ class OOXMLBinaryValue
+ */
+
+OOXMLBinaryValue::OOXMLBinaryValue(OOXMLBinaryObjectReference::Pointer_t const &
+ pBinaryObj)
+: mpBinaryObj(pBinaryObj)
+{
+}
+
+OOXMLBinaryValue::~OOXMLBinaryValue()
+{
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t OOXMLBinaryValue::getBinary()
+{
+ return mpBinaryObj;
+}
+
+#ifdef DBG_UTIL
+string OOXMLBinaryValue::toString() const
+{
+ return "BinaryObj";
+}
+#endif
+
+OOXMLValue * OOXMLBinaryValue::clone() const
+{
+ return new OOXMLBinaryValue(mpBinaryObj);
+}
+
+/*
+ class OOXMLBooleanValue
+*/
+
+static bool GetBooleanValue(const char *pValue)
+{
+ return !strcmp(pValue, "true")
+ || !strcmp(pValue, "True")
+ || !strcmp(pValue, "1")
+ || !strcmp(pValue, "on")
+ || !strcmp(pValue, "On");
+}
+
+OOXMLValue::Pointer_t const & OOXMLBooleanValue::Create(bool bValue)
+{
+ static OOXMLValue::Pointer_t False(new OOXMLBooleanValue (false));
+ static OOXMLValue::Pointer_t True(new OOXMLBooleanValue (true));
+
+ return bValue ? True : False;
+}
+
+OOXMLValue::Pointer_t const & OOXMLBooleanValue::Create(const char *pValue)
+{
+ return Create (GetBooleanValue(pValue));
+}
+
+OOXMLBooleanValue::OOXMLBooleanValue(bool bValue)
+: mbValue(bValue)
+{
+}
+
+OOXMLBooleanValue::~OOXMLBooleanValue()
+{
+}
+
+int OOXMLBooleanValue::getInt() const
+{
+ return mbValue ? 1 : 0;
+}
+
+uno::Any OOXMLBooleanValue::getAny() const
+{
+ return uno::Any(mbValue);
+}
+
+#ifdef DBG_UTIL
+string OOXMLBooleanValue::toString() const
+{
+ return mbValue ? "true" : "false";
+}
+#endif
+
+OOXMLValue * OOXMLBooleanValue::clone() const
+{
+ return new OOXMLBooleanValue(*this);
+}
+
+/*
+ class OOXMLStringValue
+*/
+
+OOXMLStringValue::OOXMLStringValue(const OUString & rStr)
+: mStr(rStr)
+{
+}
+
+OOXMLStringValue::~OOXMLStringValue()
+{
+}
+
+uno::Any OOXMLStringValue::getAny() const
+{
+ return uno::Any(mStr);
+}
+
+OUString OOXMLStringValue::getString() const
+{
+ return mStr;
+}
+
+#ifdef DBG_UTIL
+string OOXMLStringValue::toString() const
+{
+ return OUStringToOString(mStr, RTL_TEXTENCODING_ASCII_US).getStr();
+}
+#endif
+
+OOXMLValue * OOXMLStringValue::clone() const
+{
+ return new OOXMLStringValue(*this);
+}
+
+/*
+ class OOXMLInputStreamValue
+ */
+OOXMLInputStreamValue::OOXMLInputStreamValue(uno::Reference<io::XInputStream> const & xInputStream)
+: mxInputStream(xInputStream)
+{
+}
+
+OOXMLInputStreamValue::~OOXMLInputStreamValue()
+{
+}
+
+uno::Any OOXMLInputStreamValue::getAny() const
+{
+ return uno::Any(mxInputStream);
+}
+
+#ifdef DBG_UTIL
+string OOXMLInputStreamValue::toString() const
+{
+ return "InputStream";
+}
+#endif
+
+OOXMLValue * OOXMLInputStreamValue::clone() const
+{
+ return new OOXMLInputStreamValue(mxInputStream);
+}
+
+/**
+ class OOXMLPropertySet
+*/
+
+OOXMLPropertySet::OOXMLPropertySet()
+{
+}
+
+OOXMLPropertySet::~OOXMLPropertySet()
+{
+}
+
+void OOXMLPropertySet::resolve(Properties & rHandler)
+{
+ // The pProp->resolve(rHandler) call below can cause elements to
+ // be appended to mProperties. I don't think it can cause elements
+ // to be deleted. But let's check with < here just to be safe that
+ // the indexing below works.
+ for (size_t nIt = 0; nIt < mProperties.size(); ++nIt)
+ {
+ OOXMLProperty::Pointer_t pProp = mProperties[nIt];
+
+ if (pProp)
+ pProp->resolve(rHandler);
+ }
+}
+
+OOXMLPropertySet::OOXMLProperties_t::iterator OOXMLPropertySet::begin()
+{
+ return mProperties.begin();
+}
+
+OOXMLPropertySet::OOXMLProperties_t::iterator OOXMLPropertySet::end()
+{
+ return mProperties.end();
+}
+
+OOXMLPropertySet::OOXMLProperties_t::const_iterator
+OOXMLPropertySet::begin() const
+{
+ return mProperties.begin();
+}
+
+OOXMLPropertySet::OOXMLProperties_t::const_iterator
+OOXMLPropertySet::end() const
+{
+ return mProperties.end();
+}
+
+void OOXMLPropertySet::add(const OOXMLProperty::Pointer_t& pProperty)
+{
+ if (pProperty && pProperty->getId() != 0x0)
+ {
+ mProperties.push_back(pProperty);
+ }
+}
+
+void OOXMLPropertySet::add(Id id, const OOXMLValue::Pointer_t& pValue, OOXMLProperty::Type_t eType)
+{
+ OOXMLProperty::Pointer_t pProperty(new OOXMLProperty(id, pValue, eType));
+ add(pProperty);
+}
+
+void OOXMLPropertySet::add(const OOXMLPropertySet::Pointer_t& pPropertySet)
+{
+ const OOXMLPropertySet * pSet = pPropertySet.get();
+
+ if (pSet != nullptr)
+ {
+ mProperties.insert( mProperties.end(), pSet->mProperties.begin(), pSet->mProperties.end() );
+ }
+}
+
+OOXMLPropertySet * OOXMLPropertySet::clone() const
+{
+ return new OOXMLPropertySet(*this);
+}
+
+#ifdef DBG_UTIL
+string OOXMLPropertySet::toString()
+{
+ string sResult = "[";
+ char sBuffer[256];
+ snprintf(sBuffer, sizeof(sBuffer), "%p", this);
+ sResult += sBuffer;
+ sResult += ":";
+
+ OOXMLProperties_t::iterator aItBegin = begin();
+ OOXMLProperties_t::iterator aItEnd = end();
+
+ for (OOXMLProperties_t::iterator aIt = aItBegin; aIt != aItEnd; ++aIt)
+ {
+ if (aIt != aItBegin)
+ sResult += ", ";
+
+ if (*aIt)
+ sResult += (*aIt)->toString();
+ else
+ sResult += "0x0";
+ }
+
+ sResult += "]";
+
+ return sResult;
+}
+#endif
+
+/*
+ class OOXMLPropertySetValue
+*/
+
+OOXMLPropertySetValue::OOXMLPropertySetValue(const OOXMLPropertySet::Pointer_t& pPropertySet)
+ : mpPropertySet(pPropertySet)
+{
+}
+
+OOXMLPropertySetValue::~OOXMLPropertySetValue()
+{
+}
+
+writerfilter::Reference<Properties>::Pointer_t OOXMLPropertySetValue::getProperties()
+{
+ return writerfilter::Reference<Properties>::Pointer_t
+ (mpPropertySet->clone());
+}
+
+#ifdef DBG_UTIL
+string OOXMLPropertySetValue::toString() const
+{
+ char sBuffer[256];
+
+ snprintf(sBuffer, sizeof(sBuffer), "t:%p, m:%p", this, mpPropertySet.get());
+
+ return "OOXMLPropertySetValue(" + string(sBuffer) + ")";
+}
+#endif
+
+OOXMLValue * OOXMLPropertySetValue::clone() const
+{
+ return new OOXMLPropertySetValue(*this);
+}
+
+/*
+ class OOXMLIntegerValue
+*/
+
+OOXMLValue::Pointer_t OOXMLIntegerValue::Create(sal_Int32 nValue)
+{
+ static OOXMLValue::Pointer_t Zero(new OOXMLIntegerValue (0));
+ static OOXMLValue::Pointer_t One(new OOXMLIntegerValue (1));
+ static OOXMLValue::Pointer_t Two(new OOXMLIntegerValue (2));
+ static OOXMLValue::Pointer_t Three(new OOXMLIntegerValue (3));
+ static OOXMLValue::Pointer_t Four(new OOXMLIntegerValue (4));
+ static OOXMLValue::Pointer_t Five(new OOXMLIntegerValue (5));
+ static OOXMLValue::Pointer_t Six(new OOXMLIntegerValue (6));
+ static OOXMLValue::Pointer_t Seven(new OOXMLIntegerValue (7));
+ static OOXMLValue::Pointer_t Eight(new OOXMLIntegerValue (8));
+ static OOXMLValue::Pointer_t Nine(new OOXMLIntegerValue (9));
+
+ switch (nValue) {
+ case 0: return Zero;
+ case 1: return One;
+ case 2: return Two;
+ case 3: return Three;
+ case 4: return Four;
+ case 5: return Five;
+ case 6: return Six;
+ case 7: return Seven;
+ case 8: return Eight;
+ case 9: return Nine;
+ default: break;
+ }
+
+ OOXMLValue::Pointer_t value(new OOXMLIntegerValue(nValue));
+
+ return value;
+}
+
+OOXMLIntegerValue::OOXMLIntegerValue(sal_Int32 nValue)
+: mnValue(nValue)
+{
+}
+
+OOXMLIntegerValue::~OOXMLIntegerValue()
+{
+}
+
+int OOXMLIntegerValue::getInt() const
+{
+ return mnValue;
+}
+
+uno::Any OOXMLIntegerValue::getAny() const
+{
+ return uno::Any(mnValue);
+}
+
+OOXMLValue * OOXMLIntegerValue::clone() const
+{
+ return new OOXMLIntegerValue(*this);
+}
+
+#ifdef DBG_UTIL
+string OOXMLIntegerValue::toString() const
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "%" SAL_PRIdINT32, mnValue);
+
+ return buffer;
+}
+#endif
+
+/*
+ class OOXMLHexValue
+*/
+
+OOXMLHexValue::OOXMLHexValue(sal_uInt32 nValue)
+: mnValue(nValue)
+{
+}
+
+OOXMLHexValue::OOXMLHexValue(const char * pValue)
+: mnValue(rtl_str_toUInt32(pValue, 16))
+{
+}
+
+OOXMLHexValue::~OOXMLHexValue()
+{
+}
+
+int OOXMLHexValue::getInt() const
+{
+ return mnValue;
+}
+
+OOXMLValue * OOXMLHexValue::clone() const
+{
+ return new OOXMLHexValue(*this);
+}
+
+#ifdef DBG_UTIL
+string OOXMLHexValue::toString() const
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "0x%" SAL_PRIxUINT32, mnValue);
+
+ return buffer;
+}
+#endif
+
+/*
+ class OOXMLHexColorValue
+*/
+OOXMLHexColorValue::OOXMLHexColorValue(const char * pValue)
+ : OOXMLHexValue(sal_uInt32(COL_AUTO))
+{
+ if (!strcmp(pValue, "auto"))
+ return;
+
+ mnValue = rtl_str_toUInt32(pValue, 16);
+
+ // Convert hash-encoded values (like #FF0080)
+ const sal_Int32 nLen = strlen(pValue);
+ if ( !mnValue && nLen > 1 && pValue[0] == '#' )
+ {
+ sal_Int32 nColor(COL_AUTO);
+ // Word appears to require strict 6 digit length, else it ignores it
+ if ( nLen == 7 )
+ {
+ const OUString sHashColor(pValue, nLen, RTL_TEXTENCODING_ASCII_US);
+ sax::Converter::convertColor( nColor, sHashColor );
+ }
+ mnValue = nColor;
+ }
+}
+
+// OOXMLUniversalMeasureValue
+// ECMA-376 5th ed. Part 1 , 22.9.2.15
+OOXMLUniversalMeasureValue::OOXMLUniversalMeasureValue(const char * pValue, sal_uInt32 npPt)
+{
+ double val = rtl_str_toDouble(pValue); // will ignore the trailing unit
+
+ int nLen = strlen(pValue);
+ if (nLen > 2 &&
+ pValue[nLen-2] == 'p' &&
+ pValue[nLen-1] == 't')
+ {
+ mnValue = static_cast<int>(val * npPt);
+ }
+ else if (nLen > 2 &&
+ pValue[nLen - 2] == 'c' &&
+ pValue[nLen - 1] == 'm')
+ {
+ mnValue = static_cast<int>(val * npPt * 72 / 2.54);
+ }
+ else if (nLen > 2 &&
+ pValue[nLen - 2] == 'm' &&
+ pValue[nLen - 1] == 'm')
+ {
+ mnValue = static_cast<int>(val * npPt * 72 / 25.4);
+ }
+ else if (nLen > 2 &&
+ pValue[nLen - 2] == 'i' &&
+ pValue[nLen - 1] == 'n')
+ {
+ mnValue = static_cast<int>(val * npPt * 72);
+ }
+ else if (nLen > 2 &&
+ pValue[nLen - 2] == 'p' &&
+ ( pValue[nLen - 1] == 'c' || pValue[nLen - 1] == 'i' ))
+ {
+ mnValue = static_cast<int>(val * npPt * 12);
+ }
+ else
+ {
+ mnValue = static_cast<int>(val);
+ }
+}
+
+OOXMLUniversalMeasureValue::~OOXMLUniversalMeasureValue()
+{
+}
+
+int OOXMLUniversalMeasureValue::getInt() const
+{
+ return mnValue;
+}
+
+#ifdef DBG_UTIL
+string OOXMLUniversalMeasureValue::toString() const
+{
+ return OString::number(mnValue).getStr();
+}
+#endif
+
+// OOXMLMeasurementOrPercentValue
+// ECMA-376 5th ed. Part 1 , 17.18.107; 17.18.11
+OOXMLMeasurementOrPercentValue::OOXMLMeasurementOrPercentValue(const char * pValue)
+{
+ double val = rtl_str_toDouble(pValue); // will ignore the trailing unit
+
+ int nLen = strlen(pValue);
+ if (nLen > 1 &&
+ pValue[nLen - 1] == '%')
+ {
+ mnValue = static_cast<int>(val * 50);
+ }
+ else
+ {
+ mnValue = OOXMLTwipsMeasureValue(pValue).getInt();
+ }
+}
+
+int OOXMLMeasurementOrPercentValue::getInt() const
+{
+ return mnValue;
+}
+
+#ifdef DBG_UTIL
+string OOXMLMeasurementOrPercentValue::toString() const
+{
+ return OString::number(mnValue).getStr();
+}
+#endif
+
+/*
+ class OOXMLShapeValue
+ */
+
+
+OOXMLShapeValue::OOXMLShapeValue(uno::Reference<drawing::XShape> const & rShape)
+: mrShape(rShape)
+{
+}
+
+OOXMLShapeValue::~OOXMLShapeValue()
+{
+}
+
+uno::Any OOXMLShapeValue::getAny() const
+{
+ return uno::Any(mrShape);
+}
+
+#ifdef DBG_UTIL
+string OOXMLShapeValue::toString() const
+{
+ return "Shape";
+}
+#endif
+
+OOXMLValue * OOXMLShapeValue::clone() const
+{
+ return new OOXMLShapeValue(mrShape);
+}
+
+/*
+ class OOXMLStarMathValue
+ */
+
+
+OOXMLStarMathValue::OOXMLStarMathValue( uno::Reference< embed::XEmbeddedObject > const & c )
+: component(c)
+{
+}
+
+OOXMLStarMathValue::~OOXMLStarMathValue()
+{
+}
+
+uno::Any OOXMLStarMathValue::getAny() const
+{
+ return uno::Any(component);
+}
+
+#ifdef DBG_UTIL
+string OOXMLStarMathValue::toString() const
+{
+ return "StarMath";
+}
+#endif
+
+OOXMLValue * OOXMLStarMathValue::clone() const
+{
+ return new OOXMLStarMathValue( component );
+}
+
+/*
+ class OOXMLTableImpl
+ */
+
+OOXMLTable::OOXMLTable()
+{
+}
+
+OOXMLTable::~OOXMLTable()
+{
+}
+
+
+void OOXMLTable::resolve(Table & rTable)
+{
+ Table * pTable = &rTable;
+
+ int nPos = 0;
+
+ for (const auto& rPropSet : mPropertySets)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ (rPropSet->getProperties());
+
+ if (pProperties)
+ pTable->entry(nPos, pProperties);
+
+ ++nPos;
+ }
+}
+
+void OOXMLTable::add(const ValuePointer_t& pPropertySet)
+{
+ if (pPropertySet)
+ mPropertySets.push_back(pPropertySet);
+}
+
+OOXMLTable * OOXMLTable::clone() const
+{
+ return new OOXMLTable(*this);
+}
+
+/*
+ class: OOXMLPropertySetEntryToString
+*/
+
+OOXMLPropertySetEntryToString::OOXMLPropertySetEntryToString(Id nId)
+: mnId(nId)
+{
+}
+
+OOXMLPropertySetEntryToString::~OOXMLPropertySetEntryToString()
+{
+}
+
+void OOXMLPropertySetEntryToString::sprm(Sprm & /*rSprm*/)
+{
+}
+
+void OOXMLPropertySetEntryToString::attribute(Id nId, Value & rValue)
+{
+ if (nId == mnId)
+ mStr = rValue.getString();
+}
+
+/*
+ class: OOXMLPropertySetEntryToInteger
+*/
+
+OOXMLPropertySetEntryToInteger::OOXMLPropertySetEntryToInteger(Id nId)
+: mnId(nId), mnValue(0)
+{
+}
+
+OOXMLPropertySetEntryToInteger::~OOXMLPropertySetEntryToInteger()
+{
+}
+
+void OOXMLPropertySetEntryToInteger::sprm(Sprm & /*rSprm*/)
+{
+}
+
+void OOXMLPropertySetEntryToInteger::attribute(Id nId, Value & rValue)
+{
+ if (nId == mnId)
+ mnValue = rValue.getInt();
+}
+
+/*
+ class: OOXMLPropertySetEntryToBool
+*/
+
+OOXMLPropertySetEntryToBool::OOXMLPropertySetEntryToBool(Id nId)
+ : mnId(nId), mValue(false)
+{}
+
+OOXMLPropertySetEntryToBool::~OOXMLPropertySetEntryToBool() {}
+
+void OOXMLPropertySetEntryToBool::sprm(Sprm & /*rSprm*/) {}
+
+void OOXMLPropertySetEntryToBool::attribute(Id nId, Value & rValue)
+{
+ if (nId == mnId)
+ mValue = (rValue.getInt() != 0);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLPropertySet.hxx b/writerfilter/source/ooxml/OOXMLPropertySet.hxx
new file mode 100644
index 000000000..b30fbaf61
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLPropertySet.hxx
@@ -0,0 +1,413 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+#include "OOXMLBinaryObjectReference.hxx"
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::ooxml
+{
+class OOXMLValue : public Value
+{
+public:
+ typedef tools::SvRef<OOXMLValue> Pointer_t;
+ OOXMLValue();
+ virtual ~OOXMLValue() override;
+
+ OOXMLValue(OOXMLValue const&) = default;
+ OOXMLValue(OOXMLValue&&) = default;
+ OOXMLValue& operator=(OOXMLValue const&) = default;
+ OOXMLValue& operator=(OOXMLValue&&) = default;
+
+ virtual int getInt() const override;
+ ;
+ virtual OUString getString() const override;
+ virtual css::uno::Any getAny() const override;
+ virtual writerfilter::Reference<Properties>::Pointer_t getProperties() override;
+ virtual writerfilter::Reference<BinaryObj>::Pointer_t getBinary() override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const;
+};
+
+class OOXMLProperty : public Sprm
+{
+public:
+ typedef tools::SvRef<OOXMLProperty> Pointer_t;
+ enum Type_t
+ {
+ SPRM,
+ ATTRIBUTE
+ };
+
+private:
+ Id mId;
+ mutable OOXMLValue::Pointer_t mpValue;
+ Type_t meType;
+
+public:
+ OOXMLProperty(Id id, const OOXMLValue::Pointer_t& pValue, Type_t eType);
+ OOXMLProperty(const OOXMLProperty& rSprm) = delete;
+ virtual ~OOXMLProperty() override;
+
+ sal_uInt32 getId() const override;
+ Value::Pointer_t getValue() override;
+ writerfilter::Reference<Properties>::Pointer_t getProps() override;
+#ifdef DBG_UTIL
+ std::string getName() const override;
+ std::string toString() const override;
+#endif
+ void resolve(Properties& rProperties);
+};
+
+class OOXMLBinaryValue : public OOXMLValue
+{
+ mutable OOXMLBinaryObjectReference::Pointer_t mpBinaryObj;
+
+public:
+ explicit OOXMLBinaryValue(OOXMLBinaryObjectReference::Pointer_t const& pBinaryObj);
+ virtual ~OOXMLBinaryValue() override;
+
+ virtual writerfilter::Reference<BinaryObj>::Pointer_t getBinary() override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLBooleanValue : public OOXMLValue
+{
+ bool mbValue;
+ explicit OOXMLBooleanValue(bool bValue);
+
+public:
+ static OOXMLValue::Pointer_t const& Create(bool bValue);
+ static OOXMLValue::Pointer_t const& Create(const char* pValue);
+
+ virtual ~OOXMLBooleanValue() override;
+
+ OOXMLBooleanValue(OOXMLBooleanValue const&) = default;
+ OOXMLBooleanValue(OOXMLBooleanValue&&) = default;
+ OOXMLBooleanValue& operator=(OOXMLBooleanValue const&) = delete; // due to const mbValue
+ OOXMLBooleanValue& operator=(OOXMLBooleanValue&&) = delete; // due to const mbValue
+
+ virtual int getInt() const override;
+ virtual css::uno::Any getAny() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLStringValue : public OOXMLValue
+{
+ OUString mStr;
+
+public:
+ explicit OOXMLStringValue(const OUString& rStr);
+ virtual ~OOXMLStringValue() override;
+
+ OOXMLStringValue(OOXMLStringValue const&) = default;
+ OOXMLStringValue(OOXMLStringValue&&) = default;
+ OOXMLStringValue& operator=(OOXMLStringValue const&) = delete; // due to const mStr
+ OOXMLStringValue& operator=(OOXMLStringValue&&) = delete; // due to const mStr
+
+ virtual css::uno::Any getAny() const override;
+ virtual OUString getString() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLInputStreamValue : public OOXMLValue
+{
+ css::uno::Reference<css::io::XInputStream> mxInputStream;
+
+public:
+ explicit OOXMLInputStreamValue(css::uno::Reference<css::io::XInputStream> const& xInputStream);
+ virtual ~OOXMLInputStreamValue() override;
+
+ virtual css::uno::Any getAny() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLPropertySet : public writerfilter::Reference<Properties>
+{
+public:
+ typedef std::vector<OOXMLProperty::Pointer_t> OOXMLProperties_t;
+ typedef tools::SvRef<OOXMLPropertySet> Pointer_t;
+
+private:
+ OOXMLProperties_t mProperties;
+ void add(const OOXMLProperty::Pointer_t& pProperty);
+
+public:
+ OOXMLPropertySet();
+ virtual ~OOXMLPropertySet() override;
+
+ OOXMLPropertySet(OOXMLPropertySet const&) = default;
+ OOXMLPropertySet(OOXMLPropertySet&&) = default;
+ OOXMLPropertySet& operator=(OOXMLPropertySet const&) = default;
+ OOXMLPropertySet& operator=(OOXMLPropertySet&&) = default;
+
+ void resolve(Properties& rHandler) override;
+ void add(Id id, const OOXMLValue::Pointer_t& pValue, OOXMLProperty::Type_t eType);
+ void add(const OOXMLPropertySet::Pointer_t& pPropertySet);
+ OOXMLPropertySet* clone() const;
+
+ OOXMLProperties_t::iterator begin();
+ OOXMLProperties_t::iterator end();
+ OOXMLProperties_t::const_iterator begin() const;
+ OOXMLProperties_t::const_iterator end() const;
+
+#ifdef DBG_UTIL
+ std::string toString();
+#endif
+};
+
+class OOXMLValue;
+
+class OOXMLTable : public writerfilter::Reference<Table>
+{
+public:
+ typedef tools::SvRef<OOXMLValue> ValuePointer_t;
+ OOXMLTable();
+ virtual ~OOXMLTable() override;
+
+ OOXMLTable(OOXMLTable const&) = default;
+ OOXMLTable(OOXMLTable&&) = default;
+ OOXMLTable& operator=(OOXMLTable const&) = default;
+ OOXMLTable& operator=(OOXMLTable&&) = default;
+
+ void resolve(Table& rTable) override;
+ void add(const ValuePointer_t& pPropertySet);
+ OOXMLTable* clone() const;
+
+private:
+ typedef std::vector<ValuePointer_t> PropertySets_t;
+ PropertySets_t mPropertySets;
+};
+
+class OOXMLPropertySetValue : public OOXMLValue
+{
+ OOXMLPropertySet::Pointer_t mpPropertySet;
+
+public:
+ explicit OOXMLPropertySetValue(const OOXMLPropertySet::Pointer_t& pPropertySet);
+ virtual ~OOXMLPropertySetValue() override;
+
+ OOXMLPropertySetValue(OOXMLPropertySetValue const&) = default;
+ OOXMLPropertySetValue(OOXMLPropertySetValue&&) = default;
+ OOXMLPropertySetValue& operator=(OOXMLPropertySetValue const&)
+ = delete; // due to const mpPropertySet
+ OOXMLPropertySetValue& operator=(OOXMLPropertySetValue&&)
+ = delete; // due to const mpPropertySet
+
+ virtual writerfilter::Reference<Properties>::Pointer_t getProperties() override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLIntegerValue : public OOXMLValue
+{
+ sal_Int32 mnValue;
+ explicit OOXMLIntegerValue(sal_Int32 nValue);
+
+public:
+ static OOXMLValue::Pointer_t Create(sal_Int32 nValue);
+ virtual ~OOXMLIntegerValue() override;
+
+ OOXMLIntegerValue(OOXMLIntegerValue const&) = default;
+ OOXMLIntegerValue(OOXMLIntegerValue&&) = default;
+ OOXMLIntegerValue& operator=(OOXMLIntegerValue const&) = delete; // due to const mnValue
+ OOXMLIntegerValue& operator=(OOXMLIntegerValue&&) = delete; // due to const mnValue
+
+ virtual int getInt() const override;
+ virtual css::uno::Any getAny() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLHexValue : public OOXMLValue
+{
+protected:
+ sal_uInt32 mnValue;
+
+public:
+ explicit OOXMLHexValue(sal_uInt32 nValue);
+ explicit OOXMLHexValue(const char* pValue);
+ virtual ~OOXMLHexValue() override;
+
+ OOXMLHexValue(OOXMLHexValue const&) = default;
+ OOXMLHexValue(OOXMLHexValue&&) = default;
+ OOXMLHexValue& operator=(OOXMLHexValue const&) = default;
+ OOXMLHexValue& operator=(OOXMLHexValue&&) = default;
+
+ virtual int getInt() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLHexColorValue : public OOXMLHexValue
+{
+public:
+ explicit OOXMLHexColorValue(const char* pValue);
+};
+
+class OOXMLUniversalMeasureValue : public OOXMLValue
+{
+private:
+ int mnValue;
+
+public:
+ OOXMLUniversalMeasureValue(const char* pValue, sal_uInt32 npPt);
+ virtual ~OOXMLUniversalMeasureValue() override;
+
+ OOXMLUniversalMeasureValue(OOXMLUniversalMeasureValue const&) = default;
+ OOXMLUniversalMeasureValue(OOXMLUniversalMeasureValue&&) = default;
+ OOXMLUniversalMeasureValue& operator=(OOXMLUniversalMeasureValue const&) = default;
+ OOXMLUniversalMeasureValue& operator=(OOXMLUniversalMeasureValue&&) = default;
+
+ virtual int getInt() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+};
+
+/// npPt is quotient defining how much units are in 1 pt
+template <sal_uInt32 npPt> class OOXMLNthPtMeasureValue : public OOXMLUniversalMeasureValue
+{
+public:
+ explicit OOXMLNthPtMeasureValue(const char* pValue)
+ : OOXMLUniversalMeasureValue(pValue, npPt)
+ {
+ }
+ virtual OOXMLValue* clone() const override { return new OOXMLNthPtMeasureValue<npPt>(*this); }
+};
+
+/// Handles OOXML's ST_TwipsMeasure value.
+typedef OOXMLNthPtMeasureValue<20> OOXMLTwipsMeasureValue;
+
+/// Handles OOXML's ST_HpsMeasure value.
+typedef OOXMLNthPtMeasureValue<2> OOXMLHpsMeasureValue;
+
+class OOXMLMeasurementOrPercentValue : public OOXMLValue
+{
+ int mnValue;
+
+public:
+ explicit OOXMLMeasurementOrPercentValue(const char* pValue);
+
+ virtual int getInt() const override;
+ virtual OOXMLValue* clone() const override { return new OOXMLMeasurementOrPercentValue(*this); }
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+};
+
+class OOXMLShapeValue : public OOXMLValue
+{
+ css::uno::Reference<css::drawing::XShape> mrShape;
+
+public:
+ explicit OOXMLShapeValue(css::uno::Reference<css::drawing::XShape> const& rShape);
+ virtual ~OOXMLShapeValue() override;
+
+ virtual css::uno::Any getAny() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLStarMathValue : public OOXMLValue
+{
+ css::uno::Reference<css::embed::XEmbeddedObject> component;
+
+public:
+ explicit OOXMLStarMathValue(css::uno::Reference<css::embed::XEmbeddedObject> const& component);
+ virtual ~OOXMLStarMathValue() override;
+
+ virtual css::uno::Any getAny() const override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const override;
+};
+
+class OOXMLPropertySetEntryToString : public Properties
+{
+ Id mnId;
+ OUString mStr;
+
+public:
+ explicit OOXMLPropertySetEntryToString(Id nId);
+ virtual ~OOXMLPropertySetEntryToString() override;
+
+ virtual void sprm(Sprm& rSprm) override;
+ virtual void attribute(Id nId, Value& rValue) override;
+
+ const OUString& getString() const { return mStr; }
+};
+
+class OOXMLPropertySetEntryToInteger : public Properties
+{
+ Id mnId;
+ int mnValue;
+
+public:
+ explicit OOXMLPropertySetEntryToInteger(Id nId);
+ virtual ~OOXMLPropertySetEntryToInteger() override;
+
+ virtual void sprm(Sprm& rSprm) override;
+ virtual void attribute(Id nId, Value& rValue) override;
+
+ int getValue() const { return mnValue; }
+};
+
+class OOXMLPropertySetEntryToBool : public Properties
+{
+ Id mnId;
+ bool mValue;
+
+public:
+ explicit OOXMLPropertySetEntryToBool(Id nId);
+ virtual ~OOXMLPropertySetEntryToBool() override;
+
+ virtual void sprm(Sprm& rSprm) override;
+ virtual void attribute(Id nId, Value& rValue) override;
+
+ bool getValue() const { return mValue; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
new file mode 100644
index 000000000..1cfd48139
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
@@ -0,0 +1,448 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "OOXMLStreamImpl.hxx"
+#include <oox/core/fasttokenhandler.hxx>
+
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <comphelper/storagehelper.hxx>
+
+namespace writerfilter::ooxml
+{
+
+using namespace com::sun::star;
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(uno::Reference<uno::XComponentContext> const & xContext,
+ uno::Reference<io::XInputStream> const & xStorageStream,
+ StreamType_t nType, bool bRepairStorage)
+: mxContext(xContext), mxStorageStream(xStorageStream), mnStreamType(nType)
+{
+ mxStorage.set
+ (comphelper::OStorageHelper::GetStorageOfFormatFromInputStream
+ (OFOPXML_STORAGE_FORMAT_STRING, mxStorageStream, xContext, bRepairStorage));
+ mxRelationshipAccess.set(mxStorage, uno::UNO_QUERY_THROW);
+
+ init();
+}
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(OOXMLStreamImpl const & rOOXMLStream, StreamType_t nStreamType)
+: mxContext(rOOXMLStream.mxContext),
+ mxStorageStream(rOOXMLStream.mxStorageStream),
+ mxStorage(rOOXMLStream.mxStorage),
+ mnStreamType(nStreamType),
+ msPath(rOOXMLStream.msPath)
+{
+ mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ init();
+}
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(OOXMLStreamImpl const & rOOXMLStream, const OUString & rId)
+: mxContext(rOOXMLStream.mxContext),
+ mxStorageStream(rOOXMLStream.mxStorageStream),
+ mxStorage(rOOXMLStream.mxStorage),
+ mnStreamType(UNKNOWN),
+ msId(rId),
+ msPath(rOOXMLStream.msPath)
+{
+ mxRelationshipAccess.set(rOOXMLStream.mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ init();
+}
+
+OOXMLStreamImpl::~OOXMLStreamImpl()
+{
+}
+
+const OUString & OOXMLStreamImpl::getTarget() const
+{
+ return msTarget;
+}
+
+bool OOXMLStreamImpl::lcl_getTarget(const uno::Reference<embed::XRelationshipAccess>&
+ xRelationshipAccess,
+ StreamType_t nStreamType,
+ const OUString & rId,
+ OUString & rDocumentTarget)
+{
+ static const char sId[] = "Id";
+ static const char sTarget[] = "Target";
+ static const char sTargetMode[] = "TargetMode";
+ static const char sExternal[] = "External";
+ if (maIdCache.empty())
+ {
+ // Cache is empty? Then let's build it!
+ const uno::Sequence< uno::Sequence<beans::StringPair> >aSeqs = xRelationshipAccess->getAllRelationships();
+ for (const uno::Sequence<beans::StringPair>& rSeq : aSeqs)
+ {
+ OUString aId;
+ OUString aTarget;
+ bool bExternal = false;
+ for (const beans::StringPair& rPair : rSeq)
+ {
+ if (rPair.First == sId)
+ aId = rPair.Second;
+ else if (rPair.First == sTarget)
+ aTarget = rPair.Second;
+ else if (rPair.First == sTargetMode && rPair.Second == sExternal)
+ bExternal = true;
+ }
+ // Only cache external targets, internal ones are more complex (see below)
+ if (bExternal || aTarget.startsWith("#"))
+ maIdCache[aId] = aTarget;
+ }
+ }
+
+ if (maIdCache.find(rId) != maIdCache.end())
+ {
+ rDocumentTarget = maIdCache[rId];
+ return true;
+ }
+
+ bool bFound = false;
+ static uno::Reference<uri::XUriReferenceFactory> xFac = uri::UriReferenceFactory::create(mxContext);
+ // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
+ // keep the XUriReference implementation happy )
+ // add mspath to represent the 'source' of this stream
+ uno::Reference<uri::XUriReference> xBase = xFac->parse("file:///" + msPath);
+
+ static const char sType[] = "Type";
+ static const OUStringLiteral sDocumentType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+ static const OUStringLiteral sStylesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+ static const OUStringLiteral sNumberingType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
+ static const OUStringLiteral sFonttableType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
+ static const OUStringLiteral sFootnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
+ static const OUStringLiteral sEndnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
+ static const OUStringLiteral sCommentsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
+ static const OUStringLiteral sThemeType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
+ static const OUStringLiteral sCustomType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
+ static const OUStringLiteral sCustomPropsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
+ static const OUStringLiteral sGlossaryType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument";
+ static const OUStringLiteral sWebSettings = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
+ static const OUStringLiteral sSettingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
+ static const OUStringLiteral sChartType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
+ static const OUStringLiteral sEmbeddingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
+ static const OUStringLiteral sFooterType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
+ static const OUStringLiteral sHeaderType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
+ static const OUStringLiteral sOleObjectType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
+ static const OUStringLiteral sCommentsExtendedType = u"http://schemas.microsoft.com/office/2011/relationships/commentsExtended";
+ // OOXML strict
+ static const OUStringLiteral sDocumentTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
+ static const OUStringLiteral sStylesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
+ static const OUStringLiteral sNumberingTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/numbering";
+ static const OUStringLiteral sFonttableTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
+ static const OUStringLiteral sFootnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes";
+ static const OUStringLiteral sEndnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes";
+ static const OUStringLiteral sCommentsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/comments";
+ static const OUStringLiteral sThemeTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/theme";
+ static const OUStringLiteral sCustomTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
+ static const OUStringLiteral sCustomPropsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps";
+ static const OUStringLiteral sGlossaryTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument";
+ static const OUStringLiteral sWebSettingsStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
+ static const OUStringLiteral sSettingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
+ static const OUStringLiteral sChartTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/chart";
+ static const OUStringLiteral sEmbeddingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/package";
+ static const OUStringLiteral sFootersTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footer";
+ static const OUStringLiteral sHeaderTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/header";
+ static const OUStringLiteral sOleObjectTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject";
+ static const OUStringLiteral sVBAProjectType = u"http://schemas.microsoft.com/office/2006/relationships/vbaProject";
+ static const OUStringLiteral sVBADataType = u"http://schemas.microsoft.com/office/2006/relationships/wordVbaData";
+
+ OUString sStreamType;
+ OUString sStreamTypeStrict;
+
+ switch (nStreamType)
+ {
+ case VBAPROJECT:
+ sStreamType = sVBAProjectType;
+ sStreamTypeStrict = sVBAProjectType;
+ break;
+ case VBADATA:
+ sStreamType = sVBADataType;
+ sStreamTypeStrict = sVBADataType;
+ break;
+ case DOCUMENT:
+ sStreamType = sDocumentType;
+ sStreamTypeStrict = sDocumentTypeStrict;
+ break;
+ case STYLES:
+ sStreamType = sStylesType;
+ sStreamTypeStrict = sStylesTypeStrict;
+ break;
+ case NUMBERING:
+ sStreamType = sNumberingType;
+ sStreamTypeStrict = sNumberingTypeStrict;
+ break;
+ case FONTTABLE:
+ sStreamType = sFonttableType;
+ sStreamTypeStrict = sFonttableTypeStrict;
+ break;
+ case FOOTNOTES:
+ sStreamType = sFootnotesType;
+ sStreamTypeStrict = sFootnotesTypeStrict;
+ break;
+ case ENDNOTES:
+ sStreamType = sEndnotesType;
+ sStreamTypeStrict = sEndnotesTypeStrict;
+ break;
+ case COMMENTS:
+ sStreamType = sCommentsType;
+ sStreamTypeStrict = sCommentsTypeStrict;
+ break;
+ case THEME:
+ sStreamType = sThemeType;
+ sStreamTypeStrict = sThemeTypeStrict;
+ break;
+ case CUSTOMXML:
+ sStreamType = sCustomType;
+ sStreamTypeStrict = sCustomTypeStrict;
+ break;
+ case CUSTOMXMLPROPS:
+ sStreamType = sCustomPropsType;
+ sStreamTypeStrict = sCustomPropsTypeStrict;
+ break;
+ case SETTINGS:
+ sStreamType = sSettingsType;
+ sStreamTypeStrict = sSettingsTypeStrict;
+ break;
+ case GLOSSARY:
+ sStreamType = sGlossaryType;
+ sStreamTypeStrict = sGlossaryTypeStrict;
+ break;
+ case WEBSETTINGS:
+ sStreamType = sWebSettings;
+ sStreamTypeStrict = sWebSettingsStrict;
+ break;
+ case CHARTS:
+ sStreamType = sChartType;
+ sStreamTypeStrict = sChartTypeStrict;
+ break;
+ case EMBEDDINGS:
+ sStreamType = sEmbeddingsType;
+ sStreamTypeStrict = sEmbeddingsTypeStrict;
+ break;
+ case FOOTER:
+ sStreamType = sFooterType;
+ sStreamTypeStrict = sFootersTypeStrict;
+ break;
+ case HEADER:
+ sStreamType = sHeaderType;
+ sStreamTypeStrict = sHeaderTypeStrict;
+ break;
+ case COMMENTS_EXTENDED:
+ sStreamType = sCommentsExtendedType;
+ sStreamTypeStrict = sCommentsExtendedType;
+ break;
+ default:
+ break;
+ }
+
+ if (xRelationshipAccess.is())
+ {
+ const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
+ xRelationshipAccess->getAllRelationships();
+
+ for (const uno::Sequence< beans::StringPair > &rSeq : aSeqs)
+ {
+ bool bExternalTarget = false;
+ OUString sMyTarget;
+ for (const beans::StringPair &rPair : rSeq)
+ {
+ if (rPair.First == sType &&
+ ( rPair.Second == sStreamType ||
+ rPair.Second == sStreamTypeStrict ))
+ bFound = true;
+ else if(rPair.First == sType &&
+ ((rPair.Second == sOleObjectType ||
+ rPair.Second == sOleObjectTypeStrict) &&
+ nStreamType == EMBEDDINGS))
+ {
+ bFound = true;
+ }
+ else if (rPair.First == sId &&
+ rPair.Second == rId)
+ bFound = true;
+ else if (rPair.First == sTarget)
+ {
+ // checking item[n].xml is not visited already.
+ if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
+ {
+ bFound = false;
+ }
+ else
+ {
+ sMyTarget = rPair.Second;
+ }
+ }
+ else if (rPair.First == sTargetMode &&
+ rPair.Second == sExternal)
+ bExternalTarget = true;
+ }
+
+ if (bFound)
+ {
+ if (bExternalTarget)
+ rDocumentTarget = sMyTarget;
+ else
+ {
+ // 'Target' is a relative Uri, so a 'Target=/path'
+ // with a base Uri of file://base/foo will resolve to
+ // file://base/word. We need something more than some
+ // simple string concatenation here to handle that.
+ uno::Reference<uri::XUriReference> xPart = xFac->parse(sMyTarget);
+ uno::Reference<uri::XUriReference> xAbs = xFac->makeAbsolute(xBase, xPart, true, uri::RelativeUriExcessParentSegments_RETAIN);
+ if (!xAbs)
+ {
+ //it was invalid gibberish
+ bFound = false;
+ }
+ else
+ {
+ rDocumentTarget = xAbs->getPath();
+ // path will start with the fragment separator. need to
+ // remove that
+ rDocumentTarget = rDocumentTarget.copy( 1 );
+ if(sStreamType == sEmbeddingsType)
+ embeddingsTarget = rDocumentTarget;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
+{
+ OUString sTarget;
+
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
+ (mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
+ return sTarget;
+
+ return OUString();
+}
+
+void OOXMLStreamImpl::init()
+{
+ bool bFound = lcl_getTarget(mxRelationshipAccess,
+ mnStreamType, msId, msTarget);
+
+ if (!bFound)
+ return;
+
+ sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
+ if (nLastIndex >= 0)
+ msPath = msTarget.copy(0, nLastIndex + 1);
+
+ uno::Reference<embed::XHierarchicalStorageAccess>
+ xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
+
+ if (xHierarchicalStorageAccess.is())
+ {
+ uno::Any aAny(xHierarchicalStorageAccess->
+ openStreamElementByHierarchicalName
+ (msTarget, embed::ElementModes::SEEKABLEREAD));
+ aAny >>= mxDocumentStream;
+ // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
+ // So when it changes, we should empty the cache.
+ maIdCache.clear();
+ }
+}
+
+uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
+{
+ uno::Reference<io::XInputStream> xResult;
+
+ if (mxDocumentStream.is())
+ xResult = mxDocumentStream->getInputStream();
+
+ return xResult;
+}
+
+uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
+{
+ return mxContext;
+}
+
+uno::Reference <xml::sax::XFastTokenHandler> OOXMLStreamImpl::getFastTokenHandler()
+{
+ if (! mxFastTokenHandler.is())
+ mxFastTokenHandler.set(new oox::core::FastTokenHandler());
+
+ return mxFastTokenHandler;
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const uno::Reference<uno::XComponentContext>& xContext,
+ const uno::Reference<io::XInputStream>& rStream,
+ bool bRepairStorage)
+{
+ OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
+ OOXMLStream::DOCUMENT, bRepairStorage);
+ return OOXMLStream::Pointer_t(pStream);
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType)
+{
+ OOXMLStream::Pointer_t pRet;
+
+ if (nStreamType != OOXMLStream::VBADATA)
+ {
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ pRet = new OOXMLStreamImpl(*pImpl, nStreamType);
+ }
+ else
+ {
+ // VBADATA is not a relation of the document, but of the VBAPROJECT stream.
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ {
+ OOXMLStreamImpl aProject(*pImpl, OOXMLStream::VBAPROJECT);
+ pRet = new OOXMLStreamImpl(aProject, OOXMLStream::VBADATA);
+ }
+ }
+
+ return pRet;
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const OOXMLStream::Pointer_t& pStream, const OUString & rId)
+{
+ OOXMLStream::Pointer_t pRet;
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ pRet = new OOXMLStreamImpl(*pImpl, rId);
+ return pRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.hxx b/writerfilter/source/ooxml/OOXMLStreamImpl.hxx
new file mode 100644
index 000000000..e09db3c4f
--- /dev/null
+++ b/writerfilter/source/ooxml/OOXMLStreamImpl.hxx
@@ -0,0 +1,83 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <map>
+
+#include <ooxml/OOXMLDocument.hxx>
+#include <com/sun/star/embed/XRelationshipAccess.hpp>
+
+extern OUString customTarget;
+extern OUString embeddingsTarget;
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLStreamImpl : public OOXMLStream
+{
+ void init();
+
+ css::uno::Reference<css::uno::XComponentContext> mxContext;
+ css::uno::Reference<css::io::XInputStream> mxStorageStream;
+ css::uno::Reference<css::embed::XStorage> mxStorage;
+ css::uno::Reference<css::embed::XRelationshipAccess> mxRelationshipAccess;
+ css::uno::Reference<css::io::XStream> mxDocumentStream;
+ css::uno::Reference<css::xml::sax::XFastParser> mxFastParser;
+ css::uno::Reference<css::xml::sax::XFastTokenHandler> mxFastTokenHandler;
+
+ StreamType_t mnStreamType;
+
+ OUString msId;
+ OUString msPath;
+ OUString msTarget;
+
+ /// Cache holding an Id <-> Target map of external relations.
+ std::map<OUString, OUString> maIdCache;
+
+ bool lcl_getTarget(const css::uno::Reference<css::embed::XRelationshipAccess>& xRelationshipAccess,
+ StreamType_t nStreamType,
+ const OUString & rId,
+ OUString & rDocumentTarget);
+public:
+ typedef tools::SvRef<OOXMLStreamImpl> Pointer_t;
+
+ OOXMLStreamImpl
+ (OOXMLStreamImpl const & rStream, StreamType_t nType);
+ OOXMLStreamImpl
+ (css::uno::Reference<css::uno::XComponentContext> const & xContext,
+ css::uno::Reference<css::io::XInputStream> const & xStorageStream,
+ StreamType_t nType, bool bRepairStorage);
+ OOXMLStreamImpl(OOXMLStreamImpl const & rStream, const OUString & rId);
+
+ virtual ~OOXMLStreamImpl() override;
+
+ virtual css::uno::Reference<css::xml::sax::XFastParser> getFastParser() override;
+ virtual css::uno::Reference<css::io::XInputStream> getDocumentStream() override;
+ virtual css::uno::Reference<css::uno::XComponentContext> getContext() override;
+ virtual OUString getTargetForId(const OUString & rId) override;
+ virtual const OUString & getTarget() const override;
+
+ virtual css::uno::Reference<css::xml::sax::XFastTokenHandler> getFastTokenHandler() override;
+
+ // Giving access to mxDocumentStream. It is needed by resolving custom xml to get list of customxml's used in document.
+ const css::uno::Reference<css::io::XStream>& accessDocumentStream() { return mxDocumentStream;}
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/ooxml/README b/writerfilter/source/ooxml/README
new file mode 100644
index 000000000..c72b341ae
--- /dev/null
+++ b/writerfilter/source/ooxml/README
@@ -0,0 +1,13 @@
+= DOCX tokenizer
+
+== Coding style
+
+This directory uses the PEP 8 (see
+<http://legacy.python.org/dev/peps/pep-0008/>) coding style for Python files.
+Please run
+
+----
+pycodestyle *.py
+----
+
+before committing.
diff --git a/writerfilter/source/ooxml/factory_ns.py b/writerfilter/source/ooxml/factory_ns.py
new file mode 100644
index 000000000..1d9924e23
--- /dev/null
+++ b/writerfilter/source/ooxml/factory_ns.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+from xml.dom import minidom
+import sys
+
+
+def createHeader(model, ns):
+ nsToken = ns.replace('-', '_')
+ print("""
+#ifndef INCLUDED_OOXML_FACTORY_%s_HXX
+#define INCLUDED_OOXML_FACTORY_%s_HXX
+#include "ooxml/OOXMLFactory.hxx"
+#include "OOXMLFactory_generated.hxx"
+#include "oox/token/namespaces.hxx"
+#include "ooxml/resourceids.hxx"
+#include "tools/ref.hxx"
+
+namespace writerfilter {
+namespace ooxml {
+
+/// @cond GENERATED
+""" % (nsToken.upper(), nsToken.upper()))
+
+ print("""class OOXMLFactory_%s : public OOXMLFactory_ns
+{
+public:
+ typedef tools::SvRef<OOXMLFactory_ns> Pointer_t;
+
+ static Pointer_t getInstance();
+
+ virtual const AttributeInfo* getAttributeInfoArray(Id nId);
+ virtual bool getElementId(Id nDefine, Id nId, ResourceType& rOutResource, Id& rOutElement);
+ virtual bool getListValue(Id nId, const OUString& rValue, sal_uInt32& rOutValue);
+ virtual Id getResourceId(Id nDefine, sal_Int32 nToken);
+""" % nsToken)
+
+ actions = []
+ for nsNode in [i for i in model.getElementsByTagName("namespace") if i.getAttribute("name") == ns]:
+ for resource in nsNode.getElementsByTagName("resource"):
+ for action in [i.getAttribute("name") for i in resource.childNodes if i.nodeType == minidom.Node.ELEMENT_NODE and i.tagName == "action"]:
+ if action != "characters" and action not in actions:
+ actions.append(action)
+ for action in actions:
+ print(" void %sAction(OOXMLFastContextHandler* pHandler);" % action)
+
+ print("""virtual void charactersAction(OOXMLFastContextHandler* pHandler, const OUString & sText);
+ virtual void attributeAction(OOXMLFastContextHandler* pHandler, Token_t nToken, const OOXMLValue::Pointer_t& pValue);
+
+ virtual ~OOXMLFactory_%s();
+
+protected:
+ static Pointer_t m_pInstance;
+
+ OOXMLFactory_%s();
+};
+""" % (nsToken, nsToken))
+
+ print("""/// @endcond
+}}
+#endif //INCLUDED_OOXML_FACTORY_%s_HXX""" % nsToken.upper())
+
+
+modelPath = sys.argv[1]
+filePath = sys.argv[2]
+model = minidom.parse(modelPath)
+ns = filePath.split('OOXMLFactory_')[1].split('.hxx')[0]
+createHeader(model, ns)
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/factoryimpl.py b/writerfilter/source/ooxml/factoryimpl.py
new file mode 100644
index 000000000..c68d5ba06
--- /dev/null
+++ b/writerfilter/source/ooxml/factoryimpl.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+from xml.dom import minidom
+import sys
+
+
+def getElementsByTagNamesNS(parent, ns, names, ret=minidom.NodeList()):
+ for node in parent.childNodes:
+ if node.nodeType == minidom.Node.ELEMENT_NODE and node.namespaceURI == ns and node.tagName in names:
+ ret.append(node)
+ getElementsByTagNamesNS(node, ns, names, ret)
+ return ret
+
+
+def createFastChildContextFromFactory(model):
+ print("""uno::Reference<xml::sax::XFastContextHandler> OOXMLFactory::createFastChildContextFromFactory
+(OOXMLFastContextHandler* pHandler, OOXMLFactory_ns::Pointer_t pFactory, Token_t Element)
+{
+ uno::Reference <xml::sax::XFastContextHandler> aResult;
+ const Id nDefine = pHandler->getDefine();
+
+ if (pFactory.get() != NULL)
+ {
+ ResourceType nResource;
+ Id nElementId;
+ if (pFactory->getElementId(nDefine, Element, nResource, nElementId))
+ {
+ const Id nId = pFactory->getResourceId(nDefine, Element);
+
+ switch (nResource)
+ {""")
+ resources = [
+ "List", "Integer", "Hex", "HexColor", "String",
+ "TwipsMeasure_asSigned", "TwipsMeasure_asZero",
+ "HpsMeasure", "Boolean", "MeasurementOrPercent",
+ ]
+ for resource in [r.getAttribute("resource") for r in model.getElementsByTagName("resource")]:
+ if resource not in resources:
+ resources.append(resource)
+ print(""" case ResourceType::%s:
+ aResult.set(OOXMLFastHelper<OOXMLFastContextHandler%s>::createAndSetParentAndDefine(pHandler, Element, nId, nElementId));
+ break;""" % (resource, resource))
+ print(""" case ResourceType::Any:
+ aResult.set(createFastChildContextFromStart(pHandler, Element));
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+
+ return aResult;
+}
+""")
+
+
+def getFactoryForNamespace(model):
+ print("""OOXMLFactory_ns::Pointer_t OOXMLFactory::getFactoryForNamespace(Id nId)
+{
+ OOXMLFactory_ns::Pointer_t pResult;
+
+ switch (oox::getNamespace(nId))
+ {""")
+
+ for namespace in [ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]:
+ id = namespace.replace('-', '_')
+ print(""" case NN_%s:
+ pResult = OOXMLFactory_%s::getInstance();
+ break;""" % (id, id))
+ print(""" default:
+ break;
+ }
+
+ return pResult;
+}
+""")
+
+
+def createFastChildContextFromStart(model):
+ print("""uno::Reference<xml::sax::XFastContextHandler> OOXMLFactory::createFastChildContextFromStart
+(OOXMLFastContextHandler* pHandler, Token_t Element)
+{
+ uno::Reference<xml::sax::XFastContextHandler> aResult;
+ OOXMLFactory_ns::Pointer_t pFactory;
+
+""")
+
+ for namespace in [ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]:
+ id = namespace.replace('-', '_')
+ print(""" if (!aResult.is())
+ {
+ pFactory = getFactoryForNamespace(NN_%s);
+ aResult.set(createFastChildContextFromFactory(pHandler, pFactory, Element));
+ }""" % id)
+
+ print("""
+ return aResult;
+}
+""")
+
+
+def fastTokenToId(model):
+ print("""
+std::string fastTokenToId(sal_uInt32 nToken)
+{
+ std::string sResult;
+#ifdef DBG_UTIL
+
+ switch (oox::getNamespace(nToken))
+ {""")
+
+ aliases = []
+ for alias in sorted(ooxUrlAliases.values()):
+ if alias not in aliases:
+ aliases.append(alias)
+ print(""" case oox::NMSP_%s:
+ sResult += "%s:";
+ break;""" % (alias, alias))
+ print(""" }
+
+ switch (nToken & 0xffff)
+ {""")
+
+ tokens = [""]
+ for token in [t.getAttribute("localname") for t in getElementsByTagNamesNS(model, "http://relaxng.org/ns/structure/1.0", ["element", "attribute"])]:
+ if token not in tokens:
+ tokens.append(token)
+ print(""" case oox::XML_%s:
+ sResult += "%s";
+ break;""" % (token, token))
+
+ print(""" }
+#else
+ (void)nToken;
+#endif
+ return sResult;
+}
+""")
+
+
+def getFastParser():
+ print("""uno::Reference <xml::sax::XFastParser> OOXMLStreamImpl::getFastParser()
+{
+ if (!mxFastParser.is())
+ {
+ mxFastParser = css::xml::sax::FastParser::create(mxContext);
+ // the threaded parser is about 20% slower loading writer documents
+ css::uno::Reference< css::lang::XInitialization > xInit( mxFastParser, css::uno::UNO_QUERY_THROW );
+ css::uno::Sequence< css::uno::Any > args{ css::uno::Any(OUString("DisableThreadedParser")) };
+ xInit->initialize(args);
+""")
+ for url in sorted(ooxUrlAliases.keys()):
+ print(""" mxFastParser->registerNamespace("%s", oox::NMSP_%s);""" % (url, ooxUrlAliases[url]))
+ print(""" }
+
+ return mxFastParser;
+}
+
+/// @endcond
+}}""")
+
+
+def createImpl(model):
+ print("""
+#include <com/sun/star/xml/sax/FastParser.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include "ooxml/OOXMLFactory.hxx"
+#include "ooxml/OOXMLFastHelper.hxx"
+#include "ooxml/OOXMLStreamImpl.hxx"
+""")
+
+ for namespace in [ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]:
+ print('#include "OOXMLFactory_%s.hxx"' % namespace)
+
+ print("""namespace writerfilter {
+namespace ooxml {
+
+using namespace com::sun::star;
+
+/// @cond GENERATED
+""")
+
+ createFastChildContextFromFactory(model)
+ getFactoryForNamespace(model)
+ createFastChildContextFromStart(model)
+ fastTokenToId(model)
+ getFastParser()
+
+
+def parseNamespaces(fro):
+ sock = open(fro)
+ for i in sock.readlines():
+ line = i.strip()
+ alias, url = line.split(' ')[1:] # first column is ID, not interesting for us
+ ooxUrlAliases[url] = alias
+ sock.close()
+
+
+namespacesPath = sys.argv[1]
+ooxUrlAliases = {}
+parseNamespaces(namespacesPath)
+modelPath = sys.argv[2]
+model = minidom.parse(modelPath)
+createImpl(model)
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/factoryimpl_ns.py b/writerfilter/source/ooxml/factoryimpl_ns.py
new file mode 100644
index 000000000..b17e0c8ff
--- /dev/null
+++ b/writerfilter/source/ooxml/factoryimpl_ns.py
@@ -0,0 +1,767 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+from xml.dom import minidom
+import sys
+
+
+# factoryMutexDecl
+
+
+def factoryMutexDecl(nsLabel):
+ print("typedef rtl::Static<osl::Mutex, OOXMLFactory_%s> OOXMLFactory_%s_Mutex;" % (nsLabel, nsLabel))
+ print()
+
+
+# factoryConstructor
+
+
+def factoryConstructor(nsLabel):
+ print("""OOXMLFactory_%s::OOXMLFactory_%s()
+{
+ // multi-thread-safe mutex for all platforms
+
+ osl::MutexGuard aGuard(OOXMLFactory_%s_Mutex::get());
+}""" % (nsLabel, nsLabel, nsLabel))
+ print()
+
+
+# factoryDestructor
+
+
+def factoryDestructor(nsLabel):
+ print("""OOXMLFactory_%s::~OOXMLFactory_%s()
+{
+}""" % (nsLabel, nsLabel))
+ print()
+
+
+# factoryGetInstance
+
+
+def factoryGetInstance(nsLabel):
+ print("""OOXMLFactory_ns::Pointer_t OOXMLFactory_%s::m_pInstance;
+
+OOXMLFactory_ns::Pointer_t OOXMLFactory_%s::getInstance()
+{
+ if (!m_pInstance)
+ m_pInstance = new OOXMLFactory_%s();
+
+ return m_pInstance;
+}""" % (nsLabel, nsLabel, nsLabel))
+ print()
+
+
+# factoryAttributeToResourceMap
+
+
+def nsToLabel(nsNode):
+ return nsNode.getAttribute("name").replace('-', '_')
+
+
+def getChildByName(parentNode, childName):
+ elementNodes = [i for i in parentNode.childNodes if i.localName == childName]
+ assert len(elementNodes) == 1
+ return elementNodes[0]
+
+
+def resourceForAttribute(nsNode, attrNode):
+ resourceName = ""
+
+ for refNode in getChildrenByName(attrNode, "ref"):
+ refName = refNode.getAttribute("name")
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == refName]:
+ resourceName = resourceNode.getAttribute("resource")
+ break
+ if not len(resourceName):
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ resourceName = resourceForAttribute(nsNode, define)
+ break
+ if len(resourceName):
+ break
+
+ if not len(resourceName):
+ if len([i for i in attrNode.getElementsByTagName("data") if i.getAttribute("type") in ("base64Binary", "string")]):
+ resourceName = "String"
+ elif len([i for i in attrNode.getElementsByTagName("data") if i.getAttribute("type") == "boolean"]):
+ resourceName = "Boolean"
+ elif len([i for i in attrNode.getElementsByTagName("data") if i.getAttribute("type") in ("unsignedInt", "integer", "int")]):
+ resourceName = "Integer"
+ else:
+ dataNodes = attrNode.getElementsByTagName("data")
+ if len(dataNodes):
+ t = dataNodes[0].getAttribute("type")
+ # Denylist existing unexpected data types.
+ if t not in ("token", "long", "decimal", "float", "byte", "ST_DecimalNumber", "positiveInteger"):
+ raise Exception("unexpected data type: " + dataNodes[0].getAttribute("type"))
+ return resourceName
+
+
+def idForNamespace(nsNode):
+ return "NN_%s" % nsNode.getAttribute("name").replace('-', '_')
+
+
+def localIdForDefine(defineNode):
+ return "DEFINE_%s" % defineNode.getAttribute("name")
+
+
+def idForDefine(nsNode, defineNode):
+ return "%s|%s" % (idForNamespace(nsNode), localIdForDefine(defineNode))
+
+
+def fastNamespace(attrNode):
+ return "oox::NMSP_%s" % attrNode.getAttribute("prefix")
+
+
+def fastLocalName(attrNode):
+ if len(attrNode.getAttribute("localname")):
+ return "oox::XML_%s" % attrNode.getAttribute("localname")
+ else:
+ return "oox::XML_TOKEN_COUNT"
+
+
+def fastToken(attrNode):
+ ret = []
+ if len(attrNode.getAttribute("prefix")):
+ ret.append("%s|" % fastNamespace(attrNode))
+ ret.append(fastLocalName(attrNode))
+ return "".join(ret)
+
+
+def collectAttributeToResource(nsNode, defineNode):
+ ret_dict = {}
+ ret_order = []
+ for refNode in getChildrenByName(defineNode, "ref"):
+ refName = refNode.getAttribute("name")
+ parent = refNode.parentNode
+ if parent.localName in ("element", "attribute"):
+ continue
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ ret = collectAttributeToResource(nsNode, define)
+ ret_dict.update(ret[0])
+ ret_order.extend(ret[1])
+
+ attrNodes = defineNode.getElementsByTagName("attribute")
+ for attrNode in attrNodes:
+ attrToken = fastToken(attrNode)
+ resourceName = resourceForAttribute(nsNode, attrNode)
+ refDefine = "0"
+ if len(resourceName):
+ for refNode in attrNode.getElementsByTagName("ref"):
+ refName = refNode.getAttribute("name")
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ refDefine = idForDefine(nsNode, define)
+ ret_dict[attrToken] = "ResourceType::%s, %s" % (resourceName, refDefine)
+ ret_order.append(attrToken)
+
+ return [ret_dict, ret_order]
+
+
+def factoryAttributeToResourceMapInner(nsNode, defineNode):
+ ret = []
+ attributes = collectAttributeToResource(nsNode, defineNode)
+ already_used = set()
+ for k in attributes[1]:
+ if not (k in already_used):
+ ret.append(" { %s, %s }," % (k, attributes[0][k]))
+ already_used.add(k)
+
+ return ret
+
+
+def factoryAttributeToResourceMap(nsNode):
+ print("""const AttributeInfo* OOXMLFactory_%s::getAttributeInfoArray(Id nId)
+{
+ switch (nId)
+ {""" % nsToLabel(nsNode))
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = "\n".join(factoryAttributeToResourceMapInner(nsNode, defineNode))
+ if len(inner):
+ print(" case %s:" % idForDefine(nsNode, defineNode))
+ print(" {")
+ print(" const static AttributeInfo info[] = {")
+ print(inner)
+ print(" { -1, ResourceType::NoResource, 0 }")
+ print(" };")
+ print(" return info;")
+ print(" }")
+ print(" break;")
+
+ print(""" default:
+ break;
+ }
+
+ return NULL;
+}""")
+ print()
+
+
+# factoryGetListValue
+
+
+def idToLabel(idName):
+ ns, ln = idName.split(':')
+ return "NS_%s::LN_%s" % (ns, ln)
+
+
+def appendValueData(values, name, value):
+ first = name[0:1]
+
+ if not (first in values):
+ values[first] = []
+
+ values[first].append([name, value])
+
+
+def printValueData(values):
+ if "" in values:
+ output_else = ""
+ for i in values[""]:
+ print(" %sif (rValue == \"%s\") { rOutValue = %s; return true; }" % (output_else, i[0], i[1]))
+ output_else = "else "
+ print(" else switch (rValue[0])")
+ else:
+ print(" if (rValue.isEmpty())")
+ print(" return false;")
+ print(" switch (rValue[0])")
+
+ print(" {")
+ for k in sorted(values.keys()):
+ if k != "":
+ print(" case '%s':" % k)
+ output_else = ""
+ for i in values[k]:
+ print(" %sif (rValue == \"%s\") { rOutValue = %s; }" % (output_else, i[0], i[1]))
+ output_else = "else "
+ print(" else { return false; }")
+ print(" return true;")
+ print(" }")
+
+
+def factoryGetListValue(nsNode):
+ print("""bool OOXMLFactory_%s::getListValue(Id nId, const OUString& rValue, sal_uInt32& rOutValue)
+{
+ (void) rValue;
+ (void) rOutValue;
+
+ switch (nId)
+ {""" % nsToLabel(nsNode))
+
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("resource") == "List"]:
+ print(" case %s:" % idForDefine(nsNode, resourceNode))
+ values = {}
+ for valueNode in getChildrenByName(resourceNode, "value"):
+ valueData = ""
+ if len(valueNode.childNodes):
+ valueData = valueNode.childNodes[0].data
+ appendValueData(values, valueData, idToLabel(valueNode.getAttribute("tokenid")))
+ printValueData(values)
+ print(" return false;")
+
+ print(""" default:
+ break;
+ }
+
+ return false;
+}
+""")
+
+
+# factoryCreateElementMap
+
+
+def contextResource(files, nsNode, refNode):
+ refName = refNode.getAttribute("name")
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == refName]:
+ return resourceNode.getAttribute("resource")
+
+ for includeNode in getChildrenByName(getChildByName(nsNode, "grammar"), "include"):
+ namespaceNode = files[includeNode.getAttribute("href")]
+ for resourceNode in [i for i in getChildrenByName(namespaceNode, "resource") if i.getAttribute("name") == refName]:
+ return resourceNode.getAttribute("resource")
+
+ if refName == "BUILT_IN_ANY_TYPE":
+ return "Any"
+ else:
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for resourceNode in [i for i in getChildrenByName(namespaceNode, "resource") if i.getAttribute("name") == refName]:
+ return resourceNode.getAttribute("resource")
+ return ""
+
+
+def idForRef(nsNode, refNode):
+ refName = refNode.getAttribute("name")
+ result1 = ""
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ result1 = idForDefine(nsNode, define)
+ if refName == "BUILT_IN_ANY_TYPE":
+ return "0"
+ elif result1 == "":
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for define in [i for i in getChildrenByName(getChildByName(namespaceNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ return idForDefine(namespaceNode, define)
+ else:
+ return result1
+
+
+def factoryCreateElementMapInner(files, nsNode, defineNode, resourceNamespaceNode=None):
+ if not resourceNamespaceNode:
+ resourceNamespaceNode = nsNode
+ ret = {}
+ for refNode in defineNode.getElementsByTagName("ref"):
+ parent = refNode.parentNode
+ if parent.localName in ("element", "attribute"):
+ continue
+ refName = refNode.getAttribute("name")
+
+ block = {}
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ block = factoryCreateElementMapInner(files, nsNode, define)
+
+ if len(block) == 0:
+ block1 = {}
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for define in [i for i in getChildrenByName(getChildByName(namespaceNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ block1.update(factoryCreateElementMapInner(files, namespaceNode, define, nsNode))
+ else:
+ block1 = block
+
+ if len(block1):
+ ret.update(block1)
+
+ for elementNode in defineNode.getElementsByTagName("element"):
+ resource = ""
+ for refNode in getChildrenByName(elementNode, "ref"):
+ refName = refNode.getAttribute("name")
+ resource = contextResource(files, resourceNamespaceNode, refNode)
+ if len(resource):
+ break
+ if len(resource):
+ ret[fastToken(elementNode)] = " case %s: rOutResource = ResourceType::%s; rOutElement = %s; break;" % (fastToken(elementNode), resource, idForRef(nsNode, getChildByName(elementNode, "ref")))
+
+ return ret
+
+
+def factoryCreateElementMapFromStart(files, nsNode):
+ for startNode in getChildrenByName(nsNode, "start"):
+ startName = startNode.getAttribute("name")
+ block = None
+ for defineNode in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == startName]:
+ block = factoryCreateElementMapInner(files, nsNode, defineNode)
+ print(" /* start: %s*/" % startName)
+ if block:
+ for k in block.keys():
+ print(block[k])
+
+
+def factoryCreateElementMap(files, nsNode):
+ print("""bool OOXMLFactory_%s::getElementId(Id nDefine, Id nId, ResourceType& rOutResource, Id& rOutElement)
+{
+ (void) rOutResource;
+ (void) rOutElement;
+
+ switch (nDefine)
+ {""" % nsToLabel(nsNode))
+
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = factoryCreateElementMapInner(files, nsNode, defineNode)
+ if len(inner):
+ print(" case %s:" % idForDefine(nsNode, defineNode))
+ print(" switch (nId)")
+ print(" {")
+ for k in sorted(inner.keys()):
+ print(inner[k])
+ print(" default: return false;")
+ print(" }")
+ print(" return true;")
+ print(" default:")
+ print(" switch (nId)")
+ print(" {")
+ factoryCreateElementMapFromStart(files, nsNode)
+ print(""" default: return false;
+ }
+ return true;
+ }
+}
+""")
+
+
+# factoryActions
+
+
+def charactersActionForValues(nsNode, refNode):
+ ret = []
+
+ refName = refNode.getAttribute("name")
+ for defineNode in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ ret.append(" {")
+ ret.append(" // %s" % defineNode.getAttribute("name"))
+ for dataNode in getChildrenByName(defineNode, "data"):
+ if dataNode.getAttribute("type") == "int":
+ ret.append(" OOXMLValue::Pointer_t pValue(new OOXMLIntegerValue(sText));")
+ ret.append(" pValueHandler->setValue(pValue);")
+ ret.append(" }")
+
+ return ret
+
+
+def factoryChooseAction(actionNode):
+ ret = []
+ extra_space = ""
+ if actionNode.hasAttribute("tokenid"):
+ ret.append(" if (sal::static_int_cast<Id>(pHandler->getId()) == %s)" % idToLabel(actionNode.getAttribute("tokenid")))
+ ret.append(" {")
+ extra_space = " "
+ for condNode in getChildrenByName(actionNode, "cond"):
+ ret.append(" {")
+ ret.append(" OOXMLPropertySetEntryToInteger aHandler(%s);" % idToLabel(condNode.getAttribute("tokenid")))
+ ret.append(" if (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))")
+ ret.append(" pStream->getPropertySetAttrs()->resolve(aHandler);")
+ ret.append("")
+ ret.append(" if (sal::static_int_cast<Id>(aHandler.getValue()) == %s)" % idToLabel(condNode.getAttribute("value")))
+ ret.append(" {")
+ extra_space = " "
+
+ if actionNode.getAttribute("action") in ("handleXNotes", "handleHdrFtr", "handleComment", "handlePicture", "handleBreak", "handleOutOfOrderBreak", "handleOLE", "handleFontRel", "handleHyperlinkURL", "handleAltChunk"):
+ ret.append(" %sif (OOXMLFastContextHandlerProperties* pProperties = dynamic_cast<OOXMLFastContextHandlerProperties*>(pHandler))" % extra_space)
+ ret.append(" %s pProperties->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") == "propagateCharacterPropertiesAsSet":
+ ret.append(" %spHandler->propagateCharacterPropertiesAsSet(%s);" % (extra_space, idToLabel(actionNode.getAttribute("sendtokenid"))))
+ elif actionNode.getAttribute("action") in ("startCell", "endCell"):
+ ret.append(" %sif (OOXMLFastContextHandlerTextTableCell* pTextTableCell = dynamic_cast<OOXMLFastContextHandlerTextTableCell*>(pHandler))" % extra_space)
+ ret.append(" %s pTextTableCell->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") in ("startRow", "endRow"):
+ ret.append(" %sif (OOXMLFastContextHandlerTextTableRow* pTextTableRow = dynamic_cast<OOXMLFastContextHandlerTextTableRow*>(pHandler))" % extra_space)
+ ret.append(" %s pTextTableRow->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") == "handleGridAfter":
+ ret.append(" %sif (OOXMLFastContextHandlerValue* pValueHandler = dynamic_cast<OOXMLFastContextHandlerValue*>(pHandler))" % extra_space)
+ ret.append(" %s pValueHandler->%s();" % (extra_space, actionNode.getAttribute("action")))
+ # tdf#111550
+ elif actionNode.getAttribute("action") in ("start_P_Tbl"):
+ ret.append(" %sif (OOXMLFastContextHandlerTextTable* pTextTable = dynamic_cast<OOXMLFastContextHandlerTextTable*>(pHandler))" % extra_space)
+ ret.append(" %s pTextTable->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") in ("sendProperty", "handleHyperlink"):
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % extra_space)
+ ret.append(" %s pStream->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") == "fieldstart":
+ ret.append(" %spHandler->startField();" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldsep":
+ ret.append(" %spHandler->fieldSeparator();" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldend":
+ ret.append(" %spHandler->endField();" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldlock":
+ ret.append(" %s{" % (extra_space))
+ ret.append(" %sOOXMLPropertySetEntryToBool aHandler(NS_ooxml::LN_CT_FldChar_fldLock);" % (extra_space))
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % (extra_space))
+ ret.append(" %spStream->getPropertySetAttrs()->resolve(aHandler);" % (extra_space))
+ ret.append(" %sif (aHandler.getValue())" % (extra_space))
+ ret.append(" %spHandler->lockField();" % (extra_space))
+ ret.append(" %s}" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldlock_simple":
+ ret.append(" %s{" % (extra_space))
+ ret.append(" %sOOXMLPropertySetEntryToBool aHandler(NS_ooxml::LN_CT_SimpleField_fldLock);" % (extra_space))
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % (extra_space))
+ ret.append(" %spStream->getPropertySetAttrs()->resolve(aHandler);" % (extra_space))
+ ret.append(" %sif (aHandler.getValue())" % (extra_space))
+ ret.append(" %spHandler->lockField();" % (extra_space))
+ ret.append(" %s}" % (extra_space))
+ elif actionNode.getAttribute("action") == "printproperty":
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % extra_space)
+ ret.append(" %s pStream->sendProperty(%s);" % (extra_space, idToLabel(actionNode.getAttribute("sendtokenid"))))
+ elif actionNode.getAttribute("action") == "sendPropertiesWithId":
+ ret.append(" %spHandler->sendPropertiesWithId(%s);" % (extra_space, idToLabel(actionNode.getAttribute("sendtokenid"))))
+ elif actionNode.getAttribute("action") == "text":
+ ret.append(" %spHandler->text(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "positionOffset":
+ ret.append(" %spHandler->positionOffset(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "positivePercentage":
+ ret.append(" %spHandler->positivePercentage(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "alignH":
+ ret.append(" %spHandler->alignH(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "alignV":
+ ret.append(" %spHandler->alignV(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "tokenproperty":
+ ret.append(" %sOOXMLFastHelper<OOXMLIntegerValue>::newProperty(pHandler, %s, pHandler->getToken());" % (extra_space, idToLabel("ooxml:token")))
+ else:
+ ret.append(" %spHandler->%s();" % (extra_space, actionNode.getAttribute("action")))
+
+ for condNode in getChildrenByName(actionNode, "cond"):
+ ret.append(" }")
+ ret.append(" }")
+ if actionNode.hasAttribute("tokenid"):
+ ret.append(" }")
+
+ return ret
+
+
+def factoryAction(nsNode, action):
+ switchblock1 = []
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if len([j for j in getChildrenByName(i, "action") if j.getAttribute("name") == action])]:
+ switchblock1.append("case %s:" % idForDefine(nsNode, resourceNode))
+ for actionNode in [i for i in getChildrenByName(resourceNode, "action") if i.getAttribute("name") == action]:
+ switchblock1.extend(factoryChooseAction(actionNode))
+ switchblock1.append(" break;")
+ switchblock1.append("")
+
+ switchblock2 = []
+ if action == "characters":
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("resource") == "Value"]:
+ if not len(getChildrenByName(resourceNode, "attribute")):
+ resourceName = resourceNode.getAttribute("name")
+ switchblock2.append("case %s:" % idForDefine(nsNode, resourceNode))
+ ret = []
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == resourceName]:
+ for refNode in getChildrenByName(define, "ref"):
+ ret.extend(charactersActionForValues(nsNode, refNode))
+ switchblock2.extend(ret)
+ switchblock2.append(" break;")
+
+ sys.stdout.write("void OOXMLFactory_%s::%sAction(OOXMLFastContextHandler*" % (nsToLabel(nsNode), action))
+ if len(switchblock1) or len(switchblock2):
+ sys.stdout.write(" pHandler")
+ if action == "characters":
+ sys.stdout.write(", const OUString&")
+ if "sText" in "".join(switchblock1) or "sText" in "".join(switchblock2):
+ sys.stdout.write(" sText")
+ print(")")
+ print("{")
+ if len(switchblock1) or len(switchblock2):
+ print(" sal_uInt32 nDefine = pHandler->getDefine();")
+ if len(switchblock1):
+ print(" switch (nDefine)")
+ print(" {")
+ if switchblock1[-1] == "":
+ switchblock1 = switchblock1[:-1]
+ sys.stdout.write(" ")
+ print("\n ".join(switchblock1))
+ print()
+ print(" default:")
+ print(" break;")
+ print(" }")
+ if len(switchblock2):
+ print(" switch (nDefine)")
+ print(" {")
+ print("\n ".join(switchblock2))
+ print()
+ print(" default:")
+ print(" break;")
+ print(" }")
+ print("}")
+
+
+def factoryActions(nsNode):
+ actions = []
+ for resourceNode in getChildrenByName(nsNode, "resource"):
+ for actionNode in getChildrenByName(resourceNode, "action"):
+ actionName = actionNode.getAttribute("name")
+ if actionName != "characters" and actionName not in actions:
+ actions.append(actionName)
+ for action in sorted(actions):
+ factoryAction(nsNode, action)
+ print()
+ factoryAction(nsNode, "characters")
+ print()
+
+
+# factoryGetResourceId
+
+
+def collectTokenToId(nsNode, defineNode):
+ ret = {}
+ for refNode in defineNode.getElementsByTagName("ref"):
+ refName = refNode.getAttribute("name")
+ parent = refNode.parentNode
+ if parent.localName in ("element", "attribute"):
+ continue
+ refblock1 = {}
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ refblock1.update(collectTokenToId(nsNode, define))
+ if not len(refblock1):
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for define in [i for i in getChildrenByName(getChildByName(namespaceNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ ret.update(collectTokenToId(namespaceNode, define))
+ else:
+ ret.update(refblock1)
+
+ defineName = defineNode.getAttribute("name")
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == defineName]:
+ for node in [i for i in resourceNode.childNodes if i.localName in ("element", "attribute")]:
+ if node.hasAttribute("tokenid"):
+ ret[fastToken(node)] = idToLabel(node.getAttribute("tokenid"))
+
+ return ret
+
+
+def factoryTokenToIdMapInner(nsNode, defineNode):
+ ids = collectTokenToId(nsNode, defineNode)
+ ret = []
+ for i in sorted(ids.keys()):
+ ret.append(" case %s: return %s;" % (i, ids[i]))
+
+ return ret
+
+
+def factoryGetResourceId(nsNode):
+ print("""Id OOXMLFactory_%s::getResourceId(Id nDefine, sal_Int32 nToken)
+{
+ (void) nDefine;
+ (void) nToken;
+
+ switch (nDefine)
+ {""" % nsToLabel(nsNode))
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = "\n".join(factoryTokenToIdMapInner(nsNode, defineNode))
+ if len(inner):
+ print(" case %s:" % idForDefine(nsNode, defineNode))
+ print(" switch (nToken)")
+ print(" {")
+ print(inner)
+ print(" }")
+ print(" break;")
+ print(" default:")
+ print(" switch (nToken)")
+ print(" {")
+ for startNode in getChildrenByName(nsNode, "start"):
+ startName = startNode.getAttribute("name")
+ for defineNode in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == startName]:
+ inner = factoryTokenToIdMapInner(nsNode, defineNode)
+ if len(inner):
+ print("\n".join(inner))
+ print(""" }
+ break;
+ }
+ return 0;
+}
+""")
+
+
+# factoryAttributeAction
+
+
+def factoryAttributeActionDefineInner(nsNode, defineNode):
+ ret = []
+
+ defineName = defineNode.getAttribute("name")
+ block = []
+ output_else = ""
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == defineName]:
+ for attributeNode in getChildrenByName(resourceNode, "attribute"):
+ if attributeNode.hasAttribute("action"):
+ block.append(" %sif (nToken == static_cast<Token_t>(%s))" % (output_else, fastToken(attributeNode)))
+ block.append(" pHandler->%s(pValue);" % attributeNode.getAttribute("action"))
+ output_else = "else "
+ if len(block):
+ resource = ""
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == defineName]:
+ resource = resourceNode.getAttribute("resource")
+ break
+ ret.append(" if (OOXMLFastContextHandler%s* pHandler = dynamic_cast<OOXMLFastContextHandler%s*>(_pHandler))" % (resource, resource))
+ ret.append(" {")
+ ret.extend(block)
+ ret.append(" }")
+
+ return ret
+
+
+def factoryAttributeActionInner(nsNode):
+ ret = []
+
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = factoryAttributeActionDefineInner(nsNode, defineNode)
+ if len(inner):
+ ret.append(" case %s:" % idForDefine(nsNode, defineNode))
+ ret.extend(inner)
+ ret.append(" break;")
+
+ return ret
+
+
+def factoryAttributeAction(nsNode):
+ nsLabel = nsToLabel(nsNode)
+ inner = factoryAttributeActionInner(nsNode)
+ if len(inner):
+ print("""void OOXMLFactory_%s::attributeAction(OOXMLFastContextHandler* _pHandler, Token_t nToken, const OOXMLValue::Pointer_t& pValue)
+{
+ switch (_pHandler->getDefine())
+ {""" % nsLabel)
+ print("\n".join(inner))
+ print(" default:")
+ print(" break;")
+ print(" }")
+ print("}")
+ print()
+ else:
+ print("void OOXMLFactory_%s::attributeAction(OOXMLFastContextHandler*, Token_t, const OOXMLValue::Pointer_t&)" % nsLabel)
+ print("{")
+ print("}")
+ print()
+
+
+# createImpl
+
+
+def getChildrenByName(parentNode, childName):
+ return [i for i in parentNode.childNodes if i.localName == childName]
+
+
+def createImpl(modelNode, nsName):
+ print("""
+#include "ooxml/resourceids.hxx"
+#include "OOXMLFactory_%s.hxx"
+#include "ooxml/OOXMLFastHelper.hxx"
+#include "oox/token/tokens.hxx"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4060) // switch statement contains no 'case' or 'default' labels
+#pragma warning(disable:4065) // switch statement contains 'default' but no 'case' labels
+#pragma warning(disable:4702) // unreachable code
+#endif
+
+namespace writerfilter {
+namespace ooxml {
+
+using namespace com::sun::star;
+
+/// @cond GENERATED""" % nsName)
+ print()
+
+ files = {}
+ for nsNode in getChildrenByName(modelNode, "namespace"):
+ files[nsNode.getAttribute("name")] = nsNode
+
+ for nsNode in [i for i in getChildrenByName(modelNode, "namespace") if i.getAttribute("name") == nsName]:
+ nsLabel = nsToLabel(nsNode)
+
+ factoryMutexDecl(nsLabel)
+ factoryConstructor(nsLabel)
+ factoryDestructor(nsLabel)
+ factoryGetInstance(nsLabel)
+ factoryAttributeToResourceMap(nsNode)
+ factoryGetListValue(nsNode)
+ factoryCreateElementMap(files, nsNode)
+ factoryActions(nsNode)
+ factoryGetResourceId(nsNode)
+ factoryAttributeAction(nsNode)
+
+ print("""/// @endcond
+}}""")
+
+
+def main():
+ modelPath = sys.argv[1]
+ filePath = sys.argv[2]
+ modelNode = getChildByName(minidom.parse(modelPath), "model")
+ nsName = filePath.split('OOXMLFactory_')[1].split('.cxx')[0]
+ createImpl(modelNode, nsName)
+
+
+if __name__ == "__main__":
+ main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/factoryinc.py b/writerfilter/source/ooxml/factoryinc.py
new file mode 100644
index 000000000..ec07f7fda
--- /dev/null
+++ b/writerfilter/source/ooxml/factoryinc.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+from xml.dom import minidom
+import sys
+
+
+def createInclude(model):
+ print("""
+#ifndef INCLUDED_OOXML_FACTORY_GENERATED_HXX
+#define INCLUDED_OOXML_FACTORY_GENERATED_HXX
+
+namespace writerfilter {
+namespace ooxml {
+
+/// @cond GENERATED
+ """)
+
+ # Create namespaces.
+ counter = 1
+ for namespace in sorted([ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]):
+ print("const Id NN_%s = %s << 16;" % (namespace.replace('-', '_'), counter))
+ counter += 1
+
+ # Create defines.
+ counter = 1
+ defines = []
+ for define in sorted([ns.getAttribute("name") for ns in model.getElementsByTagName("define")]):
+ if define not in defines:
+ print("const Id DEFINE_%s = %s;" % (define, counter))
+ defines.append(define)
+ counter += 1
+ print("""/// @endcond
+}}
+
+#endif // INCLUDED_OOXML_FACTORY_GENERATED_HXX""")
+
+
+modelPath = sys.argv[1]
+model = minidom.parse(modelPath)
+createInclude(model)
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml
new file mode 100644
index 000000000..134726d64
--- /dev/null
+++ b/writerfilter/source/ooxml/model.xml
@@ -0,0 +1,19297 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+-->
+<model
+ xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
+ xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"
+ xmlns:dgm="http://schemas.openxmlformats.org/drawingml/2006/diagram"
+ xmlns:lc="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"
+ xmlns:o="urn:schemas-microsoft-com:office:office"
+ xmlns:p="urn:schemas-microsoft-com:office:powerpoint"
+ xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+ xmlns:v="urn:schemas-microsoft-com:vml"
+ xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
+ xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
+ xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
+ xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
+ xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
+ xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
+ xmlns:wvml="urn:schemas-microsoft-com:office:word"
+ xmlns:x="urn:schemas-microsoft-com:office:excel"
+ xmlns:xml="http://www.w3.org/XML/1998/namespace">
+ <token tokenid="ooxml:shape"/>
+ <token tokenid="ooxml:token"/>
+ <token tokenid="ooxml:inputstream"/>
+ <token tokenid="ooxml:trackchange"/>
+ <token tokenid="ooxml:object"/>
+ <token tokenid="ooxml:tblStart"/>
+ <token tokenid="ooxml:tblEnd"/>
+ <token tokenid="ooxml:tcStart"/>
+ <token tokenid="ooxml:tcEnd"/>
+
+ <!-- These are not directly generated from OOXML XML elements / attributes, need to clean them up in the future. -->
+ <token tokenid="ooxml:tblDepth"/>
+ <token tokenid="ooxml:inTbl"/>
+ <token tokenid="ooxml:tblCell"/>
+ <token tokenid="ooxml:tblRow"/>
+
+ <token tokenid="ooxml:ffdata"/>
+ <token tokenid="ooxml:starmath"/>
+ <token tokenid="ooxml:blip"/>
+ <token tokenid="ooxml:payload"/>
+ <token tokenid="ooxml:footnote"/>
+ <token tokenid="ooxml:endnote"/>
+ <token tokenid="ooxml:annotation"/>
+ <token tokenid="ooxml:headerl"/>
+ <token tokenid="ooxml:headerr"/>
+ <token tokenid="ooxml:headerf"/>
+ <token tokenid="ooxml:footerl"/>
+ <token tokenid="ooxml:footerr"/>
+ <token tokenid="ooxml:footerf"/>
+
+ <!-- Present in RTF, but not in OOXML. -->
+ <token tokenid="ooxml:CT_Settings_widowControl"/>
+ <token tokenid="ooxml:CT_Settings_longerSpaceSequence"/>
+
+ <namespace name="dml-stylesheet">
+ <start name="theme"/>
+ <start name="themeOverride"/>
+ <start name="themeManager"/>
+ <start name="hlinkClick"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-baseStylesheet"/>
+ <!-- start = theme | themeOverride | themeManager | hlinkClick -->
+ <define name="CT_EmptyElement">
+ </define>
+ <define name="CT_ColorMapping">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="bg1">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="tx1">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="bg2">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="tx2">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="accent1">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="accent2">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="accent3">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="accent4">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="accent5">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="accent6">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="hlink">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ <attribute name="folHlink">
+ <ref name="ST_ColorSchemeIndex"/>
+ </attribute>
+ </define>
+ <define name="CT_ColorMappingOverride">
+ <choice>
+ <element name="masterClrMapping">
+ <ref name="CT_EmptyElement"/>
+ </element>
+ <element name="overrideClrMapping">
+ <ref name="CT_ColorMapping"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_ColorSchemeAndMapping">
+ <element name="clrScheme">
+ <ref name="CT_ColorScheme"/>
+ </element>
+ <element name="clrMap">
+ <ref name="CT_ColorMapping"/>
+ </element>
+ </define>
+ <define name="CT_ColorSchemeList">
+ <element name="extraClrScheme">
+ <ref name="CT_ColorSchemeAndMapping"/>
+ </element>
+ </define>
+ <define name="CT_OfficeStyleSheet">
+ <element name="themeElements">
+ <ref name="CT_BaseStyles"/>
+ </element>
+ <element name="objectDefaults">
+ <ref name="CT_ObjectStyleDefaults"/>
+ </element>
+ <element name="extraClrSchemeLst">
+ <ref name="CT_ColorSchemeList"/>
+ </element>
+ <element name="custClrLst">
+ <ref name="CT_CustomColorList"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_BaseStylesOverride">
+ <element name="clrScheme">
+ <ref name="CT_ColorScheme"/>
+ </element>
+ <element name="fontScheme">
+ <ref name="CT_FontScheme"/>
+ </element>
+ <element name="fmtScheme">
+ <ref name="CT_StyleMatrix"/>
+ </element>
+ </define>
+ <define name="CT_ClipboardStyleSheet">
+ <element name="themeElements">
+ <ref name="CT_BaseStyles"/>
+ </element>
+ <element name="clrMap">
+ <ref name="CT_ColorMapping"/>
+ </element>
+ </define>
+ <define name="CT_Hyperlink">
+ <attribute name="r:id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="theme">
+ <element name="theme">
+ <ref name="CT_OfficeStyleSheet"/>
+ </element>
+ </define>
+ <define name="themeOverride">
+ <element name="themeOverride">
+ <ref name="CT_BaseStylesOverride"/>
+ </element>
+ </define>
+ <define name="themeManager">
+ <element name="themeManager">
+ <ref name="CT_EmptyElement"/>
+ </element>
+ </define>
+ <define name="hlinkClick">
+ <element name="hlinkClick">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="CT_OfficeStyleSheet" resource="Table" tokenid="ooxml:THEMETABLE"/>
+ <resource name="CT_Hyperlink" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_Hyperlink_r_id"/>
+ </resource>
+ <resource name="theme" resource="Stream">
+ <element name="theme" tokenid="ooxml:THEMETABLE"/>
+ </resource>
+ <resource name="themeOverride" resource="Stream"/>
+ <resource name="themeManager" resource="Stream"/>
+ <resource name="hlinkClick" resource="Properties">
+ <element name="hlinkClick" tokenid="ooxml:hlinkClick_hlinkClick"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-styleDefaults">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shapeProperties"/>
+ <define name="CT_DefaultShapeDefinition">
+ <element name="spPr">
+ <ref name="CT_ShapeProperties"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ <define name="CT_ObjectStyleDefaults">
+ <element name="spDef">
+ <ref name="CT_DefaultShapeDefinition"/>
+ </element>
+ <element name="lnDef">
+ <ref name="CT_DefaultShapeDefinition"/>
+ </element>
+ <element name="txDef">
+ <ref name="CT_DefaultShapeDefinition"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="dml-shape3DLighting">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <define name="ST_LightRigDirection">
+ <choice>
+ <!-- Top Left -->
+ <value>tl</value>
+ <!-- Top -->
+ <value>t</value>
+ <!-- Top Right -->
+ <value>tr</value>
+ <!-- Left -->
+ <value>l</value>
+ <!-- Right -->
+ <value>r</value>
+ <!-- Bottom Left -->
+ <value>bl</value>
+ <!-- Bottom -->
+ <value>b</value>
+ <!-- Bottom Right -->
+ <value>br</value>
+ </choice>
+ </define>
+ <define name="ST_LightRigType">
+ <choice>
+ <!-- Legacy Flat 1 -->
+ <value>legacyFlat1</value>
+ <!-- Legacy Flat 2 -->
+ <value>legacyFlat2</value>
+ <!-- Legacy Flat 3 -->
+ <value>legacyFlat3</value>
+ <!-- Legacy Flat 4 -->
+ <value>legacyFlat4</value>
+ <!-- Legacy Normal 1 -->
+ <value>legacyNormal1</value>
+ <!-- Legacy Normal 2 -->
+ <value>legacyNormal2</value>
+ <!-- Legacy Normal 3 -->
+ <value>legacyNormal3</value>
+ <!-- Legacy Normal 4 -->
+ <value>legacyNormal4</value>
+ <!-- Legacy Harsh 1 -->
+ <value>legacyHarsh1</value>
+ <!-- Legacy Harsh 2 -->
+ <value>legacyHarsh2</value>
+ <!-- Legacy Harsh 3 -->
+ <value>legacyHarsh3</value>
+ <!-- Legacy Harsh 4 -->
+ <value>legacyHarsh4</value>
+ <!-- Three Point -->
+ <value>threePt</value>
+ <!-- Light Rig Enum ( Balanced ) -->
+ <value>balanced</value>
+ <!-- Soft -->
+ <value>soft</value>
+ <!-- Harsh -->
+ <value>harsh</value>
+ <!-- Flood -->
+ <value>flood</value>
+ <!-- Contrasting -->
+ <value>contrasting</value>
+ <!-- Morning -->
+ <value>morning</value>
+ <!-- Sunrise -->
+ <value>sunrise</value>
+ <!-- Sunset -->
+ <value>sunset</value>
+ <!-- Chilly -->
+ <value>chilly</value>
+ <!-- Freezing -->
+ <value>freezing</value>
+ <!-- Flat -->
+ <value>flat</value>
+ <!-- Two Point -->
+ <value>twoPt</value>
+ <!-- Glow -->
+ <value>glow</value>
+ <!-- Bright Room -->
+ <value>brightRoom</value>
+ </choice>
+ </define>
+ <define name="CT_LightRig">
+ <element name="rot">
+ <ref name="CT_SphereCoords"/>
+ </element>
+ <attribute name="rig">
+ <ref name="ST_LightRigType"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_LightRigDirection"/>
+ </attribute>
+ </define>
+ </grammar>
+ <resource name="ST_LightRigDirection" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_tl">tl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_t">t</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_tr">tr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_l">l</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_r">r</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_bl">bl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_b">b</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigDirection_br">br</value>
+ </resource>
+ <resource name="ST_LightRigType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyFlat1">legacyFlat1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyFlat2">legacyFlat2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyFlat3">legacyFlat3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyFlat4">legacyFlat4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyNormal1">legacyNormal1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyNormal2">legacyNormal2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyNormal3">legacyNormal3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyNormal4">legacyNormal4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyHarsh1">legacyHarsh1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyHarsh2">legacyHarsh2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyHarsh3">legacyHarsh3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_legacyHarsh4">legacyHarsh4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_threePt">threePt</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_balanced">balanced</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_soft">soft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_harsh">harsh</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_flood">flood</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_contrasting">contrasting</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_morning">morning</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_sunrise">sunrise</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_sunset">sunset</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_chilly">chilly</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_freezing">freezing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_flat">flat</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_twoPt">twoPt</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_glow">glow</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LightRigType_brightRoom">brightRoom</value>
+ </resource>
+ </namespace>
+ <namespace name="dml-shape3DScene">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shape3DCamera"/>
+ <include href="dml-shape3DLighting"/>
+ <define name="CT_Scene3D">
+ <element name="camera">
+ <ref name="CT_Camera"/>
+ </element>
+ <element name="lightRig">
+ <ref name="CT_LightRig"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="dml-shape3DStyles">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shapeGeometry"/>
+ <define name="ST_BevelPresetType">
+ <choice>
+ <!-- Relaxed Inset -->
+ <value>relaxedInset</value>
+ <!-- Circle -->
+ <value>circle</value>
+ <!-- Slope -->
+ <value>slope</value>
+ <!-- Cross -->
+ <value>cross</value>
+ <!-- Angle -->
+ <value>angle</value>
+ <!-- Soft Round -->
+ <value>softRound</value>
+ <!-- Convex -->
+ <value>convex</value>
+ <!-- Cool Slant -->
+ <value>coolSlant</value>
+ <!-- Divot -->
+ <value>divot</value>
+ <!-- Riblet -->
+ <value>riblet</value>
+ <!-- Hard Edge -->
+ <value>hardEdge</value>
+ <!-- Art Deco -->
+ <value>artDeco</value>
+ </choice>
+ </define>
+ <define name="CT_Bevel">
+ <attribute name="w">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="prst">
+ <ref name="ST_BevelPresetType"/>
+ </attribute>
+ </define>
+ <define name="ST_PresetMaterialType">
+ <choice>
+ <!-- Legacy Matte -->
+ <value>legacyMatte</value>
+ <!-- Legacy Plastic -->
+ <value>legacyPlastic</value>
+ <!-- Legacy Metal -->
+ <value>legacyMetal</value>
+ <!-- Legacy Wireframe -->
+ <value>legacyWireframe</value>
+ <!-- Matte -->
+ <value>matte</value>
+ <!-- Plastic -->
+ <value>plastic</value>
+ <!-- Metal -->
+ <value>metal</value>
+ <!-- Warm Matte -->
+ <value>warmMatte</value>
+ <!-- Translucent Powder -->
+ <value>translucentPowder</value>
+ <!-- Powder -->
+ <value>powder</value>
+ <!-- Dark Edge -->
+ <value>dkEdge</value>
+ <!-- Soft Edge -->
+ <value>softEdge</value>
+ <!-- Clear -->
+ <value>clear</value>
+ <!-- Flat -->
+ <value>flat</value>
+ <!-- Soft Metal -->
+ <value>softmetal</value>
+ </choice>
+ </define>
+ <define name="CT_Shape3D">
+ <element name="bevelT">
+ <ref name="CT_Bevel"/>
+ </element>
+ <element name="bevelB">
+ <ref name="CT_Bevel"/>
+ </element>
+ <element name="extrusionClr">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="contourClr">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="z">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="extrusionH">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="contourW">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="prstMaterial">
+ <ref name="ST_PresetMaterialType"/>
+ </attribute>
+ </define>
+ <define name="CT_FlatText">
+ <attribute name="z">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="EG_Text3D">
+ <choice>
+ <element name="sp3d">
+ <ref name="CT_Shape3D"/>
+ </element>
+ <element name="flatTx">
+ <ref name="CT_FlatText"/>
+ </element>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="ST_BevelPresetType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_relaxedInset">relaxedInset</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_circle">circle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_slope">slope</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_cross">cross</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_angle">angle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_softRound">softRound</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_convex">convex</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_coolSlant">coolSlant</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_divot">divot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_riblet">riblet</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_hardEdge">hardEdge</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BevelPresetType_artDeco">artDeco</value>
+ </resource>
+ <resource name="ST_PresetMaterialType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_legacyMatte">legacyMatte</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_legacyPlastic">legacyPlastic</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_legacyMetal">legacyMetal</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_legacyWireframe">legacyWireframe</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_matte">matte</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_plastic">plastic</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_metal">metal</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_warmMatte">warmMatte</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_translucentPowder">translucentPowder</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_powder">powder</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_dkEdge">dkEdge</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_softEdge">softEdge</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_clear">clear</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_flat">flat</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetMaterialType_softmetal">softmetal</value>
+ </resource>
+ </namespace>
+ <namespace name="dml-shape3DCamera">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <define name="ST_PresetCameraType">
+ <choice>
+ <!-- Legacy Oblique Top Left -->
+ <value>legacyObliqueTopLeft</value>
+ <!-- Legacy Oblique Top -->
+ <value>legacyObliqueTop</value>
+ <!-- Legacy Oblique Top Right -->
+ <value>legacyObliqueTopRight</value>
+ <!-- Legacy Oblique Left -->
+ <value>legacyObliqueLeft</value>
+ <!-- Legacy Oblique Front -->
+ <value>legacyObliqueFront</value>
+ <!-- Legacy Oblique Right -->
+ <value>legacyObliqueRight</value>
+ <!-- Legacy Oblique Bottom Left -->
+ <value>legacyObliqueBottomLeft</value>
+ <!-- Legacy Oblique Bottom -->
+ <value>legacyObliqueBottom</value>
+ <!-- Legacy Oblique Bottom Right -->
+ <value>legacyObliqueBottomRight</value>
+ <!-- Legacy Perspective Top Left -->
+ <value>legacyPerspectiveTopLeft</value>
+ <!-- Legacy Perspective Top -->
+ <value>legacyPerspectiveTop</value>
+ <!-- Legacy Perspective Top Right -->
+ <value>legacyPerspectiveTopRight</value>
+ <!-- Legacy Perspective Left -->
+ <value>legacyPerspectiveLeft</value>
+ <!-- Legacy Perspective Front -->
+ <value>legacyPerspectiveFront</value>
+ <!-- Legacy Perspective Right -->
+ <value>legacyPerspectiveRight</value>
+ <!-- Legacy Perspective Bottom Left -->
+ <value>legacyPerspectiveBottomLeft</value>
+ <!-- Legacy Perspective Bottom -->
+ <value>legacyPerspectiveBottom</value>
+ <!-- Legacy Perspective Bottom Right -->
+ <value>legacyPerspectiveBottomRight</value>
+ <!-- Orthographic Front -->
+ <value>orthographicFront</value>
+ <!-- Isometric Top Up -->
+ <value>isometricTopUp</value>
+ <!-- Isometric Top Down -->
+ <value>isometricTopDown</value>
+ <!-- Isometric Bottom Up -->
+ <value>isometricBottomUp</value>
+ <!-- Isometric Bottom Down -->
+ <value>isometricBottomDown</value>
+ <!-- Isometric Left Up -->
+ <value>isometricLeftUp</value>
+ <!-- Isometric Left Down -->
+ <value>isometricLeftDown</value>
+ <!-- Isometric Right Up -->
+ <value>isometricRightUp</value>
+ <!-- Isometric Right Down -->
+ <value>isometricRightDown</value>
+ <!-- Isometric Off Axis 1 Left -->
+ <value>isometricOffAxis1Left</value>
+ <!-- Isometric Off Axis 1 Right -->
+ <value>isometricOffAxis1Right</value>
+ <!-- Isometric Off Axis 1 Top -->
+ <value>isometricOffAxis1Top</value>
+ <!-- Isometric Off Axis 2 Left -->
+ <value>isometricOffAxis2Left</value>
+ <!-- Isometric Off Axis 2 Right -->
+ <value>isometricOffAxis2Right</value>
+ <!-- Isometric Off Axis 2 Top -->
+ <value>isometricOffAxis2Top</value>
+ <!-- Isometric Off Axis 3 Left -->
+ <value>isometricOffAxis3Left</value>
+ <!-- Isometric Off Axis 3 Right -->
+ <value>isometricOffAxis3Right</value>
+ <!-- Isometric Off Axis 3 Bottom -->
+ <value>isometricOffAxis3Bottom</value>
+ <!-- Isometric Off Axis 4 Left -->
+ <value>isometricOffAxis4Left</value>
+ <!-- Isometric Off Axis 4 Right -->
+ <value>isometricOffAxis4Right</value>
+ <!-- Isometric Off Axis 4 Bottom -->
+ <value>isometricOffAxis4Bottom</value>
+ <!-- Oblique Top Left -->
+ <value>obliqueTopLeft</value>
+ <!-- Oblique Top -->
+ <value>obliqueTop</value>
+ <!-- Oblique Top Right -->
+ <value>obliqueTopRight</value>
+ <!-- Oblique Left -->
+ <value>obliqueLeft</value>
+ <!-- Oblique Right -->
+ <value>obliqueRight</value>
+ <!-- Oblique Bottom Left -->
+ <value>obliqueBottomLeft</value>
+ <!-- Oblique Bottom -->
+ <value>obliqueBottom</value>
+ <!-- Oblique Bottom Right -->
+ <value>obliqueBottomRight</value>
+ <!-- Perspective Front -->
+ <value>perspectiveFront</value>
+ <!-- Perspective Left -->
+ <value>perspectiveLeft</value>
+ <!-- Perspective Right -->
+ <value>perspectiveRight</value>
+ <!-- Orthographic Above -->
+ <value>perspectiveAbove</value>
+ <!-- Perspective Below -->
+ <value>perspectiveBelow</value>
+ <!-- Perspective Above Left Facing -->
+ <value>perspectiveAboveLeftFacing</value>
+ <!-- Perspective Above Right Facing -->
+ <value>perspectiveAboveRightFacing</value>
+ <!-- Perspective Contrasting Left Facing -->
+ <value>perspectiveContrastingLeftFacing</value>
+ <!-- Perspective Contrasting Right Facing -->
+ <value>perspectiveContrastingRightFacing</value>
+ <!-- Perspective Heroic Left Facing -->
+ <value>perspectiveHeroicLeftFacing</value>
+ <!-- Perspective Heroic Right Facing -->
+ <value>perspectiveHeroicRightFacing</value>
+ <!-- Perspective Heroic Extreme Left Facing -->
+ <value>perspectiveHeroicExtremeLeftFacing</value>
+ <!-- Perspective Heroic Extreme Right Facing -->
+ <value>perspectiveHeroicExtremeRightFacing</value>
+ <!-- Perspective Relaxed -->
+ <value>perspectiveRelaxed</value>
+ <!-- Perspective Relaxed Moderately -->
+ <value>perspectiveRelaxedModerately</value>
+ </choice>
+ </define>
+ <define name="ST_FOVAngle">
+ </define>
+ <define name="CT_Camera">
+ <element name="rot">
+ <ref name="CT_SphereCoords"/>
+ </element>
+ <attribute name="prst">
+ <ref name="ST_PresetCameraType"/>
+ </attribute>
+ <attribute name="fov">
+ <ref name="ST_FOVAngle"/>
+ </attribute>
+ <attribute name="zoom">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ </grammar>
+ <resource name="ST_PresetCameraType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueTopLeft">legacyObliqueTopLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueTop">legacyObliqueTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueTopRight">legacyObliqueTopRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueLeft">legacyObliqueLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueFront">legacyObliqueFront</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueRight">legacyObliqueRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueBottomLeft">legacyObliqueBottomLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueBottom">legacyObliqueBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyObliqueBottomRight">legacyObliqueBottomRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveTopLeft">legacyPerspectiveTopLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveTop">legacyPerspectiveTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveTopRight">legacyPerspectiveTopRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveLeft">legacyPerspectiveLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveFront">legacyPerspectiveFront</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveRight">legacyPerspectiveRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveBottomLeft">legacyPerspectiveBottomLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveBottom">legacyPerspectiveBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_legacyPerspectiveBottomRight">legacyPerspectiveBottomRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_orthographicFront">orthographicFront</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricTopUp">isometricTopUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricTopDown">isometricTopDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricBottomUp">isometricBottomUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricBottomDown">isometricBottomDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricLeftUp">isometricLeftUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricLeftDown">isometricLeftDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricRightUp">isometricRightUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricRightDown">isometricRightDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis1Left">isometricOffAxis1Left</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis1Right">isometricOffAxis1Right</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis1Top">isometricOffAxis1Top</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis2Left">isometricOffAxis2Left</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis2Right">isometricOffAxis2Right</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis2Top">isometricOffAxis2Top</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis3Left">isometricOffAxis3Left</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis3Right">isometricOffAxis3Right</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis3Bottom">isometricOffAxis3Bottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis4Left">isometricOffAxis4Left</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis4Right">isometricOffAxis4Right</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_isometricOffAxis4Bottom">isometricOffAxis4Bottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueTopLeft">obliqueTopLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueTop">obliqueTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueTopRight">obliqueTopRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueLeft">obliqueLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueRight">obliqueRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueBottomLeft">obliqueBottomLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueBottom">obliqueBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_obliqueBottomRight">obliqueBottomRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveFront">perspectiveFront</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveLeft">perspectiveLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveRight">perspectiveRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveAbove">perspectiveAbove</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveBelow">perspectiveBelow</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveAboveLeftFacing">perspectiveAboveLeftFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveAboveRightFacing">perspectiveAboveRightFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveContrastingLeftFacing">perspectiveContrastingLeftFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveContrastingRightFacing">perspectiveContrastingRightFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveHeroicLeftFacing">perspectiveHeroicLeftFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveHeroicRightFacing">perspectiveHeroicRightFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveHeroicExtremeLeftFacing">perspectiveHeroicExtremeLeftFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveHeroicExtremeRightFacing">perspectiveHeroicExtremeRightFacing</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveRelaxed">perspectiveRelaxed</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetCameraType_perspectiveRelaxedModerately">perspectiveRelaxedModerately</value>
+ </resource>
+ </namespace>
+ <namespace name="dml-baseStylesheet">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <!-- ISO RELAX NG Schema -->
+ <define name="ST_ColorSchemeIndex">
+ <choice>
+ <!-- Dark 1 -->
+ <value>dk1</value>
+ <!-- Light 1 -->
+ <value>lt1</value>
+ <!-- Dark 2 -->
+ <value>dk2</value>
+ <!-- Light 2 -->
+ <value>lt2</value>
+ <!-- Accent 1 -->
+ <value>accent1</value>
+ <!-- Accent 2 -->
+ <value>accent2</value>
+ <!-- Accent 3 -->
+ <value>accent3</value>
+ <!-- Accent 4 -->
+ <value>accent4</value>
+ <!-- Accent 5 -->
+ <value>accent5</value>
+ <!-- Accent 6 -->
+ <value>accent6</value>
+ <!-- Hyperlink -->
+ <value>hlink</value>
+ <!-- Followed Hyperlink -->
+ <value>folHlink</value>
+ </choice>
+ </define>
+ <define name="CT_ColorScheme">
+ <element name="dk1">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="lt1">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="dk2">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="lt2">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="accent1">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="accent2">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="accent3">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="accent4">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="accent5">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="accent6">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="hlink">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="folHlink">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="name">
+ <data type="string">
+ </data>
+ </attribute>
+ </define>
+ <define name="CT_CustomColor">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="name">
+ <data type="string">
+ </data>
+ </attribute>
+ </define>
+ <define name="CT_SupplementalFont">
+ <attribute name="script">
+ <data type="string">
+ </data>
+ </attribute>
+ <attribute name="typeface">
+ <ref name="ST_TextTypeface"/>
+ <data type="string">
+ </data>
+ </attribute>
+ </define>
+ <define name="CT_CustomColorList">
+ <element name="custClr">
+ <ref name="CT_CustomColor"/>
+ </element>
+ </define>
+ <define name="CT_FontCollection">
+ <element name="latin">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="ea">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="cs">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="font">
+ <ref name="CT_SupplementalFont"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ <define name="CT_EffectStyleItem">
+ <ref name="EG_EffectProperties"/>
+ <element name="scene3d">
+ <ref name="CT_Scene3D"/>
+ </element>
+ <element name="sp3d">
+ <ref name="CT_Shape3D"/>
+ </element>
+ </define>
+ <define name="CT_FontScheme">
+ <element name="majorFont">
+ <ref name="CT_FontCollection"/>
+ </element>
+ <element name="minorFont">
+ <ref name="CT_FontCollection"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FillStyleList">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="CT_LineStyleList">
+ <element name="ln">
+ <ref name="CT_LineProperties"/>
+ </element>
+ </define>
+ <define name="CT_EffectStyleList">
+ <element name="effectStyle">
+ <ref name="CT_EffectStyleItem"/>
+ </element>
+ </define>
+ <define name="CT_BackgroundFillStyleList">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="CT_StyleMatrix">
+ <element name="fillStyleLst">
+ <ref name="CT_FillStyleList"/>
+ </element>
+ <element name="lnStyleLst">
+ <ref name="CT_LineStyleList"/>
+ </element>
+ <element name="effectStyleLst">
+ <ref name="CT_EffectStyleList"/>
+ </element>
+ <element name="bgFillStyleLst">
+ <ref name="CT_BackgroundFillStyleList"/>
+ </element>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_BaseStyles">
+ <element name="clrScheme">
+ <ref name="CT_ColorScheme"/>
+ </element>
+ <element name="fontScheme">
+ <ref name="CT_FontScheme"/>
+ </element>
+ <element name="fmtScheme">
+ <ref name="CT_StyleMatrix"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_ColorSchemeIndex" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_dk1">dk1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_lt1">lt1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_dk2">dk2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_lt2">lt2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_accent1">accent1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_accent2">accent2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_accent3">accent3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_accent4">accent4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_accent5">accent5</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_accent6">accent6</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_hlink">hlink</value>
+ <value tokenid="ooxml:Value_drawingml_ST_ColorSchemeIndex_folHlink">folHlink</value>
+ </resource>
+ <resource name="CT_ColorScheme" resource="Properties">
+ <element name="dk1" tokenid="ooxml:CT_ColorScheme_dk1"/>
+ <element name="lt1" tokenid="ooxml:CT_ColorScheme_lt1"/>
+ <element name="dk2" tokenid="ooxml:CT_ColorScheme_dk2"/>
+ <element name="lt2" tokenid="ooxml:CT_ColorScheme_lt2"/>
+ <element name="accent1" tokenid="ooxml:CT_ColorScheme_accent1"/>
+ <element name="accent2" tokenid="ooxml:CT_ColorScheme_accent2"/>
+ <element name="accent3" tokenid="ooxml:CT_ColorScheme_accent3"/>
+ <element name="accent4" tokenid="ooxml:CT_ColorScheme_accent4"/>
+ <element name="accent5" tokenid="ooxml:CT_ColorScheme_accent5"/>
+ <element name="accent6" tokenid="ooxml:CT_ColorScheme_accent6"/>
+ <element name="hlink" tokenid="ooxml:CT_ColorScheme_hlink"/>
+ <element name="folHlink" tokenid="ooxml:CT_ColorScheme_folHlink"/>
+ <element name="extLst" tokenid="ooxml:CT_ColorScheme_extLst"/>
+ <attribute name="name" tokenid="ooxml:CT_ColorScheme_name"/>
+ </resource>
+ <resource name="CT_SupplementalFont" resource="Properties">
+ <attribute name="script" tokenid="ooxml:CT_SupplementalFont_script"/>
+ <attribute name="typeface" tokenid="ooxml:CT_SupplementalFont_typeface"/>
+ </resource>
+ <resource name="CT_FontCollection" resource="Properties">
+ <element name="latin" tokenid="ooxml:CT_FontCollection_latin"/>
+ <element name="ea" tokenid="ooxml:CT_FontCollection_ea"/>
+ <element name="cs" tokenid="ooxml:CT_FontCollection_cs"/>
+ <element name="font" tokenid="ooxml:CT_FontCollection_font"/>
+ <element name="extLst" tokenid="ooxml:CT_FontCollection_extLst"/>
+ </resource>
+ <resource name="CT_FontScheme" resource="Properties">
+ <element name="majorFont" tokenid="ooxml:CT_FontScheme_majorFont"/>
+ <element name="minorFont" tokenid="ooxml:CT_FontScheme_minorFont"/>
+ <element name="extLst" tokenid="ooxml:CT_FontScheme_extLst"/>
+ <attribute name="name" tokenid="ooxml:CT_FontScheme_name"/>
+ </resource>
+ <resource name="CT_FillStyleList" resource="Properties"/>
+ <resource name="CT_LineStyleList" resource="Properties">
+ <element name="ln" tokenid="ooxml:CT_LineStyleList_ln"/>
+ </resource>
+ <resource name="CT_EffectStyleList" resource="Properties">
+ <element name="effectStyle" tokenid="ooxml:CT_EffectStyleList_effectStyle"/>
+ </resource>
+ <resource name="CT_BackgroundFillStyleList" resource="Properties"/>
+ <resource name="CT_StyleMatrix" resource="Properties">
+ <element name="fillStyleLst" tokenid="ooxml:CT_StyleMatrix_fillStyleLst"/>
+ <element name="lnStyleLst" tokenid="ooxml:CT_StyleMatrix_lnStyleLst"/>
+ <element name="effectStyleLst" tokenid="ooxml:CT_StyleMatrix_effectStyleLst"/>
+ <element name="bgFillStyleLst" tokenid="ooxml:CT_StyleMatrix_bgFillStyleLst"/>
+ <attribute name="name" tokenid="ooxml:CT_StyleMatrix_name"/>
+ </resource>
+ <resource name="CT_BaseStyles" resource="Properties">
+ <element name="clrScheme" tokenid="ooxml:CT_BaseStyles_clrScheme"/>
+ <element name="fontScheme" tokenid="ooxml:CT_BaseStyles_fontScheme"/>
+ <element name="fmtScheme" tokenid="ooxml:CT_BaseStyles_fmtScheme"/>
+ <element name="extLst" tokenid="ooxml:CT_BaseStyles_extLst"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-textCharacter">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shapeEffects"/>
+ <include href="dml-shapeLineProperties"/>
+ <define name="ST_TextPoint">
+ <data type="int"/>
+ </define>
+ <define name="ST_TextNonNegativePoint">
+ <data type="int"/>
+ </define>
+ <define name="ST_TextFontSize">
+ <data type="int"/>
+ </define>
+ <define name="ST_Panose">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_TextTypeface">
+ <data type="string"/>
+ </define>
+ <define name="CT_TextFont">
+ <attribute name="typeface">
+ <ref name="ST_TextTypeface"/>
+ </attribute>
+ <attribute name="panose">
+ <ref name="ST_Panose"/>
+ </attribute>
+ <attribute name="pitchFamily">
+ <data type="byte"/>
+ </attribute>
+ <attribute name="charset">
+ <data type="byte"/>
+ </attribute>
+ </define>
+ <define name="ST_TextLanguageID">
+ <data type="string"/>
+ </define>
+ <define name="ST_TextUnderlineType">
+ <choice>
+ <!-- Text Underline Enum ( None ) -->
+ <value>none</value>
+ <!-- Text Underline Enum ( Words ) -->
+ <value>words</value>
+ <!-- Text Underline Enum ( Single ) -->
+ <value>sng</value>
+ <!-- Text Underline Enum ( Double ) -->
+ <value>dbl</value>
+ <!-- Text Underline Enum ( Heavy ) -->
+ <value>heavy</value>
+ <!-- Text Underline Enum ( Dotted ) -->
+ <value>dotted</value>
+ <!-- Text Underline Enum ( Heavy Dotted ) -->
+ <value>dottedHeavy</value>
+ <!-- Text Underline Enum ( Dashed ) -->
+ <value>dash</value>
+ <!-- Text Underline Enum ( Heavy Dashed ) -->
+ <value>dashHeavy</value>
+ <!-- Text Underline Enum ( Long Dashed ) -->
+ <value>dashLong</value>
+ <!-- Text Underline Enum ( Heavy Long Dashed ) -->
+ <value>dashLongHeavy</value>
+ <!-- Text Underline Enum ( Dot Dash ) -->
+ <value>dotDash</value>
+ <!-- Text Underline Enum ( Heavy Dot Dash ) -->
+ <value>dotDashHeavy</value>
+ <!-- Text Underline Enum ( Dot Dot Dash ) -->
+ <value>dotDotDash</value>
+ <!-- Text Underline Enum ( Heavy Dot Dot Dash ) -->
+ <value>dotDotDashHeavy</value>
+ <!-- Text Underline Enum ( Wavy ) -->
+ <value>wavy</value>
+ <!-- Text Underline Enum ( Heavy Wavy ) -->
+ <value>wavyHeavy</value>
+ <!-- Text Underline Enum ( Double Wavy ) -->
+ <value>wavyDbl</value>
+ </choice>
+ </define>
+ <define name="CT_TextUnderlineLineFollowText">
+ </define>
+ <define name="CT_TextUnderlineFillFollowText">
+ </define>
+ <define name="CT_TextUnderlineFillGroupWrapper">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="EG_TextUnderlineLine">
+ <choice>
+ <element name="uLnTx">
+ <ref name="CT_TextUnderlineLineFollowText"/>
+ </element>
+ <element name="uLn">
+ <ref name="CT_LineProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_TextUnderlineFill">
+ <choice>
+ <element name="uFillTx">
+ <ref name="CT_TextUnderlineFillFollowText"/>
+ </element>
+ <element name="uFill">
+ <ref name="CT_TextUnderlineFillGroupWrapper"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_TextStrikeType">
+ <choice>
+ <!-- Text Strike Enum ( No Strike ) -->
+ <value>noStrike</value>
+ <!-- Text Strike Enum ( Single Strike ) -->
+ <value>sngStrike</value>
+ <!-- Text Strike Enum ( Double Strike ) -->
+ <value>dblStrike</value>
+ </choice>
+ </define>
+ <define name="ST_TextCapsType">
+ <choice>
+ <!-- Text Caps Enum ( None ) -->
+ <value>none</value>
+ <!-- Text Caps Enum ( Small ) -->
+ <value>small</value>
+ <!-- Text Caps Enum ( All ) -->
+ <value>all</value>
+ </choice>
+ </define>
+ <define name="CT_TextCharacterProperties">
+ <element name="ln">
+ <ref name="CT_LineProperties"/>
+ </element>
+ <ref name="EG_FillProperties"/>
+ <ref name="EG_EffectProperties"/>
+ <element name="highlight">
+ <ref name="CT_Color"/>
+ </element>
+ <ref name="EG_TextUnderlineLine"/>
+ <ref name="EG_TextUnderlineFill"/>
+ <element name="latin">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="ea">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="cs">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="sym">
+ <ref name="CT_TextFont"/>
+ </element>
+ <element name="hlinkClick">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ <element name="hlinkMouseOver">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="kumimoji">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="lang">
+ <ref name="ST_TextLanguageID"/>
+ </attribute>
+ <attribute name="altLang">
+ <ref name="ST_TextLanguageID"/>
+ </attribute>
+ <attribute name="sz">
+ <ref name="ST_TextFontSize"/>
+ </attribute>
+ <attribute name="b">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="i">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="u">
+ <ref name="ST_TextUnderlineType"/>
+ </attribute>
+ <attribute name="strike">
+ <ref name="ST_TextStrikeType"/>
+ </attribute>
+ <attribute name="kern">
+ <ref name="ST_TextNonNegativePoint"/>
+ </attribute>
+ <attribute name="cap">
+ <ref name="ST_TextCapsType"/>
+ </attribute>
+ <attribute name="spc">
+ <ref name="ST_TextPoint"/>
+ </attribute>
+ <attribute name="normalizeH">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="baseline">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="noProof">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="dirty">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="err">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="smtClean">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="smtId">
+ <data type="unsignedInt"/>
+ </attribute>
+ <attribute name="bmk">
+ <data type="string"/>
+ </attribute>
+ </define>
+ </grammar>
+ <resource name="ST_TextPoint" resource="Integer"/>
+ <resource name="ST_TextNonNegativePoint" resource="Integer"/>
+ <resource name="ST_TextFontSize" resource="Integer"/>
+ <resource name="ST_Panose" resource="Hex"/>
+ <resource name="ST_TextTypeface" resource="String"/>
+ <resource name="CT_TextFont" resource="Properties">
+ <attribute name="typeface" tokenid="ooxml:CT_TextFont_typeface"/>
+ <attribute name="panose" tokenid="ooxml:CT_TextFont_panose"/>
+ <attribute name="pitchFamily" tokenid="ooxml:CT_TextFont_pitchFamily"/>
+ <attribute name="charset" tokenid="ooxml:CT_TextFont_charset"/>
+ </resource>
+ <resource name="ST_TextLanguageID" resource="String"/>
+ <resource name="ST_TextUnderlineType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_none">none</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_words">words</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_sng">sng</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dbl">dbl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_heavy">heavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dotted">dotted</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dottedHeavy">dottedHeavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dash">dash</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dashHeavy">dashHeavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dashLong">dashLong</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dashLongHeavy">dashLongHeavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dotDash">dotDash</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dotDashHeavy">dotDashHeavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dotDotDash">dotDotDash</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_dotDotDashHeavy">dotDotDashHeavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_wavy">wavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_wavyHeavy">wavyHeavy</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextUnderlineType_wavyDbl">wavyDbl</value>
+ </resource>
+ <resource name="ST_TextStrikeType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_TextStrikeType_noStrike">noStrike</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextStrikeType_sngStrike">sngStrike</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextStrikeType_dblStrike">dblStrike</value>
+ </resource>
+ <resource name="ST_TextCapsType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_TextCapsType_none">none</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextCapsType_small">small</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextCapsType_all">all</value>
+ </resource>
+ </namespace>
+ <namespace name="dml-shapeEffects">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <!-- start = blip -->
+ <define name="CT_AlphaBiLevelEffect">
+ <attribute name="thresh">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_AlphaCeilingEffect">
+ </define>
+ <define name="CT_AlphaFloorEffect">
+ </define>
+ <define name="CT_AlphaInverseEffect">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_AlphaModulateFixedEffect">
+ <attribute name="amt">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_AlphaOutsetEffect">
+ <attribute name="rad">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_AlphaReplaceEffect">
+ <attribute name="a">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_BiLevelEffect">
+ <attribute name="thresh">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_BlurEffect">
+ <attribute name="rad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="grow">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_ColorChangeEffect">
+ <element name="clrFrom">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="clrTo">
+ <ref name="CT_Color"/>
+ </element>
+ <attribute name="useA">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_ColorReplaceEffect">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_DuotoneEffect">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_GlowEffect">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="rad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_GrayscaleEffect">
+ </define>
+ <define name="CT_HSLEffect">
+ <attribute name="hue">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sat">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ <attribute name="lum">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_InnerShadowEffect">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_LuminanceEffect">
+ <attribute name="bright">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ <attribute name="contrast">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_OuterShadowEffect">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ <attribute name="rotWithShape">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="ST_PresetShadowVal">
+ <choice>
+ <!-- Top Left Drop Shadow -->
+ <value>shdw1</value>
+ <!-- Top Right Drop Shadow -->
+ <value>shdw2</value>
+ <!-- Back Left Perspective Shadow -->
+ <value>shdw3</value>
+ <!-- Back Right Perspective Shadow -->
+ <value>shdw4</value>
+ <!-- Bottom Left Drop Shadow -->
+ <value>shdw5</value>
+ <!-- Bottom Right Drop Shadow -->
+ <value>shdw6</value>
+ <!-- Front Left Perspective Shadow -->
+ <value>shdw7</value>
+ <!-- Front Right Perspective Shadow -->
+ <value>shdw8</value>
+ <!-- Top Left Small Drop Shadow -->
+ <value>shdw9</value>
+ <!-- Top Left Large Drop Shadow -->
+ <value>shdw10</value>
+ <!-- Back Left Long Perspective Shadow -->
+ <value>shdw11</value>
+ <!-- Back Right Long Perspective Shadow -->
+ <value>shdw12</value>
+ <!-- Top Left Double Drop Shadow -->
+ <value>shdw13</value>
+ <!-- Bottom Right Small Drop Shadow -->
+ <value>shdw14</value>
+ <!-- Front Left Long Perspective Shadow -->
+ <value>shdw15</value>
+ <!-- Front Right LongPerspective Shadow -->
+ <value>shdw16</value>
+ <!-- 3D Outer Box Shadow -->
+ <value>shdw17</value>
+ <!-- 3D Inner Box Shadow -->
+ <value>shdw18</value>
+ <!-- Back Center Perspective Shadow -->
+ <value>shdw19</value>
+ <!-- Front Bottom Shadow -->
+ <value>shdw20</value>
+ </choice>
+ </define>
+ <define name="CT_PresetShadowEffect">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="prst">
+ <ref name="ST_PresetShadowVal"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_ReflectionEffect">
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="stA">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="stPos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="endA">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="endPos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="fadeDir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ <attribute name="rotWithShape">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_RelativeOffsetEffect">
+ <attribute name="tx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="ty">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_SoftEdgesEffect">
+ <attribute name="rad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_TintEffect">
+ <attribute name="hue">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="amt">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_TransformEffect">
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="tx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="ty">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_NoFillProperties">
+ </define>
+ <define name="CT_SolidColorFillProperties">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_LinearShadeProperties">
+ <attribute name="ang">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="scaled">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="ST_PathShadeType">
+ <choice>
+ <!-- Shape -->
+ <value>shape</value>
+ <!-- Circle -->
+ <value>circle</value>
+ <!-- Rectangle -->
+ <value>rect</value>
+ </choice>
+ </define>
+ <define name="CT_PathShadeProperties">
+ <element name="fillToRect">
+ <ref name="CT_RelativeRect"/>
+ </element>
+ <attribute name="path">
+ <ref name="ST_PathShadeType"/>
+ </attribute>
+ </define>
+ <define name="EG_ShadeProperties">
+ <choice>
+ <element name="lin">
+ <ref name="CT_LinearShadeProperties"/>
+ </element>
+ <element name="path">
+ <ref name="CT_PathShadeProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_TileFlipMode">
+ <choice>
+ <!-- None -->
+ <value>none</value>
+ <!-- Horizontal -->
+ <value>x</value>
+ <!-- Vertical -->
+ <value>y</value>
+ <!-- Horizontal and Vertical -->
+ <value>xy</value>
+ </choice>
+ </define>
+ <define name="CT_GradientStop">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="pos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_GradientStopList">
+ <element name="gs">
+ <ref name="CT_GradientStop"/>
+ </element>
+ </define>
+ <define name="CT_GradientFillProperties">
+ <element name="gsLst">
+ <ref name="CT_GradientStopList"/>
+ </element>
+ <ref name="EG_ShadeProperties"/>
+ <element name="tileRect">
+ <ref name="CT_RelativeRect"/>
+ </element>
+ <attribute name="flip">
+ <ref name="ST_TileFlipMode"/>
+ </attribute>
+ <attribute name="rotWithShape">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_TileInfoProperties">
+ <attribute name="tx">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="ty">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="flip">
+ <ref name="ST_TileFlipMode"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_StretchInfoProperties">
+ <element name="fillRect">
+ <ref name="CT_RelativeRect"/>
+ </element>
+ </define>
+ <define name="EG_FillModeProperties">
+ <choice>
+ <element name="tile">
+ <ref name="CT_TileInfoProperties"/>
+ </element>
+ <element name="stretch">
+ <ref name="CT_StretchInfoProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_BlipCompression">
+ <choice>
+ <!-- Email Compression -->
+ <value>email</value>
+ <!-- Screen Viewing Compression -->
+ <value>screen</value>
+ <!-- Printing Compression -->
+ <value>print</value>
+ <!-- High Quality Printing Compression -->
+ <value>hqprint</value>
+ <!-- No Compression -->
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="CT_Blip">
+ <choice>
+ <element name="alphaBiLevel">
+ <ref name="CT_AlphaBiLevelEffect"/>
+ </element>
+ <element name="alphaCeiling">
+ <ref name="CT_AlphaCeilingEffect"/>
+ </element>
+ <element name="alphaFloor">
+ <ref name="CT_AlphaFloorEffect"/>
+ </element>
+ <element name="alphaInv">
+ <ref name="CT_AlphaInverseEffect"/>
+ </element>
+ <element name="alphaMod">
+ <ref name="CT_AlphaModulateEffect"/>
+ </element>
+ <element name="alphaModFix">
+ <ref name="CT_AlphaModulateFixedEffect"/>
+ </element>
+ <element name="alphaRepl">
+ <ref name="CT_AlphaReplaceEffect"/>
+ </element>
+ <element name="biLevel">
+ <ref name="CT_BiLevelEffect"/>
+ </element>
+ <element name="blur">
+ <ref name="CT_BlurEffect"/>
+ </element>
+ <element name="clrChange">
+ <ref name="CT_ColorChangeEffect"/>
+ </element>
+ <element name="clrRepl">
+ <ref name="CT_ColorReplaceEffect"/>
+ </element>
+ <element name="duotone">
+ <ref name="CT_DuotoneEffect"/>
+ </element>
+ <element name="fillOverlay">
+ <ref name="CT_FillOverlayEffect"/>
+ </element>
+ <element name="grayscl">
+ <ref name="CT_GrayscaleEffect"/>
+ </element>
+ <element name="hsl">
+ <ref name="CT_HSLEffect"/>
+ </element>
+ <element name="lum">
+ <ref name="CT_LuminanceEffect"/>
+ </element>
+ <element name="tint">
+ <ref name="CT_TintEffect"/>
+ </element>
+ </choice>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Blob"/>
+ <attribute name="cstate">
+ <ref name="ST_BlipCompression"/>
+ </attribute>
+ </define>
+ <define name="CT_BlipFillProperties">
+ <element name="blip">
+ <ref name="CT_Blip"/>
+ </element>
+ <element name="srcRect">
+ <ref name="CT_RelativeRect"/>
+ </element>
+ <ref name="EG_FillModeProperties"/>
+ <attribute name="dpi">
+ <data type="unsignedInt"/>
+ </attribute>
+ <attribute name="rotWithShape">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="ST_PresetPatternVal">
+ <choice>
+ <!-- 5% -->
+ <value>pct5</value>
+ <!-- 10% -->
+ <value>pct10</value>
+ <!-- 20% -->
+ <value>pct20</value>
+ <!-- 25% -->
+ <value>pct25</value>
+ <!-- 30% -->
+ <value>pct30</value>
+ <!-- 40% -->
+ <value>pct40</value>
+ <!-- 50% -->
+ <value>pct50</value>
+ <!-- 60% -->
+ <value>pct60</value>
+ <!-- 70% -->
+ <value>pct70</value>
+ <!-- 75% -->
+ <value>pct75</value>
+ <!-- 80% -->
+ <value>pct80</value>
+ <!-- 90% -->
+ <value>pct90</value>
+ <!-- Horizontal -->
+ <value>horz</value>
+ <!-- Vertical -->
+ <value>vert</value>
+ <!-- Light Horizontal -->
+ <value>ltHorz</value>
+ <!-- Light Vertical -->
+ <value>ltVert</value>
+ <!-- Dark Horizontal -->
+ <value>dkHorz</value>
+ <!-- Dark Vertical -->
+ <value>dkVert</value>
+ <!-- Narrow Horizontal -->
+ <value>narHorz</value>
+ <!-- Narrow Vertical -->
+ <value>narVert</value>
+ <!-- Dashed Horizontal -->
+ <value>dashHorz</value>
+ <!-- Dashed Vertical -->
+ <value>dashVert</value>
+ <!-- Cross -->
+ <value>cross</value>
+ <!-- Downward Diagonal -->
+ <value>dnDiag</value>
+ <!-- Upward Diagonal -->
+ <value>upDiag</value>
+ <!-- Light Downward Diagonal -->
+ <value>ltDnDiag</value>
+ <!-- Light Upward Diagonal -->
+ <value>ltUpDiag</value>
+ <!-- Dark Downward Diagonal -->
+ <value>dkDnDiag</value>
+ <!-- Dark Upward Diagonal -->
+ <value>dkUpDiag</value>
+ <!-- Wide Downward Diagonal -->
+ <value>wdDnDiag</value>
+ <!-- Wide Upward Diagonal -->
+ <value>wdUpDiag</value>
+ <!-- Dashed Downward Diagonal -->
+ <value>dashDnDiag</value>
+ <!-- Dashed Upward Diagonal -->
+ <value>dashUpDiag</value>
+ <!-- Diagonal Cross -->
+ <value>diagCross</value>
+ <!-- Small Checker Board -->
+ <value>smCheck</value>
+ <!-- Large Checker Board -->
+ <value>lgCheck</value>
+ <!-- Small Grid -->
+ <value>smGrid</value>
+ <!-- Large Grid -->
+ <value>lgGrid</value>
+ <!-- Dotted Grid -->
+ <value>dotGrid</value>
+ <!-- Small Confetti -->
+ <value>smConfetti</value>
+ <!-- Large Confetti -->
+ <value>lgConfetti</value>
+ <!-- Horizontal Brick -->
+ <value>horzBrick</value>
+ <!-- Diagonal Brick -->
+ <value>diagBrick</value>
+ <!-- Solid Diamond -->
+ <value>solidDmnd</value>
+ <!-- Open Diamond -->
+ <value>openDmnd</value>
+ <!-- Dotted Diamond -->
+ <value>dotDmnd</value>
+ <!-- Plaid -->
+ <value>plaid</value>
+ <!-- Sphere -->
+ <value>sphere</value>
+ <!-- Weave -->
+ <value>weave</value>
+ <!-- Divot -->
+ <value>divot</value>
+ <!-- Shingle -->
+ <value>shingle</value>
+ <!-- Wave -->
+ <value>wave</value>
+ <!-- Trellis -->
+ <value>trellis</value>
+ <!-- Zig Zag -->
+ <value>zigZag</value>
+ <!-- Dashed Dotted -->
+ <value>dashDot</value>
+ <!-- Dashed Dotted Upward Diagonal -->
+ <value>dashdotUpDiag</value>
+ <!-- Solid Dotted -->
+ <value>lsolidDoted</value>
+ </choice>
+ </define>
+ <define name="CT_PatternFillProperties">
+ <element name="fgClr">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="bgClr">
+ <ref name="CT_Color"/>
+ </element>
+ <attribute name="prst">
+ <ref name="ST_PresetPatternVal"/>
+ </attribute>
+ </define>
+ <define name="CT_GroupFillProperties">
+ </define>
+ <define name="EG_FillProperties">
+ <choice>
+ <element name="noFill">
+ <ref name="CT_NoFillProperties"/>
+ </element>
+ <element name="solidFill">
+ <ref name="CT_SolidColorFillProperties"/>
+ </element>
+ <element name="gradFill">
+ <ref name="CT_GradientFillProperties"/>
+ </element>
+ <element name="blipFill">
+ <ref name="CT_BlipFillProperties"/>
+ </element>
+ <element name="pattFill">
+ <ref name="CT_PatternFillProperties"/>
+ </element>
+ <element name="grpFill">
+ <ref name="CT_GroupFillProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_FillProperties">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="CT_FillEffect">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="ST_BlendMode">
+ <choice>
+ <!-- Overlay -->
+ <value>over</value>
+ <!-- Multiply -->
+ <value>mult</value>
+ <!-- Screen -->
+ <value>screen</value>
+ <!-- Darken -->
+ <value>darken</value>
+ <!-- Lighten -->
+ <value>lighten</value>
+ </choice>
+ </define>
+ <define name="CT_FillOverlayEffect">
+ <ref name="EG_FillProperties"/>
+ <attribute name="blend">
+ <ref name="ST_BlendMode"/>
+ </attribute>
+ </define>
+ <define name="CT_EffectReference">
+ <attribute name="ref">
+ <data type="token"/>
+ </attribute>
+ </define>
+ <define name="EG_Effect">
+ <choice>
+ <element name="cont">
+ <ref name="CT_EffectContainer"/>
+ </element>
+ <element name="effect">
+ <ref name="CT_EffectReference"/>
+ </element>
+ <element name="alphaBiLevel">
+ <ref name="CT_AlphaBiLevelEffect"/>
+ </element>
+ <element name="alphaCeiling">
+ <ref name="CT_AlphaCeilingEffect"/>
+ </element>
+ <element name="alphaFloor">
+ <ref name="CT_AlphaFloorEffect"/>
+ </element>
+ <element name="alphaInv">
+ <ref name="CT_AlphaInverseEffect"/>
+ </element>
+ <element name="alphaMod">
+ <ref name="CT_AlphaModulateEffect"/>
+ </element>
+ <element name="alphaModFix">
+ <ref name="CT_AlphaModulateFixedEffect"/>
+ </element>
+ <element name="alphaOutset">
+ <ref name="CT_AlphaOutsetEffect"/>
+ </element>
+ <element name="alphaRepl">
+ <ref name="CT_AlphaReplaceEffect"/>
+ </element>
+ <element name="biLevel">
+ <ref name="CT_BiLevelEffect"/>
+ </element>
+ <element name="blend">
+ <ref name="CT_BlendEffect"/>
+ </element>
+ <element name="blur">
+ <ref name="CT_BlurEffect"/>
+ </element>
+ <element name="clrChange">
+ <ref name="CT_ColorChangeEffect"/>
+ </element>
+ <element name="clrRepl">
+ <ref name="CT_ColorReplaceEffect"/>
+ </element>
+ <element name="duotone">
+ <ref name="CT_DuotoneEffect"/>
+ </element>
+ <element name="fill">
+ <ref name="CT_FillEffect"/>
+ </element>
+ <element name="fillOverlay">
+ <ref name="CT_FillOverlayEffect"/>
+ </element>
+ <element name="glow">
+ <ref name="CT_GlowEffect"/>
+ </element>
+ <element name="grayscl">
+ <ref name="CT_GrayscaleEffect"/>
+ </element>
+ <element name="hsl">
+ <ref name="CT_HSLEffect"/>
+ </element>
+ <element name="innerShdw">
+ <ref name="CT_InnerShadowEffect"/>
+ </element>
+ <element name="lum">
+ <ref name="CT_LuminanceEffect"/>
+ </element>
+ <element name="outerShdw">
+ <ref name="CT_OuterShadowEffect"/>
+ </element>
+ <element name="prstShdw">
+ <ref name="CT_PresetShadowEffect"/>
+ </element>
+ <element name="reflection">
+ <ref name="CT_ReflectionEffect"/>
+ </element>
+ <element name="relOff">
+ <ref name="CT_RelativeOffsetEffect"/>
+ </element>
+ <element name="softEdge">
+ <ref name="CT_SoftEdgesEffect"/>
+ </element>
+ <element name="tint">
+ <ref name="CT_TintEffect"/>
+ </element>
+ <element name="xfrm">
+ <ref name="CT_TransformEffect"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_EffectContainerType">
+ <choice>
+ <!-- Sibling -->
+ <value>sib</value>
+ <!-- Tree -->
+ <value>tree</value>
+ </choice>
+ </define>
+ <define name="CT_EffectContainer">
+ <ref name="EG_Effect"/>
+ <attribute name="type">
+ <ref name="ST_EffectContainerType"/>
+ </attribute>
+ <attribute name="name">
+ <data type="token"/>
+ </attribute>
+ </define>
+ <define name="CT_AlphaModulateEffect">
+ <element name="cont">
+ <ref name="CT_EffectContainer"/>
+ </element>
+ </define>
+ <define name="CT_BlendEffect">
+ <element name="cont">
+ <ref name="CT_EffectContainer"/>
+ </element>
+ <attribute name="blend">
+ <ref name="ST_BlendMode"/>
+ </attribute>
+ </define>
+ <define name="CT_EffectList">
+ <element name="blur">
+ <ref name="CT_BlurEffect"/>
+ </element>
+ <element name="fillOverlay">
+ <ref name="CT_FillOverlayEffect"/>
+ </element>
+ <element name="glow">
+ <ref name="CT_GlowEffect"/>
+ </element>
+ <element name="innerShdw">
+ <ref name="CT_InnerShadowEffect"/>
+ </element>
+ <element name="outerShdw">
+ <ref name="CT_OuterShadowEffect"/>
+ </element>
+ <element name="prstShdw">
+ <ref name="CT_PresetShadowEffect"/>
+ </element>
+ <element name="reflection">
+ <ref name="CT_ReflectionEffect"/>
+ </element>
+ <element name="softEdge">
+ <ref name="CT_SoftEdgesEffect"/>
+ </element>
+ </define>
+ <define name="EG_EffectProperties">
+ <choice>
+ <element name="effectLst">
+ <ref name="CT_EffectList"/>
+ </element>
+ <element name="effectDag">
+ <ref name="CT_EffectContainer"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_EffectProperties">
+ <ref name="EG_EffectProperties"/>
+ </define>
+ <define name="blip">
+ <element name="blip">
+ <ref name="CT_Blip"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_PresetShadowVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw1">shdw1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw2">shdw2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw3">shdw3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw4">shdw4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw5">shdw5</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw6">shdw6</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw7">shdw7</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw8">shdw8</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw9">shdw9</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw10">shdw10</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw11">shdw11</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw12">shdw12</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw13">shdw13</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw14">shdw14</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw15">shdw15</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw16">shdw16</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw17">shdw17</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw18">shdw18</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw19">shdw19</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetShadowVal_shdw20">shdw20</value>
+ </resource>
+ <resource name="CT_SolidColorFillProperties" resource="Properties"/>
+ <resource name="ST_PathShadeType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PathShadeType_shape">shape</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathShadeType_circle">circle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathShadeType_rect">rect</value>
+ </resource>
+ <resource name="ST_TileFlipMode" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_TileFlipMode_none">none</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TileFlipMode_x">x</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TileFlipMode_y">y</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TileFlipMode_xy">xy</value>
+ </resource>
+ <resource name="CT_GradientStop" resource="Properties">
+ <attribute name="pos" tokenid="ooxml:CT_GradientStop_pos"/>
+ </resource>
+ <resource name="CT_TileInfoProperties" resource="Properties">
+ <attribute name="tx" tokenid="ooxml:CT_TileInfoProperties_tx"/>
+ <attribute name="ty" tokenid="ooxml:CT_TileInfoProperties_ty"/>
+ <attribute name="sx" tokenid="ooxml:CT_TileInfoProperties_sx"/>
+ <attribute name="sy" tokenid="ooxml:CT_TileInfoProperties_sy"/>
+ <attribute name="flip" tokenid="ooxml:CT_TileInfoProperties_flip"/>
+ <attribute name="algn" tokenid="ooxml:CT_TileInfoProperties_algn"/>
+ </resource>
+ <resource name="CT_StretchInfoProperties" resource="Properties">
+ <element name="fillRect" tokenid="ooxml:CT_StretchInfoProperties_fillRect"/>
+ </resource>
+ <resource name="EG_FillModeProperties" resource="Properties">
+ <element name="tile" tokenid="ooxml:EG_FillModeProperties_tile"/>
+ <element name="stretch" tokenid="ooxml:EG_FillModeProperties_stretch"/>
+ </resource>
+ <resource name="ST_BlipCompression" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_BlipCompression_email">email</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlipCompression_screen">screen</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlipCompression_print">print</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlipCompression_hqprint">hqprint</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlipCompression_none">none</value>
+ </resource>
+ <resource name="CT_Blip" resource="Properties">
+ <element name="alphaBiLevel" tokenid="ooxml:CT_Blip_alphaBiLevel"/>
+ <element name="alphaCeiling" tokenid="ooxml:CT_Blip_alphaCeiling"/>
+ <element name="alphaFloor" tokenid="ooxml:CT_Blip_alphaFloor"/>
+ <element name="alphaInv" tokenid="ooxml:CT_Blip_alphaInv"/>
+ <element name="alphaMod" tokenid="ooxml:CT_Blip_alphaMod"/>
+ <element name="alphaModFix" tokenid="ooxml:CT_Blip_alphaModFix"/>
+ <element name="alphaRepl" tokenid="ooxml:CT_Blip_alphaRepl"/>
+ <element name="biLevel" tokenid="ooxml:CT_Blip_biLevel"/>
+ <element name="blur" tokenid="ooxml:CT_Blip_blur"/>
+ <element name="clrChange" tokenid="ooxml:CT_Blip_clrChange"/>
+ <element name="clrRepl" tokenid="ooxml:CT_Blip_clrRepl"/>
+ <element name="duotone" tokenid="ooxml:CT_Blip_duotone"/>
+ <element name="fillOverlay" tokenid="ooxml:CT_Blip_fillOverlay"/>
+ <element name="grayscl" tokenid="ooxml:CT_Blip_grayscl"/>
+ <element name="hsl" tokenid="ooxml:CT_Blip_hsl"/>
+ <element name="lum" tokenid="ooxml:CT_Blip_lum"/>
+ <element name="tint" tokenid="ooxml:CT_Blip_tint"/>
+ <element name="extLst" tokenid="ooxml:CT_Blip_extLst"/>
+ <attribute name="cstate" tokenid="ooxml:CT_Blip_cstate"/>
+ </resource>
+ <resource name="CT_BlipFillProperties" resource="Properties">
+ <element name="blip" tokenid="ooxml:CT_BlipFillProperties_blip"/>
+ <element name="srcRect" tokenid="ooxml:CT_BlipFillProperties_srcRect"/>
+ <attribute name="dpi" tokenid="ooxml:CT_BlipFillProperties_dpi"/>
+ <attribute name="rotWithShape" tokenid="ooxml:CT_BlipFillProperties_rotWithShape"/>
+ </resource>
+ <resource name="ST_PresetPatternVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct5">pct5</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct10">pct10</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct20">pct20</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct25">pct25</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct30">pct30</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct40">pct40</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct50">pct50</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct60">pct60</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct70">pct70</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct75">pct75</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct80">pct80</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_pct90">pct90</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_horz">horz</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_vert">vert</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_ltHorz">ltHorz</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_ltVert">ltVert</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dkHorz">dkHorz</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dkVert">dkVert</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_narHorz">narHorz</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_narVert">narVert</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dashHorz">dashHorz</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dashVert">dashVert</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_cross">cross</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dnDiag">dnDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_upDiag">upDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_ltDnDiag">ltDnDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_ltUpDiag">ltUpDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dkDnDiag">dkDnDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dkUpDiag">dkUpDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_wdDnDiag">wdDnDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_wdUpDiag">wdUpDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dashDnDiag">dashDnDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dashUpDiag">dashUpDiag</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_diagCross">diagCross</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_smCheck">smCheck</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_lgCheck">lgCheck</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_smGrid">smGrid</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_lgGrid">lgGrid</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dotGrid">dotGrid</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_smConfetti">smConfetti</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_lgConfetti">lgConfetti</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_horzBrick">horzBrick</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_diagBrick">diagBrick</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_solidDmnd">solidDmnd</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_openDmnd">openDmnd</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_dotDmnd">dotDmnd</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_plaid">plaid</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_sphere">sphere</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_weave">weave</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_divot">divot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_shingle">shingle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_wave">wave</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_trellis">trellis</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetPatternVal_zigZag">zigZag</value>
+ </resource>
+ <resource name="ST_BlendMode" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_BlendMode_over">over</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlendMode_mult">mult</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlendMode_screen">screen</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlendMode_darken">darken</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlendMode_lighten">lighten</value>
+ </resource>
+ <resource name="EG_Effect" resource="Properties">
+ <element name="cont" tokenid="ooxml:EG_Effect_cont"/>
+ <element name="effect" tokenid="ooxml:EG_Effect_effect"/>
+ <element name="alphaBiLevel" tokenid="ooxml:EG_Effect_alphaBiLevel"/>
+ <element name="alphaCeiling" tokenid="ooxml:EG_Effect_alphaCeiling"/>
+ <element name="alphaFloor" tokenid="ooxml:EG_Effect_alphaFloor"/>
+ <element name="alphaInv" tokenid="ooxml:EG_Effect_alphaInv"/>
+ <element name="alphaMod" tokenid="ooxml:EG_Effect_alphaMod"/>
+ <element name="alphaModFix" tokenid="ooxml:EG_Effect_alphaModFix"/>
+ <element name="alphaOutset" tokenid="ooxml:EG_Effect_alphaOutset"/>
+ <element name="alphaRepl" tokenid="ooxml:EG_Effect_alphaRepl"/>
+ <element name="biLevel" tokenid="ooxml:EG_Effect_biLevel"/>
+ <element name="blend" tokenid="ooxml:EG_Effect_blend"/>
+ <element name="blur" tokenid="ooxml:EG_Effect_blur"/>
+ <element name="clrChange" tokenid="ooxml:EG_Effect_clrChange"/>
+ <element name="clrRepl" tokenid="ooxml:EG_Effect_clrRepl"/>
+ <element name="duotone" tokenid="ooxml:EG_Effect_duotone"/>
+ <element name="fill" tokenid="ooxml:EG_Effect_fill"/>
+ <element name="fillOverlay" tokenid="ooxml:EG_Effect_fillOverlay"/>
+ <element name="glow" tokenid="ooxml:EG_Effect_glow"/>
+ <element name="grayscl" tokenid="ooxml:EG_Effect_grayscl"/>
+ <element name="hsl" tokenid="ooxml:EG_Effect_hsl"/>
+ <element name="innerShdw" tokenid="ooxml:EG_Effect_innerShdw"/>
+ <element name="lum" tokenid="ooxml:EG_Effect_lum"/>
+ <element name="outerShdw" tokenid="ooxml:EG_Effect_outerShdw"/>
+ <element name="prstShdw" tokenid="ooxml:EG_Effect_prstShdw"/>
+ <element name="reflection" tokenid="ooxml:EG_Effect_reflection"/>
+ <element name="relOff" tokenid="ooxml:EG_Effect_relOff"/>
+ <element name="softEdge" tokenid="ooxml:EG_Effect_softEdge"/>
+ <element name="tint" tokenid="ooxml:EG_Effect_tint"/>
+ <element name="xfrm" tokenid="ooxml:EG_Effect_xfrm"/>
+ </resource>
+ <resource name="ST_EffectContainerType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_EffectContainerType_sib">sib</value>
+ <value tokenid="ooxml:Value_drawingml_ST_EffectContainerType_tree">tree</value>
+ </resource>
+ <resource name="CT_EffectContainer" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_EffectContainer_type"/>
+ <attribute name="name" tokenid="ooxml:CT_EffectContainer_name"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-shapeLineProperties">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shapeEffects"/>
+ <define name="ST_LineEndType">
+ <choice>
+ <!-- None -->
+ <value>none</value>
+ <!-- Triangle Arrow Head -->
+ <value>triangle</value>
+ <!-- Stealth Arrow -->
+ <value>stealth</value>
+ <!-- Diamond -->
+ <value>diamond</value>
+ <!-- Oval -->
+ <value>oval</value>
+ <!-- Arrow Head -->
+ <value>arrow</value>
+ </choice>
+ </define>
+ <define name="ST_LineEndWidth">
+ <choice>
+ <!-- Small -->
+ <value>sm</value>
+ <!-- Medium -->
+ <value>med</value>
+ <!-- Large -->
+ <value>lg</value>
+ </choice>
+ </define>
+ <define name="ST_LineEndLength">
+ <choice>
+ <!-- Small -->
+ <value>sm</value>
+ <!-- Medium -->
+ <value>med</value>
+ <!-- Large -->
+ <value>lg</value>
+ </choice>
+ </define>
+ <define name="CT_LineEndProperties">
+ <attribute name="type">
+ <ref name="ST_LineEndType"/>
+ </attribute>
+ <attribute name="w">
+ <ref name="ST_LineEndWidth"/>
+ </attribute>
+ <attribute name="len">
+ <ref name="ST_LineEndLength"/>
+ </attribute>
+ </define>
+ <define name="EG_LineFillProperties">
+ <choice>
+ <element name="noFill">
+ <ref name="CT_NoFillProperties"/>
+ </element>
+ <element name="solidFill">
+ <ref name="CT_SolidColorFillProperties"/>
+ </element>
+ <element name="gradFill">
+ <ref name="CT_GradientFillProperties"/>
+ </element>
+ <element name="pattFill">
+ <ref name="CT_PatternFillProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_LineJoinBevel">
+ </define>
+ <define name="CT_LineJoinRound">
+ </define>
+ <define name="CT_LineJoinMiterProperties">
+ <attribute name="lim">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="EG_LineJoinProperties">
+ <choice>
+ <element name="round">
+ <ref name="CT_LineJoinRound"/>
+ </element>
+ <element name="bevel">
+ <ref name="CT_LineJoinBevel"/>
+ </element>
+ <element name="miter">
+ <ref name="CT_LineJoinMiterProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_PresetLineDashVal">
+ <choice>
+ <!-- Solid -->
+ <value>solid</value>
+ <!-- Dot -->
+ <value>dot</value>
+ <!-- Dash -->
+ <value>dash</value>
+ <!-- Large Dash -->
+ <value>lgDash</value>
+ <!-- Dash Dot -->
+ <value>dashDot</value>
+ <!-- Large Dash Dot -->
+ <value>lgDashDot</value>
+ <!-- Large Dash Dot Dot -->
+ <value>lgDashDotDot</value>
+ <!-- System Dash -->
+ <value>sysDash</value>
+ <!-- System Dot -->
+ <value>sysDot</value>
+ <!-- System Dash Dot -->
+ <value>sysDashDot</value>
+ <!-- System Dash Dot Dot -->
+ <value>sysDashDotDot</value>
+ </choice>
+ </define>
+ <define name="CT_PresetLineDashProperties">
+ <attribute name="val">
+ <ref name="ST_PresetLineDashVal"/>
+ </attribute>
+ </define>
+ <define name="CT_DashStop">
+ <attribute name="d">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ <attribute name="sp">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_DashStopList">
+ <element name="ds">
+ <ref name="CT_DashStop"/>
+ </element>
+ </define>
+ <define name="EG_LineDashProperties">
+ <choice>
+ <element name="prstDash">
+ <ref name="CT_PresetLineDashProperties"/>
+ </element>
+ <element name="custDash">
+ <ref name="CT_DashStopList"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_LineCap">
+ <choice>
+ <!-- Round Line Cap -->
+ <value>rnd</value>
+ <!-- Square Line Cap -->
+ <value>sq</value>
+ <!-- Flat Line Cap -->
+ <value>flat</value>
+ </choice>
+ </define>
+ <define name="ST_LineWidth">
+ </define>
+ <define name="ST_PenAlignment">
+ <choice>
+ <!-- Center Alignment -->
+ <value>ctr</value>
+ <!-- Inset Alignment -->
+ <value>in</value>
+ </choice>
+ </define>
+ <define name="ST_CompoundLine">
+ <choice>
+ <!-- Single Line -->
+ <value>sng</value>
+ <!-- Double Lines -->
+ <value>dbl</value>
+ <!-- Thick Thin Double Lines -->
+ <value>thickThin</value>
+ <!-- Thin Thick Double Lines -->
+ <value>thinThick</value>
+ <!-- Thin Thick Thin Triple Lines -->
+ <value>tri</value>
+ </choice>
+ </define>
+ <define name="CT_LineProperties">
+ <ref name="EG_LineFillProperties"/>
+ <ref name="EG_LineDashProperties"/>
+ <ref name="EG_LineJoinProperties"/>
+ <element name="headEnd">
+ <ref name="CT_LineEndProperties"/>
+ </element>
+ <element name="tailEnd">
+ <ref name="CT_LineEndProperties"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="w">
+ <ref name="ST_LineWidth"/>
+ </attribute>
+ <attribute name="cap">
+ <ref name="ST_LineCap"/>
+ </attribute>
+ <attribute name="cmpd">
+ <ref name="ST_CompoundLine"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_PenAlignment"/>
+ </attribute>
+ </define>
+ </grammar>
+ <resource name="ST_LineEndType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndType_none">none</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndType_triangle">triangle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndType_stealth">stealth</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndType_diamond">diamond</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndType_oval">oval</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndType_arrow">arrow</value>
+ </resource>
+ <resource name="ST_LineEndWidth" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndWidth_sm">sm</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndWidth_med">med</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndWidth_lg">lg</value>
+ </resource>
+ <resource name="ST_LineEndLength" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndLength_sm">sm</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndLength_med">med</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineEndLength_lg">lg</value>
+ </resource>
+ <resource name="CT_LineEndProperties" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_LineEndProperties_type"/>
+ <attribute name="w" tokenid="ooxml:CT_LineEndProperties_w"/>
+ <attribute name="len" tokenid="ooxml:CT_LineEndProperties_len"/>
+ </resource>
+ <resource name="EG_LineFillProperties" resource="Properties">
+ <element name="noFill" tokenid="ooxml:EG_LineFillProperties_noFill"/>
+ <element name="solidFill" tokenid="ooxml:EG_LineFillProperties_solidFill"/>
+ <element name="gradFill" tokenid="ooxml:EG_LineFillProperties_gradFill"/>
+ <element name="pattFill" tokenid="ooxml:EG_LineFillProperties_pattFill"/>
+ </resource>
+ <resource name="ST_PresetLineDashVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_solid">solid</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_dot">dot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_dash">dash</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_lgDash">lgDash</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_dashDot">dashDot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_lgDashDot">lgDashDot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_lgDashDotDot">lgDashDotDot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_sysDash">sysDash</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_sysDot">sysDot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_sysDashDot">sysDashDot</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PresetLineDashVal_sysDashDotDot">sysDashDotDot</value>
+ </resource>
+ <resource name="ST_LineCap" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_LineCap_rnd">rnd</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineCap_sq">sq</value>
+ <value tokenid="ooxml:Value_drawingml_ST_LineCap_flat">flat</value>
+ </resource>
+ <resource name="ST_PenAlignment" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PenAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PenAlignment_in">in</value>
+ </resource>
+ <resource name="ST_CompoundLine" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_CompoundLine_sng">sng</value>
+ <value tokenid="ooxml:Value_drawingml_ST_CompoundLine_dbl">dbl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_CompoundLine_thickThin">thickThin</value>
+ <value tokenid="ooxml:Value_drawingml_ST_CompoundLine_thinThick">thinThick</value>
+ <value tokenid="ooxml:Value_drawingml_ST_CompoundLine_tri">tri</value>
+ </resource>
+ <resource name="CT_LineProperties" resource="Properties">
+ <element name="headEnd" tokenid="ooxml:CT_LineProperties_headEnd"/>
+ <element name="tailEnd" tokenid="ooxml:CT_LineProperties_tailEnd"/>
+ <element name="extLst" tokenid="ooxml:CT_LineProperties_extLst"/>
+ <attribute name="w" tokenid="ooxml:CT_LineProperties_w"/>
+ <attribute name="cap" tokenid="ooxml:CT_LineProperties_cap"/>
+ <attribute name="cmpd" tokenid="ooxml:CT_LineProperties_cmpd"/>
+ <attribute name="algn" tokenid="ooxml:CT_LineProperties_algn"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-shapeProperties">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shape3DStyles"/>
+ <include href="dml-shape3DScene"/>
+ <include href="dml-shapeGeometry"/>
+ <include href="dml-shapeEffects"/>
+ <include href="dml-shapeLineProperties"/>
+ <define name="CT_ShapeProperties">
+ <element name="xfrm">
+ <ref name="CT_Transform2D"/>
+ </element>
+ <ref name="EG_Geometry"/>
+ <ref name="EG_FillProperties"/>
+ <element name="ln">
+ <ref name="CT_LineProperties"/>
+ </element>
+ <ref name="EG_EffectProperties"/>
+ <element name="scene3d">
+ <ref name="CT_Scene3D"/>
+ </element>
+ <element name="sp3d">
+ <ref name="CT_Shape3D"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="bwMode">
+ <ref name="ST_BlackWhiteMode"/>
+ </attribute>
+ </define>
+ <define name="CT_GroupShapeProperties">
+ <element name="xfrm">
+ <ref name="CT_GroupTransform2D"/>
+ </element>
+ <ref name="EG_FillProperties"/>
+ <ref name="EG_EffectProperties"/>
+ <element name="scene3d">
+ <ref name="CT_Scene3D"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="bwMode">
+ <ref name="ST_BlackWhiteMode"/>
+ </attribute>
+ </define>
+ </grammar>
+ <resource name="CT_ShapeProperties" resource="Properties">
+ <element name="xfrm" tokenid="ooxml:CT_ShapeProperties_xfrm"/>
+ <element name="ln" tokenid="ooxml:CT_ShapeProperties_ln"/>
+ <element name="scene3d" tokenid="ooxml:CT_ShapeProperties_scene3d"/>
+ <element name="sp3d" tokenid="ooxml:CT_ShapeProperties_sp3d"/>
+ <element name="extLst" tokenid="ooxml:CT_ShapeProperties_extLst"/>
+ <attribute name="bwMode" tokenid="ooxml:CT_ShapeProperties_bwMode"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-baseTypes">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="shared-relationshipReference"/>
+ <define name="CT_OfficeArtExtension">
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <attribute name="uri">
+ <data type="token"/>
+ </attribute>
+ </define>
+ <define name="ST_Coordinate">
+ <data type="long"/>
+ </define>
+ <define name="ST_PositiveCoordinate">
+ <data type="long"/>
+ </define>
+ <define name="ST_Angle">
+ <data type="int"/>
+ </define>
+ <define name="CT_Angle">
+ <attribute name="val">
+ <ref name="ST_Angle"/>
+ </attribute>
+ </define>
+ <define name="ST_FixedAngle">
+ </define>
+ <define name="ST_PositiveFixedAngle">
+ </define>
+ <define name="CT_PositiveFixedAngle">
+ <attribute name="val">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ </define>
+ <define name="ST_Percentage">
+ <data type="int"/>
+ </define>
+ <define name="CT_Percentage">
+ <attribute name="val">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="ST_PositivePercentage">
+ </define>
+ <define name="CT_PositivePercentage">
+ <attribute name="val">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="ST_FixedPercentage">
+ </define>
+ <define name="CT_FixedPercentage">
+ <attribute name="val">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="ST_PositiveFixedPercentage">
+ </define>
+ <define name="CT_PositiveFixedPercentage">
+ <attribute name="val">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Ratio">
+ <attribute name="n">
+ <data type="long"/>
+ </attribute>
+ <attribute name="d">
+ <data type="long"/>
+ </attribute>
+ </define>
+ <define name="CT_Point2D">
+ <attribute name="x">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="y">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_PositiveSize2D">
+ <attribute name="cx">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="cy">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_ComplementTransform">
+ </define>
+ <define name="CT_InverseTransform">
+ </define>
+ <define name="CT_GrayscaleTransform">
+ </define>
+ <define name="CT_GammaTransform">
+ </define>
+ <define name="CT_InverseGammaTransform">
+ </define>
+ <define name="EG_ColorTransform">
+ <choice>
+ <element name="tint">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="shade">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="comp">
+ <ref name="CT_ComplementTransform"/>
+ </element>
+ <element name="inv">
+ <ref name="CT_InverseTransform"/>
+ </element>
+ <element name="gray">
+ <ref name="CT_GrayscaleTransform"/>
+ </element>
+ <element name="alpha">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="alphaOff">
+ <ref name="CT_FixedPercentage"/>
+ </element>
+ <element name="alphaMod">
+ <ref name="CT_PositivePercentage"/>
+ </element>
+ <element name="hue">
+ <ref name="CT_PositiveFixedAngle"/>
+ </element>
+ <element name="hueOff">
+ <ref name="CT_Angle"/>
+ </element>
+ <element name="hueMod">
+ <ref name="CT_PositivePercentage"/>
+ </element>
+ <element name="sat">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="satOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="satMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lum">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lumOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lumMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="red">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="redOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="redMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="green">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="greenOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="greenMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="blue">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="blueOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="blueMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="gamma">
+ <ref name="CT_GammaTransform"/>
+ </element>
+ <element name="invGamma">
+ <ref name="CT_InverseGammaTransform"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_ScRgbColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="r">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="g">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="ST_HexBinary3">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_SRgbColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_HexBinary3"/>
+ </attribute>
+ </define>
+ <define name="CT_HslColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="hue">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sat">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="lum">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="ST_SystemColorVal">
+ <choice>
+ <!-- Scroll Bar System Color -->
+ <value>scrollBar</value>
+ <!-- Background System Color -->
+ <value>background</value>
+ <!-- Active Caption System Color -->
+ <value>activeCaption</value>
+ <!-- Inactive Caption System Color -->
+ <value>inactiveCaption</value>
+ <!-- Menu System Color -->
+ <value>menu</value>
+ <!-- Window System Color -->
+ <value>window</value>
+ <!-- Window Frame System Color -->
+ <value>windowFrame</value>
+ <!-- Menu Text System Color -->
+ <value>menuText</value>
+ <!-- Window Text System Color -->
+ <value>windowText</value>
+ <!-- Caption Text System Color -->
+ <value>captionText</value>
+ <!-- Active Border System Color -->
+ <value>activeBorder</value>
+ <!-- Inactive Border System Color -->
+ <value>inactiveBorder</value>
+ <!-- Application Workspace System Color -->
+ <value>appWorkspace</value>
+ <!-- Highlight System Color -->
+ <value>highlight</value>
+ <!-- Highlight Text System Color -->
+ <value>highlightText</value>
+ <!-- Button Face System Color -->
+ <value>btnFace</value>
+ <!-- Button Shadow System Color -->
+ <value>btnShadow</value>
+ <!-- Gray Text System Color -->
+ <value>grayText</value>
+ <!-- Button Text System Color -->
+ <value>btnText</value>
+ <!-- Inactive Caption Text System Color -->
+ <value>inactiveCaptionText</value>
+ <!-- Button Highlight System Color -->
+ <value>btnHighlight</value>
+ <!-- 3D Dark System Color -->
+ <value>3dDkShadow</value>
+ <!-- 3D Light System Color -->
+ <value>3dLight</value>
+ <!-- Info Text System Color -->
+ <value>infoText</value>
+ <!-- Info Back System Color -->
+ <value>infoBk</value>
+ <!-- Hot Light System Color -->
+ <value>hotLight</value>
+ <!-- Gradient Active Caption System Color -->
+ <value>gradientActiveCaption</value>
+ <!-- Gradient Inactive Caption System Color -->
+ <value>gradientInactiveCaption</value>
+ <!-- Menu Highlight System Color -->
+ <value>menuHighlight</value>
+ <!-- Menu Bar System Color -->
+ <value>menuBar</value>
+ </choice>
+ </define>
+ <define name="CT_SystemColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_SystemColorVal"/>
+ </attribute>
+ <attribute name="lastClr">
+ <ref name="ST_HexBinary3"/>
+ </attribute>
+ </define>
+ <define name="ST_SchemeColorVal">
+ <choice>
+ <!-- Background Color 1 -->
+ <value>bg1</value>
+ <!-- Text Color 1 -->
+ <value>tx1</value>
+ <!-- Background Color 2 -->
+ <value>bg2</value>
+ <!-- Text Color 2 -->
+ <value>tx2</value>
+ <!-- Accent Color 1 -->
+ <value>accent1</value>
+ <!-- Accent Color 2 -->
+ <value>accent2</value>
+ <!-- Accent Color 3 -->
+ <value>accent3</value>
+ <!-- Accent Color 4 -->
+ <value>accent4</value>
+ <!-- Accent Color 5 -->
+ <value>accent5</value>
+ <!-- Accent Color 6 -->
+ <value>accent6</value>
+ <!-- Hyperlink Color -->
+ <value>hlink</value>
+ <!-- Followed Hyperlink Color -->
+ <value>folHlink</value>
+ <!-- Style Color -->
+ <value>phClr</value>
+ <!-- Dark Color 1 -->
+ <value>dk1</value>
+ <!-- Light Color 1 -->
+ <value>lt1</value>
+ <!-- Dark Color 2 -->
+ <value>dk2</value>
+ <!-- Light Color 2 -->
+ <value>lt2</value>
+ </choice>
+ </define>
+ <define name="CT_SchemeColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_SchemeColorVal"/>
+ </attribute>
+ </define>
+ <define name="ST_PresetColorVal">
+ <choice>
+ <!-- Alice Blue Preset Color -->
+ <value>aliceBlue</value>
+ <!-- Antique White Preset Color -->
+ <value>antiqueWhite</value>
+ <!-- Aqua Preset Color -->
+ <value>aqua</value>
+ <!-- Aquamarine Preset Color -->
+ <value>aquamarine</value>
+ <!-- Azure Preset Color -->
+ <value>azure</value>
+ <!-- Beige Preset Color -->
+ <value>beige</value>
+ <!-- Bisque Preset Color -->
+ <value>bisque</value>
+ <!-- Black Preset Color -->
+ <value>black</value>
+ <!-- Blanched Almond Preset Color -->
+ <value>blanchedAlmond</value>
+ <!-- Blue Preset Color -->
+ <value>blue</value>
+ <!-- Blue Violet Preset Color -->
+ <value>blueViolet</value>
+ <!-- Brown Preset Color -->
+ <value>brown</value>
+ <!-- Burly Wood Preset Color -->
+ <value>burlyWood</value>
+ <!-- Cadet Blue Preset Color -->
+ <value>cadetBlue</value>
+ <!-- Chartreuse Preset Color -->
+ <value>chartreuse</value>
+ <!-- Chocolate Preset Color -->
+ <value>chocolate</value>
+ <!-- Coral Preset Color -->
+ <value>coral</value>
+ <!-- Cornflower Blue Preset Color -->
+ <value>cornflowerBlue</value>
+ <!-- Cornsilk Preset Color -->
+ <value>cornsilk</value>
+ <!-- Crimson Preset Color -->
+ <value>crimson</value>
+ <!-- Cyan Preset Color -->
+ <value>cyan</value>
+ <!-- Dark Blue Preset Color -->
+ <value>dkBlue</value>
+ <!-- Dark Cyan Preset Color -->
+ <value>dkCyan</value>
+ <!-- Dark Goldenrod Preset Color -->
+ <value>dkGoldenrod</value>
+ <!-- Dark Gray Preset Color -->
+ <value>dkGray</value>
+ <!-- Dark Green Preset Color -->
+ <value>dkGreen</value>
+ <!-- Dark Khaki Preset Color -->
+ <value>dkKhaki</value>
+ <!-- Dark Magenta Preset Color -->
+ <value>dkMagenta</value>
+ <!-- Dark Olive Green Preset Color -->
+ <value>dkOliveGreen</value>
+ <!-- Dark Orange Preset Color -->
+ <value>dkOrange</value>
+ <!-- Dark Orchid Preset Color -->
+ <value>dkOrchid</value>
+ <!-- Dark Red Preset Color -->
+ <value>dkRed</value>
+ <!-- Dark Salmon Preset Color -->
+ <value>dkSalmon</value>
+ <!-- Dark Sea Green Preset Color -->
+ <value>dkSeaGreen</value>
+ <!-- Dark Slate Blue Preset Color -->
+ <value>dkSlateBlue</value>
+ <!-- Dark Slate Gray Preset Color -->
+ <value>dkSlateGray</value>
+ <!-- Dark Turquoise Preset Color -->
+ <value>dkTurquoise</value>
+ <!-- Dark Violet Preset Color -->
+ <value>dkViolet</value>
+ <!-- Deep Pink Preset Color -->
+ <value>deepPink</value>
+ <!-- Deep Sky Blue Preset Color -->
+ <value>deepSkyBlue</value>
+ <!-- Dim Gray Preset Color -->
+ <value>dimGray</value>
+ <!-- Dodger Blue Preset Color -->
+ <value>dodgerBlue</value>
+ <!-- Firebrick Preset Color -->
+ <value>firebrick</value>
+ <!-- Floral White Preset Color -->
+ <value>floralWhite</value>
+ <!-- Forest Green Preset Color -->
+ <value>forestGreen</value>
+ <!-- Fuchsia Preset Color -->
+ <value>fuchsia</value>
+ <!-- Gainsboro Preset Color -->
+ <value>gainsboro</value>
+ <!-- Ghost White Preset Color -->
+ <value>ghostWhite</value>
+ <!-- Gold Preset Color -->
+ <value>gold</value>
+ <!-- Goldenrod Preset Color -->
+ <value>goldenrod</value>
+ <!-- Gray Preset Color -->
+ <value>gray</value>
+ <!-- Green Preset Color -->
+ <value>green</value>
+ <!-- Green Yellow Preset Color -->
+ <value>greenYellow</value>
+ <!-- Honeydew Preset Color -->
+ <value>honeydew</value>
+ <!-- Hot Pink Preset Color -->
+ <value>hotPink</value>
+ <!-- Indian Red Preset Color -->
+ <value>indianRed</value>
+ <!-- Indigo Preset Color -->
+ <value>indigo</value>
+ <!-- Ivory Preset Color -->
+ <value>ivory</value>
+ <!-- Khaki Preset Color -->
+ <value>khaki</value>
+ <!-- Lavender Preset Color -->
+ <value>lavender</value>
+ <!-- Lavender Blush Preset Color -->
+ <value>lavenderBlush</value>
+ <!-- Lawn Green Preset Color -->
+ <value>lawnGreen</value>
+ <!-- Lemon Chiffon Preset Color -->
+ <value>lemonChiffon</value>
+ <!-- Light Blue Preset Color -->
+ <value>ltBlue</value>
+ <!-- Light Coral Preset Color -->
+ <value>ltCoral</value>
+ <!-- Light Cyan Preset Color -->
+ <value>ltCyan</value>
+ <!-- Light Goldenrod Yellow Preset Color -->
+ <value>ltGoldenrodYellow</value>
+ <!-- Light Gray Preset Color -->
+ <value>ltGray</value>
+ <!-- Light Green Preset Color -->
+ <value>ltGreen</value>
+ <!-- Light Pink Preset Color -->
+ <value>ltPink</value>
+ <!-- Light Salmon Preset Color -->
+ <value>ltSalmon</value>
+ <!-- Light Sea Green Preset Color -->
+ <value>ltSeaGreen</value>
+ <!-- Light Sky Blue Preset Color -->
+ <value>ltSkyBlue</value>
+ <!-- Light Slate Gray Preset Color -->
+ <value>ltSlateGray</value>
+ <!-- Light Steel Blue Preset Color -->
+ <value>ltSteelBlue</value>
+ <!-- Light Yellow Preset Color -->
+ <value>ltYellow</value>
+ <!-- Lime Preset Color -->
+ <value>lime</value>
+ <!-- Lime Green Preset Color -->
+ <value>limeGreen</value>
+ <!-- Linen Preset Color -->
+ <value>linen</value>
+ <!-- Magenta Preset Color -->
+ <value>magenta</value>
+ <!-- Maroon Preset Color -->
+ <value>maroon</value>
+ <!-- Medium Aquamarine Preset Color -->
+ <value>medAquamarine</value>
+ <!-- Medium Blue Preset Color -->
+ <value>medBlue</value>
+ <!-- Medium Orchid Preset Color -->
+ <value>medOrchid</value>
+ <!-- Medium Purple Preset Color -->
+ <value>medPurple</value>
+ <!-- Medium Sea Green Preset Color -->
+ <value>medSeaGreen</value>
+ <!-- Medium Slate Blue Preset Color -->
+ <value>medSlateBlue</value>
+ <!-- Medium Spring Green Preset Color -->
+ <value>medSpringGreen</value>
+ <!-- Medium Turquoise Preset Color -->
+ <value>medTurquoise</value>
+ <!-- Medium Violet Red Preset Color -->
+ <value>medVioletRed</value>
+ <!-- Midnight Blue Preset Color -->
+ <value>midnightBlue</value>
+ <!-- Mint Cream Preset Color -->
+ <value>mintCream</value>
+ <!-- Misty Rose Preset Color -->
+ <value>mistyRose</value>
+ <!-- Moccasin Preset Color -->
+ <value>moccasin</value>
+ <!-- Navajo White Preset Color -->
+ <value>navajoWhite</value>
+ <!-- Navy Preset Color -->
+ <value>navy</value>
+ <!-- Old Lace Preset Color -->
+ <value>oldLace</value>
+ <!-- Olive Preset Color -->
+ <value>olive</value>
+ <!-- Olive Drab Preset Color -->
+ <value>oliveDrab</value>
+ <!-- Orange Preset Color -->
+ <value>orange</value>
+ <!-- Orange Red Preset Color -->
+ <value>orangeRed</value>
+ <!-- Orchid Preset Color -->
+ <value>orchid</value>
+ <!-- Pale Goldenrod Preset Color -->
+ <value>paleGoldenrod</value>
+ <!-- Pale Green Preset Color -->
+ <value>paleGreen</value>
+ <!-- Pale Turquoise Preset Color -->
+ <value>paleTurquoise</value>
+ <!-- Pale Violet Red Preset Color -->
+ <value>paleVioletRed</value>
+ <!-- Papaya Whip Preset Color -->
+ <value>papayaWhip</value>
+ <!-- Peach Puff Preset Color -->
+ <value>peachPuff</value>
+ <!-- Peru Preset Color -->
+ <value>peru</value>
+ <!-- Pink Preset Color -->
+ <value>pink</value>
+ <!-- Plum Preset Color -->
+ <value>plum</value>
+ <!-- Powder Blue Preset Color -->
+ <value>powderBlue</value>
+ <!-- Purple Preset Color -->
+ <value>purple</value>
+ <!-- Red Preset Color -->
+ <value>red</value>
+ <!-- Rosy Brown Preset Color -->
+ <value>rosyBrown</value>
+ <!-- Royal Blue Preset Color -->
+ <value>royalBlue</value>
+ <!-- Saddle Brown Preset Color -->
+ <value>saddleBrown</value>
+ <!-- Salmon Preset Color -->
+ <value>salmon</value>
+ <!-- Sandy Brown Preset Color -->
+ <value>sandyBrown</value>
+ <!-- Sea Green Preset Color -->
+ <value>seaGreen</value>
+ <!-- Sea Shell Preset Color -->
+ <value>seaShell</value>
+ <!-- Sienna Preset Color -->
+ <value>sienna</value>
+ <!-- Silver Preset Color -->
+ <value>silver</value>
+ <!-- Sky Blue Preset Color -->
+ <value>skyBlue</value>
+ <!-- Slate Blue Preset Color -->
+ <value>slateBlue</value>
+ <!-- Slate Gray Preset Color -->
+ <value>slateGray</value>
+ <!-- Snow Preset Color -->
+ <value>snow</value>
+ <!-- Spring Green Preset Color -->
+ <value>springGreen</value>
+ <!-- Steel Blue Preset Color -->
+ <value>steelBlue</value>
+ <!-- Tan Preset Color -->
+ <value>tan</value>
+ <!-- Teal Preset Color -->
+ <value>teal</value>
+ <!-- Thistle Preset Color -->
+ <value>thistle</value>
+ <!-- Tomato Preset Color -->
+ <value>tomato</value>
+ <!-- Turquoise Preset Color -->
+ <value>turquoise</value>
+ <!-- Violet Preset Color -->
+ <value>violet</value>
+ <!-- Wheat Preset Color -->
+ <value>wheat</value>
+ <!-- White Preset Color -->
+ <value>white</value>
+ <!-- White Smoke Preset Color -->
+ <value>whiteSmoke</value>
+ <!-- Yellow Preset Color -->
+ <value>yellow</value>
+ <!-- Yellow Green Preset Color -->
+ <value>yellowGreen</value>
+ </choice>
+ </define>
+ <define name="CT_PresetColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_PresetColorVal"/>
+ </attribute>
+ </define>
+ <define name="EG_OfficeArtExtensionList">
+ <element name="ext">
+ <ref name="CT_OfficeArtExtension"/>
+ </element>
+ </define>
+ <define name="CT_OfficeArtExtensionList">
+ <ref name="EG_OfficeArtExtensionList"/>
+ </define>
+ <define name="CT_Scale2D">
+ <element name="sx">
+ <ref name="CT_Ratio"/>
+ </element>
+ <element name="sy">
+ <ref name="CT_Ratio"/>
+ </element>
+ </define>
+ <define name="CT_Transform2D">
+ <element name="off">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="ext">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <attribute name="rot">
+ <ref name="ST_Angle"/>
+ </attribute>
+ <attribute name="flipH">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="flipV">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_GroupTransform2D">
+ <element name="off">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="ext">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <element name="chOff">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="chExt">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <attribute name="rot">
+ <ref name="ST_Angle"/>
+ </attribute>
+ <attribute name="flipH">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="flipV">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_Point3D">
+ <attribute name="x">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="y">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="z">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_Vector3D">
+ <attribute name="dx">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="dy">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="dz">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_SphereCoords">
+ <attribute name="lat">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="lon">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="rev">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_RelativeRect">
+ <attribute name="l">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="ST_RectAlignment">
+ <choice>
+ <!-- Rectangle Alignment Enum ( Top Left ) -->
+ <value>tl</value>
+ <!-- Rectangle Alignment Enum ( Top ) -->
+ <value>t</value>
+ <!-- Rectangle Alignment Enum ( Top Right ) -->
+ <value>tr</value>
+ <!-- Rectangle Alignment Enum ( Left ) -->
+ <value>l</value>
+ <!-- Rectangle Alignment Enum ( Center ) -->
+ <value>ctr</value>
+ <!-- Rectangle Alignment Enum ( Right ) -->
+ <value>r</value>
+ <!-- Rectangle Alignment Enum ( Bottom Left ) -->
+ <value>bl</value>
+ <!-- Rectangle Alignment Enum ( Bottom ) -->
+ <value>b</value>
+ <!-- Rectangle Alignment Enum ( Bottom Right ) -->
+ <value>br</value>
+ </choice>
+ </define>
+ <define name="EG_ColorChoice">
+ <choice>
+ <element name="scrgbClr">
+ <ref name="CT_ScRgbColor"/>
+ </element>
+ <element name="srgbClr">
+ <ref name="CT_SRgbColor"/>
+ </element>
+ <element name="hslClr">
+ <ref name="CT_HslColor"/>
+ </element>
+ <element name="sysClr">
+ <ref name="CT_SystemColor"/>
+ </element>
+ <element name="schemeClr">
+ <ref name="CT_SchemeColor"/>
+ </element>
+ <element name="prstClr">
+ <ref name="CT_PresetColor"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_Color">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_ColorMRU">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="ST_BlackWhiteMode">
+ <choice>
+ <!-- Color -->
+ <value>clr</value>
+ <!-- Automatic -->
+ <value>auto</value>
+ <!-- Gray -->
+ <value>gray</value>
+ <!-- Light Gray -->
+ <value>ltGray</value>
+ <!-- Inverse Gray -->
+ <value>invGray</value>
+ <!-- Gray and White -->
+ <value>grayWhite</value>
+ <!-- Black and Gray -->
+ <value>blackGray</value>
+ <!-- Black and White -->
+ <value>blackWhite</value>
+ <!-- Black -->
+ <value>black</value>
+ <!-- White -->
+ <value>white</value>
+ <!-- Hidden -->
+ <value>hidden</value>
+ </choice>
+ </define>
+ <define name="AG_Blob">
+ <attribute name="r:embed">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:link">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_EmbeddedWAVAudioFile">
+ <attribute name="r:embed"/>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="builtIn">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_Hyperlink">
+ <element name="snd">
+ <ref name="CT_EmbeddedWAVAudioFile"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="r:id"/>
+ <attribute name="invalidUrl">
+ <data type="string"/>
+ </attribute>
+ <attribute name="action">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tgtFrame">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tooltip">
+ <data type="string"/>
+ </attribute>
+ <attribute name="history">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="highlightClick">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="endSnd">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="ST_DrawingElementId">
+ <data type="unsignedInt"/>
+ </define>
+ </grammar>
+ <resource name="ST_Coordinate" resource="Integer"/>
+ <resource name="ST_PositiveCoordinate" resource="Integer"/>
+ <resource name="ST_Angle" resource="Integer"/>
+ <resource name="CT_Angle" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Angle_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="CT_PositiveFixedAngle" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PositiveFixedAngle_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Percentage" resource="Integer"/>
+ <resource name="CT_Percentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Percentage_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_PositivePercentage" resource="Value">
+ <action name="characters" action="positivePercentage"/>
+ </resource>
+ <resource name="CT_PositivePercentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PositivePercentage_val" action="setValue"/>
+ </resource>
+ <resource name="CT_FixedPercentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FixedPercentage_val" action="setValue"/>
+ </resource>
+ <resource name="CT_PositiveFixedPercentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PositiveFixedPercentage_val" action="setValue"/>
+ </resource>
+ <resource name="CT_Point2D" resource="Properties">
+ <attribute name="x" tokenid="ooxml:CT_Point2D_x"/>
+ <attribute name="y" tokenid="ooxml:CT_Point2D_y"/>
+ </resource>
+ <resource name="CT_PositiveSize2D" resource="Properties">
+ <attribute name="cx" tokenid="ooxml:CT_PositiveSize2D_cx"/>
+ <attribute name="cy" tokenid="ooxml:CT_PositiveSize2D_cy"/>
+ </resource>
+ <resource name="CT_ScRgbColor" resource="Properties">
+ <attribute name="r" tokenid="ooxml:CT_ScRgbColor_r"/>
+ <attribute name="g" tokenid="ooxml:CT_ScRgbColor_g"/>
+ <attribute name="b" tokenid="ooxml:CT_ScRgbColor_b"/>
+ </resource>
+ <resource name="ST_HexBinary3" resource="Hex"/>
+ <resource name="CT_SRgbColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SRgbColor_val"/>
+ </resource>
+ <resource name="CT_HslColor" resource="Properties">
+ <attribute name="hue" tokenid="ooxml:CT_HslColor_hue"/>
+ <attribute name="sat" tokenid="ooxml:CT_HslColor_sat"/>
+ <attribute name="lum" tokenid="ooxml:CT_HslColor_lum"/>
+ </resource>
+ <resource name="ST_SystemColorVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_scrollBar">scrollBar</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_background">background</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_activeCaption">activeCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_inactiveCaption">inactiveCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menu">menu</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_window">window</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_windowFrame">windowFrame</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menuText">menuText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_windowText">windowText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_captionText">captionText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_activeBorder">activeBorder</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_inactiveBorder">inactiveBorder</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_appWorkspace">appWorkspace</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_highlight">highlight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_highlightText">highlightText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnFace">btnFace</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnShadow">btnShadow</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_grayText">grayText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnText">btnText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_inactiveCaptionText">inactiveCaptionText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnHighlight">btnHighlight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_3dDkShadow">3dDkShadow</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_3dLight">3dLight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_infoText">infoText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_infoBk">infoBk</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_hotLight">hotLight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_gradientActiveCaption">gradientActiveCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_gradientInactiveCaption">gradientInactiveCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menuHighlight">menuHighlight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menuBar">menuBar</value>
+ </resource>
+ <resource name="CT_SystemColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SystemColor_val"/>
+ <attribute name="lastClr" tokenid="ooxml:CT_SystemColor_lastClr"/>
+ </resource>
+ <resource name="ST_SchemeColorVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_bg1">bg1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_tx1">tx1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_bg2">bg2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_tx2">tx2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent1">accent1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent2">accent2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent3">accent3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent4">accent4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent5">accent5</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent6">accent6</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_hlink">hlink</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_folHlink">folHlink</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_phClr">phClr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_dk1">dk1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_lt1">lt1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_dk2">dk2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_lt2">lt2</value>
+ </resource>
+ <resource name="CT_SchemeColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SchemeColor_val"/>
+ </resource>
+ <resource name="ST_PresetColorVal" resource="List">
+ <value tokenid="ooxml:Value_ST_PresetColorVal_aliceBlue">aliceBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_antiqueWhite">antiqueWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_aqua">aqua</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_aquamarine">aquamarine</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_azure">azure</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_beige">beige</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_bisque">bisque</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_black">black</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_blanchedAlmond">blanchedAlmond</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_blue">blue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_blueViolet">blueViolet</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_brown">brown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_burlyWood">burlyWood</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cadetBlue">cadetBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_chartreuse">chartreuse</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_chocolate">chocolate</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_coral">coral</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cornflowerBlue">cornflowerBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cornsilk">cornsilk</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_crimson">crimson</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cyan">cyan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_deepPink">deepPink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_deepSkyBlue">deepSkyBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dimGray">dimGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkBlue">dkBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkCyan">dkCyan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkGoldenrod">dkGoldenrod</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkGray">dkGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkGreen">dkGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkKhaki">dkKhaki</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkMagenta">dkMagenta</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkOliveGreen">dkOliveGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkOrange">dkOrange</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkOrchid">dkOrchid</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkRed">dkRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSalmon">dkSalmon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSeaGreen">dkSeaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSlateBlue">dkSlateBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSlateGray">dkSlateGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkTurquoise">dkTurquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkViolet">dkViolet</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dodgerBlue">dodgerBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_firebrick">firebrick</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_floralWhite">floralWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_forestGreen">forestGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_fuchsia">fuchsia</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_gainsboro">gainsboro</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ghostWhite">ghostWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_gold">gold</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_goldenrod">goldenrod</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_gray">gray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_green">green</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_greenYellow">greenYellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_honeydew">honeydew</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_hotPink">hotPink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_indianRed">indianRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_indigo">indigo</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ivory">ivory</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_khaki">khaki</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lavender">lavender</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lavenderBlush">lavenderBlush</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lawnGreen">lawnGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lemonChiffon">lemonChiffon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lime">lime</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_limeGreen">limeGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_linen">linen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltBlue">ltBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltCoral">ltCoral</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltCyan">ltCyan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltGoldenrodYellow">ltGoldenrodYellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltGray">ltGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltGreen">ltGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltPink">ltPink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSalmon">ltSalmon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSeaGreen">ltSeaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSkyBlue">ltSkyBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSlateGray">ltSlateGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSteelBlue">ltSteelBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltYellow">ltYellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_magenta">magenta</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_maroon">maroon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medAquamarine">medAquamarine</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medBlue">medBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medOrchid">medOrchid</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medPurple">medPurple</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medSeaGreen">medSeaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medSlateBlue">medSlateBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medSpringGreen">medSpringGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medTurquoise">medTurquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medVioletRed">medVioletRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_midnightBlue">midnightBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_mintCream">mintCream</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_mistyRose">mistyRose</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_moccasin">moccasin</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_navajoWhite">navajoWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_navy">navy</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_oldLace">oldLace</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_olive">olive</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_oliveDrab">oliveDrab</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_orange">orange</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_orangeRed">orangeRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_orchid">orchid</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleGoldenrod">paleGoldenrod</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleGreen">paleGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleTurquoise">paleTurquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleVioletRed">paleVioletRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_papayaWhip">papayaWhip</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_peachPuff">peachPuff</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_peru">peru</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_pink">pink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_plum">plum</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_powderBlue">powderBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_purple">purple</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_red">red</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_rosyBrown">rosyBrown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_royalBlue">royalBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_saddleBrown">saddleBrown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_salmon">salmon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_sandyBrown">sandyBrown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_seaGreen">seaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_seaShell">seaShell</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_sienna">sienna</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_silver">silver</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_skyBlue">skyBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_slateBlue">slateBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_slateGray">slateGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_snow">snow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_springGreen">springGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_steelBlue">steelBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_tan">tan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_teal">teal</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_thistle">thistle</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_tomato">tomato</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_turquoise">turquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_violet">violet</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_wheat">wheat</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_white">white</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_whiteSmoke">whiteSmoke</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_yellow">yellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_yellowGreen">yellowGreen</value>
+ </resource>
+ <resource name="CT_PresetColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PresetColor_val"/>
+ </resource>
+ <resource name="CT_Transform2D" resource="Properties">
+ <element name="off" tokenid="ooxml:CT_Transform2D_off"/>
+ <element name="ext" tokenid="ooxml:CT_Transform2D_ext"/>
+ <attribute name="rot" tokenid="ooxml:CT_Transform2D_rot"/>
+ <attribute name="flipH" tokenid="ooxml:CT_Transform2D_flipH"/>
+ <attribute name="flipV" tokenid="ooxml:CT_Transform2D_flipV"/>
+ </resource>
+ <resource name="ST_RectAlignment" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_tl">tl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_t">t</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_tr">tr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_l">l</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_r">r</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_bl">bl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_b">b</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_br">br</value>
+ </resource>
+ <resource name="EG_ColorChoice" resource="Properties">
+ <element name="scrgbClr" tokenid="ooxml:EG_ColorChoice_scrgbClr"/>
+ <element name="srgbClr" tokenid="ooxml:EG_ColorChoice_srgbClr"/>
+ <element name="hslClr" tokenid="ooxml:EG_ColorChoice_hslClr"/>
+ <element name="sysClr" tokenid="ooxml:EG_ColorChoice_sysClr"/>
+ <element name="schemeClr" tokenid="ooxml:EG_ColorChoice_schemeClr"/>
+ <element name="prstClr" tokenid="ooxml:EG_ColorChoice_prstClr"/>
+ </resource>
+ <resource name="CT_Color" resource="Properties"/>
+ <resource name="CT_ColorMRU" resource="Properties"/>
+ <resource name="ST_BlackWhiteMode" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_clr">clr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_auto">auto</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_gray">gray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_ltGray">ltGray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_invGray">invGray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_grayWhite">grayWhite</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_blackGray">blackGray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_blackWhite">blackWhite</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_black">black</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_white">white</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_hidden">hidden</value>
+ </resource>
+ <resource name="AG_Blob" resource="Properties">
+ <attribute name="r:embed" tokenid="ooxml:AG_Blob_r_embed"/>
+ <attribute name="r:link" tokenid="ooxml:AG_Blob_r_link"/>
+ </resource>
+ <resource name="ST_DrawingElementId" resource="Integer"/>
+ </namespace>
+ <namespace name="dml-documentProperties">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shapeGeometry"/>
+ <define name="AG_Locking">
+ <attribute name="noGrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noSelect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noRot">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeAspect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noMove">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noResize">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noEditPoints">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noAdjustHandles">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeArrowheads">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeShapeType">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_ConnectorLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Locking"/>
+ </define>
+ <define name="CT_ShapeLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Locking"/>
+ <attribute name="noTextEdit">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Locking"/>
+ <attribute name="noCrop">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_GroupLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="noGrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noUngrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noSelect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noRot">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeAspect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noMove">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noResize">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_GraphicalObjectFrameLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="noGrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noDrilldown">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noSelect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeAspect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noMove">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noResize">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualDrawingProps">
+ <element name="a:hlinkClick">
+ <ref name="CT_Hyperlink_URL"/>
+ </element>
+ <element name="hlinkHover">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="id">
+ <ref name="ST_DrawingElementId"/>
+ </attribute>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="descr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hidden">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="title">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Hyperlink_URL">
+ <attribute name="r:id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualDrawingShapeProps">
+ <element name="spLocks">
+ <ref name="CT_ShapeLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="txBox">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualConnectorProperties">
+ <element name="cxnSpLocks">
+ <ref name="CT_ConnectorLocking"/>
+ </element>
+ <element name="stCxn">
+ <ref name="CT_Connection"/>
+ </element>
+ <element name="endCxn">
+ <ref name="CT_Connection"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ <define name="CT_NonVisualPictureProperties">
+ <element name="picLocks">
+ <ref name="CT_PictureLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="preferRelativeResize">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualGroupDrawingShapeProps">
+ <element name="grpSpLocks">
+ <ref name="CT_GroupLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ <define name="CT_NonVisualGraphicFrameProperties">
+ <element name="graphicFrameLocks">
+ <ref name="CT_GraphicalObjectFrameLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="CT_Hyperlink_URL" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_Hyperlink_URL"/>
+ <action name="start" action="handleHyperlinkURL"/>
+ </resource>
+ <resource name="CT_GraphicalObjectFrameLocking" resource="Properties">
+ <element name="extLst" tokenid="ooxml:CT_GraphicalObjectFrameLocking_extLst"/>
+ <attribute name="noGrp" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noGrp"/>
+ <attribute name="noDrilldown" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noDrilldown"/>
+ <attribute name="noSelect" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noSelect"/>
+ <attribute name="noChangeAspect" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noChangeAspect"/>
+ <attribute name="noMove" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noMove"/>
+ <attribute name="noResize" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noResize"/>
+ </resource>
+ <resource name="CT_NonVisualDrawingProps" resource="Properties">
+ <element name="a:hlinkClick" tokenid="ooxml:CT_NonVisualDrawingProps_a_hlinkClick"/>
+ <element name="hlinkHover" tokenid="ooxml:CT_NonVisualDrawingProps_hlinkHover"/>
+ <element name="extLst" tokenid="ooxml:CT_NonVisualDrawingProps_extLst"/>
+ <attribute name="id" tokenid="ooxml:CT_NonVisualDrawingProps_id"/>
+ <attribute name="name" tokenid="ooxml:CT_NonVisualDrawingProps_name"/>
+ <attribute name="descr" tokenid="ooxml:CT_NonVisualDrawingProps_descr"/>
+ <attribute name="hidden" tokenid="ooxml:CT_NonVisualDrawingProps_hidden"/>
+ <attribute name="title" tokenid="ooxml:CT_NonVisualDrawingProps_title"/>
+ </resource>
+ <resource name="CT_NonVisualPictureProperties" resource="Properties">
+ <element name="picLocks" tokenid="ooxml:CT_NonVisualPictureProperties_picLocks"/>
+ <element name="extLst" tokenid="ooxml:CT_NonVisualPictureProperties_extLst"/>
+ <attribute name="preferRelativeResize" tokenid="ooxml:CT_NonVisualPictureProperties_preferRelativeResize"/>
+ </resource>
+ <resource name="CT_NonVisualGraphicFrameProperties" resource="Properties">
+ <element name="graphicFrameLocks" tokenid="ooxml:CT_NonVisualGraphicFrameProperties_graphicFrameLocks"/>
+ <element name="extLst" tokenid="ooxml:CT_NonVisualGraphicFrameProperties_extLst"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-graphicalObject">
+ <start name="graphic"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <!-- ISO RELAX NG Schema -->
+ <!-- start = graphic -->
+ <define name="CT_GraphicalObjectData">
+ <ref name="pic"/>
+ <ref name="relIds"/>
+ <ref name="lockedCanvas"/>
+ <ref name="chart"/>
+ <ref name="wsp"/>
+ <ref name="wgp"/>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <attribute name="uri">
+ <data type="token"/>
+ </attribute>
+ </define>
+ <define name="CT_GraphicalObject">
+ <element name="graphicData">
+ <ref name="CT_GraphicalObjectData"/>
+ </element>
+ </define>
+ <define name="graphic">
+ <element name="graphic">
+ <ref name="CT_GraphicalObject"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="CT_GraphicalObjectData" resource="Properties">
+ <element name="pic" tokenid="ooxml:CT_GraphicalObjectData_pic"/>
+ <element name="relIds" tokenid="ooxml:CT_GraphicalObjectData_relIds"/>
+ <element name="lockedCanvas" tokenid="ooxml:CT_GraphicalObjectData_lockedCanvas"/>
+ <element name="chart" tokenid="ooxml:CT_GraphicalObjectData_chart"/>
+ <element name="wsp" tokenid="ooxml:CT_GraphicalObjectData_wsp"/>
+ <element name="wgp" tokenid="ooxml:CT_GraphicalObjectData_wgp"/>
+ <attribute name="uri" tokenid="ooxml:CT_GraphicalObjectData_uri"/>
+ </resource>
+ <resource name="CT_GraphicalObject" resource="Properties">
+ <element name="graphicData" tokenid="ooxml:CT_GraphicalObject_graphicData"/>
+ </resource>
+ <resource name="graphic" resource="Properties">
+ <element name="graphic" tokenid="ooxml:graphic_graphic"/>
+ </resource>
+ </namespace>
+ <namespace name="wp14">
+ <start name="sizeRelH"/>
+ <start name="sizeRelV"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing">
+ <define name="ST_SizeRelFromH">
+ <choice>
+ <value>margin</value>
+ <value>page</value>
+ <value>leftMargin</value>
+ <value>rightMargin</value>
+ <value>insideMargin</value>
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="ST_SizeRelFromV">
+ <choice>
+ <value>margin</value>
+ <value>page</value>
+ <value>topMargin</value>
+ <value>bottomMargin</value>
+ <value>insideMargin</value>
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="CT_SizeRelH">
+ <element name="pctWidth">
+ <ref name="ST_PositivePercentage"/>
+ </element>
+ <attribute name="relativeFrom">
+ <ref name="ST_SizeRelFromH"/>
+ </attribute>
+ </define>
+ <define name="CT_SizeRelV">
+ <element name="pctHeight">
+ <ref name="ST_PositivePercentage"/>
+ </element>
+ <attribute name="relativeFrom">
+ <ref name="ST_SizeRelFromV"/>
+ </attribute>
+ </define>
+ <define name="sizeRelH">
+ <element name="sizeRelH">
+ <ref name="CT_SizeRelH"/>
+ </element>
+ </define>
+ <define name="sizeRelV">
+ <element name="sizeRelV">
+ <ref name="CT_SizeRelV"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_SizeRelFromH" resource="List">
+ <value tokenid="ooxml:ST_SizeRelFromH_margin">margin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_page">page</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_leftMargin">leftMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_rightMargin">rightMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="ST_SizeRelFromV" resource="List">
+ <value tokenid="ooxml:ST_SizeRelFromV_margin">margin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_page">page</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_topMargin">topMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_bottomMargin">bottomMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="CT_SizeRelH" resource="Properties">
+ <element name="pctWidth" tokenid="ooxml:CT_SizeRelH_pctWidth"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_SizeRelH_relativeFrom"/>
+ </resource>
+ <resource name="CT_SizeRelV" resource="Properties">
+ <element name="pctHeight" tokenid="ooxml:CT_SizeRelV_pctHeight"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_SizeRelV_relativeFrom"/>
+ </resource>
+ <resource name="sizeRelH" resource="Properties">
+ <element name="sizeRelH" tokenid="ooxml:sizeRelH_sizeRelH"/>
+ </resource>
+ <resource name="sizeRelV" resource="Properties">
+ <element name="sizeRelV" tokenid="ooxml:sizeRelV_sizeRelV"/>
+ </resource>
+ </namespace>
+ <namespace name="w14">
+ <start name="glow"/>
+ <start name="shadow"/>
+ <start name="reflection"/>
+ <start name="textOutline"/>
+ <start name="textFill"/>
+ <start name="scene3d"/>
+ <start name="props3d"/>
+ <start name="ligatures"/>
+ <start name="numForm"/>
+ <start name="numSpacing"/>
+ <start name="stylisticSets"/>
+ <start name="cntxtAlts"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2010/wordml" attributeFormDefault="qualified">
+ <define name="ST_SchemeColorVal">
+ <choice>
+ <value>bg1</value>
+ <value>tx1</value>
+ <value>bg2</value>
+ <value>tx2</value>
+ <value>accent1</value>
+ <value>accent2</value>
+ <value>accent3</value>
+ <value>accent4</value>
+ <value>accent5</value>
+ <value>accent6</value>
+ <value>hlink</value>
+ <value>folHlink</value>
+ <value>dk1</value>
+ <value>lt1</value>
+ <value>dk2</value>
+ <value>lt2</value>
+ <value>phClr</value>
+ </choice>
+ </define>
+ <define name="ST_RectAlignment">
+ <choice>
+ <value>none</value>
+ <value>tl</value>
+ <value>t</value>
+ <value>tr</value>
+ <value>l</value>
+ <value>ctr</value>
+ <value>r</value>
+ <value>bl</value>
+ <value>b</value>
+ <value>br</value>
+ </choice>
+ </define>
+ <define name="ST_LineCap">
+ <choice>
+ <value>rnd</value>
+ <value>sq</value>
+ <value>flat</value>
+ </choice>
+ </define>
+ <define name="ST_CompoundLine">
+ <choice>
+ <value>sng</value>
+ <value>dbl</value>
+ <value>thickThin</value>
+ <value>thinThick</value>
+ <value>tri</value>
+ </choice>
+ </define>
+ <define name="ST_PenAlignment">
+ <choice>
+ <value>ctr</value>
+ <value>in</value>
+ </choice>
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <value>true</value>
+ <value>false</value>
+ <value>0</value>
+ <value>1</value>
+ </choice>
+ </define>
+ <define name="ST_PathShadeType">
+ <choice>
+ <value>shape</value>
+ <value>circle</value>
+ <value>rect</value>
+ </choice>
+ </define>
+ <define name="ST_PresetLineDashVal">
+ <choice>
+ <value>solid</value>
+ <value>dot</value>
+ <value>sysDot</value>
+ <value>dash</value>
+ <value>sysDash</value>
+ <value>lgDash</value>
+ <value>dashDot</value>
+ <value>sysDashDot</value>
+ <value>lgDashDot</value>
+ <value>lgDashDotDot</value>
+ <value>sysDashDotDot</value>
+ </choice>
+ </define>
+ <define name="ST_PresetCameraType">
+ <choice>
+ <value>legacyObliqueTopLeft</value>
+ <value>legacyObliqueTop</value>
+ <value>legacyObliqueTopRight</value>
+ <value>legacyObliqueLeft</value>
+ <value>legacyObliqueFront</value>
+ <value>legacyObliqueRight</value>
+ <value>legacyObliqueBottomLeft</value>
+ <value>legacyObliqueBottom</value>
+ <value>legacyObliqueBottomRight</value>
+ <value>legacyPerspectiveTopLeft</value>
+ <value>legacyPerspectiveTop</value>
+ <value>legacyPerspectiveTopRight</value>
+ <value>legacyPerspectiveLeft</value>
+ <value>legacyPerspectiveFront</value>
+ <value>legacyPerspectiveRight</value>
+ <value>legacyPerspectiveBottomLeft</value>
+ <value>legacyPerspectiveBottom</value>
+ <value>legacyPerspectiveBottomRight</value>
+ <value>orthographicFront</value>
+ <value>isometricTopUp</value>
+ <value>isometricTopDown</value>
+ <value>isometricBottomUp</value>
+ <value>isometricBottomDown</value>
+ <value>isometricLeftUp</value>
+ <value>isometricLeftDown</value>
+ <value>isometricRightUp</value>
+ <value>isometricRightDown</value>
+ <value>isometricOffAxis1Left</value>
+ <value>isometricOffAxis1Right</value>
+ <value>isometricOffAxis1Top</value>
+ <value>isometricOffAxis2Left</value>
+ <value>isometricOffAxis2Right</value>
+ <value>isometricOffAxis2Top</value>
+ <value>isometricOffAxis3Left</value>
+ <value>isometricOffAxis3Right</value>
+ <value>isometricOffAxis3Bottom</value>
+ <value>isometricOffAxis4Left</value>
+ <value>isometricOffAxis4Right</value>
+ <value>isometricOffAxis4Bottom</value>
+ <value>obliqueTopLeft</value>
+ <value>obliqueTop</value>
+ <value>obliqueTopRight</value>
+ <value>obliqueLeft</value>
+ <value>obliqueRight</value>
+ <value>obliqueBottomLeft</value>
+ <value>obliqueBottom</value>
+ <value>obliqueBottomRight</value>
+ <value>perspectiveFront</value>
+ <value>perspectiveLeft</value>
+ <value>perspectiveRight</value>
+ <value>perspectiveAbove</value>
+ <value>perspectiveBelow</value>
+ <value>perspectiveAboveLeftFacing</value>
+ <value>perspectiveAboveRightFacing</value>
+ <value>perspectiveContrastingLeftFacing</value>
+ <value>perspectiveContrastingRightFacing</value>
+ <value>perspectiveHeroicLeftFacing</value>
+ <value>perspectiveHeroicRightFacing</value>
+ <value>perspectiveHeroicExtremeLeftFacing</value>
+ <value>perspectiveHeroicExtremeRightFacing</value>
+ <value>perspectiveRelaxed</value>
+ <value>perspectiveRelaxedModerately</value>
+ </choice>
+ </define>
+ <define name="ST_LightRigType">
+ <choice>
+ <value>legacyFlat1</value>
+ <value>legacyFlat2</value>
+ <value>legacyFlat3</value>
+ <value>legacyFlat4</value>
+ <value>legacyNormal1</value>
+ <value>legacyNormal2</value>
+ <value>legacyNormal3</value>
+ <value>legacyNormal4</value>
+ <value>legacyHarsh1</value>
+ <value>legacyHarsh2</value>
+ <value>legacyHarsh3</value>
+ <value>legacyHarsh4</value>
+ <value>threePt</value>
+ <value>balanced</value>
+ <value>soft</value>
+ <value>harsh</value>
+ <value>flood</value>
+ <value>contrasting</value>
+ <value>morning</value>
+ <value>sunrise</value>
+ <value>sunset</value>
+ <value>chilly</value>
+ <value>freezing</value>
+ <value>flat</value>
+ <value>twoPt</value>
+ <value>glow</value>
+ <value>brightRoom</value>
+ </choice>
+ </define>
+ <define name="ST_LightRigDirection">
+ <choice>
+ <value>tl</value>
+ <value>t</value>
+ <value>tr</value>
+ <value>l</value>
+ <value>r</value>
+ <value>bl</value>
+ <value>b</value>
+ <value>br</value>
+ </choice>
+ </define>
+ <define name="ST_BevelPresetType">
+ <choice>
+ <value>relaxedInset</value>
+ <value>circle</value>
+ <value>slope</value>
+ <value>cross</value>
+ <value>angle</value>
+ <value>softRound</value>
+ <value>convex</value>
+ <value>coolSlant</value>
+ <value>divot</value>
+ <value>riblet</value>
+ <value>hardEdge</value>
+ <value>artDeco</value>
+ </choice>
+ </define>
+ <define name="ST_PresetMaterialType">
+ <choice>
+ <value>legacyMatte</value>
+ <value>legacyPlastic</value>
+ <value>legacyMetal</value>
+ <value>legacyWireframe</value>
+ <value>matte</value>
+ <value>plastic</value>
+ <value>metal</value>
+ <value>warmMatte</value>
+ <value>translucentPowder</value>
+ <value>powder</value>
+ <value>dkEdge</value>
+ <value>softEdge</value>
+ <value>clear</value>
+ <value>flat</value>
+ <value>softmetal</value>
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="ST_Ligatures">
+ <choice>
+ <value>none</value>
+ <value>standard</value>
+ <value>contextual</value>
+ <value>historical</value>
+ <value>discretional</value>
+ <value>standardContextual</value>
+ <value>standardHistorical</value>
+ <value>contextualHistorical</value>
+ <value>standardDiscretional</value>
+ <value>contextualDiscretional</value>
+ <value>historicalDiscretional</value>
+ <value>standardContextualHistorical</value>
+ <value>standardContextualDiscretional</value>
+ <value>standardHistoricalDiscretional</value>
+ <value>contextualHistoricalDiscretional</value>
+ <value>all</value>
+ </choice>
+ </define>
+ <define name="ST_NumForm">
+ <choice>
+ <value>default</value>
+ <value>lining</value>
+ <value>oldStyle</value>
+ </choice>
+ </define>
+ <define name="ST_NumSpacing">
+ <choice>
+ <value>default</value>
+ <value>proportional</value>
+ <value>tabular</value>
+ </choice>
+ </define>
+
+ <define name="ST_PositiveCoordinate">
+ <data type="long"/>
+ </define>
+ <define name="ST_HexColorRGB">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_PositiveFixedPercentage">
+ <data type="long"/>
+ </define>
+ <define name="ST_PositivePercentage">
+ <data type="long"/>
+ </define>
+ <define name="ST_Percentage">
+ <data type="long"/>
+ </define>
+ <define name="ST_PositiveFixedAngle">
+ <data type="int"/>
+ </define>
+ <define name="ST_FixedAngle">
+ <data type="int"/>
+ </define>
+ <define name="ST_LineWidth">
+ <data type="int"/>
+ </define>
+ <define name="ST_UnsignedDecimalNumber">
+ <data type="unsignedLong"/>
+ </define>
+
+ <define name="EG_ColorChoice">
+ <choice>
+ <element name="srgbClr">
+ <ref name="CT_SRgbColor"/>
+ </element>
+ <element name="schemeClr">
+ <ref name="CT_SchemeColor"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_ColorTransform">
+ <choice>
+ <element name="tint">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="shade">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="alpha">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="hueMod">
+ <ref name="CT_PositivePercentage"/>
+ </element>
+ <element name="sat">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="satOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="satMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lum">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lumOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lumMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_FillProperties">
+ <choice>
+ <element name="noFill">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="solidFill">
+ <ref name="CT_SolidColorFillProperties"/>
+ </element>
+ <element name="gradFill">
+ <ref name="CT_GradientFillProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_ShadeProperties">
+ <choice>
+ <element name="lin">
+ <ref name="CT_LinearShadeProperties"/>
+ </element>
+ <element name="path">
+ <ref name="CT_PathShadeProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_LineDashProperties">
+ <choice>
+ <element name="prstDash">
+ <ref name="CT_PresetLineDashProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_LineJoinProperties">
+ <choice>
+ <element name="round">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="bevel">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="miter">
+ <ref name="CT_LineJoinMiterProperties"/>
+ </element>
+ </choice>
+ </define>
+
+ <define name="CT_SRgbColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_HexColorRGB"/>
+ </attribute>
+ </define>
+ <define name="CT_SchemeColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_SchemeColorVal"/>
+ </attribute>
+ </define>
+ <define name="CT_PositiveFixedPercentage">
+ <attribute name="val">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_PositivePercentage">
+ <attribute name="val">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Percentage">
+ <attribute name="val">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Empty">
+ </define>
+ <define name="CT_SolidColorFillProperties">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_GradientFillProperties">
+ <element name="gsLst">
+ <ref name="CT_GradientStopList"/>
+ </element>
+ <ref name="EG_ShadeProperties"/>
+ </define>
+ <define name="CT_LinearShadeProperties">
+ <attribute name="ang">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="scaled">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_PathShadeProperties">
+ <element name="fillToRect">
+ <ref name="CT_RelativeRect"/>
+ </element>
+ <attribute name="path">
+ <ref name="ST_PathShadeType"/>
+ </attribute>
+ </define>
+ <define name="CT_GradientStopList">
+ <element name="gs">
+ <ref name="CT_GradientStop"/>
+ </element>
+ </define>
+ <define name="CT_GradientStop">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="pos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_RelativeRect">
+ <attribute name="l">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_PresetLineDashProperties">
+ <attribute name="val">
+ <ref name="ST_PresetLineDashVal"/>
+ </attribute>
+ </define>
+ <define name="CT_LineJoinMiterProperties">
+ <attribute name="lim">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Camera">
+ <attribute name="prst">
+ <ref name="ST_PresetCameraType"/>
+ </attribute>
+ </define>
+ <define name="CT_LightRig">
+ <element name="rot">
+ <ref name="CT_SphereCoords"/>
+ </element>
+ <attribute name="rig">
+ <ref name="ST_LightRigType"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_LightRigDirection"/>
+ </attribute>
+ </define>
+ <define name="CT_SphereCoords">
+ <attribute name="lat">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="lon">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="rev">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_Bevel">
+ <attribute name="w">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="prst">
+ <ref name="ST_BevelPresetType"/>
+ </attribute>
+ </define>
+ <define name="CT_Color">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_StyleSet">
+ <attribute name="id">
+ <ref name="ST_UnsignedDecimalNumber"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_OnOff">
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+
+
+ <!-- Main Elements-->
+ <define name="CT_Glow">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="rad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_Shadow">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_Reflection">
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="stA">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="stPos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="endA">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="endPos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="fadeDir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_TextOutlineEffect">
+ <ref name="EG_FillProperties"/>
+ <ref name="EG_LineDashProperties"/>
+ <ref name="EG_LineJoinProperties"/>
+ <attribute name="w">
+ <ref name="ST_LineWidth"/>
+ </attribute>
+ <attribute name="cap">
+ <ref name="ST_LineCap"/>
+ </attribute>
+ <attribute name="cmpd">
+ <ref name="ST_CompoundLine"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_PenAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_FillTextEffect">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="CT_Scene3D">
+ <element name="camera">
+ <ref name="CT_Camera"/>
+ </element>
+ <element name="lightRig">
+ <ref name="CT_LightRig"/>
+ </element>
+ </define>
+ <define name="CT_Props3D">
+ <element name="bevelT">
+ <ref name="CT_Bevel"/>
+ </element>
+ <element name="bevelB">
+ <ref name="CT_Bevel"/>
+ </element>
+ <element name="extrusionClr">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="contourClr">
+ <ref name="CT_Color"/>
+ </element>
+ <attribute name="extrusionH">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="contourW">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="prstMaterial">
+ <ref name="ST_PresetMaterialType"/>
+ </attribute>
+ </define>
+ <define name="CT_Ligatures">
+ <attribute name="val">
+ <ref name="ST_Ligatures"/>
+ </attribute>
+ </define>
+ <define name="CT_NumForm">
+ <attribute name="val">
+ <ref name="ST_NumForm"/>
+ </attribute>
+ </define>
+ <define name="CT_NumSpacing">
+ <attribute name="val">
+ <ref name="ST_NumSpacing"/>
+ </attribute>
+ </define>
+ <define name="CT_StylisticSets">
+ <element name="styleSet">
+ <ref name="CT_StyleSet"/>
+ </element>
+ </define>
+
+ <define name="glow">
+ <element name="glow">
+ <ref name="CT_Glow"/>
+ </element>
+ </define>
+ <define name="shadow">
+ <element name="shadow">
+ <ref name="CT_Shadow"/>
+ </element>
+ </define>
+ <define name="reflection">
+ <element name="reflection">
+ <ref name="CT_Reflection"/>
+ </element>
+ </define>
+ <define name="textOutline">
+ <element name="textOutline">
+ <ref name="CT_TextOutlineEffect"/>
+ </element>
+ </define>
+ <define name="textFill">
+ <element name="textFill">
+ <ref name="CT_FillTextEffect"/>
+ </element>
+ </define>
+ <define name="scene3d">
+ <element name="scene3d">
+ <ref name="CT_Scene3D"/>
+ </element>
+ </define>
+ <define name="props3d">
+ <element name="props3d">
+ <ref name="CT_Props3D"/>
+ </element>
+ </define>
+ <define name="ligatures">
+ <element name="ligatures">
+ <ref name="CT_Ligatures"/>
+ </element>
+ </define>
+ <define name="numForm">
+ <element name="numForm">
+ <ref name="CT_NumForm"/>
+ </element>
+ </define>
+ <define name="numSpacing">
+ <element name="numSpacing">
+ <ref name="CT_NumSpacing"/>
+ </element>
+ </define>
+ <define name="stylisticSets">
+ <element name="stylisticSets">
+ <ref name="CT_StylisticSets"/>
+ </element>
+ </define>
+ <define name="cntxtAlts">
+ <element name="cntxtAlts">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+
+ <define name="ST_String">
+ <data type="string"/>
+ </define>
+ <define name="CT_String">
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtCheckbox">
+ <element name="checked">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="checkedState">
+ <ref name="CT_String"/>
+ </element>
+ <element name="uncheckedState">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ </grammar>
+
+ <!-- Simple Types Resource Definitions -->
+ <resource name="CT_String" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_String_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SdtCheckbox" resource="Properties">
+ <element name="checked" tokenid="ooxml:CT_SdtCheckbox_checked"/>
+ <element name="checkedState" tokenid="ooxml:CT_SdtCheckbox_checkedState"/>
+ <element name="uncheckedState" tokenid="ooxml:CT_SdtCheckbox_uncheckedState"/>
+ </resource>
+ <resource name="ST_SchemeColorVal" resource="List">
+ <value tokenid="ooxml:ST_SchemeColorVal_bg1">bg1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_tx1">tx1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_bg2">bg2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_tx2">tx2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent1">accent1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent2">accent2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent3">accent3</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent4">accent4</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent5">accent5</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent6">accent6</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_hlink">hlink</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_folHlink">folHlink</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_dk1">dk1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_lt1">lt1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_dk2">dk2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_lt2">lt2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_phClr">phClr</value>
+ </resource>
+ <resource name="ST_RectAlignment" resource="List">
+ <value tokenid="ooxml:ST_RectAlignment_none">none</value>
+ <value tokenid="ooxml:ST_RectAlignment_tl">tl</value>
+ <value tokenid="ooxml:ST_RectAlignment_t">t</value>
+ <value tokenid="ooxml:ST_RectAlignment_tr">tr</value>
+ <value tokenid="ooxml:ST_RectAlignment_l">l</value>
+ <value tokenid="ooxml:ST_RectAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:ST_RectAlignment_r">r</value>
+ <value tokenid="ooxml:ST_RectAlignment_bl">bl</value>
+ <value tokenid="ooxml:ST_RectAlignment_b">b</value>
+ <value tokenid="ooxml:ST_RectAlignment_br">br</value>
+ </resource>
+ <resource name="ST_LineCap" resource="List">
+ <value tokenid="ooxml:ST_LineCap_rnd">rnd</value>
+ <value tokenid="ooxml:ST_LineCap_sq">sq</value>
+ <value tokenid="ooxml:ST_LineCap_flat">flat</value>
+ </resource>
+ <resource name="ST_CompoundLine" resource="List">
+ <value tokenid="ooxml:ST_CompoundLine_sng">sng</value>
+ <value tokenid="ooxml:ST_CompoundLine_dbl">dbl</value>
+ <value tokenid="ooxml:ST_CompoundLine_thickThin">thickThin</value>
+ <value tokenid="ooxml:ST_CompoundLine_thinThick">thinThick</value>
+ <value tokenid="ooxml:ST_CompoundLine_tri">tri</value>
+ </resource>
+ <resource name="ST_PenAlignment" resource="List">
+ <value tokenid="ooxml:ST_PenAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:ST_PenAlignment_in">in</value>
+ </resource>
+ <resource name="ST_OnOff" resource="List">
+ <value tokenid="ooxml:ST_OnOff_true">true</value>
+ <value tokenid="ooxml:ST_OnOff_false">false</value>
+ <value tokenid="ooxml:ST_OnOff_0">0</value>
+ <value tokenid="ooxml:ST_OnOff_1">1</value>
+ </resource>
+ <resource name="ST_PathShadeType" resource="List">
+ <value tokenid="ooxml:ST_PathShadeType_shape">shape</value>
+ <value tokenid="ooxml:ST_PathShadeType_circle">circle</value>
+ <value tokenid="ooxml:ST_PathShadeType_rect">rect</value>
+ </resource>
+ <resource name="ST_PresetLineDashVal" resource="List">
+ <value tokenid="ooxml:ST_PresetLineDashVal_solid">solid</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_dot">dot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDot">sysDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_dash">dash</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDash">sysDash</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_lgDash">lgDash</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_dashDot">dashDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDashDot">sysDashDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_lgDashDot">lgDashDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_lgDashDotDot">lgDashDotDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDashDotDot">sysDashDotDot</value>
+ </resource>
+ <resource name="ST_PresetCameraType" resource="List">
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueTopLeft">legacyObliqueTopLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueTop">legacyObliqueTop</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueTopRight">legacyObliqueTopRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueLeft">legacyObliqueLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueFront">legacyObliqueFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueRight">legacyObliqueRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueBottomLeft">legacyObliqueBottomLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueBottom">legacyObliqueBottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueBottomRight">legacyObliqueBottomRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveTopLeft">legacyPerspectiveTopLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveTop">legacyPerspectiveTop</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveTopRight">legacyPerspectiveTopRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveLeft">legacyPerspectiveLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveFront">legacyPerspectiveFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveRight">legacyPerspectiveRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveBottomLeft">legacyPerspectiveBottomLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveBottom">legacyPerspectiveBottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveBottomRight">legacyPerspectiveBottomRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_orthographicFront">orthographicFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricTopUp">isometricTopUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricTopDown">isometricTopDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricBottomUp">isometricBottomUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricBottomDown">isometricBottomDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricLeftUp">isometricLeftUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricLeftDown">isometricLeftDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricRightUp">isometricRightUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricRightDown">isometricRightDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis1Left">isometricOffAxis1Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis1Right">isometricOffAxis1Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis1Top">isometricOffAxis1Top</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis2Left">isometricOffAxis2Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis2Right">isometricOffAxis2Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis2Top">isometricOffAxis2Top</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis3Left">isometricOffAxis3Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis3Right">isometricOffAxis3Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis3Bottom">isometricOffAxis3Bottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis4Left">isometricOffAxis4Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis4Right">isometricOffAxis4Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis4Bottom">isometricOffAxis4Bottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueTopLeft">obliqueTopLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueTop">obliqueTop</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueTopRight">obliqueTopRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueLeft">obliqueLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueRight">obliqueRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueBottomLeft">obliqueBottomLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueBottom">obliqueBottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueBottomRight">obliqueBottomRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveFront">perspectiveFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveLeft">perspectiveLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveRight">perspectiveRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveAbove">perspectiveAbove</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveBelow">perspectiveBelow</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveAboveLeftFacing">perspectiveAboveLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveAboveRightFacing">perspectiveAboveRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveContrastingLeftFacing">perspectiveContrastingLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveContrastingRightFacing">perspectiveContrastingRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicLeftFacing">perspectiveHeroicLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicRightFacing">perspectiveHeroicRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicExtremeLeftFacing">perspectiveHeroicExtremeLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicExtremeRightFacing">perspectiveHeroicExtremeRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveRelaxed">perspectiveRelaxed</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveRelaxedModerately">perspectiveRelaxedModerately</value>
+ </resource>
+ <resource name="ST_LightRigType" resource="List">
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat1">legacyFlat1</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat2">legacyFlat2</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat3">legacyFlat3</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat4">legacyFlat4</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal1">legacyNormal1</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal2">legacyNormal2</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal3">legacyNormal3</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal4">legacyNormal4</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh1">legacyHarsh1</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh2">legacyHarsh2</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh3">legacyHarsh3</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh4">legacyHarsh4</value>
+ <value tokenid="ooxml:ST_LightRigType_threePt">threePt</value>
+ <value tokenid="ooxml:ST_LightRigType_balanced">balanced</value>
+ <value tokenid="ooxml:ST_LightRigType_soft">soft</value>
+ <value tokenid="ooxml:ST_LightRigType_harsh">harsh</value>
+ <value tokenid="ooxml:ST_LightRigType_flood">flood</value>
+ <value tokenid="ooxml:ST_LightRigType_contrasting">contrasting</value>
+ <value tokenid="ooxml:ST_LightRigType_morning">morning</value>
+ <value tokenid="ooxml:ST_LightRigType_sunrise">sunrise</value>
+ <value tokenid="ooxml:ST_LightRigType_sunset">sunset</value>
+ <value tokenid="ooxml:ST_LightRigType_chilly">chilly</value>
+ <value tokenid="ooxml:ST_LightRigType_freezing">freezing</value>
+ <value tokenid="ooxml:ST_LightRigType_flat">flat</value>
+ <value tokenid="ooxml:ST_LightRigType_twoPt">twoPt</value>
+ <value tokenid="ooxml:ST_LightRigType_glow">glow</value>
+ <value tokenid="ooxml:ST_LightRigType_brightRoom">brightRoom</value>
+ </resource>
+ <resource name="ST_LightRigDirection" resource="List">
+ <value tokenid="ooxml:ST_LightRigDirection_tl">tl</value>
+ <value tokenid="ooxml:ST_LightRigDirection_t">t</value>
+ <value tokenid="ooxml:ST_LightRigDirection_tr">tr</value>
+ <value tokenid="ooxml:ST_LightRigDirection_l">l</value>
+ <value tokenid="ooxml:ST_LightRigDirection_r">r</value>
+ <value tokenid="ooxml:ST_LightRigDirection_bl">bl</value>
+ <value tokenid="ooxml:ST_LightRigDirection_b">b</value>
+ <value tokenid="ooxml:ST_LightRigDirection_br">br</value>
+ </resource>
+ <resource name="ST_BevelPresetType" resource="List">
+ <value tokenid="ooxml:ST_BevelPresetType_relaxedInset">relaxedInset</value>
+ <value tokenid="ooxml:ST_BevelPresetType_circle">circle</value>
+ <value tokenid="ooxml:ST_BevelPresetType_slope">slope</value>
+ <value tokenid="ooxml:ST_BevelPresetType_cross">cross</value>
+ <value tokenid="ooxml:ST_BevelPresetType_angle">angle</value>
+ <value tokenid="ooxml:ST_BevelPresetType_softRound">softRound</value>
+ <value tokenid="ooxml:ST_BevelPresetType_convex">convex</value>
+ <value tokenid="ooxml:ST_BevelPresetType_coolSlant">coolSlant</value>
+ <value tokenid="ooxml:ST_BevelPresetType_divot">divot</value>
+ <value tokenid="ooxml:ST_BevelPresetType_riblet">riblet</value>
+ <value tokenid="ooxml:ST_BevelPresetType_hardEdge">hardEdge</value>
+ <value tokenid="ooxml:ST_BevelPresetType_artDeco">artDeco</value>
+ </resource>
+ <resource name="ST_PresetMaterialType" resource="List">
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyMatte">legacyMatte</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyPlastic">legacyPlastic</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyMetal">legacyMetal</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyWireframe">legacyWireframe</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_matte">matte</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_plastic">plastic</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_metal">metal</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_warmMatte">warmMatte</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_translucentPowder">translucentPowder</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_powder">powder</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_dkEdge">dkEdge</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_softEdge">softEdge</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_clear">clear</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_flat">flat</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_softmetal">softmetal</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_none">none</value>
+ </resource>
+ <resource name="ST_Ligatures" resource="List">
+ <value tokenid="ooxml:ST_Ligatures_none">none</value>
+ <value tokenid="ooxml:ST_Ligatures_standard">standard</value>
+ <value tokenid="ooxml:ST_Ligatures_contextual">contextual</value>
+ <value tokenid="ooxml:ST_Ligatures_historical">historical</value>
+ <value tokenid="ooxml:ST_Ligatures_discretional">discretional</value>
+ <value tokenid="ooxml:ST_Ligatures_standardContextual">standardContextual</value>
+ <value tokenid="ooxml:ST_Ligatures_standardHistorical">standardHistorical</value>
+ <value tokenid="ooxml:ST_Ligatures_contextualHistorical">contextualHistorical</value>
+ <value tokenid="ooxml:ST_Ligatures_standardDiscretional">standardDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_contextualDiscretional">contextualDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_historicalDiscretional">historicalDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_standardContextualHistorical">standardContextualHistorical</value>
+ <value tokenid="ooxml:ST_Ligatures_standardContextualDiscretional">standardContextualDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_standardHistoricalDiscretional">standardHistoricalDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_contextualHistoricalDiscretional">contextualHistoricalDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_all">all</value>
+ </resource>
+ <resource name="ST_NumForm" resource="List">
+ <value tokenid="ooxml:ST_NumForm_default">default</value>
+ <value tokenid="ooxml:ST_NumForm_lining">lining</value>
+ <value tokenid="ooxml:ST_NumForm_oldStyle">oldStyle</value>
+ </resource>
+ <resource name="ST_NumSpacing" resource="List">
+ <value tokenid="ooxml:ST_NumSpacing_default">default</value>
+ <value tokenid="ooxml:ST_NumSpacing_proportional">proportional</value>
+ <value tokenid="ooxml:ST_NumSpacing_tabular">tabular</value>
+ </resource>
+
+ <resource name="ST_PositiveCoordinate" resource="Integer"/>
+ <resource name="ST_HexColorRGB" resource="Hex"/>
+ <resource name="ST_PositivePercentage" resource="Integer"/>
+ <resource name="ST_PositiveFixedPercentage" resource="Integer"/>
+ <resource name="ST_Percentage" resource="Integer"/>
+ <resource name="ST_PositiveFixedAngle" resource="Integer"/>
+ <resource name="ST_FixedAngle" resource="Integer"/>
+ <resource name="ST_LineWidth" resource="Integer"/>
+ <resource name="ST_UnsignedDecimalNumber" resource="Integer"/>
+
+ <!-- Groups Resource Definitions -->
+ <resource name="EG_ColorTransform" resource="Properties">
+ <element name="tint" tokenid="ooxml:EG_ColorTransform_tint"/>
+ <element name="shade" tokenid="ooxml:EG_ColorTransform_shade"/>
+ <element name="alpha" tokenid="ooxml:EG_ColorTransform_alpha"/>
+ <element name="hueMod" tokenid="ooxml:EG_ColorTransform_hueMod"/>
+ <element name="sat" tokenid="ooxml:EG_ColorTransform_sat"/>
+ <element name="satOff" tokenid="ooxml:EG_ColorTransform_satOff"/>
+ <element name="satMod" tokenid="ooxml:EG_ColorTransform_satMod"/>
+ <element name="lum" tokenid="ooxml:EG_ColorTransform_lum"/>
+ <element name="lumOff" tokenid="ooxml:EG_ColorTransform_lumOff"/>
+ <element name="lumMod" tokenid="ooxml:EG_ColorTransform_lumMod"/>
+ </resource>
+ <resource name="EG_ColorChoice" resource="Properties">
+ <element name="srgbClr" tokenid="ooxml:EG_ColorChoice_srgbClr"/>
+ <element name="schemeClr" tokenid="ooxml:EG_ColorChoice_schemeClr"/>
+ </resource>
+ <resource name="EG_FillProperties" resource="Properties">
+ <element name="noFill" tokenid="ooxml:EG_FillProperties_noFill"/>
+ <element name="solidFill" tokenid="ooxml:EG_FillProperties_solidFill"/>
+ <element name="gradFill" tokenid="ooxml:EG_FillProperties_gradFill"/>
+ </resource>
+ <resource name="EG_ShadeProperties" resource="Properties">
+ <element name="lin" tokenid="ooxml:EG_ShadeProperties_lin"/>
+ <element name="path" tokenid="ooxml:EG_ShadeProperties_path"/>
+ </resource>
+ <resource name="EG_LineDashProperties" resource="Properties">
+ <element name="prstDash" tokenid="ooxml:EG_LineDashProperties_prstDash"/>
+ </resource>
+ <resource name="EG_LineJoinProperties" resource="Properties">
+ <element name="round" tokenid="ooxml:EG_LineJoinProperties_round"/>
+ <element name="bevel" tokenid="ooxml:EG_LineJoinProperties_bevel"/>
+ <element name="miter" tokenid="ooxml:EG_LineJoinProperties_miter"/>
+ </resource>
+
+ <!-- Complex Types Resource Definitions -->
+ <resource name="CT_Glow" resource="Properties">
+ <attribute name="rad" tokenid="ooxml:CT_Glow_rad"/>
+ </resource>
+ <resource name="CT_SRgbColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SRgbColor_val"/>
+ </resource>
+ <resource name="CT_SchemeColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SchemeColor_val"/>
+ </resource>
+ <resource name="CT_PositiveFixedPercentage" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PositiveFixedPercentage_val"/>
+ </resource>
+ <resource name="CT_PositivePercentage" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PositivePercentage_val"/>
+ </resource>
+ <resource name="CT_Percentage" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Percentage_val"/>
+ </resource>
+ <resource name="CT_Empty" resource="Properties"/>
+ <resource name="CT_SolidColorFillProperties" resource="Properties"/>
+ <resource name="CT_GradientFillProperties" resource="Properties">
+ <element name="gsLst" tokenid="ooxml:CT_GradientFillProperties_gsLst"/>
+ </resource>
+ <resource name="CT_GradientStopList" resource="Properties">
+ <element name="gs" tokenid="ooxml:CT_GradientStopList_gs"/>
+ </resource>
+ <resource name="CT_GradientStop" resource="Properties">
+ <attribute name="pos" tokenid="ooxml:CT_GradientStop_pos"/>
+ </resource>
+ <resource name="CT_LinearShadeProperties" resource="Properties">
+ <attribute name="ang" tokenid="ooxml:CT_LinearShadeProperties_ang"/>
+ <attribute name="scaled" tokenid="ooxml:CT_LinearShadeProperties_scaled"/>
+ </resource>
+ <resource name="CT_PathShadeProperties" resource="Properties">
+ <element name="fillToRect" tokenid="ooxml:CT_PathShadeProperties_fillToRect"/>
+ <attribute name="path" tokenid="ooxml:CT_PathShadeProperties_path"/>
+ </resource>
+ <resource name="CT_RelativeRect" resource="Properties">
+ <attribute name="l" tokenid="ooxml:CT_RelativeRect_l"/>
+ <attribute name="t" tokenid="ooxml:CT_RelativeRect_t"/>
+ <attribute name="r" tokenid="ooxml:CT_RelativeRect_r"/>
+ <attribute name="b" tokenid="ooxml:CT_RelativeRect_b"/>
+ </resource>
+ <resource name="CT_PresetLineDashProperties" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PresetLineDashProperties_val"/>
+ </resource>
+ <resource name="CT_LineJoinMiterProperties" resource="Properties">
+ <attribute name="lim" tokenid="ooxml:CT_LineJoinMiterProperties_lim"/>
+ </resource>
+ <resource name="CT_Camera" resource="Properties">
+ <attribute name="prst" tokenid="ooxml:CT_Camera_prst"/>
+ </resource>
+ <resource name="CT_LightRig" resource="Properties">
+ <element name="rot" tokenid="ooxml:CT_LightRig_rot"/>
+ <attribute name="rig" tokenid="ooxml:CT_LightRig_rig"/>
+ <attribute name="dir" tokenid="ooxml:CT_LightRig_dir"/>
+ </resource>
+ <resource name="CT_SphereCoords" resource="Properties">
+ <attribute name="lat" tokenid="ooxml:CT_SphereCoords_lat"/>
+ <attribute name="lon" tokenid="ooxml:CT_SphereCoords_lon"/>
+ <attribute name="rev" tokenid="ooxml:CT_SphereCoords_rev"/>
+ </resource>
+ <resource name="CT_Bevel" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_Bevel_w"/>
+ <attribute name="h" tokenid="ooxml:CT_Bevel_h"/>
+ <attribute name="prst" tokenid="ooxml:CT_Bevel_prst"/>
+ </resource>
+ <resource name="CT_Color" resource="Properties"/>
+ <resource name="CT_StyleSet" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_StyleSet_id"/>
+ <attribute name="val" tokenid="ooxml:CT_StyleSet_val"/>
+ </resource>
+ <resource name="CT_OnOff" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OnOff_val" action="setValue"/>
+ <action name="start" action="setDefaultBooleanValue"/>
+ </resource>
+
+ <!-- Main element content -->
+ <resource name="CT_Shadow" resource="Properties">
+ <attribute name="blurRad" tokenid="ooxml:CT_Shadow_blurRad"/>
+ <attribute name="dist" tokenid="ooxml:CT_Shadow_dist"/>
+ <attribute name="dir" tokenid="ooxml:CT_Shadow_dir"/>
+ <attribute name="sx" tokenid="ooxml:CT_Shadow_sx"/>
+ <attribute name="sy" tokenid="ooxml:CT_Shadow_sy"/>
+ <attribute name="kx" tokenid="ooxml:CT_Shadow_kx"/>
+ <attribute name="ky" tokenid="ooxml:CT_Shadow_ky"/>
+ <attribute name="algn" tokenid="ooxml:CT_Shadow_algn"/>
+ </resource>
+ <resource name="CT_Reflection" resource="Properties">
+ <attribute name="blurRad" tokenid="ooxml:CT_Reflection_blurRad"/>
+ <attribute name="stA" tokenid="ooxml:CT_Reflection_stA"/>
+ <attribute name="stPos" tokenid="ooxml:CT_Reflection_stPos"/>
+ <attribute name="endA" tokenid="ooxml:CT_Reflection_endA"/>
+ <attribute name="endPos" tokenid="ooxml:CT_Reflection_endPos"/>
+ <attribute name="dist" tokenid="ooxml:CT_Reflection_dist"/>
+ <attribute name="dir" tokenid="ooxml:CT_Reflection_dir"/>
+ <attribute name="fadeDir" tokenid="ooxml:CT_Reflection_fadeDir"/>
+ <attribute name="sx" tokenid="ooxml:CT_Reflection_sx"/>
+ <attribute name="sy" tokenid="ooxml:CT_Reflection_sy"/>
+ <attribute name="kx" tokenid="ooxml:CT_Reflection_kx"/>
+ <attribute name="ky" tokenid="ooxml:CT_Reflection_ky"/>
+ <attribute name="algn" tokenid="ooxml:CT_Reflection_algn"/>
+ </resource>
+ <resource name="CT_TextOutlineEffect" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_TextOutlineEffect_w"/>
+ <attribute name="cap" tokenid="ooxml:CT_TextOutlineEffect_cap"/>
+ <attribute name="cmpd" tokenid="ooxml:CT_TextOutlineEffect_cmpd"/>
+ <attribute name="algn" tokenid="ooxml:CT_TextOutlineEffect_algn"/>
+ </resource>
+ <resource name="CT_FillTextEffect" resource="Properties"/>
+ <resource name="CT_Scene3D" resource="Properties">
+ <element name="camera" tokenid="ooxml:CT_Scene3D_camera"/>
+ <element name="lightRig" tokenid="ooxml:CT_Scene3D_lightRig"/>
+ </resource>
+ <resource name="CT_Props3D" resource="Properties">
+ <element name="bevelT" tokenid="ooxml:CT_Props3D_bevelT"/>
+ <element name="bevelB" tokenid="ooxml:CT_Props3D_bevelB"/>
+ <element name="extrusionClr" tokenid="ooxml:CT_Props3D_extrusionClr"/>
+ <element name="contourClr" tokenid="ooxml:CT_Props3D_contourClr"/>
+ <attribute name="extrusionH" tokenid="ooxml:CT_Props3D_extrusionH"/>
+ <attribute name="contourW" tokenid="ooxml:CT_Props3D_contourW"/>
+ <attribute name="prstMaterial" tokenid="ooxml:CT_Props3D_prstMaterial"/>
+ </resource>
+ <resource name="CT_Ligatures" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Ligatures_val"/>
+ </resource>
+ <resource name="CT_NumForm" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_NumForm_val"/>
+ </resource>
+ <resource name="CT_NumSpacing" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_NumSpacing_val"/>
+ </resource>
+ <resource name="CT_StylisticSets" resource="Properties">
+ <attribute name="styleSet" tokenid="ooxml:CT_StylisticSets_styleSet"/>
+ </resource>
+
+ <resource name="glow" resource="Properties">
+ <element name="glow" tokenid="ooxml:glow_glow"/>
+ </resource>
+ <resource name="shadow" resource="Properties">
+ <element name="shadow" tokenid="ooxml:shadow_shadow"/>
+ </resource>
+ <resource name="reflection" resource="Properties">
+ <element name="reflection" tokenid="ooxml:reflection_reflection"/>
+ </resource>
+ <resource name="textOutline" resource="Properties">
+ <element name="textOutline" tokenid="ooxml:textOutline_textOutline"/>
+ </resource>
+ <resource name="textFill" resource="Properties">
+ <element name="textFill" tokenid="ooxml:textFill_textFill"/>
+ </resource>
+ <resource name="scene3d" resource="Properties">
+ <element name="scene3d" tokenid="ooxml:scene3d_scene3d"/>
+ </resource>
+ <resource name="props3d" resource="Properties">
+ <element name="props3d" tokenid="ooxml:props3d_props3d"/>
+ </resource>
+ <resource name="ligatures" resource="Properties">
+ <element name="ligatures" tokenid="ooxml:ligatures_ligatures"/>
+ </resource>
+ <resource name="numForm" resource="Properties">
+ <element name="numForm" tokenid="ooxml:numForm_numForm"/>
+ </resource>
+ <resource name="numSpacing" resource="Properties">
+ <element name="numSpacing" tokenid="ooxml:numSpacing_numSpacing"/>
+ </resource>
+ <resource name="stylisticSets" resource="Properties">
+ <element name="stylisticSets" tokenid="ooxml:stylisticSets_stylisticSets"/>
+ </resource>
+ <resource name="cntxtAlts" resource="Properties">
+ <element name="cntxtAlts" tokenid="ooxml:cntxtAlts_cntxtAlts"/>
+ </resource>
+ </namespace>
+ <namespace name="w15">
+ <start name="commentsEx"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2012/wordml" attributeFormDefault="qualified">
+ <define name="commentsEx">
+ <element name="commentsEx">
+ <ref name="CT_CommentsEx"/>
+ </element>
+ </define>
+ <define name="CT_CommentsEx">
+ <element name="commentEx">
+ <ref name="CT_CommentEx"/>
+ </element>
+ </define>
+ <define name="CT_CommentEx">
+ <attribute name="paraId">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ <!-- Not yet used
+ <attribute name="paraIdParent">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ -->
+ <attribute name="done">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_LongHexNumber">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <value>true</value>
+ <value>false</value>
+ <value>0</value>
+ <value>1</value>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="CT_CommentsEx" resource="Stream">
+ <element name="commentEx" tokenid="ooxml:CT_CommentsEx_commentEx"/>
+ </resource>
+ <resource name="CT_CommentEx" resource="CommentEx">
+ <attribute name="paraId" tokenid="ooxml:CT_CommentEx_paraId" action="att_paraId"/>
+ <attribute name="done" tokenid="ooxml:CT_CommentEx_done" action="att_done"/>
+ </resource>
+ <resource name="ST_LongHexNumber" resource="String"/>
+ <resource name="ST_OnOff" resource="Boolean"/>
+ </namespace>
+ <namespace name="a14">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/drawing/2010/main">
+ <!-- Simple types -->
+ <define name="ST_ArtisticEffectParam10">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ArtisticEffectParam100">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ArtisticEffectParam4">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ArtisticEffectParam6">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ColorTemperature">
+ <data type="integer"/>
+ </define>
+ <define name="ST_SaturationAmount">
+ <data type="integer"/>
+ </define>
+
+ <!-- Complex types for effects -->
+ <define name="CT_PictureEffectBlur">
+ <attribute name="visible">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectCement">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="crackSpacing">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectChalkSketch">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam4"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectCrisscrossEtching">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam4"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectCutout">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="numberOfShades">
+ <ref name="ST_ArtisticEffectParam6"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectFilmGrain">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="grainSize">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectGlass">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="scaling">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectGlowDiffused">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="intensity">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectGlowEdges">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="smoothness">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectLightScreen">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="gridSize">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectLineDrawing">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pencilSize">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectMarker">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="size">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectMosiaicBubbles">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPaintStrokes">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="intensity">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPaintBrush">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="brushSize">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPastelsSmooth">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="scaling">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPencilGrayscale">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pencilSize">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPencilSketch">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPhotocopy">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="detail">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPlasticWrap">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="smoothness">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectTexturizer">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="scaling">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectWatercolorSponge">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="brushSize">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectBrightnessContrast">
+ <attribute name="bright">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ <attribute name="contrast">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectColorTemperature">
+ <attribute name="colorTemp">
+ <ref name="ST_ColorTemperature"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectSaturation">
+ <attribute name="sat">
+ <ref name="ST_SaturationAmount"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectSharpenSoften">
+ <attribute name="amount">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+
+ <!-- Complex types for containers -->
+ <define name="CT_PictureEffect">
+ <choice>
+ <element name="artisticBlur">
+ <ref name="CT_PictureEffectBlur"/>
+ </element>
+ <element name="artisticCement">
+ <ref name="CT_PictureEffectCement"/>
+ </element>
+ <element name="artisticChalkSketch">
+ <ref name="CT_PictureEffectChalkSketch"/>
+ </element>
+ <element name="artisticCrisscrossEtching">
+ <ref name="CT_PictureEffectCrisscrossEtching"/>
+ </element>
+ <element name="artisticCutout">
+ <ref name="CT_PictureEffectCutout"/>
+ </element>
+ <element name="artisticFilmGrain">
+ <ref name="CT_PictureEffectFilmGrain"/>
+ </element>
+ <element name="artisticGlass">
+ <ref name="CT_PictureEffectGlass"/>
+ </element>
+ <element name="artisticGlowDiffused">
+ <ref name="CT_PictureEffectGlowDiffused"/>
+ </element>
+ <element name="artisticGlowEdges">
+ <ref name="CT_PictureEffectGlowEdges"/>
+ </element>
+ <element name="artisticLightScreen">
+ <ref name="CT_PictureEffectLightScreen"/>
+ </element>
+ <element name="artisticLineDrawing">
+ <ref name="CT_PictureEffectLineDrawing"/>
+ </element>
+ <element name="artisticMarker">
+ <ref name="CT_PictureEffectMarker"/>
+ </element>
+ <element name="artisticMosiaicBubbles">
+ <ref name="CT_PictureEffectMosiaicBubbles"/>
+ </element>
+ <element name="artisticPaintStrokes">
+ <ref name="CT_PictureEffectPaintStrokes"/>
+ </element>
+ <element name="artisticPaintBrush">
+ <ref name="CT_PictureEffectPaintBrush"/>
+ </element>
+ <element name="artisticPastelsSmooth">
+ <ref name="CT_PictureEffectPastelsSmooth"/>
+ </element>
+ <element name="artisticPencilGrayscale">
+ <ref name="CT_PictureEffectPencilGrayscale"/>
+ </element>
+ <element name="artisticPencilSketch">
+ <ref name="CT_PictureEffectPencilSketch"/>
+ </element>
+ <element name="artisticPhotocopy">
+ <ref name="CT_PictureEffectPhotocopy"/>
+ </element>
+ <element name="artisticPlasticWrap">
+ <ref name="CT_PictureEffectPlasticWrap"/>
+ </element>
+ <element name="artisticTexturizer">
+ <ref name="CT_PictureEffectTexturizer"/>
+ </element>
+ <element name="artisticWatercolorSponge">
+ <ref name="CT_PictureEffectWatercolorSponge"/>
+ </element>
+ <element name="brightnessContrast">
+ <ref name="CT_PictureEffectBrightnessContrast"/>
+ </element>
+ <element name="colorTemperature">
+ <ref name="CT_PictureEffectColorTemperature"/>
+ </element>
+ <element name="saturation">
+ <ref name="CT_PictureEffectSaturation"/>
+ </element>
+ <element name="sharpenSoften">
+ <ref name="CT_PictureEffectSharpenSoften"/>
+ </element>
+ </choice>
+ <attribute name="visible">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureLayer">
+ <element name="imgEffect">
+ <ref name="CT_PictureEffect"/>
+ </element>
+ <attribute name="r:embed">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Photo">
+ <element name="imgLayer">
+ <ref name="CT_PictureLayer"/>
+ </element>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="dml-shapeGeometry">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <define name="ST_ShapeType">
+ <choice>
+ <!-- Line Shape -->
+ <value>line</value>
+ <!-- Line Inverse Shape -->
+ <value>lineInv</value>
+ <!-- Triangle Shape -->
+ <value>triangle</value>
+ <!-- Right Triangle Shape -->
+ <value>rtTriangle</value>
+ <!-- Rectangle Shape -->
+ <value>rect</value>
+ <!-- Diamond Shape -->
+ <value>diamond</value>
+ <!-- Parallelogram Shape -->
+ <value>parallelogram</value>
+ <!-- Trapezoid Shape -->
+ <value>trapezoid</value>
+ <!-- Non-Isosceles Trapezoid Shape -->
+ <value>nonIsoscelesTrapezoid</value>
+ <!-- Pentagon Shape -->
+ <value>pentagon</value>
+ <!-- Hexagon Shape -->
+ <value>hexagon</value>
+ <!-- Heptagon Shape -->
+ <value>heptagon</value>
+ <!-- Octagon Shape -->
+ <value>octagon</value>
+ <!-- Decagon Shape -->
+ <value>decagon</value>
+ <!-- Dodecagon Shape -->
+ <value>dodecagon</value>
+ <!-- Four Pointed Star Shape -->
+ <value>star4</value>
+ <!-- Five Pointed Star Shape -->
+ <value>star5</value>
+ <!-- Six Pointed Star Shape -->
+ <value>star6</value>
+ <!-- Seven Pointed Star Shape -->
+ <value>star7</value>
+ <!-- Eight Pointed Star Shape -->
+ <value>star8</value>
+ <!-- Ten Pointed Star Shape -->
+ <value>star10</value>
+ <!-- Twelve Pointed Star Shape -->
+ <value>star12</value>
+ <!-- Sixteen Pointed Star Shape -->
+ <value>star16</value>
+ <!-- Twenty Four Pointed Star Shape -->
+ <value>star24</value>
+ <!-- Thirty Two Pointed Star Shape -->
+ <value>star32</value>
+ <!-- Round Corner Rectangle Shape -->
+ <value>roundRect</value>
+ <!-- One Round Corner Rectangle Shape -->
+ <value>round1Rect</value>
+ <!-- Two Same-side Round Corner Rectangle Shape -->
+ <value>round2SameRect</value>
+ <!-- Two Diagonal Round Corner Rectangle Shape -->
+ <value>round2DiagRect</value>
+ <!-- One Snip One Round Corner Rectangle Shape -->
+ <value>snipRoundRect</value>
+ <!-- One Snip Corner Rectangle Shape -->
+ <value>snip1Rect</value>
+ <!-- Two Same-side Snip Corner Rectangle Shape -->
+ <value>snip2SameRect</value>
+ <!-- Two Diagonal Snip Corner Rectangle Shape -->
+ <value>snip2DiagRect</value>
+ <!-- Plaque Shape -->
+ <value>plaque</value>
+ <!-- Ellipse Shape -->
+ <value>ellipse</value>
+ <!-- Teardrop Shape -->
+ <value>teardrop</value>
+ <!-- Home Plate Shape -->
+ <value>homePlate</value>
+ <!-- Chevron Shape -->
+ <value>chevron</value>
+ <!-- Pie Wedge Shape -->
+ <value>pieWedge</value>
+ <!-- Pie Shape -->
+ <value>pie</value>
+ <!-- Block Arc Shape -->
+ <value>blockArc</value>
+ <!-- Donut Shape -->
+ <value>donut</value>
+ <!-- No Smoking Shape -->
+ <value>noSmoking</value>
+ <!-- Right Arrow Shape -->
+ <value>rightArrow</value>
+ <!-- Left Arrow Shape -->
+ <value>leftArrow</value>
+ <!-- Up Arrow Shape -->
+ <value>upArrow</value>
+ <!-- Down Arrow Shape -->
+ <value>downArrow</value>
+ <!-- Striped Right Arrow Shape -->
+ <value>stripedRightArrow</value>
+ <!-- Notched Right Arrow Shape -->
+ <value>notchedRightArrow</value>
+ <!-- Bent Up Arrow Shape -->
+ <value>bentUpArrow</value>
+ <!-- Left Right Arrow Shape -->
+ <value>leftRightArrow</value>
+ <!-- Up Down Arrow Shape -->
+ <value>upDownArrow</value>
+ <!-- Left Up Arrow Shape -->
+ <value>leftUpArrow</value>
+ <!-- Left Right Up Arrow Shape -->
+ <value>leftRightUpArrow</value>
+ <!-- Quad-Arrow Shape -->
+ <value>quadArrow</value>
+ <!-- Callout Left Arrow Shape -->
+ <value>leftArrowCallout</value>
+ <!-- Callout Right Arrow Shape -->
+ <value>rightArrowCallout</value>
+ <!-- Callout Up Arrow Shape -->
+ <value>upArrowCallout</value>
+ <!-- Callout Down Arrow Shape -->
+ <value>downArrowCallout</value>
+ <!-- Callout Left Right Arrow Shape -->
+ <value>leftRightArrowCallout</value>
+ <!-- Callout Up Down Arrow Shape -->
+ <value>upDownArrowCallout</value>
+ <!-- Callout Quad-Arrow Shape -->
+ <value>quadArrowCallout</value>
+ <!-- Bent Arrow Shape -->
+ <value>bentArrow</value>
+ <!-- U-Turn Arrow Shape -->
+ <value>uturnArrow</value>
+ <!-- Circular Arrow Shape -->
+ <value>circularArrow</value>
+ <!-- Left Circular Arrow Shape -->
+ <value>leftCircularArrow</value>
+ <!-- Left Right Circular Arrow Shape -->
+ <value>leftRightCircularArrow</value>
+ <!-- Curved Right Arrow Shape -->
+ <value>curvedRightArrow</value>
+ <!-- Curved Left Arrow Shape -->
+ <value>curvedLeftArrow</value>
+ <!-- Curved Up Arrow Shape -->
+ <value>curvedUpArrow</value>
+ <!-- Curved Down Arrow Shape -->
+ <value>curvedDownArrow</value>
+ <!-- Swoosh Arrow Shape -->
+ <value>swooshArrow</value>
+ <!-- Cube Shape -->
+ <value>cube</value>
+ <!-- Can Shape -->
+ <value>can</value>
+ <!-- Lightning Bolt Shape -->
+ <value>lightningBolt</value>
+ <!-- Heart Shape -->
+ <value>heart</value>
+ <!-- Sun Shape -->
+ <value>sun</value>
+ <!-- Moon Shape -->
+ <value>moon</value>
+ <!-- Smiley Face Shape -->
+ <value>smileyFace</value>
+ <!-- Irregular Seal 1 Shape -->
+ <value>irregularSeal1</value>
+ <!-- Irregular Seal 2 Shape -->
+ <value>irregularSeal2</value>
+ <!-- Folded Corner Shape -->
+ <value>foldedCorner</value>
+ <!-- Bevel Shape -->
+ <value>bevel</value>
+ <!-- Frame Shape -->
+ <value>frame</value>
+ <!-- Half Frame Shape -->
+ <value>halfFrame</value>
+ <!-- Corner Shape -->
+ <value>corner</value>
+ <!-- Diagonal Stripe Shape -->
+ <value>diagStripe</value>
+ <!-- Chord Shape -->
+ <value>chord</value>
+ <!-- Curved Arc Shape -->
+ <value>arc</value>
+ <!-- Left Bracket Shape -->
+ <value>leftBracket</value>
+ <!-- Right Bracket Shape -->
+ <value>rightBracket</value>
+ <!-- Left Brace Shape -->
+ <value>leftBrace</value>
+ <!-- Right Brace Shape -->
+ <value>rightBrace</value>
+ <!-- Bracket Pair Shape -->
+ <value>bracketPair</value>
+ <!-- Brace Pair Shape -->
+ <value>bracePair</value>
+ <!-- Straight Connector 1 Shape -->
+ <value>straightConnector1</value>
+ <!-- Bent Connector 2 Shape -->
+ <value>bentConnector2</value>
+ <!-- Bent Connector 3 Shape -->
+ <value>bentConnector3</value>
+ <!-- Bent Connector 4 Shape -->
+ <value>bentConnector4</value>
+ <!-- Bent Connector 5 Shape -->
+ <value>bentConnector5</value>
+ <!-- Curved Connector 2 Shape -->
+ <value>curvedConnector2</value>
+ <!-- Curved Connector 3 Shape -->
+ <value>curvedConnector3</value>
+ <!-- Curved Connector 4 Shape -->
+ <value>curvedConnector4</value>
+ <!-- Curved Connector 5 Shape -->
+ <value>curvedConnector5</value>
+ <!-- Callout 1 Shape -->
+ <value>callout1</value>
+ <!-- Callout 2 Shape -->
+ <value>callout2</value>
+ <!-- Callout 3 Shape -->
+ <value>callout3</value>
+ <!-- Callout 1 Shape -->
+ <value>accentCallout1</value>
+ <!-- Callout 2 Shape -->
+ <value>accentCallout2</value>
+ <!-- Callout 3 Shape -->
+ <value>accentCallout3</value>
+ <!-- Callout 1 with Border Shape -->
+ <value>borderCallout1</value>
+ <!-- Callout 2 with Border Shape -->
+ <value>borderCallout2</value>
+ <!-- Callout 3 with Border Shape -->
+ <value>borderCallout3</value>
+ <!-- Callout 1 with Border and Accent Shape -->
+ <value>accentBorderCallout1</value>
+ <!-- Callout 2 with Border and Accent Shape -->
+ <value>accentBorderCallout2</value>
+ <!-- Callout 3 with Border and Accent Shape -->
+ <value>accentBorderCallout3</value>
+ <!-- Callout Wedge Rectangle Shape -->
+ <value>wedgeRectCallout</value>
+ <!-- Callout Wedge Round Rectangle Shape -->
+ <value>wedgeRoundRectCallout</value>
+ <!-- Callout Wedge Ellipse Shape -->
+ <value>wedgeEllipseCallout</value>
+ <!-- Callout Cloud Shape -->
+ <value>cloudCallout</value>
+ <!-- Cloud Shape -->
+ <value>cloud</value>
+ <!-- Ribbon Shape -->
+ <value>ribbon</value>
+ <!-- Ribbon 2 Shape -->
+ <value>ribbon2</value>
+ <!-- Ellipse Ribbon Shape -->
+ <value>ellipseRibbon</value>
+ <!-- Ellipse Ribbon 2 Shape -->
+ <value>ellipseRibbon2</value>
+ <!-- Left Right Ribbon Shape -->
+ <value>leftRightRibbon</value>
+ <!-- Vertical Scroll Shape -->
+ <value>verticalScroll</value>
+ <!-- Horizontal Scroll Shape -->
+ <value>horizontalScroll</value>
+ <!-- Wave Shape -->
+ <value>wave</value>
+ <!-- Double Wave Shape -->
+ <value>doubleWave</value>
+ <!-- Plus Shape -->
+ <value>plus</value>
+ <!-- Process Flow Shape -->
+ <value>flowChartProcess</value>
+ <!-- Decision Flow Shape -->
+ <value>flowChartDecision</value>
+ <!-- Input Output Flow Shape -->
+ <value>flowChartInputOutput</value>
+ <!-- Predefined Process Flow Shape -->
+ <value>flowChartPredefinedProcess</value>
+ <!-- Internal Storage Flow Shape -->
+ <value>flowChartInternalStorage</value>
+ <!-- Document Flow Shape -->
+ <value>flowChartDocument</value>
+ <!-- Multi-Document Flow Shape -->
+ <value>flowChartMultidocument</value>
+ <!-- Terminator Flow Shape -->
+ <value>flowChartTerminator</value>
+ <!-- Preparation Flow Shape -->
+ <value>flowChartPreparation</value>
+ <!-- Manual Input Flow Shape -->
+ <value>flowChartManualInput</value>
+ <!-- Manual Operation Flow Shape -->
+ <value>flowChartManualOperation</value>
+ <!-- Connector Flow Shape -->
+ <value>flowChartConnector</value>
+ <!-- Punched Card Flow Shape -->
+ <value>flowChartPunchedCard</value>
+ <!-- Punched Tape Flow Shape -->
+ <value>flowChartPunchedTape</value>
+ <!-- Summing Junction Flow Shape -->
+ <value>flowChartSummingJunction</value>
+ <!-- Or Flow Shape -->
+ <value>flowChartOr</value>
+ <!-- Collate Flow Shape -->
+ <value>flowChartCollate</value>
+ <!-- Sort Flow Shape -->
+ <value>flowChartSort</value>
+ <!-- Extract Flow Shape -->
+ <value>flowChartExtract</value>
+ <!-- Merge Flow Shape -->
+ <value>flowChartMerge</value>
+ <!-- Offline Storage Flow Shape -->
+ <value>flowChartOfflineStorage</value>
+ <!-- Online Storage Flow Shape -->
+ <value>flowChartOnlineStorage</value>
+ <!-- Magnetic Tape Flow Shape -->
+ <value>flowChartMagneticTape</value>
+ <!-- Magnetic Disk Flow Shape -->
+ <value>flowChartMagneticDisk</value>
+ <!-- Magnetic Drum Flow Shape -->
+ <value>flowChartMagneticDrum</value>
+ <!-- Display Flow Shape -->
+ <value>flowChartDisplay</value>
+ <!-- Delay Flow Shape -->
+ <value>flowChartDelay</value>
+ <!-- Alternate Process Flow Shape -->
+ <value>flowChartAlternateProcess</value>
+ <!-- Off-Page Connector Flow Shape -->
+ <value>flowChartOffpageConnector</value>
+ <!-- Blank Button Shape -->
+ <value>actionButtonBlank</value>
+ <!-- Home Button Shape -->
+ <value>actionButtonHome</value>
+ <!-- Help Button Shape -->
+ <value>actionButtonHelp</value>
+ <!-- Information Button Shape -->
+ <value>actionButtonInformation</value>
+ <!-- Forward or Next Button Shape -->
+ <value>actionButtonForwardNext</value>
+ <!-- Back or Previous Button Shape -->
+ <value>actionButtonBackPrevious</value>
+ <!-- End Button Shape -->
+ <value>actionButtonEnd</value>
+ <!-- Beginning Button Shape -->
+ <value>actionButtonBeginning</value>
+ <!-- Return Button Shape -->
+ <value>actionButtonReturn</value>
+ <!-- Document Button Shape -->
+ <value>actionButtonDocument</value>
+ <!-- Sound Button Shape -->
+ <value>actionButtonSound</value>
+ <!-- Movie Button Shape -->
+ <value>actionButtonMovie</value>
+ <!-- Gear 6 Shape -->
+ <value>gear6</value>
+ <!-- Gear 9 Shape -->
+ <value>gear9</value>
+ <!-- Funnel Shape -->
+ <value>funnel</value>
+ <!-- Plus Math Shape -->
+ <value>mathPlus</value>
+ <!-- Minus Math Shape -->
+ <value>mathMinus</value>
+ <!-- Multiply Math Shape -->
+ <value>mathMultiply</value>
+ <!-- Divide Math Shape -->
+ <value>mathDivide</value>
+ <!-- Equal Math Shape -->
+ <value>mathEqual</value>
+ <!-- Not Equal Math Shape -->
+ <value>mathNotEqual</value>
+ <!-- Corner Tabs Shape -->
+ <value>cornerTabs</value>
+ <!-- Square Tabs Shape -->
+ <value>squareTabs</value>
+ <!-- Plaque Tabs Shape -->
+ <value>plaqueTabs</value>
+ <!-- Chart X Shape -->
+ <value>chartX</value>
+ <!-- Chart Star Shape -->
+ <value>chartStar</value>
+ <!-- Chart Plus Shape -->
+ <value>chartPlus</value>
+ </choice>
+ </define>
+ <define name="ST_TextShapeType">
+ <choice>
+ <!-- No Text Shape -->
+ <value>textNoShape</value>
+ <!-- Plain Text Shape -->
+ <value>textPlain</value>
+ <!-- Stop Sign Text Shape -->
+ <value>textStop</value>
+ <!-- Triangle Text Shape -->
+ <value>textTriangle</value>
+ <!-- Inverted Triangle Text Shape -->
+ <value>textTriangleInverted</value>
+ <!-- Chevron Text Shape -->
+ <value>textChevron</value>
+ <!-- Inverted Chevron Text Shape -->
+ <value>textChevronInverted</value>
+ <!-- Inside Ring Text Shape -->
+ <value>textRingInside</value>
+ <!-- Outside Ring Text Shape -->
+ <value>textRingOutside</value>
+ <!-- Upward Arch Text Shape -->
+ <value>textArchUp</value>
+ <!-- Downward Arch Text Shape -->
+ <value>textArchDown</value>
+ <!-- Circle Text Shape -->
+ <value>textCircle</value>
+ <!-- Button Text Shape -->
+ <value>textButton</value>
+ <!-- Upward Pour Arch Text Shape -->
+ <value>textArchUpPour</value>
+ <!-- Downward Pour Arch Text Shape -->
+ <value>textArchDownPour</value>
+ <!-- Circle Pour Text Shape -->
+ <value>textCirclePour</value>
+ <!-- Button Pour Text Shape -->
+ <value>textButtonPour</value>
+ <!-- Upward Curve Text Shape -->
+ <value>textCurveUp</value>
+ <!-- Downward Curve Text Shape -->
+ <value>textCurveDown</value>
+ <!-- Upward Can Text Shape -->
+ <value>textCanUp</value>
+ <!-- Downward Can Text Shape -->
+ <value>textCanDown</value>
+ <!-- Wave 1 Text Shape -->
+ <value>textWave1</value>
+ <!-- Wave 2 Text Shape -->
+ <value>textWave2</value>
+ <!-- Double Wave 1 Text Shape -->
+ <value>textDoubleWave1</value>
+ <!-- Wave 4 Text Shape -->
+ <value>textWave4</value>
+ <!-- Inflate Text Shape -->
+ <value>textInflate</value>
+ <!-- Deflate Text Shape -->
+ <value>textDeflate</value>
+ <!-- Bottom Inflate Text Shape -->
+ <value>textInflateBottom</value>
+ <!-- Bottom Deflate Text Shape -->
+ <value>textDeflateBottom</value>
+ <!-- Top Inflate Text Shape -->
+ <value>textInflateTop</value>
+ <!-- Top Deflate Text Shape -->
+ <value>textDeflateTop</value>
+ <!-- Deflate-Inflate Text Shape -->
+ <value>textDeflateInflate</value>
+ <!-- Deflate-Inflate-Deflate Text Shape -->
+ <value>textDeflateInflateDeflate</value>
+ <!-- Right Fade Text Shape -->
+ <value>textFadeRight</value>
+ <!-- Left Fade Text Shape -->
+ <value>textFadeLeft</value>
+ <!-- Upward Fade Text Shape -->
+ <value>textFadeUp</value>
+ <!-- Downward Fade Text Shape -->
+ <value>textFadeDown</value>
+ <!-- Upward Slant Text Shape -->
+ <value>textSlantUp</value>
+ <!-- Downward Slant Text Shape -->
+ <value>textSlantDown</value>
+ <!-- Upward Cascade Text Shape -->
+ <value>textCascadeUp</value>
+ <!-- Downward Cascade Text Shape -->
+ <value>textCascadeDown</value>
+ </choice>
+ </define>
+ <define name="ST_GeomGuideName">
+ <data type="token"/>
+ </define>
+ <define name="ST_GeomGuideFormula">
+ <data type="string"/>
+ </define>
+ <define name="CT_GeomGuide">
+ <attribute name="name">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="fmla">
+ <ref name="ST_GeomGuideFormula"/>
+ </attribute>
+ </define>
+ <define name="CT_GeomGuideList">
+ <element name="gd">
+ <ref name="CT_GeomGuide"/>
+ </element>
+ </define>
+ <define name="ST_AdjCoordinate">
+ <choice>
+ <ref name="ST_Coordinate"/>
+ <ref name="ST_GeomGuideName"/>
+ </choice>
+ </define>
+ <!-- Union -->
+ <define name="ST_AdjAngle">
+ <choice>
+ <ref name="ST_Angle"/>
+ <ref name="ST_GeomGuideName"/>
+ </choice>
+ </define>
+ <!-- Union -->
+ <define name="CT_AdjPoint2D">
+ <attribute name="x">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="y">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_GeomRect">
+ <attribute name="l">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_XYAdjustHandle">
+ <element name="pos">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ <attribute name="gdRefX">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minX">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxX">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="gdRefY">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minY">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxY">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_PolarAdjustHandle">
+ <element name="pos">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ <attribute name="gdRefR">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="gdRefAng">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minAng">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxAng">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_ConnectionSite">
+ <element name="pos">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ <attribute name="ang">
+ <ref name="ST_AdjAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_AdjustHandleList">
+ <choice>
+ <element name="ahXY">
+ <ref name="CT_XYAdjustHandle"/>
+ </element>
+ <element name="ahPolar">
+ <ref name="CT_PolarAdjustHandle"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_ConnectionSiteList">
+ <element name="cxn">
+ <ref name="CT_ConnectionSite"/>
+ </element>
+ </define>
+ <define name="CT_Connection">
+ <attribute name="id">
+ <ref name="ST_DrawingElementId"/>
+ </attribute>
+ <attribute name="idx">
+ <data type="unsignedInt"/>
+ </attribute>
+ </define>
+ <define name="CT_Path2DMoveTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DLineTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DArcTo">
+ <attribute name="wR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="hR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="stAng">
+ <ref name="ST_AdjAngle"/>
+ </attribute>
+ <attribute name="swAng">
+ <ref name="ST_AdjAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_Path2DQuadBezierTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DCubicBezierTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DClose">
+ </define>
+ <define name="ST_PathFillMode">
+ <choice>
+ <!-- No Path Fill -->
+ <value>none</value>
+ <!-- Normal Path Fill -->
+ <value>norm</value>
+ <!-- Lighten Path Fill -->
+ <value>lighten</value>
+ <!-- Lighten Path Fill Less -->
+ <value>lightenLess</value>
+ <!-- Darken Path Fill -->
+ <value>darken</value>
+ <!-- Darken Path Fill Less -->
+ <value>darkenLess</value>
+ </choice>
+ </define>
+ <define name="CT_Path2D">
+ <choice>
+ <element name="close">
+ <ref name="CT_Path2DClose"/>
+ </element>
+ <element name="moveTo">
+ <ref name="CT_Path2DMoveTo"/>
+ </element>
+ <element name="lnTo">
+ <ref name="CT_Path2DLineTo"/>
+ </element>
+ <element name="arcTo">
+ <ref name="CT_Path2DArcTo"/>
+ </element>
+ <element name="quadBezTo">
+ <ref name="CT_Path2DQuadBezierTo"/>
+ </element>
+ <element name="cubicBezTo">
+ <ref name="CT_Path2DCubicBezierTo"/>
+ </element>
+ </choice>
+ <attribute name="w">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="fill">
+ <ref name="ST_PathFillMode"/>
+ </attribute>
+ <attribute name="stroke">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="extrusionOk">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_Path2DList">
+ <element name="path">
+ <ref name="CT_Path2D"/>
+ </element>
+ </define>
+ <define name="CT_PresetGeometry2D">
+ <element name="avLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <attribute name="prst">
+ <ref name="ST_ShapeType"/>
+ </attribute>
+ </define>
+ <define name="CT_PresetTextShape">
+ <element name="avLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <attribute name="prst">
+ <ref name="ST_TextShapeType"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomGeometry2D">
+ <element name="avLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <element name="gdLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <element name="ahLst">
+ <ref name="CT_AdjustHandleList"/>
+ </element>
+ <element name="cxnLst">
+ <ref name="CT_ConnectionSiteList"/>
+ </element>
+ <element name="rect">
+ <ref name="CT_GeomRect"/>
+ </element>
+ <element name="pathLst">
+ <ref name="CT_Path2DList"/>
+ </element>
+ </define>
+ <define name="EG_Geometry">
+ <choice>
+ <element name="custGeom">
+ <ref name="CT_CustomGeometry2D"/>
+ </element>
+ <element name="prstGeom">
+ <ref name="CT_PresetGeometry2D"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_TextGeometry">
+ <choice>
+ <element name="custGeom">
+ <ref name="CT_CustomGeometry2D"/>
+ </element>
+ <element name="prstTxWarp">
+ <ref name="CT_PresetTextShape"/>
+ </element>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="ST_ShapeType" resource="List">
+ <value tokenid="ooxml:Value_ST_ShapeType_line">line</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_lineInv">lineInv</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_triangle">triangle</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rtTriangle">rtTriangle</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rect">rect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_diamond">diamond</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_parallelogram">parallelogram</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_trapezoid">trapezoid</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_nonIsoscelesTrapezoid">nonIsoscelesTrapezoid</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_pentagon">pentagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_hexagon">hexagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_heptagon">heptagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_octagon">octagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_decagon">decagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_dodecagon">dodecagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star4">star4</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star5">star5</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star6">star6</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star7">star7</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star8">star8</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star10">star10</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star12">star12</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star16">star16</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star24">star24</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star32">star32</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_roundRect">roundRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_round1Rect">round1Rect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_round2SameRect">round2SameRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_round2DiagRect">round2DiagRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snipRoundRect">snipRoundRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snip1Rect">snip1Rect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snip2SameRect">snip2SameRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snip2DiagRect">snip2DiagRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_plaque">plaque</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ellipse">ellipse</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_teardrop">teardrop</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_homePlate">homePlate</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chevron">chevron</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_pieWedge">pieWedge</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_pie">pie</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_blockArc">blockArc</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_donut">donut</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_noSmoking">noSmoking</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightArrow">rightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftArrow">leftArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upArrow">upArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_downArrow">downArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_stripedRightArrow">stripedRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_notchedRightArrow">notchedRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentUpArrow">bentUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightArrow">leftRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upDownArrow">upDownArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftUpArrow">leftUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightUpArrow">leftRightUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_quadArrow">quadArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftArrowCallout">leftArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightArrowCallout">rightArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upArrowCallout">upArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_downArrowCallout">downArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightArrowCallout">leftRightArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upDownArrowCallout">upDownArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_quadArrowCallout">quadArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentArrow">bentArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_uturnArrow">uturnArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_circularArrow">circularArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftCircularArrow">leftCircularArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightCircularArrow">leftRightCircularArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedRightArrow">curvedRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedLeftArrow">curvedLeftArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedUpArrow">curvedUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedDownArrow">curvedDownArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_swooshArrow">swooshArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cube">cube</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_can">can</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_lightningBolt">lightningBolt</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_heart">heart</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_sun">sun</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_moon">moon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_smileyFace">smileyFace</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_irregularSeal1">irregularSeal1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_irregularSeal2">irregularSeal2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_foldedCorner">foldedCorner</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bevel">bevel</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_frame">frame</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_halfFrame">halfFrame</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_corner">corner</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_diagStripe">diagStripe</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chord">chord</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_arc">arc</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftBracket">leftBracket</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightBracket">rightBracket</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftBrace">leftBrace</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightBrace">rightBrace</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bracketPair">bracketPair</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bracePair">bracePair</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_straightConnector1">straightConnector1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector2">bentConnector2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector3">bentConnector3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector4">bentConnector4</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector5">bentConnector5</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector2">curvedConnector2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector3">curvedConnector3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector4">curvedConnector4</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector5">curvedConnector5</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_callout1">callout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_callout2">callout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_callout3">callout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentCallout1">accentCallout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentCallout2">accentCallout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentCallout3">accentCallout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_borderCallout1">borderCallout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_borderCallout2">borderCallout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_borderCallout3">borderCallout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentBorderCallout1">accentBorderCallout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentBorderCallout2">accentBorderCallout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentBorderCallout3">accentBorderCallout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wedgeRectCallout">wedgeRectCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wedgeRoundRectCallout">wedgeRoundRectCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wedgeEllipseCallout">wedgeEllipseCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cloudCallout">cloudCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cloud">cloud</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ribbon">ribbon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ribbon2">ribbon2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ellipseRibbon">ellipseRibbon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ellipseRibbon2">ellipseRibbon2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightRibbon">leftRightRibbon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_verticalScroll">verticalScroll</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_horizontalScroll">horizontalScroll</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wave">wave</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_doubleWave">doubleWave</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_plus">plus</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartProcess">flowChartProcess</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDecision">flowChartDecision</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartInputOutput">flowChartInputOutput</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPredefinedProcess">flowChartPredefinedProcess</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartInternalStorage">flowChartInternalStorage</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDocument">flowChartDocument</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMultidocument">flowChartMultidocument</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartTerminator">flowChartTerminator</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPreparation">flowChartPreparation</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartManualInput">flowChartManualInput</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartManualOperation">flowChartManualOperation</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartConnector">flowChartConnector</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPunchedCard">flowChartPunchedCard</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPunchedTape">flowChartPunchedTape</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartSummingJunction">flowChartSummingJunction</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOr">flowChartOr</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartCollate">flowChartCollate</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartSort">flowChartSort</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartExtract">flowChartExtract</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMerge">flowChartMerge</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOfflineStorage">flowChartOfflineStorage</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOnlineStorage">flowChartOnlineStorage</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMagneticTape">flowChartMagneticTape</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMagneticDisk">flowChartMagneticDisk</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMagneticDrum">flowChartMagneticDrum</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDisplay">flowChartDisplay</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDelay">flowChartDelay</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartAlternateProcess">flowChartAlternateProcess</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOffpageConnector">flowChartOffpageConnector</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonBlank">actionButtonBlank</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonHome">actionButtonHome</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonHelp">actionButtonHelp</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonInformation">actionButtonInformation</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonForwardNext">actionButtonForwardNext</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonBackPrevious">actionButtonBackPrevious</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonEnd">actionButtonEnd</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonBeginning">actionButtonBeginning</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonReturn">actionButtonReturn</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonDocument">actionButtonDocument</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonSound">actionButtonSound</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonMovie">actionButtonMovie</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_gear6">gear6</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_gear9">gear9</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_funnel">funnel</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathPlus">mathPlus</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathMinus">mathMinus</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathMultiply">mathMultiply</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathDivide">mathDivide</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathEqual">mathEqual</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathNotEqual">mathNotEqual</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cornerTabs">cornerTabs</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_squareTabs">squareTabs</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_plaqueTabs">plaqueTabs</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chartX">chartX</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chartStar">chartStar</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chartPlus">chartPlus</value>
+ </resource>
+ <resource name="ST_TextShapeType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textNoShape">textNoShape</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textPlain">textPlain</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textStop">textStop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textTriangle">textTriangle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textTriangleInverted">textTriangleInverted</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textChevron">textChevron</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textChevronInverted">textChevronInverted</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textRingInside">textRingInside</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textRingOutside">textRingOutside</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchUp">textArchUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchDown">textArchDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCircle">textCircle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textButton">textButton</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchUpPour">textArchUpPour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchDownPour">textArchDownPour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCirclePour">textCirclePour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textButtonPour">textButtonPour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCurveUp">textCurveUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCurveDown">textCurveDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCanUp">textCanUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCanDown">textCanDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textWave1">textWave1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textWave2">textWave2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDoubleWave1">textDoubleWave1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textWave4">textWave4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textInflate">textInflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflate">textDeflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textInflateBottom">textInflateBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateBottom">textDeflateBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textInflateTop">textInflateTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateTop">textDeflateTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateInflate">textDeflateInflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateInflateDeflate">textDeflateInflateDeflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeRight">textFadeRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeLeft">textFadeLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeUp">textFadeUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeDown">textFadeDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textSlantUp">textSlantUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textSlantDown">textSlantDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCascadeUp">textCascadeUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCascadeDown">textCascadeDown</value>
+ </resource>
+ <resource name="ST_GeomGuideName" resource="String"/>
+ <resource name="ST_GeomGuideFormula" resource="String"/>
+ <resource name="CT_GeomGuideList" resource="Properties">
+ <element name="gd" tokenid="ooxml:CT_GeomGuideList_gd"/>
+ </resource>
+ <resource name="ST_PathFillMode" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_none">none</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_norm">norm</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_lighten">lighten</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_lightenLess">lightenLess</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_darken">darken</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_darkenLess">darkenLess</value>
+ </resource>
+ <resource name="CT_PresetGeometry2D" resource="Properties">
+ <element name="avLst" tokenid="ooxml:CT_PresetGeometry2D_avLst"/>
+ <attribute name="prst" tokenid="ooxml:CT_PresetGeometry2D_prst"/>
+ </resource>
+ <resource name="CT_CustomGeometry2D" resource="Properties">
+ <element name="avLst" tokenid="ooxml:CT_CustomGeometry2D_avLst"/>
+ <element name="gdLst" tokenid="ooxml:CT_CustomGeometry2D_gdLst"/>
+ <element name="ahLst" tokenid="ooxml:CT_CustomGeometry2D_ahLst"/>
+ <element name="cxnLst" tokenid="ooxml:CT_CustomGeometry2D_cxnLst"/>
+ <element name="rect" tokenid="ooxml:CT_CustomGeometry2D_rect"/>
+ <element name="pathLst" tokenid="ooxml:CT_CustomGeometry2D_pathLst"/>
+ </resource>
+ <resource name="EG_Geometry" resource="Properties">
+ <element name="custGeom" tokenid="ooxml:EG_Geometry_custGeom"/>
+ <element name="prstGeom" tokenid="ooxml:EG_Geometry_prstGeom"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-wordprocessingDrawing">
+ <start name="inline"/>
+ <start name="anchor"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
+ <include href="dml-graphicalObject"/>
+ <include href="dml-documentProperties"/>
+ <!-- start = inline | anchor -->
+ <define name="ST_Coordinate">
+ <data type="long"/>
+ </define>
+ <define name="CT_EffectExtent">
+ <attribute name="l">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="ST_WrapDistance">
+ <data type="unsignedInt"/>
+ </define>
+ <define name="ST_EditId">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_Inline">
+ <element name="extent">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <element name="docPr">
+ <ref name="CT_NonVisualDrawingProps"/>
+ </element>
+ <element name="cNvGraphicFramePr">
+ <ref name="CT_NonVisualGraphicFrameProperties"/>
+ </element>
+ <element name="a:graphic">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelH">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelV">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="wp14:anchorId">
+ <ref name="ST_EditId"/>
+ </attribute>
+ </define>
+ <define name="ST_WrapText">
+ <choice>
+ <!-- Both Sides -->
+ <value>bothSides</value>
+ <!-- Left Side Only -->
+ <value>left</value>
+ <!-- Right Side Only -->
+ <value>right</value>
+ <!-- Largest Side Only -->
+ <value>largest</value>
+ </choice>
+ </define>
+ <define name="CT_WrapPath">
+ <element name="start">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="lineTo">
+ <ref name="CT_Point2D"/>
+ </element>
+ <attribute name="edited">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapNone">
+ </define>
+ <define name="CT_WrapSquare">
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <attribute name="wrapText">
+ <ref name="ST_WrapText"/>
+ </attribute>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapTight">
+ <element name="wrapPolygon">
+ <ref name="CT_WrapPath"/>
+ </element>
+ <attribute name="wrapText">
+ <ref name="ST_WrapText"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapThrough">
+ <element name="wrapPolygon">
+ <ref name="CT_WrapPath"/>
+ </element>
+ <attribute name="wrapText">
+ <ref name="ST_WrapText"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapTopBottom">
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="EG_WrapType">
+ <choice>
+ <element name="wrapNone">
+ <ref name="CT_WrapNone"/>
+ </element>
+ <element name="wrapSquare">
+ <ref name="CT_WrapSquare"/>
+ </element>
+ <element name="wrapTight">
+ <ref name="CT_WrapTight"/>
+ </element>
+ <element name="wrapThrough">
+ <ref name="CT_WrapThrough"/>
+ </element>
+ <element name="wrapTopAndBottom">
+ <ref name="CT_WrapTopBottom"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_PositionOffset">
+ <data type="int"/>
+ </define>
+ <define name="ST_AlignH">
+ <choice>
+ <!-- Left Alignment -->
+ <value>left</value>
+ <!-- Right Alignment -->
+ <value>right</value>
+ <!-- Center Alignment -->
+ <value>center</value>
+ <!-- Inside -->
+ <value>inside</value>
+ <!-- Outside -->
+ <value>outside</value>
+ </choice>
+ </define>
+ <define name="ST_RelFromH">
+ <choice>
+ <!-- Page Margin -->
+ <value>margin</value>
+ <!-- Page Edge -->
+ <value>page</value>
+ <!-- Column -->
+ <value>column</value>
+ <!-- Character -->
+ <value>character</value>
+ <!-- Left Margin -->
+ <value>leftMargin</value>
+ <!-- Right Margin -->
+ <value>rightMargin</value>
+ <!-- Inside Margin -->
+ <value>insideMargin</value>
+ <!-- Outside Margin -->
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="CT_PosH">
+ <choice>
+ <element name="align">
+ <ref name="ST_AlignH"/>
+ </element>
+ <element name="posOffset">
+ <ref name="ST_PositionOffset"/>
+ </element>
+ </choice>
+ <attribute name="relativeFrom">
+ <ref name="ST_RelFromH"/>
+ </attribute>
+ </define>
+ <define name="ST_AlignV">
+ <choice>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Bottom -->
+ <value>bottom</value>
+ <!-- Center Alignment -->
+ <value>center</value>
+ <!-- Inside -->
+ <value>inside</value>
+ <!-- Outside -->
+ <value>outside</value>
+ </choice>
+ </define>
+ <define name="ST_RelFromV">
+ <choice>
+ <!-- Page Margin -->
+ <value>margin</value>
+ <!-- Page Edge -->
+ <value>page</value>
+ <!-- Paragraph -->
+ <value>paragraph</value>
+ <!-- Line -->
+ <value>line</value>
+ <!-- Top Margin -->
+ <value>topMargin</value>
+ <!-- Bottom Margin -->
+ <value>bottomMargin</value>
+ <!-- Inside Margin -->
+ <value>insideMargin</value>
+ <!-- Outside Margin -->
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="CT_PosV">
+ <choice>
+ <element name="align">
+ <ref name="ST_AlignV"/>
+ </element>
+ <element name="posOffset">
+ <ref name="ST_PositionOffset"/>
+ </element>
+ </choice>
+ <attribute name="relativeFrom">
+ <ref name="ST_RelFromV"/>
+ </attribute>
+ </define>
+ <define name="CT_Anchor">
+ <element name="simplePos">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="positionH">
+ <ref name="CT_PosH"/>
+ </element>
+ <element name="positionV">
+ <ref name="CT_PosV"/>
+ </element>
+ <element name="extent">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <ref name="EG_WrapType"/>
+ <element name="docPr">
+ <ref name="CT_NonVisualDrawingProps"/>
+ </element>
+ <element name="cNvGraphicFramePr">
+ <ref name="CT_NonVisualGraphicFrameProperties"/>
+ </element>
+ <element name="a:graphic">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelH">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelV">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="simplePos">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="relativeHeight">
+ <data type="unsignedInt"/>
+ </attribute>
+ <attribute name="behindDoc">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="locked">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="layoutInCell">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="hidden">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="allowOverlap">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="wp14:anchorId">
+ <ref name="ST_EditId"/>
+ </attribute>
+ </define>
+ <define name="inline">
+ <element name="inline">
+ <ref name="CT_Inline"/>
+ </element>
+ </define>
+ <define name="anchor">
+ <element name="anchor">
+ <ref name="CT_Anchor"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_Coordinate" resource="Integer"/>
+ <resource name="CT_EffectExtent" resource="Properties">
+ <attribute name="l" tokenid="ooxml:CT_EffectExtent_l"/>
+ <attribute name="t" tokenid="ooxml:CT_EffectExtent_t"/>
+ <attribute name="r" tokenid="ooxml:CT_EffectExtent_r"/>
+ <attribute name="b" tokenid="ooxml:CT_EffectExtent_b"/>
+ </resource>
+ <resource name="ST_WrapDistance" resource="Integer"/>
+ <resource name="CT_Inline" resource="Properties">
+ <element name="extent" tokenid="ooxml:CT_Inline_extent"/>
+ <element name="effectExtent" tokenid="ooxml:CT_Inline_effectExtent"/>
+ <element name="docPr" tokenid="ooxml:CT_Inline_docPr"/>
+ <element name="cNvGraphicFramePr" tokenid="ooxml:CT_Inline_cNvGraphicFramePr"/>
+ <element name="a:graphic" tokenid="ooxml:CT_Inline_a_graphic"/>
+ <element name="wp14:sizeRelH" tokenid="ooxml:CT_Inline_wp14_sizeRelH"/>
+ <element name="wp14:sizeRelV" tokenid="ooxml:CT_Inline_wp14_sizeRelV"/>
+ <attribute name="distT" tokenid="ooxml:CT_Inline_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_Inline_distB"/>
+ <attribute name="distL" tokenid="ooxml:CT_Inline_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_Inline_distR"/>
+ <attribute name="wp14:anchorId" tokenid="ooxml:CT_Inline_wp14_anchorId"/>
+ </resource>
+ <resource name="ST_WrapText" resource="List">
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_bothSides">bothSides</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_left">left</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_right">right</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_largest">largest</value>
+ </resource>
+ <resource name="CT_WrapPath" resource="Properties">
+ <element name="start" tokenid="ooxml:CT_WrapPath_start"/>
+ <element name="lineTo" tokenid="ooxml:CT_WrapPath_lineTo"/>
+ <attribute name="edited" tokenid="ooxml:CT_WrapPath_edited"/>
+ </resource>
+ <resource name="CT_WrapNone" resource="Properties"/>
+ <resource name="CT_WrapSquare" resource="Properties">
+ <element name="effectExtent" tokenid="ooxml:CT_WrapSquare_effectExtent"/>
+ <attribute name="wrapText" tokenid="ooxml:CT_WrapSquare_wrapText"/>
+ <attribute name="distT" tokenid="ooxml:CT_WrapSquare_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_WrapSquare_distB"/>
+ <attribute name="distL" tokenid="ooxml:CT_WrapSquare_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_WrapSquare_distR"/>
+ </resource>
+ <resource name="CT_WrapTight" resource="Properties">
+ <element name="wrapPolygon" tokenid="ooxml:CT_WrapTight_wrapPolygon"/>
+ <attribute name="wrapText" tokenid="ooxml:CT_WrapTight_wrapText"/>
+ <attribute name="distL" tokenid="ooxml:CT_WrapTight_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_WrapTight_distR"/>
+ </resource>
+ <resource name="CT_WrapThrough" resource="Properties">
+ <element name="wrapPolygon" tokenid="ooxml:CT_WrapThrough_wrapPolygon"/>
+ <attribute name="wrapText" tokenid="ooxml:CT_WrapThrough_wrapText"/>
+ <attribute name="distL" tokenid="ooxml:CT_WrapThrough_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_WrapThrough_distR"/>
+ </resource>
+ <resource name="CT_WrapTopBottom" resource="Properties">
+ <element name="effectExtent" tokenid="ooxml:CT_WrapTopBottom_effectExtent"/>
+ <attribute name="distT" tokenid="ooxml:CT_WrapTopBottom_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_WrapTopBottom_distB"/>
+ </resource>
+ <resource name="EG_WrapType" resource="Properties">
+ <element name="wrapNone" tokenid="ooxml:EG_WrapType_wrapNone"/>
+ <element name="wrapSquare" tokenid="ooxml:EG_WrapType_wrapSquare"/>
+ <element name="wrapTight" tokenid="ooxml:EG_WrapType_wrapTight"/>
+ <element name="wrapThrough" tokenid="ooxml:EG_WrapType_wrapThrough"/>
+ <element name="wrapTopAndBottom" tokenid="ooxml:EG_WrapType_wrapTopAndBottom"/>
+ </resource>
+ <resource name="ST_PositionOffset" resource="Value">
+ <action name="characters" action="positionOffset"/>
+ </resource>
+ <resource name="ST_AlignH" resource="Value">
+ <action name="characters" action="alignH"/>
+ </resource>
+ <resource name="ST_RelFromH" resource="List">
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_margin">margin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_page">page</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_column">column</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_character">character</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_leftMargin">leftMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_rightMargin">rightMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="CT_PosH" resource="Properties">
+ <element name="align" tokenid="ooxml:CT_PosH_align"/>
+ <element name="posOffset" tokenid="ooxml:CT_PosH_posOffset"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_PosH_relativeFrom"/>
+ </resource>
+ <resource name="ST_AlignV" resource="Value">
+ <action name="characters" action="alignV"/>
+ </resource>
+ <resource name="ST_RelFromV" resource="List">
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_margin">margin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_page">page</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_paragraph">paragraph</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_line">line</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_topMargin">topMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_bottomMargin">bottomMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="CT_PosV" resource="Properties">
+ <element name="align" tokenid="ooxml:CT_PosV_align"/>
+ <element name="posOffset" tokenid="ooxml:CT_PosV_posOffset"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_PosV_relativeFrom"/>
+ </resource>
+ <resource name="ST_EditId" resource="Hex"/>
+ <resource name="CT_Anchor" resource="Properties">
+ <element name="simplePos" tokenid="ooxml:CT_Anchor_simplePos_elem"/>
+ <element name="positionH" tokenid="ooxml:CT_Anchor_positionH"/>
+ <element name="positionV" tokenid="ooxml:CT_Anchor_positionV"/>
+ <element name="extent" tokenid="ooxml:CT_Anchor_extent"/>
+ <element name="effectExtent" tokenid="ooxml:CT_Anchor_effectExtent"/>
+ <element name="docPr" tokenid="ooxml:CT_Anchor_docPr"/>
+ <element name="cNvGraphicFramePr" tokenid="ooxml:CT_Anchor_cNvGraphicFramePr"/>
+ <element name="a:graphic" tokenid="ooxml:CT_Anchor_a_graphic"/>
+ <element name="wp14:sizeRelV" tokenid="ooxml:CT_Anchor_wp14_sizeRelV"/>
+ <attribute name="distT" tokenid="ooxml:CT_Anchor_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_Anchor_distB"/>
+ <attribute name="distL" tokenid="ooxml:CT_Anchor_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_Anchor_distR"/>
+ <attribute name="simplePos" tokenid="ooxml:CT_Anchor_simplePos_attr"/>
+ <attribute name="relativeHeight" tokenid="ooxml:CT_Anchor_relativeHeight"/>
+ <attribute name="behindDoc" tokenid="ooxml:CT_Anchor_behindDoc"/>
+ <attribute name="locked" tokenid="ooxml:CT_Anchor_locked"/>
+ <attribute name="layoutInCell" tokenid="ooxml:CT_Anchor_layoutInCell"/>
+ <attribute name="hidden" tokenid="ooxml:CT_Anchor_hidden"/>
+ <attribute name="allowOverlap" tokenid="ooxml:CT_Anchor_allowOverlap"/>
+ <attribute name="wp14:anchorId" tokenid="ooxml:CT_Anchor_wp14_anchorId"/>
+ </resource>
+ <resource name="inline" resource="Properties">
+ <element name="inline" tokenid="ooxml:inline_inline"/>
+ </resource>
+ <resource name="anchor" resource="Properties">
+ <element name="anchor" tokenid="ooxml:anchor_anchor"/>
+ </resource>
+ </namespace>
+ <namespace name="sml-customXmlMappings">
+ <start name="schemaLibrary"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
+ <!-- ISO RELAX NG Schema -->
+ <!-- start = schemaLibrary -->
+ <define name="CT_Schema">
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="manifestLocation">
+ <data type="string"/>
+ </attribute>
+ <attribute name="schemaLocation">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SchemaLibrary">
+ <element name="schema">
+ <ref name="CT_Schema"/>
+ </element>
+ </define>
+ <define name="schemaLibrary">
+ <element name="schemaLibrary">
+ <ref name="CT_SchemaLibrary"/>
+ </element>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="shared-math">
+ <start name="oMathPara"/>
+ <start name="oMath"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/officeDocument/2006/math" attributeFormDefault="qualified">
+ <include href="wml"/>
+ <!-- start = mathPr | oMathPara | oMath -->
+ <define name="ST_Integer255">
+ <data type="integer"/>
+ </define>
+ <define name="CT_Integer255">
+ <attribute name="val">
+ <ref name="ST_Integer255"/>
+ </attribute>
+ </define>
+ <define name="ST_Integer2">
+ <data type="integer"/>
+ </define>
+ <define name="CT_Integer2">
+ <attribute name="val">
+ <ref name="ST_Integer2"/>
+ </attribute>
+ </define>
+ <define name="ST_SpacingRule">
+ <data type="integer"/>
+ </define>
+ <define name="CT_SpacingRule">
+ <attribute name="val">
+ <ref name="ST_SpacingRule"/>
+ </attribute>
+ </define>
+ <define name="ST_UnSignedInteger">
+ <data type="unsignedInt"/>
+ </define>
+ <define name="CT_UnSignedInteger">
+ <attribute name="val">
+ <ref name="ST_UnSignedInteger"/>
+ </attribute>
+ </define>
+ <define name="ST_Char">
+ <data type="string"/>
+ </define>
+ <define name="CT_Char">
+ <attribute name="val">
+ <ref name="ST_Char"/>
+ </attribute>
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <!-- On -->
+ <value>on</value>
+ <!-- Off -->
+ <value>off</value>
+ </choice>
+ </define>
+ <define name="CT_OnOff">
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_String">
+ <data type="string"/>
+ </define>
+ <define name="CT_String">
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="ST_XAlign">
+ <choice>
+ <!-- Left Justification -->
+ <value>left</value>
+ <!-- Center -->
+ <value>center</value>
+ <!-- Right -->
+ <value>right</value>
+ </choice>
+ </define>
+ <define name="CT_XAlign">
+ <attribute name="val">
+ <ref name="ST_XAlign"/>
+ </attribute>
+ </define>
+ <define name="ST_YAlign">
+ <choice>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Center (Function) -->
+ <value>center</value>
+ <!-- Bottom Alignment -->
+ <value>bot</value>
+ </choice>
+ </define>
+ <define name="CT_YAlign">
+ <attribute name="val">
+ <ref name="ST_YAlign"/>
+ </attribute>
+ </define>
+ <define name="ST_Shp">
+ <choice>
+ <!-- Centered (Delimiters) -->
+ <value>centered</value>
+ <!-- Match -->
+ <value>match</value>
+ </choice>
+ </define>
+ <define name="CT_Shp">
+ <attribute name="val">
+ <ref name="ST_Shp"/>
+ </attribute>
+ </define>
+ <define name="ST_FType">
+ <choice>
+ <!-- Bar Fraction -->
+ <value>bar</value>
+ <!-- Skewed -->
+ <value>skw</value>
+ <!-- Linear Fraction -->
+ <value>lin</value>
+ <!-- No-Bar Fraction (Stack) -->
+ <value>noBar</value>
+ </choice>
+ </define>
+ <define name="CT_FType">
+ <attribute name="val">
+ <ref name="ST_FType"/>
+ </attribute>
+ </define>
+ <define name="ST_LimLoc">
+ <choice>
+ <!-- Under-Over location -->
+ <value>undOvr</value>
+ <!-- Subscript-Superscript location -->
+ <value>subSup</value>
+ </choice>
+ </define>
+ <define name="CT_LimLoc">
+ <attribute name="val">
+ <ref name="ST_LimLoc"/>
+ </attribute>
+ </define>
+ <define name="ST_TopBot">
+ <choice>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Bottom Alignment -->
+ <value>bot</value>
+ </choice>
+ </define>
+ <define name="CT_TopBot">
+ <attribute name="val">
+ <ref name="ST_TopBot"/>
+ </attribute>
+ </define>
+ <define name="ST_Script">
+ <choice>
+ <!-- Roman -->
+ <value>roman</value>
+ <!-- Script -->
+ <value>script</value>
+ <!-- Fraktur -->
+ <value>fraktur</value>
+ <!-- double-struck -->
+ <value>double-struck</value>
+ <!-- Sans-Serif -->
+ <value>sans-serif</value>
+ <!-- Monospace -->
+ <value>monospace</value>
+ </choice>
+ </define>
+ <define name="CT_Script">
+ <attribute name="val">
+ <ref name="ST_Script"/>
+ </attribute>
+ </define>
+ <define name="ST_Style">
+ <choice>
+ <!-- Plain -->
+ <value>p</value>
+ <!-- Bold -->
+ <value>b</value>
+ <!-- Italic -->
+ <value>i</value>
+ <!-- Bold-Italic -->
+ <value>bi</value>
+ </choice>
+ </define>
+ <define name="CT_Style">
+ <attribute name="val">
+ <ref name="ST_Style"/>
+ </attribute>
+ </define>
+ <define name="CT_ManualBreak">
+ <attribute name="alnAt">
+ <ref name="ST_Integer255"/>
+ </attribute>
+ </define>
+ <define name="EG_ScriptStyle">
+ <element name="scr">
+ <ref name="CT_Script"/>
+ </element>
+ <element name="sty">
+ <ref name="CT_Style"/>
+ </element>
+ </define>
+ <define name="CT_RPR">
+ <element name="lit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <choice>
+ <element name="nor">
+ <ref name="CT_OnOff"/>
+ </element>
+ <ref name="EG_ScriptStyle"/>
+ </choice>
+ <element name="brk">
+ <ref name="CT_ManualBreak"/>
+ </element>
+ <element name="aln">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_Text">
+ <ref name="ST_String"/>
+ <attribute name="xml:space">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_R">
+ <element name="rPr">
+ <ref name="CT_RPR"/>
+ </element>
+ <ref name="EG_RPr"/>
+ <choice>
+ <ref name="EG_RunInnerContent"/>
+ <element name="t">
+ <ref name="CT_Text"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_CtrlPr">
+ <ref name="EG_RPrMath"/>
+ </define>
+ <define name="CT_AccPr">
+ <element name="chr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Acc">
+ <element name="accPr">
+ <ref name="CT_AccPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_BarPr">
+ <element name="pos">
+ <ref name="CT_TopBot"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Bar">
+ <element name="barPr">
+ <ref name="CT_BarPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_BoxPr">
+ <element name="opEmu">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noBreak">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="diff">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="brk">
+ <ref name="CT_ManualBreak"/>
+ </element>
+ <element name="aln">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Box">
+ <element name="boxPr">
+ <ref name="CT_BoxPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_BorderBoxPr">
+ <element name="hideTop">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideBot">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideLeft">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideRight">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeH">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeV">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeBLTR">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeTLBR">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_BorderBox">
+ <element name="borderBoxPr">
+ <ref name="CT_BorderBoxPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_DPr">
+ <element name="begChr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="sepChr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="endChr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="grow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="shp">
+ <ref name="CT_Shp"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_D">
+ <element name="dPr">
+ <ref name="CT_DPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_EqArrPr">
+ <element name="baseJc">
+ <ref name="CT_YAlign"/>
+ </element>
+ <element name="maxDist">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="objDist">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rSpRule">
+ <ref name="CT_SpacingRule"/>
+ </element>
+ <element name="rSp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_EqArr">
+ <element name="eqArrPr">
+ <ref name="CT_EqArrPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_FPr">
+ <element name="type">
+ <ref name="CT_FType"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_F">
+ <element name="fPr">
+ <ref name="CT_FPr"/>
+ </element>
+ <element name="num">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="den">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_FuncPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Func">
+ <element name="funcPr">
+ <ref name="CT_FuncPr"/>
+ </element>
+ <element name="fName">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_GroupChrPr">
+ <element name="chr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="pos">
+ <ref name="CT_TopBot"/>
+ </element>
+ <element name="vertJc">
+ <ref name="CT_TopBot"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_GroupChr">
+ <element name="groupChrPr">
+ <ref name="CT_GroupChrPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_LimLowPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_LimLow">
+ <element name="limLowPr">
+ <ref name="CT_LimLowPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="lim">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_LimUppPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_LimUpp">
+ <element name="limUppPr">
+ <ref name="CT_LimUppPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="lim">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_MCPr">
+ <element name="count">
+ <ref name="CT_Integer255"/>
+ </element>
+ <element name="mcJc">
+ <ref name="CT_XAlign"/>
+ </element>
+ </define>
+ <define name="CT_MC">
+ <element name="mcPr">
+ <ref name="CT_MCPr"/>
+ </element>
+ </define>
+ <define name="CT_MCS">
+ <element name="mc">
+ <ref name="CT_MC"/>
+ </element>
+ </define>
+ <define name="CT_MPr">
+ <element name="baseJc">
+ <ref name="CT_YAlign"/>
+ </element>
+ <element name="plcHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rSpRule">
+ <ref name="CT_SpacingRule"/>
+ </element>
+ <element name="cGpRule">
+ <ref name="CT_SpacingRule"/>
+ </element>
+ <element name="rSp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="cSp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="cGp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="mcs">
+ <ref name="CT_MCS"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_MR">
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_M">
+ <element name="mPr">
+ <ref name="CT_MPr"/>
+ </element>
+ <element name="mr">
+ <ref name="CT_MR"/>
+ </element>
+ </define>
+ <define name="CT_NaryPr">
+ <element name="chr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="limLoc">
+ <ref name="CT_LimLoc"/>
+ </element>
+ <element name="grow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="subHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="supHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Nary">
+ <element name="naryPr">
+ <ref name="CT_NaryPr"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_PhantPr">
+ <element name="show">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="zeroWid">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="zeroAsc">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="zeroDesc">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="transp">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Phant">
+ <element name="phantPr">
+ <ref name="CT_PhantPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_RadPr">
+ <element name="degHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Rad">
+ <element name="radPr">
+ <ref name="CT_RadPr"/>
+ </element>
+ <element name="deg">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SPrePr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SPre">
+ <element name="sPrePr">
+ <ref name="CT_SPrePr"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SSubPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SSub">
+ <element name="sSubPr">
+ <ref name="CT_SSubPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SSubSupPr">
+ <element name="alnScr">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SSubSup">
+ <element name="sSubSupPr">
+ <ref name="CT_SSubSupPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SSupPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SSup">
+ <element name="sSupPr">
+ <ref name="CT_SSupPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="EG_OMathMathElements">
+ <choice>
+ <element name="acc">
+ <ref name="CT_Acc"/>
+ </element>
+ <element name="bar">
+ <ref name="CT_Bar"/>
+ </element>
+ <element name="box">
+ <ref name="CT_Box"/>
+ </element>
+ <element name="borderBox">
+ <ref name="CT_BorderBox"/>
+ </element>
+ <element name="d">
+ <ref name="CT_D"/>
+ </element>
+ <element name="eqArr">
+ <ref name="CT_EqArr"/>
+ </element>
+ <element name="f">
+ <ref name="CT_F"/>
+ </element>
+ <element name="func">
+ <ref name="CT_Func"/>
+ </element>
+ <element name="groupChr">
+ <ref name="CT_GroupChr"/>
+ </element>
+ <element name="limLow">
+ <ref name="CT_LimLow"/>
+ </element>
+ <element name="limUpp">
+ <ref name="CT_LimUpp"/>
+ </element>
+ <element name="m">
+ <ref name="CT_M"/>
+ </element>
+ <element name="nary">
+ <ref name="CT_Nary"/>
+ </element>
+ <element name="phant">
+ <ref name="CT_Phant"/>
+ </element>
+ <element name="rad">
+ <ref name="CT_Rad"/>
+ </element>
+ <element name="sPre">
+ <ref name="CT_SPre"/>
+ </element>
+ <element name="sSub">
+ <ref name="CT_SSub"/>
+ </element>
+ <element name="sSubSup">
+ <ref name="CT_SSubSup"/>
+ </element>
+ <element name="sSup">
+ <ref name="CT_SSup"/>
+ </element>
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_OMathElements">
+ <choice>
+ <ref name="EG_OMathMathElements"/>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_OMathArgPr">
+ <element name="argSz">
+ <ref name="CT_Integer2"/>
+ </element>
+ </define>
+ <define name="CT_OMathArg">
+ <element name="argPr">
+ <ref name="CT_OMathArgPr"/>
+ </element>
+ <ref name="EG_OMathElements"/>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="ST_Jc">
+ <choice>
+ <!-- Align To Leading Edge -->
+ <value>start</value>
+ <!-- Align To Trailing Edge -->
+ <value>end</value>
+ <!-- Left Justification (ecma) -->
+ <value>left</value>
+ <!-- Right (ecma) -->
+ <value>right</value>
+ <!-- Center (Equation) -->
+ <value>center</value>
+ <!-- Centered as Group (Equations) -->
+ <value>centerGroup</value>
+ </choice>
+ </define>
+ <define name="CT_OMathJc">
+ <attribute name="val">
+ <ref name="ST_Jc"/>
+ </attribute>
+ </define>
+ <define name="CT_OMathParaPr">
+ <element name="jc">
+ <ref name="CT_OMathJc"/>
+ </element>
+ </define>
+ <define name="ST_TwipsMeasure">
+ <data type="unsignedInt"/>
+ </define>
+ <define name="CT_TwipsMeasure">
+ <attribute name="val">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_BreakBin">
+ <choice>
+ <!-- Before -->
+ <value>before</value>
+ <!-- After -->
+ <value>after</value>
+ <!-- Repeat -->
+ <value>repeat</value>
+ </choice>
+ </define>
+ <define name="CT_BreakBin">
+ <attribute name="val">
+ <ref name="ST_BreakBin"/>
+ </attribute>
+ </define>
+ <define name="ST_BreakBinSub">
+ <choice>
+ <!-- Minus Minus -->
+ <value>--</value>
+ <!-- Minus Plus -->
+ <value>-+</value>
+ <!-- Plus Minus -->
+ <value>+-</value>
+ </choice>
+ </define>
+ <define name="CT_BreakBinSub">
+ <attribute name="val">
+ <ref name="ST_BreakBinSub"/>
+ </attribute>
+ </define>
+ <define name="CT_MathPr">
+ <element name="mathFont">
+ <ref name="CT_String"/>
+ </element>
+ <element name="brkBin">
+ <ref name="CT_BreakBin"/>
+ </element>
+ <element name="brkBinSub">
+ <ref name="CT_BreakBinSub"/>
+ </element>
+ <element name="smallFrac">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dispDef">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="lMargin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="rMargin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="defJc">
+ <ref name="CT_OMathJc"/>
+ </element>
+ <element name="preSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="postSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="interSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="intraSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <choice>
+ <element name="wrapIndent">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="wrapRight">
+ <ref name="CT_OnOff"/>
+ </element>
+ </choice>
+ <element name="intLim">
+ <ref name="CT_LimLoc"/>
+ </element>
+ <element name="naryLim">
+ <ref name="CT_LimLoc"/>
+ </element>
+ </define>
+ <define name="mathPr">
+ <element name="mathPr">
+ <ref name="CT_MathPr"/>
+ </element>
+ </define>
+ <define name="CT_OMathPara">
+ <element name="oMathParaPr">
+ <ref name="CT_OMathParaPr"/>
+ </element>
+ <element name="oMath">
+ <ref name="CT_OMath"/>
+ </element>
+ </define>
+ <define name="CT_OMath">
+ <ref name="EG_OMathElements"/>
+ </define>
+ <define name="oMathPara">
+ <element name="oMathPara">
+ <ref name="CT_OMathPara"/>
+ </element>
+ </define>
+ <define name="oMath">
+ <element name="oMath">
+ <ref name="CT_OMath"/>
+ </element>
+ </define>
+ <define name="oMathParaPr">
+ <element name="oMathParaPr">
+ <ref name="CT_OMathParaPr"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_Integer255" resource="Integer"/>
+ <resource name="CT_Integer255" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Integer255_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_Integer2" resource="Integer"/>
+ <resource name="CT_Integer2" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Integer2_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_SpacingRule" resource="Integer"/>
+ <resource name="CT_SpacingRule" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SpacingRule_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_UnSignedInteger" resource="Integer"/>
+ <resource name="CT_UnSignedInteger" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_UnSignedInteger_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_Char" resource="String"/>
+ <resource name="CT_Char" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Char_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_OnOff" resource="List">
+ <value tokenid="ooxml:Value_math_ST_OnOff_on">on</value>
+ <value tokenid="ooxml:Value_math_ST_OnOff_off">off</value>
+ </resource>
+ <resource name="CT_OnOff" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OnOff_val" action="setValue"/>
+ <action name="start" action="setDefaultBooleanValue"/>
+ </resource>
+ <resource name="ST_String" resource="String"/>
+ <resource name="CT_String" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_String_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_XAlign" resource="List">
+ <value tokenid="ooxml:Value_math_ST_XAlign_left">left</value>
+ <value tokenid="ooxml:Value_math_ST_XAlign_center">center</value>
+ <value tokenid="ooxml:Value_math_ST_XAlign_right">right</value>
+ </resource>
+ <resource name="CT_XAlign" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_XAlign_val" action="setValue"/>
+ </resource>
+ <resource name="ST_YAlign" resource="List">
+ <value tokenid="ooxml:Value_math_ST_YAlign_top">top</value>
+ <value tokenid="ooxml:Value_math_ST_YAlign_center">center</value>
+ <value tokenid="ooxml:Value_math_ST_YAlign_bot">bot</value>
+ </resource>
+ <resource name="CT_YAlign" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_YAlign_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Shp" resource="List">
+ <value tokenid="ooxml:Value_math_ST_Shp_centered">centered</value>
+ <value tokenid="ooxml:Value_math_ST_Shp_match">match</value>
+ </resource>
+ <resource name="CT_Shp" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Shp_val" action="setValue"/>
+ </resource>
+ <resource name="ST_FType" resource="List">
+ <value tokenid="ooxml:Value_math_ST_FType_bar">bar</value>
+ <value tokenid="ooxml:Value_math_ST_FType_skw">skw</value>
+ <value tokenid="ooxml:Value_math_ST_FType_lin">lin</value>
+ <value tokenid="ooxml:Value_math_ST_FType_noBar">noBar</value>
+ </resource>
+ <resource name="CT_FType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FType_val" action="setValue"/>
+ </resource>
+ <resource name="ST_LimLoc" resource="List">
+ <value tokenid="ooxml:Value_math_ST_LimLoc_undOvr">undOvr</value>
+ <value tokenid="ooxml:Value_math_ST_LimLoc_subSup">subSup</value>
+ </resource>
+ <resource name="CT_LimLoc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_LimLoc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_TopBot" resource="List">
+ <value tokenid="ooxml:Value_math_ST_TopBot_top">top</value>
+ <value tokenid="ooxml:Value_math_ST_TopBot_bot">bot</value>
+ </resource>
+ <resource name="CT_TopBot" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TopBot_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Script" resource="List">
+ <value tokenid="ooxml:Value_math_ST_Script_roman">roman</value>
+ <value tokenid="ooxml:Value_math_ST_Script_script">script</value>
+ <value tokenid="ooxml:Value_math_ST_Script_fraktur">fraktur</value>
+ <value tokenid="ooxml:Value_math_ST_Script_doublemstruck">double-struck</value>
+ <value tokenid="ooxml:Value_math_ST_Script_sansmserif">sans-serif</value>
+ <value tokenid="ooxml:Value_math_ST_Script_monospace">monospace</value>
+ </resource>
+ <resource name="CT_Script" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Script_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Style" resource="List">
+ <value tokenid="ooxml:Value_ST_Style_b">b</value>
+ <value tokenid="ooxml:Value_ST_Style_bi">bi</value>
+ <value tokenid="ooxml:Value_ST_Style_i">i</value>
+ <value tokenid="ooxml:Value_ST_Style_p">p</value>
+ </resource>
+ <resource name="CT_Style" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Style_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Jc" resource="String">
+ <value tokenid="ooxml:Value_math_ST_Jc_start">left</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_end">right</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_left">left</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_right">right</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_center">center</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_centerGroup">centerGroup</value>
+ </resource>
+ <resource name="CT_OMathJc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OMathJc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_TwipsMeasure" resource="TwipsMeasure_asSigned"/>
+ <resource name="CT_TwipsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TwipsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_BreakBin" resource="List">
+ <value tokenid="ooxml:Value_math_ST_BreakBin_before">before</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBin_after">after</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBin_repeat">repeat</value>
+ </resource>
+ <resource name="CT_BreakBin" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_BreakBin_val" action="setValue"/>
+ </resource>
+ <resource name="ST_BreakBinSub" resource="List">
+ <value tokenid="ooxml:Value_math_ST_BreakBinSub_mm">--</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBinSub_mp">-+</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBinSub_pm">+-</value>
+ </resource>
+ <resource name="CT_BreakBinSub" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_BreakBinSub_val" action="setValue"/>
+ </resource>
+ </namespace>
+ <namespace name="shared-relationshipReference">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
+ <!-- ISO RELAX NG Schema -->
+ <define name="id">
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="embed">
+ <attribute name="embed">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="link">
+ <attribute name="link"/>
+ </define>
+ <define name="dm">
+ <attribute name="dm"/>
+ </define>
+ <define name="lo">
+ <attribute name="lo"/>
+ </define>
+ <define name="qs">
+ <attribute name="qs"/>
+ </define>
+ <define name="cs">
+ <attribute name="cs"/>
+ </define>
+ <define name="blip">
+ <attribute name="blip"/>
+ </define>
+ <define name="pict">
+ <attribute name="pict"/>
+ </define>
+ <define name="href">
+ <attribute name="href">
+ <data type="string"/>
+ </attribute>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="dml-chartDrawing">
+ <start name="pic"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/picture">
+ <include href="dml-shapeProperties"/>
+ <include href="dml-documentProperties"/>
+ <!-- start = pic -->
+ <define name="CT_PictureNonVisual">
+ <element name="cNvPr">
+ <ref name="CT_NonVisualDrawingProps"/>
+ </element>
+ <element name="cNvPicPr">
+ <ref name="CT_NonVisualPictureProperties"/>
+ </element>
+ </define>
+ <define name="CT_Picture">
+ <element name="nvPicPr">
+ <ref name="CT_PictureNonVisual"/>
+ </element>
+ <element name="blipFill">
+ <ref name="CT_BlipFillProperties"/>
+ </element>
+ <element name="spPr">
+ <ref name="CT_ShapeProperties"/>
+ </element>
+ </define>
+ <define name="pic">
+ <element name="pic">
+ <ref name="CT_Picture"/>
+ </element>
+ </define>
+ <define name="CT_RelIds">
+ <attribute name="r:dm">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:lo">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:qs">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:cs">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="relIds">
+ <element name="dgm:relIds">
+ <ref name="CT_RelIds"/>
+ </element>
+ </define>
+ <define name="CT_GvmlGroupShape">
+ <element name="nvGrpSpPr">
+ <ref name="CT_NonVisualGroupDrawingShapeProps"/>
+ </element>
+ <element name="grpSpPr">
+ <ref name="CT_GroupShapeProperties"/>
+ </element>
+ </define>
+ <define name="lockedCanvas">
+ <element name="lc:lockedCanvas">
+ <ref name="CT_GvmlGroupShape"/>
+ </element>
+ </define>
+ <define name="CT_Chart">
+ <attribute name="r:id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="chart">
+ <element name="c:chart">
+ <ref name="CT_Chart"/>
+ </element>
+ </define>
+ <define name="CT_WordprocessingShape">
+ <element name="cNvSpPr">
+ <ref name="CT_NonVisualDrawingShapeProps"/>
+ </element>
+ <element name="spPr">
+ <ref name="CT_ShapeProperties"/>
+ </element>
+ </define>
+ <define name="wsp">
+ <element name="wps:wsp">
+ <ref name="CT_WordprocessingShape"/>
+ </element>
+ </define>
+ <define name="CT_WordprocessingGroup">
+ <element name="cNvGrpSpPr">
+ <ref name="CT_NonVisualGroupDrawingShapeProps"/>
+ </element>
+ <element name="grpSpPr">
+ <ref name="CT_WordprocessingGroup"/>
+ </element>
+ </define>
+ <define name="wgp">
+ <element name="wpg:wgp">
+ <ref name="CT_WordprocessingGroup"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="CT_PictureNonVisual" resource="Properties">
+ <element name="cNvPr" tokenid="ooxml:CT_PictureNonVisual_cNvPr"/>
+ <element name="cNvPicPr" tokenid="ooxml:CT_PictureNonVisual_cNvPicPr"/>
+ </resource>
+ <resource name="CT_Picture" resource="Shape">
+ <element name="nvPicPr" tokenid="ooxml:CT_Picture_nvPicPr"/>
+ <element name="blipFill" tokenid="ooxml:CT_Picture_blipFill"/>
+ <element name="spPr" tokenid="ooxml:CT_Picture_spPr"/>
+ </resource>
+ <resource name="pic" resource="Properties">
+ <element name="pic" tokenid="ooxml:pic_pic"/>
+ </resource>
+ <resource name="CT_RelIds" resource="Shape">
+ <attribute name="r:dm" tokenid="ooxml:CT_RelIds_dm"/>
+ <attribute name="r:lo" tokenid="ooxml:CT_RelIds_lo"/>
+ <attribute name="r:qs" tokenid="ooxml:CT_RelIds_qs"/>
+ <attribute name="r:cs" tokenid="ooxml:CT_RelIds_cs"/>
+ </resource>
+ <resource name="relIds" resource="Shape">
+ <element name="dgm:relIds" tokenid="ooxml:dgm_relIds"/>
+ </resource>
+ <resource name="CT_GvmlGroupShape" resource="Shape">
+ <element name="a:nvGrpSpPr" tokenid="ooxml:CT_GvmlGroupShape_nvGrpSpPr"/>
+ <element name="a:grpSpPr" tokenid="ooxml:CT_GvmlGroupShape_grpSpPr"/>
+ </resource>
+ <resource name="lockedCanvas" resource="Shape">
+ <element name="lc:lockedCanvas" tokenid="ooxml:lc_lockedCanvas"/>
+ </resource>
+ <resource name="CT_Chart" resource="Shape">
+ <attribute name="r:id" tokenid="ooxml:CT_RelId_chart"/>
+ </resource>
+ <resource name="chart" resource="Shape">
+ <element name="c:chart" tokenid="ooxml:c_chart"/>
+ </resource>
+ <resource name="CT_WordprocessingShape" resource="Shape">
+ <element name="wps:cNvSpPr" tokenid="ooxml:CT_WordprocessingShape_cNvSpPr"/>
+ <element name="wps:spPr" tokenid="ooxml:CT_WordprocessingShape_spPr"/>
+ </resource>
+ <resource name="wsp" resource="Shape">
+ <element name="wps:wsp" tokenid="ooxml:wps_wsp"/>
+ </resource>
+ <resource name="CT_WordprocessingGroup" resource="Shape">
+ <element name="wpg:cNvGrpSpPr" tokenid="ooxml:CT_WordprocessingGroup_cNvGrpSpPr"/>
+ <element name="wpg:grpSpPr" tokenid="ooxml:CT_WordprocessingGroup_grpSpPr"/>
+ </resource>
+ <resource name="wgp" resource="Shape">
+ <element name="wpg:wgp" tokenid="ooxml:wpg_wgp"/>
+ </resource>
+
+ </namespace>
+ <namespace name="vml-main">
+ <start name="shape"/>
+ <start name="shapetype"/>
+ <start name="group"/>
+ <start name="background"/>
+ <start name="fill"/>
+ <start name="formulas"/>
+ <start name="handles"/>
+ <start name="imagedata"/>
+ <start name="path"/>
+ <start name="textbox"/>
+ <start name="shadow"/>
+ <start name="stroke"/>
+ <start name="textpath"/>
+ <start name="arc"/>
+ <start name="curve"/>
+ <start name="image"/>
+ <start name="line"/>
+ <start name="oval"/>
+ <start name="polyline"/>
+ <start name="rect"/>
+ <start name="roundrect"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="urn:schemas-microsoft-com:vml">
+ <include href="vml-officeDrawing"/>
+ <include href="vml-wordprocessingDrawing"/>
+ <!-- start = shape | shapetype | group | background | fill | formulas | handles | imagedata | path | textbox | shadow | stroke | textpath | arc | curve | image | line | oval | polyline | rect | roundrect -->
+ <define name="AG_Id">
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Style">
+ <attribute name="style">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Type">
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Adj">
+ <attribute name="adj">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Path">
+ <attribute name="path">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Fill">
+ <attribute name="filled">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fillcolor">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Chromakey">
+ <attribute name="chromakey">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_Ext">
+ <attribute name="ext">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_CoreAttributes">
+ <ref name="AG_Id"/>
+ <ref name="AG_Style"/>
+ <attribute name="href">
+ <data type="string"/>
+ </attribute>
+ <attribute name="target">
+ <data type="string"/>
+ </attribute>
+ <attribute name="class">
+ <data type="string"/>
+ </attribute>
+ <attribute name="title">
+ <data type="string"/>
+ </attribute>
+ <attribute name="alt">
+ <data type="string"/>
+ </attribute>
+ <attribute name="coordsize">
+ <data type="string"/>
+ </attribute>
+ <attribute name="coordorigin">
+ <data type="string"/>
+ </attribute>
+ <attribute name="wrapcoords">
+ <data type="string"/>
+ </attribute>
+ <attribute name="print">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_ShapeAttributes">
+ <ref name="AG_Chromakey"/>
+ <ref name="AG_Fill"/>
+ <attribute name="opacity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="stroked">
+ <data type="string"/>
+ </attribute>
+ <attribute name="strokecolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="strokeweight">
+ <data type="string"/>
+ </attribute>
+ <attribute name="insetpen">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_OfficeCoreAttributes">
+ <attribute name="o:spid"/>
+ <attribute name="o:oned"/>
+ <attribute name="o:regroupid"/>
+ <attribute name="o:doubleclicknotify"/>
+ <attribute name="o:button"/>
+ <attribute name="o:userhidden"/>
+ <attribute name="o:bullet"/>
+ <attribute name="o:hr"/>
+ <attribute name="o:hrstd"/>
+ <attribute name="o:hrnoshade"/>
+ <attribute name="o:hrpct"/>
+ <attribute name="o:hralign"/>
+ <attribute name="o:allowincell"/>
+ <attribute name="o:allowoverlap"/>
+ <attribute name="o:userdrawn"/>
+ <attribute name="o:bordertopcolor"/>
+ <attribute name="o:borderleftcolor"/>
+ <attribute name="o:borderbottomcolor"/>
+ <attribute name="o:borderrightcolor"/>
+ <attribute name="o:dgmlayout"/>
+ <attribute name="o:dgmnodekind"/>
+ <attribute name="o:dgmlayoutmru"/>
+ <attribute name="o:insetmode"/>
+ </define>
+ <define name="AG_OfficeShapeAttributes">
+ <attribute name="o:spt"/>
+ <attribute name="o:connectortype"/>
+ <attribute name="o:bwmode"/>
+ <attribute name="o:bwpure"/>
+ <attribute name="o:bwnormal"/>
+ <attribute name="o:forcedash"/>
+ <attribute name="o:oleicon"/>
+ <attribute name="o:ole"/>
+ <attribute name="o:preferrelative"/>
+ <attribute name="o:cliptowrap"/>
+ <attribute name="o:clip"/>
+ </define>
+ <define name="AG_AllCoreAttributes">
+ <ref name="AG_CoreAttributes"/>
+ <ref name="AG_OfficeCoreAttributes"/>
+ </define>
+ <define name="AG_AllShapeAttributes">
+ <ref name="AG_ShapeAttributes"/>
+ <ref name="AG_OfficeShapeAttributes"/>
+ </define>
+ <define name="AG_ImageAttributes">
+ <attribute name="src">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cropleft">
+ <data type="string"/>
+ </attribute>
+ <attribute name="croptop">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cropright">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cropbottom">
+ <data type="string"/>
+ </attribute>
+ <attribute name="gain">
+ <data type="string"/>
+ </attribute>
+ <attribute name="blacklevel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="gamma">
+ <data type="string"/>
+ </attribute>
+ <attribute name="grayscale">
+ <data type="string"/>
+ </attribute>
+ <attribute name="bilevel">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="AG_StrokeAttributes">
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="weight">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color">
+ <data type="string"/>
+ </attribute>
+ <attribute name="opacity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="linestyle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="miterlimit">
+ <data type="decimal"/>
+ </attribute>
+ <attribute name="joinstyle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="endcap">
+ <data type="string"/>
+ </attribute>
+ <attribute name="dashstyle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="filltype">
+ <data type="string"/>
+ </attribute>
+ <attribute name="src">
+ <data type="string"/>
+ </attribute>
+ <attribute name="imageaspect">
+ <data type="string"/>
+ </attribute>
+ <attribute name="imagesize">
+ <data type="string"/>
+ </attribute>
+ <attribute name="imagealignshape">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="startarrow">
+ <data type="string"/>
+ </attribute>
+ <attribute name="startarrowwidth">
+ <data type="string"/>
+ </attribute>
+ <attribute name="startarrowlength">
+ <data type="string"/>
+ </attribute>
+ <attribute name="endarrow">
+ <data type="string"/>
+ </attribute>
+ <attribute name="endarrowwidth">
+ <data type="string"/>
+ </attribute>
+ <attribute name="endarrowlength">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:href"/>
+ <attribute name="o:althref"/>
+ <attribute name="o:title"/>
+ <attribute name="o:forcedash"/>
+ <attribute name="r:id"/>
+ <attribute name="insetpen">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:relid"/>
+ </define>
+ <define name="EG_ShapeElements">
+ <choice>
+ <ref name="path"/>
+ <ref name="formulas"/>
+ <ref name="handles"/>
+ <ref name="fill"/>
+ <ref name="stroke"/>
+ <ref name="shadow"/>
+ <ref name="textbox"/>
+ <ref name="textpath"/>
+ <ref name="imagedata"/>
+ <element name="o:skew">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:extrusion">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:callout">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:lock">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:clippath">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:signatureline">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wvml:wrap">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wvml:anchorlock">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wvml:bordertop">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wvml:borderbottom">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wvml:borderleft">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wvml:borderright">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="x:ClientData">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="p:textdata">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </choice>
+ </define>
+ <define name="shape">
+ <element name="shape">
+ <ref name="CT_Shape"/>
+ </element>
+ </define>
+ <define name="shapetype">
+ <element name="shapetype">
+ <ref name="CT_Shapetype"/>
+ </element>
+ </define>
+ <define name="group">
+ <element name="group">
+ <ref name="CT_Group"/>
+ </element>
+ </define>
+ <define name="background">
+ <element name="background">
+ <ref name="CT_Background"/>
+ </element>
+ </define>
+ <define name="CT_Shape">
+ <choice>
+ <ref name="EG_ShapeElements"/>
+ <element name="o:ink">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="p:iscomment">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </choice>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <ref name="AG_Type"/>
+ <ref name="AG_Adj"/>
+ <ref name="AG_Path"/>
+ <attribute name="o:gfxdata"/>
+ <attribute name="equationxml">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Shapetype">
+ <ref name="EG_ShapeElements"/>
+ <element name="o:complex">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <ref name="AG_Adj"/>
+ <ref name="AG_Path"/>
+ <attribute name="o:master"/>
+ </define>
+ <define name="CT_Group">
+ <choice>
+ <ref name="EG_ShapeElements"/>
+ <ref name="group"/>
+ <ref name="shape"/>
+ <ref name="shapetype"/>
+ <ref name="arc"/>
+ <ref name="curve"/>
+ <ref name="image"/>
+ <ref name="line"/>
+ <ref name="oval"/>
+ <ref name="polyline"/>
+ <ref name="rect"/>
+ <ref name="roundrect"/>
+ <element name="o:diagram">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </choice>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_Fill"/>
+ <attribute name="editas">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:tableproperties"/>
+ <attribute name="o:tablelimits"/>
+ </define>
+ <define name="CT_Background">
+ <ref name="fill"/>
+ <ref name="AG_Id"/>
+ <ref name="AG_Fill"/>
+ <attribute name="o:bwmode"/>
+ <attribute name="o:bwpure"/>
+ <attribute name="o:bwnormal"/>
+ <attribute name="o:targetscreensize"/>
+ </define>
+ <define name="fill">
+ <element name="fill">
+ <ref name="CT_Fill"/>
+ </element>
+ </define>
+ <define name="formulas">
+ <element name="formulas">
+ <ref name="CT_Formulas"/>
+ </element>
+ </define>
+ <define name="handles">
+ <element name="handles">
+ <ref name="CT_Handles"/>
+ </element>
+ </define>
+ <define name="imagedata">
+ <element name="imagedata">
+ <ref name="CT_ImageData"/>
+ </element>
+ </define>
+ <define name="path">
+ <element name="path">
+ <ref name="CT_Path"/>
+ </element>
+ </define>
+ <define name="textbox">
+ <element name="textbox">
+ <ref name="CT_Textbox"/>
+ </element>
+ </define>
+ <define name="shadow">
+ <element name="shadow">
+ <ref name="CT_Shadow"/>
+ </element>
+ </define>
+ <define name="stroke">
+ <element name="stroke">
+ <ref name="CT_Stroke"/>
+ </element>
+ </define>
+ <define name="textpath">
+ <element name="textpath">
+ <ref name="CT_TextPath"/>
+ </element>
+ </define>
+ <define name="CT_Fill">
+ <element name="o:fill">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <ref name="AG_Id"/>
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color">
+ <data type="string"/>
+ </attribute>
+ <attribute name="opacity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="src">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:href"/>
+ <attribute name="o:althref"/>
+ <attribute name="size">
+ <data type="string"/>
+ </attribute>
+ <attribute name="origin">
+ <data type="string"/>
+ </attribute>
+ <attribute name="position">
+ <data type="string"/>
+ </attribute>
+ <attribute name="aspect">
+ <data type="string"/>
+ </attribute>
+ <attribute name="colors">
+ <data type="string"/>
+ </attribute>
+ <attribute name="angle">
+ <data type="decimal"/>
+ </attribute>
+ <attribute name="alignshape">
+ <data type="string"/>
+ </attribute>
+ <attribute name="focus">
+ <data type="string"/>
+ </attribute>
+ <attribute name="focussize">
+ <data type="string"/>
+ </attribute>
+ <attribute name="focusposition">
+ <data type="string"/>
+ </attribute>
+ <attribute name="method">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:detectmouseclick"/>
+ <attribute name="o:title"/>
+ <attribute name="o:opacity2"/>
+ <attribute name="recolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rotate">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:id"/>
+ <attribute name="o:relid"/>
+ </define>
+ <define name="CT_Formulas">
+ <element name="f">
+ <ref name="CT_F"/>
+ </element>
+ </define>
+ <define name="CT_F">
+ <attribute name="eqn">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Handles">
+ <element name="h">
+ <ref name="CT_H"/>
+ </element>
+ </define>
+ <define name="CT_H">
+ <attribute name="position">
+ <data type="string"/>
+ </attribute>
+ <attribute name="polar">
+ <data type="string"/>
+ </attribute>
+ <attribute name="map">
+ <data type="string"/>
+ </attribute>
+ <attribute name="invx">
+ <data type="string"/>
+ </attribute>
+ <attribute name="invy">
+ <data type="string"/>
+ </attribute>
+ <attribute name="switch">
+ <data type="string"/>
+ </attribute>
+ <attribute name="xrange">
+ <data type="string"/>
+ </attribute>
+ <attribute name="yrange">
+ <data type="string"/>
+ </attribute>
+ <attribute name="radiusrange">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_ImageData">
+ <ref name="AG_Id"/>
+ <ref name="AG_ImageAttributes"/>
+ <ref name="AG_Chromakey"/>
+ <attribute name="embosscolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="recolortarget">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:href"/>
+ <attribute name="o:althref"/>
+ <attribute name="o:title"/>
+ <attribute name="o:oleid"/>
+ <attribute name="o:detectmouseclick"/>
+ <attribute name="o:movie"/>
+ <attribute name="o:relid"/>
+ <attribute name="r:id"/>
+ <attribute name="r:pict"/>
+ <attribute name="r:href"/>
+ </define>
+ <define name="CT_Path">
+ <ref name="AG_Id"/>
+ <attribute name="v">
+ <data type="string"/>
+ </attribute>
+ <attribute name="limo">
+ <data type="string"/>
+ </attribute>
+ <attribute name="textboxrect">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fillok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="strokeok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="shadowok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="arrowok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="gradientshapeok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="textpathok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="insetpenok">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:connecttype"/>
+ <attribute name="o:connectlocs"/>
+ <attribute name="o:connectangles"/>
+ <attribute name="o:extrusionok"/>
+ </define>
+ <define name="CT_Shadow">
+ <ref name="AG_Id"/>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="obscured">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color">
+ <data type="string"/>
+ </attribute>
+ <attribute name="opacity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="offset">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="offset2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="origin">
+ <data type="string"/>
+ </attribute>
+ <attribute name="matrix">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Stroke">
+ <element name="o:left">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:top">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:right">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:bottom">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="o:column">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <ref name="AG_Id"/>
+ <ref name="AG_StrokeAttributes"/>
+ </define>
+ <define name="CT_Textbox">
+ <choice>
+ <element name="w:txbxContent">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </choice>
+ <ref name="AG_Id"/>
+ <ref name="AG_Style"/>
+ <attribute name="inset">
+ <data type="string"/>
+ </attribute>
+ <attribute name="o:singleclick"/>
+ <attribute name="o:insetmode"/>
+ </define>
+ <define name="CT_TextPath">
+ <ref name="AG_Id"/>
+ <ref name="AG_Style"/>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fitshape">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fitpath">
+ <data type="string"/>
+ </attribute>
+ <attribute name="trim">
+ <data type="string"/>
+ </attribute>
+ <attribute name="xscale">
+ <data type="string"/>
+ </attribute>
+ <attribute name="string">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="arc">
+ <element name="arc">
+ <ref name="CT_Arc"/>
+ </element>
+ </define>
+ <define name="curve">
+ <element name="curve">
+ <ref name="CT_Curve"/>
+ </element>
+ </define>
+ <define name="image">
+ <element name="image">
+ <ref name="CT_Image"/>
+ </element>
+ </define>
+ <define name="line">
+ <element name="line">
+ <ref name="CT_Line"/>
+ </element>
+ </define>
+ <define name="oval">
+ <element name="oval">
+ <ref name="CT_Oval"/>
+ </element>
+ </define>
+ <define name="polyline">
+ <element name="polyline">
+ <ref name="CT_PolyLine"/>
+ </element>
+ </define>
+ <define name="rect">
+ <element name="rect">
+ <ref name="CT_Rect"/>
+ </element>
+ </define>
+ <define name="roundrect">
+ <element name="roundrect">
+ <ref name="CT_RoundRect"/>
+ </element>
+ </define>
+ <define name="CT_Arc">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <attribute name="startAngle">
+ <data type="decimal"/>
+ </attribute>
+ <attribute name="endAngle">
+ <data type="decimal"/>
+ </attribute>
+ </define>
+ <define name="CT_Curve">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <attribute name="from">
+ <data type="string"/>
+ </attribute>
+ <attribute name="control1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="control2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="to">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Image">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <ref name="AG_ImageAttributes"/>
+ </define>
+ <define name="CT_Line">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <attribute name="from">
+ <data type="string"/>
+ </attribute>
+ <attribute name="to">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Oval">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ </define>
+ <define name="CT_PolyLine">
+ <choice>
+ <ref name="EG_ShapeElements"/>
+ <element name="o:ink">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </choice>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <attribute name="points">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Rect">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ </define>
+ <define name="CT_RoundRect">
+ <ref name="EG_ShapeElements"/>
+ <ref name="AG_AllCoreAttributes"/>
+ <ref name="AG_AllShapeAttributes"/>
+ <attribute name="arcsize">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_FillType">
+ <choice>
+ <!-- Solid Fill -->
+ <value>solid</value>
+ <!-- Linear Gradient -->
+ <value>gradient</value>
+ <!-- Radial Gradient -->
+ <value>gradientRadial</value>
+ <!-- Tiled Image -->
+ <value>tile</value>
+ <!-- Image Pattern -->
+ <value>pattern</value>
+ <!-- Stretch Image to Fit -->
+ <value>frame</value>
+ </choice>
+ </define>
+ <define name="ST_StrokeLineStyle">
+ <choice>
+ <!-- Single Line -->
+ <value>single</value>
+ <!-- Two Thin Lines -->
+ <value>thinThin</value>
+ <!-- Thin Line Outside Thick Line -->
+ <value>thinThick</value>
+ <!-- Thick Line Outside Thin Line -->
+ <value>thickThin</value>
+ <!-- Thick Line Between Thin Lines -->
+ <value>thickBetweenThin</value>
+ </choice>
+ </define>
+ <define name="ST_StrokeJoinStyle">
+ <choice>
+ <!-- Round Joint -->
+ <value>round</value>
+ <!-- Bevel Joint -->
+ <value>bevel</value>
+ <!-- Miter Joint -->
+ <value>miter</value>
+ </choice>
+ </define>
+ <define name="ST_StrokeEndCap">
+ <choice>
+ <!-- Flat End -->
+ <value>flat</value>
+ <!-- Square End -->
+ <value>square</value>
+ <!-- Round End -->
+ <value>round</value>
+ </choice>
+ </define>
+ <define name="ST_StrokeArrowLength">
+ <choice>
+ <!-- Short Arrowhead -->
+ <value>short</value>
+ <!-- Medium Arrowhead -->
+ <value>medium</value>
+ <!-- Long Arrowhead -->
+ <value>long</value>
+ </choice>
+ </define>
+ <define name="ST_StrokeArrowWidth">
+ <choice>
+ <!-- Narrow Arrowhead -->
+ <value>narrow</value>
+ <!-- Medium Arrowhead -->
+ <value>medium</value>
+ <!-- Wide Arrowhead -->
+ <value>wide</value>
+ </choice>
+ </define>
+ <define name="ST_StrokeArrowType">
+ <choice>
+ <!-- No Arrowhead -->
+ <value>none</value>
+ <!-- Block Arrowhead -->
+ <value>block</value>
+ <!-- Classic Arrowhead -->
+ <value>classic</value>
+ <!-- Oval Arrowhead -->
+ <value>oval</value>
+ <!-- Diamond Arrowhead -->
+ <value>diamond</value>
+ <!-- Open Arrowhead -->
+ <value>open</value>
+ </choice>
+ </define>
+ <define name="ST_ImageAspect">
+ <choice>
+ <!-- Ignore Aspect Ratio -->
+ <value>ignore</value>
+ <!-- At Most -->
+ <value>atMost</value>
+ <!-- At Least -->
+ <value>atLeast</value>
+ </choice>
+ </define>
+ <define name="ST_TrueFalseBlank">
+ <choice>
+ <!-- Logical True -->
+ <value>t</value>
+ <!-- Logical False -->
+ <value>f</value>
+ <!-- Logical True -->
+ <value>true</value>
+ <!-- Logical False -->
+ <value>false</value>
+ <!-- Blank - Logical False -->
+ <value/>
+ </choice>
+ </define>
+ <define name="BUILT_IN_ANY_TYPE">
+ <choice>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <data type="string"/>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="ST_FillType" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_FillType_solid">solid</value>
+ <value tokenid="ooxml:Value_vml_ST_FillType_gradient">gradient</value>
+ <value tokenid="ooxml:Value_vml_ST_FillType_gradientRadial">gradientRadial</value>
+ <value tokenid="ooxml:Value_vml_ST_FillType_tile">tile</value>
+ <value tokenid="ooxml:Value_vml_ST_FillType_pattern">pattern</value>
+ <value tokenid="ooxml:Value_vml_ST_FillType_frame">frame</value>
+ </resource>
+ <resource name="ST_StrokeLineStyle" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_StrokeLineStyle_single">single</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeLineStyle_thinThin">thinThin</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeLineStyle_thinThick">thinThick</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeLineStyle_thickThin">thickThin</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeLineStyle_thickBetweenThin">thickBetweenThin</value>
+ </resource>
+ <resource name="ST_StrokeJoinStyle" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_StrokeJoinStyle_round">round</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeJoinStyle_bevel">bevel</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeJoinStyle_miter">miter</value>
+ </resource>
+ <resource name="ST_StrokeEndCap" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_StrokeEndCap_flat">flat</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeEndCap_square">square</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeEndCap_round">round</value>
+ </resource>
+ <resource name="ST_StrokeArrowLength" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowLength_short">short</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowLength_medium">medium</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowLength_long">long</value>
+ </resource>
+ <resource name="ST_StrokeArrowWidth" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowWidth_narrow">narrow</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowWidth_medium">medium</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowWidth_wide">wide</value>
+ </resource>
+ <resource name="ST_StrokeArrowType" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowType_none">none</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowType_block">block</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowType_classic">classic</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowType_oval">oval</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowType_diamond">diamond</value>
+ <value tokenid="ooxml:Value_vml_ST_StrokeArrowType_open">open</value>
+ </resource>
+ <resource name="ST_ImageAspect" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_ImageAspect_ignore">ignore</value>
+ <value tokenid="ooxml:Value_vml_ST_ImageAspect_atMost">atMost</value>
+ <value tokenid="ooxml:Value_vml_ST_ImageAspect_atLeast">atLeast</value>
+ </resource>
+ <resource name="ST_TrueFalseBlank" resource="List">
+ <value tokenid="ooxml:Value_vml_ST_TrueFalseBlank_t">t</value>
+ <value tokenid="ooxml:Value_vml_ST_TrueFalseBlank_f">f</value>
+ <value tokenid="ooxml:Value_vml_ST_TrueFalseBlank_true">true</value>
+ <value tokenid="ooxml:Value_vml_ST_TrueFalseBlank_false">false</value>
+ <value tokenid="ooxml:Value_vml_ST_TrueFalseBlank_"/>
+ </resource>
+ <resource name="CT_Background" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_Background_id"/>
+ </resource>
+ <resource name="background" resource="Properties">
+ <element name="background" tokenid="ooxml:background_background"/>
+ </resource>
+ </namespace>
+ <namespace name="vml-officeDrawing">
+ <start name="shapedefaults"/>
+ <start name="shapelayout"/>
+ <start name="signatureline"/>
+ <start name="ink"/>
+ <start name="diagram"/>
+ <start name="skew"/>
+ <start name="extrusion"/>
+ <start name="callout"/>
+ <start name="lock"/>
+ <start name="OLEObject"/>
+ <start name="complex"/>
+ <start name="left"/>
+ <start name="top"/>
+ <start name="right"/>
+ <start name="bottom"/>
+ <start name="column"/>
+ <start name="clippath"/>
+ <start name="fill"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="urn:schemas-microsoft-com:office:office" >
+ <include href="vml-main"/>
+ <!-- External schema: http://schemas.openxmlformats.org/officeDocument/2006/relationships -->
+ <!-- start = shapedefaults | shapelayout | signatureline | ink | diagram | skew | extrusion | callout | lock | OLEObject | complex | left | top | right | bottom | column | clippath | fill -->
+ <define name="bwmode">
+ <attribute name="bwmode"/>
+ </define>
+ <define name="bwpure">
+ <attribute name="bwpure"/>
+ </define>
+ <define name="bwnormal">
+ <attribute name="bwnormal"/>
+ </define>
+ <define name="targetscreensize">
+ <attribute name="targetscreensize"/>
+ </define>
+ <define name="insetmode">
+ <attribute name="insetmode"/>
+ </define>
+ <define name="spt">
+ <attribute name="spt">
+ <data type="float"/>
+ </attribute>
+ </define>
+ <define name="wrapcoords">
+ <attribute name="wrapcoords">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="oned">
+ <attribute name="oned"/>
+ </define>
+ <define name="regroupid">
+ <attribute name="regroupid">
+ <data type="integer"/>
+ </attribute>
+ </define>
+ <define name="doubleclicknotify">
+ <attribute name="doubleclicknotify"/>
+ </define>
+ <define name="connectortype">
+ <attribute name="connectortype"/>
+ </define>
+ <define name="button">
+ <attribute name="button"/>
+ </define>
+ <define name="userhidden">
+ <attribute name="userhidden"/>
+ </define>
+ <define name="forcedash">
+ <attribute name="forcedash"/>
+ </define>
+ <define name="oleicon">
+ <attribute name="oleicon"/>
+ </define>
+ <define name="ole">
+ <attribute name="ole"/>
+ </define>
+ <define name="preferrelative">
+ <attribute name="preferrelative"/>
+ </define>
+ <define name="cliptowrap">
+ <attribute name="cliptowrap"/>
+ </define>
+ <define name="clip">
+ <attribute name="clip"/>
+ </define>
+ <define name="bullet">
+ <attribute name="bullet"/>
+ </define>
+ <define name="hr">
+ <attribute name="hr"/>
+ </define>
+ <define name="hrstd">
+ <attribute name="hrstd"/>
+ </define>
+ <define name="hrnoshade">
+ <attribute name="hrnoshade"/>
+ </define>
+ <define name="hrpct">
+ <attribute name="hrpct">
+ <data type="float"/>
+ </attribute>
+ </define>
+ <define name="hralign">
+ <attribute name="hralign"/>
+ </define>
+ <define name="allowincell">
+ <attribute name="allowincell"/>
+ </define>
+ <define name="allowoverlap">
+ <attribute name="allowoverlap"/>
+ </define>
+ <define name="userdrawn">
+ <attribute name="userdrawn"/>
+ </define>
+ <define name="bordertopcolor">
+ <attribute name="bordertopcolor">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="borderleftcolor">
+ <attribute name="borderleftcolor">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="borderbottomcolor">
+ <attribute name="borderbottomcolor">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="borderrightcolor">
+ <attribute name="borderrightcolor">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="connecttype">
+ <attribute name="connecttype"/>
+ </define>
+ <define name="connectlocs">
+ <attribute name="connectlocs">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="connectangles">
+ <attribute name="connectangles">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="master">
+ <attribute name="master">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="extrusionok">
+ <attribute name="extrusionok"/>
+ </define>
+ <define name="href">
+ <attribute name="href">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="althref">
+ <attribute name="althref">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="title">
+ <attribute name="title">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="singleclick">
+ <attribute name="singleclick"/>
+ </define>
+ <define name="oleid">
+ <attribute name="oleid">
+ <data type="float"/>
+ </attribute>
+ </define>
+ <define name="detectmouseclick">
+ <attribute name="detectmouseclick"/>
+ </define>
+ <define name="movie">
+ <attribute name="movie">
+ <data type="float"/>
+ </attribute>
+ </define>
+ <define name="spid">
+ <attribute name="spid">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="opacity2">
+ <attribute name="opacity2">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="relid">
+ <attribute name="relid"/>
+ </define>
+ <define name="dgmlayout">
+ <attribute name="dgmlayout">
+ <data type="integer"/>
+ </attribute>
+ </define>
+ <define name="dgmnodekind">
+ <attribute name="dgmnodekind">
+ <data type="integer"/>
+ </attribute>
+ </define>
+ <define name="dgmlayoutmru">
+ <attribute name="dgmlayoutmru">
+ <data type="integer"/>
+ </attribute>
+ </define>
+ <define name="gfxdata">
+ <attribute name="gfxdata">
+ <data type="base64Binary"/>
+ </attribute>
+ </define>
+ <define name="tableproperties">
+ <attribute name="tableproperties">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="tablelimits">
+ <attribute name="tablelimits">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="shapedefaults">
+ <element name="shapedefaults">
+ <ref name="CT_ShapeDefaults"/>
+ </element>
+ </define>
+ <define name="shapelayout">
+ <element name="shapelayout">
+ <ref name="CT_ShapeLayout"/>
+ </element>
+ </define>
+ <define name="signatureline">
+ <element name="signatureline">
+ <ref name="CT_SignatureLine"/>
+ </element>
+ </define>
+ <define name="ink">
+ <element name="ink">
+ <ref name="CT_Ink"/>
+ </element>
+ </define>
+ <define name="diagram">
+ <element name="diagram">
+ <ref name="CT_Diagram"/>
+ </element>
+ </define>
+ <define name="CT_ShapeDefaults">
+ <element name="v:fill">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="v:stroke">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="v:textbox">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="v:shadow">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <ref name="skew"/>
+ <ref name="extrusion"/>
+ <ref name="callout"/>
+ <ref name="lock"/>
+ <element name="colormru">
+ <ref name="CT_ColorMru"/>
+ </element>
+ <element name="colormenu">
+ <ref name="CT_ColorMenu"/>
+ </element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="spidmax">
+ <data type="integer"/>
+ </attribute>
+ <attribute name="style">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fill">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fillcolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="stroke">
+ <data type="string"/>
+ </attribute>
+ <attribute name="strokecolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="allowincell">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Ink">
+ <attribute name="i">
+ <data type="base64Binary"/>
+ </attribute>
+ <attribute name="annotation">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SignatureLine">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="issignatureline">
+ <data type="string"/>
+ </attribute>
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ <attribute name="provid">
+ <data type="string"/>
+ </attribute>
+ <attribute name="signinginstructionsset">
+ <data type="string"/>
+ </attribute>
+ <attribute name="allowcomments">
+ <data type="string"/>
+ </attribute>
+ <attribute name="showsigndate">
+ <data type="string"/>
+ </attribute>
+ <attribute name="suggestedsigner">
+ <data type="string"/>
+ </attribute>
+ <attribute name="suggestedsigner2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="suggestedsigneremail">
+ <data type="string"/>
+ </attribute>
+ <attribute name="signinginstructions">
+ <data type="string"/>
+ </attribute>
+ <attribute name="addlxml">
+ <data type="string"/>
+ </attribute>
+ <attribute name="sigprovurl">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_ShapeLayout">
+ <element name="idmap">
+ <ref name="CT_IdMap"/>
+ </element>
+ <element name="regrouptable">
+ <ref name="CT_RegroupTable"/>
+ </element>
+ <element name="rules">
+ <ref name="CT_Rules"/>
+ </element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </define>
+ <define name="CT_IdMap">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="data">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_RegroupTable">
+ <element name="entry">
+ <ref name="CT_Entry"/>
+ </element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </define>
+ <define name="CT_Entry">
+ <attribute name="new">
+ <data type="int"/>
+ </attribute>
+ <attribute name="old">
+ <data type="int"/>
+ </attribute>
+ </define>
+ <define name="CT_Rules">
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </define>
+ <define name="CT_R">
+ <element name="proxy">
+ <ref name="CT_Proxy"/>
+ </element>
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="how">
+ <data type="string"/>
+ </attribute>
+ <attribute name="idref">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Proxy">
+ <attribute name="start">
+ <data type="string"/>
+ </attribute>
+ <attribute name="end">
+ <data type="string"/>
+ </attribute>
+ <attribute name="idref">
+ <data type="string"/>
+ </attribute>
+ <attribute name="connectloc">
+ <data type="int"/>
+ </attribute>
+ </define>
+ <define name="CT_Diagram">
+ <element name="relationtable">
+ <ref name="CT_RelationTable"/>
+ </element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="dgmstyle">
+ <data type="integer"/>
+ </attribute>
+ <attribute name="autoformat">
+ <data type="string"/>
+ </attribute>
+ <attribute name="reverse">
+ <data type="string"/>
+ </attribute>
+ <attribute name="autolayout">
+ <data type="string"/>
+ </attribute>
+ <attribute name="dgmscalex">
+ <data type="integer"/>
+ </attribute>
+ <attribute name="dgmscaley">
+ <data type="integer"/>
+ </attribute>
+ <attribute name="dgmfontsize">
+ <data type="integer"/>
+ </attribute>
+ <attribute name="constrainbounds">
+ <data type="string"/>
+ </attribute>
+ <attribute name="dgmbasetextscale">
+ <data type="integer"/>
+ </attribute>
+ </define>
+ <define name="CT_RelationTable">
+ <element name="rel">
+ <ref name="CT_Relation"/>
+ </element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </define>
+ <define name="CT_Relation">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="idsrc">
+ <data type="string"/>
+ </attribute>
+ <attribute name="iddest">
+ <data type="string"/>
+ </attribute>
+ <attribute name="idcntr">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_ColorMru">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="colors">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_ColorMenu">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="strokecolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fillcolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="shadowcolor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="extrusioncolor">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="skew">
+ <element name="skew">
+ <ref name="CT_Skew"/>
+ </element>
+ </define>
+ <define name="extrusion">
+ <element name="extrusion">
+ <ref name="CT_Extrusion"/>
+ </element>
+ </define>
+ <define name="callout">
+ <element name="callout">
+ <ref name="CT_Callout"/>
+ </element>
+ </define>
+ <define name="lock">
+ <element name="lock">
+ <ref name="CT_Lock"/>
+ </element>
+ </define>
+ <define name="OLEObject">
+ <element name="OLEObject">
+ <ref name="CT_OLEObject"/>
+ </element>
+ </define>
+ <define name="complex">
+ <element name="complex">
+ <ref name="CT_Complex"/>
+ </element>
+ </define>
+ <define name="left">
+ <element name="left">
+ <ref name="CT_StrokeChild"/>
+ </element>
+ </define>
+ <define name="top">
+ <element name="top">
+ <ref name="CT_StrokeChild"/>
+ </element>
+ </define>
+ <define name="right">
+ <element name="right">
+ <ref name="CT_StrokeChild"/>
+ </element>
+ </define>
+ <define name="bottom">
+ <element name="bottom">
+ <ref name="CT_StrokeChild"/>
+ </element>
+ </define>
+ <define name="column">
+ <element name="column">
+ <ref name="CT_StrokeChild"/>
+ </element>
+ </define>
+ <define name="clippath">
+ <element name="clippath">
+ <ref name="CT_ClipPath"/>
+ </element>
+ </define>
+ <define name="fill">
+ <element name="fill">
+ <ref name="CT_Fill"/>
+ </element>
+ </define>
+ <define name="CT_Skew">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="offset">
+ <data type="string"/>
+ </attribute>
+ <attribute name="origin">
+ <data type="string"/>
+ </attribute>
+ <attribute name="matrix">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Extrusion">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="render">
+ <data type="string"/>
+ </attribute>
+ <attribute name="viewpointorigin">
+ <data type="string"/>
+ </attribute>
+ <attribute name="viewpoint">
+ <data type="string"/>
+ </attribute>
+ <attribute name="plane">
+ <data type="string"/>
+ </attribute>
+ <attribute name="skewangle">
+ <data type="float"/>
+ </attribute>
+ <attribute name="skewamt">
+ <data type="string"/>
+ </attribute>
+ <attribute name="foredepth">
+ <data type="string"/>
+ </attribute>
+ <attribute name="backdepth">
+ <data type="string"/>
+ </attribute>
+ <attribute name="orientation">
+ <data type="string"/>
+ </attribute>
+ <attribute name="orientationangle">
+ <data type="float"/>
+ </attribute>
+ <attribute name="lockrotationcenter">
+ <data type="string"/>
+ </attribute>
+ <attribute name="autorotationcenter">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rotationcenter">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rotationangle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="colormode">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color">
+ <data type="string"/>
+ </attribute>
+ <attribute name="shininess">
+ <data type="float"/>
+ </attribute>
+ <attribute name="specularity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="diffusity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="metal">
+ <data type="string"/>
+ </attribute>
+ <attribute name="edge">
+ <data type="string"/>
+ </attribute>
+ <attribute name="facet">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightface">
+ <data type="string"/>
+ </attribute>
+ <attribute name="brightness">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightposition">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightlevel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightharsh">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightposition2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightlevel2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lightharsh2">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Callout">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="gap">
+ <data type="string"/>
+ </attribute>
+ <attribute name="angle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="dropauto">
+ <data type="string"/>
+ </attribute>
+ <attribute name="drop">
+ <data type="string"/>
+ </attribute>
+ <attribute name="distance">
+ <data type="string"/>
+ </attribute>
+ <attribute name="lengthspecified">
+ <data type="string"/>
+ </attribute>
+ <attribute name="length">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accentbar">
+ <data type="string"/>
+ </attribute>
+ <attribute name="textborder">
+ <data type="string"/>
+ </attribute>
+ <attribute name="minusx">
+ <data type="string"/>
+ </attribute>
+ <attribute name="minusy">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Lock">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="position">
+ <data type="string"/>
+ </attribute>
+ <attribute name="selection">
+ <data type="string"/>
+ </attribute>
+ <attribute name="grouping">
+ <data type="string"/>
+ </attribute>
+ <attribute name="ungrouping">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rotation">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cropping">
+ <data type="string"/>
+ </attribute>
+ <attribute name="verticies">
+ <data type="string"/>
+ </attribute>
+ <attribute name="adjusthandles">
+ <data type="string"/>
+ </attribute>
+ <attribute name="text">
+ <data type="string"/>
+ </attribute>
+ <attribute name="aspectratio">
+ <data type="string"/>
+ </attribute>
+ <attribute name="shapetype">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_OLEObject">
+ <element name="LinkType">
+ <ref name="ST_OLELinkType"/>
+ </element>
+ <element name="LockedField">
+ <ref name="ST_TrueFalseBlank"/>
+ </element>
+ <element name="FieldCodes">
+ <data type="string"/>
+ </element>
+ <attribute name="Type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="ProgID">
+ <data type="string"/>
+ </attribute>
+ <attribute name="ShapeID">
+ <data type="string"/>
+ </attribute>
+ <attribute name="DrawAspect">
+ <data type="string"/>
+ </attribute>
+ <attribute name="ObjectID">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:id">
+ <data type="string"/>
+ </attribute>
+ <attribute name="UpdateMode">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Complex">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </define>
+ <define name="CT_StrokeChild">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="on">
+ <data type="string"/>
+ </attribute>
+ <attribute name="weight">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color">
+ <data type="string"/>
+ </attribute>
+ <attribute name="color2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="opacity">
+ <data type="string"/>
+ </attribute>
+ <attribute name="linestyle">
+ <ref name="ST_StrokeLineStyle"/>
+ </attribute>
+ <attribute name="miterlimit">
+ <data type="decimal"/>
+ </attribute>
+ <attribute name="joinstyle">
+ <ref name="ST_StrokeJoinStyle"/>
+ </attribute>
+ <attribute name="endcap">
+ <ref name="ST_StrokeEndCap"/>
+ </attribute>
+ <attribute name="dashstyle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="insetpen">
+ <data type="string"/>
+ </attribute>
+ <attribute name="filltype">
+ <ref name="ST_FillType"/>
+ </attribute>
+ <attribute name="src">
+ <data type="string"/>
+ </attribute>
+ <attribute name="imageaspect">
+ <ref name="ST_ImageAspect"/>
+ </attribute>
+ <attribute name="imagesize">
+ <data type="string"/>
+ </attribute>
+ <attribute name="imagealignshape">
+ <data type="string"/>
+ </attribute>
+ <attribute name="startarrow">
+ <ref name="ST_StrokeArrowType"/>
+ </attribute>
+ <attribute name="startarrowwidth">
+ <ref name="ST_StrokeArrowWidth"/>
+ </attribute>
+ <attribute name="startarrowlength">
+ <ref name="ST_StrokeArrowLength"/>
+ </attribute>
+ <attribute name="endarrow">
+ <ref name="ST_StrokeArrowType"/>
+ </attribute>
+ <attribute name="endarrowwidth">
+ <ref name="ST_StrokeArrowWidth"/>
+ </attribute>
+ <attribute name="endarrowlength">
+ <ref name="ST_StrokeArrowLength"/>
+ </attribute>
+ <ref name="href"/>
+ <ref name="althref"/>
+ <ref name="title"/>
+ <ref name="forcedash"/>
+ </define>
+ <define name="CT_ClipPath">
+ <attribute name="v">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Fill">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_Angle">
+ <choice>
+ <!-- Any Angle -->
+ <value>any</value>
+ <!-- 30 degrees -->
+ <value>30</value>
+ <!-- 45 degrees -->
+ <value>45</value>
+ <!-- 60 degrees -->
+ <value>60</value>
+ <!-- 90 degrees -->
+ <value>90</value>
+ <!-- Automatic Angle -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="ST_OLELinkType">
+ <choice>
+ <!-- Other Image -->
+ <value>Picture</value>
+ <!-- Bitmap Image -->
+ <value>Bitmap</value>
+ <!-- Enhanced Metafile Image -->
+ <value>EnhancedMetaFile</value>
+ </choice>
+ </define>
+ <define name="ST_TrueFalseBlank">
+ <choice>
+ <!-- Blank - Logical False -->
+ <value/>
+ <!-- Logical True -->
+ <value>t</value>
+ <!-- Logical False -->
+ <value>f</value>
+ <!-- Logical True -->
+ <value>true</value>
+ <!-- Logical False -->
+ <value>false</value>
+ </choice>
+ </define>
+ <define name="ST_FillType">
+ <choice>
+ <!-- Centered Radial Gradient -->
+ <value>gradientCenter</value>
+ <!-- Solid Fill -->
+ <value>solid</value>
+ <!-- Image Pattern -->
+ <value>pattern</value>
+ <!-- Tiled Image -->
+ <value>tile</value>
+ <!-- Stretch Image to Fit -->
+ <value>frame</value>
+ <!-- Unscaled Gradient -->
+ <value>gradientUnscaled</value>
+ <!-- Radial Gradient -->
+ <value>gradientRadial</value>
+ <!-- Linear Gradient -->
+ <value>gradient</value>
+ <!-- Use Background Fill -->
+ <value>background</value>
+ </choice>
+ </define>
+ <define name="BUILT_IN_ANY_TYPE">
+ <choice>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <data type="string"/>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="OLEObject" resource="Properties">
+ <element name="OLEObject" tokenid="ooxml:OLEObject_OLEObject"/>
+ </resource>
+ <resource name="CT_OLEObject" resource="Properties">
+ <element name="LinkType" tokenid="ooxml:CT_OLEObject_LinkType"/>
+ <element name="LockedField" tokenid="ooxml:CT_OLEObject_LockedField"/>
+ <element name="FieldCodes" tokenid="ooxml:CT_OLEObject_FieldCodes"/>
+ <attribute name="Type" tokenid="ooxml:CT_OLEObject_Type"/>
+ <attribute name="ProgID" tokenid="ooxml:CT_OLEObject_ProgID"/>
+ <attribute name="ShapeID" tokenid="ooxml:CT_OLEObject_ShapeID"/>
+ <attribute name="DrawAspect" tokenid="ooxml:CT_OLEObject_DrawAspect"/>
+ <attribute name="ObjectID" tokenid="ooxml:CT_OLEObject_ObjectID"/>
+ <attribute name="r:id" tokenid="ooxml:CT_OLEObject_r_id"/>
+ <attribute name="UpdateMode" tokenid="ooxml:CT_OLEObject_UpdateMode"/>
+ <action name="end" action="handleOLE"/>
+ </resource>
+ <resource name="ST_Angle" resource="List">
+ <value tokenid="ooxml:Value_vmlOffice_ST_Angle_any">any</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_Angle_30">30</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_Angle_45">45</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_Angle_60">60</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_Angle_90">90</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_Angle_auto">auto</value>
+ </resource>
+ <resource name="ST_OLELinkType" resource="List">
+ <value tokenid="ooxml:Value_vmlOffice_ST_OLELinkType_Picture">Picture</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_OLELinkType_Bitmap">Bitmap</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_OLELinkType_EnhancedMetaFile">EnhancedMetaFile</value>
+ </resource>
+ <resource name="ST_TrueFalseBlank" resource="List">
+ <value tokenid="ooxml:Value_vmlOffice_ST_TrueFalseBlank_"/>
+ <value tokenid="ooxml:Value_vmlOffice_ST_TrueFalseBlank_t">t</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_TrueFalseBlank_f">f</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_TrueFalseBlank_true">true</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_TrueFalseBlank_false">false</value>
+ </resource>
+ <resource name="ST_FillType" resource="List">
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_gradientCenter">gradientCenter</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_solid">solid</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_pattern">pattern</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_tile">tile</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_frame">frame</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_gradientUnscaled">gradientUnscaled</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_gradientRadial">gradientRadial</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_gradient">gradient</value>
+ <value tokenid="ooxml:Value_vmlOffice_ST_FillType_background">background</value>
+ </resource>
+ </namespace>
+ <namespace name="vml-wordprocessingDrawing">
+ <start name="bordertop"/>
+ <start name="borderleft"/>
+ <start name="borderright"/>
+ <start name="borderbottom"/>
+ <start name="wrap"/>
+ <start name="anchorlock"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="urn:schemas-microsoft-com:office:word">
+ <!-- ISO RELAX NG Schema -->
+ <!-- start = bordertop | borderleft | borderright | borderbottom | wrap | anchorlock -->
+ <define name="bordertop">
+ <element name="bordertop">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="borderleft">
+ <element name="borderleft">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="borderright">
+ <element name="borderright">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="borderbottom">
+ <element name="borderbottom">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_Border">
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ <attribute name="width">
+ <data type="positiveInteger"/>
+ </attribute>
+ <attribute name="shadow">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="wrap">
+ <element name="wrap">
+ <ref name="CT_Wrap"/>
+ </element>
+ </define>
+ <define name="CT_Wrap">
+ <attribute name="type">
+ <ref name="ST_WrapType"/>
+ </attribute>
+ <attribute name="side">
+ <ref name="ST_WrapSide"/>
+ </attribute>
+ <attribute name="anchorx">
+ <ref name="ST_HorizontalAnchor"/>
+ </attribute>
+ <attribute name="anchory">
+ <ref name="ST_VerticalAnchor"/>
+ </attribute>
+ </define>
+ <define name="anchorlock">
+ <element name="anchorlock">
+ <ref name="CT_AnchorLock"/>
+ </element>
+ </define>
+ <define name="CT_AnchorLock">
+ </define>
+ <define name="ST_WrapType">
+ <choice>
+ <!-- Top and bottom wrapping -->
+ <value>topAndBottom</value>
+ <!-- Square wrapping -->
+ <value>square</value>
+ <!-- No wrapping -->
+ <value>none</value>
+ <!-- Tight wrapping -->
+ <value>tight</value>
+ <!-- Through wrapping -->
+ <value>through</value>
+ </choice>
+ </define>
+ <define name="ST_WrapSide">
+ <choice>
+ <!-- Both sides -->
+ <value>both</value>
+ <!-- Left side -->
+ <value>left</value>
+ <!-- Right side -->
+ <value>right</value>
+ <!-- Largest side -->
+ <value>largest</value>
+ </choice>
+ </define>
+ <define name="ST_HorizontalAnchor">
+ <choice>
+ <!-- Margin -->
+ <value>margin</value>
+ <!-- Page -->
+ <value>page</value>
+ <!-- Text -->
+ <value>text</value>
+ <!-- Character -->
+ <value>char</value>
+ </choice>
+ </define>
+ <define name="ST_VerticalAnchor">
+ <choice>
+ <!-- Margin -->
+ <value>margin</value>
+ <!-- Page -->
+ <value>page</value>
+ <!-- Text -->
+ <value>text</value>
+ <!-- Line -->
+ <value>line</value>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="wrap" resource="Properties">
+ <element name="wrap" tokenid="ooxml:wrap_wrap"/>
+ </resource>
+ <resource name="CT_Wrap" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_Wrap_type"/>
+ <attribute name="side" tokenid="ooxml:CT_Wrap_side"/>
+ <attribute name="anchorx" tokenid="ooxml:CT_Wrap_anchorx"/>
+ <attribute name="anchory" tokenid="ooxml:CT_Wrap_anchory"/>
+ </resource>
+ <resource name="ST_WrapType" resource="List">
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapType_topAndBottom">topAndBottom</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapType_square">square</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapType_none">none</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapType_tight">tight</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapType_through">through</value>
+ </resource>
+ <resource name="ST_WrapSide" resource="List">
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapSide_both">both</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapSide_left">left</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapSide_right">right</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_WrapSide_largest">largest</value>
+ </resource>
+ <resource name="ST_HorizontalAnchor" resource="List">
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_HorizontalAnchor_margin">margin</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_HorizontalAnchor_page">page</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_HorizontalAnchor_text">text</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_HorizontalAnchor_char">char</value>
+ </resource>
+ <resource name="ST_VerticalAnchor" resource="List">
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_VerticalAnchor_margin">margin</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_VerticalAnchor_page">page</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_VerticalAnchor_text">text</value>
+ <value tokenid="ooxml:Value_vml_wordprocessingDrawing_ST_VerticalAnchor_line">line</value>
+ </resource>
+ </namespace>
+ <namespace name="wml">
+ <start name="recipients"/>
+ <start name="txbxContent"/>
+ <start name="comments"/>
+ <start name="footnotes"/>
+ <start name="endnotes"/>
+ <start name="hdr"/>
+ <start name="ftr"/>
+ <start name="settings"/>
+ <start name="webSettings"/>
+ <start name="fonts"/>
+ <start name="numbering"/>
+ <start name="styles"/>
+ <start name="document"/>
+ <start name="glossaryDocument"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/wordprocessingml/2006/main" attributeFormDefault="qualified">
+ <include href="shared-math"/>
+ <include href="dml-wordprocessingDrawing"/>
+ <include href="shared-relationshipReference"/>
+ <!-- start = recipients | txbxContent | comments | footnotes | endnotes | hdr | ftr | settings | webSettings | fonts | numbering | styles | document | glossaryDocument -->
+ <define name="CT_Empty">
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <!-- True -->
+ <value>true</value>
+ <!-- False -->
+ <value>false</value>
+ <!-- True -->
+ <value>on</value>
+ <!-- False -->
+ <value>off</value>
+ <!-- False -->
+ <value>0</value>
+ <!-- True -->
+ <value>1</value>
+ </choice>
+ </define>
+ <define name="CT_OnOff">
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_LongHexNumber">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_LongHexNumber">
+ <attribute name="val">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_ShortHexNumber">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_ShortHexNumber">
+ <attribute name="val">
+ <ref name="ST_ShortHexNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_UcharHexNumber">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_UcharHexNumber">
+ <attribute name="val">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_DecimalNumber">
+ <data type="integer"/>
+ </define>
+ <define name="CT_DecimalNumber">
+ <attribute name="val">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_UnsignedDecimalNumber">
+ <data type="unsignedLong"/>
+ </define>
+<!-- MS documentation states that TwipsMeasure is a positive value
+ but it doesn't indicate how to handle an invalid negative
+ value. So, ST_TwipsMeasure matches the documented type,
+ and the extension (_asSigned, _asZero, or perhaps _asAbsolute)
+ indicates how MS handles it in practice.
+
+ Historically, LO has treated TwipsMeasure as signed,
+ i.e. that negative numbers are allowed and treated as negative,
+ so that is the default handling.
+-->
+ <define name="ST_TwipsMeasure">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="ST_TwipsMeasure_asSigned">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="ST_TwipsMeasure_asZero">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="CT_TwipsMeasure">
+ <attribute name="val">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_SignedTwipsMeasure">
+ <data type="integer"/>
+ </define>
+ <define name="CT_SignedTwipsMeasure">
+ <attribute name="val">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_PixelsMeasure">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="CT_PixelsMeasure">
+ <attribute name="val">
+ <ref name="ST_PixelsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_HpsMeasure">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="CT_HpsMeasure">
+ <attribute name="val">
+ <ref name="ST_HpsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_SignedHpsMeasure">
+ <data type="integer"/>
+ </define>
+ <define name="CT_SignedHpsMeasure">
+ <attribute name="val">
+ <ref name="ST_SignedHpsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_DateTime">
+ <data type="dateTime"/>
+ </define>
+ <define name="CT_MacroName">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_EighthPointMeasure">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="ST_PointMeasure">
+ <data type="unsignedLong"/>
+ </define>
+ <define name="ST_String">
+ <data type="string"/>
+ </define>
+ <define name="CT_String">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_TextScale">
+ <data type="integer"/>
+ </define>
+ <define name="CT_TextScale">
+ <attribute name="val">
+ <ref name="ST_TextScale"/>
+ </attribute>
+ </define>
+ <define name="ST_HighlightColor">
+ <choice>
+ <!-- Black Highlighting Color -->
+ <value>black</value>
+ <!-- Blue Highlighting Color -->
+ <value>blue</value>
+ <!-- Cyan Highlighting Color -->
+ <value>cyan</value>
+ <!-- Green Highlighting Color -->
+ <value>green</value>
+ <!-- Magenta Highlighting Color -->
+ <value>magenta</value>
+ <!-- Red Highlighting Color -->
+ <value>red</value>
+ <!-- Yellow Highlighting Color -->
+ <value>yellow</value>
+ <!-- White Highlighting Color -->
+ <value>white</value>
+ <!-- Dark Blue Highlighting Color -->
+ <value>darkBlue</value>
+ <!-- Dark Cyan Highlighting Color -->
+ <value>darkCyan</value>
+ <!-- Dark Green Highlighting Color -->
+ <value>darkGreen</value>
+ <!-- Dark Magenta Highlighting Color -->
+ <value>darkMagenta</value>
+ <!-- Dark Red Highlighting Color -->
+ <value>darkRed</value>
+ <!-- Dark Yellow Highlighting Color -->
+ <value>darkYellow</value>
+ <!-- Dark Gray Highlighting Color -->
+ <value>darkGray</value>
+ <!-- Light Gray Highlighting Color -->
+ <value>lightGray</value>
+ <!-- No Text Highlighting -->
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="CT_Highlight">
+ <attribute name="val">
+ <ref name="ST_HighlightColor"/>
+ </attribute>
+ </define>
+ <define name="ST_HexColorAuto">
+ <choice>
+ <!-- Automatically Determined Color -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="ST_HexColorRGB">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_HexColor">
+ <choice>
+ <ref name="ST_HexColorAuto"/>
+ <ref name="ST_HexColorRGB"/>
+ </choice>
+ </define>
+ <!-- Union -->
+ <define name="CT_Color">
+ <attribute name="val">
+ <ref name="ST_HexColor"/>
+ </attribute>
+ <attribute name="themeColor">
+ <ref name="ST_ThemeColor"/>
+ </attribute>
+ <attribute name="themeTint">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="themeShade">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_LangCode">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_Lang">
+ <choice>
+ <ref name="ST_LangCode"/>
+ <ref name="ST_String"/>
+ </choice>
+ </define>
+ <!-- Union -->
+ <define name="CT_Lang">
+ <attribute name="val">
+ <ref name="ST_Lang"/>
+ </attribute>
+ </define>
+ <define name="CT_Guid">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_Underline">
+ <choice>
+ <!-- Single Underline -->
+ <value>single</value>
+ <!-- Underline Non-Space Characters Only -->
+ <value>words</value>
+ <!-- Double Underline -->
+ <value>double</value>
+ <!-- Thick Underline -->
+ <value>thick</value>
+ <!-- Dotted Underline -->
+ <value>dotted</value>
+ <!-- Thick Dotted Underline -->
+ <value>dottedHeavy</value>
+ <!-- Dashed Underline -->
+ <value>dash</value>
+ <!-- Thick Dashed Underline -->
+ <value>dashedHeavy</value>
+ <!-- Long Dashed Underline -->
+ <value>dashLong</value>
+ <!-- Thick Long Dashed Underline -->
+ <value>dashLongHeavy</value>
+ <!-- Dash-Dot Underline -->
+ <value>dotDash</value>
+ <!-- Thick Dash-Dot Underline -->
+ <value>dashDotHeavy</value>
+ <!-- Dash-Dot-Dot Underline -->
+ <value>dotDotDash</value>
+ <!-- Thick Dash-Dot-Dot Underline -->
+ <value>dashDotDotHeavy</value>
+ <!-- Wave Underline -->
+ <value>wave</value>
+ <!-- Heavy Wave Underline -->
+ <value>wavyHeavy</value>
+ <!-- Double Wave Underline -->
+ <value>wavyDouble</value>
+ <!-- No Underline -->
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="CT_Underline">
+ <attribute name="val">
+ <ref name="ST_Underline"/>
+ </attribute>
+ <attribute name="color">
+ <ref name="ST_HexColor"/>
+ </attribute>
+ <attribute name="themeColor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="themeTint">
+ <data type="string"/>
+ </attribute>
+ <attribute name="themeShade">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_TextEffect">
+ <choice>
+ <!-- Blinking Background Animation -->
+ <value>blinkBackground</value>
+ <!-- Colored Lights Animation -->
+ <value>lights</value>
+ <!-- Black Dashed Line Animation -->
+ <value>antsBlack</value>
+ <!-- Marching Red Ants -->
+ <value>antsRed</value>
+ <!-- Shimmer Animation -->
+ <value>shimmer</value>
+ <!-- Sparkling Lights Animation -->
+ <value>sparkle</value>
+ <!-- No Animation -->
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="CT_TextEffect">
+ <attribute name="val">
+ <ref name="ST_TextEffect"/>
+ </attribute>
+ </define>
+ <define name="ST_Border">
+ <choice>
+ <!-- No Border -->
+ <value>nil</value>
+ <!-- No Border -->
+ <value>none</value>
+ <!-- Single Line Border -->
+ <value>single</value>
+ <!-- Single Line Border -->
+ <value>thick</value>
+ <!-- Double Line Border -->
+ <value>double</value>
+ <!-- Dotted Line Border -->
+ <value>dotted</value>
+ <!-- Dashed Line Border -->
+ <value>dashed</value>
+ <!-- Dot Dash Line Border -->
+ <value>dotDash</value>
+ <!-- Dot Dot Dash Line Border -->
+ <value>dotDotDash</value>
+ <!-- Triple Line Border -->
+ <value>triple</value>
+ <!-- Thin, Thick Line Border -->
+ <value>thinThickSmallGap</value>
+ <!-- Thick, Thin Line Border -->
+ <value>thickThinSmallGap</value>
+ <!-- Thin, Thick, Thin Line Border -->
+ <value>thinThickThinSmallGap</value>
+ <!-- Thin, Thick Line Border -->
+ <value>thinThickMediumGap</value>
+ <!-- Thick, Thin Line Border -->
+ <value>thickThinMediumGap</value>
+ <!-- Thin, Thick, Thin Line Border -->
+ <value>thinThickThinMediumGap</value>
+ <!-- Thin, Thick Line Border -->
+ <value>thinThickLargeGap</value>
+ <!-- Thick, Thin Line Border -->
+ <value>thickThinLargeGap</value>
+ <!-- Thin, Thick, Thin Line Border -->
+ <value>thinThickThinLargeGap</value>
+ <!-- Wavy Line Border -->
+ <value>wave</value>
+ <!-- Double Wave Line Border -->
+ <value>doubleWave</value>
+ <!-- Dashed Line Border -->
+ <value>dashSmallGap</value>
+ <!-- Dash Dot Strokes Line Border -->
+ <value>dashDotStroked</value>
+ <!-- 3D Embossed Line Border -->
+ <value>threeDEmboss</value>
+ <!-- 3D Engraved Line Border -->
+ <value>threeDEngrave</value>
+ <!-- Outset Line Border -->
+ <value>outset</value>
+ <!-- Inset Line Border -->
+ <value>inset</value>
+ <!-- Apples Art Border -->
+ <value>apples</value>
+ <!-- Arched Scallops Art Border -->
+ <value>archedScallops</value>
+ <!-- Baby Pacifier Art Border -->
+ <value>babyPacifier</value>
+ <!-- Baby Rattle Art Border -->
+ <value>babyRattle</value>
+ <!-- Three Color Balloons Art Border -->
+ <value>balloons3Colors</value>
+ <!-- Hot Air Balloons Art Border -->
+ <value>balloonsHotAir</value>
+ <!-- Black Dash Art Border -->
+ <value>basicBlackDashes</value>
+ <!-- Black Dot Art Border -->
+ <value>basicBlackDots</value>
+ <!-- Black Square Art Border -->
+ <value>basicBlackSquares</value>
+ <!-- Thin Line Art Border -->
+ <value>basicThinLines</value>
+ <!-- White Dash Art Border -->
+ <value>basicWhiteDashes</value>
+ <!-- White Dot Art Border -->
+ <value>basicWhiteDots</value>
+ <!-- White Square Art Border -->
+ <value>basicWhiteSquares</value>
+ <!-- Wide Inline Art Border -->
+ <value>basicWideInline</value>
+ <!-- Wide Midline Art Border -->
+ <value>basicWideMidline</value>
+ <!-- Wide Outline Art Border -->
+ <value>basicWideOutline</value>
+ <!-- Bats Art Border -->
+ <value>bats</value>
+ <!-- Birds Art Border -->
+ <value>birds</value>
+ <!-- Birds Flying Art Border -->
+ <value>birdsFlight</value>
+ <!-- Cabin Art Border -->
+ <value>cabins</value>
+ <!-- Cake Art Border -->
+ <value>cakeSlice</value>
+ <!-- Candy Corn Art Border -->
+ <value>candyCorn</value>
+ <!-- Knot Work Art Border -->
+ <value>celticKnotwork</value>
+ <!-- Certificate Banner Art Border -->
+ <value>certificateBanner</value>
+ <!-- Chain Link Art Border -->
+ <value>chainLink</value>
+ <!-- Champagne Bottle Art Border -->
+ <value>champagneBottle</value>
+ <!-- Black and White Bar Art Border -->
+ <value>checkedBarBlack</value>
+ <!-- Color Checked Bar Art Border -->
+ <value>checkedBarColor</value>
+ <!-- Checkerboard Art Border -->
+ <value>checkered</value>
+ <!-- Christmas Tree Art Border -->
+ <value>christmasTree</value>
+ <!-- Circles And Lines Art Border -->
+ <value>circlesLines</value>
+ <!-- Circles and Rectangles Art Border -->
+ <value>circlesRectangles</value>
+ <!-- Wave Art Border -->
+ <value>classicalWave</value>
+ <!-- Clocks Art Border -->
+ <value>clocks</value>
+ <!-- Compass Art Border -->
+ <value>compass</value>
+ <!-- Confetti Art Border -->
+ <value>confetti</value>
+ <!-- Confetti Art Border -->
+ <value>confettiGrays</value>
+ <!-- Confetti Art Border -->
+ <value>confettiOutline</value>
+ <!-- Confetti Streamers Art Border -->
+ <value>confettiStreamers</value>
+ <!-- Confetti Art Border -->
+ <value>confettiWhite</value>
+ <!-- Corner Triangle Art Border -->
+ <value>cornerTriangles</value>
+ <!-- Dashed Line Art Border -->
+ <value>couponCutoutDashes</value>
+ <!-- Dotted Line Art Border -->
+ <value>couponCutoutDots</value>
+ <!-- Maze Art Border -->
+ <value>crazyMaze</value>
+ <!-- Butterfly Art Border -->
+ <value>creaturesButterfly</value>
+ <!-- Fish Art Border -->
+ <value>creaturesFish</value>
+ <!-- Insects Art Border -->
+ <value>creaturesInsects</value>
+ <!-- Ladybug Art Border -->
+ <value>creaturesLadyBug</value>
+ <!-- Cross-stitch Art Border -->
+ <value>crossStitch</value>
+ <!-- Cupid Art Border -->
+ <value>cup</value>
+ <!-- Archway Art Border -->
+ <value>decoArch</value>
+ <!-- Color Archway Art Border -->
+ <value>decoArchColor</value>
+ <!-- Blocks Art Border -->
+ <value>decoBlocks</value>
+ <!-- Gray Diamond Art Border -->
+ <value>diamondsGray</value>
+ <!-- Double D Art Border -->
+ <value>doubleD</value>
+ <!-- Diamond Art Border -->
+ <value>doubleDiamonds</value>
+ <!-- Earth Art Border -->
+ <value>earth1</value>
+ <!-- Earth Art Border -->
+ <value>earth2</value>
+ <!-- Shadowed Square Art Border -->
+ <value>eclipsingSquares1</value>
+ <!-- Shadowed Square Art Border -->
+ <value>eclipsingSquares2</value>
+ <!-- Painted Egg Art Border -->
+ <value>eggsBlack</value>
+ <!-- Fans Art Border -->
+ <value>fans</value>
+ <!-- Film Reel Art Border -->
+ <value>film</value>
+ <!-- Firecracker Art Border -->
+ <value>firecrackers</value>
+ <!-- Flowers Art Border -->
+ <value>flowersBlockPrint</value>
+ <!-- Daisy Art Border -->
+ <value>flowersDaisies</value>
+ <!-- Flowers Art Border -->
+ <value>flowersModern1</value>
+ <!-- Flowers Art Border -->
+ <value>flowersModern2</value>
+ <!-- Pansy Art Border -->
+ <value>flowersPansy</value>
+ <!-- Red Rose Art Border -->
+ <value>flowersRedRose</value>
+ <!-- Roses Art Border -->
+ <value>flowersRoses</value>
+ <!-- Flowers in a Teacup Art Border -->
+ <value>flowersTeacup</value>
+ <!-- Small Flower Art Border -->
+ <value>flowersTiny</value>
+ <!-- Gems Art Border -->
+ <value>gems</value>
+ <!-- Gingerbread Man Art Border -->
+ <value>gingerbreadMan</value>
+ <!-- Triangle Gradient Art Border -->
+ <value>gradient</value>
+ <!-- Handmade Art Border -->
+ <value>handmade1</value>
+ <!-- Handmade Art Border -->
+ <value>handmade2</value>
+ <!-- Heart-Shaped Balloon Art Border -->
+ <value>heartBalloon</value>
+ <!-- Gray Heart Art Border -->
+ <value>heartGray</value>
+ <!-- Hearts Art Border -->
+ <value>hearts</value>
+ <!-- Pattern Art Border -->
+ <value>heebieJeebies</value>
+ <!-- Holly Art Border -->
+ <value>holly</value>
+ <!-- House Art Border -->
+ <value>houseFunky</value>
+ <!-- Circular Art Border -->
+ <value>hypnotic</value>
+ <!-- Ice Cream Cone Art Border -->
+ <value>iceCreamCones</value>
+ <!-- Light Bulb Art Border -->
+ <value>lightBulb</value>
+ <!-- Lightning Art Border -->
+ <value>lightning1</value>
+ <!-- Lightning Art Border -->
+ <value>lightning2</value>
+ <!-- Map Pins Art Border -->
+ <value>mapPins</value>
+ <!-- Maple Leaf Art Border -->
+ <value>mapleLeaf</value>
+ <!-- Muffin Art Border -->
+ <value>mapleMuffins</value>
+ <!-- Marquee Art Border -->
+ <value>marquee</value>
+ <!-- Marquee Art Border -->
+ <value>marqueeToothed</value>
+ <!-- Moon Art Border -->
+ <value>moons</value>
+ <!-- Mosaic Art Border -->
+ <value>mosaic</value>
+ <!-- Musical Note Art Border -->
+ <value>musicNotes</value>
+ <!-- Patterned Art Border -->
+ <value>northwest</value>
+ <!-- Oval Art Border -->
+ <value>ovals</value>
+ <!-- Package Art Border -->
+ <value>packages</value>
+ <!-- Black Palm Tree Art Border -->
+ <value>palmsBlack</value>
+ <!-- Color Palm Tree Art Border -->
+ <value>palmsColor</value>
+ <!-- Paper Clip Art Border -->
+ <value>paperClips</value>
+ <!-- Papyrus Art Border -->
+ <value>papyrus</value>
+ <!-- Party Favor Art Border -->
+ <value>partyFavor</value>
+ <!-- Party Glass Art Border -->
+ <value>partyGlass</value>
+ <!-- Pencils Art Border -->
+ <value>pencils</value>
+ <!-- Character Art Border -->
+ <value>people</value>
+ <!-- Waving Character Border -->
+ <value>peopleWaving</value>
+ <!-- Character With Hat Art Border -->
+ <value>peopleHats</value>
+ <!-- Poinsettia Art Border -->
+ <value>poinsettias</value>
+ <!-- Postage Stamp Art Border -->
+ <value>postageStamp</value>
+ <!-- Pumpkin Art Border -->
+ <value>pumpkin1</value>
+ <!-- Push Pin Art Border -->
+ <value>pushPinNote2</value>
+ <!-- Push Pin Art Border -->
+ <value>pushPinNote1</value>
+ <!-- Pyramid Art Border -->
+ <value>pyramids</value>
+ <!-- Pyramid Art Border -->
+ <value>pyramidsAbove</value>
+ <!-- Quadrants Art Border -->
+ <value>quadrants</value>
+ <!-- Rings Art Border -->
+ <value>rings</value>
+ <!-- Safari Art Border -->
+ <value>safari</value>
+ <!-- Saw tooth Art Border -->
+ <value>sawtooth</value>
+ <!-- Gray Saw tooth Art Border -->
+ <value>sawtoothGray</value>
+ <!-- Scared Cat Art Border -->
+ <value>scaredCat</value>
+ <!-- Umbrella Art Border -->
+ <value>seattle</value>
+ <!-- Shadowed Squares Art Border -->
+ <value>shadowedSquares</value>
+ <!-- Shark Tooth Art Border -->
+ <value>sharksTeeth</value>
+ <!-- Bird Tracks Art Border -->
+ <value>shorebirdTracks</value>
+ <!-- Rocket Art Border -->
+ <value>skyrocket</value>
+ <!-- Snowflake Art Border -->
+ <value>snowflakeFancy</value>
+ <!-- Snowflake Art Border -->
+ <value>snowflakes</value>
+ <!-- Sombrero Art Border -->
+ <value>sombrero</value>
+ <!-- Southwest-themed Art Border -->
+ <value>southwest</value>
+ <!-- Stars Art Border -->
+ <value>stars</value>
+ <!-- Stars On Top Art Border -->
+ <value>starsTop</value>
+ <!-- 3-D Stars Art Border -->
+ <value>stars3d</value>
+ <!-- Stars Art Border -->
+ <value>starsBlack</value>
+ <!-- Stars With Shadows Art Border -->
+ <value>starsShadowed</value>
+ <!-- Sun Art Border -->
+ <value>sun</value>
+ <!-- Whirligig Art Border -->
+ <value>swirligig</value>
+ <!-- Torn Paper Art Border -->
+ <value>tornPaper</value>
+ <!-- Black Torn Paper Art Border -->
+ <value>tornPaperBlack</value>
+ <!-- Tree Art Border -->
+ <value>trees</value>
+ <!-- Triangle Art Border -->
+ <value>triangleParty</value>
+ <!-- Triangles Art Border -->
+ <value>triangles</value>
+ <!-- Tribal Art Border One -->
+ <value>tribal1</value>
+ <!-- Tribal Art Border Two -->
+ <value>tribal2</value>
+ <!-- Tribal Art Border Three -->
+ <value>tribal3</value>
+ <!-- Tribal Art Border Four -->
+ <value>tribal4</value>
+ <!-- Tribal Art Border Five -->
+ <value>tribal5</value>
+ <!-- Tribal Art Border Six -->
+ <value>tribal6</value>
+ <!-- Twisted Lines Art Border -->
+ <value>twistedLines1</value>
+ <!-- Twisted Lines Art Border -->
+ <value>twistedLines2</value>
+ <!-- Vine Art Border -->
+ <value>vine</value>
+ <!-- Wavy Line Art Border -->
+ <value>waveline</value>
+ <!-- Weaving Angles Art Border -->
+ <value>weavingAngles</value>
+ <!-- Weaving Braid Art Border -->
+ <value>weavingBraid</value>
+ <!-- Weaving Ribbon Art Border -->
+ <value>weavingRibbon</value>
+ <!-- Weaving Strips Art Border -->
+ <value>weavingStrips</value>
+ <!-- White Flowers Art Border -->
+ <value>whiteFlowers</value>
+ <!-- Woodwork Art Border -->
+ <value>woodwork</value>
+ <!-- Crisscross Art Border -->
+ <value>xIllusions</value>
+ <!-- Triangle Art Border -->
+ <value>zanyTriangles</value>
+ <!-- Zigzag Art Border -->
+ <value>zigZag</value>
+ <!-- Zigzag stitch -->
+ <value>zigZagStitch</value>
+ </choice>
+ </define>
+ <define name="CT_Border">
+ <attribute name="val">
+ <ref name="ST_Border"/>
+ </attribute>
+ <attribute name="color">
+ <ref name="ST_HexColor"/>
+ </attribute>
+ <attribute name="themeColor">
+ <ref name="ST_ThemeColor"/>
+ </attribute>
+ <attribute name="themeTint">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="themeShade">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="sz">
+ <ref name="ST_EighthPointMeasure"/>
+ </attribute>
+ <attribute name="space">
+ <ref name="ST_PointMeasure"/>
+ </attribute>
+ <attribute name="shadow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="frame">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_Shd">
+ <choice>
+ <!-- No Pattern -->
+ <value>nil</value>
+ <!-- No Pattern -->
+ <value>clear</value>
+ <!-- 100% Fill Pattern -->
+ <value>solid</value>
+ <!-- Horizontal Stripe Pattern -->
+ <value>horzStripe</value>
+ <!-- Vertical Stripe Pattern -->
+ <value>vertStripe</value>
+ <!-- Reverse Diagonal Stripe Pattern -->
+ <value>reverseDiagStripe</value>
+ <!-- Diagonal Stripe Pattern -->
+ <value>diagStripe</value>
+ <!-- Horizontal Cross Pattern -->
+ <value>horzCross</value>
+ <!-- Diagonal Cross Pattern -->
+ <value>diagCross</value>
+ <!-- Thin Horizontal Stripe Pattern -->
+ <value>thinHorzStripe</value>
+ <!-- Thin Vertical Stripe Pattern -->
+ <value>thinVertStripe</value>
+ <!-- Thin Reverse Diagonal Stripe Pattern -->
+ <value>thinReverseDiagStripe</value>
+ <!-- Thin Diagonal Stripe Pattern -->
+ <value>thinDiagStripe</value>
+ <!-- Thin Horizontal Cross Pattern -->
+ <value>thinHorzCross</value>
+ <!-- Thin Diagonal Cross Pattern -->
+ <value>thinDiagCross</value>
+ <!-- 5% Fill Pattern -->
+ <value>pct5</value>
+ <!-- 10% Fill Pattern -->
+ <value>pct10</value>
+ <!-- 12.5% Fill Pattern -->
+ <value>pct12</value>
+ <!-- 15% Fill Pattern -->
+ <value>pct15</value>
+ <!-- 20% Fill Pattern -->
+ <value>pct20</value>
+ <!-- 25% Fill Pattern -->
+ <value>pct25</value>
+ <!-- 30% Fill Pattern -->
+ <value>pct30</value>
+ <!-- 35% Fill Pattern -->
+ <value>pct35</value>
+ <!-- 37.5% Fill Pattern -->
+ <value>pct37</value>
+ <!-- 40% Fill Pattern -->
+ <value>pct40</value>
+ <!-- 45% Fill Pattern -->
+ <value>pct45</value>
+ <!-- 50% Fill Pattern -->
+ <value>pct50</value>
+ <!-- 55% Fill Pattern -->
+ <value>pct55</value>
+ <!-- 60% Fill Pattern -->
+ <value>pct60</value>
+ <!-- 62.5% Fill Pattern -->
+ <value>pct62</value>
+ <!-- 65% Fill Pattern -->
+ <value>pct65</value>
+ <!-- 70% Fill Pattern -->
+ <value>pct70</value>
+ <!-- 75% Fill Pattern -->
+ <value>pct75</value>
+ <!-- 80% Fill Pattern -->
+ <value>pct80</value>
+ <!-- 85% Fill Pattern -->
+ <value>pct85</value>
+ <!-- 87.5% Fill Pattern -->
+ <value>pct87</value>
+ <!-- 90% Fill Pattern -->
+ <value>pct90</value>
+ <!-- 95% Fill Pattern -->
+ <value>pct95</value>
+ </choice>
+ </define>
+ <define name="CT_Shd">
+ <attribute name="val">
+ <ref name="ST_Shd"/>
+ </attribute>
+ <attribute name="color">
+ <ref name="ST_HexColor"/>
+ </attribute>
+ <attribute name="themeColor">
+ <ref name="ST_ThemeColor"/>
+ </attribute>
+ <attribute name="themeTint">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="themeShade">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="fill">
+ <ref name="ST_HexColor"/>
+ </attribute>
+ <attribute name="themeFill">
+ <ref name="ST_ThemeColor"/>
+ </attribute>
+ <attribute name="themeFillTint">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="themeFillShade">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_VerticalAlignRun">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FitText">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_Em">
+ <choice>
+ <!-- No Emphasis Mark -->
+ <value>none</value>
+ <!-- Dot Emphasis Mark Above Characters -->
+ <value>dot</value>
+ <!-- Comma Emphasis Mark Above Characters -->
+ <value>comma</value>
+ <!-- Circle Emphasis Mark Above Characters -->
+ <value>circle</value>
+ <!-- Dot Emphasis Mark Below Characters -->
+ <value>underDot</value>
+ </choice>
+ </define>
+ <define name="CT_Em">
+ <attribute name="val">
+ <ref name="ST_Em"/>
+ </attribute>
+ </define>
+ <define name="CT_Language">
+ <attribute name="val">
+ <ref name="ST_Lang"/>
+ </attribute>
+ <attribute name="eastAsia">
+ <ref name="ST_Lang"/>
+ </attribute>
+ <attribute name="bidi">
+ <ref name="ST_Lang"/>
+ </attribute>
+ </define>
+ <define name="ST_CombineBrackets">
+ <choice>
+ <!-- No Enclosing Brackets -->
+ <value>none</value>
+ <!-- Round Brackets -->
+ <value>round</value>
+ <!-- Square Brackets -->
+ <value>square</value>
+ <!-- Angle Brackets -->
+ <value>angle</value>
+ <!-- Curly Brackets -->
+ <value>curly</value>
+ </choice>
+ </define>
+ <define name="CT_EastAsianLayout">
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="combine">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="combineBrackets">
+ <ref name="ST_CombineBrackets"/>
+ </attribute>
+ <attribute name="vert">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="vertCompress">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_XAlign">
+ <choice>
+ <!-- Left Aligned Horizontally -->
+ <value>left</value>
+ <!-- Centered Horizontally -->
+ <value>center</value>
+ <!-- Right Aligned Horizontally -->
+ <value>right</value>
+ <!-- Inside -->
+ <value>inside</value>
+ <!-- Outside -->
+ <value>outside</value>
+ </choice>
+ </define>
+ <define name="ST_YAlign">
+ <choice>
+ <!-- In line With Text -->
+ <value>inline</value>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Centered Vertically -->
+ <value>center</value>
+ <!-- Bottom -->
+ <value>bottom</value>
+ <!-- Inside Anchor Extents -->
+ <value>inside</value>
+ <!-- Outside Anchor Extents -->
+ <value>outside</value>
+ </choice>
+ </define>
+ <define name="ST_HeightRule">
+ <choice>
+ <!-- Determine Height Based On Contents -->
+ <value>auto</value>
+ <!-- Exact Height -->
+ <value>exact</value>
+ <!-- Minimum Height -->
+ <value>atLeast</value>
+ </choice>
+ </define>
+ <define name="ST_Wrap">
+ <choice>
+ <!-- Default Text Wrapping Around Frame -->
+ <value>auto</value>
+ <!-- No Text Wrapping Beside Frame -->
+ <value>notBeside</value>
+ <!-- Allow Text Wrapping Around Frame -->
+ <value>around</value>
+ <!-- Tight Text Wrapping Around Frame -->
+ <value>tight</value>
+ <!-- Through Text Wrapping Around Frame -->
+ <value>through</value>
+ <!-- No Text Wrapping Around Frame -->
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="ST_VAnchor">
+ <choice>
+ <!-- Relative To Vertical Text Extents -->
+ <value>text</value>
+ <!-- Relative To Margin -->
+ <value>margin</value>
+ <!-- Relative To Page -->
+ <value>page</value>
+ </choice>
+ </define>
+ <define name="ST_HAnchor">
+ <choice>
+ <!-- Relative to Text Extents -->
+ <value>text</value>
+ <!-- Relative To Margin -->
+ <value>margin</value>
+ <!-- Relative to Page -->
+ <value>page</value>
+ </choice>
+ </define>
+ <define name="ST_DropCap">
+ <choice>
+ <!-- Not Drop Cap -->
+ <value>none</value>
+ <!-- Drop Cap Inside Margin -->
+ <value>drop</value>
+ <!-- Drop Cap Outside Margin -->
+ <value>margin</value>
+ </choice>
+ </define>
+ <define name="CT_FramePr">
+ <attribute name="dropCap">
+ <ref name="ST_DropCap"/>
+ </attribute>
+ <attribute name="lines">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="w">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="vSpace">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="hSpace">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="wrap">
+ <ref name="ST_Wrap"/>
+ </attribute>
+ <attribute name="hAnchor">
+ <ref name="ST_HAnchor"/>
+ </attribute>
+ <attribute name="vAnchor">
+ <ref name="ST_VAnchor"/>
+ </attribute>
+ <attribute name="x">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="xAlign">
+ <ref name="ST_XAlign"/>
+ </attribute>
+ <attribute name="y">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="yAlign">
+ <ref name="ST_YAlign"/>
+ </attribute>
+ <attribute name="hRule">
+ <ref name="ST_HeightRule"/>
+ </attribute>
+ <attribute name="anchorLock">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_TabJc">
+ <choice>
+ <!-- No Tab Stop -->
+ <value>clear</value>
+ <!-- Leading Tab -->
+ <value>start</value>
+ <!-- Left Tab (ecma) -->
+ <value>left</value>
+ <!-- Centered Tab -->
+ <value>center</value>
+ <!-- Trailing Tab -->
+ <value>end</value>
+ <!-- Right Tab (ecma) -->
+ <value>right</value>
+ <!-- Decimal Tab -->
+ <value>decimal</value>
+ <!-- Bar Tab -->
+ <value>bar</value>
+ <!-- List Tab -->
+ <value>num</value>
+ </choice>
+ </define>
+ <define name="ST_TabTlc">
+ <choice>
+ <!-- No tab stop leader -->
+ <value>none</value>
+ <!-- Dotted leader line -->
+ <value>dot</value>
+ <!-- Dashed tab stop leader line -->
+ <value>hyphen</value>
+ <!-- Solid leader line -->
+ <value>underscore</value>
+ <!-- Heavy solid leader line -->
+ <value>heavy</value>
+ <!-- Middle dot leader line -->
+ <value>middleDot</value>
+ </choice>
+ </define>
+ <define name="CT_TabStop">
+ <attribute name="val">
+ <ref name="ST_TabJc"/>
+ </attribute>
+ <attribute name="leader">
+ <ref name="ST_TabTlc"/>
+ </attribute>
+ <attribute name="pos">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_LineSpacingRule">
+ <choice>
+ <!-- Automatically Determined Line Height -->
+ <value>auto</value>
+ <!-- Exact Line Height -->
+ <value>exact</value>
+ <!-- Minimum Line Height -->
+ <value>atLeast</value>
+ </choice>
+ </define>
+ <define name="CT_Spacing">
+ <attribute name="before">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="beforeLines">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="beforeAutospacing">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="after">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="afterLines">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="afterAutospacing">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="line">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="lineRule">
+ <ref name="ST_LineSpacingRule"/>
+ </attribute>
+ </define>
+ <define name="CT_Ind">
+ <attribute name="end">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="endChars">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="start">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="startChars">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="left">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="leftChars">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="right">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="rightChars">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="hanging">
+ <ref name="ST_TwipsMeasure_asSigned"/>
+ </attribute>
+ <attribute name="hangingChars">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="firstLine">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="firstLineChars">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_Jc">
+ <choice>
+ <!-- Align To Leading Edge -->
+ <value>start</value>
+ <!-- Align To Trailing Edge -->
+ <value>end</value>
+ <!-- Align Left (ecma) -->
+ <value>left</value>
+ <!-- Align Center -->
+ <value>center</value>
+ <!-- Align Right (ecma) -->
+ <value>right</value>
+ <!-- Justified -->
+ <value>both</value>
+ <!-- Medium Kashida Length -->
+ <value>mediumKashida</value>
+ <!-- Distribute All Characters Equally -->
+ <value>distribute</value>
+ <!-- Align to List Tab -->
+ <value>numTab</value>
+ <!-- Widest Kashida Length -->
+ <value>highKashida</value>
+ <!-- Low Kashida Length -->
+ <value>lowKashida</value>
+ <!-- Thai Language Justification -->
+ <value>thaiDistribute</value>
+ </choice>
+ </define>
+ <define name="CT_Jc">
+ <attribute name="val">
+ <ref name="ST_Jc"/>
+ </attribute>
+ </define>
+ <define name="ST_View">
+ <choice>
+ <!-- Default View -->
+ <value>none</value>
+ <!-- Print Layout View -->
+ <value>print</value>
+ <!-- Outline View -->
+ <value>outline</value>
+ <!-- Master Document View -->
+ <value>masterPages</value>
+ <!-- Draft View -->
+ <value>normal</value>
+ <!-- Web Page View -->
+ <value>web</value>
+ </choice>
+ </define>
+ <define name="CT_View">
+ <attribute name="val">
+ <ref name="ST_View"/>
+ </attribute>
+ </define>
+ <define name="ST_Zoom">
+ <choice>
+ <!-- No Preset Magnification -->
+ <value>none</value>
+ <!-- Display One Full Page -->
+ <value>fullPage</value>
+ <!-- Display Page Width -->
+ <value>bestFit</value>
+ <!-- Display Text Width -->
+ <value>textFit</value>
+ </choice>
+ </define>
+ <define name="ST_Percentage">
+ <data type="int"/>
+ </define>
+ <define name="CT_Zoom">
+ <attribute name="val">
+ <ref name="ST_Zoom"/>
+ </attribute>
+ <attribute name="percent">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_WritingStyle">
+ <attribute name="lang">
+ <data type="string"/>
+ </attribute>
+ <attribute name="vendorID">
+ <data type="string"/>
+ </attribute>
+ <attribute name="dllVersion">
+ <data type="string"/>
+ </attribute>
+ <attribute name="nlCheck">
+ <data type="string"/>
+ </attribute>
+ <attribute name="checkStyle">
+ <data type="string"/>
+ </attribute>
+ <attribute name="appName">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Proof">
+ <attribute name="spelling">
+ <data type="string"/>
+ </attribute>
+ <attribute name="grammar">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_DocType">
+ <choice>
+ <!-- Default Document -->
+ <value>notSpecified</value>
+ <!-- Letter -->
+ <value>letter</value>
+ <!-- E-Mail Message -->
+ <value>eMail</value>
+ </choice>
+ </define>
+ <define name="CT_DocType">
+ <attribute name="val">
+ <ref name="ST_DocType"/>
+ </attribute>
+ </define>
+ <define name="ST_DocProtect">
+ <choice>
+ <!-- No Editing Restrictions -->
+ <value>none</value>
+ <!-- Allow No Editing -->
+ <value>readOnly</value>
+ <!-- Allow Editing of Comments -->
+ <value>comments</value>
+ <!-- Allow Editing With Revision Tracking -->
+ <value>trackedChanges</value>
+ <!-- Allow Editing of Form Fields -->
+ <value>forms</value>
+ </choice>
+ </define>
+ <define name="ST_CryptProv">
+ <choice>
+ <!-- AES Provider -->
+ <value>rsaAES</value>
+ <!-- Any Provider -->
+ <value>rsaFull</value>
+ </choice>
+ </define>
+ <define name="ST_AlgClass">
+ <choice>
+ <!-- Hashing -->
+ <value>hash</value>
+ </choice>
+ </define>
+ <define name="ST_AlgType">
+ <choice>
+ <!-- Any Type -->
+ <value>typeAny</value>
+ </choice>
+ </define>
+ <define name="AG_Password">
+ <attribute name="cryptProviderType">
+ <ref name="ST_CryptProv"/>
+ </attribute>
+ <attribute name="cryptAlgorithmClass">
+ <ref name="ST_AlgClass"/>
+ </attribute>
+ <attribute name="cryptAlgorithmType">
+ <ref name="ST_AlgType"/>
+ </attribute>
+ <attribute name="cryptAlgorithmSid">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cryptSpinCount">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="cryptProvider">
+ <data type="string"/>
+ </attribute>
+ <attribute name="algIdExt">
+ <data type="string"/>
+ </attribute>
+ <attribute name="algIdExtSource">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cryptProviderTypeExt">
+ <data type="string"/>
+ </attribute>
+ <attribute name="cryptProviderTypeExtSource">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hash">
+ <data type="base64Binary"/>
+ </attribute>
+ <attribute name="salt">
+ <data type="base64Binary"/>
+ </attribute>
+ </define>
+ <define name="CT_DocProtect">
+ <attribute name="edit">
+ <ref name="ST_DocProtect"/>
+ </attribute>
+ <attribute name="formatting">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="enforcement">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <ref name="AG_Password"/>
+ </define>
+ <define name="CT_MailMergeDocType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_MailMergeDataType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_MailMergeDest">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_MailMergeOdsoFMDFieldType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_TrackChangesView">
+ <attribute name="markup">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="comments">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="insDel">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="formatting">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="inkAnnotations">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_Kinsoku">
+ <attribute name="lang">
+ <ref name="ST_Lang"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="ST_TextDirection">
+ <choice>
+ <!-- Left to Right, Top to Bottom -->
+ <value>lrTb</value>
+ <!-- Top to Bottom, Right to Left -->
+ <value>tbRl</value>
+ <!-- Bottom to Top, Left to Right -->
+ <value>btLr</value>
+ <!-- Left to Right, Top to Bottom Rotated -->
+ <value>lrTbV</value>
+ <!-- Top to Bottom, Right to Left Rotated -->
+ <value>tbRlV</value>
+ <!-- Top to Bottom, Left to Right Rotated -->
+ <value>tbLrV</value>
+ </choice>
+ </define>
+ <define name="CT_TextDirection">
+ <attribute name="val">
+ <ref name="ST_TextDirection"/>
+ </attribute>
+ </define>
+ <define name="ST_TextAlignment">
+ <choice>
+ <!-- Align Text at Top -->
+ <value>top</value>
+ <!-- Align Text at Center -->
+ <value>center</value>
+ <!-- Align Text at Baseline -->
+ <value>baseline</value>
+ <!-- Align Text at Bottom -->
+ <value>bottom</value>
+ <!-- Automatically Determine Alignment -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="CT_TextAlignment">
+ <attribute name="val">
+ <ref name="ST_TextAlignment"/>
+ </attribute>
+ </define>
+ <define name="ST_DisplacedByCustomXml">
+ <choice>
+ <!-- Displaced by Next Custom XML Markup Tag -->
+ <value>next</value>
+ <!-- Displaced by Previous Custom XML Markup Tag -->
+ <value>prev</value>
+ </choice>
+ </define>
+ <define name="ST_AnnotationVMerge">
+ <choice>
+ <!-- Vertically Merged Cell -->
+ <value>cont</value>
+ <!-- Vertically Split Cell -->
+ <value>rest</value>
+ </choice>
+ </define>
+ <define name="CT_Markup">
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_TrackChange">
+ <ref name="CT_Markup"/>
+ <attribute name="author">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="date">
+ <ref name="ST_DateTime"/>
+ </attribute>
+ </define>
+ <define name="CT_CellMergeTrackChange">
+ <ref name="CT_TrackChange"/>
+ <attribute name="vMerge">
+ <ref name="ST_AnnotationVMerge"/>
+ </attribute>
+ <attribute name="vMergeOrig">
+ <ref name="ST_AnnotationVMerge"/>
+ </attribute>
+ </define>
+ <define name="CT_TrackChangeRange">
+ <ref name="CT_TrackChange"/>
+ <attribute name="displacedByCustomXml">
+ <ref name="ST_DisplacedByCustomXml"/>
+ </attribute>
+ </define>
+ <define name="CT_MarkupRange">
+ <ref name="CT_Markup"/>
+ <attribute name="displacedByCustomXml">
+ <ref name="ST_DisplacedByCustomXml"/>
+ </attribute>
+ </define>
+ <define name="CT_MarkupRangeBookmark">
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ <ref name="CT_MarkupRange"/>
+ </define>
+ <define name="CT_MarkupRangePerm">
+ <ref name="CT_MarkupRange"/>
+ </define>
+ <define name="CT_MarkupRangeCommentStart">
+ <ref name="CT_Markup"/>
+ </define>
+ <define name="CT_MarkupRangeCommentEnd">
+ <ref name="CT_Markup"/>
+ </define>
+ <define name="CT_BookmarkRange">
+ <ref name="CT_MarkupRangeBookmark"/>
+ <attribute name="colFirst">
+ <data type="string"/>
+ </attribute>
+ <attribute name="colLast">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Bookmark">
+ <ref name="CT_BookmarkRange"/>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_MoveBookmark">
+ <ref name="CT_Bookmark"/>
+ <attribute name="author">
+ <data type="string"/>
+ </attribute>
+ <attribute name="date">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Comment">
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <ref name="CT_TrackChange"/>
+ <ref name="EG_BlockLevelElts"/>
+ <attribute name="initials">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_PermStart">
+ <ref name="CT_MarkupRangePerm"/>
+ <attribute name="ed">
+ <data type="string"/>
+ </attribute>
+ <attribute name="edGrp">
+ <data type="string"/>
+ </attribute>
+ <attribute name="colFirst">
+ <data type="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="colLast">
+ <data type="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_PermEnd">
+ <ref name="CT_MarkupRangePerm"/>
+ </define>
+ <define name="CT_TrackChangeNumbering">
+ <ref name="CT_TrackChange"/>
+ <attribute name="original">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_TblPrExChange">
+ <ref name="CT_TrackChange"/>
+ <element name="tblPrEx">
+ <ref name="CT_TblPrExBase"/>
+ </element>
+ </define>
+ <define name="CT_TcPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="tcPr">
+ <ref name="CT_TcPrInner"/>
+ </element>
+ </define>
+ <define name="CT_TrPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="trPr">
+ <ref name="CT_TrPrBase"/>
+ </element>
+ </define>
+ <define name="CT_TblGridChange">
+ <ref name="CT_Markup"/>
+ <element name="tblGrid">
+ <ref name="CT_TblGridBase"/>
+ </element>
+ </define>
+ <define name="CT_TblPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="tblPr">
+ <ref name="CT_TblPrBase"/>
+ </element>
+ </define>
+ <define name="CT_SectPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="sectPr">
+ <ref name="CT_SectPrBase"/>
+ </element>
+ </define>
+ <define name="CT_PPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="pPr">
+ <ref name="CT_PPrBase"/>
+ </element>
+ </define>
+ <define name="CT_RPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="rPr">
+ <ref name="CT_RPrOriginal"/>
+ </element>
+ </define>
+ <define name="CT_ParaRPrChange">
+ <ref name="CT_TrackChange"/>
+ <element name="rPr">
+ <ref name="CT_ParaRPrOriginal"/>
+ </element>
+ </define>
+ <define name="CT_RunTrackChange">
+ <ref name="CT_TrackChange"/>
+ <choice>
+ <ref name="EG_ContentRunContent"/>
+ <ref name="EG_OMathMathElements"/>
+ </choice>
+ </define>
+ <define name="EG_CellMarkupElements">
+ <choice>
+ <element name="cellIns">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="cellDel">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="cellMerge">
+ <ref name="CT_CellMergeTrackChange"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_RangeMarkupElements">
+ <choice>
+ <element name="bookmarkStart">
+ <ref name="CT_Bookmark"/>
+ </element>
+ <element name="bookmarkEnd">
+ <ref name="CT_MarkupRangeBookmark"/>
+ </element>
+ <element name="permStart">
+ <ref name="CT_PermStart"/>
+ </element>
+ <element name="permEnd">
+ <ref name="CT_PermEnd"/>
+ </element>
+ <element name="moveFromRangeStart">
+ <ref name="CT_MoveBookmark"/>
+ </element>
+ <element name="moveFromRangeEnd">
+ <ref name="CT_MarkupRangeBookmark"/>
+ </element>
+ <element name="moveToRangeStart">
+ <ref name="CT_MoveBookmark"/>
+ </element>
+ <element name="moveToRangeEnd">
+ <ref name="CT_MarkupRangeBookmark"/>
+ </element>
+ <element name="commentRangeStart">
+ <ref name="CT_MarkupRangeCommentStart"/>
+ </element>
+ <element name="commentRangeEnd">
+ <ref name="CT_MarkupRangeCommentEnd"/>
+ </element>
+ <element name="customXmlInsRangeStart">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="customXmlInsRangeEnd">
+ <ref name="CT_Markup"/>
+ </element>
+ <element name="customXmlDelRangeStart">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="customXmlDelRangeEnd">
+ <ref name="CT_Markup"/>
+ </element>
+ <element name="customXmlMoveFromRangeStart">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="customXmlMoveFromRangeEnd">
+ <ref name="CT_Markup"/>
+ </element>
+ <element name="customXmlMoveToRangeStart">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="customXmlMoveToRangeEnd">
+ <ref name="CT_Markup"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_NumPr">
+ <element name="ilvl">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="numId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="numberingChange">
+ <ref name="CT_TrackChangeNumbering"/>
+ </element>
+ <element name="ins">
+ <ref name="CT_TrackChange"/>
+ </element>
+ </define>
+ <define name="CT_PBdr">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="between">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bar">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_Tabs">
+ <element name="tab">
+ <ref name="CT_TabStop"/>
+ </element>
+ </define>
+ <define name="CT_TextboxTightWrap">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_PPrBase">
+ <element name="pStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="keepNext">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="keepLines">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="pageBreakBefore">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="framePr">
+ <ref name="CT_FramePr"/>
+ </element>
+ <element name="widowControl">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="numPr">
+ <ref name="CT_NumPr"/>
+ </element>
+ <element name="suppressLineNumbers">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="pBdr">
+ <ref name="CT_PBdr"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="tabs">
+ <ref name="CT_Tabs"/>
+ </element>
+ <element name="suppressAutoHyphens">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="kinsoku">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wordWrap">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="overflowPunct">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="topLinePunct">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="autoSpaceDE">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="autoSpaceDN">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bidi">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="adjustRightInd">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="snapToGrid">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="spacing">
+ <ref name="CT_Spacing"/>
+ </element>
+ <element name="ind">
+ <ref name="CT_Ind"/>
+ </element>
+ <element name="contextualSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="mirrorIndents">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressOverlap">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="textDirection">
+ <ref name="CT_TextDirection"/>
+ </element>
+ <element name="textAlignment">
+ <ref name="CT_TextAlignment"/>
+ </element>
+ <element name="textboxTightWrap">
+ <ref name="CT_TextboxTightWrap"/>
+ </element>
+ <element name="outlineLvl">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="divId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="cnfStyle">
+ <ref name="CT_Cnf"/>
+ </element>
+ </define>
+ <define name="CT_PPr">
+ <ref name="CT_PPrBase"/>
+ <element name="rPr">
+ <ref name="CT_ParaRPr"/>
+ </element>
+ <element name="sectPr">
+ <ref name="CT_SectPr"/>
+ </element>
+ <element name="pPrChange">
+ <ref name="CT_PPrChange"/>
+ </element>
+ </define>
+ <define name="CT_Background">
+ <ref name="CT_PictureBase"/>
+ <attribute name="color">
+ <ref name="ST_HexColor"/>
+ </attribute>
+ <attribute name="themeColor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="themeTint">
+ <data type="string"/>
+ </attribute>
+ <attribute name="themeShade">
+ <data type="string"/>
+ </attribute>
+ <element name="v:background">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </define>
+ <define name="CT_Rel">
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureBase">
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </define>
+ <define name="CT_Object">
+ <ref name="CT_PictureBase"/>
+ <attribute name="dxaOrig">
+ <data type="string"/>
+ </attribute>
+ <attribute name="dyaOrig">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Picture">
+ <ref name="CT_PictureBase"/>
+ <element name="movie">
+ <ref name="CT_Rel"/>
+ </element>
+ </define>
+ <define name="CT_Drawing">
+ <choice>
+ <ref name="anchor"/>
+ <ref name="inline"/>
+ </choice>
+ </define>
+ <define name="CT_SimpleField">
+ <element name="fldData">
+ <ref name="CT_FLDData"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="instr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fldLock">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="dirty">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_FldCharType">
+ <choice>
+ <!-- Start Character -->
+ <value>begin</value>
+ <!-- Separator Character -->
+ <value>separate</value>
+ <!-- End Character -->
+ <value>end</value>
+ </choice>
+ </define>
+ <define name="ST_InfoTextType">
+ <choice>
+ <!-- Literal Text -->
+ <value>text</value>
+ <!-- Glossary Document Entry -->
+ <value>autoText</value>
+ </choice>
+ </define>
+ <define name="ST_FFName">
+ <data type="string"/>
+ </define>
+ <define name="CT_FFTextType">
+ <attribute name="val">
+ <ref name="ST_FFName"/>
+ </attribute>
+ </define>
+ <define name="CT_FFName">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FldChar">
+ <choice>
+ <element name="fldData">
+ <ref name="CT_FLDData"/>
+ </element>
+ <element name="ffData">
+ <ref name="CT_FFData"/>
+ </element>
+ <element name="numberingChange">
+ <ref name="CT_TrackChangeNumbering"/>
+ </element>
+ </choice>
+ <attribute name="fldCharType">
+ <ref name="ST_FldCharType"/>
+ </attribute>
+ <attribute name="fldLock">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="dirty">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Hyperlink">
+ <ref name="EG_PContent"/>
+ <attribute name="tgtFrame">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tooltip">
+ <data type="string"/>
+ </attribute>
+ <attribute name="docLocation">
+ <data type="string"/>
+ </attribute>
+ <attribute name="history">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="anchor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_FLDData">
+ <ref name="ST_String"/>
+ </define>
+ <define name="CT_FFData">
+ <choice>
+ <element name="name">
+ <ref name="CT_FFName"/>
+ </element>
+ <element name="enabled">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="calcOnExit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="entryMacro">
+ <ref name="CT_MacroName"/>
+ </element>
+ <element name="exitMacro">
+ <ref name="CT_MacroName"/>
+ </element>
+ <element name="helpText">
+ <ref name="CT_FFHelpText"/>
+ </element>
+ <element name="statusText">
+ <ref name="CT_FFStatusText"/>
+ </element>
+ <element name="checkBox">
+ <ref name="CT_FFCheckBox"/>
+ </element>
+ <element name="ddList">
+ <ref name="CT_FFDDList"/>
+ </element>
+ <element name="textInput">
+ <ref name="CT_FFTextInput"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_FFHelpText">
+ <attribute name="type">
+ <ref name="ST_InfoTextType"/>
+ </attribute>
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FFStatusText">
+ <attribute name="type">
+ <ref name="ST_InfoTextType"/>
+ </attribute>
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FFCheckBox">
+ <choice>
+ <element name="size">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="sizeAuto">
+ <ref name="CT_OnOff"/>
+ </element>
+ </choice>
+ <element name="default">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="checked">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_FFDDList">
+ <element name="result">
+ <ref name="CT_String"/>
+ </element>
+ <element name="default">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="listEntry">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_FFTextInput">
+ <element name="type">
+ <ref name="CT_FFTextType"/>
+ </element>
+ <element name="default">
+ <ref name="CT_String"/>
+ </element>
+ <element name="maxLength">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="format">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="ST_SectionMark">
+ <choice>
+ <!-- Next Page Section Break -->
+ <value>nextPage</value>
+ <!-- Column Section Break -->
+ <value>nextColumn</value>
+ <!-- Continuous Section Break -->
+ <value>continuous</value>
+ <!-- Even Page Section Break -->
+ <value>evenPage</value>
+ <!-- Odd Page Section Break -->
+ <value>oddPage</value>
+ </choice>
+ </define>
+ <define name="CT_SectType">
+ <attribute name="val">
+ <ref name="ST_SectionMark"/>
+ </attribute>
+ </define>
+ <define name="CT_PaperSource">
+ <attribute name="first">
+ <data type="string"/>
+ </attribute>
+ <attribute name="other">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_NumberFormat">
+ <choice>
+ <!-- Decimal Numbers -->
+ <value>decimal</value>
+ <!-- Uppercase Roman Numerals -->
+ <value>upperRoman</value>
+ <!-- Lowercase Roman Numerals -->
+ <value>lowerRoman</value>
+ <!-- Uppercase Latin Alphabet -->
+ <value>upperLetter</value>
+ <!-- Lowercase Latin Alphabet -->
+ <value>lowerLetter</value>
+ <!-- Ordinal -->
+ <value>ordinal</value>
+ <!-- Cardinal Text -->
+ <value>cardinalText</value>
+ <!-- Ordinal Text -->
+ <value>ordinalText</value>
+ <!-- Hexadecimal Numbering -->
+ <value>hex</value>
+ <!-- Chicago Manual of Style -->
+ <value>chicago</value>
+ <!-- Ideographs -->
+ <value>ideographDigital</value>
+ <!-- Japanese Counting System -->
+ <value>japaneseCounting</value>
+ <!-- AIUEO Order Hiragana -->
+ <value>aiueo</value>
+ <!-- Iroha Ordered Katakana -->
+ <value>iroha</value>
+ <!-- Double Byte Arabic Numerals -->
+ <value>decimalFullWidth</value>
+ <!-- Single Byte Arabic Numerals -->
+ <value>decimalHalfWidth</value>
+ <!-- Japanese Legal Numbering -->
+ <value>japaneseLegal</value>
+ <!-- Japanese Digital Ten Thousand Counting System -->
+ <value>japaneseDigitalTenThousand</value>
+ <!-- Decimal Numbers Enclosed in a Circle -->
+ <value>decimalEnclosedCircle</value>
+ <!-- Double Byte Arabic Numerals Alternate -->
+ <value>decimalFullWidth2</value>
+ <!-- Full-Width AIUEO Order Hiragana -->
+ <value>aiueoFullWidth</value>
+ <!-- Full-Width Iroha Ordered Katakana -->
+ <value>irohaFullWidth</value>
+ <!-- Initial Zero Arabic Numerals -->
+ <value>decimalZero</value>
+ <!-- Bullet -->
+ <value>bullet</value>
+ <!-- Korean Ganada Numbering -->
+ <value>ganada</value>
+ <!-- Korean Chosung Numbering -->
+ <value>chosung</value>
+ <!-- Decimal Numbers Followed by a Period -->
+ <value>decimalEnclosedFullstop</value>
+ <!-- Decimal Numbers Enclosed in Parenthesis -->
+ <value>decimalEnclosedParen</value>
+ <!-- Decimal Numbers Enclosed in a Circle -->
+ <value>decimalEnclosedCircleChinese</value>
+ <!-- Ideographs Enclosed in a Circle -->
+ <value>ideographEnclosedCircle</value>
+ <!-- Traditional Ideograph Format -->
+ <value>ideographTraditional</value>
+ <!-- Zodiac Ideograph Format -->
+ <value>ideographZodiac</value>
+ <!-- Traditional Zodiac Ideograph Format -->
+ <value>ideographZodiacTraditional</value>
+ <!-- Taiwanese Counting System -->
+ <value>taiwaneseCounting</value>
+ <!-- Traditional Legal Ideograph Format -->
+ <value>ideographLegalTraditional</value>
+ <!-- Taiwanese Counting Thousand System -->
+ <value>taiwaneseCountingThousand</value>
+ <!-- Taiwanese Digital Counting System -->
+ <value>taiwaneseDigital</value>
+ <!-- Chinese Counting System -->
+ <value>chineseCounting</value>
+ <!-- Chinese Legal Simplified Format -->
+ <value>chineseLegalSimplified</value>
+ <!-- Chinese Counting Thousand System -->
+ <value>chineseCountingThousand</value>
+ <!-- Korean Digital Counting System -->
+ <value>koreanDigital</value>
+ <!-- Korean Counting System -->
+ <value>koreanCounting</value>
+ <!-- Korean Legal Numbering -->
+ <value>koreanLegal</value>
+ <!-- Korean Digital Counting System Alternate -->
+ <value>koreanDigital2</value>
+ <!-- Vietnamese Numerals -->
+ <value>vietnameseCounting</value>
+ <!-- Lowercase Russian Alphabet -->
+ <value>russianLower</value>
+ <!-- Uppercase Russian Alphabet -->
+ <value>russianUpper</value>
+ <!-- No Numbering -->
+ <value>none</value>
+ <!-- Number With Dashes -->
+ <value>numberInDash</value>
+ <!-- Hebrew Numerals -->
+ <value>hebrew1</value>
+ <!-- Hebrew Alphabet -->
+ <value>hebrew2</value>
+ <!-- Arabic Alphabet -->
+ <value>arabicAlpha</value>
+ <!-- Arabic Abjad Numerals -->
+ <value>arabicAbjad</value>
+ <!-- Hindi Vowels -->
+ <value>hindiVowels</value>
+ <!-- Hindi Consonants -->
+ <value>hindiConsonants</value>
+ <!-- Hindi Numbers -->
+ <value>hindiNumbers</value>
+ <!-- Hindi Counting System -->
+ <value>hindiCounting</value>
+ <!-- Thai Letters -->
+ <value>thaiLetters</value>
+ <!-- Thai Numerals -->
+ <value>thaiNumbers</value>
+ <!-- Thai Counting System -->
+ <value>thaiCounting</value>
+ <value>custom</value>
+ </choice>
+ </define>
+ <define name="ST_PageOrientation">
+ <choice>
+ <!-- Portrait Mode -->
+ <value>portrait</value>
+ <!-- Landscape Mode -->
+ <value>landscape</value>
+ </choice>
+ </define>
+ <define name="CT_PageSz">
+ <attribute name="w">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="orient">
+ <ref name="ST_PageOrientation"/>
+ </attribute>
+ <attribute name="code">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_PageMar">
+ <attribute name="top">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="right">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="bottom">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="left">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="header">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="footer">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="gutter">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_PageBorderZOrder">
+ <choice>
+ <!-- Page Border Ahead of Text -->
+ <value>front</value>
+ <!-- Page Border Behind Text -->
+ <value>back</value>
+ </choice>
+ </define>
+ <define name="ST_PageBorderDisplay">
+ <choice>
+ <!-- Display Page Border on All Pages -->
+ <value>allPages</value>
+ <!-- Display Page Border on First Page -->
+ <value>firstPage</value>
+ <!-- Display Page Border on All Pages Except First -->
+ <value>notFirstPage</value>
+ </choice>
+ </define>
+ <define name="ST_PageBorderOffset">
+ <choice>
+ <!-- Page Border Is Positioned Relative to Page Edges -->
+ <value>page</value>
+ <!-- Page Border Is Positioned Relative to Text Extents -->
+ <value>text</value>
+ </choice>
+ </define>
+ <define name="CT_PageBorders">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ <attribute name="zOrder">
+ <ref name="ST_PageBorderZOrder"/>
+ </attribute>
+ <attribute name="display">
+ <ref name="ST_PageBorderDisplay"/>
+ </attribute>
+ <attribute name="offsetFrom">
+ <ref name="ST_PageBorderOffset"/>
+ </attribute>
+ </define>
+ <define name="ST_ChapterSep">
+ <choice>
+ <!-- Hyphen Chapter Separator -->
+ <value>hyphen</value>
+ <!-- Period Chapter Separator -->
+ <value>period</value>
+ <!-- Colon Chapter Separator -->
+ <value>colon</value>
+ <!-- Em Dash Chapter Separator -->
+ <value>emDash</value>
+ <!-- En Dash Chapter Separator -->
+ <value>enDash</value>
+ </choice>
+ </define>
+ <define name="ST_LineNumberRestart">
+ <choice>
+ <!-- Restart Line Numbering on Each Page -->
+ <value>newPage</value>
+ <!-- Restart Line Numbering for Each Section -->
+ <value>newSection</value>
+ <!-- Continue Line Numbering From Previous Section -->
+ <value>continuous</value>
+ </choice>
+ </define>
+ <define name="CT_LineNumber">
+ <attribute name="countBy">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="start">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="distance">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="restart">
+ <ref name="ST_LineNumberRestart"/>
+ </attribute>
+ </define>
+ <define name="CT_PageNumber">
+ <attribute name="fmt">
+ <ref name="ST_NumberFormat"/>
+ </attribute>
+ <attribute name="start">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="chapStyle">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="chapSep">
+ <ref name="ST_ChapterSep"/>
+ </attribute>
+ </define>
+ <define name="CT_Column">
+ <attribute name="w">
+ <ref name="ST_TwipsMeasure_asZero"/>
+ </attribute>
+ <attribute name="space">
+ <ref name="ST_TwipsMeasure_asZero"/>
+ </attribute>
+ </define>
+ <define name="CT_Columns">
+ <element name="col">
+ <ref name="CT_Column"/>
+ </element>
+ <attribute name="equalWidth">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="space">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ <attribute name="num">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="sep">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_VerticalJc">
+ <choice>
+ <!-- Align Top -->
+ <value>top</value>
+ <!-- Align Center -->
+ <value>center</value>
+ <!-- Vertical Justification -->
+ <value>both</value>
+ <!-- Align Bottom -->
+ <value>bottom</value>
+ </choice>
+ </define>
+ <define name="CT_VerticalJc">
+ <attribute name="val">
+ <ref name="ST_VerticalJc"/>
+ </attribute>
+ </define>
+ <define name="ST_DocGrid">
+ <choice>
+ <!-- No Document Grid -->
+ <value>default</value>
+ <!-- Line Grid Only -->
+ <value>lines</value>
+ <!-- Line and Character Grid -->
+ <value>linesAndChars</value>
+ <!-- Character Grid Only -->
+ <value>snapToChars</value>
+ </choice>
+ </define>
+ <define name="CT_DocGrid">
+ <attribute name="type">
+ <ref name="ST_DocGrid"/>
+ </attribute>
+ <attribute name="linePitch">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="charSpace">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_HdrFtr">
+ <choice>
+ <!-- Even Numbered Pages Only -->
+ <value>even</value>
+ <!-- Default Header or Footer -->
+ <value>default</value>
+ <!-- First Page Only -->
+ <value>first</value>
+ </choice>
+ </define>
+ <define name="ST_FtnEdn">
+ <choice>
+ <!-- Normal Footnote/Endnote -->
+ <value>normal</value>
+ <!-- Separator -->
+ <value>separator</value>
+ <!-- Continuation Separator -->
+ <value>continuationSeparator</value>
+ <!-- Continuation Notice Separator -->
+ <value>continuationNotice</value>
+ </choice>
+ </define>
+ <define name="CT_HdrFtrRef">
+ <attribute name="type">
+ <ref name="ST_HdrFtr"/>
+ </attribute>
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="EG_HdrFtrReferences">
+ <choice>
+ <element name="headerReference">
+ <ref name="CT_HdrFtrRef"/>
+ </element>
+ <element name="footerReference">
+ <ref name="CT_HdrFtrRef"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_HdrFtr">
+ <ref name="EG_BlockLevelElts"/>
+ </define>
+ <define name="EG_SectPrContents">
+ <element name="footnotePr">
+ <ref name="CT_FtnProps"/>
+ </element>
+ <element name="endnotePr">
+ <ref name="CT_EdnProps"/>
+ </element>
+ <element name="type">
+ <ref name="CT_SectType"/>
+ </element>
+ <element name="pgSz">
+ <ref name="CT_PageSz"/>
+ </element>
+ <element name="pgMar">
+ <ref name="CT_PageMar"/>
+ </element>
+ <element name="paperSrc">
+ <ref name="CT_PaperSource"/>
+ </element>
+ <element name="pgBorders">
+ <ref name="CT_PageBorders"/>
+ </element>
+ <element name="lnNumType">
+ <ref name="CT_LineNumber"/>
+ </element>
+ <element name="pgNumType">
+ <ref name="CT_PageNumber"/>
+ </element>
+ <element name="cols">
+ <ref name="CT_Columns"/>
+ </element>
+ <element name="formProt">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="vAlign">
+ <ref name="CT_VerticalJc"/>
+ </element>
+ <element name="noEndnote">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="titlePg">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="textDirection">
+ <ref name="CT_TextDirection"/>
+ </element>
+ <element name="bidi">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rtlGutter">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="docGrid">
+ <ref name="CT_DocGrid"/>
+ </element>
+ <element name="printerSettings">
+ <ref name="CT_Rel"/>
+ </element>
+ </define>
+ <define name="AG_SectPrAttributes">
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidSect">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SectPrBase">
+ <ref name="EG_SectPrContents"/>
+ <ref name="AG_SectPrAttributes"/>
+ </define>
+ <define name="CT_SectPr">
+ <ref name="EG_HdrFtrReferences"/>
+ <ref name="EG_SectPrContents"/>
+ <element name="sectPrChange">
+ <ref name="CT_SectPrChange"/>
+ </element>
+ <ref name="AG_SectPrAttributes"/>
+ </define>
+ <define name="CT_finalSectPr">
+ <ref name="EG_HdrFtrReferences"/>
+ <ref name="EG_SectPrContents"/>
+ <element name="sectPrChange">
+ <ref name="CT_SectPrChange"/>
+ </element>
+ <ref name="AG_SectPrAttributes"/>
+ </define>
+ <define name="ST_BrType">
+ <choice>
+ <!-- Page Break -->
+ <value>page</value>
+ <!-- Column Break -->
+ <value>column</value>
+ <!-- Line Break -->
+ <value>textWrapping</value>
+ </choice>
+ </define>
+ <define name="ST_BrClear">
+ <choice>
+ <!-- Restart On Next Line -->
+ <value>none</value>
+ <!-- Restart In Next Text Region When In Leftmost Position -->
+ <value>left</value>
+ <!-- Restart In Next Text Region When In Rightmost Position -->
+ <value>right</value>
+ <!-- Restart On Next Full Line -->
+ <value>all</value>
+ </choice>
+ </define>
+ <define name="CT_Br">
+ <attribute name="type">
+ <ref name="ST_BrType"/>
+ </attribute>
+ <attribute name="clear">
+ <ref name="ST_BrClear"/>
+ </attribute>
+ </define>
+ <define name="CT_Br_OutOfOrder">
+ <attribute name="type">
+ <ref name="ST_BrType"/>
+ </attribute>
+ <attribute name="clear">
+ <ref name="ST_BrClear"/>
+ </attribute>
+ </define>
+ <define name="ST_PTabAlignment">
+ <choice>
+ <!-- Left -->
+ <value>left</value>
+ <!-- Center -->
+ <value>center</value>
+ <!-- Right -->
+ <value>right</value>
+ </choice>
+ </define>
+ <define name="ST_PTabRelativeTo">
+ <choice>
+ <!-- Relative To Text Margins -->
+ <value>margin</value>
+ <!-- Relative To Indents -->
+ <value>indent</value>
+ </choice>
+ </define>
+ <define name="ST_PTabLeader">
+ <choice>
+ <!-- No Leader Character -->
+ <value>none</value>
+ <!-- Dot Leader Character -->
+ <value>dot</value>
+ <!-- Hyphen Leader Character -->
+ <value>hyphen</value>
+ <!-- Underscore Leader Character -->
+ <value>underscore</value>
+ <!-- Centered Dot Leader Character -->
+ <value>middleDot</value>
+ </choice>
+ </define>
+ <define name="CT_PTab">
+ <attribute name="alignment">
+ <ref name="ST_PTabAlignment"/>
+ </attribute>
+ <attribute name="relativeTo">
+ <ref name="ST_PTabRelativeTo"/>
+ </attribute>
+ <attribute name="leader">
+ <ref name="ST_PTabLeader"/>
+ </attribute>
+ </define>
+ <define name="CT_Sym">
+ <attribute name="font">
+ <data type="string"/>
+ </attribute>
+ <attribute name="char">
+ <ref name="ST_ShortHexNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_ProofErr">
+ <attribute name="type">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Text">
+ <ref name="ST_String"/>
+ <attribute name="xml:space">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdnRefChar">
+ </define>
+ <define name="CT_FtnEdnSep">
+ </define>
+ <define name="CT_FtnEdnCont">
+ </define>
+ <define name="CT_PgNum">
+ </define>
+ <define name="CT_Cr">
+ </define>
+ <define name="CT_Tab">
+ </define>
+ <define name="EG_RunInnerContent">
+ <choice>
+ <element name="br">
+ <ref name="CT_Br"/>
+ </element>
+ <element name="t">
+ <ref name="CT_Text"/>
+ </element>
+ <element name="delText">
+ <ref name="CT_Text"/>
+ </element>
+ <element name="instrText">
+ <ref name="CT_Text"/>
+ </element>
+ <element name="delInstrText">
+ <ref name="CT_Text"/>
+ </element>
+ <element name="noBreakHyphen">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="softHyphen">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="dayShort">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="monthShort">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="yearShort">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="dayLong">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="monthLong">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="yearLong">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="annotationRef">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="footnoteRef">
+ <ref name="CT_FtnEdnRefChar"/>
+ </element>
+ <element name="endnoteRef">
+ <ref name="CT_FtnEdnRefChar"/>
+ </element>
+ <element name="separator">
+ <ref name="CT_FtnEdnSep"/>
+ </element>
+ <element name="continuationSeparator">
+ <ref name="CT_FtnEdnCont"/>
+ </element>
+ <element name="sym">
+ <ref name="CT_Sym"/>
+ </element>
+ <element name="pgNum">
+ <ref name="CT_PgNum"/>
+ </element>
+ <element name="cr">
+ <ref name="CT_Cr"/>
+ </element>
+ <element name="tab">
+ <ref name="CT_Tab"/>
+ </element>
+ <element name="object">
+ <ref name="CT_Object"/>
+ </element>
+ <element name="pict">
+ <ref name="CT_Picture"/>
+ </element>
+ <element name="fldChar">
+ <ref name="CT_FldChar"/>
+ </element>
+ <element name="ruby">
+ <ref name="CT_Ruby"/>
+ </element>
+ <element name="footnoteReference">
+ <ref name="CT_FtnEdnRef"/>
+ </element>
+ <element name="endnoteReference">
+ <ref name="CT_FtnEdnRef"/>
+ </element>
+ <element name="commentReference">
+ <ref name="CT_CommentRef"/>
+ </element>
+ <element name="drawing">
+ <ref name="CT_Drawing"/>
+ </element>
+ <element name="ptab">
+ <ref name="CT_PTab"/>
+ </element>
+ <element name="lastRenderedPageBreak">
+ <ref name="CT_Empty"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_R">
+ <ref name="EG_RPr"/>
+ <ref name="EG_RunInnerContent"/>
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_Hint">
+ <choice>
+ <!-- High ANSI Font -->
+ <value>default</value>
+ <!-- East Asian Font -->
+ <value>eastAsia</value>
+ <!-- Complex Script Font -->
+ <value>cs</value>
+ </choice>
+ </define>
+ <define name="ST_Theme">
+ <choice>
+ <!-- Major East Asian Theme Font -->
+ <value>majorEastAsia</value>
+ <!-- Major Complex Script Theme Font -->
+ <value>majorBidi</value>
+ <!-- Major ASCII Theme Font -->
+ <value>majorAscii</value>
+ <!-- Major High ANSI Theme Font -->
+ <value>majorHAnsi</value>
+ <!-- Minor East Asian Theme Font -->
+ <value>minorEastAsia</value>
+ <!-- Minor Complex Script Theme Font -->
+ <value>minorBidi</value>
+ <!-- Minor ASCII Theme Font -->
+ <value>minorAscii</value>
+ <!-- Minor High ANSI Theme Font -->
+ <value>minorHAnsi</value>
+ </choice>
+ </define>
+ <define name="CT_Fonts">
+ <attribute name="hint">
+ <ref name="ST_Hint"/>
+ </attribute>
+ <attribute name="ascii">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="hAnsi">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="eastAsia">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="cs">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="asciiTheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ <attribute name="hAnsiTheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ <attribute name="eastAsiaTheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ <attribute name="cstheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ </define>
+ <define name="EG_RPrBase">
+ <element name="rStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="rFonts">
+ <ref name="CT_Fonts"/>
+ </element>
+ <element name="b">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bCs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="i">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="iCs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="caps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="smallCaps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strike">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dstrike">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="outline">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="shadow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="emboss">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="imprint">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noProof">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="snapToGrid">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="vanish">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="webHidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="color">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="spacing">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="w">
+ <ref name="CT_TextScale"/>
+ </element>
+ <element name="kern">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="position">
+ <ref name="CT_SignedHpsMeasure"/>
+ </element>
+ <element name="sz">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="szCs">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="highlight">
+ <ref name="CT_Highlight"/>
+ </element>
+ <element name="u">
+ <ref name="CT_Underline"/>
+ </element>
+ <element name="effect">
+ <ref name="CT_TextEffect"/>
+ </element>
+ <element name="bdr">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="fitText">
+ <ref name="CT_FitText"/>
+ </element>
+ <element name="vertAlign">
+ <ref name="CT_VerticalAlignRun"/>
+ </element>
+ <element name="rtl">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="cs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="em">
+ <ref name="CT_Em"/>
+ </element>
+ <element name="lang">
+ <ref name="CT_Language"/>
+ </element>
+ <element name="eastAsianLayout">
+ <ref name="CT_EastAsianLayout"/>
+ </element>
+ <element name="specVanish">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="oMath">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="w14:glow">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:shadow">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:reflection">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:textOutline">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:textFill">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:scene3d">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:props3d">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:ligatures">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:numForm">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:numSpacing">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:stylisticSets">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:cntxtAlts">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </define>
+ <define name="EG_RPrContent">
+ <ref name="EG_RPrBase"/>
+ <element name="rPrChange">
+ <ref name="CT_RPrChange"/>
+ </element>
+ </define>
+ <define name="CT_RPr">
+ <ref name="EG_RPrContent"/>
+ </define>
+ <define name="EG_RPr">
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ </define>
+ <define name="EG_RPrMath">
+ <choice>
+ <ref name="EG_RPr"/>
+ <element name="ins">
+ <ref name="CT_RPrChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_RPrChange"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_RPrOriginal">
+ <ref name="EG_RPrBase"/>
+ </define>
+ <define name="CT_ParaRPrOriginal">
+ <ref name="EG_ParaRPrTrackChanges"/>
+ <ref name="EG_RPrBase"/>
+ </define>
+ <define name="CT_ParaRPr">
+ <ref name="EG_ParaRPrTrackChanges"/>
+ <ref name="EG_RPrBase"/>
+ <element name="rPrChange">
+ <ref name="CT_ParaRPrChange"/>
+ </element>
+ </define>
+ <define name="CT_ParaTrackChange">
+ <ref name="CT_TrackChange"/>
+ </define>
+ <define name="EG_ParaRPrTrackChanges">
+ <element name="ins">
+ <ref name="CT_ParaTrackChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_ParaTrackChange"/>
+ </element>
+ <element name="moveFrom">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="moveTo">
+ <ref name="CT_TrackChange"/>
+ </element>
+ </define>
+ <define name="CT_AltChunk">
+ <element name="altChunkPr">
+ <ref name="CT_AltChunkPr"/>
+ </element>
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_AltChunkPr">
+ <element name="matchSrc">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="ST_RubyAlign">
+ <choice>
+ <value>center</value>
+ <value>distributeLetter</value>
+ <value>distributeSpace</value>
+ <value>left</value>
+ <value>right</value>
+ <value>rightVertical</value>
+ </choice>
+ </define>
+ <define name="CT_RubyAlign">
+ <attribute name="val">
+ <ref name="ST_RubyAlign"/>
+ </attribute>
+ </define>
+ <define name="CT_RubyPr">
+ <element name="rubyAlign">
+ <ref name="CT_RubyAlign"/>
+ </element>
+ <element name="hps">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="hpsRaise">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="hpsBaseText">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="lid">
+ <ref name="CT_Lang"/>
+ </element>
+ <element name="dirty">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="EG_RubyContent">
+ <choice>
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_RubyContent">
+ <ref name="EG_RubyContent"/>
+ </define>
+ <define name="CT_Ruby">
+ <element name="rubyPr">
+ <ref name="CT_RubyPr"/>
+ </element>
+ <element name="rt">
+ <ref name="CT_RubyContent"/>
+ </element>
+ <element name="rubyBase">
+ <ref name="CT_RubyContent"/>
+ </element>
+ </define>
+ <define name="CT_Lock">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtListItem">
+ <attribute name="displayText">
+ <data type="string"/>
+ </attribute>
+ <attribute name="value">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtDateMappingType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CalendarType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtDate">
+ <element name="dateFormat">
+ <ref name="CT_String"/>
+ </element>
+ <element name="lid">
+ <ref name="CT_Lang"/>
+ </element>
+ <element name="storeMappedDataAs">
+ <ref name="CT_SdtDateMappingType"/>
+ </element>
+ <element name="calendar">
+ <ref name="CT_CalendarType"/>
+ </element>
+ <attribute name="fullDate">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtDocPart">
+ <element name="docPartGallery">
+ <ref name="CT_String"/>
+ </element>
+ <element name="docPartCategory">
+ <ref name="CT_String"/>
+ </element>
+ <element name="docPartUnique">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_SdtDropDownList">
+ <element name="listItem">
+ <ref name="CT_SdtListItem"/>
+ </element>
+ <attribute name="lastValue">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPlaceholderDocPart">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPlaceholder">
+ <element name="docPart">
+ <ref name="CT_SdtPlaceholderDocPart"/>
+ </element>
+ </define>
+ <define name="CT_SdtText">
+ <attribute name="multiLine">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DataBinding">
+ <attribute name="prefixMappings">
+ <data type="string"/>
+ </attribute>
+ <attribute name="xpath">
+ <data type="string"/>
+ </attribute>
+ <attribute name="storeItemID">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtColor">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPr">
+ <choice>
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ <element name="alias">
+ <ref name="CT_String"/>
+ </element>
+ <element name="lock">
+ <ref name="CT_Lock"/>
+ </element>
+ <element name="placeholder">
+ <ref name="CT_SdtPlaceholder"/>
+ </element>
+ <element name="showingPlcHdr">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dataBinding">
+ <ref name="CT_DataBinding"/>
+ </element>
+ <element name="temporary">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="id">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tag">
+ <ref name="CT_String"/>
+ </element>
+ <element name="equation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="comboBox">
+ <ref name="CT_SdtDropDownList"/>
+ </element>
+ <element name="w14:checkbox">
+ <ref name="CT_SdtCheckbox"/>
+ </element>
+ <element name="date">
+ <ref name="CT_SdtDate"/>
+ </element>
+ <element name="docPartObj">
+ <ref name="CT_SdtDocPart"/>
+ </element>
+ <element name="docPartList">
+ <ref name="CT_SdtDocPart"/>
+ </element>
+ <element name="dropDownList">
+ <ref name="CT_SdtDropDownList"/>
+ </element>
+ <element name="picture">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="richText">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="text">
+ <ref name="CT_SdtText"/>
+ </element>
+ <element name="citation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="group">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bibliography">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="w15:color">
+ <ref name="CT_SdtColor"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_SdtEndPr">
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ </define>
+ <define name="EG_ContentRunContent">
+ <choice>
+ <element name="customXml">
+ <ref name="CT_CustomXmlRun"/>
+ </element>
+ <element name="smartTag">
+ <ref name="CT_SmartTagRun"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtRun"/>
+ </element>
+ <element name="dir">
+ <ref name="CT_DirContentRun"/>
+ </element>
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_DirContentRun">
+ <ref name="EG_PContent"/>
+ <attribute name="val">
+ <ref name="ST_Direction"/>
+ </attribute>
+ </define>
+ <define name="ST_Direction">
+ <choice>
+ <value>ltr</value>
+ <value>rtl</value>
+ </choice>
+ </define>
+ <define name="CT_SdtContentRun">
+ <ref name="EG_PContent"/>
+ </define>
+ <define name="EG_ContentBlockContent">
+ <choice>
+ <element name="customXml">
+ <ref name="CT_CustomXmlBlock"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtBlock"/>
+ </element>
+ <element name="p">
+ <ref name="CT_P"/>
+ </element>
+ <element name="tbl">
+ <ref name="CT_Tbl"/>
+ </element>
+ <!-- tdf#108714 : allow <w:br> at block level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <element name="br">
+ <ref name="CT_Br_OutOfOrder"/>
+ </element>
+ <!-- end tdf#108714 -->
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_SdtContentBlock">
+ <ref name="EG_ContentBlockContent"/>
+ </define>
+ <define name="EG_ContentRowContent">
+ <choice>
+ <element name="tr">
+ <ref name="CT_Row"/>
+ </element>
+ <element name="customXml">
+ <ref name="CT_CustomXmlRow"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtRow"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_SdtContentRow">
+ <ref name="EG_ContentRowContent"/>
+ </define>
+ <define name="EG_ContentCellContent">
+ <choice>
+ <element name="tc">
+ <ref name="CT_Tc"/>
+ </element>
+ <element name="customXml">
+ <ref name="CT_CustomXmlCell"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtCell"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_SdtContentCell">
+ <ref name="EG_ContentCellContent"/>
+ </define>
+ <define name="CT_SdtBlock">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentBlock"/>
+ </element>
+ </define>
+ <define name="CT_SdtRun">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentRun"/>
+ </element>
+ </define>
+ <define name="CT_SdtCell">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentCell"/>
+ </element>
+ </define>
+ <define name="CT_SdtRow">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentRow"/>
+ </element>
+ </define>
+ <define name="CT_Attr">
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlRun">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SmartTagRun">
+ <element name="smartTagPr">
+ <ref name="CT_SmartTagPr"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlBlock">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_ContentBlockContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlPr">
+ <element name="placeholder">
+ <ref name="CT_String"/>
+ </element>
+ <element name="attr">
+ <ref name="CT_Attr"/>
+ </element>
+ </define>
+ <define name="CT_CustomXmlRow">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_ContentRowContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlCell">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_ContentCellContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SmartTagPr">
+ <element name="attr">
+ <ref name="CT_Attr"/>
+ </element>
+ </define>
+ <define name="EG_PContent">
+ <choice>
+ <ref name="EG_ContentRunContent"/>
+ <element name="fldSimple">
+ <ref name="CT_SimpleField"/>
+ </element>
+ <element name="hyperlink">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ <element name="subDoc">
+ <ref name="CT_Rel"/>
+ </element>
+ </choice>
+ </define>
+ <!-- [MS-DOCX] sect. 2.2.4 "p and tr Extensions" -->
+ <!-- Should rather be in w14 namespace, but I don't see how to reference things from there -->
+ <define name="AG_Parids">
+ <attribute name="w14:paraId">
+ <data type="string"/>
+ </attribute>
+ <!-- Not yet used
+ <attribute name="textId">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ -->
+ </define>
+ <define name="CT_P">
+ <element name="pPr">
+ <ref name="CT_PPr"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidP">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidRDefault">
+ <data type="string"/>
+ </attribute>
+ <ref name="AG_Parids"/>
+ <!-- tdf#108714 : allow <w:br> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <element name="br">
+ <ref name="CT_Br_OutOfOrder"/>
+ </element>
+ <!-- end tdf#108714 -->
+ <!-- tdf#111550 : allow <w:tbl> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <element name="tbl">
+ <ref name="CT_P_Tbl"/>
+ </element>
+ </define>
+ <define name="ST_TblWidth">
+ <choice>
+ <!-- No Width -->
+ <value>nil</value>
+ <!-- Width in Fiftieths of a Percent -->
+ <value>pct</value>
+ <!-- Width in Twentieths of a Point -->
+ <value>dxa</value>
+ <!-- Automatically Determined Width -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="ST_MeasurementOrPercent">
+ <data type="string"/>
+ </define>
+ <define name="CT_Height">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hRule">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_TblWidth">
+ <attribute name="w">
+ <ref name="ST_MeasurementOrPercent"/>
+ </attribute>
+ <attribute name="type">
+ <ref name="ST_TblWidth"/>
+ </attribute>
+ </define>
+ <define name="CT_TblGridCol">
+ <attribute name="w">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="CT_TblGridBase">
+ <element name="gridCol">
+ <ref name="CT_TblGridCol"/>
+ </element>
+ </define>
+ <define name="CT_TblGrid">
+ <ref name="CT_TblGridBase"/>
+ <element name="tblGridChange">
+ <ref name="CT_TblGridChange"/>
+ </element>
+ </define>
+ <define name="CT_TcBorders">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="start">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="end">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideH">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideV">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="tl2br">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="tr2bl">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_TcMar">
+ <element name="top">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="start">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="left">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="right">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="end">
+ <ref name="CT_TblWidth"/>
+ </element>
+ </define>
+ <define name="ST_Merge">
+ <choice>
+ <!-- Continue Merged Region -->
+ <value>continue</value>
+ <!-- Start/Restart Merged Region -->
+ <value>restart</value>
+ </choice>
+ </define>
+ <define name="CT_VMerge">
+ <attribute name="val">
+ <ref name="ST_Merge"/>
+ </attribute>
+ </define>
+ <define name="CT_HMerge">
+ <attribute name="val">
+ <ref name="ST_Merge"/>
+ </attribute>
+ </define>
+ <define name="CT_TcPrBase">
+ <element name="cnfStyle">
+ <ref name="CT_Cnf"/>
+ </element>
+ <element name="tcW">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="gridSpan">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="hMerge">
+ <ref name="CT_HMerge"/>
+ </element>
+ <element name="vMerge">
+ <ref name="CT_VMerge"/>
+ </element>
+ <element name="tcBorders">
+ <ref name="CT_TcBorders"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="noWrap">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="tcMar">
+ <ref name="CT_TcMar"/>
+ </element>
+ <element name="textDirection">
+ <ref name="CT_TextDirection"/>
+ </element>
+ <element name="tcFitText">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="vAlign">
+ <ref name="CT_VerticalJc"/>
+ </element>
+ <element name="hideMark">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_TcPr">
+ <ref name="CT_TcPrInner"/>
+ <element name="tcPrChange">
+ <ref name="CT_TcPrChange"/>
+ </element>
+ </define>
+ <define name="CT_TcPrInner">
+ <ref name="CT_TcPrBase"/>
+ <ref name="EG_CellMarkupElements"/>
+ </define>
+ <define name="CT_Tc">
+ <element name="tcPr">
+ <ref name="CT_TcPr"/>
+ </element>
+ <ref name="EG_BlockLevelElts"/>
+ </define>
+ <define name="ST_Cnf">
+ <data type="string"/>
+ </define>
+ <define name="CT_Cnf">
+ <attribute name="val">
+ <ref name="ST_Cnf"/>
+ </attribute>
+ <attribute name="firstRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="oddVBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="evenVBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="oddHBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="evenHBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstRowFirstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstRowLastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRowFirstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRowLastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_TrPrBase">
+ <choice>
+ <element name="cnfStyle">
+ <ref name="CT_Cnf"/>
+ </element>
+ <element name="divId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="gridBefore">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="gridAfter">
+ <ref name="CT_TrPrBaseGridAfter"/>
+ </element>
+ <element name="wBefore">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="wAfter">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="cantSplit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="trHeight">
+ <ref name="CT_Height"/>
+ </element>
+ <element name="tblHeader">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="tblCellSpacing">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="hidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_TrPrBaseGridAfter">
+ <attribute name="val">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_TrPr">
+ <ref name="CT_TrPrBase"/>
+ <element name="ins">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="trPrChange">
+ <ref name="CT_TrPrChange"/>
+ </element>
+ </define>
+ <define name="CT_Row">
+ <element name="tblPrEx">
+ <ref name="CT_TblPrEx"/>
+ </element>
+ <element name="trPr">
+ <ref name="CT_TrPr"/>
+ </element>
+ <ref name="EG_ContentCellContent"/>
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidTr">
+ <data type="string"/>
+ </attribute>
+ <ref name="AG_Parids"/>
+ </define>
+ <define name="ST_TblLayout">
+ <choice>
+ <!-- Fixed Width Table Layout -->
+ <value>fixed</value>
+ <!-- AutoFit Table Layout -->
+ <value>autofit</value>
+ </choice>
+ </define>
+ <define name="CT_TblLayoutType">
+ <attribute name="type">
+ <ref name="ST_TblLayout"/>
+ </attribute>
+ </define>
+ <define name="ST_TblOverlap">
+ <choice>
+ <!-- Floating Table Cannot Overlap -->
+ <value>never</value>
+ <!-- Floating Table Can Overlap -->
+ <value>overlap</value>
+ </choice>
+ </define>
+ <define name="CT_TblOverlap">
+ <attribute name="val">
+ <ref name="ST_TblOverlap"/>
+ </attribute>
+ </define>
+ <define name="CT_TblPPr">
+ <attribute name="leftFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="rightFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="topFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="bottomFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="vertAnchor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="horzAnchor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tblpXSpec">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tblpX">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="tblpYSpec">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tblpY">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="CT_TblCellMar">
+ <element name="top">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="start">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="left">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="right">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="end">
+ <ref name="CT_TblWidth"/>
+ </element>
+ </define>
+ <define name="CT_TblBorders">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="start">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="end">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideH">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideV">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_TblPrBase">
+ <element name="tblStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="tblpPr">
+ <ref name="CT_TblPPr"/>
+ </element>
+ <element name="tblOverlap">
+ <ref name="CT_TblOverlap"/>
+ </element>
+ <element name="bidiVisual">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="tblStyleRowBandSize">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tblStyleColBandSize">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tblW">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="tblCellSpacing">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblInd">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblBorders">
+ <ref name="CT_TblBorders"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="tblLayout">
+ <ref name="CT_TblLayoutType"/>
+ </element>
+ <element name="tblCellMar">
+ <ref name="CT_TblCellMar"/>
+ </element>
+ <element name="tblLook">
+ <ref name="CT_TblLook"/>
+ </element>
+ <element name="tblCaption">
+ <ref name="CT_String"/>
+ </element>
+ <element name="tblDescription">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_TblPr">
+ <ref name="CT_TblPrBase"/>
+ <element name="tblPrChange">
+ <ref name="CT_TblPrChange"/>
+ </element>
+ </define>
+ <define name="CT_TblPrExBase">
+ <element name="tblW">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="tblCellSpacing">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblInd">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblBorders">
+ <ref name="CT_TblBorders"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="tblLayout">
+ <ref name="CT_TblLayoutType"/>
+ </element>
+ <element name="tblCellMar">
+ <ref name="CT_TblCellMar"/>
+ </element>
+ <element name="tblLook">
+ <ref name="CT_TblLook"/>
+ </element>
+ <element name="tblCaption">
+ <ref name="CT_String"/>
+ </element>
+ <element name="tblDescription">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_TblPrEx">
+ <ref name="CT_TblPrExBase"/>
+ <element name="tblPrExChange">
+ <ref name="CT_TblPrExChange"/>
+ </element>
+ </define>
+ <define name="CT_Tbl">
+ <ref name="EG_RangeMarkupElements"/>
+ <element name="tblPr">
+ <ref name="CT_TblPr"/>
+ </element>
+ <element name="tblGrid">
+ <ref name="CT_TblGrid"/>
+ </element>
+ <ref name="EG_ContentRowContent"/>
+ </define>
+ <!-- tdf#111550 : Special element - copy of usual CT_Tbl, but only used as direct child of CT_P -->
+ <define name="CT_P_Tbl">
+ <ref name="EG_RangeMarkupElements"/>
+ <element name="tblPr">
+ <ref name="CT_TblPr"/>
+ </element>
+ <element name="tblGrid">
+ <ref name="CT_TblGrid"/>
+ </element>
+ <ref name="EG_ContentRowContent"/>
+ </define>
+ <define name="CT_TblLook">
+ <attribute name="firstRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="noHBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="noVBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_ShortHexNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_FtnPos">
+ <choice>
+ <!-- Footnotes Positioned at Page Bottom -->
+ <value>pageBottom</value>
+ <!-- Footnotes Positioned Beneath Text -->
+ <value>beneathText</value>
+ <!-- Footnotes Positioned At End of Section -->
+ <value>sectEnd</value>
+ <!-- Footnotes Positioned At End of Document -->
+ <value>docEnd</value>
+ </choice>
+ </define>
+ <define name="CT_FtnPos">
+ <attribute name="val">
+ <ref name="ST_FtnPos"/>
+ </attribute>
+ </define>
+ <define name="ST_EdnPos">
+ <choice>
+ <!-- Endnotes Positioned at End of Section -->
+ <value>sectEnd</value>
+ <!-- Endnotes Positioned at End of Document -->
+ <value>docEnd</value>
+ </choice>
+ </define>
+ <define name="CT_EdnPos">
+ <attribute name="val">
+ <ref name="ST_EdnPos"/>
+ </attribute>
+ </define>
+ <define name="CT_NumFmt">
+ <attribute name="format">
+ <data type="string"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_NumberFormat"/>
+ </attribute>
+ </define>
+ <define name="ST_RestartNumber">
+ <choice>
+ <!-- Continue Numbering From Previous Section -->
+ <value>continuous</value>
+ <!-- Restart Numbering For Each Section -->
+ <value>eachSect</value>
+ <!-- Restart Numbering On Each Page -->
+ <value>eachPage</value>
+ </choice>
+ </define>
+ <define name="CT_NumRestart">
+ <attribute name="val">
+ <ref name="ST_RestartNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdnRef">
+ <attribute name="customMarkFollows">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdnSepRef">
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdn">
+ <ref name="EG_BlockLevelElts"/>
+ <attribute name="type">
+ <ref name="ST_FtnEdn"/>
+ </attribute>
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_CommentRef">
+ <ref name="CT_Markup"/>
+ </define>
+ <define name="EG_FtnEdnNumProps">
+ <element name="numStart">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="numRestart">
+ <ref name="CT_NumRestart"/>
+ </element>
+ </define>
+ <define name="CT_FtnProps">
+ <element name="pos">
+ <ref name="CT_FtnPos"/>
+ </element>
+ <element name="numFmt">
+ <ref name="CT_NumFmt"/>
+ </element>
+ <ref name="EG_FtnEdnNumProps"/>
+ </define>
+ <define name="CT_EdnProps">
+ <element name="pos">
+ <ref name="CT_EdnPos"/>
+ </element>
+ <element name="numFmt">
+ <ref name="CT_NumFmt"/>
+ </element>
+ <ref name="EG_FtnEdnNumProps"/>
+ </define>
+ <define name="CT_FtnDocProps">
+ <ref name="CT_FtnProps"/>
+ <element name="footnote">
+ <ref name="CT_FtnEdnSepRef"/>
+ </element>
+ </define>
+ <define name="CT_EdnDocProps">
+ <ref name="CT_EdnProps"/>
+ <element name="endnote">
+ <ref name="CT_FtnEdnSepRef"/>
+ </element>
+ </define>
+ <define name="CT_RecipientData">
+ <element name="active">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="column">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="uniqueTag">
+ <data type="base64Binary"/>
+ </element>
+ </define>
+ <define name="CT_Recipients">
+ <element name="recipientData">
+ <ref name="CT_RecipientData"/>
+ </element>
+ </define>
+ <define name="recipients">
+ <element name="recipients">
+ <ref name="CT_Recipients"/>
+ </element>
+ </define>
+ <define name="CT_OdsoFieldMapData">
+ <element name="type">
+ <ref name="CT_MailMergeOdsoFMDFieldType"/>
+ </element>
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="mappedName">
+ <ref name="CT_String"/>
+ </element>
+ <element name="column">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="lid">
+ <ref name="CT_Lang"/>
+ </element>
+ <element name="dynamicAddress">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_MailMergeSourceType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Odso">
+ <element name="udl">
+ <ref name="CT_String"/>
+ </element>
+ <element name="table">
+ <ref name="CT_String"/>
+ </element>
+ <element name="src">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="colDelim">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="type">
+ <ref name="CT_MailMergeSourceType"/>
+ </element>
+ <element name="fHdr">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="fieldMapData">
+ <ref name="CT_OdsoFieldMapData"/>
+ </element>
+ <element name="recipientData">
+ <ref name="CT_Rel"/>
+ </element>
+ </define>
+ <define name="CT_MailMerge">
+ <element name="mainDocumentType">
+ <ref name="CT_MailMergeDocType"/>
+ </element>
+ <element name="linkToQuery">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dataType">
+ <ref name="CT_MailMergeDataType"/>
+ </element>
+ <element name="connectString">
+ <ref name="CT_String"/>
+ </element>
+ <element name="query">
+ <ref name="CT_String"/>
+ </element>
+ <element name="dataSource">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="headerSource">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="doNotSuppressBlankLines">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="destination">
+ <ref name="CT_MailMergeDest"/>
+ </element>
+ <element name="addressFieldName">
+ <ref name="CT_String"/>
+ </element>
+ <element name="mailSubject">
+ <ref name="CT_String"/>
+ </element>
+ <element name="mailAsAttachment">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="viewMergedData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="activeRecord">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="checkErrors">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="odso">
+ <ref name="CT_Odso"/>
+ </element>
+ </define>
+ <define name="CT_TargetScreenSz">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Compat">
+ <element name="useSingleBorderforContiguousCells">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wpJustification">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noTabHangInd">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noLeading">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="spaceForUL">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noColumnBalance">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="balanceSingleByteDoubleByteWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noExtraLineSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotLeaveBackslashAlone">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ulTrailSpace">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotExpandShiftReturn">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="spacingInWholePoints">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="lineWrapLikeWord6">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printBodyTextBeforeHeader">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printColBlack">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wpSpaceWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="showBreaksInFrames">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="subFontBySize">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressBottomSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressTopSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressSpacingAtTopOfPage">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressTopSpacingWP">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressSpBfAfterPgBrk">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="swapBordersFacingPages">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="convMailMergeEsc">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="truncateFontHeightsLikeWP6">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="mwSmallCaps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="usePrinterMetrics">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSuppressParagraphBorders">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wrapTrailSpaces">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="footnoteLayoutLikeWW8">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="shapeLayoutLikeWW8">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alignTablesRowByRow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="forgetLastTabAlignment">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="adjustLineHeightInTable">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="autoSpaceLikeWord95">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noSpaceRaiseLower">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseHTMLParagraphAutoSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="layoutRawTableWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="layoutTableRowsApart">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useWord97LineBreakRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotBreakWrappedTables">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSnapToGridInCell">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="selectFldWithFirstOrLastChar">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="applyBreakingRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotWrapTextWithPunct">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseEastAsianBreakRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useWord2002TableStyleRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="growAutofit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useFELayout">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useNormalStyleForList">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseIndentAsNumberingTabStop">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useAltKinsokuLineBreakRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="allowSpaceOfSameStyleInTable">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSuppressIndentation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotAutofitConstrainedTables">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="autofitToFirstFixedWidthCell">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="underlineTabInNumList">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="displayHangulFixedWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="splitPgBreakAndParaMark">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotVertAlignCellWithSp">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotBreakConstrainedForcedTable">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotVertAlignInTxbx">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useAnsiKerningPairs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="cachedColBalance">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="compatSetting">
+ <ref name="CT_CompatSetting"/>
+ </element>
+ </define>
+ <define name="CT_CompatSetting">
+ <attribute name="name">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="uri">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_DocVar">
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocVars">
+ <element name="docVar">
+ <ref name="CT_DocVar"/>
+ </element>
+ </define>
+ <define name="CT_DocRsids">
+ <element name="rsidRoot">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="rsid">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ </define>
+ <define name="CT_CharacterSpacing">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SaveThroughXslt">
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="solutionID">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_RPrDefault">
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ </define>
+ <define name="CT_PPrDefault">
+ <element name="pPr">
+ <ref name="CT_PPr"/>
+ </element>
+ </define>
+ <define name="CT_DocDefaults">
+ <element name="rPrDefault">
+ <ref name="CT_RPrDefault"/>
+ </element>
+ <element name="pPrDefault">
+ <ref name="CT_PPrDefault"/>
+ </element>
+ </define>
+ <define name="ST_ColorSchemeIndex">
+ <choice>
+ <!-- Dark 1 Theme Color Reference -->
+ <value>dark1</value>
+ <!-- Light 1 Theme Color Reference -->
+ <value>light1</value>
+ <!-- Dark 2 Theme Color Reference -->
+ <value>dark2</value>
+ <!-- Light 2 Theme Color Reference -->
+ <value>light2</value>
+ <!-- Accent 1 Theme Color Reference -->
+ <value>accent1</value>
+ <!-- Accent 2 Theme Color Reference -->
+ <value>accent2</value>
+ <!-- Accent 3 Theme Color Reference -->
+ <value>accent3</value>
+ <!-- Accent4 Theme Color Reference -->
+ <value>accent4</value>
+ <!-- Accent5 Theme Color Reference -->
+ <value>accent5</value>
+ <!-- Accent 6 Theme Color Reference -->
+ <value>accent6</value>
+ <!-- Hyperlink Theme Color Reference -->
+ <value>hyperlink</value>
+ <!-- Followed Hyperlink Theme Color Reference -->
+ <value>followedHyperlink</value>
+ </choice>
+ </define>
+ <define name="CT_ColorSchemeMapping">
+ <attribute name="bg1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="t1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="bg2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="t2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent3">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent4">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent5">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent6">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hyperlink">
+ <data type="string"/>
+ </attribute>
+ <attribute name="followedHyperlink">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_ReadingModeInkLockDown">
+ <attribute name="actualPg">
+ <data type="string"/>
+ </attribute>
+ <attribute name="w">
+ <data type="string"/>
+ </attribute>
+ <attribute name="h">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fontSz">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_WriteProtection">
+ <attribute name="recommended">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <ref name="AG_Password"/>
+ </define>
+ <define name="CT_Settings">
+ <element name="writeProtection">
+ <ref name="CT_WriteProtection"/>
+ </element>
+ <element name="view">
+ <ref name="CT_View"/>
+ </element>
+ <element name="zoom">
+ <ref name="CT_Zoom"/>
+ </element>
+ <element name="linkStyles">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="removePersonalInformation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="removeDateAndTime">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotDisplayPageBoundaries">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="displayBackgroundShape">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printPostScriptOverText">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printFractionalCharacterWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printFormsData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="embedTrueTypeFonts">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="embedSystemFonts">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveSubsetFonts">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveFormsData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="mirrorMargins">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alignBordersAndEdges">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bordersDoNotSurroundHeader">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bordersDoNotSurroundFooter">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="gutterAtTop">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideSpellingErrors">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideGrammaticalErrors">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="activeWritingStyle">
+ <ref name="CT_WritingStyle"/>
+ </element>
+ <element name="proofState">
+ <ref name="CT_Proof"/>
+ </element>
+ <element name="formsDesign">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="attachedTemplate">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="linkStyles">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="stylePaneFormatFilter">
+ <ref name="CT_ShortHexNumber"/>
+ </element>
+ <element name="stylePaneSortMethod">
+ <ref name="CT_ShortHexNumber"/>
+ </element>
+ <element name="documentType">
+ <ref name="CT_DocType"/>
+ </element>
+ <element name="mailMerge">
+ <ref name="CT_MailMerge"/>
+ </element>
+ <element name="revisionView">
+ <ref name="CT_TrackChangesView"/>
+ </element>
+ <element name="trackRevisions">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotTrackMoves">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotTrackFormatting">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="documentProtection">
+ <ref name="CT_DocProtect"/>
+ </element>
+ <element name="autoFormatOverride">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="styleLockTheme">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="styleLockQFSet">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="defaultTabStop">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="autoHyphenation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="consecutiveHyphenLimit">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="hyphenationZone">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="doNotHyphenateCaps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="showEnvelope">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="summaryLength">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="clickAndTypeStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="defaultTableStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="evenAndOddHeaders">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bookFoldRevPrinting">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bookFoldPrinting">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bookFoldPrintingSheets">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="drawingGridHorizontalSpacing">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="drawingGridVerticalSpacing">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="displayHorizontalDrawingGridEvery">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="displayVerticalDrawingGridEvery">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="doNotUseMarginsForDrawingGridOrigin">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="drawingGridHorizontalOrigin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="drawingGridVerticalOrigin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="doNotShadeFormData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noPunctuationKerning">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="characterSpacingControl">
+ <ref name="CT_CharacterSpacing"/>
+ </element>
+ <element name="printTwoOnOne">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strictFirstAndLastChars">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noLineBreaksAfter">
+ <ref name="CT_Kinsoku"/>
+ </element>
+ <element name="noLineBreaksBefore">
+ <ref name="CT_Kinsoku"/>
+ </element>
+ <element name="savePreviewPicture">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotValidateAgainstSchema">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveInvalidXml">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ignoreMixedContent">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alwaysShowPlaceholderText">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotDemarcateInvalidXml">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveXmlDataOnly">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useXSLTWhenSaving">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveThroughXslt">
+ <ref name="CT_SaveThroughXslt"/>
+ </element>
+ <element name="showXMLTags">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alwaysMergeEmptyNamespace">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="updateFields">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hdrShapeDefaults">
+ <ref name="CT_ShapeDefaults"/>
+ </element>
+ <element name="footnotePr">
+ <ref name="CT_FtnDocProps"/>
+ </element>
+ <element name="endnotePr">
+ <ref name="CT_EdnDocProps"/>
+ </element>
+ <element name="compat">
+ <ref name="CT_Compat"/>
+ </element>
+ <element name="docVars">
+ <ref name="CT_DocVars"/>
+ </element>
+ <element name="rsids">
+ <ref name="CT_DocRsids"/>
+ </element>
+ <ref name="mathPr"/>
+ <element name="uiCompat97To2003">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="attachedSchema">
+ <ref name="CT_String"/>
+ </element>
+ <element name="themeFontLang">
+ <ref name="CT_Language"/>
+ </element>
+ <element name="clrSchemeMapping">
+ <ref name="CT_ColorSchemeMapping"/>
+ </element>
+ <element name="doNotIncludeSubdocsInStats">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotAutoCompressPictures">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="forceUpgrade">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="captions">
+ <ref name="CT_Captions"/>
+ </element>
+ <element name="readModeInkLockDown">
+ <ref name="CT_ReadingModeInkLockDown"/>
+ </element>
+ <element name="smartTagType">
+ <ref name="CT_SmartTagType"/>
+ </element>
+ <ref name="schemaLibrary"/>
+ <element name="shapeDefaults">
+ <ref name="CT_ShapeDefaults"/>
+ </element>
+ <element name="doNotEmbedSmartTags">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="decimalSymbol">
+ <ref name="CT_String"/>
+ </element>
+ <element name="listSeparator">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_WebSettings">
+ <element name="frameset">
+ <ref name="CT_Frameset"/>
+ </element>
+ <element name="divs">
+ <ref name="CT_Divs"/>
+ </element>
+ <element name="encoding">
+ <ref name="CT_String"/>
+ </element>
+ <element name="optimizeForBrowser">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="relyOnVML">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="allowPNG">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotRelyOnCSS">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSaveAsSingleFile">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotOrganizeInFolder">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseLongFileNames">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="pixelsPerInch">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="targetScreenSz">
+ <ref name="CT_TargetScreenSz"/>
+ </element>
+ <element name="saveSmartTagsAsXml">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_FrameScrollbar">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Frame">
+ <element name="sz">
+ <ref name="CT_String"/>
+ </element>
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="sourceFileName">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="marW">
+ <ref name="CT_PixelsMeasure"/>
+ </element>
+ <element name="marH">
+ <ref name="CT_PixelsMeasure"/>
+ </element>
+ <element name="scrollbar">
+ <ref name="CT_FrameScrollbar"/>
+ </element>
+ <element name="noResizeAllowed">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="linkedToFile">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_FrameLayout">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FramesetSplitbar">
+ <element name="w">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="color">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="noBorder">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="flatBorders">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_Frameset">
+ <element name="sz">
+ <ref name="CT_String"/>
+ </element>
+ <element name="framesetSplitbar">
+ <ref name="CT_FramesetSplitbar"/>
+ </element>
+ <element name="frameLayout">
+ <ref name="CT_FrameLayout"/>
+ </element>
+ <choice>
+ <element name="frameset">
+ <ref name="CT_Frameset"/>
+ </element>
+ <element name="frame">
+ <ref name="CT_Frame"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_NumPicBullet">
+ <element name="pict">
+ <ref name="CT_Picture"/>
+ </element>
+ <attribute name="numPicBulletId">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LevelSuffix">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LevelText">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="null">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LvlLegacy">
+ <attribute name="legacy">
+ <data type="string"/>
+ </attribute>
+ <attribute name="legacySpace">
+ <data type="string"/>
+ </attribute>
+ <attribute name="legacyIndent">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Lvl">
+ <element name="start">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="numFmt">
+ <ref name="CT_NumFmt"/>
+ </element>
+ <element name="lvlRestart">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="pStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="isLgl">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suff">
+ <ref name="CT_LevelSuffix"/>
+ </element>
+ <element name="lvlText">
+ <ref name="CT_LevelText"/>
+ </element>
+ <element name="lvlPicBulletId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="legacy">
+ <ref name="CT_LvlLegacy"/>
+ </element>
+ <element name="lvlJc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="pPr">
+ <ref name="CT_PPr"/>
+ </element>
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ <attribute name="ilvl">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tplc">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tentative">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_MultiLevelType">
+ <choice>
+ <!-- Single Level Numbering Definition -->
+ <value>singleLevel</value>
+ <!-- Multilevel Numbering Definition -->
+ <value>multilevel</value>
+ <!-- Hybrid Multilevel Numbering Definition -->
+ <value>hybridMultilevel</value>
+ </choice>
+ </define>
+ <define name="CT_MultiLevelType">
+ <attribute name="val">
+ <ref name="ST_MultiLevelType"/>
+ </attribute>
+ </define>
+ <define name="CT_AbstractNum">
+ <element name="nsid">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="multiLevelType">
+ <ref name="CT_MultiLevelType"/>
+ </element>
+ <element name="tmpl">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="styleLink">
+ <ref name="CT_String"/>
+ </element>
+ <element name="numStyleLink">
+ <ref name="CT_String"/>
+ </element>
+ <element name="lvl">
+ <ref name="CT_Lvl"/>
+ </element>
+ <attribute name="abstractNumId">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_NumLvl">
+ <element name="startOverride">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="lvl">
+ <ref name="CT_Lvl"/>
+ </element>
+ <attribute name="ilvl">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Num">
+ <element name="abstractNumId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="lvlOverride">
+ <ref name="CT_NumLvl"/>
+ </element>
+ <attribute name="numId">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Numbering">
+ <element name="numPicBullet">
+ <ref name="CT_NumPicBullet"/>
+ </element>
+ <element name="abstractNum">
+ <ref name="CT_AbstractNum"/>
+ </element>
+ <element name="num">
+ <ref name="CT_Num"/>
+ </element>
+ <element name="numIdMacAtCleanup">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ </define>
+ <define name="ST_TblStyleOverrideType">
+ <choice>
+ <!-- Whole table formatting -->
+ <value>wholeTable</value>
+ <!-- First Row Conditional Formatting -->
+ <value>firstRow</value>
+ <!-- Last table row formatting -->
+ <value>lastRow</value>
+ <!-- First Column Conditional Formatting -->
+ <value>firstCol</value>
+ <!-- Last table column formatting -->
+ <value>lastCol</value>
+ <!-- Banded Column Conditional Formatting -->
+ <value>band1Vert</value>
+ <!-- Even Column Stripe Conditional Formatting -->
+ <value>band2Vert</value>
+ <!-- Banded Row Conditional Formatting -->
+ <value>band1Horz</value>
+ <!-- Even Row Stripe Conditional Formatting -->
+ <value>band2Horz</value>
+ <!-- Top right table cell formatting -->
+ <value>neCell</value>
+ <!-- Top left table cell formatting -->
+ <value>nwCell</value>
+ <!-- Bottom right table cell formatting -->
+ <value>seCell</value>
+ <!-- Bottom left table cell formatting -->
+ <value>swCell</value>
+ </choice>
+ </define>
+ <define name="CT_Style_tblStylePr">
+ <element name="pPr">
+ <ref name="CT_PPrBase"/>
+ </element>
+ <element name="rPr">
+ <ref name="EG_RPrBase"/>
+ </element>
+ <element name="tblPr">
+ <ref name="CT_TblPrBase"/>
+ </element>
+ <element name="trPr">
+ <ref name="CT_TrPrBase"/>
+ </element>
+ <element name="tcPr">
+ <ref name="CT_TcPrBase"/>
+ </element>
+ <attribute name="type">
+ <ref name="ST_TblStyleOverrideType"/>
+ </attribute>
+ </define>
+ <define name="CT_Style_TblPr">
+ <ref name="CT_TblPrBase"/>
+ </define>
+ <define name="CT_Style_TrPr">
+ <ref name="CT_TrPrBase"/>
+ </define>
+ <define name="CT_Style_TcPr">
+ <ref name="CT_TcPrBase"/>
+ </define>
+ <define name="ST_StyleType">
+ <choice>
+ <!-- Paragraph Style -->
+ <value>paragraph</value>
+ <!-- Character Style -->
+ <value>character</value>
+ <!-- Table Style -->
+ <value>table</value>
+ <!-- Numbering Style -->
+ <value>numbering</value>
+ </choice>
+ </define>
+ <define name="CT_Style">
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="aliases">
+ <ref name="CT_String"/>
+ </element>
+ <element name="basedOn">
+ <ref name="CT_String"/>
+ </element>
+ <element name="next">
+ <ref name="CT_String"/>
+ </element>
+ <element name="link">
+ <ref name="CT_String"/>
+ </element>
+ <element name="autoRedefine">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="uiPriority">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="semiHidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="unhideWhenUsed">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="qFormat">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="locked">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="personal">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="personalCompose">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="personalReply">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rsid">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="pPr">
+ <ref name="CT_PPrBase"/>
+ </element>
+ <element name="rPr">
+ <ref name="EG_RPrBase"/>
+ </element>
+ <element name="tblPr">
+ <ref name="CT_TblPrBase"/>
+ </element>
+ <element name="trPr">
+ <ref name="CT_TrPrBase"/>
+ </element>
+ <element name="tcPr">
+ <ref name="CT_TcPrBase"/>
+ </element>
+ <element name="tblStylePr">
+ <ref name="CT_Style_tblStylePr"/>
+ </element>
+ <attribute name="type">
+ <ref name="ST_StyleType"/>
+ </attribute>
+ <attribute name="styleId">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="default">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="customStyle">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_LsdException">
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="locked">
+ <data type="string"/>
+ </attribute>
+ <attribute name="uiPriority">
+ <data type="string"/>
+ </attribute>
+ <attribute name="semiHidden">
+ <data type="string"/>
+ </attribute>
+ <attribute name="unhideWhenUsed">
+ <data type="string"/>
+ </attribute>
+ <attribute name="qFormat">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LatentStyles">
+ <element name="lsdException">
+ <ref name="CT_LsdException"/>
+ </element>
+ <attribute name="defLockedState">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defUIPriority">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defSemiHidden">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defUnhideWhenUsed">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defQFormat">
+ <data type="string"/>
+ </attribute>
+ <attribute name="count">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Styles">
+ <element name="docDefaults">
+ <ref name="CT_DocDefaults"/>
+ </element>
+ <element name="latentStyles">
+ <ref name="CT_LatentStyles"/>
+ </element>
+ <element name="style">
+ <ref name="CT_Style"/>
+ </element>
+ </define>
+ <define name="ST_Panose">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_Panose">
+ <attribute name="val">
+ <ref name="ST_Panose"/>
+ </attribute>
+ </define>
+ <define name="ST_FontFamily">
+ <choice>
+ <!-- Novelty Font -->
+ <value>decorative</value>
+ <!-- Monospace Font -->
+ <value>modern</value>
+ <!-- Proportional Font With Serifs -->
+ <value>roman</value>
+ <!-- Script Font -->
+ <value>script</value>
+ <!-- Proportional Font Without Serifs -->
+ <value>swiss</value>
+ <!-- No Font Family -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="CT_FontFamily">
+ <attribute name="val">
+ <ref name="ST_FontFamily"/>
+ </attribute>
+ </define>
+ <define name="ST_Pitch">
+ <choice>
+ <!-- Fixed Width -->
+ <value>fixed</value>
+ <!-- Proportional Width -->
+ <value>variable</value>
+ <!-- Default -->
+ <value>default</value>
+ </choice>
+ </define>
+ <define name="CT_Pitch">
+ <attribute name="val">
+ <ref name="ST_Pitch"/>
+ </attribute>
+ </define>
+ <define name="CT_FontSig">
+ <attribute name="usb0">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="usb1">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="usb2">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="usb3">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="csb0">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="csb1">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FontRel">
+ <ref name="CT_Rel"/>
+ <attribute name="fontKey">
+ <data type="string"/>
+ </attribute>
+ <attribute name="subsetted">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Font">
+ <element name="altName">
+ <ref name="CT_String"/>
+ </element>
+ <element name="panose1">
+ <ref name="CT_Panose"/>
+ </element>
+ <element name="charset">
+ <ref name="CT_Charset"/>
+ </element>
+ <element name="characterSet">
+ <ref name="CT_String"/>
+ </element>
+ <element name="family">
+ <ref name="CT_FontFamily"/>
+ </element>
+ <element name="notTrueType">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="pitch">
+ <ref name="CT_Pitch"/>
+ </element>
+ <element name="sig">
+ <ref name="CT_FontSig"/>
+ </element>
+ <element name="embedRegular">
+ <ref name="CT_FontRel"/>
+ </element>
+ <element name="embedBold">
+ <ref name="CT_FontRel"/>
+ </element>
+ <element name="embedItalic">
+ <ref name="CT_FontRel"/>
+ </element>
+ <element name="embedBoldItalic">
+ <ref name="CT_FontRel"/>
+ </element>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FontsList">
+ <element name="font">
+ <ref name="CT_Font"/>
+ </element>
+ </define>
+ <define name="CT_Charset">
+ <attribute name="val">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="characterSet">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_DivBdr">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_Div">
+ <element name="blockQuote">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bodyDiv">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="marLeft">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="marRight">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="marTop">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="marBottom">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="divBdr">
+ <ref name="CT_DivBdr"/>
+ </element>
+ <element name="divsChild">
+ <ref name="CT_Divs"/>
+ </element>
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Divs">
+ <element name="div">
+ <ref name="CT_Div"/>
+ </element>
+ </define>
+ <define name="CT_TxbxContent">
+ <ref name="EG_BlockLevelElts"/>
+ </define>
+ <define name="txbxContent">
+ <element name="txbxContent">
+ <ref name="CT_TxbxContent"/>
+ </element>
+ </define>
+ <define name="EG_MathContent">
+ <choice>
+ <ref name="oMathPara"/>
+ <ref name="oMath"/>
+ </choice>
+ </define>
+ <define name="EG_BlockLevelChunkElts">
+ <ref name="EG_ContentBlockContent"/>
+ </define>
+ <define name="EG_BlockLevelElts">
+ <choice>
+ <ref name="EG_BlockLevelChunkElts"/>
+ <element name="altChunk">
+ <ref name="CT_AltChunk"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_RunLevelElts">
+ <choice>
+ <element name="proofErr">
+ <ref name="CT_ProofErr"/>
+ </element>
+ <ref name="EG_RangeMarkupElements"/>
+ <element name="ins">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <element name="moveFrom">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <element name="moveTo">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <ref name="EG_MathContent"/>
+ </choice>
+ </define>
+ <define name="CT_Body">
+ <ref name="EG_BlockLevelElts"/>
+ <element name="sectPr">
+ <ref name="CT_finalSectPr"/>
+ </element>
+ </define>
+ <define name="CT_ShapeDefaults">
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </define>
+ <define name="CT_Comments">
+ <element name="comment">
+ <ref name="CT_Comment"/>
+ </element>
+ </define>
+ <define name="comments">
+ <element name="comments">
+ <ref name="CT_Comments"/>
+ </element>
+ </define>
+ <define name="CT_Footnotes">
+ <element name="footnote">
+ <ref name="CT_FtnEdn"/>
+ </element>
+ </define>
+ <define name="footnotes">
+ <element name="footnotes">
+ <ref name="CT_Footnotes"/>
+ </element>
+ </define>
+ <define name="CT_Endnotes">
+ <element name="endnote">
+ <ref name="CT_FtnEdn"/>
+ </element>
+ </define>
+ <define name="endnotes">
+ <element name="endnotes">
+ <ref name="CT_Endnotes"/>
+ </element>
+ </define>
+ <define name="hdr">
+ <element name="hdr">
+ <ref name="CT_HdrFtr"/>
+ </element>
+ </define>
+ <define name="ftr">
+ <element name="ftr">
+ <ref name="CT_HdrFtr"/>
+ </element>
+ </define>
+ <define name="CT_SmartTagType">
+ <attribute name="namespaceuri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="url">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_ThemeColor">
+ <choice>
+ <!-- Dark 1 Theme Color -->
+ <value>dark1</value>
+ <!-- Light 1 Theme Color -->
+ <value>light1</value>
+ <!-- Dark 2 Theme Color -->
+ <value>dark2</value>
+ <!-- Light 2 Theme Color -->
+ <value>light2</value>
+ <!-- Accent 1 Theme Color -->
+ <value>accent1</value>
+ <!-- Accent 2 Theme Color -->
+ <value>accent2</value>
+ <!-- Accent 3 Theme Color -->
+ <value>accent3</value>
+ <!-- Accent 4 Theme Color -->
+ <value>accent4</value>
+ <!-- Accent 5 Theme Color -->
+ <value>accent5</value>
+ <!-- Accent 6 Theme Color -->
+ <value>accent6</value>
+ <!-- Hyperlink Theme Color -->
+ <value>hyperlink</value>
+ <!-- Followed Hyperlink Theme Color -->
+ <value>followedHyperlink</value>
+ <!-- No Theme Color -->
+ <value>none</value>
+ <!-- Background 1 Theme Color -->
+ <value>background1</value>
+ <!-- Text 1 Theme Color -->
+ <value>text1</value>
+ <!-- Background 2 Theme Color -->
+ <value>background2</value>
+ <!-- Text 2 Theme Color -->
+ <value>text2</value>
+ </choice>
+ </define>
+ <define name="CT_DocPartBehavior">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartBehaviors">
+ <element name="behavior">
+ <ref name="CT_DocPartBehavior"/>
+ </element>
+ </define>
+ <define name="CT_DocPartType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartTypes">
+ <element name="type">
+ <ref name="CT_DocPartType"/>
+ </element>
+ <attribute name="all">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartGallery">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartCategory">
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="gallery">
+ <ref name="CT_DocPartGallery"/>
+ </element>
+ </define>
+ <define name="CT_DocPartName">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="decorated">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartPr">
+ <choice>
+ <element name="name">
+ <ref name="CT_DocPartName"/>
+ </element>
+ <element name="style">
+ <ref name="CT_String"/>
+ </element>
+ <element name="category">
+ <ref name="CT_DocPartCategory"/>
+ </element>
+ <element name="types">
+ <ref name="CT_DocPartTypes"/>
+ </element>
+ <element name="behaviors">
+ <ref name="CT_DocPartBehaviors"/>
+ </element>
+ <element name="description">
+ <ref name="CT_String"/>
+ </element>
+ <element name="guid">
+ <ref name="CT_Guid"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_DocPart">
+ <element name="docPartPr">
+ <ref name="CT_DocPartPr"/>
+ </element>
+ <element name="docPartBody">
+ <ref name="CT_Body"/>
+ </element>
+ </define>
+ <define name="CT_DocParts">
+ <element name="docPart">
+ <ref name="CT_DocPart"/>
+ </element>
+ </define>
+ <define name="settings">
+ <element name="settings">
+ <ref name="CT_Settings"/>
+ </element>
+ </define>
+ <define name="webSettings">
+ <element name="webSettings">
+ <ref name="CT_WebSettings"/>
+ </element>
+ </define>
+ <define name="fonts">
+ <element name="fonts">
+ <ref name="CT_FontsList"/>
+ </element>
+ </define>
+ <define name="numbering">
+ <element name="numbering">
+ <ref name="CT_Numbering"/>
+ </element>
+ </define>
+ <define name="styles">
+ <element name="styles">
+ <ref name="CT_Styles"/>
+ </element>
+ </define>
+ <define name="ST_CaptionPos">
+ <choice>
+ <!-- Position Caption Above Object -->
+ <value>above</value>
+ <!-- Position Caption Below Object -->
+ <value>below</value>
+ <!-- Position Caption Left Of Object -->
+ <value>left</value>
+ <!-- Position Caption Right Of Object -->
+ <value>right</value>
+ </choice>
+ </define>
+ <define name="CT_Caption">
+ <attribute name="name">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="pos">
+ <ref name="ST_CaptionPos"/>
+ </attribute>
+ <attribute name="chapNum">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="heading">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="noLabel">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="numFmt">
+ <ref name="ST_NumberFormat"/>
+ </attribute>
+ <attribute name="sep">
+ <ref name="ST_ChapterSep"/>
+ </attribute>
+ </define>
+ <define name="CT_AutoCaption">
+ <attribute name="name">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="caption">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_AutoCaptions">
+ <element name="autoCaption">
+ <ref name="CT_AutoCaption"/>
+ </element>
+ </define>
+ <define name="CT_Captions">
+ <element name="caption">
+ <ref name="CT_Caption"/>
+ </element>
+ <element name="autoCaptions">
+ <ref name="CT_AutoCaptions"/>
+ </element>
+ </define>
+ <define name="CT_DocumentBase">
+ <element name="background">
+ <ref name="CT_Background"/>
+ </element>
+ </define>
+ <define name="CT_Document">
+ <ref name="CT_DocumentBase"/>
+ <element name="body">
+ <ref name="CT_Body"/>
+ </element>
+ </define>
+ <define name="CT_GlossaryDocument">
+ <ref name="CT_DocumentBase"/>
+ <element name="docParts">
+ <ref name="CT_DocParts"/>
+ </element>
+ </define>
+ <define name="document">
+ <element name="document">
+ <ref name="CT_Document"/>
+ </element>
+ </define>
+ <define name="glossaryDocument">
+ <element name="glossaryDocument">
+ <ref name="CT_GlossaryDocument"/>
+ </element>
+ </define>
+ <define name="BUILT_IN_ANY_TYPE">
+ <choice>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <data type="string"/>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="CT_Empty" resource="Stream">
+ <action name="end" tokenid="ooxml:EG_RunInnerContent_noBreakHyphen" action="noBreakHyphen"/>
+ <action name="end" tokenid="ooxml:EG_RunInnerContent_softHyphen" action="softHyphen"/>
+ <action name="end" tokenid="ooxml:EG_RunInnerContent_cr" action="cr"/>
+ </resource>
+ <resource name="ST_OnOff" resource="Boolean"/>
+ <resource name="CT_OnOff" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OnOff_val" action="setValue"/>
+ <action name="start" action="setDefaultBooleanValue"/>
+ </resource>
+ <resource name="ST_LongHexNumber" resource="Hex"/>
+ <resource name="CT_LongHexNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_LongHexNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="ST_ShortHexNumber" resource="Hex"/>
+ <resource name="CT_ShortHexNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_ShortHexNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="ST_UcharHexNumber" resource="Hex"/>
+ <resource name="CT_UcharHexNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_UcharHexNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="ST_DecimalNumber" resource="Integer"/>
+ <resource name="CT_DecimalNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DecimalNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_UnsignedDecimalNumber" resource="Integer"/>
+<!--
+ Historically, LO has treated TwipsMeasure as signed,
+ i.e. that negative numbers are allowed and treated as negative,
+ so that is the default handling.
+-->
+ <resource name="ST_TwipsMeasure" resource="TwipsMeasure_asSigned"/>
+ <resource name="ST_TwipsMeasure_asSigned" resource="TwipsMeasure_asSigned"/>
+ <resource name="ST_TwipsMeasure_asZero" resource="TwipsMeasure_asZero"/>
+ <resource name="CT_TwipsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TwipsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_SignedTwipsMeasure" resource="TwipsMeasure_asSigned"/>
+ <resource name="CT_SignedTwipsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SignedTwipsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_PixelsMeasure" resource="Integer"/>
+ <resource name="CT_PixelsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PixelsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_HpsMeasure" resource="HpsMeasure"/>
+ <resource name="CT_HpsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_HpsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_SignedHpsMeasure" resource="Integer"/>
+ <resource name="CT_SignedHpsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SignedHpsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_MeasurementOrPercent" resource="MeasurementOrPercent"/>
+ <resource name="ST_DateTime" resource="String"/>
+ <resource name="CT_MacroName" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MacroName_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_EighthPointMeasure" resource="Integer"/>
+ <resource name="ST_PointMeasure" resource="Integer"/>
+ <resource name="ST_String" resource="String"/>
+ <resource name="CT_String" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_String_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_TextScale" resource="Integer"/>
+ <resource name="CT_TextScale" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextScale_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_HighlightColor" resource="List">
+ <value tokenid="ooxml:Value_ST_HighlightColor_black">black</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_blue">blue</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_cyan">cyan</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_green">green</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_magenta">magenta</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_red">red</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_yellow">yellow</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_white">white</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkBlue">darkBlue</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkCyan">darkCyan</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkGreen">darkGreen</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkMagenta">darkMagenta</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkRed">darkRed</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkYellow">darkYellow</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkGray">darkGray</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_lightGray">lightGray</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_none">none</value>
+ </resource>
+ <resource name="CT_Highlight" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Highlight_val" action="setValue"/>
+ </resource>
+ <resource name="ST_HexColorAuto" resource="List">
+ <value tokenid="ooxml:Value_ST_HexColorAuto_auto">auto</value>
+ </resource>
+ <resource name="ST_HexColorRGB" resource="Hex"/>
+ <resource name="ST_HexColor" resource="HexColor"/>
+ <resource name="CT_Color" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Color_val"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Color_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Color_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Color_themeShade"/>
+ </resource>
+ <resource name="ST_LangCode" resource="Hex"/>
+ <resource name="ST_Lang" resource="String"/>
+ <resource name="CT_Lang" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Lang_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="CT_Guid" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Guid_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_Underline" resource="List">
+ <value tokenid="ooxml:Value_ST_Underline_single">single</value>
+ <value tokenid="ooxml:Value_ST_Underline_words">words</value>
+ <value tokenid="ooxml:Value_ST_Underline_double">double</value>
+ <value tokenid="ooxml:Value_ST_Underline_thick">thick</value>
+ <value tokenid="ooxml:Value_ST_Underline_dotted">dotted</value>
+ <value tokenid="ooxml:Value_ST_Underline_dottedHeavy">dottedHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dash">dash</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashedHeavy">dashedHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashLong">dashLong</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashLongHeavy">dashLongHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dotDash">dotDash</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashDotHeavy">dashDotHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dotDotDash">dotDotDash</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashDotDotHeavy">dashDotDotHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_wave">wave</value>
+ <value tokenid="ooxml:Value_ST_Underline_wavyHeavy">wavyHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_wavyDouble">wavyDouble</value>
+ <value tokenid="ooxml:Value_ST_Underline_none">none</value>
+ </resource>
+ <resource name="CT_Underline" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Underline_val"/>
+ <attribute name="color" tokenid="ooxml:CT_Underline_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Underline_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Underline_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Underline_themeShade"/>
+ </resource>
+ <resource name="ST_TextEffect" resource="List">
+ <value tokenid="ooxml:Value_ST_TextEffect_none">none</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_lights">lights</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_blinkBackground">blinkBackground</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_sparkle">sparkle</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_antsBlack">antsBlack</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_antsRed">antsRed</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_shimmer">shimmer</value>
+ </resource>
+ <resource name="CT_TextEffect" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextEffect_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Border" resource="List">
+ <value tokenid="ooxml:Value_ST_Border_nil">nil</value>
+ <value tokenid="ooxml:Value_ST_Border_none">none</value>
+ <value tokenid="ooxml:Value_ST_Border_single">single</value>
+ <value tokenid="ooxml:Value_ST_Border_thick">thick</value>
+ <value tokenid="ooxml:Value_ST_Border_double">double</value>
+ <value tokenid="ooxml:Value_ST_Border_dotted">dotted</value>
+ <value tokenid="ooxml:Value_ST_Border_dashed">dashed</value>
+ <value tokenid="ooxml:Value_ST_Border_dotDash">dotDash</value>
+ <value tokenid="ooxml:Value_ST_Border_dotDotDash">dotDotDash</value>
+ <value tokenid="ooxml:Value_ST_Border_triple">triple</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickSmallGap">thinThickSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thickThinSmallGap">thickThinSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickThinSmallGap">thinThickThinSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickMediumGap">thinThickMediumGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thickThinMediumGap">thickThinMediumGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickThinMediumGap">thinThickThinMediumGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickLargeGap">thinThickLargeGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thickThinLargeGap">thickThinLargeGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickThinLargeGap">thinThickThinLargeGap</value>
+ <value tokenid="ooxml:Value_ST_Border_wave">wave</value>
+ <value tokenid="ooxml:Value_ST_Border_doubleWave">doubleWave</value>
+ <value tokenid="ooxml:Value_ST_Border_dashSmallGap">dashSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_dashDotStroked">dashDotStroked</value>
+ <value tokenid="ooxml:Value_ST_Border_threeDEmboss">threeDEmboss</value>
+ <value tokenid="ooxml:Value_ST_Border_threeDEngrave">threeDEngrave</value>
+ <value tokenid="ooxml:Value_ST_Border_outset">outset</value>
+ <value tokenid="ooxml:Value_ST_Border_inset">inset</value>
+ <value tokenid="ooxml:Value_ST_Border_apples">apples</value>
+ <value tokenid="ooxml:Value_ST_Border_archedScallops">archedScallops</value>
+ <value tokenid="ooxml:Value_ST_Border_babyPacifier">babyPacifier</value>
+ <value tokenid="ooxml:Value_ST_Border_babyRattle">babyRattle</value>
+ <value tokenid="ooxml:Value_ST_Border_balloons3Colors">balloons3Colors</value>
+ <value tokenid="ooxml:Value_ST_Border_balloonsHotAir">balloonsHotAir</value>
+ <value tokenid="ooxml:Value_ST_Border_basicBlackDashes">basicBlackDashes</value>
+ <value tokenid="ooxml:Value_ST_Border_basicBlackDots">basicBlackDots</value>
+ <value tokenid="ooxml:Value_ST_Border_basicBlackSquares">basicBlackSquares</value>
+ <value tokenid="ooxml:Value_ST_Border_basicThinLines">basicThinLines</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWhiteDashes">basicWhiteDashes</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWhiteDots">basicWhiteDots</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWhiteSquares">basicWhiteSquares</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWideInline">basicWideInline</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWideMidline">basicWideMidline</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWideOutline">basicWideOutline</value>
+ <value tokenid="ooxml:Value_ST_Border_bats">bats</value>
+ <value tokenid="ooxml:Value_ST_Border_birds">birds</value>
+ <value tokenid="ooxml:Value_ST_Border_birdsFlight">birdsFlight</value>
+ <value tokenid="ooxml:Value_ST_Border_cabins">cabins</value>
+ <value tokenid="ooxml:Value_ST_Border_cakeSlice">cakeSlice</value>
+ <value tokenid="ooxml:Value_ST_Border_candyCorn">candyCorn</value>
+ <value tokenid="ooxml:Value_ST_Border_celticKnotwork">celticKnotwork</value>
+ <value tokenid="ooxml:Value_ST_Border_certificateBanner">certificateBanner</value>
+ <value tokenid="ooxml:Value_ST_Border_chainLink">chainLink</value>
+ <value tokenid="ooxml:Value_ST_Border_champagneBottle">champagneBottle</value>
+ <value tokenid="ooxml:Value_ST_Border_checkedBarBlack">checkedBarBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_checkedBarColor">checkedBarColor</value>
+ <value tokenid="ooxml:Value_ST_Border_checkered">checkered</value>
+ <value tokenid="ooxml:Value_ST_Border_christmasTree">christmasTree</value>
+ <value tokenid="ooxml:Value_ST_Border_circlesLines">circlesLines</value>
+ <value tokenid="ooxml:Value_ST_Border_circlesRectangles">circlesRectangles</value>
+ <value tokenid="ooxml:Value_ST_Border_classicalWave">classicalWave</value>
+ <value tokenid="ooxml:Value_ST_Border_clocks">clocks</value>
+ <value tokenid="ooxml:Value_ST_Border_compass">compass</value>
+ <value tokenid="ooxml:Value_ST_Border_confetti">confetti</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiGrays">confettiGrays</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiOutline">confettiOutline</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiStreamers">confettiStreamers</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiWhite">confettiWhite</value>
+ <value tokenid="ooxml:Value_ST_Border_cornerTriangles">cornerTriangles</value>
+ <value tokenid="ooxml:Value_ST_Border_couponCutoutDashes">couponCutoutDashes</value>
+ <value tokenid="ooxml:Value_ST_Border_couponCutoutDots">couponCutoutDots</value>
+ <value tokenid="ooxml:Value_ST_Border_crazyMaze">crazyMaze</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesButterfly">creaturesButterfly</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesFish">creaturesFish</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesInsects">creaturesInsects</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesLadyBug">creaturesLadyBug</value>
+ <value tokenid="ooxml:Value_ST_Border_crossStitch">crossStitch</value>
+ <value tokenid="ooxml:Value_ST_Border_cup">cup</value>
+ <value tokenid="ooxml:Value_ST_Border_decoArch">decoArch</value>
+ <value tokenid="ooxml:Value_ST_Border_decoArchColor">decoArchColor</value>
+ <value tokenid="ooxml:Value_ST_Border_decoBlocks">decoBlocks</value>
+ <value tokenid="ooxml:Value_ST_Border_diamondsGray">diamondsGray</value>
+ <value tokenid="ooxml:Value_ST_Border_doubleD">doubleD</value>
+ <value tokenid="ooxml:Value_ST_Border_doubleDiamonds">doubleDiamonds</value>
+ <value tokenid="ooxml:Value_ST_Border_earth1">earth1</value>
+ <value tokenid="ooxml:Value_ST_Border_earth2">earth2</value>
+ <value tokenid="ooxml:Value_ST_Border_eclipsingSquares1">eclipsingSquares1</value>
+ <value tokenid="ooxml:Value_ST_Border_eclipsingSquares2">eclipsingSquares2</value>
+ <value tokenid="ooxml:Value_ST_Border_eggsBlack">eggsBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_fans">fans</value>
+ <value tokenid="ooxml:Value_ST_Border_film">film</value>
+ <value tokenid="ooxml:Value_ST_Border_firecrackers">firecrackers</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersBlockPrint">flowersBlockPrint</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersDaisies">flowersDaisies</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersModern1">flowersModern1</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersModern2">flowersModern2</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersPansy">flowersPansy</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersRedRose">flowersRedRose</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersRoses">flowersRoses</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersTeacup">flowersTeacup</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersTiny">flowersTiny</value>
+ <value tokenid="ooxml:Value_ST_Border_gems">gems</value>
+ <value tokenid="ooxml:Value_ST_Border_gingerbreadMan">gingerbreadMan</value>
+ <value tokenid="ooxml:Value_ST_Border_gradient">gradient</value>
+ <value tokenid="ooxml:Value_ST_Border_handmade1">handmade1</value>
+ <value tokenid="ooxml:Value_ST_Border_handmade2">handmade2</value>
+ <value tokenid="ooxml:Value_ST_Border_heartBalloon">heartBalloon</value>
+ <value tokenid="ooxml:Value_ST_Border_heartGray">heartGray</value>
+ <value tokenid="ooxml:Value_ST_Border_hearts">hearts</value>
+ <value tokenid="ooxml:Value_ST_Border_heebieJeebies">heebieJeebies</value>
+ <value tokenid="ooxml:Value_ST_Border_holly">holly</value>
+ <value tokenid="ooxml:Value_ST_Border_houseFunky">houseFunky</value>
+ <value tokenid="ooxml:Value_ST_Border_hypnotic">hypnotic</value>
+ <value tokenid="ooxml:Value_ST_Border_iceCreamCones">iceCreamCones</value>
+ <value tokenid="ooxml:Value_ST_Border_lightBulb">lightBulb</value>
+ <value tokenid="ooxml:Value_ST_Border_lightning1">lightning1</value>
+ <value tokenid="ooxml:Value_ST_Border_lightning2">lightning2</value>
+ <value tokenid="ooxml:Value_ST_Border_mapPins">mapPins</value>
+ <value tokenid="ooxml:Value_ST_Border_mapleLeaf">mapleLeaf</value>
+ <value tokenid="ooxml:Value_ST_Border_mapleMuffins">mapleMuffins</value>
+ <value tokenid="ooxml:Value_ST_Border_marquee">marquee</value>
+ <value tokenid="ooxml:Value_ST_Border_marqueeToothed">marqueeToothed</value>
+ <value tokenid="ooxml:Value_ST_Border_moons">moons</value>
+ <value tokenid="ooxml:Value_ST_Border_mosaic">mosaic</value>
+ <value tokenid="ooxml:Value_ST_Border_musicNotes">musicNotes</value>
+ <value tokenid="ooxml:Value_ST_Border_northwest">northwest</value>
+ <value tokenid="ooxml:Value_ST_Border_ovals">ovals</value>
+ <value tokenid="ooxml:Value_ST_Border_packages">packages</value>
+ <value tokenid="ooxml:Value_ST_Border_palmsBlack">palmsBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_palmsColor">palmsColor</value>
+ <value tokenid="ooxml:Value_ST_Border_paperClips">paperClips</value>
+ <value tokenid="ooxml:Value_ST_Border_papyrus">papyrus</value>
+ <value tokenid="ooxml:Value_ST_Border_partyFavor">partyFavor</value>
+ <value tokenid="ooxml:Value_ST_Border_partyGlass">partyGlass</value>
+ <value tokenid="ooxml:Value_ST_Border_pencils">pencils</value>
+ <value tokenid="ooxml:Value_ST_Border_people">people</value>
+ <value tokenid="ooxml:Value_ST_Border_peopleWaving">peopleWaving</value>
+ <value tokenid="ooxml:Value_ST_Border_peopleHats">peopleHats</value>
+ <value tokenid="ooxml:Value_ST_Border_poinsettias">poinsettias</value>
+ <value tokenid="ooxml:Value_ST_Border_postageStamp">postageStamp</value>
+ <value tokenid="ooxml:Value_ST_Border_pumpkin1">pumpkin1</value>
+ <value tokenid="ooxml:Value_ST_Border_pushPinNote2">pushPinNote2</value>
+ <value tokenid="ooxml:Value_ST_Border_pushPinNote1">pushPinNote1</value>
+ <value tokenid="ooxml:Value_ST_Border_pyramids">pyramids</value>
+ <value tokenid="ooxml:Value_ST_Border_pyramidsAbove">pyramidsAbove</value>
+ <value tokenid="ooxml:Value_ST_Border_quadrants">quadrants</value>
+ <value tokenid="ooxml:Value_ST_Border_rings">rings</value>
+ <value tokenid="ooxml:Value_ST_Border_safari">safari</value>
+ <value tokenid="ooxml:Value_ST_Border_sawtooth">sawtooth</value>
+ <value tokenid="ooxml:Value_ST_Border_sawtoothGray">sawtoothGray</value>
+ <value tokenid="ooxml:Value_ST_Border_scaredCat">scaredCat</value>
+ <value tokenid="ooxml:Value_ST_Border_seattle">seattle</value>
+ <value tokenid="ooxml:Value_ST_Border_shadowedSquares">shadowedSquares</value>
+ <value tokenid="ooxml:Value_ST_Border_sharksTeeth">sharksTeeth</value>
+ <value tokenid="ooxml:Value_ST_Border_shorebirdTracks">shorebirdTracks</value>
+ <value tokenid="ooxml:Value_ST_Border_skyrocket">skyrocket</value>
+ <value tokenid="ooxml:Value_ST_Border_snowflakeFancy">snowflakeFancy</value>
+ <value tokenid="ooxml:Value_ST_Border_snowflakes">snowflakes</value>
+ <value tokenid="ooxml:Value_ST_Border_sombrero">sombrero</value>
+ <value tokenid="ooxml:Value_ST_Border_southwest">southwest</value>
+ <value tokenid="ooxml:Value_ST_Border_stars">stars</value>
+ <value tokenid="ooxml:Value_ST_Border_starsTop">starsTop</value>
+ <value tokenid="ooxml:Value_ST_Border_stars3d">stars3d</value>
+ <value tokenid="ooxml:Value_ST_Border_starsBlack">starsBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_starsShadowed">starsShadowed</value>
+ <value tokenid="ooxml:Value_ST_Border_sun">sun</value>
+ <value tokenid="ooxml:Value_ST_Border_swirligig">swirligig</value>
+ <value tokenid="ooxml:Value_ST_Border_tornPaper">tornPaper</value>
+ <value tokenid="ooxml:Value_ST_Border_tornPaperBlack">tornPaperBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_trees">trees</value>
+ <value tokenid="ooxml:Value_ST_Border_triangleParty">triangleParty</value>
+ <value tokenid="ooxml:Value_ST_Border_triangles">triangles</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal1">tribal1</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal2">tribal2</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal3">tribal3</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal4">tribal4</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal5">tribal5</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal6">tribal6</value>
+ <value tokenid="ooxml:Value_ST_Border_twistedLines1">twistedLines1</value>
+ <value tokenid="ooxml:Value_ST_Border_twistedLines2">twistedLines2</value>
+ <value tokenid="ooxml:Value_ST_Border_vine">vine</value>
+ <value tokenid="ooxml:Value_ST_Border_waveline">waveline</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingAngles">weavingAngles</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingBraid">weavingBraid</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingRibbon">weavingRibbon</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingStrips">weavingStrips</value>
+ <value tokenid="ooxml:Value_ST_Border_whiteFlowers">whiteFlowers</value>
+ <value tokenid="ooxml:Value_ST_Border_woodwork">woodwork</value>
+ <value tokenid="ooxml:Value_ST_Border_xIllusions">xIllusions</value>
+ <value tokenid="ooxml:Value_ST_Border_zanyTriangles">zanyTriangles</value>
+ <value tokenid="ooxml:Value_ST_Border_zigZag">zigZag</value>
+ <value tokenid="ooxml:Value_ST_Border_zigZagStitch">zigZagStitch</value>
+ </resource>
+ <resource name="CT_Border" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Border_val"/>
+ <attribute name="color" tokenid="ooxml:CT_Border_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Border_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Border_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Border_themeShade"/>
+ <attribute name="sz" tokenid="ooxml:CT_Border_sz"/>
+ <attribute name="space" tokenid="ooxml:CT_Border_space"/>
+ <attribute name="shadow" tokenid="ooxml:CT_Border_shadow"/>
+ <attribute name="frame" tokenid="ooxml:CT_Border_frame"/>
+ </resource>
+ <!-- This DOCX values will be mapped to match the 'DOC' values that are defined here: -->
+ <!-- http://msdn.microsoft.com/en-us/library/dd945712(v=office.12).aspx -->
+ <resource name="ST_Shd" resource="List">
+ <value tokenid="ooxml:Value_ST_Shd_clear">clear</value>
+ <value tokenid="ooxml:Value_ST_Shd_solid">solid</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct5">pct5</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct10">pct10</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct20">pct20</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct25">pct25</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct30">pct30</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct40">pct40</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct50">pct50</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct60">pct60</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct70">pct70</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct75">pct75</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct80">pct80</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct90">pct90</value>
+ <value tokenid="ooxml:Value_ST_Shd_horzStripe">horzStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_vertStripe">vertStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_reverseDiagStripe">reverseDiagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_diagStripe">diagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_horzCross">horzCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_diagCross">diagCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinHorzStripe">thinHorzStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinVertStripe">thinVertStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinReverseDiagStripe">thinReverseDiagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinDiagStripe">thinDiagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinHorzCross">thinHorzCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinDiagCross">thinDiagCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct12">pct12</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct15">pct15</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct35">pct35</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct37">pct37</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct45">pct45</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct55">pct55</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct62">pct62</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct65">pct65</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct85">pct85</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct87">pct87</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct95">pct95</value>
+ <value tokenid="ooxml:Value_ST_Shd_nil">nil</value>
+ </resource>
+ <resource name="CT_Shd" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Shd_val"/>
+ <attribute name="color" tokenid="ooxml:CT_Shd_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Shd_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Shd_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Shd_themeShade"/>
+ <attribute name="fill" tokenid="ooxml:CT_Shd_fill"/>
+ <attribute name="themeFill" tokenid="ooxml:CT_Shd_themeFill"/>
+ <attribute name="themeFillTint" tokenid="ooxml:CT_Shd_themeFillTint"/>
+ <attribute name="themeFillShade" tokenid="ooxml:CT_Shd_themeFillShade"/>
+ </resource>
+ <resource name="CT_VerticalAlignRun" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_VerticalAlignRun_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FitText" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_FitText_val"/>
+ <attribute name="id" tokenid="ooxml:CT_FitText_id"/>
+ </resource>
+ <resource name="ST_Em" resource="List">
+ <value tokenid="ooxml:Value_ST_Em_none">none</value>
+ <value tokenid="ooxml:Value_ST_Em_dot">dot</value>
+ <value tokenid="ooxml:Value_ST_Em_comma">comma</value>
+ <value tokenid="ooxml:Value_ST_Em_circle">circle</value>
+ <value tokenid="ooxml:Value_ST_Em_underDot">underDot</value>
+ </resource>
+ <resource name="CT_Em" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Em_val" action="setValue"/>
+ </resource>
+ <resource name="CT_Language" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Language_val"/>
+ <attribute name="eastAsia" tokenid="ooxml:CT_Language_eastAsia"/>
+ <attribute name="bidi" tokenid="ooxml:CT_Language_bidi"/>
+ </resource>
+ <resource name="ST_CombineBrackets" resource="List">
+ <value tokenid="ooxml:Value_ST_CombineBrackets_none">none</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_round">round</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_square">square</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_angle">angle</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_curly">curly</value>
+ </resource>
+ <resource name="CT_EastAsianLayout" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_EastAsianLayout_id"/>
+ <attribute name="combine" tokenid="ooxml:CT_EastAsianLayout_combine"/>
+ <attribute name="combineBrackets" tokenid="ooxml:CT_EastAsianLayout_combineBrackets"/>
+ <attribute name="vert" tokenid="ooxml:CT_EastAsianLayout_vert"/>
+ <attribute name="vertCompress" tokenid="ooxml:CT_EastAsianLayout_vertCompress"/>
+ </resource>
+ <resource name="ST_XAlign" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_XAlign_left">left</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_center">center</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_right">right</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_inside">inside</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_outside">outside</value>
+ </resource>
+ <resource name="ST_YAlign" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_YAlign_inline">inline</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_top">top</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_center">center</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_bottom">bottom</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_inside">inside</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_outside">outside</value>
+ </resource>
+ <resource name="ST_HeightRule" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_HeightRule_auto">auto</value>
+ <value tokenid="ooxml:Value_doc_ST_HeightRule_exact">exact</value>
+ <value tokenid="ooxml:Value_doc_ST_HeightRule_atLeast">atLeast</value>
+ </resource>
+ <resource name="ST_Wrap" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_Wrap_auto">auto</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_notBeside">notBeside</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_around">around</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_tight">tight</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_through">through</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_none">none</value>
+ </resource>
+ <resource name="ST_VAnchor" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_VAnchor_text">text</value>
+ <value tokenid="ooxml:Value_doc_ST_VAnchor_margin">margin</value>
+ <value tokenid="ooxml:Value_doc_ST_VAnchor_page">page</value>
+ </resource>
+ <resource name="ST_HAnchor" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_HAnchor_text">text</value>
+ <value tokenid="ooxml:Value_doc_ST_HAnchor_margin">margin</value>
+ <value tokenid="ooxml:Value_doc_ST_HAnchor_page">page</value>
+ </resource>
+ <resource name="ST_DropCap" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DropCap_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_DropCap_drop">drop</value>
+ <value tokenid="ooxml:Value_doc_ST_DropCap_margin">margin</value>
+ </resource>
+ <resource name="CT_FramePr" resource="Properties">
+ <attribute name="dropCap" tokenid="ooxml:CT_FramePr_dropCap"/>
+ <attribute name="lines" tokenid="ooxml:CT_FramePr_lines"/>
+ <attribute name="w" tokenid="ooxml:CT_FramePr_w"/>
+ <attribute name="h" tokenid="ooxml:CT_FramePr_h"/>
+ <attribute name="vSpace" tokenid="ooxml:CT_FramePr_vSpace"/>
+ <attribute name="hSpace" tokenid="ooxml:CT_FramePr_hSpace"/>
+ <attribute name="wrap" tokenid="ooxml:CT_FramePr_wrap"/>
+ <attribute name="hAnchor" tokenid="ooxml:CT_FramePr_hAnchor"/>
+ <attribute name="vAnchor" tokenid="ooxml:CT_FramePr_vAnchor"/>
+ <attribute name="x" tokenid="ooxml:CT_FramePr_x"/>
+ <attribute name="xAlign" tokenid="ooxml:CT_FramePr_xAlign"/>
+ <attribute name="y" tokenid="ooxml:CT_FramePr_y"/>
+ <attribute name="yAlign" tokenid="ooxml:CT_FramePr_yAlign"/>
+ <attribute name="hRule" tokenid="ooxml:CT_FramePr_hRule"/>
+ <attribute name="anchorLock" tokenid="ooxml:CT_FramePr_anchorLock"/>
+ </resource>
+ <resource name="ST_TabJc" resource="List">
+ <value tokenid="ooxml:Value_ST_TabJc_clear">clear</value>
+ <value tokenid="ooxml:Value_ST_TabJc_start">start</value>
+ <value tokenid="ooxml:Value_ST_TabJc_left">left</value>
+ <value tokenid="ooxml:Value_ST_TabJc_center">center</value>
+ <value tokenid="ooxml:Value_ST_TabJc_end">end</value>
+ <value tokenid="ooxml:Value_ST_TabJc_right">right</value>
+ <value tokenid="ooxml:Value_ST_TabJc_decimal">decimal</value>
+ <value tokenid="ooxml:Value_ST_TabJc_bar">bar</value>
+ <value tokenid="ooxml:Value_ST_TabJc_num">num</value>
+ </resource>
+ <resource name="ST_TabTlc" resource="List">
+ <value tokenid="ooxml:Value_ST_TabTlc_none">none</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_dot">dot</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_hyphen">hyphen</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_underscore">underscore</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_heavy">heavy</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_middleDot">middleDot</value>
+ </resource>
+ <resource name="CT_TabStop" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_TabStop_val"/>
+ <attribute name="leader" tokenid="ooxml:CT_TabStop_leader"/>
+ <attribute name="pos" tokenid="ooxml:CT_TabStop_pos"/>
+ </resource>
+ <resource name="ST_LineSpacingRule" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_LineSpacingRule_auto">auto</value>
+ <value tokenid="ooxml:Value_doc_ST_LineSpacingRule_exact">exact</value>
+ <value tokenid="ooxml:Value_doc_ST_LineSpacingRule_atLeast">atLeast</value>
+ </resource>
+ <resource name="CT_Spacing" resource="Properties">
+ <attribute name="before" tokenid="ooxml:CT_Spacing_before"/>
+ <attribute name="beforeLines" tokenid="ooxml:CT_Spacing_beforeLines"/>
+ <attribute name="beforeAutospacing" tokenid="ooxml:CT_Spacing_beforeAutospacing"/>
+ <attribute name="after" tokenid="ooxml:CT_Spacing_after"/>
+ <attribute name="afterLines" tokenid="ooxml:CT_Spacing_afterLines"/>
+ <attribute name="afterAutospacing" tokenid="ooxml:CT_Spacing_afterAutospacing"/>
+ <attribute name="line" tokenid="ooxml:CT_Spacing_line"/>
+ <attribute name="lineRule" tokenid="ooxml:CT_Spacing_lineRule"/>
+ </resource>
+ <resource name="CT_Ind" resource="Properties">
+ <attribute name="end" tokenid="ooxml:CT_Ind_end"/>
+ <attribute name="endChars" tokenid="ooxml:CT_Ind_endChars"/>
+ <attribute name="start" tokenid="ooxml:CT_Ind_start"/>
+ <attribute name="startChars" tokenid="ooxml:CT_Ind_startChars"/>
+ <attribute name="hanging" tokenid="ooxml:CT_Ind_hanging"/>
+ <attribute name="hangingChars" tokenid="ooxml:CT_Ind_hangingChars"/>
+ <attribute name="firstLine" tokenid="ooxml:CT_Ind_firstLine"/>
+ <attribute name="firstLineChars" tokenid="ooxml:CT_Ind_firstLineChars"/>
+ <!-- ECMA 1st version -->
+ <attribute name="left" tokenid="ooxml:CT_Ind_left"/>
+ <attribute name="leftChars" tokenid="ooxml:CT_Ind_leftChars"/>
+ <attribute name="right" tokenid="ooxml:CT_Ind_right"/>
+ <attribute name="rightChars" tokenid="ooxml:CT_Ind_rightChars"/>
+ </resource>
+ <resource name="ST_Jc" resource="List">
+ <value tokenid="ooxml:Value_ST_Jc_left">left</value>
+ <value tokenid="ooxml:Value_ST_Jc_right">right</value>
+ <value tokenid="ooxml:Value_ST_Jc_start">start</value>
+ <value tokenid="ooxml:Value_ST_Jc_center">center</value>
+ <value tokenid="ooxml:Value_ST_Jc_end">end</value>
+ <value tokenid="ooxml:Value_ST_Jc_both">both</value>
+ <value tokenid="ooxml:Value_ST_Jc_mediumKashida">mediumKashida</value>
+ <value tokenid="ooxml:Value_ST_Jc_distribute">distribute</value>
+ <value tokenid="ooxml:Value_ST_Jc_numTab">numTab</value>
+ <value tokenid="ooxml:Value_ST_Jc_highKashida">highKashida</value>
+ <value tokenid="ooxml:Value_ST_Jc_lowKashida">lowKashida</value>
+ <value tokenid="ooxml:Value_ST_Jc_thaiDistribute">thaiDistribute</value>
+ </resource>
+ <resource name="CT_Jc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Jc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_View" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_View_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_View_print">print</value>
+ <value tokenid="ooxml:Value_doc_ST_View_outline">outline</value>
+ <value tokenid="ooxml:Value_doc_ST_View_masterPages">masterPages</value>
+ <value tokenid="ooxml:Value_doc_ST_View_normal">normal</value>
+ <value tokenid="ooxml:Value_doc_ST_View_web">web</value>
+ </resource>
+ <resource name="CT_View" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_View_val"/>
+ </resource>
+ <resource name="ST_Zoom" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_Zoom_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_Zoom_fullPage">fullPage</value>
+ <value tokenid="ooxml:Value_doc_ST_Zoom_bestFit">bestFit</value>
+ <value tokenid="ooxml:Value_doc_ST_Zoom_textFit">textFit</value>
+ </resource>
+ <resource name="ST_Percentage" resource="Integer"/>
+ <resource name="CT_Zoom" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Zoom_val"/>
+ <attribute name="percent" tokenid="ooxml:CT_Zoom_percent"/>
+ </resource>
+ <resource name="CT_WritingStyle" resource="Properties">
+ <attribute name="lang" tokenid="ooxml:CT_WritingStyle_lang"/>
+ <attribute name="vendorID" tokenid="ooxml:CT_WritingStyle_vendorID"/>
+ <attribute name="dllVersion" tokenid="ooxml:CT_WritingStyle_dllVersion"/>
+ <attribute name="nlCheck" tokenid="ooxml:CT_WritingStyle_nlCheck"/>
+ <attribute name="checkStyle" tokenid="ooxml:CT_WritingStyle_checkStyle"/>
+ <attribute name="appName" tokenid="ooxml:CT_WritingStyle_appName"/>
+ </resource>
+ <resource name="CT_Proof" resource="Properties">
+ <attribute name="spelling" tokenid="ooxml:CT_Proof_spelling"/>
+ <attribute name="grammar" tokenid="ooxml:CT_Proof_grammar"/>
+ </resource>
+ <resource name="ST_DocType" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DocType_notSpecified">notSpecified</value>
+ <value tokenid="ooxml:Value_doc_ST_DocType_letter">letter</value>
+ <value tokenid="ooxml:Value_doc_ST_DocType_eMail">eMail</value>
+ </resource>
+ <resource name="CT_DocType" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_DocType_val"/>
+ </resource>
+ <resource name="ST_DocProtect" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_readOnly">readOnly</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_comments">comments</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_trackedChanges">trackedChanges</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_forms">forms</value>
+ </resource>
+ <resource name="ST_CryptProv" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_CryptProv_rsaAES">rsaAES</value>
+ <value tokenid="ooxml:Value_doc_ST_CryptProv_rsaFull">rsaFull</value>
+ </resource>
+ <resource name="ST_AlgClass" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_AlgClass_hash">hash</value>
+ </resource>
+ <resource name="ST_AlgType" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_AlgType_typeAny">typeAny</value>
+ </resource>
+ <resource name="AG_Password" resource="Properties">
+ <attribute name="cryptProviderType" tokenid="ooxml:AG_Password_cryptProviderType"/>
+ <attribute name="cryptAlgorithmClass" tokenid="ooxml:AG_Password_cryptAlgorithmClass"/>
+ <attribute name="cryptAlgorithmType" tokenid="ooxml:AG_Password_cryptAlgorithmType"/>
+ <attribute name="cryptAlgorithmSid" tokenid="ooxml:AG_Password_cryptAlgorithmSid"/>
+ <attribute name="cryptSpinCount" tokenid="ooxml:AG_Password_cryptSpinCount"/>
+ <attribute name="cryptProvider" tokenid="ooxml:AG_Password_cryptProvider"/>
+ <attribute name="algIdExt" tokenid="ooxml:AG_Password_algIdExt"/>
+ <attribute name="algIdExtSource" tokenid="ooxml:AG_Password_algIdExtSource"/>
+ <attribute name="cryptProviderTypeExt" tokenid="ooxml:AG_Password_cryptProviderTypeExt"/>
+ <attribute name="cryptProviderTypeExtSource" tokenid="ooxml:AG_Password_cryptProviderTypeExtSource"/>
+ <attribute name="hash" tokenid="ooxml:AG_Password_hash"/>
+ <attribute name="salt" tokenid="ooxml:AG_Password_salt"/>
+ </resource>
+ <resource name="CT_DocProtect" resource="Properties">
+ <attribute name="edit" tokenid="ooxml:CT_DocProtect_edit"/>
+ <attribute name="formatting" tokenid="ooxml:CT_DocProtect_formatting"/>
+ <attribute name="enforcement" tokenid="ooxml:CT_DocProtect_enforcement"/>
+ </resource>
+ <resource name="CT_MailMergeDocType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeDocType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMergeDataType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeDataType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMergeDest" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeDest_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMergeOdsoFMDFieldType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeOdsoFMDFieldType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_TrackChangesView" resource="Properties">
+ <attribute name="markup" tokenid="ooxml:CT_TrackChangesView_markup"/>
+ <attribute name="comments" tokenid="ooxml:CT_TrackChangesView_comments"/>
+ <attribute name="insDel" tokenid="ooxml:CT_TrackChangesView_insDel"/>
+ <attribute name="formatting" tokenid="ooxml:CT_TrackChangesView_formatting"/>
+ <attribute name="inkAnnotations" tokenid="ooxml:CT_TrackChangesView_inkAnnotations"/>
+ </resource>
+ <resource name="CT_Kinsoku" resource="Properties">
+ <attribute name="lang" tokenid="ooxml:CT_Kinsoku_lang"/>
+ <attribute name="val" tokenid="ooxml:CT_Kinsoku_val"/>
+ </resource>
+ <resource name="ST_TextDirection" resource="List">
+ <value tokenid="ooxml:Value_ST_TextDirection_lrTb">lrTb</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_tbRl">tbRl</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_btLr">btLr</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_lrTbV">lrTbV</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_tbRlV">tbRlV</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_tbLrV">tbLrV</value>
+ </resource>
+ <resource name="CT_TextDirection" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextDirection_val" action="setValue"/>
+ </resource>
+ <resource name="ST_TextAlignment" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_top">top</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_center">center</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_baseline">baseline</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_bottom">bottom</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_auto">auto</value>
+ </resource>
+ <resource name="CT_TextAlignment" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextAlignment_val" action="setValue"/>
+ </resource>
+ <resource name="ST_DisplacedByCustomXml" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DisplacedByCustomXml_next">next</value>
+ <value tokenid="ooxml:Value_doc_ST_DisplacedByCustomXml_prev">prev</value>
+ </resource>
+ <resource name="ST_AnnotationVMerge" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_AnnotationVMerge_cont">cont</value>
+ <value tokenid="ooxml:Value_doc_ST_AnnotationVMerge_rest">rest</value>
+ </resource>
+ <resource name="CT_Markup" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_Markup_id"/>
+ </resource>
+ <resource name="CT_TrackChange" resource="Properties">
+ <attribute name="author" tokenid="ooxml:CT_TrackChange_author"/>
+ <attribute name="date" tokenid="ooxml:CT_TrackChange_date"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd" action="clearProps"/>
+ </resource>
+ <resource name="CT_CellMergeTrackChange" resource="Properties">
+ <attribute name="vMerge" tokenid="ooxml:CT_CellMergeTrackChange_vMerge"/>
+ <attribute name="vMergeOrig" tokenid="ooxml:CT_CellMergeTrackChange_vMergeOrig"/>
+ </resource>
+ <resource name="CT_TrackChangeRange" resource="Properties">
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_TrackChangeRange_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_MarkupRange" resource="Properties">
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_MarkupRange_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_MarkupRangeBookmark" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_MarkupRangeBookmark_id"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd"/>
+ </resource>
+ <resource name="CT_PermStart" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_PermStart_id"/>
+ <attribute name="colFirst" tokenid="ooxml:CT_PermStart_colFirst"/>
+ <attribute name="colLast" tokenid="ooxml:CT_PermStart_colLast"/>
+ <attribute name="ed" tokenid="ooxml:CT_PermStart_ed"/>
+ <attribute name="edGrp" tokenid="ooxml:CT_PermStart_edGrp"/>
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermStart_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_PermEnd" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_PermEnd_id"/>
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermEnd_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_MarkupRangeCommentStart" resource="Properties">
+ <attribute name="id" tokenid="ooxml:EG_RangeMarkupElements_commentRangeStart"/>
+ </resource>
+ <resource name="CT_MarkupRangeCommentEnd" resource="Properties">
+ <attribute name="id" tokenid="ooxml:EG_RangeMarkupElements_commentRangeEnd"/>
+ </resource>
+ <resource name="CT_BookmarkRange" resource="Properties">
+ <attribute name="colFirst" tokenid="ooxml:CT_BookmarkRange_colFirst"/>
+ <attribute name="colLast" tokenid="ooxml:CT_BookmarkRange_colLast"/>
+ </resource>
+ <resource name="CT_Bookmark" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_Bookmark_name"/>
+ </resource>
+ <resource name="CT_MoveBookmark" resource="Properties">
+ <attribute name="author" tokenid="ooxml:CT_MoveBookmark_author"/>
+ <attribute name="date" tokenid="ooxml:CT_MoveBookmark_date"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/>
+ </resource>
+ <resource name="CT_Comment" resource="XNote">
+ <attribute name="id" action="checkId"/>
+ <attribute name="initials" tokenid="ooxml:CT_Comment_initials"/>
+ </resource>
+ <resource name="CT_TrackChangeNumbering" resource="Properties">
+ <attribute name="original" tokenid="ooxml:CT_TrackChangeNumbering_original"/>
+ </resource>
+ <resource name="CT_TblPrExChange" resource="Properties">
+ <element name="tblPrEx" tokenid="ooxml:CT_TblPrExChange_tblPrEx"/>
+ </resource>
+ <resource name="CT_TcPrChange" resource="Properties">
+ <element name="tcPr" tokenid="ooxml:CT_TcPrChange_tcPr"/>
+ </resource>
+ <resource name="CT_TrPrChange" resource="Properties">
+ <element name="trPr" tokenid="ooxml:CT_TrPrChange_trPr"/>
+ </resource>
+ <resource name="CT_TblGridChange" resource="Properties">
+ <element name="tblGrid" tokenid="ooxml:CT_TblGridChange_tblGrid"/>
+ </resource>
+ <resource name="CT_TblPrChange" resource="Properties">
+ <element name="tblPr" tokenid="ooxml:CT_TblPrChange_tblPr"/>
+ </resource>
+ <resource name="CT_SectPrChange" resource="Properties">
+ <element name="sectPr" tokenid="ooxml:CT_SectPrChange_sectPr"/>
+ </resource>
+ <resource name="CT_PPrChange" resource="Properties">
+ <element name="pPr" tokenid="ooxml:CT_PPrChange_pPr"/>
+ </resource>
+ <resource name="CT_RPrChange" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_RPrChange_rPr"/>
+ </resource>
+ <resource name="CT_ParaRPrChange" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_ParaRPrChange_rPr"/>
+ </resource>
+ <resource name="CT_RunTrackChange" resource="Stream">
+ <action name="start" action="tokenproperty"/>
+ <action name="start" action="sendPropertiesWithId" sendtokenid="ooxml:trackchange"/>
+ <action name="start" action="clearProps"/>
+ <action name="end" action="tokenproperty"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:endtrackchange"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="EG_RangeMarkupElements" resource="Properties">
+ <element name="bookmarkStart" tokenid="ooxml:EG_RangeMarkupElements_bookmarkStart"/>
+ <element name="bookmarkEnd" tokenid="ooxml:EG_RangeMarkupElements_bookmarkEnd"/>
+ <element name="permStart" tokenid="ooxml:EG_RangeMarkupElements_PermStart"/>
+ <element name="permEnd" tokenid="ooxml:EG_RangeMarkupElements_PermEnd"/>
+ <element name="moveFromRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/>
+ <element name="moveFromRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/>
+ <element name="moveToRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/>
+ <element name="moveToRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd"/>
+ <element name="commentRangeStart" tokenid="ooxml:EG_RangeMarkupElements_commentRangeStart"/>
+ <element name="commentRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_commentRangeEnd"/>
+ <element name="customXmlInsRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart"/>
+ <element name="customXmlInsRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd"/>
+ <element name="customXmlDelRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart"/>
+ <element name="customXmlDelRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd"/>
+ <element name="customXmlMoveFromRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart"/>
+ <element name="customXmlMoveFromRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd"/>
+ <element name="customXmlMoveToRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart"/>
+ <element name="customXmlMoveToRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd"/>
+ </resource>
+ <resource name="CT_NumPr" resource="Properties">
+ <element name="ilvl" tokenid="ooxml:CT_NumPr_ilvl"/>
+ <element name="numId" tokenid="ooxml:CT_NumPr_numId"/>
+ <element name="numberingChange" tokenid="ooxml:CT_NumPr_numberingChange"/>
+ <element name="ins" tokenid="ooxml:CT_NumPr_ins"/>
+ </resource>
+ <resource name="CT_PBdr" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_PBdr_top"/>
+ <element name="left" tokenid="ooxml:CT_PBdr_left"/>
+ <element name="bottom" tokenid="ooxml:CT_PBdr_bottom"/>
+ <element name="right" tokenid="ooxml:CT_PBdr_right"/>
+ <element name="between" tokenid="ooxml:CT_PBdr_between"/>
+ <element name="bar" tokenid="ooxml:CT_PBdr_bar"/>
+ </resource>
+ <resource name="CT_Tabs" resource="Properties">
+ <element name="tab" tokenid="ooxml:CT_Tabs_tab"/>
+ </resource>
+ <resource name="CT_TextboxTightWrap" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextboxTightWrap_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_PPrBase" resource="Properties">
+ <element name="pStyle" tokenid="ooxml:CT_PPrBase_pStyle"/>
+ <element name="keepNext" tokenid="ooxml:CT_PPrBase_keepNext"/>
+ <element name="keepLines" tokenid="ooxml:CT_PPrBase_keepLines"/>
+ <element name="pageBreakBefore" tokenid="ooxml:CT_PPrBase_pageBreakBefore"/>
+ <element name="framePr" tokenid="ooxml:CT_PPrBase_framePr"/>
+ <element name="widowControl" tokenid="ooxml:CT_PPrBase_widowControl"/>
+ <element name="numPr" tokenid="ooxml:CT_PPrBase_numPr"/>
+ <element name="suppressLineNumbers" tokenid="ooxml:CT_PPrBase_suppressLineNumbers"/>
+ <element name="pBdr" tokenid="ooxml:CT_PrBase_pBdr"/>
+ <element name="shd" tokenid="ooxml:CT_PrBase_shd"/>
+ <element name="tabs" tokenid="ooxml:CT_PPrBase_tabs"/>
+ <element name="suppressAutoHyphens" tokenid="ooxml:CT_PPrBase_suppressAutoHyphens"/>
+ <element name="kinsoku" tokenid="ooxml:CT_PPrBase_kinsoku"/>
+ <element name="wordWrap" tokenid="ooxml:CT_PPrBase_wordWrap"/>
+ <element name="overflowPunct" tokenid="ooxml:CT_PPrBase_overflowPunct"/>
+ <element name="topLinePunct" tokenid="ooxml:CT_PPrBase_topLinePunct"/>
+ <element name="autoSpaceDE" tokenid="ooxml:CT_PPrBase_autoSpaceDE"/>
+ <element name="autoSpaceDN" tokenid="ooxml:CT_PPrBase_autoSpaceDN"/>
+ <element name="bidi" tokenid="ooxml:CT_PPrBase_bidi"/>
+ <element name="adjustRightInd" tokenid="ooxml:CT_PPrBase_adjustRightInd"/>
+ <element name="snapToGrid" tokenid="ooxml:CT_PPrBase_snapToGrid"/>
+ <element name="spacing" tokenid="ooxml:CT_PPrBase_spacing"/>
+ <element name="ind" tokenid="ooxml:CT_PPrBase_ind"/>
+ <element name="contextualSpacing" tokenid="ooxml:CT_PPrBase_contextualSpacing"/>
+ <element name="mirrorIndents" tokenid="ooxml:CT_PPrBase_mirrorIndents"/>
+ <element name="suppressOverlap" tokenid="ooxml:CT_PPrBase_suppressOverlap"/>
+ <element name="jc" tokenid="ooxml:CT_PPrBase_jc"/>
+ <element name="textDirection" tokenid="ooxml:CT_PPrBase_textDirection"/>
+ <element name="textAlignment" tokenid="ooxml:CT_PPrBase_textAlignment"/>
+ <element name="textboxTightWrap" tokenid="ooxml:CT_PPrBase_textboxTightWrap"/>
+ <element name="outlineLvl" tokenid="ooxml:CT_PPrBase_outlineLvl"/>
+ <element name="divId" tokenid="ooxml:CT_PPrBase_divId"/>
+ <element name="cnfStyle" tokenid="ooxml:CT_PPrBase_cnfStyle"/>
+ </resource>
+ <resource name="CT_PPr" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_PPr_rPr"/>
+ <element name="sectPr" tokenid="ooxml:CT_PPr_sectPr"/>
+ <element name="pPrChange" tokenid="ooxml:CT_PPr_pPrChange"/>
+ </resource>
+ <resource name="CT_Background" resource="Properties">
+ <attribute name="color" tokenid="ooxml:CT_Background_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Background_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Background_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Background_themeShade"/>
+ <element name="v:background" tokenid="ooxml:CT_Background_v_background"/>
+ </resource>
+ <resource name="CT_Rel" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_Rel_id"/>
+ </resource>
+ <resource name="CT_PictureBase" resource="Properties"/>
+ <resource name="CT_Object" resource="Shape">
+ <attribute name="dxaOrig" tokenid="ooxml:CT_Object_dxaOrig"/>
+ <attribute name="dyaOrig" tokenid="ooxml:CT_Object_dyaOrig"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:object"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_Picture" resource="Shape">
+ <element name="movie" tokenid="ooxml:CT_Picture_movie"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:object"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_Drawing" resource="Properties">
+ <action name="end" action="handlePicture"/>
+ </resource>
+ <resource name="CT_SimpleField" resource="Stream">
+ <element name="fldData" tokenid="ooxml:CT_SimpleField_fldData"/>
+ <attribute name="instr" tokenid="ooxml:CT_SimpleField_instr"/>
+ <attribute name="fldLock" tokenid="ooxml:CT_SimpleField_fldLock"/>
+ <attribute name="dirty" tokenid="ooxml:CT_SimpleField_dirty"/>
+ <action name="start" action="fieldstart"/>
+ <action name="start" action="startCharacterGroup"/>
+ <action name="start" action="printproperty" sendtokenid="ooxml:CT_SimpleField_instr"/>
+ <action name="start" action="endCharacterGroup"/>
+ <action name="start" action="fieldlock_simple"/>
+ <action name="start" action="fieldsep"/>
+ <action name="end" action="fieldend"/>
+ </resource>
+ <resource name="ST_FldCharType" resource="List">
+ <value tokenid="ooxml:Value_ST_FldCharType_begin">begin</value>
+ <value tokenid="ooxml:Value_ST_FldCharType_separate">separate</value>
+ <value tokenid="ooxml:Value_ST_FldCharType_end">end</value>
+ </resource>
+ <resource name="ST_InfoTextType" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_InfoTextType_text">text</value>
+ <value tokenid="ooxml:Value_doc_ST_InfoTextType_autoText">autoText</value>
+ </resource>
+ <resource name="ST_FFName" resource="String"/>
+ <resource name="CT_FFTextType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FFTextType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FFName" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FFName_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FldChar" resource="Stream">
+ <element name="fldData" tokenid="ooxml:CT_FldChar_fldData"/>
+ <element name="ffData" tokenid="ooxml:CT_FldChar_ffData"/>
+ <element name="numberingChange" tokenid="ooxml:CT_FldChar_numberingChange"/>
+ <attribute name="fldCharType" tokenid="ooxml:CT_FldChar_fldCharType"/>
+ <attribute name="fldLock" tokenid="ooxml:CT_FldChar_fldLock"/>
+ <attribute name="dirty" tokenid="ooxml:CT_FldChar_dirty"/>
+ <action name="start" action="fieldstart">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_begin"/>
+ </action>
+ <action name="start" action="fieldsep">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_separate"/>
+ </action>
+ <action name="start" action="fieldend">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_end"/>
+ </action>
+ <action name="start" action="fieldlock"/>
+ </resource>
+ <resource name="CT_Hyperlink" resource="Stream">
+ <attribute name="tgtFrame" tokenid="ooxml:CT_Hyperlink_tgtFrame"/>
+ <attribute name="tooltip" tokenid="ooxml:CT_Hyperlink_tooltip"/>
+ <attribute name="docLocation" tokenid="ooxml:CT_Hyperlink_docLocation"/>
+ <attribute name="history" tokenid="ooxml:CT_Hyperlink_history"/>
+ <attribute name="anchor" tokenid="ooxml:CT_Hyperlink_anchor"/>
+ <attribute name="r:id" tokenid="ooxml:CT_Hyperlink_r_id"/>
+ <action name="start" action="fieldstart"/>
+ <action name="start" action="handleHyperlink"/>
+ <action name="start" action="fieldsep"/>
+ <action name="end" action="fieldend"/>
+ </resource>
+ <resource name="CT_FLDData" resource="Stream">
+ <action name="characters" action="ignore"/>
+ </resource>
+ <resource name="CT_FFData" resource="Properties">
+ <element name="name" tokenid="ooxml:CT_FFData_name"/>
+ <element name="enabled" tokenid="ooxml:CT_FFData_enabled"/>
+ <element name="calcOnExit" tokenid="ooxml:CT_FFData_calcOnExit"/>
+ <element name="entryMacro" tokenid="ooxml:CT_FFData_entryMacro"/>
+ <element name="exitMacro" tokenid="ooxml:CT_FFData_exitMacro"/>
+ <element name="helpText" tokenid="ooxml:CT_FFData_helpText"/>
+ <element name="statusText" tokenid="ooxml:CT_FFData_statusText"/>
+ <element name="checkBox" tokenid="ooxml:CT_FFData_checkBox"/>
+ <element name="ddList" tokenid="ooxml:CT_FFData_ddList"/>
+ <element name="textInput" tokenid="ooxml:CT_FFData_textInput"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:ffdata"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_FFHelpText" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_FFHelpText_type"/>
+ <attribute name="val" tokenid="ooxml:CT_FFHelpText_val"/>
+ </resource>
+ <resource name="CT_FFStatusText" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_FFStatusText_type"/>
+ <attribute name="val" tokenid="ooxml:CT_FFStatusText_val"/>
+ </resource>
+ <resource name="CT_FFCheckBox" resource="Properties">
+ <element name="size" tokenid="ooxml:CT_FFCheckBox_size"/>
+ <element name="sizeAuto" tokenid="ooxml:CT_FFCheckBox_sizeAuto"/>
+ <element name="default" tokenid="ooxml:CT_FFCheckBox_default"/>
+ <element name="checked" tokenid="ooxml:CT_FFCheckBox_checked"/>
+ </resource>
+ <resource name="CT_FFDDList" resource="Properties">
+ <element name="result" tokenid="ooxml:CT_FFDDList_result"/>
+ <element name="default" tokenid="ooxml:CT_FFDDList_default"/>
+ <element name="listEntry" tokenid="ooxml:CT_FFDDList_listEntry"/>
+ </resource>
+ <resource name="CT_FFTextInput" resource="Properties">
+ <element name="type" tokenid="ooxml:CT_FFTextInput_type"/>
+ <element name="default" tokenid="ooxml:CT_FFTextInput_default"/>
+ <element name="maxLength" tokenid="ooxml:CT_FFTextInput_maxLength"/>
+ <element name="format" tokenid="ooxml:CT_FFTextInput_format"/>
+ </resource>
+ <resource name="ST_SectionMark" resource="List">
+ <value tokenid="ooxml:Value_ST_SectionMark_continuous">continuous</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_nextColumn">nextColumn</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_nextPage">nextPage</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_evenPage">evenPage</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_oddPage">oddPage</value>
+ </resource>
+ <resource name="CT_SectType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SectType_val" action="setValue"/>
+ </resource>
+ <resource name="ST_NumberFormat" resource="List">
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimal">decimal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_upperRoman">upperRoman</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_lowerRoman">lowerRoman</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_upperLetter">upperLetter</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_lowerLetter">lowerLetter</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ordinal">ordinal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_cardinalText">cardinalText</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ordinalText">ordinalText</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hex">hex</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chicago">chicago</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographDigital">ideographDigital</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_japaneseCounting">japaneseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_aiueo">aiueo</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_iroha">iroha</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalFullWidth">decimalFullWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalHalfWidth">decimalHalfWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_japaneseLegal">japaneseLegal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_japaneseDigitalTenThousand">japaneseDigitalTenThousand</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedCircle">decimalEnclosedCircle</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalFullWidth2">decimalFullWidth2</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_aiueoFullWidth">aiueoFullWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_irohaFullWidth">irohaFullWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalZero">decimalZero</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_bullet">bullet</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ganada">ganada</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chosung">chosung</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedFullstop">decimalEnclosedFullstop</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedParen">decimalEnclosedParen</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedCircleChinese">decimalEnclosedCircleChinese</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographEnclosedCircle">ideographEnclosedCircle</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographTraditional">ideographTraditional</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographZodiac">ideographZodiac</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographZodiacTraditional">ideographZodiacTraditional</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_taiwaneseCounting">taiwaneseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographLegalTraditional">ideographLegalTraditional</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_taiwaneseCountingThousand">taiwaneseCountingThousand</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_taiwaneseDigital">taiwaneseDigital</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chineseCounting">chineseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chineseLegalSimplified">chineseLegalSimplified</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chineseCountingThousand">chineseCountingThousand</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanDigital">koreanDigital</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanCounting">koreanCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanLegal">koreanLegal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanDigital2">koreanDigital2</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_vietnameseCounting">vietnameseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_russianLower">russianLower</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_russianUpper">russianUpper</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_none">none</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_numberInDash">numberInDash</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hebrew1">hebrew1</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hebrew2">hebrew2</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_arabicAlpha">arabicAlpha</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_arabicAbjad">arabicAbjad</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiVowels">hindiVowels</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiConsonants">hindiConsonants</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiNumbers">hindiNumbers</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiCounting">hindiCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_thaiLetters">thaiLetters</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_thaiNumbers">thaiNumbers</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_thaiCounting">thaiCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_custom">custom</value>
+ </resource>
+ <resource name="ST_PageOrientation" resource="List">
+ <value tokenid="ooxml:Value_ST_PageOrientation_portrait">portrait</value>
+ <value tokenid="ooxml:Value_ST_PageOrientation_landscape">landscape</value>
+ </resource>
+ <resource name="CT_PageSz" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_PageSz_w"/>
+ <attribute name="h" tokenid="ooxml:CT_PageSz_h"/>
+ <attribute name="orient" tokenid="ooxml:CT_PageSz_orient"/>
+ <attribute name="code" tokenid="ooxml:CT_PageSz_code"/>
+ </resource>
+ <resource name="CT_PageMar" resource="Properties">
+ <attribute name="top" tokenid="ooxml:CT_PageMar_top"/>
+ <attribute name="right" tokenid="ooxml:CT_PageMar_right"/>
+ <attribute name="bottom" tokenid="ooxml:CT_PageMar_bottom"/>
+ <attribute name="left" tokenid="ooxml:CT_PageMar_left"/>
+ <attribute name="header" tokenid="ooxml:CT_PageMar_header"/>
+ <attribute name="footer" tokenid="ooxml:CT_PageMar_footer"/>
+ <attribute name="gutter" tokenid="ooxml:CT_PageMar_gutter"/>
+ </resource>
+ <resource name="ST_PageBorderZOrder" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_PageBorderZOrder_front">front</value>
+ <value tokenid="ooxml:Value_doc_ST_PageBorderZOrder_back">back</value>
+ </resource>
+ <resource name="ST_PageBorderDisplay" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_PageBorderDisplay_allPages">allPages</value>
+ <value tokenid="ooxml:Value_doc_ST_PageBorderDisplay_firstPage">firstPage</value>
+ <value tokenid="ooxml:Value_doc_ST_PageBorderDisplay_notFirstPage">notFirstPage</value>
+ </resource>
+ <resource name="ST_PageBorderOffset" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_PageBorderOffset_page">page</value>
+ <value tokenid="ooxml:Value_doc_ST_PageBorderOffset_text">text</value>
+ </resource>
+ <resource name="CT_PageBorders" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_PageBorders_top"/>
+ <element name="left" tokenid="ooxml:CT_PageBorders_left"/>
+ <element name="bottom" tokenid="ooxml:CT_PageBorders_bottom"/>
+ <element name="right" tokenid="ooxml:CT_PageBorders_right"/>
+ <attribute name="zOrder" tokenid="ooxml:CT_PageBorders_zOrder"/>
+ <attribute name="display" tokenid="ooxml:CT_PageBorders_display"/>
+ <attribute name="offsetFrom" tokenid="ooxml:CT_PageBorders_offsetFrom"/>
+ </resource>
+ <resource name="ST_ChapterSep" resource="List">
+ <value tokenid="ooxml:Value_ST_ChapterSep_hyphen">hyphen</value>
+ <value tokenid="ooxml:Value_ST_ChapterSep_period">period</value>
+ <value tokenid="ooxml:Value_ST_ChapterSep_colon">colon</value>
+ <value tokenid="ooxml:Value_ST_ChapterSep_emDash">emDash</value>
+ <value tokenid="ooxml:Value_ST_ChapterSep_enDash">enDash</value>
+ </resource>
+ <resource name="ST_LineNumberRestart" resource="List">
+ <value tokenid="ooxml:Value_ST_LineNumberRestart_newPage">newPage</value>
+ <value tokenid="ooxml:Value_ST_LineNumberRestart_newSection">newSection</value>
+ <value tokenid="ooxml:Value_ST_LineNumberRestart_continuous">continuous</value>
+ </resource>
+ <resource name="CT_LineNumber" resource="Properties">
+ <attribute name="countBy" tokenid="ooxml:CT_LineNumber_countBy"/>
+ <attribute name="start" tokenid="ooxml:CT_LineNumber_start"/>
+ <attribute name="distance" tokenid="ooxml:CT_LineNumber_distance"/>
+ <attribute name="restart" tokenid="ooxml:CT_LineNumber_restart"/>
+ </resource>
+ <resource name="CT_PageNumber" resource="Properties">
+ <attribute name="fmt" tokenid="ooxml:CT_PageNumber_fmt"/>
+ <attribute name="start" tokenid="ooxml:CT_PageNumber_start"/>
+ <attribute name="chapStyle" tokenid="ooxml:CT_PageNumber_chapStyle"/>
+ <attribute name="chapSep" tokenid="ooxml:CT_PageNumber_chapSep"/>
+ </resource>
+ <resource name="CT_Column" resource="Properties">
+ <attribute name="space" tokenid="ooxml:CT_Column_space"/>
+ <attribute name="w" tokenid="ooxml:CT_Column_w"/>
+ </resource>
+ <resource name="CT_Columns" resource="Properties">
+ <attribute name="equalWidth" tokenid="ooxml:CT_Columns_equalWidth"/>
+ <attribute name="space" tokenid="ooxml:CT_Columns_space"/>
+ <attribute name="num" tokenid="ooxml:CT_Columns_num"/>
+ <attribute name="sep" tokenid="ooxml:CT_Columns_sep"/>
+ <element name="col" tokenid="ooxml:CT_Columns_col"/>
+ </resource>
+ <resource name="ST_VerticalJc" resource="List">
+ <value tokenid="ooxml:Value_ST_VerticalJc_top">top</value>
+ <value tokenid="ooxml:Value_ST_VerticalJc_center">center</value>
+ <value tokenid="ooxml:Value_ST_VerticalJc_both">both</value>
+ <value tokenid="ooxml:Value_ST_VerticalJc_bottom">bottom</value>
+ </resource>
+ <resource name="CT_VerticalJc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_VerticalJc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_DocGrid" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DocGrid_default">default</value>
+ <value tokenid="ooxml:Value_doc_ST_DocGrid_lines">lines</value>
+ <value tokenid="ooxml:Value_doc_ST_DocGrid_linesAndChars">linesAndChars</value>
+ <value tokenid="ooxml:Value_doc_ST_DocGrid_snapToChars">snapToChars</value>
+ </resource>
+ <resource name="CT_DocGrid" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_DocGrid_type"/>
+ <attribute name="linePitch" tokenid="ooxml:CT_DocGrid_linePitch"/>
+ <attribute name="charSpace" tokenid="ooxml:CT_DocGrid_charSpace"/>
+ </resource>
+ <resource name="ST_HdrFtr" resource="List">
+ <value tokenid="ooxml:Value_ST_HdrFtr_even">even</value>
+ <value tokenid="ooxml:Value_ST_HdrFtr_default">default</value>
+ <value tokenid="ooxml:Value_ST_HdrFtr_first">first</value>
+ </resource>
+ <resource name="ST_FtnEdn" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_FtnEdn_normal">normal</value>
+ <value tokenid="ooxml:Value_doc_ST_FtnEdn_separator">separator</value>
+ <value tokenid="ooxml:Value_doc_ST_FtnEdn_continuationSeparator">continuationSeparator</value>
+ <value tokenid="ooxml:Value_doc_ST_FtnEdn_continuationNotice">continuationNotice</value>
+ </resource>
+ <resource name="CT_HdrFtrRef" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_HdrFtrRef_type"/>
+ <attribute name="r:id" tokenid="ooxml:CT_HdrFtrRef_id"/>
+ <action name="end" action="handleHdrFtr"/>
+ </resource>
+ <resource name="EG_HdrFtrReferences" resource="Properties">
+ <element name="headerReference" tokenid="ooxml:EG_HdrFtrReferences_headerReference"/>
+ <element name="footerReference" tokenid="ooxml:EG_HdrFtrReferences_footerReference"/>
+ </resource>
+ <resource name="CT_HdrFtr" resource="Stream">
+ <action name="end" action="endParagraphGroup"/>
+ </resource>
+ <resource name="EG_SectPrContents" resource="Properties">
+ <element name="bidi" tokenid="ooxml:EG_SectPrContents_bidi"/>
+ <element name="cols" tokenid="ooxml:EG_SectPrContents_cols"/>
+ <element name="docGrid" tokenid="ooxml:EG_SectPrContents_docGrid"/>
+ <element name="endnotePr" tokenid="ooxml:EG_SectPrContents_endnotePr"/>
+ <element name="footnotePr" tokenid="ooxml:EG_SectPrContents_footnotePr"/>
+ <element name="formProt" tokenid="ooxml:EG_SectPrContents_formProt"/>
+ <element name="lnNumType" tokenid="ooxml:EG_SectPrContents_lnNumType"/>
+ <element name="noEndnote" tokenid="ooxml:EG_SectPrContents_noEndnote"/>
+ <element name="paperSrc" tokenid="ooxml:EG_SectPrContents_paperSrc"/>
+ <element name="pgBorders" tokenid="ooxml:EG_SectPrContents_pgBorders"/>
+ <element name="pgMar" tokenid="ooxml:EG_SectPrContents_pgMar"/>
+ <element name="pgNumType" tokenid="ooxml:EG_SectPrContents_pgNumType"/>
+ <element name="pgSz" tokenid="ooxml:EG_SectPrContents_pgSz"/>
+ <element name="printerSettings" tokenid="ooxml:EG_SectPrContents_printerSettings"/>
+ <element name="rtlGutter" tokenid="ooxml:EG_SectPrContents_rtlGutter"/>
+ <element name="textDirection" tokenid="ooxml:EG_SectPrContents_textDirection"/>
+ <element name="titlePg" tokenid="ooxml:EG_SectPrContents_titlePg"/>
+ <element name="type" tokenid="ooxml:EG_SectPrContents_type"/>
+ <element name="vAlign" tokenid="ooxml:EG_SectPrContents_vAlign"/>
+ </resource>
+ <resource name="CT_SectPrBase" resource="Properties"/>
+ <resource name="CT_SectPr" resource="Properties">
+ <action name="start" action="handleLastParagraphInSection"/>
+ <element name="sectPrChange" tokenid="ooxml:CT_SectPr_sectPrChange"/>
+ <action name="start" action="setLastParagraphInSection"/>
+ </resource>
+ <resource name="CT_finalSectPr" resource="Properties">
+ <action name="start" action="handleLastParagraphInSection"/>
+ <element name="sectPrChange" tokenid="ooxml:CT_SectPr_sectPrChange"/>
+ </resource>
+ <resource name="ST_BrType" resource="List">
+ <value tokenid="ooxml:Value_ST_BrType_column">column</value>
+ <value tokenid="ooxml:Value_ST_BrType_page">page</value>
+ <value tokenid="ooxml:Value_ST_BrType_textWrapping">textWrapping</value>
+ </resource>
+ <resource name="ST_BrClear" resource="List">
+ <value tokenid="ooxml:Value_ST_BrClear_none">none</value>
+ <value tokenid="ooxml:Value_ST_BrClear_left">left</value>
+ <value tokenid="ooxml:Value_ST_BrClear_right">right</value>
+ <value tokenid="ooxml:Value_ST_BrClear_all">all</value>
+ </resource>
+ <resource name="CT_Br" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_Br_type"/>
+ <attribute name="clear" tokenid="ooxml:CT_Br_clear"/>
+ <action name="end" action="handleBreak"/>
+ </resource>
+ <resource name="CT_Br_OutOfOrder" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_Br_type"/>
+ <attribute name="clear" tokenid="ooxml:CT_Br_clear"/>
+ <action name="end" action="handleOutOfOrderBreak"/>
+ </resource>
+ <resource name="ST_PTabAlignment" resource="List">
+ <value tokenid="ooxml:Value_ST_PTabAlignment_left">left</value>
+ <value tokenid="ooxml:Value_ST_PTabAlignment_center">center</value>
+ <value tokenid="ooxml:Value_ST_PTabAlignment_right">right</value>
+ </resource>
+ <resource name="ST_PTabRelativeTo" resource="List">
+ <value tokenid="ooxml:Value_ST_PTabRelativeTo_margin">margin</value>
+ <value tokenid="ooxml:Value_ST_PTabRelativeTo_indent">indent</value>
+ </resource>
+ <resource name="ST_PTabLeader" resource="List">
+ <value tokenid="ooxml:Value_ST_PTabLeader_none">none</value>
+ <value tokenid="ooxml:Value_ST_PTabLeader_dot">dot</value>
+ <value tokenid="ooxml:Value_ST_PTabLeader_hyphen">hyphen</value>
+ <value tokenid="ooxml:Value_ST_PTabLeader_underscore">underscore</value>
+ <value tokenid="ooxml:Value_ST_PTabLeader_middleDot">middleDot</value>
+ </resource>
+ <resource name="CT_PTab" resource="Properties">
+ <attribute name="alignment" tokenid="ooxml:CT_PTab_alignment"/>
+ <attribute name="relativeTo" tokenid="ooxml:CT_PTab_relativeTo"/>
+ <attribute name="leader" tokenid="ooxml:CT_PTab_leader"/>
+ <action name="end" action="tab"/>
+ </resource>
+ <resource name="CT_Sym" resource="Properties">
+ <attribute name="font" tokenid="ooxml:CT_Sym_font"/>
+ <attribute name="char" tokenid="ooxml:CT_Sym_char"/>
+ <action name="end" action="symbol"/>
+ </resource>
+ <resource name="CT_Text" resource="Stream">
+ <attribute name="xml:space" tokenid="ooxml:CT_Text_space"/>
+ <action name="characters" action="text"/>
+ </resource>
+ <resource name="CT_FtnEdnRefChar" resource="Stream">
+ <action name="end" action="ftnednref"/>
+ </resource>
+ <resource name="CT_FtnEdnSep" resource="Stream">
+ <action name="end" action="ftnednsep"/>
+ </resource>
+ <resource name="CT_FtnEdnCont" resource="Stream">
+ <action name="end" action="ftnedncont"/>
+ </resource>
+ <resource name="CT_PgNum" resource="Stream">
+ <action name="end" action="pgNum"/>
+ </resource>
+ <resource name="CT_Cr" resource="Properties">
+ <action name="end" action="handleBreak"/>
+ </resource>
+ <resource name="CT_Tab" resource="Stream">
+ <action name="end" action="tab"/>
+ </resource>
+ <resource name="EG_RunInnerContent" resource="Stream">
+ <element name="br" tokenid="ooxml:EG_RunInnerContent_br"/>
+ <element name="t" tokenid="ooxml:EG_RunInnerContent_t"/>
+ <element name="delText" tokenid="ooxml:EG_RunInnerContent_delText"/>
+ <element name="instrText" tokenid="ooxml:EG_RunInnerContent_instrText"/>
+ <element name="delInstrText" tokenid="ooxml:EG_RunInnerContent_delInstrText"/>
+ <element name="noBreakHyphen" tokenid="ooxml:EG_RunInnerContent_noBreakHyphen"/>
+ <element name="softHyphen" tokenid="ooxml:EG_RunInnerContent_softHyphen"/>
+ <element name="dayShort" tokenid="ooxml:EG_RunInnerContent_dayShort"/>
+ <element name="monthShort" tokenid="ooxml:EG_RunInnerContent_monthShort"/>
+ <element name="yearShort" tokenid="ooxml:EG_RunInnerContent_yearShort"/>
+ <element name="dayLong" tokenid="ooxml:EG_RunInnerContent_dayLong"/>
+ <element name="monthLong" tokenid="ooxml:EG_RunInnerContent_monthLong"/>
+ <element name="yearLong" tokenid="ooxml:EG_RunInnerContent_yearLong"/>
+ <element name="annotationRef" tokenid="ooxml:EG_RunInnerContent_annotationRef"/>
+ <element name="footnoteRef" tokenid="ooxml:EG_RunInnerContent_footnoteRef"/>
+ <element name="endnoteRef" tokenid="ooxml:EG_RunInnerContent_endnoteRef"/>
+ <element name="separator" tokenid="ooxml:EG_RunInnerContent_separator"/>
+ <element name="continuationSeparator" tokenid="ooxml:EG_RunInnerContent_continuationSeparator"/>
+ <element name="sym" tokenid="ooxml:EG_RunInnerContent_sym"/>
+ <element name="pgNum" tokenid="ooxml:EG_RunInnerContent_pgNum"/>
+ <element name="cr" tokenid="ooxml:EG_RunInnerContent_cr"/>
+ <element name="tab" tokenid="ooxml:EG_RunInnerContent_tab"/>
+ <element name="object" tokenid="ooxml:EG_RunInnerContent_object"/>
+ <element name="pict" tokenid="ooxml:EG_RunInnerContent_pict"/>
+ <element name="fldChar" tokenid="ooxml:EG_RunInnerContent_fldChar"/>
+ <element name="ruby" tokenid="ooxml:EG_RunInnerContent_ruby"/>
+ <element name="footnoteReference" tokenid="ooxml:EG_RunInnerContent_footnoteReference"/>
+ <element name="endnoteReference" tokenid="ooxml:EG_RunInnerContent_endnoteReference"/>
+ <element name="commentReference" tokenid="ooxml:EG_RunInnerContent_commentReference"/>
+ <element name="drawing" tokenid="ooxml:EG_RunInnerContent_drawing"/>
+ <element name="ptab" tokenid="ooxml:EG_RunInnerContent_ptab"/>
+ <element name="lastRenderedPageBreak" tokenid="ooxml:EG_RunInnerContent_lastRenderedPageBreak"/>
+ </resource>
+ <resource name="CT_R" resource="Stream">
+ <action name="start" action="startCharacterGroup"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RubyContent_r" sendtokenid="ooxml:EG_RubyContent_r"/>
+ </resource>
+ <resource name="ST_Hint" resource="List">
+ <value tokenid="ooxml:Value_ST_Hint_default">default</value>
+ <value tokenid="ooxml:Value_ST_Hint_eastAsia">eastAsia</value>
+ <value tokenid="ooxml:Value_ST_Hint_cs">cs</value>
+ </resource>
+ <resource name="ST_Theme" resource="List">
+ <value tokenid="ooxml:Value_ST_Theme_majorEastAsia">majorEastAsia</value>
+ <value tokenid="ooxml:Value_ST_Theme_majorBidi">majorBidi</value>
+ <value tokenid="ooxml:Value_ST_Theme_majorAscii">majorAscii</value>
+ <value tokenid="ooxml:Value_ST_Theme_majorHAnsi">majorHAnsi</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorEastAsia">minorEastAsia</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorBidi">minorBidi</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorAscii">minorAscii</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorHAnsi">minorHAnsi</value>
+ </resource>
+ <resource name="CT_Fonts" resource="Properties">
+ <attribute name="hint" tokenid="ooxml:CT_Fonts_hint"/>
+ <attribute name="ascii" tokenid="ooxml:CT_Fonts_ascii"/>
+ <attribute name="hAnsi" tokenid="ooxml:CT_Fonts_hAnsi"/>
+ <attribute name="eastAsia" tokenid="ooxml:CT_Fonts_eastAsia"/>
+ <attribute name="cs" tokenid="ooxml:CT_Fonts_cs"/>
+ <attribute name="asciiTheme" tokenid="ooxml:CT_Fonts_asciiTheme"/>
+ <attribute name="hAnsiTheme" tokenid="ooxml:CT_Fonts_hAnsiTheme"/>
+ <attribute name="eastAsiaTheme" tokenid="ooxml:CT_Fonts_eastAsiaTheme"/>
+ <attribute name="cstheme" tokenid="ooxml:CT_Fonts_cstheme"/>
+ </resource>
+ <resource name="EG_RPrBase" resource="Properties">
+ <element name="rStyle" tokenid="ooxml:EG_RPrBase_rStyle"/>
+ <element name="rFonts" tokenid="ooxml:EG_RPrBase_rFonts"/>
+ <element name="b" tokenid="ooxml:EG_RPrBase_b"/>
+ <element name="bCs" tokenid="ooxml:EG_RPrBase_bCs"/>
+ <element name="i" tokenid="ooxml:EG_RPrBase_i"/>
+ <element name="iCs" tokenid="ooxml:EG_RPrBase_iCs"/>
+ <element name="caps" tokenid="ooxml:EG_RPrBase_caps"/>
+ <element name="smallCaps" tokenid="ooxml:EG_RPrBase_smallCaps"/>
+ <element name="strike" tokenid="ooxml:EG_RPrBase_strike"/>
+ <element name="dstrike" tokenid="ooxml:EG_RPrBase_dstrike"/>
+ <element name="outline" tokenid="ooxml:EG_RPrBase_outline"/>
+ <element name="shadow" tokenid="ooxml:EG_RPrBase_shadow"/>
+ <element name="emboss" tokenid="ooxml:EG_RPrBase_emboss"/>
+ <element name="imprint" tokenid="ooxml:EG_RPrBase_imprint"/>
+ <element name="noProof" tokenid="ooxml:EG_RPrBase_noProof"/>
+ <element name="snapToGrid" tokenid="ooxml:EG_RPrBase_snapToGrid"/>
+ <element name="vanish" tokenid="ooxml:EG_RPrBase_vanish"/>
+ <element name="webHidden" tokenid="ooxml:EG_RPrBase_webHidden"/>
+ <element name="color" tokenid="ooxml:EG_RPrBase_color"/>
+ <element name="spacing" tokenid="ooxml:EG_RPrBase_spacing"/>
+ <element name="w" tokenid="ooxml:EG_RPrBase_w"/>
+ <element name="kern" tokenid="ooxml:EG_RPrBase_kern"/>
+ <element name="position" tokenid="ooxml:EG_RPrBase_position"/>
+ <element name="sz" tokenid="ooxml:EG_RPrBase_sz"/>
+ <element name="szCs" tokenid="ooxml:EG_RPrBase_szCs"/>
+ <element name="highlight" tokenid="ooxml:EG_RPrBase_highlight"/>
+ <element name="u" tokenid="ooxml:EG_RPrBase_u"/>
+ <element name="effect" tokenid="ooxml:EG_RPrBase_effect"/>
+ <element name="bdr" tokenid="ooxml:EG_RPrBase_bdr"/>
+ <element name="shd" tokenid="ooxml:EG_RPrBase_shd"/>
+ <element name="fitText" tokenid="ooxml:EG_RPrBase_fitText"/>
+ <element name="vertAlign" tokenid="ooxml:EG_RPrBase_vertAlign"/>
+ <element name="rtl" tokenid="ooxml:EG_RPrBase_rtl"/>
+ <element name="cs" tokenid="ooxml:EG_RPrBase_cs"/>
+ <element name="em" tokenid="ooxml:EG_RPrBase_em"/>
+ <element name="lang" tokenid="ooxml:EG_RPrBase_lang"/>
+ <element name="eastAsianLayout" tokenid="ooxml:EG_RPrBase_eastAsianLayout"/>
+ <element name="specVanish" tokenid="ooxml:EG_RPrBase_specVanish"/>
+ <element name="oMath" tokenid="ooxml:EG_RPrBase_oMath"/>
+ <element name="w14:glow" tokenid="ooxml:EG_RPrBase_w14_glow"/>
+ <element name="w14:shadow" tokenid="ooxml:EG_RPrBase_w14_shadow"/>
+ <element name="w14:reflection" tokenid="ooxml:EG_RPrBase_w14_reflection"/>
+ <element name="w14:textOutline" tokenid="ooxml:EG_RPrBase_w14_textOutline"/>
+ <element name="w14:textFill" tokenid="ooxml:EG_RPrBase_w14_textFill"/>
+ <element name="w14:scene3d" tokenid="ooxml:EG_RPrBase_w14_scene3d"/>
+ <element name="w14:props3d" tokenid="ooxml:EG_RPrBase_w14_props3d"/>
+ <element name="w14:ligatures" tokenid="ooxml:EG_RPrBase_w14_ligatures"/>
+ <element name="w14:numForm" tokenid="ooxml:EG_RPrBase_w14_numForm"/>
+ <element name="w14:numSpacing" tokenid="ooxml:EG_RPrBase_w14_numSpacing"/>
+ <element name="w14:stylisticSets" tokenid="ooxml:EG_RPrBase_w14_stylisticSets"/>
+ <element name="w14:cntxtAlts" tokenid="ooxml:EG_RPrBase_w14_cntxtAlts"/>
+ </resource>
+ <resource name="EG_RPrContent" resource="Properties">
+ <element name="rPrChange" tokenid="ooxml:EG_RPrContent_rPrChange"/>
+ </resource>
+ <resource name="CT_RPr" resource="Properties">
+ </resource>
+ <resource name="CT_RPrOriginal" resource="Properties"/>
+ <resource name="CT_ParaRPrOriginal" resource="Properties"/>
+ <resource name="CT_ParaRPr" resource="Properties">
+ <element name="ins" tokenid="ooxml:CT_ParaRPr_ins"/>
+ <element name="del" tokenid="ooxml:CT_ParaRPr_del"/>
+ <element name="moveFrom" tokenid="ooxml:CT_ParaRPr_moveFrom"/>
+ <element name="moveTo" tokenid="ooxml:CT_ParaRPr_moveTo"/>
+ <element name="rPrChange" tokenid="ooxml:CT_ParaRPr_rPrChange"/>
+ </resource>
+ <resource name="CT_ParaTrackChange" resource="Properties">
+ <action name="start" action="tokenproperty"/>
+ <action name="start" action="sendPropertiesWithId" sendtokenid="ooxml:paratrackchange"/>
+ <action name="start" action="clearProps"/>
+ </resource>
+ <resource name="CT_AltChunk" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_AltChunk"/>
+ <action name="start" action="handleAltChunk"/>
+ </resource>
+ <resource name="ST_RubyAlign" resource="List">
+ <value tokenid="ooxml:Value_ST_RubyAlign_center">center</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_distributeLetter">distributeLetter</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_distributeSpace">distributeSpace</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_left">left</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_right">right</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_rightVertical">rightVertical</value>
+ </resource>
+ <resource name="CT_RubyAlign" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_RubyAlign_val" action="setValue"/>
+ </resource>
+ <resource name="CT_RubyPr" resource="Properties">
+ <element name="rubyAlign" tokenid="ooxml:CT_RubyPr_rubyAlign"/>
+ <element name="hps" tokenid="ooxml:CT_RubyPr_hps"/>
+ <element name="hpsRaise" tokenid="ooxml:CT_RubyPr_hpsRaise"/>
+ <element name="hpsBaseText" tokenid="ooxml:CT_RubyPr_hpsBaseText"/>
+ <element name="lid" tokenid="ooxml:CT_RubyPr_lid"/>
+ <element name="dirty" tokenid="ooxml:CT_RubyPr_dirty"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:CT_RubyPr" sendtokenid="ooxml:CT_RubyPr"/>
+ </resource>
+ <resource name="CT_Ruby" resource="Stream">
+ <element name="rubyPr" tokenid="ooxml:CT_RubyPr"/>
+ <element name="rt" tokenid="ooxml:CT_Ruby_rt"/>
+ <element name="rubyBase" tokenid="ooxml:CT_Ruby_rubyBase"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RunInnerContent_ruby" sendtokenid="ooxml:EG_RunInnerContent_ruby"/>
+ </resource>
+ <resource name="CT_RubyContent" resource="Stream">
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:CT_Ruby_rt" sendtokenid="ooxml:CT_Ruby_rt"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:CT_Ruby_rubyBase" sendtokenid="ooxml:CT_Ruby_rubyBase"/>
+ </resource>
+ <resource name="EG_RubyContent" resource="Stream">
+ <element name="r" tokenid="ooxml:EG_RubyContent_r"/>
+ </resource>
+ <resource name="CT_Lock" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Lock_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SdtDateMappingType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SdtDateMappingType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_CalendarType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_CalendarType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SdtText" resource="Properties">
+ <attribute name="multiLine" tokenid="ooxml:CT_SdtText_multiLine"/>
+ </resource>
+ <resource name="CT_SdtPlaceholder" resource="Properties">
+ <attribute name="docPart" tokenid="ooxml:CT_SdtPlaceholder_docPart"/>
+ </resource>
+ <resource name="CT_DataBinding" resource="Properties">
+ <attribute name="prefixMappings" tokenid="ooxml:CT_DataBinding_prefixMappings"/>
+ <attribute name="xpath" tokenid="ooxml:CT_DataBinding_xpath"/>
+ <attribute name="storeItemID" tokenid="ooxml:CT_DataBinding_storeItemID"/>
+ </resource>
+ <resource name="CT_SdtColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SdtColor_val"/>
+ </resource>
+ <resource name="CT_SdtPr" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_SdtPr_rPr"/>
+ <element name="alias" tokenid="ooxml:CT_SdtPr_alias"/>
+ <element name="lock" tokenid="ooxml:CT_SdtPr_lock"/>
+ <element name="placeholder" tokenid="ooxml:CT_SdtPr_placeholder"/>
+ <element name="showingPlcHdr" tokenid="ooxml:CT_SdtPr_showingPlcHdr"/>
+ <element name="dataBinding" tokenid="ooxml:CT_SdtPr_dataBinding"/>
+ <element name="temporary" tokenid="ooxml:CT_SdtPr_temporary"/>
+ <element name="id" tokenid="ooxml:CT_SdtPr_id"/>
+ <element name="tag" tokenid="ooxml:CT_SdtPr_tag"/>
+ <element name="equation" tokenid="ooxml:CT_SdtPr_equation"/>
+ <element name="comboBox" tokenid="ooxml:CT_SdtPr_comboBox"/>
+ <element name="w14:checkbox" tokenid="ooxml:CT_SdtPr_checkbox"/>
+ <element name="date" tokenid="ooxml:CT_SdtPr_date"/>
+ <element name="docPartObj" tokenid="ooxml:CT_SdtPr_docPartObj"/>
+ <element name="docPartList" tokenid="ooxml:CT_SdtPr_docPartList"/>
+ <element name="dropDownList" tokenid="ooxml:CT_SdtPr_dropDownList"/>
+ <element name="picture" tokenid="ooxml:CT_SdtPr_picture"/>
+ <element name="richText" tokenid="ooxml:CT_SdtPr_richText"/>
+ <element name="text" tokenid="ooxml:CT_SdtPr_text"/>
+ <element name="citation" tokenid="ooxml:CT_SdtPr_citation"/>
+ <element name="group" tokenid="ooxml:CT_SdtPr_group"/>
+ <element name="bibliography" tokenid="ooxml:CT_SdtPr_bibliography"/>
+ <element name="w15:color" tokenid="ooxml:CT_SdtPr_color"/>
+ </resource>
+ <resource name="CT_SdtEndPr" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_SdtEndPr_rPr"/>
+ </resource>
+ <resource name="CT_DirContentRun" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DirContentRun_val" action="setValue"/>
+ <action name="start" action="pushBiDiEmbedLevel"/>
+ <action name="end" action="popBiDiEmbedLevel"/>
+ </resource>
+ <resource name="ST_Direction" resource="List">
+ <value tokenid="ooxml:Value_ST_Direction_ltr">ltr</value>
+ <value tokenid="ooxml:Value_ST_Direction_rtl">rtl</value>
+ </resource>
+ <resource name="CT_SdtContentRun" resource="Stream"/>
+ <resource name="CT_SdtContentBlock" resource="Stream"/>
+ <resource name="CT_SdtContentRow" resource="Stream"/>
+ <resource name="CT_SdtContentCell" resource="Stream">
+ <action name="start" action="startSdt"/>
+ <action name="end" action="endSdt"/>
+ </resource>
+ <resource name="CT_SdtBlock" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtBlock_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtBlock_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtBlock_sdtContent"/>
+ <element name="sdtEndContent" tokenid="ooxml:CT_SdtBlock_sdtEndContent"/>
+ <action name="start" action="startSdt"/>
+ <action name="end" action="endSdt"/>
+ </resource>
+ <resource name="CT_SdtRun" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtRun_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtRun_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtRun_sdtContent"/>
+ <element name="sdtEndContent" tokenid="ooxml:CT_SdtRun_sdtEndContent"/>
+ <action name="start" action="startSdtRun"/>
+ <action name="end" action="endSdtRun"/>
+ </resource>
+ <resource name="CT_SdtCell" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtCell_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtCell_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtCell_sdtContent"/>
+ </resource>
+ <resource name="CT_SdtRow" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtRow_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtRow_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtRow_sdtContent"/>
+ </resource>
+ <resource name="CT_SdtDropDownList" resource="Properties">
+ <element name="listItem" tokenid="ooxml:CT_SdtDropDownList_listItem"/>
+ </resource>
+ <resource name="CT_SdtDate" resource="Properties">
+ <attribute name="fullDate" tokenid="ooxml:CT_SdtDate_fullDate"/>
+ <element name="dateFormat" tokenid="ooxml:CT_SdtDate_dateFormat"/>
+ <element name="lid" tokenid="ooxml:CT_SdtDate_lid"/>
+ <element name="storeMappedDataAs" tokenid="ooxml:CT_SdtDate_storeMappedDataAs"/>
+ <element name="calendar" tokenid="ooxml:CT_SdtDate_calendar"/>
+ </resource>
+ <resource name="CT_SdtDocPart" resource="Properties">
+ <element name="docPartGallery" tokenid="ooxml:CT_SdtDocPart_docPartGallery"/>
+ <element name="docPartCategory" tokenid="ooxml:CT_SdtDocPart_docPartCategory"/>
+ <element name="docPartUnique" tokenid="ooxml:CT_SdtDocPart_docPartUnique"/>
+ </resource>
+ <resource name="CT_SdtListItem" resource="Properties">
+ <attribute name="displayText" tokenid="ooxml:CT_SdtListItem_displayText"/>
+ <attribute name="value" tokenid="ooxml:CT_SdtListItem_value"/>
+ </resource>
+ <resource name="CT_SdtPlaceholderDocPart" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SdtPlaceholder_docPart_val"/>
+ </resource>
+ <resource name="CT_Attr" resource="Properties">
+ <attribute name="uri" tokenid="ooxml:CT_Attr_uri"/>
+ <attribute name="name" tokenid="ooxml:CT_Attr_name"/>
+ <attribute name="val" tokenid="ooxml:CT_Attr_val"/>
+ </resource>
+ <resource name="CT_CustomXmlRun" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlRun_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlRun_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlRun_element"/>
+ </resource>
+ <resource name="CT_CustomXmlBlock" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlBlock_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlBlock_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlBlock_element"/>
+ </resource>
+ <resource name="CT_CustomXmlCell" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlCell_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlCell_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlCell_element"/>
+ </resource>
+ <resource name="CT_CustomXmlRow" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlRow_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlRow_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlRow_element"/>
+ </resource>
+ <resource name="CT_SmartTagRun" resource="Properties">
+ <element name="smartTagPr" tokenid="ooxml:CT_SmartTagRun_smartTagPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_SmartTagRun_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_SmartTagRun_element"/>
+ </resource>
+ <resource name="CT_SmartTagPr" resource="Properties">
+ <element name="attr" tokenid="ooxml:CT_SmartTagPr_attr"/>
+ </resource>
+ <resource name="EG_PContent" resource="Properties">
+ <element name="fldSimple" tokenid="ooxml:EG_PContent_fldSimple"/>
+ <element name="hyperlink" tokenid="ooxml:EG_PContent_hyperlink"/>
+ <element name="subDoc" tokenid="ooxml:EG_PContent_subDoc"/>
+ </resource>
+ <resource name="CT_P" resource="Stream">
+ <attribute name="w14:paraId" tokenid="ooxml:AG_Parids_paraId"/>
+ <action name="start" action="handleLastParagraphInSection"/>
+ <action name="start" action="startParagraphGroup"/>
+ <action name="start" action="setHandle"/>
+ <action name="start" action="sendTableDepth"/>
+ <action name="end" action="endOfParagraph"/>
+ </resource>
+ <resource name="ST_TblWidth" resource="List">
+ <value tokenid="ooxml:Value_ST_TblWidth_nil">nil</value>
+ <value tokenid="ooxml:Value_ST_TblWidth_pct">pct</value>
+ <value tokenid="ooxml:Value_ST_TblWidth_dxa">dxa</value>
+ <value tokenid="ooxml:Value_ST_TblWidth_auto">auto</value>
+ </resource>
+ <resource name="CT_Height" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Height_val"/>
+ <attribute name="hRule" tokenid="ooxml:CT_Height_hRule"/>
+ </resource>
+ <resource name="CT_TblWidth" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_TblWidth_w"/>
+ <attribute name="type" tokenid="ooxml:CT_TblWidth_type"/>
+ </resource>
+ <resource name="CT_TblPPr" resource="Properties">
+ <attribute name="vertAnchor" tokenid="ooxml:CT_TblPPr_vertAnchor"/>
+ <attribute name="tblpYSpec" tokenid="ooxml:CT_TblPPr_tblpYSpec"/>
+ <attribute name="horzAnchor" tokenid="ooxml:CT_TblPPr_horzAnchor"/>
+ <attribute name="tblpXSpec" tokenid="ooxml:CT_TblPPr_tblpXSpec"/>
+ <attribute name="tblpY" tokenid="ooxml:CT_TblPPr_tblpY"/>
+ <attribute name="tblpX" tokenid="ooxml:CT_TblPPr_tblpX"/>
+ <attribute name="leftFromText" tokenid="ooxml:CT_TblPPr_leftFromText"/>
+ <attribute name="rightFromText" tokenid="ooxml:CT_TblPPr_rightFromText"/>
+ <attribute name="topFromText" tokenid="ooxml:CT_TblPPr_topFromText"/>
+ <attribute name="bottomFromText" tokenid="ooxml:CT_TblPPr_bottomFromText"/>
+ </resource>
+ <resource name="CT_TblGridCol" resource="Value">
+ <attribute name="w" tokenid="ooxml:CT_TblGridCol_w" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="CT_TblGridBase" resource="Properties">
+ <element name="gridCol" tokenid="ooxml:CT_TblGridBase_gridCol"/>
+ </resource>
+ <resource name="CT_TblGrid" resource="Properties">
+ <element name="tblGridChange" tokenid="ooxml:CT_TblGrid_tblGridChange"/>
+ <action name="end" action="propagateTableProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_TcBorders" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TcBorders_top"/>
+ <element name="start" tokenid="ooxml:CT_TcBorders_start"/>
+ <element name="left" tokenid="ooxml:CT_TcBorders_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TcBorders_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TcBorders_end"/>
+ <element name="right" tokenid="ooxml:CT_TcBorders_right"/>
+ <element name="insideH" tokenid="ooxml:CT_TcBorders_insideH"/>
+ <element name="insideV" tokenid="ooxml:CT_TcBorders_insideV"/>
+ <element name="tl2br" tokenid="ooxml:CT_TcBorders_tl2br"/>
+ <element name="tr2bl" tokenid="ooxml:CT_TcBorders_tr2bl"/>
+ </resource>
+ <resource name="CT_TcMar" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TcMar_top"/>
+ <element name="start" tokenid="ooxml:CT_TcMar_start"/>
+ <element name="left" tokenid="ooxml:CT_TcMar_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TcMar_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TcMar_end"/>
+ <element name="right" tokenid="ooxml:CT_TcMar_right"/>
+ </resource>
+ <resource name="ST_Merge" resource="List">
+ <value tokenid="ooxml:Value_ST_Merge_continue">continue</value>
+ <value tokenid="ooxml:Value_ST_Merge_restart">restart</value>
+ </resource>
+ <resource name="CT_VMerge" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_VMerge_val" action="setValue"/>
+ </resource>
+ <resource name="CT_HMerge" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_HMerge_val" action="setValue"/>
+ </resource>
+ <resource name="CT_TcPrBase" resource="Properties">
+ <element name="cnfStyle" tokenid="ooxml:CT_TcPrBase_cnfStyle"/>
+ <element name="tcW" tokenid="ooxml:CT_TcPrBase_tcW"/>
+ <element name="gridSpan" tokenid="ooxml:CT_TcPrBase_gridSpan"/>
+ <element name="hMerge" tokenid="ooxml:CT_TcPrBase_hMerge"/>
+ <element name="vMerge" tokenid="ooxml:CT_TcPrBase_vMerge"/>
+ <element name="tcBorders" tokenid="ooxml:CT_TcPrBase_tcBorders"/>
+ <element name="shd" tokenid="ooxml:CT_TcPrBase_shd"/>
+ <element name="noWrap" tokenid="ooxml:CT_TcPrBase_noWrap"/>
+ <element name="tcMar" tokenid="ooxml:CT_TcPrBase_tcMar"/>
+ <element name="textDirection" tokenid="ooxml:CT_TcPrBase_textDirection"/>
+ <element name="tcFitText" tokenid="ooxml:CT_TcPrBase_tcFitText"/>
+ <element name="vAlign" tokenid="ooxml:CT_TcPrBase_vAlign"/>
+ <element name="hideMark" tokenid="ooxml:CT_TcPrBase_hideMark"/>
+ <element name="cellDel" tokenid="ooxml:CT_TcPrBase_cellDel"/>
+ <element name="cellIns" tokenid="ooxml:CT_TcPrBase_cellIns"/>
+ <element name="cellMerge" tokenid="ooxml:CT_TcPrBase_cellMerge"/>
+ </resource>
+ <resource name="CT_TcPr" resource="Properties">
+ <element name="tcPrChange" tokenid="ooxml:CT_TcPr_tcPrChange"/>
+ <action name="end" action="propagateCellProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_TcPrInner" resource="Properties"/>
+ <resource name="CT_Tc" resource="TextTableCell">
+ <action name="start" action="startCell"/>
+ <action name="end" action="endCell"/>
+ <action name="end" action="sendCellProperties"/>
+ <action name="end" action="endParagraphGroup"/>
+ </resource>
+ <resource name="ST_Cnf" resource="String"/>
+ <resource name="CT_Cnf" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Cnf_val"/>
+ <attribute name="firstRow" tokenid="ooxml:CT_Cnf_firstRow"/>
+ <attribute name="lastRow" tokenid="ooxml:CT_Cnf_lastRow"/>
+ <attribute name="firstColumn" tokenid="ooxml:CT_Cnf_firstColumn"/>
+ <attribute name="lastColumn" tokenid="ooxml:CT_Cnf_lastColumn"/>
+ <attribute name="oddVBand" tokenid="ooxml:CT_Cnf_oddVBand"/>
+ <attribute name="evenVBand" tokenid="ooxml:CT_Cnf_evenVBand"/>
+ <attribute name="oddHBand" tokenid="ooxml:CT_Cnf_oddHBand"/>
+ <attribute name="evenHBand" tokenid="ooxml:CT_Cnf_evenHBand"/>
+ <attribute name="firstRowFirstColumn" tokenid="ooxml:CT_Cnf_firstRowFirstColumn"/>
+ <attribute name="firstRowLastColumn" tokenid="ooxml:CT_Cnf_firstRowLastColumn"/>
+ <attribute name="lastRowFirstColumn" tokenid="ooxml:CT_Cnf_lastRowFirstColumn"/>
+ <attribute name="lastRowLastColumn" tokenid="ooxml:CT_Cnf_lastRowLastColumn"/>
+ </resource>
+ <resource name="CT_TrPrBase" resource="Properties">
+ <element name="cnfStyle" tokenid="ooxml:CT_TrPrBase_cnfStyle"/>
+ <element name="divId" tokenid="ooxml:CT_TrPrBase_divId"/>
+ <element name="gridBefore" tokenid="ooxml:CT_TrPrBase_gridBefore"/>
+ <element name="gridAfter" tokenid="ooxml:CT_TrPrBase_gridAfter"/>
+ <element name="wBefore" tokenid="ooxml:CT_TrPrBase_wBefore"/>
+ <element name="wAfter" tokenid="ooxml:CT_TrPrBase_wAfter"/>
+ <element name="cantSplit" tokenid="ooxml:CT_TrPrBase_cantSplit"/>
+ <element name="trHeight" tokenid="ooxml:CT_TrPrBase_trHeight"/>
+ <element name="tblHeader" tokenid="ooxml:CT_TrPrBase_tblHeader"/>
+ <element name="tblCellSpacing" tokenid="ooxml:CT_TrPrBase_tblCellSpacing"/>
+ <element name="jc" tokenid="ooxml:CT_TrPrBase_jc"/>
+ <element name="hidden" tokenid="ooxml:CT_TrPrBase_hidden"/>
+ </resource>
+ <resource name="CT_TrPrBaseGridAfter" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TrPrBase_gridAfter" action="setValue"/>
+ <action name="end" action="handleGridAfter"/>
+ </resource>
+ <resource name="CT_TrPr" resource="Properties">
+ <element name="ins" tokenid="ooxml:CT_TrPr_ins"/>
+ <element name="del" tokenid="ooxml:CT_TrPr_del"/>
+ <element name="trPrChange" tokenid="ooxml:CT_TrPr_trPrChange"/>
+ <action name="end" action="propagateRowProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_Row" resource="TextTableRow">
+ <action name="start" action="startRow"/>
+ <action name="end" action="sendRowProperties"/>
+ <action name="end" action="sendTableProperties"/>
+ <action name="end" action="endRow"/>
+ </resource>
+ <resource name="ST_TblLayout" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_TblLayout_fixed">fixed</value>
+ <value tokenid="ooxml:Value_doc_ST_TblLayout_autofit">autofit</value>
+ </resource>
+ <resource name="CT_TblLayoutType" resource="Value">
+ <attribute name="type" tokenid="ooxml:CT_TblLayoutType_type" action="setValue"/>
+ </resource>
+ <resource name="ST_TblOverlap" resource="List">
+ <value tokenid="ooxml:Value_ST_TblOverlap_never">never</value>
+ <value tokenid="ooxml:Value_ST_TblOverlap_overlap">overlap</value>
+ </resource>
+ <resource name="CT_TblOverlap" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TblOverlap_val" action="setValue"/>
+ </resource>
+ <resource name="CT_TblCellMar" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TblCellMar_top"/>
+ <element name="start" tokenid="ooxml:CT_TblCellMar_start"/>
+ <element name="left" tokenid="ooxml:CT_TblCellMar_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TblCellMar_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TblCellMar_end"/>
+ <element name="right" tokenid="ooxml:CT_TblCellMar_right"/>
+ </resource>
+ <resource name="CT_TblBorders" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TblBorders_top"/>
+ <element name="start" tokenid="ooxml:CT_TblBorders_start"/>
+ <element name="left" tokenid="ooxml:CT_TblBorders_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TblBorders_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TblBorders_end"/>
+ <element name="right" tokenid="ooxml:CT_TblBorders_right"/>
+ <element name="insideH" tokenid="ooxml:CT_TblBorders_insideH"/>
+ <element name="insideV" tokenid="ooxml:CT_TblBorders_insideV"/>
+ </resource>
+ <resource name="CT_TblPrBase" resource="Properties">
+ <element name="tblStyle" tokenid="ooxml:CT_TblPrBase_tblStyle"/>
+ <element name="tblpPr" tokenid="ooxml:CT_TblPrBase_tblpPr"/>
+ <element name="tblOverlap" tokenid="ooxml:CT_TblPrBase_tblOverlap"/>
+ <element name="bidiVisual" tokenid="ooxml:CT_TblPrBase_bidiVisual"/>
+ <element name="tblStyleRowBandSize" tokenid="ooxml:CT_TblPrBase_tblStyleRowBandSize"/>
+ <element name="tblStyleColBandSize" tokenid="ooxml:CT_TblPrBase_tblStyleColBandSize"/>
+ <element name="tblW" tokenid="ooxml:CT_TblPrBase_tblW"/>
+ <element name="jc" tokenid="ooxml:CT_TblPrBase_jc"/>
+ <element name="tblCellSpacing" tokenid="ooxml:CT_TblPrBase_tblCellSpacing"/>
+ <element name="tblInd" tokenid="ooxml:CT_TblPrBase_tblInd"/>
+ <element name="tblBorders" tokenid="ooxml:CT_TblPrBase_tblBorders"/>
+ <element name="shd" tokenid="ooxml:CT_TblPrBase_shd"/>
+ <element name="tblLayout" tokenid="ooxml:CT_TblPrBase_tblLayout"/>
+ <element name="tblCellMar" tokenid="ooxml:CT_TblPrBase_tblCellMar"/>
+ <element name="tblLook" tokenid="ooxml:CT_TblPrBase_tblLook"/>
+ <element name="tblCaption" tokenid="ooxml:CT_TblPrBase_tblCaption"/>
+ <element name="tblDescription" tokenid="ooxml:CT_TblPrBase_tblDescription"/>
+ </resource>
+ <resource name="CT_TblPr" resource="Properties">
+ <element name="tblPrChange" tokenid="ooxml:CT_TblPr_tblPrChange"/>
+ <action name="end" action="propagateTableProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_TblPrEx" resource="Properties">
+ <element name="tblPrExChange" tokenid="ooxml:CT_TblPrEx_tblPrExChange"/>
+ <element name="tblBorders" tokenid="ooxml:CT_TblPrEx_tblBorders"/>
+ </resource>
+ <resource name="CT_Tbl" resource="TextTable"/>
+ <!-- tdf#111550 : allow <w:tbl> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <resource name="CT_P_Tbl" resource="TextTable">
+ <action name="start" action="start_P_Tbl"/>
+ </resource>
+ <resource name="CT_TblLook" resource="Properties">
+ <attribute name="firstRow" tokenid="ooxml:CT_TblLook_firstRow"/>
+ <attribute name="lastRow" tokenid="ooxml:CT_TblLook_lastRow"/>
+ <attribute name="firstColumn" tokenid="ooxml:CT_TblLook_firstColumn"/>
+ <attribute name="lastColumn" tokenid="ooxml:CT_TblLook_lastColumn"/>
+ <attribute name="noHBand" tokenid="ooxml:CT_TblLook_noHBand"/>
+ <attribute name="noVBand" tokenid="ooxml:CT_TblLook_noVBand"/>
+ <attribute name="val" tokenid="ooxml:CT_TblLook_val"/>
+ </resource>
+ <resource name="ST_FtnPos" resource="List">
+ <value tokenid="ooxml:Value_ST_FtnPos_pageBottom">pageBottom</value>
+ <value tokenid="ooxml:Value_ST_FtnPos_beneathText">beneathText</value>
+ <value tokenid="ooxml:Value_ST_FtnPos_sectEnd">sectEnd</value>
+ <value tokenid="ooxml:Value_ST_FtnPos_docEnd">docEnd</value>
+ </resource>
+ <resource name="CT_FtnPos" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FtnPos_val" action="setValue"/>
+ </resource>
+ <resource name="ST_EdnPos" resource="List">
+ <value tokenid="ooxml:Value_ST_EdnPos_sectEnd">sectEnd</value>
+ <value tokenid="ooxml:Value_ST_EdnPos_docEnd">docEnd</value>
+ </resource>
+ <resource name="CT_EdnPos" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_EdnPos_val" action="setValue"/>
+ </resource>
+ <resource name="CT_NumFmt" resource="Properties">
+ <attribute name="format" tokenid="ooxml:CT_NumFmt_format"/>
+ <attribute name="val" tokenid="ooxml:CT_NumFmt_val"/>
+ </resource>
+ <resource name="ST_RestartNumber" resource="List">
+ <value tokenid="ooxml:Value_ST_RestartNumber_continuous">continuous</value>
+ <value tokenid="ooxml:Value_ST_RestartNumber_eachSect">eachSect</value>
+ <value tokenid="ooxml:Value_ST_RestartNumber_eachPage">eachPage</value>
+ </resource>
+ <resource name="CT_NumRestart" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_NumRestart_val" action="setValue"/>
+ </resource>
+ <resource name="CT_FtnEdnRef" resource="Properties">
+ <attribute name="customMarkFollows" tokenid="ooxml:CT_FtnEdnRef_customMarkFollows"/>
+ <attribute name="id" tokenid="ooxml:CT_FtnEdnRef_id" action="setXNoteId"/>
+ <action name="end" action="handleXNotes"/>
+ </resource>
+ <resource name="CT_FtnEdnSepRef" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_FtnEdnSepRef_id"/>
+ </resource>
+ <resource name="CT_FtnEdn" resource="XNote">
+ <attribute name="type" tokenid="ooxml:CT_FtnEdn_type" action="checkType"/>
+ <attribute name="id" tokenid="ooxml:CT_FtnEdn_id" action="checkId"/>
+ <action name="start" action="propagateCharacterProperties"/>
+ <action name="end" action="endSectionGroup"/>
+ </resource>
+ <resource name="CT_CommentRef" resource="Properties">
+ <action name="end" action="handleComment"/>
+ </resource>
+ <resource name="EG_FtnEdnNumProps" resource="Properties">
+ <element name="numStart" tokenid="ooxml:EG_FtnEdnNumProps_numStart"/>
+ <element name="numRestart" tokenid="ooxml:EG_FtnEdnNumProps_numRestart"/>
+ </resource>
+ <resource name="CT_FtnProps" resource="Properties">
+ <element name="pos" tokenid="ooxml:CT_FtnProps_pos"/>
+ <element name="numFmt" tokenid="ooxml:CT_FtnProps_numFmt"/>
+ </resource>
+ <resource name="CT_EdnProps" resource="Properties">
+ <element name="pos" tokenid="ooxml:CT_EdnProps_pos"/>
+ <element name="numFmt" tokenid="ooxml:CT_EdnProps_numFmt"/>
+ </resource>
+ <resource name="CT_FtnDocProps" resource="Properties">
+ <element name="footnote" tokenid="ooxml:CT_FtnDocProps_footnote"/>
+ </resource>
+ <resource name="CT_EdnDocProps" resource="Properties">
+ <element name="endnote" tokenid="ooxml:CT_EdnDocProps_endnote"/>
+ </resource>
+ <resource name="CT_MailMergeSourceType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeSourceType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMerge" resource="Properties">
+ <element name="mainDocumentType" tokenid="ooxml:CT_MailMerge_mainDocumentType"/>
+ <element name="linkToQuery" tokenid="ooxml:CT_MailMerge_linkToQuery"/>
+ <element name="dataType" tokenid="ooxml:CT_MailMerge_dataType"/>
+ <element name="connectString" tokenid="ooxml:CT_MailMerge_connectString"/>
+ <element name="query" tokenid="ooxml:CT_MailMerge_query"/>
+ <element name="dataSource" tokenid="ooxml:CT_MailMerge_dataSource"/>
+ <element name="headerSource" tokenid="ooxml:CT_MailMerge_headerSource"/>
+ <element name="doNotSuppressBlankLines" tokenid="ooxml:CT_MailMerge_doNotSuppressBlankLines"/>
+ <element name="destination" tokenid="ooxml:CT_MailMerge_destination"/>
+ <element name="addressFieldName" tokenid="ooxml:CT_MailMerge_addressFieldName"/>
+ <element name="mailSubject" tokenid="ooxml:CT_MailMerge_mailSubject"/>
+ <element name="mailAsAttachment" tokenid="ooxml:CT_MailMerge_mailAsAttachment"/>
+ <element name="viewMergedData" tokenid="ooxml:CT_MailMerge_viewMergedData"/>
+ <element name="activeRecord" tokenid="ooxml:CT_MailMerge_activeRecord"/>
+ <element name="checkErrors" tokenid="ooxml:CT_MailMerge_checkErrors"/>
+ <element name="odso" tokenid="ooxml:CT_MailMerge_odso"/>
+ </resource>
+ <resource name="CT_TargetScreenSz" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TargetScreenSz_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_Compat" resource="Properties">
+ <element name="useSingleBorderforContiguousCells" tokenid="ooxml:CT_Compat_useSingleBorderforContiguousCells"/>
+ <element name="wpJustification" tokenid="ooxml:CT_Compat_wpJustification"/>
+ <element name="noTabHangInd" tokenid="ooxml:CT_Compat_noTabHangInd"/>
+ <element name="noLeading" tokenid="ooxml:CT_Compat_noLeading"/>
+ <element name="spaceForUL" tokenid="ooxml:CT_Compat_spaceForUL"/>
+ <element name="noColumnBalance" tokenid="ooxml:CT_Compat_noColumnBalance"/>
+ <element name="balanceSingleByteDoubleByteWidth" tokenid="ooxml:CT_Compat_balanceSingleByteDoubleByteWidth"/>
+ <element name="noExtraLineSpacing" tokenid="ooxml:CT_Compat_noExtraLineSpacing"/>
+ <element name="doNotLeaveBackslashAlone" tokenid="ooxml:CT_Compat_doNotLeaveBackslashAlone"/>
+ <element name="ulTrailSpace" tokenid="ooxml:CT_Compat_ulTrailSpace"/>
+ <element name="doNotExpandShiftReturn" tokenid="ooxml:CT_Compat_doNotExpandShiftReturn"/>
+ <element name="spacingInWholePoints" tokenid="ooxml:CT_Compat_spacingInWholePoints"/>
+ <element name="lineWrapLikeWord6" tokenid="ooxml:CT_Compat_lineWrapLikeWord6"/>
+ <element name="printBodyTextBeforeHeader" tokenid="ooxml:CT_Compat_printBodyTextBeforeHeader"/>
+ <element name="printColBlack" tokenid="ooxml:CT_Compat_printColBlack"/>
+ <element name="wpSpaceWidth" tokenid="ooxml:CT_Compat_wpSpaceWidth"/>
+ <element name="showBreaksInFrames" tokenid="ooxml:CT_Compat_showBreaksInFrames"/>
+ <element name="subFontBySize" tokenid="ooxml:CT_Compat_subFontBySize"/>
+ <element name="suppressBottomSpacing" tokenid="ooxml:CT_Compat_suppressBottomSpacing"/>
+ <element name="suppressTopSpacing" tokenid="ooxml:CT_Compat_suppressTopSpacing"/>
+ <element name="suppressSpacingAtTopOfPage" tokenid="ooxml:CT_Compat_suppressSpacingAtTopOfPage"/>
+ <element name="suppressTopSpacingWP" tokenid="ooxml:CT_Compat_suppressTopSpacingWP"/>
+ <element name="suppressSpBfAfterPgBrk" tokenid="ooxml:CT_Compat_suppressSpBfAfterPgBrk"/>
+ <element name="swapBordersFacingPages" tokenid="ooxml:CT_Compat_swapBordersFacingPages"/>
+ <element name="convMailMergeEsc" tokenid="ooxml:CT_Compat_convMailMergeEsc"/>
+ <element name="truncateFontHeightsLikeWP6" tokenid="ooxml:CT_Compat_truncateFontHeightsLikeWP6"/>
+ <element name="mwSmallCaps" tokenid="ooxml:CT_Compat_mwSmallCaps"/>
+ <element name="usePrinterMetrics" tokenid="ooxml:CT_Compat_usePrinterMetrics"/>
+ <element name="doNotSuppressParagraphBorders" tokenid="ooxml:CT_Compat_doNotSuppressParagraphBorders"/>
+ <element name="wrapTrailSpaces" tokenid="ooxml:CT_Compat_wrapTrailSpaces"/>
+ <element name="footnoteLayoutLikeWW8" tokenid="ooxml:CT_Compat_footnoteLayoutLikeWW8"/>
+ <element name="shapeLayoutLikeWW8" tokenid="ooxml:CT_Compat_shapeLayoutLikeWW8"/>
+ <element name="alignTablesRowByRow" tokenid="ooxml:CT_Compat_alignTablesRowByRow"/>
+ <element name="forgetLastTabAlignment" tokenid="ooxml:CT_Compat_forgetLastTabAlignment"/>
+ <element name="adjustLineHeightInTable" tokenid="ooxml:CT_Compat_adjustLineHeightInTable"/>
+ <element name="autoSpaceLikeWord95" tokenid="ooxml:CT_Compat_autoSpaceLikeWord95"/>
+ <element name="noSpaceRaiseLower" tokenid="ooxml:CT_Compat_noSpaceRaiseLower"/>
+ <element name="doNotUseHTMLParagraphAutoSpacing" tokenid="ooxml:CT_Compat_doNotUseHTMLParagraphAutoSpacing"/>
+ <element name="layoutRawTableWidth" tokenid="ooxml:CT_Compat_layoutRawTableWidth"/>
+ <element name="layoutTableRowsApart" tokenid="ooxml:CT_Compat_layoutTableRowsApart"/>
+ <element name="useWord97LineBreakRules" tokenid="ooxml:CT_Compat_useWord97LineBreakRules"/>
+ <element name="doNotBreakWrappedTables" tokenid="ooxml:CT_Compat_doNotBreakWrappedTables"/>
+ <element name="doNotSnapToGridInCell" tokenid="ooxml:CT_Compat_doNotSnapToGridInCell"/>
+ <element name="selectFldWithFirstOrLastChar" tokenid="ooxml:CT_Compat_selectFldWithFirstOrLastChar"/>
+ <element name="applyBreakingRules" tokenid="ooxml:CT_Compat_applyBreakingRules"/>
+ <element name="doNotWrapTextWithPunct" tokenid="ooxml:CT_Compat_doNotWrapTextWithPunct"/>
+ <element name="doNotUseEastAsianBreakRules" tokenid="ooxml:CT_Compat_doNotUseEastAsianBreakRules"/>
+ <element name="useWord2002TableStyleRules" tokenid="ooxml:CT_Compat_useWord2002TableStyleRules"/>
+ <element name="growAutofit" tokenid="ooxml:CT_Compat_growAutofit"/>
+ <element name="useFELayout" tokenid="ooxml:CT_Compat_useFELayout"/>
+ <element name="useNormalStyleForList" tokenid="ooxml:CT_Compat_useNormalStyleForList"/>
+ <element name="doNotUseIndentAsNumberingTabStop" tokenid="ooxml:CT_Compat_doNotUseIndentAsNumberingTabStop"/>
+ <element name="useAltKinsokuLineBreakRules" tokenid="ooxml:CT_Compat_useAltKinsokuLineBreakRules"/>
+ <element name="allowSpaceOfSameStyleInTable" tokenid="ooxml:CT_Compat_allowSpaceOfSameStyleInTable"/>
+ <element name="doNotSuppressIndentation" tokenid="ooxml:CT_Compat_doNotSuppressIndentation"/>
+ <element name="doNotAutofitConstrainedTables" tokenid="ooxml:CT_Compat_doNotAutofitConstrainedTables"/>
+ <element name="autofitToFirstFixedWidthCell" tokenid="ooxml:CT_Compat_autofitToFirstFixedWidthCell"/>
+ <element name="underlineTabInNumList" tokenid="ooxml:CT_Compat_underlineTabInNumList"/>
+ <element name="displayHangulFixedWidth" tokenid="ooxml:CT_Compat_displayHangulFixedWidth"/>
+ <element name="splitPgBreakAndParaMark" tokenid="ooxml:CT_Compat_splitPgBreakAndParaMark"/>
+ <element name="doNotVertAlignCellWithSp" tokenid="ooxml:CT_Compat_doNotVertAlignCellWithSp"/>
+ <element name="doNotBreakConstrainedForcedTable" tokenid="ooxml:CT_Compat_doNotBreakConstrainedForcedTable"/>
+ <element name="doNotVertAlignInTxbx" tokenid="ooxml:CT_Compat_doNotVertAlignInTxbx"/>
+ <element name="useAnsiKerningPairs" tokenid="ooxml:CT_Compat_useAnsiKerningPairs"/>
+ <element name="cachedColBalance" tokenid="ooxml:CT_Compat_cachedColBalance"/>
+ <element name="compatSetting" tokenid="ooxml:CT_Compat_compatSetting"/>
+ </resource>
+ <resource name="CT_CompatSetting" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_CompatSetting_name"/>
+ <attribute name="uri" tokenid="ooxml:CT_CompatSetting_uri"/>
+ <attribute name="val" tokenid="ooxml:CT_CompatSetting_val"/>
+ </resource>
+ <resource name="CT_DocVar" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_DocVar_name"/>
+ <attribute name="val" tokenid="ooxml:CT_DocVar_val"/>
+ </resource>
+ <resource name="CT_DocRsids" resource="Properties">
+ <element name="rsidRoot" tokenid="ooxml:CT_DocRsids_rsidRoot"/>
+ <element name="rsid" tokenid="ooxml:CT_DocRsids_rsid"/>
+ </resource>
+ <resource name="CT_CharacterSpacing" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_CharacterSpacing_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SaveThroughXslt" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_SaveThroughXslt_r_id"/>
+ <attribute name="solutionID" tokenid="ooxml:CT_SaveThroughXslt_solutionID"/>
+ </resource>
+ <resource name="CT_RPrDefault" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_RPrDefault_rPr"/>
+ </resource>
+ <resource name="CT_PPrDefault" resource="Properties">
+ <element name="pPr" tokenid="ooxml:CT_PPrDefault_pPr"/>
+ </resource>
+ <resource name="CT_DocDefaults" resource="Properties">
+ <element name="pPrDefault" tokenid="ooxml:CT_DocDefaults_pPrDefault"/>
+ <element name="rPrDefault" tokenid="ooxml:CT_DocDefaults_rPrDefault"/>
+ </resource>
+ <resource name="CT_LatentStyles" resource="Properties">
+ <attribute name="defLockedState" tokenid="ooxml:CT_LatentStyles_defLockedState"/>
+ <attribute name="defUIPriority" tokenid="ooxml:CT_LatentStyles_defUIPriority"/>
+ <attribute name="defSemiHidden" tokenid="ooxml:CT_LatentStyles_defSemiHidden"/>
+ <attribute name="defUnhideWhenUsed" tokenid="ooxml:CT_LatentStyles_defUnhideWhenUsed"/>
+ <attribute name="defQFormat" tokenid="ooxml:CT_LatentStyles_defQFormat"/>
+ <attribute name="count" tokenid="ooxml:CT_LatentStyles_count"/>
+ <element name="lsdException" tokenid="ooxml:CT_LatentStyles_lsdException"/>
+ </resource>
+ <resource name="CT_LsdException" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_LsdException_name"/>
+ <attribute name="locked" tokenid="ooxml:CT_LsdException_locked"/>
+ <attribute name="uiPriority" tokenid="ooxml:CT_LsdException_uiPriority"/>
+ <attribute name="semiHidden" tokenid="ooxml:CT_LsdException_semiHidden"/>
+ <attribute name="unhideWhenUsed" tokenid="ooxml:CT_LsdException_unhideWhenUsed"/>
+ <attribute name="qFormat" tokenid="ooxml:CT_LsdException_qFormat"/>
+ </resource>
+ <resource name="ST_ColorSchemeIndex" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_dark1">dark1</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_light1">light1</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_dark2">dark2</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_light2">light2</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent1">accent1</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent2">accent2</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent3">accent3</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent4">accent4</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent5">accent5</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent6">accent6</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_hyperlink">hyperlink</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_followedHyperlink">followedHyperlink</value>
+ </resource>
+ <resource name="CT_ReadingModeInkLockDown" resource="Properties">
+ <attribute name="actualPg" tokenid="ooxml:CT_ReadingModeInkLockDown_actualPg"/>
+ <attribute name="w" tokenid="ooxml:CT_ReadingModeInkLockDown_w"/>
+ <attribute name="h" tokenid="ooxml:CT_ReadingModeInkLockDown_h"/>
+ <attribute name="fontSz" tokenid="ooxml:CT_ReadingModeInkLockDown_fontSz"/>
+ </resource>
+ <resource name="CT_WriteProtection" resource="Properties">
+ <attribute name="recommended" tokenid="ooxml:CT_WriteProtection_recommended"/>
+ </resource>
+ <resource name="CT_Settings" resource="PropertyTable" tokenid="ooxml:SETTINGS">
+ <element name="writeProtection" tokenid="ooxml:CT_Settings_writeProtection"/>
+ <element name="view" tokenid="ooxml:CT_Settings_view"/>
+ <element name="zoom" tokenid="ooxml:CT_Settings_zoom"/>
+ <element name="removePersonalInformation" tokenid="ooxml:CT_Settings_removePersonalInformation"/>
+ <element name="removeDateAndTime" tokenid="ooxml:CT_Settings_removeDateAndTime"/>
+ <element name="doNotDisplayPageBoundaries" tokenid="ooxml:CT_Settings_doNotDisplayPageBoundaries"/>
+ <element name="displayBackgroundShape" tokenid="ooxml:CT_Settings_displayBackgroundShape"/>
+ <element name="printPostScriptOverText" tokenid="ooxml:CT_Settings_printPostScriptOverText"/>
+ <element name="printFractionalCharacterWidth" tokenid="ooxml:CT_Settings_printFractionalCharacterWidth"/>
+ <element name="printFormsData" tokenid="ooxml:CT_Settings_printFormsData"/>
+ <element name="embedTrueTypeFonts" tokenid="ooxml:CT_Settings_embedTrueTypeFonts"/>
+ <element name="embedSystemFonts" tokenid="ooxml:CT_Settings_embedSystemFonts"/>
+ <element name="saveSubsetFonts" tokenid="ooxml:CT_Settings_saveSubsetFonts"/>
+ <element name="saveFormsData" tokenid="ooxml:CT_Settings_saveFormsData"/>
+ <element name="mirrorMargins" tokenid="ooxml:CT_Settings_mirrorMargins"/>
+ <element name="alignBordersAndEdges" tokenid="ooxml:CT_Settings_alignBordersAndEdges"/>
+ <element name="bordersDoNotSurroundHeader" tokenid="ooxml:CT_Settings_bordersDoNotSurroundHeader"/>
+ <element name="bordersDoNotSurroundFooter" tokenid="ooxml:CT_Settings_bordersDoNotSurroundFooter"/>
+ <element name="gutterAtTop" tokenid="ooxml:CT_Settings_gutterAtTop"/>
+ <element name="hideSpellingErrors" tokenid="ooxml:CT_Settings_hideSpellingErrors"/>
+ <element name="hideGrammaticalErrors" tokenid="ooxml:CT_Settings_hideGrammaticalErrors"/>
+ <element name="activeWritingStyle" tokenid="ooxml:CT_Settings_activeWritingStyle"/>
+ <element name="proofState" tokenid="ooxml:CT_Settings_proofState"/>
+ <element name="formsDesign" tokenid="ooxml:CT_Settings_formsDesign"/>
+ <element name="attachedTemplate" tokenid="ooxml:CT_Settings_attachedTemplate"/>
+ <element name="linkStyles" tokenid="ooxml:CT_Settings_linkStyles"/>
+ <element name="stylePaneFormatFilter" tokenid="ooxml:CT_Settings_stylePaneFormatFilter"/>
+ <element name="stylePaneSortMethod" tokenid="ooxml:CT_Settings_stylePaneSortMethod"/>
+ <element name="documentType" tokenid="ooxml:CT_Settings_documentType"/>
+ <element name="mailMerge" tokenid="ooxml:CT_Settings_mailMerge"/>
+ <element name="revisionView" tokenid="ooxml:CT_Settings_revisionView"/>
+ <element name="trackRevisions" tokenid="ooxml:CT_Settings_trackRevisions"/>
+ <element name="doNotTrackMoves" tokenid="ooxml:CT_Settings_doNotTrackMoves"/>
+ <element name="doNotTrackFormatting" tokenid="ooxml:CT_Settings_doNotTrackFormatting"/>
+ <element name="documentProtection" tokenid="ooxml:CT_Settings_documentProtection"/>
+ <element name="autoFormatOverride" tokenid="ooxml:CT_Settings_autoFormatOverride"/>
+ <element name="styleLockTheme" tokenid="ooxml:CT_Settings_styleLockTheme"/>
+ <element name="styleLockQFSet" tokenid="ooxml:CT_Settings_styleLockQFSet"/>
+ <element name="defaultTabStop" tokenid="ooxml:CT_Settings_defaultTabStop"/>
+ <element name="autoHyphenation" tokenid="ooxml:CT_Settings_autoHyphenation"/>
+ <element name="consecutiveHyphenLimit" tokenid="ooxml:CT_Settings_consecutiveHyphenLimit"/>
+ <element name="hyphenationZone" tokenid="ooxml:CT_Settings_hyphenationZone"/>
+ <element name="doNotHyphenateCaps" tokenid="ooxml:CT_Settings_doNotHyphenateCaps"/>
+ <element name="showEnvelope" tokenid="ooxml:CT_Settings_showEnvelope"/>
+ <element name="summaryLength" tokenid="ooxml:CT_Settings_summaryLength"/>
+ <element name="clickAndTypeStyle" tokenid="ooxml:CT_Settings_clickAndTypeStyle"/>
+ <element name="defaultTableStyle" tokenid="ooxml:CT_Settings_defaultTableStyle"/>
+ <element name="evenAndOddHeaders" tokenid="ooxml:CT_Settings_evenAndOddHeaders"/>
+ <element name="bookFoldRevPrinting" tokenid="ooxml:CT_Settings_bookFoldRevPrinting"/>
+ <element name="bookFoldPrinting" tokenid="ooxml:CT_Settings_bookFoldPrinting"/>
+ <element name="bookFoldPrintingSheets" tokenid="ooxml:CT_Settings_bookFoldPrintingSheets"/>
+ <element name="drawingGridHorizontalSpacing" tokenid="ooxml:CT_Settings_drawingGridHorizontalSpacing"/>
+ <element name="drawingGridVerticalSpacing" tokenid="ooxml:CT_Settings_drawingGridVerticalSpacing"/>
+ <element name="displayHorizontalDrawingGridEvery" tokenid="ooxml:CT_Settings_displayHorizontalDrawingGridEvery"/>
+ <element name="displayVerticalDrawingGridEvery" tokenid="ooxml:CT_Settings_displayVerticalDrawingGridEvery"/>
+ <element name="doNotUseMarginsForDrawingGridOrigin" tokenid="ooxml:CT_Settings_doNotUseMarginsForDrawingGridOrigin"/>
+ <element name="drawingGridHorizontalOrigin" tokenid="ooxml:CT_Settings_drawingGridHorizontalOrigin"/>
+ <element name="drawingGridVerticalOrigin" tokenid="ooxml:CT_Settings_drawingGridVerticalOrigin"/>
+ <element name="doNotShadeFormData" tokenid="ooxml:CT_Settings_doNotShadeFormData"/>
+ <element name="noPunctuationKerning" tokenid="ooxml:CT_Settings_noPunctuationKerning"/>
+ <element name="characterSpacingControl" tokenid="ooxml:CT_Settings_characterSpacingControl"/>
+ <element name="printTwoOnOne" tokenid="ooxml:CT_Settings_printTwoOnOne"/>
+ <element name="strictFirstAndLastChars" tokenid="ooxml:CT_Settings_strictFirstAndLastChars"/>
+ <element name="noLineBreaksAfter" tokenid="ooxml:CT_Settings_noLineBreaksAfter"/>
+ <element name="noLineBreaksBefore" tokenid="ooxml:CT_Settings_noLineBreaksBefore"/>
+ <element name="savePreviewPicture" tokenid="ooxml:CT_Settings_savePreviewPicture"/>
+ <element name="doNotValidateAgainstSchema" tokenid="ooxml:CT_Settings_doNotValidateAgainstSchema"/>
+ <element name="saveInvalidXml" tokenid="ooxml:CT_Settings_saveInvalidXml"/>
+ <element name="ignoreMixedContent" tokenid="ooxml:CT_Settings_ignoreMixedContent"/>
+ <element name="alwaysShowPlaceholderText" tokenid="ooxml:CT_Settings_alwaysShowPlaceholderText"/>
+ <element name="doNotDemarcateInvalidXml" tokenid="ooxml:CT_Settings_doNotDemarcateInvalidXml"/>
+ <element name="saveXmlDataOnly" tokenid="ooxml:CT_Settings_saveXmlDataOnly"/>
+ <element name="useXSLTWhenSaving" tokenid="ooxml:CT_Settings_useXSLTWhenSaving"/>
+ <element name="saveThroughXslt" tokenid="ooxml:CT_Settings_saveThroughXslt"/>
+ <element name="showXMLTags" tokenid="ooxml:CT_Settings_showXMLTags"/>
+ <element name="alwaysMergeEmptyNamespace" tokenid="ooxml:CT_Settings_alwaysMergeEmptyNamespace"/>
+ <element name="updateFields" tokenid="ooxml:CT_Settings_updateFields"/>
+ <element name="hdrShapeDefaults" tokenid="ooxml:CT_Settings_hdrShapeDefaults"/>
+ <element name="footnotePr" tokenid="ooxml:CT_Settings_footnotePr"/>
+ <element name="endnotePr" tokenid="ooxml:CT_Settings_endnotePr"/>
+ <element name="compat" tokenid="ooxml:CT_Settings_compat"/>
+ <element name="docVars" tokenid="ooxml:CT_Settings_docVars"/>
+ <element name="rsids" tokenid="ooxml:CT_Settings_rsids"/>
+ <element name="uiCompat97To2003" tokenid="ooxml:CT_Settings_uiCompat97To2003"/>
+ <element name="attachedSchema" tokenid="ooxml:CT_Settings_attachedSchema"/>
+ <element name="themeFontLang" tokenid="ooxml:CT_Settings_themeFontLang"/>
+ <element name="clrSchemeMapping" tokenid="ooxml:CT_Settings_clrSchemeMapping"/>
+ <element name="doNotIncludeSubdocsInStats" tokenid="ooxml:CT_Settings_doNotIncludeSubdocsInStats"/>
+ <element name="doNotAutoCompressPictures" tokenid="ooxml:CT_Settings_doNotAutoCompressPictures"/>
+ <element name="forceUpgrade" tokenid="ooxml:CT_Settings_forceUpgrade"/>
+ <element name="captions" tokenid="ooxml:CT_Settings_captions"/>
+ <element name="readModeInkLockDown" tokenid="ooxml:CT_Settings_readModeInkLockDown"/>
+ <element name="smartTagType" tokenid="ooxml:CT_Settings_smartTagType"/>
+ <element name="shapeDefaults" tokenid="ooxml:CT_Settings_shapeDefaults"/>
+ <element name="doNotEmbedSmartTags" tokenid="ooxml:CT_Settings_doNotEmbedSmartTags"/>
+ <element name="decimalSymbol" tokenid="ooxml:CT_Settings_decimalSymbol"/>
+ <element name="listSeparator" tokenid="ooxml:CT_Settings_listSeparator"/>
+ </resource>
+ <resource name="CT_FrameScrollbar" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FrameScrollbar_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FrameLayout" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FrameLayout_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_LevelSuffix" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_LevelSuffix_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_LevelText" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_LevelText_val"/>
+ <attribute name="null" tokenid="ooxml:CT_LevelText_null"/>
+ </resource>
+ <resource name="CT_LvlLegacy" resource="Properties">
+ <attribute name="legacy" tokenid="ooxml:CT_LvlLegacy_legacy"/>
+ <attribute name="legacySpace" tokenid="ooxml:CT_LvlLegacy_legacySpace"/>
+ <attribute name="legacyIndent" tokenid="ooxml:CT_LvlLegacy_legacyIndent"/>
+ </resource>
+ <resource name="CT_Lvl" resource="Properties">
+ <element name="start" tokenid="ooxml:CT_Lvl_start"/>
+ <element name="numFmt" tokenid="ooxml:CT_Lvl_numFmt"/>
+ <element name="lvlRestart" tokenid="ooxml:CT_Lvl_lvlRestart"/>
+ <element name="pStyle" tokenid="ooxml:CT_Lvl_pStyle"/>
+ <element name="isLgl" tokenid="ooxml:CT_Lvl_isLgl"/>
+ <element name="suff" tokenid="ooxml:CT_Lvl_suff"/>
+ <element name="lvlText" tokenid="ooxml:CT_Lvl_lvlText"/>
+ <element name="lvlPicBulletId" tokenid="ooxml:CT_Lvl_lvlPicBulletId"/>
+ <element name="legacy" tokenid="ooxml:CT_Lvl_legacy"/>
+ <element name="lvlJc" tokenid="ooxml:CT_Lvl_lvlJc"/>
+ <element name="pPr" tokenid="ooxml:CT_Lvl_pPr"/>
+ <element name="rPr" tokenid="ooxml:CT_Lvl_rPr"/>
+ <attribute name="ilvl" tokenid="ooxml:CT_Lvl_ilvl"/>
+ <attribute name="tplc" tokenid="ooxml:CT_Lvl_tplc"/>
+ <attribute name="tentative" tokenid="ooxml:CT_Lvl_tentative"/>
+ </resource>
+ <resource name="ST_MultiLevelType" resource="List">
+ <value tokenid="ooxml:Value_ST_MultiLevelType_singleLevel">singleLevel</value>
+ <value tokenid="ooxml:Value_ST_MultiLevelType_multilevel">multilevel</value>
+ <value tokenid="ooxml:Value_ST_MultiLevelType_hybridMultilevel">hybridMultilevel</value>
+ </resource>
+ <resource name="CT_MultiLevelType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MultiLevelType_val" action="setValue"/>
+ </resource>
+ <resource name="CT_NumPicBullet" resource="Properties">
+ <element name="pict" tokenid="ooxml:CT_NumPicBullet_pict"/>
+ <attribute name="numPicBulletId" tokenid="ooxml:CT_NumPicBullet_numPicBulletId"/>
+ </resource>
+ <resource name="CT_AbstractNum" resource="Properties">
+ <element name="nsid" tokenid="ooxml:CT_AbstractNum_nsid"/>
+ <element name="multiLevelType" tokenid="ooxml:CT_AbstractNum_multiLevelType"/>
+ <element name="tmpl" tokenid="ooxml:CT_AbstractNum_tmpl"/>
+ <element name="name" tokenid="ooxml:CT_AbstractNum_name"/>
+ <element name="styleLink" tokenid="ooxml:CT_AbstractNum_styleLink"/>
+ <element name="numStyleLink" tokenid="ooxml:CT_AbstractNum_numStyleLink"/>
+ <element name="lvl" tokenid="ooxml:CT_AbstractNum_lvl"/>
+ <attribute name="abstractNumId" tokenid="ooxml:CT_AbstractNum_abstractNumId"/>
+ </resource>
+ <resource name="CT_NumLvl" resource="Properties">
+ <element name="startOverride" tokenid="ooxml:CT_NumLvl_startOverride"/>
+ <element name="lvl" tokenid="ooxml:CT_NumLvl_lvl"/>
+ <attribute name="ilvl" tokenid="ooxml:CT_NumLvl_ilvl"/>
+ </resource>
+ <resource name="CT_Num" resource="Properties">
+ <element name="abstractNumId" tokenid="ooxml:CT_Num_abstractNumId"/>
+ <element name="lvlOverride" tokenid="ooxml:CT_Num_lvlOverride"/>
+ <attribute name="numId" tokenid="ooxml:CT_Num_numId"/>
+ </resource>
+ <resource name="CT_Numbering" resource="PropertyTable" tokenid="ooxml:NUMBERING">
+ <element name="numPicBullet" tokenid="ooxml:CT_Numbering_numPicBullet"/>
+ <element name="abstractNum" tokenid="ooxml:CT_Numbering_abstractNum"/>
+ <element name="num" tokenid="ooxml:CT_Numbering_num"/>
+ <element name="numIdMacAtCleanup" tokenid="ooxml:CT_Numbering_numIdMacAtCleanup"/>
+ </resource>
+ <resource name="ST_TblStyleOverrideType" resource="List">
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_wholeTable">wholeTable</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_firstRow">firstRow</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_lastRow">lastRow</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_firstCol">firstCol</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_lastCol">lastCol</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band1Vert">band1Vert</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band2Vert">band2Vert</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band1Horz">band1Horz</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band2Horz">band2Horz</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_neCell">neCell</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_nwCell">nwCell</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_seCell">seCell</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_swCell">swCell</value>
+ </resource>
+ <resource name="CT_Style_tblStylePr" resource="Properties">
+ <element name="pPr" tokenid="ooxml:CT_PPrBase"/>
+ <element name="rPr" tokenid="ooxml:EG_RPrBase"/>
+ <element name="tblPr" tokenid="ooxml:CT_TblPrBase"/>
+ <element name="trPr" tokenid="ooxml:CT_TrPrBase"/>
+ <element name="tcPr" tokenid="ooxml:CT_TcPrBase"/>
+ <attribute name="type" tokenid="ooxml:CT_TblStyleOverrideType"/>
+ </resource>
+ <resource name="ST_StyleType" resource="List">
+ <value tokenid="ooxml:Value_ST_StyleType_paragraph">paragraph</value>
+ <value tokenid="ooxml:Value_ST_StyleType_character">character</value>
+ <value tokenid="ooxml:Value_ST_StyleType_table">table</value>
+ <value tokenid="ooxml:Value_ST_StyleType_numbering">numbering</value>
+ </resource>
+ <resource name="CT_Style" resource="Properties">
+ <element name="name" tokenid="ooxml:CT_Style_name"/>
+ <element name="aliases" tokenid="ooxml:CT_Style_aliases"/>
+ <element name="basedOn" tokenid="ooxml:CT_Style_basedOn"/>
+ <element name="next" tokenid="ooxml:CT_Style_next"/>
+ <element name="link" tokenid="ooxml:CT_Style_link"/>
+ <element name="autoRedefine" tokenid="ooxml:CT_Style_autoRedefine"/>
+ <element name="hidden" tokenid="ooxml:CT_Style_hidden"/>
+ <element name="uiPriority" tokenid="ooxml:CT_Style_uiPriority"/>
+ <element name="semiHidden" tokenid="ooxml:CT_Style_semiHidden"/>
+ <element name="unhideWhenUsed" tokenid="ooxml:CT_Style_unhideWhenUsed"/>
+ <element name="qFormat" tokenid="ooxml:CT_Style_qFormat"/>
+ <element name="locked" tokenid="ooxml:CT_Style_locked"/>
+ <element name="personal" tokenid="ooxml:CT_Style_personal"/>
+ <element name="personalCompose" tokenid="ooxml:CT_Style_personalCompose"/>
+ <element name="personalReply" tokenid="ooxml:CT_Style_personalReply"/>
+ <element name="rsid" tokenid="ooxml:CT_Style_rsid"/>
+ <element name="pPr" tokenid="ooxml:CT_Style_pPr"/>
+ <element name="rPr" tokenid="ooxml:CT_Style_rPr"/>
+ <element name="tblPr" tokenid="ooxml:CT_Style_tblPr"/>
+ <element name="trPr" tokenid="ooxml:CT_Style_trPr"/>
+ <element name="tcPr" tokenid="ooxml:CT_Style_tcPr"/>
+ <element name="tblStylePr" tokenid="ooxml:CT_Style_tblStylePr"/>
+ <attribute name="type" tokenid="ooxml:CT_Style_type"/>
+ <attribute name="styleId" tokenid="ooxml:CT_Style_styleId"/>
+ <attribute name="default" tokenid="ooxml:CT_Style_default"/>
+ <attribute name="customStyle" tokenid="ooxml:CT_Style_customStyle"/>
+ </resource>
+ <resource name="CT_Styles" resource="Table" tokenid="ooxml:STYLESHEET"/>
+ <resource name="ST_Panose" resource="Hex"/>
+ <resource name="CT_Panose" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Panose_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="CT_Charset" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Charset_val"/>
+ <attribute name="characterSet" tokenid="ooxml:CT_Charset_characterSet"/>
+ </resource>
+ <resource name="ST_FontFamily" resource="List">
+ <value tokenid="ooxml:Value_ST_FontFamily_decorative">decorative</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_modern">modern</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_roman">roman</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_script">script</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_swiss">swiss</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_auto">auto</value>
+ </resource>
+ <resource name="CT_FontFamily" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FontFamily_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Pitch" resource="List">
+ <value tokenid="ooxml:Value_ST_Pitch_fixed">fixed</value>
+ <value tokenid="ooxml:Value_ST_Pitch_variable">variable</value>
+ <value tokenid="ooxml:Value_ST_Pitch_default">default</value>
+ </resource>
+ <resource name="CT_Pitch" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Pitch_val"/>
+ </resource>
+ <resource name="CT_FontSig" resource="Properties">
+ <attribute name="usb0" tokenid="ooxml:CT_FontSig_usb0"/>
+ <attribute name="usb1" tokenid="ooxml:CT_FontSig_usb1"/>
+ <attribute name="usb2" tokenid="ooxml:CT_FontSig_usb2"/>
+ <attribute name="usb3" tokenid="ooxml:CT_FontSig_usb3"/>
+ <attribute name="csb0" tokenid="ooxml:CT_FontSig_csb0"/>
+ <attribute name="csb1" tokenid="ooxml:CT_FontSig_csb1"/>
+ </resource>
+ <resource name="CT_FontRel" resource="Properties">
+ <attribute name="fontKey" tokenid="ooxml:CT_FontRel_fontKey"/>
+ <attribute name="subsetted" tokenid="ooxml:CT_FontRel_subsetted"/>
+ <action name="start" action="handleFontRel"/>
+ </resource>
+ <resource name="CT_Font" resource="Properties">
+ <element name="altName" tokenid="ooxml:CT_Font_altName"/>
+ <element name="panose1" tokenid="ooxml:CT_Font_panose1"/>
+ <element name="charset" tokenid="ooxml:CT_Font_charset"/>
+ <element name="characterSet" tokenid="ooxml:CT_Font_characterSet"/>
+ <element name="family" tokenid="ooxml:CT_Font_family"/>
+ <element name="notTrueType" tokenid="ooxml:CT_Font_notTrueType"/>
+ <element name="pitch" tokenid="ooxml:CT_Font_pitch"/>
+ <element name="sig" tokenid="ooxml:CT_Font_sig"/>
+ <element name="embedRegular" tokenid="ooxml:CT_Font_embedRegular"/>
+ <element name="embedBold" tokenid="ooxml:CT_Font_embedBold"/>
+ <element name="embedItalic" tokenid="ooxml:CT_Font_embedItalic"/>
+ <element name="embedBoldItalic" tokenid="ooxml:CT_Font_embedBoldItalic"/>
+ <attribute name="name" tokenid="ooxml:CT_Font_name"/>
+ </resource>
+ <resource name="CT_FontsList" resource="Table" tokenid="ooxml:FONTTABLE"/>
+ <resource name="EG_BlockLevelElts" resource="Properties">
+ <attribute name="name" tokenid="ooxml:EG_BlockLevelElts_altChunk"/>
+ </resource>
+ <resource name="EG_RunLevelElts" resource="Stream">
+ <element name="proofErr" tokenid="ooxml:EG_RunLevelElts_proofErr"/>
+ <element name="permStart" tokenid="ooxml:EG_RunLevelElts_permStart"/>
+ <element name="permEnd" tokenid="ooxml:EG_RunLevelElts_permEnd"/>
+ <element name="ins" tokenid="ooxml:EG_RunLevelElts_ins"/>
+ <element name="del" tokenid="ooxml:EG_RunLevelElts_del"/>
+ <element name="moveFrom" tokenid="ooxml:EG_RunLevelElts_moveFrom"/>
+ <element name="moveTo" tokenid="ooxml:EG_RunLevelElts_moveTo"/>
+ </resource>
+ <resource name="CT_Body" resource="Stream">
+ <action name="start" action="startSectionGroup"/>
+ <!--
+ <action name="start" action="footnoteSeparator"/>
+ <action name="start" action="footnoteCont"/>
+ <action name="start" action="endnoteSeparator"/>
+ <action name="start" action="endnoteCont"/>
+ -->
+ <action name="end" action="endCharacterGroup"/>
+ <action name="end" action="endParagraphGroup"/>
+ <action name="end" action="setLastSectionGroup"/>
+ <action name="end" action="endSectionGroup"/>
+ </resource>
+ <resource name="CT_ShapeDefaults" resource="Properties">
+ <element name="v:fill" tokenid="ooxml:CT_ShapeDefaults_v_fill"/>
+ <element name="v:stroke" tokenid="ooxml:CT_ShapeDefaults_v_stroke"/>
+ <element name="v:textbox" tokenid="ooxml:CT_ShapeDefaults_v_textbox"/>
+ <element name="v:shadow" tokenid="ooxml:CT_ShapeDefaults_v_shadow"/>
+ <element name="colormru" tokenid="ooxml:CT_ShapeDefaults_colormru"/>
+ <element name="colormenu" tokenid="ooxml:CT_ShapeDefaults_colormenu"/>
+ <attribute name="spidmax" tokenid="ooxml:CT_ShapeDefaults_spidmax"/>
+ <attribute name="style" tokenid="ooxml:CT_ShapeDefaults_style"/>
+ <attribute name="fill" tokenid="ooxml:CT_ShapeDefaults_fill"/>
+ <attribute name="fillcolor" tokenid="ooxml:CT_ShapeDefaults_fillcolor"/>
+ <attribute name="stroke" tokenid="ooxml:CT_ShapeDefaults_stroke"/>
+ <attribute name="strokecolor" tokenid="ooxml:CT_ShapeDefaults_strokecolor"/>
+ <attribute name="allowincell" tokenid="ooxml:CT_ShapeDefaults_allowincell"/>
+ </resource>
+ <resource name="CT_Comments" resource="Stream">
+ <action name="start" action="startSectionGroup"/>
+ <action name="end" action="endSectionGroup"/>
+ </resource>
+ <resource name="CT_Footnotes" resource="Stream"/>
+ <resource name="footnotes" resource="Stream"/>
+ <resource name="CT_Endnotes" resource="Stream"/>
+ <resource name="endnotes" resource="Stream"/>
+ <resource name="CT_SmartTagType" resource="Properties">
+ <attribute name="namespaceuri" tokenid="ooxml:CT_SmartTagType_namespaceuri"/>
+ <attribute name="name" tokenid="ooxml:CT_SmartTagType_name"/>
+ <attribute name="url" tokenid="ooxml:CT_SmartTagType_url"/>
+ </resource>
+ <resource name="ST_ThemeColor" resource="List">
+ <value tokenid="ooxml:Value_St_ThemeColor_dark1">dark1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_light1">light1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_dark2">dark2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_light2">light2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent1">accent1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent2">accent2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent3">accent3</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent4">accent4</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent5">accent5</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent6">accent6</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_hyperlink">hyperlink</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_followedHyperlink">followedHyperlink</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_none">none</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_background1">background1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_text1">text1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_background2">background2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_text2">text2</value>
+ </resource>
+ <resource name="CT_DocPartBehavior" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DocPartBehavior_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_DocPartType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DocPartType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_DocPartGallery" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_DocPartGallery_val"/>
+ </resource>
+ <resource name="CT_DocPartName" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_DocPartName_val"/>
+ <attribute name="decorated" tokenid="ooxml:CT_DocPartName_decorated"/>
+ </resource>
+ <resource name="settings" resource="Stream">
+ <element name="settings" tokenid="ooxml:settings_settings"/>
+ </resource>
+ <resource name="fonts" resource="Stream">
+ <element name="fonts" tokenid="ooxml:FONTTABLE"/>
+ </resource>
+ <resource name="numbering" resource="Stream">
+ <element name="numbering" tokenid="ooxml:NUMBERING"/>
+ </resource>
+ <resource name="styles" resource="Stream">
+ <element name="styles" tokenid="ooxml:STYLESHEET"/>
+ </resource>
+ <resource name="ST_CaptionPos" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_above">above</value>
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_below">below</value>
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_left">left</value>
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_right">right</value>
+ </resource>
+ <resource name="CT_Caption" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_Caption_name"/>
+ <attribute name="pos" tokenid="ooxml:CT_Caption_pos"/>
+ <attribute name="chapNum" tokenid="ooxml:CT_Caption_chapNum"/>
+ <attribute name="heading" tokenid="ooxml:CT_Caption_heading"/>
+ <attribute name="noLabel" tokenid="ooxml:CT_Caption_noLabel"/>
+ <attribute name="numFmt" tokenid="ooxml:CT_Caption_numFmt"/>
+ <attribute name="sep" tokenid="ooxml:CT_Caption_sep"/>
+ </resource>
+ <resource name="CT_AutoCaption" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_AutoCaption_name"/>
+ <attribute name="caption" tokenid="ooxml:CT_AutoCaption_caption"/>
+ </resource>
+ <resource name="CT_AutoCaptions" resource="Properties">
+ <element name="autoCaption" tokenid="ooxml:CT_AutoCaptions_autoCaption"/>
+ </resource>
+ <resource name="CT_Captions" resource="Properties">
+ <element name="caption" tokenid="ooxml:CT_Captions_caption"/>
+ <element name="autoCaptions" tokenid="ooxml:CT_Captions_autoCaptions"/>
+ </resource>
+ <resource name="CT_DocumentBase" resource="Properties">
+ <element name="background" tokenid="ooxml:CT_DocumentBase_background"/>
+ </resource>
+ <resource name="CT_Document" resource="Stream"/>
+ <resource name="CT_GlossaryDocument" resource="Stream"/>
+ <resource name="CT_DocParts" resource="Stream"/>
+ <resource name="CT_DocPart" resource="Stream">
+ <action name="start" action="startGlossaryEntry"/>
+ <action name="end" action="endGlossaryEntry"/>
+ </resource>
+ <resource name="CT_DocPartPr" resource="Properties">
+ <action name="start" action="startSectionGroup"/>
+ <element name="name" tokenid="ooxml:CT_DocPartPr_name"/>
+ <element name="category" tokenid="ooxml:CT_DocPartPr_category"/>
+ </resource>
+ <resource name="CT_DocPartCategory" resource="Properties">
+ <element name="gallery" tokenid="ooxml:CT_DocPartCategory_gallery"/>
+ </resource>
+ <resource name="document" resource="Stream"/>
+ <resource name="glossaryDocument" resource="Stream"/>
+ <resource name="CT_TxbxContent" resource="Stream">
+ <action name="start" action="startTxbxContent"/>
+ <action name="end" action="endTxbxContent"/>
+ </resource>
+ <resource name="CT_OMath" resource="Math"/>
+ <resource name="CT_OMathPara" resource="Stream"/>
+ <resource name="CT_OMathParaPr" resource="Properties"/>
+ <resource name="CT_OMathJc" resource="Value"/>
+ </namespace>
+</model>
+<!-- vim: shiftwidth=2 softtabstop=2 expandtab:
+-->
diff --git a/writerfilter/source/ooxml/modelpreprocess.py b/writerfilter/source/ooxml/modelpreprocess.py
new file mode 100644
index 000000000..d6ef4c175
--- /dev/null
+++ b/writerfilter/source/ooxml/modelpreprocess.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+from xml.dom import minidom
+import sys
+
+
+def prefixForGrammar(namespace):
+ ns = namespace.getElementsByTagName("grammar")[0].getAttribute("ns")
+ return ooxUrlAliases[ns]
+
+
+def parseNamespaceAliases(node):
+ ret = {}
+ for k, v in list(node.attributes.items()):
+ if k.startswith("xmlns:"):
+ ret[k.replace('xmlns:', '')] = v
+ return ret
+
+
+def parseNamespaces(fro):
+ sock = open(fro)
+ for i in sock.readlines():
+ line = i.strip()
+ alias, url = line.split(' ')[1:]
+ ooxUrlAliases[url] = alias
+ sock.close()
+
+
+def check(model):
+ defines = [i.getAttribute("name") for i in model.getElementsByTagName("define")]
+ for reference in [i.getAttribute("name") for i in model.getElementsByTagName("ref")]:
+ if reference not in defines:
+ raise Exception("Unknown define element with name '%s'" % reference)
+ for start in [i.getAttribute("name") for i in model.getElementsByTagName("start")]:
+ if start not in defines:
+ raise Exception("Unknown start element with name '%s'" % start)
+
+
+def preprocess(model):
+ modelNode = [i for i in model.childNodes if i.localName == "model"][0]
+ # Alias -> URL, based on "xmlns:" attributes.
+ modelNamespaceAliases = parseNamespaceAliases(modelNode)
+ for i in modelNode.getElementsByTagName("namespace"):
+ grammarprefix = prefixForGrammar(i)
+
+ grammar = i.getElementsByTagName("grammar")[0]
+
+ for j in i.getElementsByTagName("element") + i.getElementsByTagName("attribute"):
+ # prefix
+ prefix = ""
+ if ":" in j.getAttribute("name"):
+ nameprefix = j.getAttribute("name").split(':')[0]
+ prefix = ooxUrlAliases[modelNamespaceAliases[nameprefix]]
+ elif j.localName == "attribute":
+ if grammar.getAttribute("attributeFormDefault") == "qualified":
+ prefix = grammarprefix
+ else:
+ prefix = grammarprefix
+
+ # localname
+ if ":" in j.getAttribute("name"):
+ localname = j.getAttribute("name").split(':')[1]
+ else:
+ localname = j.getAttribute("name")
+
+ # set the attributes
+ j.setAttribute("prefix", prefix)
+ j.setAttribute("localname", localname)
+
+
+namespacesPath = sys.argv[1]
+modelPath = sys.argv[2]
+
+# URL -> alias, from oox
+ooxUrlAliases = {}
+parseNamespaces(namespacesPath)
+
+model = minidom.parse(modelPath)
+check(model)
+preprocess(model)
+model.writexml(sys.stdout)
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/qnametostr.py b/writerfilter/source/ooxml/qnametostr.py
new file mode 100644
index 000000000..e09a98570
--- /dev/null
+++ b/writerfilter/source/ooxml/qnametostr.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+import xml.sax
+import sys
+
+
+class ContentHandler(xml.sax.handler.ContentHandler):
+ def __init__(self):
+ self.tokens = []
+
+ def startDocument(self):
+ print("""
+#include "ooxml/resourceids.hxx"
+#include "ooxml/QNameToString.hxx"
+#include "unordered_map"
+
+namespace writerfilter
+{
+
+#ifdef DBG_UTIL
+
+ /* ooxml */
+ static const std::unordered_map<Id, const char*> g_QNameToStringMap {
+""")
+
+ def endDocument(self):
+ print("""
+ };
+
+ std::string QNameToString(Id qName)
+ {
+ auto it = g_QNameToStringMap.find(qName);
+ if (it == g_QNameToStringMap.end())
+ return std::string();
+
+ return it->second;
+ }
+
+#endif
+}
+""")
+
+ def startElement(self, name, attrs):
+ for k, v in list(attrs.items()):
+ if k == "tokenid":
+ if v.startswith("ooxml:"):
+ token = v.replace('ooxml:', '')
+ if token not in self.tokens:
+ print(""" { NS_ooxml::LN_%s, "ooxml:%s" },""" % (token, token))
+ self.tokens.append(token)
+
+
+parser = xml.sax.make_parser()
+parser.setContentHandler(ContentHandler())
+parser.parse(sys.argv[1])
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/resourceids.py b/writerfilter/source/ooxml/resourceids.py
new file mode 100644
index 000000000..70325c9d3
--- /dev/null
+++ b/writerfilter/source/ooxml/resourceids.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# 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/.
+#
+
+import xml.sax
+import sys
+
+
+class ContentHandler(xml.sax.handler.ContentHandler):
+ def __init__(self):
+ self.tokens = []
+ self.counter = 90001
+
+ def startDocument(self):
+ print("""
+/*
+
+ THIS FILE IS GENERATED AUTOMATICALLY! DO NOT EDIT!
+
+*/
+
+
+#ifndef INCLUDED_OOXML_RESOURCEIDS_HXX
+#define INCLUDED_OOXML_RESOURCEIDS_HXX
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter {
+
+namespace NS_ooxml
+{""")
+
+ def endDocument(self):
+ print("""}
+
+
+}
+#endif // INCLUDED_OOXML_RESOURCEIDS_HXX""")
+
+ def startElement(self, name, attrs):
+ for k, v in attrs.items():
+ if k in ("tokenid", "sendtokenid"):
+ if v.startswith("ooxml:"):
+ token = v.replace('ooxml:', '')
+ if token not in self.tokens:
+ print(" const Id LN_%s = %s;" % (token, self.counter))
+ self.tokens.append(token)
+ self.counter += 1
+
+
+parser = xml.sax.make_parser()
+parser.setContentHandler(ContentHandler())
+parser.parse(sys.argv[1])
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/writerfilter/source/ooxml/tox.ini b/writerfilter/source/ooxml/tox.ini
new file mode 100644
index 000000000..c1781905c
--- /dev/null
+++ b/writerfilter/source/ooxml/tox.ini
@@ -0,0 +1,2 @@
+[pycodestyle]
+ignore = E501
diff --git a/writerfilter/source/rtftok/README b/writerfilter/source/rtftok/README
new file mode 100644
index 000000000..4adbb7563
--- /dev/null
+++ b/writerfilter/source/rtftok/README
@@ -0,0 +1,12 @@
+= Writerfilter-based RTF tokenizer
+
+== Mathematics
+
+At the time of writing, all control words understood by SmOoxmlImport are
+imported. To view the current status:
+
+----
+grep M_TOKEN starmath/source/ooxmlimport.cxx |sed 's/.*\(M_TOKEN(\) /\1/;s/ ).*/)/'|sort -u > ~/math-import-list
+grep '[^_]M_TOKEN' writerfilter/source/rtftok/rtfdocumentimpl.cxx |sed 's/.*\(M_TOKEN(\)/\1/;s/).*/)/'|sort -u > ~/wf-export-list
+diff -u ~/math-import-list ~/wf-export-list |grep ^-M_TOKEN
+----
diff --git a/writerfilter/source/rtftok/rtfcharsets.cxx b/writerfilter/source/rtftok/rtfcharsets.cxx
new file mode 100644
index 000000000..14d27b5f2
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcharsets.cxx
@@ -0,0 +1,64 @@
+/* -*- 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 "rtfcharsets.hxx"
+#include <array>
+#include <rtl/textenc.h>
+
+namespace writerfilter::rtftok
+{
+// See RTF spec v1.9.1, page 19
+RTFEncoding const aRTFEncodings[] = {
+ // charset codepage Windows / Mac name
+ { 0, 1252 }, // ANSI
+ { 1, 0 }, // Default
+ { 2, 42 }, // Symbol
+ { 77, 10000 }, // Mac Roman
+ { 78, 10001 }, // Mac Shift Jis
+ { 79, 10003 }, // Mac Hangul
+ { 80, 10008 }, // Mac GB2312
+ { 81, 10002 }, // Mac Big5
+ { 83, 10005 }, // Mac Herbrew
+ { 84, 10004 }, // Mac Arabic
+ { 85, 10006 }, // Mac Greek
+ { 86, 10081 }, // Mac Turkish
+ { 87, 10021 }, // Mac Thai
+ { 88, 10029 }, // Mac East Europe
+ { 89, 10007 }, // Mac Russian
+ { 128, 932 }, // Shift JIS
+ { 129, 949 }, // Hangul
+ { 130, 1361 }, // Johab
+ { 134, 936 }, // GB2312
+ { 136, 950 }, // Big5
+ { 161, 1253 }, // Greek
+ { 162, 1254 }, // Turkish
+ { 163, 1258 }, // Vietnamese
+ { 177, 1255 }, // Herbrew
+ { 178, 1256 }, // Arabic
+ { 186, 1257 }, // Baltic
+ { 204, 1251 }, // Russian
+ { 222, 874 }, // Thai
+ { 238, 1250 }, // Eastern European
+ { 254, 437 }, // PC 437
+ { 255, 850 }, // OEM
+};
+
+int nRTFEncodings = std::size(aRTFEncodings);
+
+RTFFontNameSuffix const aRTFFontNameSuffixes[] = {
+ { "Baltic", RTL_TEXTENCODING_MS_1257 }, { "CE", RTL_TEXTENCODING_MS_1250 },
+ { "Cyr", RTL_TEXTENCODING_MS_1251 }, { "Greek", RTL_TEXTENCODING_MS_1253 },
+ { "Tur", RTL_TEXTENCODING_MS_1254 }, { "(Hebrew)", RTL_TEXTENCODING_MS_1255 },
+ { "(Arabic)", RTL_TEXTENCODING_MS_1256 }, { "(Vietnamese)", RTL_TEXTENCODING_MS_1258 },
+ { "", RTL_TEXTENCODING_DONTKNOW } // End of array
+};
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcharsets.hxx b/writerfilter/source/rtftok/rtfcharsets.hxx
new file mode 100644
index 000000000..826dea271
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcharsets.hxx
@@ -0,0 +1,37 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+/// RTF legacy charsets
+struct RTFEncoding
+{
+ int charset;
+ int codepage;
+};
+extern RTFEncoding const aRTFEncodings[];
+extern int nRTFEncodings;
+
+/// Font name can contain special suffixes used
+/// to determine encoding for given font table entry
+/// For example "Arial CE" is "Arial" with CP1250 encoding
+/// List of these suffixes is not official and detected in a empirical
+/// way thus may be inexact and incomplete.
+struct RTFFontNameSuffix
+{
+ const char* suffix;
+ int codepage;
+};
+extern RTFFontNameSuffix const aRTFFontNameSuffixes[];
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.cxx b/writerfilter/source/rtftok/rtfcontrolwords.cxx
new file mode 100644
index 000000000..3f5a0827b
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcontrolwords.cxx
@@ -0,0 +1,1900 @@
+/* -*- 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 "rtfcontrolwords.hxx"
+#include <oox/token/namespaces.hxx>
+
+namespace writerfilter::rtftok
+{
+RTFSymbol const aRTFControlWords[] = {
+ // sKeyword nControlType nIndex
+ { "'", RTFControlType::SYMBOL, RTFKeyword::HEXCHAR, 0 },
+ { "-", RTFControlType::SYMBOL, RTFKeyword::OPTHYPH, 0 },
+ { "*", RTFControlType::SYMBOL, RTFKeyword::IGNORE, 0 },
+ { ":", RTFControlType::SYMBOL, RTFKeyword::SUBENTRY, 0 },
+ { "\\", RTFControlType::SYMBOL, RTFKeyword::BACKSLASH, 0 },
+ { "\n", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "\r", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "\r\n", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "_", RTFControlType::SYMBOL, RTFKeyword::NOBRKHYPH, 0 },
+ { "{", RTFControlType::SYMBOL, RTFKeyword::LBRACE, 0 },
+ { "|", RTFControlType::SYMBOL, RTFKeyword::FORMULA, 0 },
+ { "}", RTFControlType::SYMBOL, RTFKeyword::RBRACE, 0 },
+ { "~", RTFControlType::SYMBOL, RTFKeyword::NOBREAK, 0 },
+ { "ab", RTFControlType::TOGGLE, RTFKeyword::AB, 1 },
+ { "absh", RTFControlType::VALUE, RTFKeyword::ABSH, 0 },
+ { "abslock", RTFControlType::FLAG, RTFKeyword::ABSLOCK, 0 },
+ { "absnoovrlp", RTFControlType::TOGGLE, RTFKeyword::ABSNOOVRLP, 1 },
+ { "absw", RTFControlType::VALUE, RTFKeyword::ABSW, 0 },
+ { "acaps", RTFControlType::TOGGLE, RTFKeyword::ACAPS, 1 },
+ { "acccircle", RTFControlType::TOGGLE, RTFKeyword::ACCCIRCLE, 1 },
+ { "acccomma", RTFControlType::TOGGLE, RTFKeyword::ACCCOMMA, 1 },
+ { "accdot", RTFControlType::TOGGLE, RTFKeyword::ACCDOT, 1 },
+ { "accnone", RTFControlType::TOGGLE, RTFKeyword::ACCNONE, 1 },
+ { "accunderdot", RTFControlType::TOGGLE, RTFKeyword::ACCUNDERDOT, 1 },
+ { "acf", RTFControlType::VALUE, RTFKeyword::ACF, 0 },
+ { "adeff", RTFControlType::VALUE, RTFKeyword::ADEFF, 0 },
+ { "additive", RTFControlType::FLAG, RTFKeyword::ADDITIVE, 0 },
+ { "adeflang", RTFControlType::VALUE, RTFKeyword::ADEFLANG, 0 },
+ { "adjustright", RTFControlType::FLAG, RTFKeyword::ADJUSTRIGHT, 0 },
+ { "adn", RTFControlType::VALUE, RTFKeyword::ADN, 6 },
+ { "aenddoc", RTFControlType::FLAG, RTFKeyword::AENDDOC, 0 },
+ { "aendnotes", RTFControlType::FLAG, RTFKeyword::AENDNOTES, 0 },
+ { "aexpnd", RTFControlType::VALUE, RTFKeyword::AEXPND, 0 },
+ { "af", RTFControlType::VALUE, RTFKeyword::AF, 0 },
+ { "afelev", RTFControlType::FLAG, RTFKeyword::AFELEV, 0 },
+ { "afs", RTFControlType::VALUE, RTFKeyword::AFS, 24 },
+ { "aftnbj", RTFControlType::FLAG, RTFKeyword::AFTNBJ, 0 },
+ { "aftncn", RTFControlType::DESTINATION, RTFKeyword::AFTNCN, 0 },
+ { "aftnnalc", RTFControlType::FLAG, RTFKeyword::AFTNNALC, 0 },
+ { "aftnnar", RTFControlType::FLAG, RTFKeyword::AFTNNAR, 0 },
+ { "aftnnauc", RTFControlType::FLAG, RTFKeyword::AFTNNAUC, 0 },
+ { "aftnnchi", RTFControlType::FLAG, RTFKeyword::AFTNNCHI, 0 },
+ { "aftnnchosung", RTFControlType::FLAG, RTFKeyword::AFTNNCHOSUNG, 0 },
+ { "aftnncnum", RTFControlType::FLAG, RTFKeyword::AFTNNCNUM, 0 },
+ { "aftnndbar", RTFControlType::FLAG, RTFKeyword::AFTNNDBAR, 0 },
+ { "aftnndbnum", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUM, 0 },
+ { "aftnndbnumd", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMD, 0 },
+ { "aftnndbnumk", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMK, 0 },
+ { "aftnndbnumt", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMT, 0 },
+ { "aftnnganada", RTFControlType::FLAG, RTFKeyword::AFTNNGANADA, 0 },
+ { "aftnngbnum", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUM, 0 },
+ { "aftnngbnumd", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUMD, 0 },
+ { "aftnngbnumk", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUMK, 0 },
+ { "aftnngbnuml", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUML, 0 },
+ { "aftnnrlc", RTFControlType::FLAG, RTFKeyword::AFTNNRLC, 0 },
+ { "aftnnruc", RTFControlType::FLAG, RTFKeyword::AFTNNRUC, 0 },
+ { "aftnnzodiac", RTFControlType::FLAG, RTFKeyword::AFTNNZODIAC, 0 },
+ { "aftnnzodiacd", RTFControlType::FLAG, RTFKeyword::AFTNNZODIACD, 0 },
+ { "aftnnzodiacl", RTFControlType::FLAG, RTFKeyword::AFTNNZODIACL, 0 },
+ { "aftnrestart", RTFControlType::FLAG, RTFKeyword::AFTNRESTART, 0 },
+ { "aftnrstcont", RTFControlType::FLAG, RTFKeyword::AFTNRSTCONT, 0 },
+ { "aftnsep", RTFControlType::DESTINATION, RTFKeyword::AFTNSEP, 0 },
+ { "aftnsepc", RTFControlType::DESTINATION, RTFKeyword::AFTNSEPC, 0 },
+ { "aftnstart", RTFControlType::VALUE, RTFKeyword::AFTNSTART, 1 },
+ { "aftntj", RTFControlType::FLAG, RTFKeyword::AFTNTJ, 0 },
+ { "ai", RTFControlType::TOGGLE, RTFKeyword::AI, 1 },
+ { "alang", RTFControlType::VALUE, RTFKeyword::ALANG, 0 },
+ { "allowfieldendsel", RTFControlType::FLAG, RTFKeyword::ALLOWFIELDENDSEL, 0 },
+ { "allprot", RTFControlType::FLAG, RTFKeyword::ALLPROT, 0 },
+ { "alntblind", RTFControlType::FLAG, RTFKeyword::ALNTBLIND, 0 },
+ { "alt", RTFControlType::FLAG, RTFKeyword::ALT, 0 },
+ { "animtext", RTFControlType::VALUE, RTFKeyword::ANIMTEXT, 0 },
+ { "annotation", RTFControlType::DESTINATION, RTFKeyword::ANNOTATION, 0 },
+ { "annotprot", RTFControlType::FLAG, RTFKeyword::ANNOTPROT, 0 },
+ { "ansi", RTFControlType::FLAG, RTFKeyword::ANSI, 0 },
+ { "ansicpg", RTFControlType::VALUE, RTFKeyword::ANSICPG, 0 },
+ { "aoutl", RTFControlType::TOGGLE, RTFKeyword::AOUTL, 1 },
+ { "ApplyBrkRules", RTFControlType::FLAG, RTFKeyword::APPLYBRKRULES, 0 },
+ { "ascaps", RTFControlType::TOGGLE, RTFKeyword::ASCAPS, 1 },
+ { "ashad", RTFControlType::TOGGLE, RTFKeyword::ASHAD, 1 },
+ { "asianbrkrule", RTFControlType::FLAG, RTFKeyword::ASIANBRKRULE, 0 },
+ { "aspalpha", RTFControlType::TOGGLE, RTFKeyword::ASPALPHA, 1 },
+ { "aspnum", RTFControlType::TOGGLE, RTFKeyword::ASPNUM, 1 },
+ { "astrike", RTFControlType::TOGGLE, RTFKeyword::ASTRIKE, 1 },
+ { "atnauthor", RTFControlType::DESTINATION, RTFKeyword::ATNAUTHOR, 0 },
+ { "atndate", RTFControlType::DESTINATION, RTFKeyword::ATNDATE, 0 },
+ { "atnicn", RTFControlType::DESTINATION, RTFKeyword::ATNICN, 0 },
+ { "atnid", RTFControlType::DESTINATION, RTFKeyword::ATNID, 0 },
+ { "atnparent", RTFControlType::DESTINATION, RTFKeyword::ATNPARENT, 0 },
+ { "atnref", RTFControlType::DESTINATION, RTFKeyword::ATNREF, 0 },
+ { "atntime", RTFControlType::DESTINATION, RTFKeyword::ATNTIME, 0 },
+ { "atrfend", RTFControlType::DESTINATION, RTFKeyword::ATRFEND, 0 },
+ { "atrfstart", RTFControlType::DESTINATION, RTFKeyword::ATRFSTART, 0 },
+ { "aul", RTFControlType::TOGGLE, RTFKeyword::AUL, 1 },
+ { "auld", RTFControlType::TOGGLE, RTFKeyword::AULD, 1 },
+ { "auldb", RTFControlType::TOGGLE, RTFKeyword::AULDB, 1 },
+ { "aulnone", RTFControlType::TOGGLE, RTFKeyword::AULNONE, 1 },
+ { "aulw", RTFControlType::TOGGLE, RTFKeyword::AULW, 1 },
+ { "aup", RTFControlType::VALUE, RTFKeyword::AUP, 6 },
+ { "author", RTFControlType::DESTINATION, RTFKeyword::AUTHOR, 0 },
+ { "autofmtoverride", RTFControlType::FLAG, RTFKeyword::AUTOFMTOVERRIDE, 0 },
+ { "b", RTFControlType::TOGGLE, RTFKeyword::B, 1 },
+ { "background", RTFControlType::DESTINATION, RTFKeyword::BACKGROUND, 0 },
+ { "bdbfhdr", RTFControlType::FLAG, RTFKeyword::BDBFHDR, 0 },
+ { "bdrrlswsix", RTFControlType::FLAG, RTFKeyword::BDRRLSWSIX, 0 },
+ { "bgbdiag", RTFControlType::FLAG, RTFKeyword::BGBDIAG, 0 },
+ { "bgcross", RTFControlType::FLAG, RTFKeyword::BGCROSS, 0 },
+ { "bgdcross", RTFControlType::FLAG, RTFKeyword::BGDCROSS, 0 },
+ { "bgdkbdiag", RTFControlType::FLAG, RTFKeyword::BGDKBDIAG, 0 },
+ { "bgdkcross", RTFControlType::FLAG, RTFKeyword::BGDKCROSS, 0 },
+ { "bgdkdcross", RTFControlType::FLAG, RTFKeyword::BGDKDCROSS, 0 },
+ { "bgdkfdiag", RTFControlType::FLAG, RTFKeyword::BGDKFDIAG, 0 },
+ { "bgdkhoriz", RTFControlType::FLAG, RTFKeyword::BGDKHORIZ, 0 },
+ { "bgdkvert", RTFControlType::FLAG, RTFKeyword::BGDKVERT, 0 },
+ { "bgfdiag", RTFControlType::FLAG, RTFKeyword::BGFDIAG, 0 },
+ { "bghoriz", RTFControlType::FLAG, RTFKeyword::BGHORIZ, 0 },
+ { "bgvert", RTFControlType::FLAG, RTFKeyword::BGVERT, 0 },
+ { "bin", RTFControlType::VALUE, RTFKeyword::BIN, 0 },
+ { "binfsxn", RTFControlType::VALUE, RTFKeyword::BINFSXN, 0 },
+ { "binsxn", RTFControlType::VALUE, RTFKeyword::BINSXN, 0 },
+ { "bkmkcolf", RTFControlType::VALUE, RTFKeyword::BKMKCOLF, 0 },
+ { "bkmkcoll", RTFControlType::VALUE, RTFKeyword::BKMKCOLL, 0 },
+ { "bkmkend", RTFControlType::DESTINATION, RTFKeyword::BKMKEND, 0 },
+ { "bkmkpub", RTFControlType::FLAG, RTFKeyword::BKMKPUB, 0 },
+ { "bkmkstart", RTFControlType::DESTINATION, RTFKeyword::BKMKSTART, 0 },
+ { "bliptag", RTFControlType::VALUE, RTFKeyword::BLIPTAG, 0 },
+ { "blipuid", RTFControlType::DESTINATION, RTFKeyword::BLIPUID, 0 },
+ { "blipupi", RTFControlType::VALUE, RTFKeyword::BLIPUPI, 0 },
+ { "blue", RTFControlType::VALUE, RTFKeyword::BLUE, 0 },
+ { "bookfold", RTFControlType::FLAG, RTFKeyword::BOOKFOLD, 0 },
+ { "bookfoldrev", RTFControlType::FLAG, RTFKeyword::BOOKFOLDREV, 0 },
+ { "bookfoldsheets", RTFControlType::VALUE, RTFKeyword::BOOKFOLDSHEETS, 0 },
+ { "box", RTFControlType::FLAG, RTFKeyword::BOX, 0 },
+ { "brdrart", RTFControlType::VALUE, RTFKeyword::BRDRART, 0 },
+ { "brdrb", RTFControlType::FLAG, RTFKeyword::BRDRB, 0 },
+ { "brdrbar", RTFControlType::FLAG, RTFKeyword::BRDRBAR, 0 },
+ { "brdrbtw", RTFControlType::FLAG, RTFKeyword::BRDRBTW, 0 },
+ { "brdrcf", RTFControlType::VALUE, RTFKeyword::BRDRCF, 0 },
+ { "brdrdash", RTFControlType::FLAG, RTFKeyword::BRDRDASH, 0 },
+ { "brdrdashd", RTFControlType::FLAG, RTFKeyword::BRDRDASHD, 0 },
+ { "brdrdashdd", RTFControlType::FLAG, RTFKeyword::BRDRDASHDD, 0 },
+ { "brdrdashdotstr", RTFControlType::FLAG, RTFKeyword::BRDRDASHDOTSTR, 0 },
+ { "brdrdashsm", RTFControlType::FLAG, RTFKeyword::BRDRDASHSM, 0 },
+ { "brdrdb", RTFControlType::FLAG, RTFKeyword::BRDRDB, 0 },
+ { "brdrdot", RTFControlType::FLAG, RTFKeyword::BRDRDOT, 0 },
+ { "brdremboss", RTFControlType::FLAG, RTFKeyword::BRDREMBOSS, 0 },
+ { "brdrengrave", RTFControlType::FLAG, RTFKeyword::BRDRENGRAVE, 0 },
+ { "brdrframe", RTFControlType::FLAG, RTFKeyword::BRDRFRAME, 0 },
+ { "brdrhair", RTFControlType::FLAG, RTFKeyword::BRDRHAIR, 0 },
+ { "brdrinset", RTFControlType::FLAG, RTFKeyword::BRDRINSET, 0 },
+ { "brdrl", RTFControlType::FLAG, RTFKeyword::BRDRL, 0 },
+ { "brdrnil", RTFControlType::FLAG, RTFKeyword::BRDRNIL, 0 },
+ { "brdrnone", RTFControlType::FLAG, RTFKeyword::BRDRNONE, 0 },
+ { "brdroutset", RTFControlType::FLAG, RTFKeyword::BRDROUTSET, 0 },
+ { "brdrr", RTFControlType::FLAG, RTFKeyword::BRDRR, 0 },
+ { "brdrs", RTFControlType::FLAG, RTFKeyword::BRDRS, 0 },
+ { "brdrsh", RTFControlType::FLAG, RTFKeyword::BRDRSH, 0 },
+ { "brdrt", RTFControlType::FLAG, RTFKeyword::BRDRT, 0 },
+ { "brdrtbl", RTFControlType::FLAG, RTFKeyword::BRDRTBL, 0 },
+ { "brdrth", RTFControlType::FLAG, RTFKeyword::BRDRTH, 0 },
+ { "brdrthtnlg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNLG, 0 },
+ { "brdrthtnmg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNMG, 0 },
+ { "brdrthtnsg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNSG, 0 },
+ { "brdrtnthlg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHLG, 0 },
+ { "brdrtnthmg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHMG, 0 },
+ { "brdrtnthsg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHSG, 0 },
+ { "brdrtnthtnlg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNLG, 0 },
+ { "brdrtnthtnmg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNMG, 0 },
+ { "brdrtnthtnsg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNSG, 0 },
+ { "brdrtriple", RTFControlType::FLAG, RTFKeyword::BRDRTRIPLE, 0 },
+ { "brdrw", RTFControlType::VALUE, RTFKeyword::BRDRW, 0 },
+ { "brdrwavy", RTFControlType::FLAG, RTFKeyword::BRDRWAVY, 0 },
+ { "brdrwavydb", RTFControlType::FLAG, RTFKeyword::BRDRWAVYDB, 0 },
+ { "brkfrm", RTFControlType::FLAG, RTFKeyword::BRKFRM, 0 },
+ { "brsp", RTFControlType::VALUE, RTFKeyword::BRSP, 0 },
+ { "bullet", RTFControlType::SYMBOL, RTFKeyword::BULLET, 0 },
+ { "buptim", RTFControlType::DESTINATION, RTFKeyword::BUPTIM, 0 },
+ { "bxe", RTFControlType::FLAG, RTFKeyword::BXE, 0 },
+ { "caccentfive", RTFControlType::FLAG, RTFKeyword::CACCENTFIVE, 0 },
+ { "caccentfour", RTFControlType::FLAG, RTFKeyword::CACCENTFOUR, 0 },
+ { "caccentone", RTFControlType::FLAG, RTFKeyword::CACCENTONE, 0 },
+ { "caccentsix", RTFControlType::FLAG, RTFKeyword::CACCENTSIX, 0 },
+ { "caccentthree", RTFControlType::FLAG, RTFKeyword::CACCENTTHREE, 0 },
+ { "caccenttwo", RTFControlType::FLAG, RTFKeyword::CACCENTTWO, 0 },
+ { "cachedcolbal", RTFControlType::FLAG, RTFKeyword::CACHEDCOLBAL, 0 },
+ { "caps", RTFControlType::TOGGLE, RTFKeyword::CAPS, 1 },
+ { "category", RTFControlType::DESTINATION, RTFKeyword::CATEGORY, 0 },
+ { "cb", RTFControlType::VALUE, RTFKeyword::CB, 0 },
+ { "cbackgroundone", RTFControlType::FLAG, RTFKeyword::CBACKGROUNDONE, 0 },
+ { "cbackgroundtwo", RTFControlType::FLAG, RTFKeyword::CBACKGROUNDTWO, 0 },
+ { "cbpat", RTFControlType::VALUE, RTFKeyword::CBPAT, 0 },
+ { "cchs", RTFControlType::VALUE, RTFKeyword::CCHS, 0 },
+ { "cell", RTFControlType::SYMBOL, RTFKeyword::CELL, 0 },
+ { "cellx", RTFControlType::VALUE, RTFKeyword::CELLX, 0 },
+ { "cf", RTFControlType::VALUE, RTFKeyword::CF, 0 },
+ { "cfollowedhyperlink", RTFControlType::FLAG, RTFKeyword::CFOLLOWEDHYPERLINK, 0 },
+ { "cfpat", RTFControlType::VALUE, RTFKeyword::CFPAT, 0 },
+ { "cgrid", RTFControlType::VALUE, RTFKeyword::CGRID, 0 },
+ { "charrsid", RTFControlType::VALUE, RTFKeyword::CHARRSID, 0 },
+ { "charscalex", RTFControlType::VALUE, RTFKeyword::CHARSCALEX, 100 },
+ { "chatn", RTFControlType::SYMBOL, RTFKeyword::CHATN, 0 },
+ { "chbgbdiag", RTFControlType::FLAG, RTFKeyword::CHBGBDIAG, 0 },
+ { "chbgcross", RTFControlType::FLAG, RTFKeyword::CHBGCROSS, 0 },
+ { "chbgdcross", RTFControlType::FLAG, RTFKeyword::CHBGDCROSS, 0 },
+ { "chbgdkbdiag", RTFControlType::FLAG, RTFKeyword::CHBGDKBDIAG, 0 },
+ { "chbgdkcross", RTFControlType::FLAG, RTFKeyword::CHBGDKCROSS, 0 },
+ { "chbgdkdcross", RTFControlType::FLAG, RTFKeyword::CHBGDKDCROSS, 0 },
+ { "chbgdkfdiag", RTFControlType::FLAG, RTFKeyword::CHBGDKFDIAG, 0 },
+ { "chbgdkhoriz", RTFControlType::FLAG, RTFKeyword::CHBGDKHORIZ, 0 },
+ { "chbgdkvert", RTFControlType::FLAG, RTFKeyword::CHBGDKVERT, 0 },
+ { "chbgfdiag", RTFControlType::FLAG, RTFKeyword::CHBGFDIAG, 0 },
+ { "chbghoriz", RTFControlType::FLAG, RTFKeyword::CHBGHORIZ, 0 },
+ { "chbgvert", RTFControlType::FLAG, RTFKeyword::CHBGVERT, 0 },
+ { "chbrdr", RTFControlType::FLAG, RTFKeyword::CHBRDR, 0 },
+ { "chcbpat", RTFControlType::VALUE, RTFKeyword::CHCBPAT, 0 },
+ { "chcfpat", RTFControlType::VALUE, RTFKeyword::CHCFPAT, 0 },
+ { "chdate", RTFControlType::SYMBOL, RTFKeyword::CHDATE, 0 },
+ { "chdpa", RTFControlType::SYMBOL, RTFKeyword::CHDPA, 0 },
+ { "chdpl", RTFControlType::SYMBOL, RTFKeyword::CHDPL, 0 },
+ { "chftn", RTFControlType::SYMBOL, RTFKeyword::CHFTN, 0 },
+ { "chftnsep", RTFControlType::SYMBOL, RTFKeyword::CHFTNSEP, 0 },
+ { "chftnsepc", RTFControlType::SYMBOL, RTFKeyword::CHFTNSEPC, 0 },
+ { "chpgn", RTFControlType::SYMBOL, RTFKeyword::CHPGN, 0 },
+ { "chhres", RTFControlType::VALUE, RTFKeyword::CHHRES, 0 },
+ { "chshdng", RTFControlType::VALUE, RTFKeyword::CHSHDNG, 0 },
+ { "chtime", RTFControlType::SYMBOL, RTFKeyword::CHTIME, 0 },
+ { "chyperlink", RTFControlType::FLAG, RTFKeyword::CHYPERLINK, 0 },
+ { "clbgbdiag", RTFControlType::FLAG, RTFKeyword::CLBGBDIAG, 0 },
+ { "clbgcross", RTFControlType::FLAG, RTFKeyword::CLBGCROSS, 0 },
+ { "clbgdcross", RTFControlType::FLAG, RTFKeyword::CLBGDCROSS, 0 },
+ { "clbgdkbdiag", RTFControlType::FLAG, RTFKeyword::CLBGDKBDIAG, 0 },
+ { "clbgdkcross", RTFControlType::FLAG, RTFKeyword::CLBGDKCROSS, 0 },
+ { "clbgdkdcross", RTFControlType::FLAG, RTFKeyword::CLBGDKDCROSS, 0 },
+ { "clbgdkfdiag", RTFControlType::FLAG, RTFKeyword::CLBGDKFDIAG, 0 },
+ { "clbgdkhor", RTFControlType::FLAG, RTFKeyword::CLBGDKHOR, 0 },
+ { "clbgdkvert", RTFControlType::FLAG, RTFKeyword::CLBGDKVERT, 0 },
+ { "clbgfdiag", RTFControlType::FLAG, RTFKeyword::CLBGFDIAG, 0 },
+ { "clbghoriz", RTFControlType::FLAG, RTFKeyword::CLBGHORIZ, 0 },
+ { "clbgvert", RTFControlType::FLAG, RTFKeyword::CLBGVERT, 0 },
+ { "clbrdrb", RTFControlType::FLAG, RTFKeyword::CLBRDRB, 0 },
+ { "clbrdrl", RTFControlType::FLAG, RTFKeyword::CLBRDRL, 0 },
+ { "clbrdrr", RTFControlType::FLAG, RTFKeyword::CLBRDRR, 0 },
+ { "clbrdrt", RTFControlType::FLAG, RTFKeyword::CLBRDRT, 0 },
+ { "clcbpat", RTFControlType::VALUE, RTFKeyword::CLCBPAT, 0 },
+ { "clcbpatraw", RTFControlType::VALUE, RTFKeyword::CLCBPATRAW, 0 },
+ { "clcfpat", RTFControlType::VALUE, RTFKeyword::CLCFPAT, 0 },
+ { "clcfpatraw", RTFControlType::VALUE, RTFKeyword::CLCFPATRAW, 0 },
+ { "cldel", RTFControlType::FLAG, RTFKeyword::CLDEL, 0 },
+ { "cldelauth", RTFControlType::VALUE, RTFKeyword::CLDELAUTH, 0 },
+ { "cldeldttm", RTFControlType::VALUE, RTFKeyword::CLDELDTTM, 0 },
+ { "cldgll", RTFControlType::FLAG, RTFKeyword::CLDGLL, 0 },
+ { "cldglu", RTFControlType::FLAG, RTFKeyword::CLDGLU, 0 },
+ { "clFitText", RTFControlType::FLAG, RTFKeyword::CLFITTEXT, 0 },
+ { "clftsWidth", RTFControlType::VALUE, RTFKeyword::CLFTSWIDTH, 0 },
+ { "clhidemark", RTFControlType::FLAG, RTFKeyword::CLHIDEMARK, 0 },
+ { "clins", RTFControlType::FLAG, RTFKeyword::CLINS, 0 },
+ { "clinsauth", RTFControlType::VALUE, RTFKeyword::CLINSAUTH, 0 },
+ { "clinsdttm", RTFControlType::VALUE, RTFKeyword::CLINSDTTM, 0 },
+ { "clmgf", RTFControlType::FLAG, RTFKeyword::CLMGF, 0 },
+ { "clmrg", RTFControlType::FLAG, RTFKeyword::CLMRG, 0 },
+ { "clmrgd", RTFControlType::FLAG, RTFKeyword::CLMRGD, 0 },
+ { "clmrgdauth", RTFControlType::VALUE, RTFKeyword::CLMRGDAUTH, 0 },
+ { "clmrgddttm", RTFControlType::VALUE, RTFKeyword::CLMRGDDTTM, 0 },
+ { "clmrgdr", RTFControlType::FLAG, RTFKeyword::CLMRGDR, 0 },
+ { "clNoWrap", RTFControlType::FLAG, RTFKeyword::CLNOWRAP, 0 },
+ { "clpadb", RTFControlType::VALUE, RTFKeyword::CLPADB, 0 },
+ { "clpadfb", RTFControlType::VALUE, RTFKeyword::CLPADFB, 0 },
+ { "clpadfl", RTFControlType::VALUE, RTFKeyword::CLPADFL, 0 },
+ { "clpadfr", RTFControlType::VALUE, RTFKeyword::CLPADFR, 0 },
+ { "clpadft", RTFControlType::VALUE, RTFKeyword::CLPADFT, 0 },
+ { "clpadl", RTFControlType::VALUE, RTFKeyword::CLPADL, 0 },
+ { "clpadr", RTFControlType::VALUE, RTFKeyword::CLPADR, 0 },
+ { "clpadt", RTFControlType::VALUE, RTFKeyword::CLPADT, 0 },
+ { "clspb", RTFControlType::VALUE, RTFKeyword::CLSPB, 0 },
+ { "clspfb", RTFControlType::VALUE, RTFKeyword::CLSPFB, 0 },
+ { "clspfl", RTFControlType::VALUE, RTFKeyword::CLSPFL, 0 },
+ { "clspfr", RTFControlType::VALUE, RTFKeyword::CLSPFR, 0 },
+ { "clspft", RTFControlType::VALUE, RTFKeyword::CLSPFT, 0 },
+ { "clspl", RTFControlType::VALUE, RTFKeyword::CLSPL, 0 },
+ { "clspr", RTFControlType::VALUE, RTFKeyword::CLSPR, 0 },
+ { "clspt", RTFControlType::VALUE, RTFKeyword::CLSPT, 0 },
+ { "clshdng", RTFControlType::VALUE, RTFKeyword::CLSHDNG, 0 },
+ { "clshdngraw", RTFControlType::VALUE, RTFKeyword::CLSHDNGRAW, 0 },
+ { "clshdrawnil", RTFControlType::FLAG, RTFKeyword::CLSHDRAWNIL, 0 },
+ { "clsplit", RTFControlType::FLAG, RTFKeyword::CLSPLIT, 0 },
+ { "clsplitr", RTFControlType::FLAG, RTFKeyword::CLSPLITR, 0 },
+ { "cltxbtlr", RTFControlType::FLAG, RTFKeyword::CLTXBTLR, 0 },
+ { "cltxlrtb", RTFControlType::FLAG, RTFKeyword::CLTXLRTB, 0 },
+ { "cltxlrtbv", RTFControlType::FLAG, RTFKeyword::CLTXLRTBV, 0 },
+ { "cltxtbrl", RTFControlType::FLAG, RTFKeyword::CLTXTBRL, 0 },
+ { "cltxtbrlv", RTFControlType::FLAG, RTFKeyword::CLTXTBRLV, 0 },
+ { "clvertalb", RTFControlType::FLAG, RTFKeyword::CLVERTALB, 0 },
+ { "clvertalc", RTFControlType::FLAG, RTFKeyword::CLVERTALC, 0 },
+ { "clvertalt", RTFControlType::FLAG, RTFKeyword::CLVERTALT, 0 },
+ { "clvmgf", RTFControlType::FLAG, RTFKeyword::CLVMGF, 0 },
+ { "clvmrg", RTFControlType::FLAG, RTFKeyword::CLVMRG, 0 },
+ { "clwWidth", RTFControlType::VALUE, RTFKeyword::CLWWIDTH, 0 },
+ { "cmaindarkone", RTFControlType::FLAG, RTFKeyword::CMAINDARKONE, 0 },
+ { "cmaindarktwo", RTFControlType::FLAG, RTFKeyword::CMAINDARKTWO, 0 },
+ { "cmainlightone", RTFControlType::FLAG, RTFKeyword::CMAINLIGHTONE, 0 },
+ { "cmainlighttwo", RTFControlType::FLAG, RTFKeyword::CMAINLIGHTTWO, 0 },
+ { "collapsed", RTFControlType::FLAG, RTFKeyword::COLLAPSED, 0 },
+ { "colno", RTFControlType::VALUE, RTFKeyword::COLNO, 0 },
+ { "colorschememapping", RTFControlType::DESTINATION, RTFKeyword::COLORSCHEMEMAPPING, 0 },
+ { "colortbl", RTFControlType::DESTINATION, RTFKeyword::COLORTBL, 0 },
+ { "cols", RTFControlType::VALUE, RTFKeyword::COLS, 1 },
+ { "colsr", RTFControlType::VALUE, RTFKeyword::COLSR, 0 },
+ { "colsx", RTFControlType::VALUE, RTFKeyword::COLSX, 720 },
+ { "column", RTFControlType::SYMBOL, RTFKeyword::COLUMN, 0 },
+ { "colw", RTFControlType::VALUE, RTFKeyword::COLW, 0 },
+ { "comment", RTFControlType::DESTINATION, RTFKeyword::COMMENT, 0 },
+ { "company", RTFControlType::DESTINATION, RTFKeyword::COMPANY, 0 },
+ { "contextualspace", RTFControlType::FLAG, RTFKeyword::CONTEXTUALSPACE, 0 },
+ { "cpg", RTFControlType::VALUE, RTFKeyword::CPG, 0 },
+ { "crauth", RTFControlType::VALUE, RTFKeyword::CRAUTH, 0 },
+ { "crdate", RTFControlType::VALUE, RTFKeyword::CRDATE, 0 },
+ { "creatim", RTFControlType::DESTINATION, RTFKeyword::CREATIM, 0 },
+ { "cs", RTFControlType::VALUE, RTFKeyword::CS, 0 },
+ { "cshade", RTFControlType::VALUE, RTFKeyword::CSHADE, 0 },
+ { "ctextone", RTFControlType::FLAG, RTFKeyword::CTEXTONE, 0 },
+ { "ctexttwo", RTFControlType::FLAG, RTFKeyword::CTEXTTWO, 0 },
+ { "ctint", RTFControlType::VALUE, RTFKeyword::CTINT, 0 },
+ { "ctrl", RTFControlType::FLAG, RTFKeyword::CTRL, 0 },
+ { "cts", RTFControlType::VALUE, RTFKeyword::CTS, 0 },
+ { "cufi", RTFControlType::VALUE, RTFKeyword::CUFI, 0 },
+ { "culi", RTFControlType::VALUE, RTFKeyword::CULI, 0 },
+ { "curi", RTFControlType::VALUE, RTFKeyword::CURI, 0 },
+ { "cvmme", RTFControlType::FLAG, RTFKeyword::CVMME, 0 },
+ { "datafield", RTFControlType::DESTINATION, RTFKeyword::DATAFIELD, 0 },
+ { "datastore", RTFControlType::DESTINATION, RTFKeyword::DATASTORE, 0 },
+ { "date", RTFControlType::FLAG, RTFKeyword::DATE, 0 },
+ { "dbch", RTFControlType::FLAG, RTFKeyword::DBCH, 0 },
+ { "defchp", RTFControlType::DESTINATION, RTFKeyword::DEFCHP, 0 },
+ { "deff", RTFControlType::VALUE, RTFKeyword::DEFF, 0 },
+ { "defformat", RTFControlType::FLAG, RTFKeyword::DEFFORMAT, 0 },
+ { "deflang", RTFControlType::VALUE, RTFKeyword::DEFLANG, 0 },
+ { "deflangfe", RTFControlType::VALUE, RTFKeyword::DEFLANGFE, 0 },
+ { "defpap", RTFControlType::DESTINATION, RTFKeyword::DEFPAP, 0 },
+ { "defshp", RTFControlType::FLAG, RTFKeyword::DEFSHP, 0 },
+ { "deftab", RTFControlType::VALUE, RTFKeyword::DEFTAB, 720 },
+ { "deleted", RTFControlType::TOGGLE, RTFKeyword::DELETED, 1 },
+ { "delrsid", RTFControlType::VALUE, RTFKeyword::DELRSID, 0 },
+ { "dfrauth", RTFControlType::VALUE, RTFKeyword::DFRAUTH, 0 },
+ { "dfrdate", RTFControlType::VALUE, RTFKeyword::DFRDATE, 0 },
+ { "dfrmtxtx", RTFControlType::VALUE, RTFKeyword::DFRMTXTX, 0 },
+ { "dfrmtxty", RTFControlType::VALUE, RTFKeyword::DFRMTXTY, 0 },
+ { "dfrstart", RTFControlType::VALUE, RTFKeyword::DFRSTART, 0 },
+ { "dfrstop", RTFControlType::VALUE, RTFKeyword::DFRSTOP, 0 },
+ { "dfrxst", RTFControlType::VALUE, RTFKeyword::DFRXST, 0 },
+ { "dghorigin", RTFControlType::VALUE, RTFKeyword::DGHORIGIN, 1701 },
+ { "dghshow", RTFControlType::VALUE, RTFKeyword::DGHSHOW, 3 },
+ { "dghspace", RTFControlType::VALUE, RTFKeyword::DGHSPACE, 120 },
+ { "dgmargin", RTFControlType::FLAG, RTFKeyword::DGMARGIN, 0 },
+ { "dgsnap", RTFControlType::FLAG, RTFKeyword::DGSNAP, 0 },
+ { "dgvorigin", RTFControlType::VALUE, RTFKeyword::DGVORIGIN, 1984 },
+ { "dgvshow", RTFControlType::VALUE, RTFKeyword::DGVSHOW, 0 },
+ { "dgvspace", RTFControlType::VALUE, RTFKeyword::DGVSPACE, 120 },
+ { "dibitmap", RTFControlType::VALUE, RTFKeyword::DIBITMAP, 0 },
+ { "disabled", RTFControlType::TOGGLE, RTFKeyword::DISABLED, 1 },
+ { "dn", RTFControlType::VALUE, RTFKeyword::DN, 6 },
+ { "dntblnsbdb", RTFControlType::FLAG, RTFKeyword::DNTBLNSBDB, 0 },
+ { "do", RTFControlType::DESTINATION, RTFKeyword::DO, 0 },
+ { "dobxcolumn", RTFControlType::FLAG, RTFKeyword::DOBXCOLUMN, 0 },
+ { "dobxmargin", RTFControlType::FLAG, RTFKeyword::DOBXMARGIN, 0 },
+ { "dobxpage", RTFControlType::FLAG, RTFKeyword::DOBXPAGE, 0 },
+ { "dobymargin", RTFControlType::FLAG, RTFKeyword::DOBYMARGIN, 0 },
+ { "dobypage", RTFControlType::FLAG, RTFKeyword::DOBYPAGE, 0 },
+ { "dobypara", RTFControlType::FLAG, RTFKeyword::DOBYPARA, 0 },
+ { "doccomm", RTFControlType::DESTINATION, RTFKeyword::DOCCOMM, 0 },
+ { "doctemp", RTFControlType::FLAG, RTFKeyword::DOCTEMP, 0 },
+ { "doctype", RTFControlType::VALUE, RTFKeyword::DOCTYPE, 0 },
+ { "docvar", RTFControlType::DESTINATION, RTFKeyword::DOCVAR, 0 },
+ { "dodhgt", RTFControlType::VALUE, RTFKeyword::DODHGT, 0 },
+ { "dolock", RTFControlType::FLAG, RTFKeyword::DOLOCK, 0 },
+ { "donotembedlingdata", RTFControlType::VALUE, RTFKeyword::DONOTEMBEDLINGDATA, 0 },
+ { "donotembedsysfont", RTFControlType::VALUE, RTFKeyword::DONOTEMBEDSYSFONT, 0 },
+ { "donotshowcomments", RTFControlType::FLAG, RTFKeyword::DONOTSHOWCOMMENTS, 0 },
+ { "donotshowinsdel", RTFControlType::FLAG, RTFKeyword::DONOTSHOWINSDEL, 0 },
+ { "donotshowmarkup", RTFControlType::FLAG, RTFKeyword::DONOTSHOWMARKUP, 0 },
+ { "donotshowprops", RTFControlType::FLAG, RTFKeyword::DONOTSHOWPROPS, 0 },
+ { "dpaendhol", RTFControlType::FLAG, RTFKeyword::DPAENDHOL, 0 },
+ { "dpaendl", RTFControlType::VALUE, RTFKeyword::DPAENDL, 0 },
+ { "dpaendsol", RTFControlType::FLAG, RTFKeyword::DPAENDSOL, 0 },
+ { "dpaendw", RTFControlType::VALUE, RTFKeyword::DPAENDW, 0 },
+ { "dparc", RTFControlType::FLAG, RTFKeyword::DPARC, 0 },
+ { "dparcflipx", RTFControlType::FLAG, RTFKeyword::DPARCFLIPX, 0 },
+ { "dparcflipy", RTFControlType::FLAG, RTFKeyword::DPARCFLIPY, 0 },
+ { "dpastarthol", RTFControlType::FLAG, RTFKeyword::DPASTARTHOL, 0 },
+ { "dpastartl", RTFControlType::VALUE, RTFKeyword::DPASTARTL, 0 },
+ { "dpastartsol", RTFControlType::FLAG, RTFKeyword::DPASTARTSOL, 0 },
+ { "dpastartw", RTFControlType::VALUE, RTFKeyword::DPASTARTW, 0 },
+ { "dpcallout", RTFControlType::FLAG, RTFKeyword::DPCALLOUT, 0 },
+ { "dpcoa", RTFControlType::VALUE, RTFKeyword::DPCOA, 0 },
+ { "dpcoaccent", RTFControlType::FLAG, RTFKeyword::DPCOACCENT, 0 },
+ { "dpcobestfit", RTFControlType::FLAG, RTFKeyword::DPCOBESTFIT, 0 },
+ { "dpcoborder", RTFControlType::FLAG, RTFKeyword::DPCOBORDER, 0 },
+ { "dpcodabs", RTFControlType::FLAG, RTFKeyword::DPCODABS, 0 },
+ { "dpcodbottom", RTFControlType::FLAG, RTFKeyword::DPCODBOTTOM, 0 },
+ { "dpcodcenter", RTFControlType::FLAG, RTFKeyword::DPCODCENTER, 0 },
+ { "dpcodescent", RTFControlType::VALUE, RTFKeyword::DPCODESCENT, 0 },
+ { "dpcodtop", RTFControlType::FLAG, RTFKeyword::DPCODTOP, 0 },
+ { "dpcolength", RTFControlType::VALUE, RTFKeyword::DPCOLENGTH, 0 },
+ { "dpcominusx", RTFControlType::FLAG, RTFKeyword::DPCOMINUSX, 0 },
+ { "dpcominusy", RTFControlType::FLAG, RTFKeyword::DPCOMINUSY, 0 },
+ { "dpcooffset", RTFControlType::VALUE, RTFKeyword::DPCOOFFSET, 0 },
+ { "dpcosmarta", RTFControlType::FLAG, RTFKeyword::DPCOSMARTA, 0 },
+ { "dpcotdouble", RTFControlType::FLAG, RTFKeyword::DPCOTDOUBLE, 0 },
+ { "dpcotright", RTFControlType::FLAG, RTFKeyword::DPCOTRIGHT, 0 },
+ { "dpcotsingle", RTFControlType::FLAG, RTFKeyword::DPCOTSINGLE, 0 },
+ { "dpcottriple", RTFControlType::FLAG, RTFKeyword::DPCOTTRIPLE, 0 },
+ { "dpcount", RTFControlType::VALUE, RTFKeyword::DPCOUNT, 0 },
+ { "dpellipse", RTFControlType::FLAG, RTFKeyword::DPELLIPSE, 0 },
+ { "dpendgroup", RTFControlType::FLAG, RTFKeyword::DPENDGROUP, 0 },
+ { "dpfillbgcb", RTFControlType::VALUE, RTFKeyword::DPFILLBGCB, 0 },
+ { "dpfillbgcg", RTFControlType::VALUE, RTFKeyword::DPFILLBGCG, 0 },
+ { "dpfillbgcr", RTFControlType::VALUE, RTFKeyword::DPFILLBGCR, 0 },
+ { "dpfillbggray", RTFControlType::VALUE, RTFKeyword::DPFILLBGGRAY, 0 },
+ { "dpfillbgpal", RTFControlType::FLAG, RTFKeyword::DPFILLBGPAL, 0 },
+ { "dpfillfgcb", RTFControlType::VALUE, RTFKeyword::DPFILLFGCB, 0 },
+ { "dpfillfgcg", RTFControlType::VALUE, RTFKeyword::DPFILLFGCG, 0 },
+ { "dpfillfgcr", RTFControlType::VALUE, RTFKeyword::DPFILLFGCR, 0 },
+ { "dpfillfggray", RTFControlType::VALUE, RTFKeyword::DPFILLFGGRAY, 0 },
+ { "dpfillfgpal", RTFControlType::FLAG, RTFKeyword::DPFILLFGPAL, 0 },
+ { "dpfillpat", RTFControlType::VALUE, RTFKeyword::DPFILLPAT, 0 },
+ { "dpgroup", RTFControlType::FLAG, RTFKeyword::DPGROUP, 0 },
+ { "dpline", RTFControlType::FLAG, RTFKeyword::DPLINE, 0 },
+ { "dplinecob", RTFControlType::VALUE, RTFKeyword::DPLINECOB, 0 },
+ { "dplinecog", RTFControlType::VALUE, RTFKeyword::DPLINECOG, 0 },
+ { "dplinecor", RTFControlType::VALUE, RTFKeyword::DPLINECOR, 0 },
+ { "dplinedado", RTFControlType::FLAG, RTFKeyword::DPLINEDADO, 0 },
+ { "dplinedadodo", RTFControlType::FLAG, RTFKeyword::DPLINEDADODO, 0 },
+ { "dplinedash", RTFControlType::FLAG, RTFKeyword::DPLINEDASH, 0 },
+ { "dplinedot", RTFControlType::FLAG, RTFKeyword::DPLINEDOT, 0 },
+ { "dplinegray", RTFControlType::VALUE, RTFKeyword::DPLINEGRAY, 0 },
+ { "dplinehollow", RTFControlType::FLAG, RTFKeyword::DPLINEHOLLOW, 0 },
+ { "dplinepal", RTFControlType::FLAG, RTFKeyword::DPLINEPAL, 0 },
+ { "dplinesolid", RTFControlType::FLAG, RTFKeyword::DPLINESOLID, 0 },
+ { "dplinew", RTFControlType::VALUE, RTFKeyword::DPLINEW, 0 },
+ { "dppolycount", RTFControlType::VALUE, RTFKeyword::DPPOLYCOUNT, 0 },
+ { "dppolygon", RTFControlType::FLAG, RTFKeyword::DPPOLYGON, 0 },
+ { "dppolyline", RTFControlType::FLAG, RTFKeyword::DPPOLYLINE, 0 },
+ { "dpptx", RTFControlType::VALUE, RTFKeyword::DPPTX, 0 },
+ { "dppty", RTFControlType::VALUE, RTFKeyword::DPPTY, 0 },
+ { "dprect", RTFControlType::FLAG, RTFKeyword::DPRECT, 0 },
+ { "dproundr", RTFControlType::FLAG, RTFKeyword::DPROUNDR, 0 },
+ { "dpshadow", RTFControlType::FLAG, RTFKeyword::DPSHADOW, 0 },
+ { "dpshadx", RTFControlType::VALUE, RTFKeyword::DPSHADX, 0 },
+ { "dpshady", RTFControlType::VALUE, RTFKeyword::DPSHADY, 0 },
+ { "dptxbtlr", RTFControlType::FLAG, RTFKeyword::DPTXBTLR, 0 },
+ { "dptxbx", RTFControlType::FLAG, RTFKeyword::DPTXBX, 0 },
+ { "dptxbxmar", RTFControlType::VALUE, RTFKeyword::DPTXBXMAR, 0 },
+ { "dptxbxtext", RTFControlType::DESTINATION, RTFKeyword::DPTXBXTEXT, 0 },
+ { "dptxlrtb", RTFControlType::FLAG, RTFKeyword::DPTXLRTB, 0 },
+ { "dptxlrtbv", RTFControlType::FLAG, RTFKeyword::DPTXLRTBV, 0 },
+ { "dptxtbrl", RTFControlType::FLAG, RTFKeyword::DPTXTBRL, 0 },
+ { "dptxtbrlv", RTFControlType::FLAG, RTFKeyword::DPTXTBRLV, 0 },
+ { "dpx", RTFControlType::VALUE, RTFKeyword::DPX, 0 },
+ { "dpxsize", RTFControlType::VALUE, RTFKeyword::DPXSIZE, 0 },
+ { "dpy", RTFControlType::VALUE, RTFKeyword::DPY, 0 },
+ { "dpysize", RTFControlType::VALUE, RTFKeyword::DPYSIZE, 0 },
+ { "dropcapli", RTFControlType::VALUE, RTFKeyword::DROPCAPLI, 0 },
+ { "dropcapt", RTFControlType::VALUE, RTFKeyword::DROPCAPT, 0 },
+ { "ds", RTFControlType::VALUE, RTFKeyword::DS, 0 },
+ { "dxfrtext", RTFControlType::VALUE, RTFKeyword::DXFRTEXT, 0 },
+ { "dy", RTFControlType::VALUE, RTFKeyword::DY, 0 },
+ { "ebcend", RTFControlType::DESTINATION, RTFKeyword::EBCEND, 0 },
+ { "ebcstart", RTFControlType::DESTINATION, RTFKeyword::EBCSTART, 0 },
+ { "edmins", RTFControlType::VALUE, RTFKeyword::EDMINS, 0 },
+ { "embo", RTFControlType::TOGGLE, RTFKeyword::EMBO, 1 },
+ { "emdash", RTFControlType::SYMBOL, RTFKeyword::EMDASH, 0 },
+ { "emfblip", RTFControlType::FLAG, RTFKeyword::EMFBLIP, 0 },
+ { "emspace", RTFControlType::SYMBOL, RTFKeyword::EMSPACE, 0 },
+ { "endash", RTFControlType::SYMBOL, RTFKeyword::ENDASH, 0 },
+ { "enddoc", RTFControlType::FLAG, RTFKeyword::ENDDOC, 0 },
+ { "endnhere", RTFControlType::FLAG, RTFKeyword::ENDNHERE, 0 },
+ { "endnotes", RTFControlType::FLAG, RTFKeyword::ENDNOTES, 0 },
+ { "enforceprot", RTFControlType::VALUE, RTFKeyword::ENFORCEPROT, 0 },
+ { "enspace", RTFControlType::SYMBOL, RTFKeyword::ENSPACE, 0 },
+ { "expnd", RTFControlType::VALUE, RTFKeyword::EXPND, 0 },
+ { "expndtw", RTFControlType::VALUE, RTFKeyword::EXPNDTW, 0 },
+ { "expshrtn", RTFControlType::FLAG, RTFKeyword::EXPSHRTN, 0 },
+ { "f", RTFControlType::VALUE, RTFKeyword::F, 0 },
+ { "faauto", RTFControlType::FLAG, RTFKeyword::FAAUTO, 0 },
+ { "facenter", RTFControlType::FLAG, RTFKeyword::FACENTER, 0 },
+ { "facingp", RTFControlType::TOGGLE, RTFKeyword::FACINGP, 1 },
+ { "factoidname", RTFControlType::DESTINATION, RTFKeyword::FACTOIDNAME, 0 },
+ { "fafixed", RTFControlType::FLAG, RTFKeyword::FAFIXED, 0 },
+ { "fahang", RTFControlType::FLAG, RTFKeyword::FAHANG, 0 },
+ { "falt", RTFControlType::DESTINATION, RTFKeyword::FALT, 0 },
+ { "faroman", RTFControlType::FLAG, RTFKeyword::FAROMAN, 0 },
+ { "favar", RTFControlType::FLAG, RTFKeyword::FAVAR, 0 },
+ { "fbias", RTFControlType::VALUE, RTFKeyword::FBIAS, 0 },
+ { "fbidi", RTFControlType::FLAG, RTFKeyword::FBIDI, 0 },
+ { "fbidis", RTFControlType::FLAG, RTFKeyword::FBIDIS, 0 },
+ { "fbimajor", RTFControlType::FLAG, RTFKeyword::FBIMAJOR, 0 },
+ { "fbiminor", RTFControlType::FLAG, RTFKeyword::FBIMINOR, 0 },
+ { "fchars", RTFControlType::DESTINATION, RTFKeyword::FCHARS, 0 },
+ { "fcharset", RTFControlType::VALUE, RTFKeyword::FCHARSET, 0 },
+ { "fcs", RTFControlType::VALUE, RTFKeyword::FCS, 0 },
+ { "fdbmajor", RTFControlType::FLAG, RTFKeyword::FDBMAJOR, 0 },
+ { "fdbminor", RTFControlType::FLAG, RTFKeyword::FDBMINOR, 0 },
+ { "fdecor", RTFControlType::FLAG, RTFKeyword::FDECOR, 0 },
+ { "felnbrelev", RTFControlType::FLAG, RTFKeyword::FELNBRELEV, 0 },
+ { "fet", RTFControlType::VALUE, RTFKeyword::FET, 0 },
+ { "fetch", RTFControlType::FLAG, RTFKeyword::FETCH, 0 },
+ { "ffdefres", RTFControlType::VALUE, RTFKeyword::FFDEFRES, 0 },
+ { "ffdeftext", RTFControlType::DESTINATION, RTFKeyword::FFDEFTEXT, 0 },
+ { "ffentrymcr", RTFControlType::DESTINATION, RTFKeyword::FFENTRYMCR, 0 },
+ { "ffexitmcr", RTFControlType::DESTINATION, RTFKeyword::FFEXITMCR, 0 },
+ { "ffformat", RTFControlType::DESTINATION, RTFKeyword::FFFORMAT, 0 },
+ { "ffhaslistbox", RTFControlType::VALUE, RTFKeyword::FFHASLISTBOX, 0 },
+ { "ffhelptext", RTFControlType::DESTINATION, RTFKeyword::FFHELPTEXT, 0 },
+ { "ffhps", RTFControlType::VALUE, RTFKeyword::FFHPS, 0 },
+ { "ffl", RTFControlType::DESTINATION, RTFKeyword::FFL, 0 },
+ { "ffmaxlen", RTFControlType::VALUE, RTFKeyword::FFMAXLEN, 0 },
+ { "ffname", RTFControlType::DESTINATION, RTFKeyword::FFNAME, 0 },
+ { "ffownhelp", RTFControlType::VALUE, RTFKeyword::FFOWNHELP, 0 },
+ { "ffownstat", RTFControlType::VALUE, RTFKeyword::FFOWNSTAT, 0 },
+ { "ffprot", RTFControlType::VALUE, RTFKeyword::FFPROT, 0 },
+ { "ffrecalc", RTFControlType::VALUE, RTFKeyword::FFRECALC, 0 },
+ { "ffres", RTFControlType::VALUE, RTFKeyword::FFRES, 0 },
+ { "ffsize", RTFControlType::VALUE, RTFKeyword::FFSIZE, 0 },
+ { "ffstattext", RTFControlType::DESTINATION, RTFKeyword::FFSTATTEXT, 0 },
+ { "fftype", RTFControlType::VALUE, RTFKeyword::FFTYPE, 0 },
+ { "fftypetxt", RTFControlType::VALUE, RTFKeyword::FFTYPETXT, 0 },
+ { "fhimajor", RTFControlType::FLAG, RTFKeyword::FHIMAJOR, 0 },
+ { "fhiminor", RTFControlType::FLAG, RTFKeyword::FHIMINOR, 0 },
+ { "fi", RTFControlType::VALUE, RTFKeyword::FI, 0 },
+ { "fid", RTFControlType::VALUE, RTFKeyword::FID, 0 },
+ { "field", RTFControlType::DESTINATION, RTFKeyword::FIELD, 0 },
+ { "file", RTFControlType::DESTINATION, RTFKeyword::FILE, 0 },
+ { "filetbl", RTFControlType::DESTINATION, RTFKeyword::FILETBL, 0 },
+ { "fittext", RTFControlType::VALUE, RTFKeyword::FITTEXT, 0 },
+ { "fjgothic", RTFControlType::FLAG, RTFKeyword::FJGOTHIC, 0 },
+ { "fjminchou", RTFControlType::FLAG, RTFKeyword::FJMINCHOU, 0 },
+ { "fldalt", RTFControlType::FLAG, RTFKeyword::FLDALT, 0 },
+ { "flddirty", RTFControlType::FLAG, RTFKeyword::FLDDIRTY, 0 },
+ { "fldedit", RTFControlType::FLAG, RTFKeyword::FLDEDIT, 0 },
+ { "fldinst", RTFControlType::DESTINATION, RTFKeyword::FLDINST, 0 },
+ { "fldlock", RTFControlType::FLAG, RTFKeyword::FLDLOCK, 0 },
+ { "fldpriv", RTFControlType::FLAG, RTFKeyword::FLDPRIV, 0 },
+ { "fldrslt", RTFControlType::DESTINATION, RTFKeyword::FLDRSLT, 0 },
+ { "fldtype", RTFControlType::DESTINATION, RTFKeyword::FLDTYPE, 0 },
+ { "flomajor", RTFControlType::FLAG, RTFKeyword::FLOMAJOR, 0 },
+ { "flominor", RTFControlType::FLAG, RTFKeyword::FLOMINOR, 0 },
+ { "fmodern", RTFControlType::FLAG, RTFKeyword::FMODERN, 0 },
+ { "fn", RTFControlType::VALUE, RTFKeyword::FN, 0 },
+ { "fname", RTFControlType::DESTINATION, RTFKeyword::FNAME, 0 },
+ { "fnetwork", RTFControlType::FLAG, RTFKeyword::FNETWORK, 0 },
+ { "fnil", RTFControlType::FLAG, RTFKeyword::FNIL, 0 },
+ { "fnonfilesys", RTFControlType::FLAG, RTFKeyword::FNONFILESYS, 0 },
+ { "fontemb", RTFControlType::DESTINATION, RTFKeyword::FONTEMB, 0 },
+ { "fontfile", RTFControlType::DESTINATION, RTFKeyword::FONTFILE, 0 },
+ { "fonttbl", RTFControlType::DESTINATION, RTFKeyword::FONTTBL, 0 },
+ { "footer", RTFControlType::DESTINATION, RTFKeyword::FOOTER, 0 },
+ { "footerf", RTFControlType::DESTINATION, RTFKeyword::FOOTERF, 0 },
+ { "footerl", RTFControlType::DESTINATION, RTFKeyword::FOOTERL, 0 },
+ { "footerr", RTFControlType::DESTINATION, RTFKeyword::FOOTERR, 0 },
+ { "footery", RTFControlType::VALUE, RTFKeyword::FOOTERY, 720 },
+ { "footnote", RTFControlType::DESTINATION, RTFKeyword::FOOTNOTE, 0 },
+ { "forceupgrade", RTFControlType::FLAG, RTFKeyword::FORCEUPGRADE, 0 },
+ { "formdisp", RTFControlType::FLAG, RTFKeyword::FORMDISP, 0 },
+ { "formfield", RTFControlType::DESTINATION, RTFKeyword::FORMFIELD, 0 },
+ { "formprot", RTFControlType::FLAG, RTFKeyword::FORMPROT, 0 },
+ { "formshade", RTFControlType::FLAG, RTFKeyword::FORMSHADE, 0 },
+ { "fosnum", RTFControlType::VALUE, RTFKeyword::FOSNUM, 0 },
+ { "fprq", RTFControlType::VALUE, RTFKeyword::FPRQ, 0 },
+ { "fracwidth", RTFControlType::FLAG, RTFKeyword::FRACWIDTH, 0 },
+ { "frelative", RTFControlType::VALUE, RTFKeyword::FRELATIVE, 0 },
+ { "frmtxbtlr", RTFControlType::FLAG, RTFKeyword::FRMTXBTLR, 0 },
+ { "frmtxlrtb", RTFControlType::FLAG, RTFKeyword::FRMTXLRTB, 0 },
+ { "frmtxlrtbv", RTFControlType::FLAG, RTFKeyword::FRMTXLRTBV, 0 },
+ { "frmtxtbrl", RTFControlType::FLAG, RTFKeyword::FRMTXTBRL, 0 },
+ { "frmtxtbrlv", RTFControlType::FLAG, RTFKeyword::FRMTXTBRLV, 0 },
+ { "froman", RTFControlType::FLAG, RTFKeyword::FROMAN, 0 },
+ { "fromhtml", RTFControlType::VALUE, RTFKeyword::FROMHTML, 0 },
+ { "fromtext", RTFControlType::FLAG, RTFKeyword::FROMTEXT, 0 },
+ { "fs", RTFControlType::VALUE, RTFKeyword::FS, 24 },
+ { "fscript", RTFControlType::FLAG, RTFKeyword::FSCRIPT, 0 },
+ { "fswiss", RTFControlType::FLAG, RTFKeyword::FSWISS, 0 },
+ { "ftech", RTFControlType::FLAG, RTFKeyword::FTECH, 0 },
+ { "ftnalt", RTFControlType::FLAG, RTFKeyword::FTNALT, 0 },
+ { "ftnbj", RTFControlType::FLAG, RTFKeyword::FTNBJ, 0 },
+ { "ftncn", RTFControlType::DESTINATION, RTFKeyword::FTNCN, 0 },
+ { "ftnil", RTFControlType::FLAG, RTFKeyword::FTNIL, 0 },
+ { "ftnlytwnine", RTFControlType::FLAG, RTFKeyword::FTNLYTWNINE, 0 },
+ { "ftnnalc", RTFControlType::FLAG, RTFKeyword::FTNNALC, 0 },
+ { "ftnnar", RTFControlType::FLAG, RTFKeyword::FTNNAR, 0 },
+ { "ftnnauc", RTFControlType::FLAG, RTFKeyword::FTNNAUC, 0 },
+ { "ftnnchi", RTFControlType::FLAG, RTFKeyword::FTNNCHI, 0 },
+ { "ftnnchosung", RTFControlType::FLAG, RTFKeyword::FTNNCHOSUNG, 0 },
+ { "ftnncnum", RTFControlType::FLAG, RTFKeyword::FTNNCNUM, 0 },
+ { "ftnndbar", RTFControlType::FLAG, RTFKeyword::FTNNDBAR, 0 },
+ { "ftnndbnum", RTFControlType::FLAG, RTFKeyword::FTNNDBNUM, 0 },
+ { "ftnndbnumd", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMD, 0 },
+ { "ftnndbnumk", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMK, 0 },
+ { "ftnndbnumt", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMT, 0 },
+ { "ftnnganada", RTFControlType::FLAG, RTFKeyword::FTNNGANADA, 0 },
+ { "ftnngbnum", RTFControlType::FLAG, RTFKeyword::FTNNGBNUM, 0 },
+ { "ftnngbnumd", RTFControlType::FLAG, RTFKeyword::FTNNGBNUMD, 0 },
+ { "ftnngbnumk", RTFControlType::FLAG, RTFKeyword::FTNNGBNUMK, 0 },
+ { "ftnngbnuml", RTFControlType::FLAG, RTFKeyword::FTNNGBNUML, 0 },
+ { "ftnnrlc", RTFControlType::FLAG, RTFKeyword::FTNNRLC, 0 },
+ { "ftnnruc", RTFControlType::FLAG, RTFKeyword::FTNNRUC, 0 },
+ { "ftnnzodiac", RTFControlType::FLAG, RTFKeyword::FTNNZODIAC, 0 },
+ { "ftnnzodiacd", RTFControlType::FLAG, RTFKeyword::FTNNZODIACD, 0 },
+ { "ftnnzodiacl", RTFControlType::FLAG, RTFKeyword::FTNNZODIACL, 0 },
+ { "ftnrestart", RTFControlType::FLAG, RTFKeyword::FTNRESTART, 0 },
+ { "ftnrstcont", RTFControlType::FLAG, RTFKeyword::FTNRSTCONT, 0 },
+ { "ftnrstpg", RTFControlType::FLAG, RTFKeyword::FTNRSTPG, 0 },
+ { "ftnsep", RTFControlType::DESTINATION, RTFKeyword::FTNSEP, 0 },
+ { "ftnsepc", RTFControlType::DESTINATION, RTFKeyword::FTNSEPC, 0 },
+ { "ftnstart", RTFControlType::VALUE, RTFKeyword::FTNSTART, 1 },
+ { "ftntj", RTFControlType::FLAG, RTFKeyword::FTNTJ, 0 },
+ { "fttruetype", RTFControlType::FLAG, RTFKeyword::FTTRUETYPE, 0 },
+ { "fvaliddos", RTFControlType::FLAG, RTFKeyword::FVALIDDOS, 0 },
+ { "fvalidhpfs", RTFControlType::FLAG, RTFKeyword::FVALIDHPFS, 0 },
+ { "fvalidmac", RTFControlType::FLAG, RTFKeyword::FVALIDMAC, 0 },
+ { "fvalidntfs", RTFControlType::FLAG, RTFKeyword::FVALIDNTFS, 0 },
+ { "g", RTFControlType::DESTINATION, RTFKeyword::G, 0 },
+ { "gcw", RTFControlType::VALUE, RTFKeyword::GCW, 0 },
+ { "generator", RTFControlType::DESTINATION, RTFKeyword::GENERATOR, 0 },
+ { "green", RTFControlType::VALUE, RTFKeyword::GREEN, 0 },
+ { "grfdocevents", RTFControlType::VALUE, RTFKeyword::GRFDOCEVENTS, 0 },
+ { "gridtbl", RTFControlType::DESTINATION, RTFKeyword::GRIDTBL, 0 },
+ { "gutter", RTFControlType::VALUE, RTFKeyword::GUTTER, 0 },
+ { "gutterprl", RTFControlType::FLAG, RTFKeyword::GUTTERPRL, 0 },
+ { "guttersxn", RTFControlType::VALUE, RTFKeyword::GUTTERSXN, 0 },
+ { "header", RTFControlType::DESTINATION, RTFKeyword::HEADER, 0 },
+ { "headerf", RTFControlType::DESTINATION, RTFKeyword::HEADERF, 0 },
+ { "headerl", RTFControlType::DESTINATION, RTFKeyword::HEADERL, 0 },
+ { "headerr", RTFControlType::DESTINATION, RTFKeyword::HEADERR, 0 },
+ { "headery", RTFControlType::VALUE, RTFKeyword::HEADERY, 720 },
+ { "hich", RTFControlType::FLAG, RTFKeyword::HICH, 0 },
+ { "highlight", RTFControlType::VALUE, RTFKeyword::HIGHLIGHT, 0 },
+ { "hl", RTFControlType::DESTINATION, RTFKeyword::HL, 0 },
+ { "hlfr", RTFControlType::DESTINATION, RTFKeyword::HLFR, 0 },
+ { "hlinkbase", RTFControlType::DESTINATION, RTFKeyword::HLINKBASE, 0 },
+ { "hlloc", RTFControlType::DESTINATION, RTFKeyword::HLLOC, 0 },
+ { "hlsrc", RTFControlType::DESTINATION, RTFKeyword::HLSRC, 0 },
+ { "horzdoc", RTFControlType::FLAG, RTFKeyword::HORZDOC, 0 },
+ { "horzsect", RTFControlType::FLAG, RTFKeyword::HORZSECT, 0 },
+ { "horzvert", RTFControlType::VALUE, RTFKeyword::HORZVERT, 0 },
+ { "hr", RTFControlType::VALUE, RTFKeyword::HR, 0 },
+ { "hres", RTFControlType::VALUE, RTFKeyword::HRES, 0 },
+ { "hrule", RTFControlType::FLAG, RTFKeyword::HRULE, 0 },
+ { "hsv", RTFControlType::DESTINATION, RTFKeyword::HSV, 0 },
+ { "htmautsp", RTFControlType::FLAG, RTFKeyword::HTMAUTSP, 0 },
+ { "htmlbase", RTFControlType::FLAG, RTFKeyword::HTMLBASE, 0 },
+ { "htmlrtf", RTFControlType::TOGGLE, RTFKeyword::HTMLRTF, 1 },
+ { "htmltag", RTFControlType::DESTINATION, RTFKeyword::HTMLTAG, 0 },
+ { "hwelev", RTFControlType::FLAG, RTFKeyword::HWELEV, 0 },
+ { "hyphauto", RTFControlType::TOGGLE, RTFKeyword::HYPHAUTO, 1 },
+ { "hyphcaps", RTFControlType::TOGGLE, RTFKeyword::HYPHCAPS, 1 },
+ { "hyphconsec", RTFControlType::VALUE, RTFKeyword::HYPHCONSEC, 0 },
+ { "hyphhotz", RTFControlType::VALUE, RTFKeyword::HYPHHOTZ, 0 },
+ { "hyphpar", RTFControlType::TOGGLE, RTFKeyword::HYPHPAR, 1 },
+ { "i", RTFControlType::TOGGLE, RTFKeyword::I, 1 },
+ { "id", RTFControlType::VALUE, RTFKeyword::ID, 0 },
+ { "ignoremixedcontent", RTFControlType::VALUE, RTFKeyword::IGNOREMIXEDCONTENT, 0 },
+ { "ilfomacatclnup", RTFControlType::VALUE, RTFKeyword::ILFOMACATCLNUP, 0 },
+ { "ilvl", RTFControlType::VALUE, RTFKeyword::ILVL, 0 },
+ { "impr", RTFControlType::TOGGLE, RTFKeyword::IMPR, 1 },
+ { "indmirror", RTFControlType::FLAG, RTFKeyword::INDMIRROR, 0 },
+ { "indrlsweleven", RTFControlType::FLAG, RTFKeyword::INDRLSWELEVEN, 0 },
+ { "info", RTFControlType::DESTINATION, RTFKeyword::INFO, 0 },
+ { "insrsid", RTFControlType::VALUE, RTFKeyword::INSRSID, 0 },
+ { "intbl", RTFControlType::FLAG, RTFKeyword::INTBL, 0 },
+ { "ipgp", RTFControlType::VALUE, RTFKeyword::IPGP, 0 },
+ { "irowband", RTFControlType::VALUE, RTFKeyword::IROWBAND, 0 },
+ { "irow", RTFControlType::VALUE, RTFKeyword::IROW, 0 },
+ { "itap", RTFControlType::VALUE, RTFKeyword::ITAP, 1 },
+ { "ixe", RTFControlType::FLAG, RTFKeyword::IXE, 0 },
+ { "jcompress", RTFControlType::FLAG, RTFKeyword::JCOMPRESS, 0 },
+ { "jexpand", RTFControlType::FLAG, RTFKeyword::JEXPAND, 0 },
+ { "jis", RTFControlType::FLAG, RTFKeyword::JIS, 0 },
+ { "jpegblip", RTFControlType::FLAG, RTFKeyword::JPEGBLIP, 0 },
+ { "jsksu", RTFControlType::FLAG, RTFKeyword::JSKSU, 0 },
+ { "keep", RTFControlType::FLAG, RTFKeyword::KEEP, 0 },
+ { "keepn", RTFControlType::FLAG, RTFKeyword::KEEPN, 0 },
+ { "kerning", RTFControlType::VALUE, RTFKeyword::KERNING, 0 },
+ { "keycode", RTFControlType::DESTINATION, RTFKeyword::KEYCODE, 0 },
+ { "keywords", RTFControlType::DESTINATION, RTFKeyword::KEYWORDS, 0 },
+ { "krnprsnet", RTFControlType::FLAG, RTFKeyword::KRNPRSNET, 0 },
+ { "ksulang", RTFControlType::VALUE, RTFKeyword::KSULANG, 0 },
+ { "jclisttab", RTFControlType::FLAG, RTFKeyword::JCLISTTAB, 0 },
+ { "landscape", RTFControlType::FLAG, RTFKeyword::LANDSCAPE, 0 },
+ { "lang", RTFControlType::VALUE, RTFKeyword::LANG, 0 },
+ { "langfe", RTFControlType::VALUE, RTFKeyword::LANGFE, 0 },
+ { "langfenp", RTFControlType::VALUE, RTFKeyword::LANGFENP, 0 },
+ { "langnp", RTFControlType::VALUE, RTFKeyword::LANGNP, 0 },
+ { "lastrow", RTFControlType::FLAG, RTFKeyword::LASTROW, 0 },
+ { "latentstyles", RTFControlType::DESTINATION, RTFKeyword::LATENTSTYLES, 0 },
+ { "lbr", RTFControlType::VALUE, RTFKeyword::LBR, 0 },
+ { "lchars", RTFControlType::DESTINATION, RTFKeyword::LCHARS, 0 },
+ { "ldblquote", RTFControlType::SYMBOL, RTFKeyword::LDBLQUOTE, 0 },
+ { "level", RTFControlType::VALUE, RTFKeyword::LEVEL, 0 },
+ { "levelfollow", RTFControlType::VALUE, RTFKeyword::LEVELFOLLOW, 0 },
+ { "levelindent", RTFControlType::VALUE, RTFKeyword::LEVELINDENT, 0 },
+ { "leveljc", RTFControlType::VALUE, RTFKeyword::LEVELJC, 0 },
+ { "leveljcn", RTFControlType::VALUE, RTFKeyword::LEVELJCN, 0 },
+ { "levellegal", RTFControlType::VALUE, RTFKeyword::LEVELLEGAL, 0 },
+ { "levelnfc", RTFControlType::VALUE, RTFKeyword::LEVELNFC, 0 },
+ { "levelnfcn", RTFControlType::VALUE, RTFKeyword::LEVELNFCN, 0 },
+ { "levelnorestart", RTFControlType::VALUE, RTFKeyword::LEVELNORESTART, 0 },
+ { "levelnumbers", RTFControlType::DESTINATION, RTFKeyword::LEVELNUMBERS, 0 },
+ { "levelold", RTFControlType::VALUE, RTFKeyword::LEVELOLD, 0 },
+ { "levelpicture", RTFControlType::VALUE, RTFKeyword::LEVELPICTURE, 0 },
+ { "levelpicturenosize", RTFControlType::FLAG, RTFKeyword::LEVELPICTURENOSIZE, 0 },
+ { "levelprev", RTFControlType::VALUE, RTFKeyword::LEVELPREV, 0 },
+ { "levelprevspace", RTFControlType::VALUE, RTFKeyword::LEVELPREVSPACE, 0 },
+ { "levelspace", RTFControlType::VALUE, RTFKeyword::LEVELSPACE, 0 },
+ { "levelstartat", RTFControlType::VALUE, RTFKeyword::LEVELSTARTAT, 0 },
+ { "leveltemplateid", RTFControlType::VALUE, RTFKeyword::LEVELTEMPLATEID, 0 },
+ { "leveltext", RTFControlType::DESTINATION, RTFKeyword::LEVELTEXT, 0 },
+ { "lfolevel", RTFControlType::DESTINATION, RTFKeyword::LFOLEVEL, 0 },
+ { "li", RTFControlType::VALUE, RTFKeyword::LI, 0 },
+ { "line", RTFControlType::SYMBOL, RTFKeyword::LINE, 0 },
+ { "linebetcol", RTFControlType::FLAG, RTFKeyword::LINEBETCOL, 0 },
+ { "linecont", RTFControlType::FLAG, RTFKeyword::LINECONT, 0 },
+ { "linemod", RTFControlType::VALUE, RTFKeyword::LINEMOD, 1 },
+ { "lineppage", RTFControlType::FLAG, RTFKeyword::LINEPPAGE, 0 },
+ { "linerestart", RTFControlType::FLAG, RTFKeyword::LINERESTART, 0 },
+ { "linestart", RTFControlType::VALUE, RTFKeyword::LINESTART, 1 },
+ { "linestarts", RTFControlType::VALUE, RTFKeyword::LINESTARTS, 1 },
+ { "linex", RTFControlType::VALUE, RTFKeyword::LINEX, 360 },
+ { "linkself", RTFControlType::FLAG, RTFKeyword::LINKSELF, 0 },
+ { "linkstyles", RTFControlType::FLAG, RTFKeyword::LINKSTYLES, 0 },
+ { "linkval", RTFControlType::DESTINATION, RTFKeyword::LINKVAL, 0 },
+ { "lin", RTFControlType::VALUE, RTFKeyword::LIN, 0 },
+ { "lisa", RTFControlType::VALUE, RTFKeyword::LISA, 0 },
+ { "lisb", RTFControlType::VALUE, RTFKeyword::LISB, 0 },
+ { "list", RTFControlType::DESTINATION, RTFKeyword::LIST, 0 },
+ { "listhybrid", RTFControlType::FLAG, RTFKeyword::LISTHYBRID, 0 },
+ { "listid", RTFControlType::VALUE, RTFKeyword::LISTID, 0 },
+ { "listlevel", RTFControlType::DESTINATION, RTFKeyword::LISTLEVEL, 0 },
+ { "listname", RTFControlType::DESTINATION, RTFKeyword::LISTNAME, 0 },
+ { "listoverride", RTFControlType::DESTINATION, RTFKeyword::LISTOVERRIDE, 0 },
+ { "listoverridecount", RTFControlType::VALUE, RTFKeyword::LISTOVERRIDECOUNT, 0 },
+ { "listoverrideformat", RTFControlType::VALUE, RTFKeyword::LISTOVERRIDEFORMAT, 0 },
+ { "listoverridestartat", RTFControlType::FLAG, RTFKeyword::LISTOVERRIDESTARTAT, 0 },
+ { "listoverridetable", RTFControlType::DESTINATION, RTFKeyword::LISTOVERRIDETABLE, 0 },
+ { "listpicture", RTFControlType::DESTINATION, RTFKeyword::LISTPICTURE, 0 },
+ { "listrestarthdn", RTFControlType::VALUE, RTFKeyword::LISTRESTARTHDN, 0 },
+ { "listsimple", RTFControlType::VALUE, RTFKeyword::LISTSIMPLE, 0 },
+ { "liststyleid", RTFControlType::VALUE, RTFKeyword::LISTSTYLEID, 0 },
+ { "liststylename", RTFControlType::DESTINATION, RTFKeyword::LISTSTYLENAME, 0 },
+ { "listtable", RTFControlType::DESTINATION, RTFKeyword::LISTTABLE, 0 },
+ { "listtemplateid", RTFControlType::VALUE, RTFKeyword::LISTTEMPLATEID, 0 },
+ { "listtext", RTFControlType::DESTINATION, RTFKeyword::LISTTEXT, 0 },
+ { "lnbrkrule", RTFControlType::FLAG, RTFKeyword::LNBRKRULE, 0 },
+ { "lndscpsxn", RTFControlType::FLAG, RTFKeyword::LNDSCPSXN, 0 },
+ { "lnongrid", RTFControlType::FLAG, RTFKeyword::LNONGRID, 0 },
+ { "loch", RTFControlType::FLAG, RTFKeyword::LOCH, 0 },
+ { "lquote", RTFControlType::SYMBOL, RTFKeyword::LQUOTE, 0 },
+ { "ls", RTFControlType::VALUE, RTFKeyword::LS, 0 },
+ { "lsdlocked", RTFControlType::VALUE, RTFKeyword::LSDLOCKED, 0 },
+ { "lsdlockeddef", RTFControlType::VALUE, RTFKeyword::LSDLOCKEDDEF, 0 },
+ { "lsdlockedexcept", RTFControlType::DESTINATION, RTFKeyword::LSDLOCKEDEXCEPT, 0 },
+ { "lsdpriority", RTFControlType::VALUE, RTFKeyword::LSDPRIORITY, 0 },
+ { "lsdprioritydef", RTFControlType::VALUE, RTFKeyword::LSDPRIORITYDEF, 0 },
+ { "lsdqformat", RTFControlType::VALUE, RTFKeyword::LSDQFORMAT, 0 },
+ { "lsdqformatdef", RTFControlType::VALUE, RTFKeyword::LSDQFORMATDEF, 0 },
+ { "lsdsemihidden", RTFControlType::VALUE, RTFKeyword::LSDSEMIHIDDEN, 0 },
+ { "lsdsemihiddendef", RTFControlType::VALUE, RTFKeyword::LSDSEMIHIDDENDEF, 0 },
+ { "lsdstimax", RTFControlType::VALUE, RTFKeyword::LSDSTIMAX, 0 },
+ { "lsdunhideused", RTFControlType::VALUE, RTFKeyword::LSDUNHIDEUSED, 0 },
+ { "lsdunhideuseddef", RTFControlType::VALUE, RTFKeyword::LSDUNHIDEUSEDDEF, 0 },
+ { "ltrch", RTFControlType::FLAG, RTFKeyword::LTRCH, 0 },
+ { "ltrdoc", RTFControlType::FLAG, RTFKeyword::LTRDOC, 0 },
+ { "ltrmark", RTFControlType::SYMBOL, RTFKeyword::LTRMARK, 0 },
+ { "ltrpar", RTFControlType::FLAG, RTFKeyword::LTRPAR, 0 },
+ { "ltrrow", RTFControlType::FLAG, RTFKeyword::LTRROW, 0 },
+ { "ltrsect", RTFControlType::FLAG, RTFKeyword::LTRSECT, 0 },
+ { "lvltentative", RTFControlType::FLAG, RTFKeyword::LVLTENTATIVE, 0 },
+ { "lytcalctblwd", RTFControlType::FLAG, RTFKeyword::LYTCALCTBLWD, 0 },
+ { "lytexcttp", RTFControlType::FLAG, RTFKeyword::LYTEXCTTP, 0 },
+ { "lytprtmet", RTFControlType::FLAG, RTFKeyword::LYTPRTMET, 0 },
+ { "lyttblrtgr", RTFControlType::FLAG, RTFKeyword::LYTTBLRTGR, 0 },
+ { "mac", RTFControlType::FLAG, RTFKeyword::MAC, 0 },
+ { "macc", RTFControlType::DESTINATION, RTFKeyword::MACC, 0 },
+ { "maccPr", RTFControlType::DESTINATION, RTFKeyword::MACCPR, 0 },
+ { "macpict", RTFControlType::FLAG, RTFKeyword::MACPICT, 0 },
+ { "mailmerge", RTFControlType::DESTINATION, RTFKeyword::MAILMERGE, 0 },
+ { "makebackup", RTFControlType::FLAG, RTFKeyword::MAKEBACKUP, 0 },
+ { "maln", RTFControlType::DESTINATION, RTFKeyword::MALN, 0 },
+ { "malnScr", RTFControlType::DESTINATION, RTFKeyword::MALNSCR, 0 },
+ { "manager", RTFControlType::DESTINATION, RTFKeyword::MANAGER, 0 },
+ { "margb", RTFControlType::VALUE, RTFKeyword::MARGB, 1440 },
+ { "margbsxn", RTFControlType::VALUE, RTFKeyword::MARGBSXN, 0 },
+ { "margl", RTFControlType::VALUE, RTFKeyword::MARGL, 1800 },
+ { "marglsxn", RTFControlType::VALUE, RTFKeyword::MARGLSXN, 0 },
+ { "margmirror", RTFControlType::FLAG, RTFKeyword::MARGMIRROR, 0 },
+ { "margmirsxn", RTFControlType::FLAG, RTFKeyword::MARGMIRSXN, 0 },
+ { "margPr", RTFControlType::DESTINATION, RTFKeyword::MARGPR, 0 },
+ { "margr", RTFControlType::VALUE, RTFKeyword::MARGR, 1800 },
+ { "margrsxn", RTFControlType::VALUE, RTFKeyword::MARGRSXN, 0 },
+ { "margSz", RTFControlType::VALUE, RTFKeyword::MARGSZ, 0 },
+ { "margt", RTFControlType::VALUE, RTFKeyword::MARGT, 1440 },
+ { "margtsxn", RTFControlType::VALUE, RTFKeyword::MARGTSXN, 0 },
+ { "mbar", RTFControlType::DESTINATION, RTFKeyword::MBAR, 0 },
+ { "mbarPr", RTFControlType::DESTINATION, RTFKeyword::MBARPR, 0 },
+ { "mbaseJc", RTFControlType::DESTINATION, RTFKeyword::MBASEJC, 0 },
+ { "mbegChr", RTFControlType::DESTINATION, RTFKeyword::MBEGCHR, 0 },
+ { "mborderBox", RTFControlType::DESTINATION, RTFKeyword::MBORDERBOX, 0 },
+ { "mborderBoxPr", RTFControlType::DESTINATION, RTFKeyword::MBORDERBOXPR, 0 },
+ { "mbox", RTFControlType::DESTINATION, RTFKeyword::MBOX, 0 },
+ { "mboxPr", RTFControlType::DESTINATION, RTFKeyword::MBOXPR, 0 },
+ { "mbrk", RTFControlType::VALUE, RTFKeyword::MBRK, 0 },
+ { "mbrkBin", RTFControlType::VALUE, RTFKeyword::MBRKBIN, 0 },
+ { "mbrkBinSub", RTFControlType::VALUE, RTFKeyword::MBRKBINSUB, 0 },
+ { "mcGp", RTFControlType::VALUE, RTFKeyword::MCGP, 0 },
+ { "mcGpRule", RTFControlType::VALUE, RTFKeyword::MCGPRULE, 0 },
+ { "mchr", RTFControlType::DESTINATION, RTFKeyword::MCHR, 0 },
+ { "mcount", RTFControlType::DESTINATION, RTFKeyword::MCOUNT, 0 },
+ { "mcSp", RTFControlType::VALUE, RTFKeyword::MCSP, 0 },
+ { "mctrlPr", RTFControlType::DESTINATION, RTFKeyword::MCTRLPR, 0 },
+ { "md", RTFControlType::DESTINATION, RTFKeyword::MD, 0 },
+ { "mdefJc", RTFControlType::VALUE, RTFKeyword::MDEFJC, 0 },
+ { "mdeg", RTFControlType::DESTINATION, RTFKeyword::MDEG, 0 },
+ { "mdegHide", RTFControlType::DESTINATION, RTFKeyword::MDEGHIDE, 0 },
+ { "mden", RTFControlType::DESTINATION, RTFKeyword::MDEN, 0 },
+ { "mdiff", RTFControlType::DESTINATION, RTFKeyword::MDIFF, 0 },
+ { "mdiffSty", RTFControlType::VALUE, RTFKeyword::MDIFFSTY, 0 },
+ { "mdispdef", RTFControlType::VALUE, RTFKeyword::MDISPDEF, 1 },
+ { "mdPr", RTFControlType::DESTINATION, RTFKeyword::MDPR, 0 },
+ { "me", RTFControlType::DESTINATION, RTFKeyword::ME, 0 },
+ { "mendChr", RTFControlType::DESTINATION, RTFKeyword::MENDCHR, 0 },
+ { "meqArr", RTFControlType::DESTINATION, RTFKeyword::MEQARR, 0 },
+ { "meqArrPr", RTFControlType::DESTINATION, RTFKeyword::MEQARRPR, 0 },
+ { "mf", RTFControlType::DESTINATION, RTFKeyword::MF, 0 },
+ { "mfName", RTFControlType::DESTINATION, RTFKeyword::MFNAME, 0 },
+ { "mfPr", RTFControlType::DESTINATION, RTFKeyword::MFPR, 0 },
+ { "mfunc", RTFControlType::DESTINATION, RTFKeyword::MFUNC, 0 },
+ { "mfuncPr", RTFControlType::DESTINATION, RTFKeyword::MFUNCPR, 0 },
+ { "mgroupChr", RTFControlType::DESTINATION, RTFKeyword::MGROUPCHR, 0 },
+ { "mgroupChrPr", RTFControlType::DESTINATION, RTFKeyword::MGROUPCHRPR, 0 },
+ { "mgrow", RTFControlType::DESTINATION, RTFKeyword::MGROW, 0 },
+ { "mhideBot", RTFControlType::DESTINATION, RTFKeyword::MHIDEBOT, 0 },
+ { "mhideLeft", RTFControlType::DESTINATION, RTFKeyword::MHIDELEFT, 0 },
+ { "mhideRight", RTFControlType::DESTINATION, RTFKeyword::MHIDERIGHT, 0 },
+ { "mhideTop", RTFControlType::DESTINATION, RTFKeyword::MHIDETOP, 0 },
+ { "mhtmltag", RTFControlType::DESTINATION, RTFKeyword::MHTMLTAG, 0 },
+ { "min", RTFControlType::VALUE, RTFKeyword::MIN, 0 },
+ { "minterSp", RTFControlType::VALUE, RTFKeyword::MINTERSP, 0 },
+ { "mintLim", RTFControlType::VALUE, RTFKeyword::MINTLIM, 0 },
+ { "mintraSp", RTFControlType::VALUE, RTFKeyword::MINTRASP, 0 },
+ { "mjc", RTFControlType::VALUE, RTFKeyword::MJC, 0 },
+ { "mlim", RTFControlType::DESTINATION, RTFKeyword::MLIM, 0 },
+ { "mlimloc", RTFControlType::DESTINATION, RTFKeyword::MLIMLOC, 0 },
+ { "mlimLoc", RTFControlType::DESTINATION, RTFKeyword::MLIMLOC, 0 },
+ { "mlimlow", RTFControlType::DESTINATION, RTFKeyword::MLIMLOW, 0 },
+ { "mlimLow", RTFControlType::DESTINATION, RTFKeyword::MLIMLOW, 0 },
+ { "mlimlowPr", RTFControlType::DESTINATION, RTFKeyword::MLIMLOWPR, 0 },
+ { "mlimLowPr", RTFControlType::DESTINATION, RTFKeyword::MLIMLOWPR, 0 },
+ { "mlimupp", RTFControlType::DESTINATION, RTFKeyword::MLIMUPP, 0 },
+ { "mlimUpp", RTFControlType::DESTINATION, RTFKeyword::MLIMUPP, 0 },
+ { "mlimuppPr", RTFControlType::DESTINATION, RTFKeyword::MLIMUPPPR, 0 },
+ { "mlimUppPr", RTFControlType::DESTINATION, RTFKeyword::MLIMUPPPR, 0 },
+ { "mlit", RTFControlType::FLAG, RTFKeyword::MLIT, 0 },
+ { "mlMargin", RTFControlType::VALUE, RTFKeyword::MLMARGIN, 0 },
+ { "mm", RTFControlType::DESTINATION, RTFKeyword::MM, 0 },
+ { "mmaddfieldname", RTFControlType::DESTINATION, RTFKeyword::MMADDFIELDNAME, 0 },
+ { "mmath", RTFControlType::DESTINATION, RTFKeyword::MMATH, 0 },
+ { "mmathFont", RTFControlType::VALUE, RTFKeyword::MMATHFONT, 0 },
+ { "mmathPict", RTFControlType::DESTINATION, RTFKeyword::MMATHPICT, 0 },
+ { "mmathPr", RTFControlType::DESTINATION, RTFKeyword::MMATHPR, 0 },
+ { "mmattach", RTFControlType::FLAG, RTFKeyword::MMATTACH, 0 },
+ { "mmaxdist", RTFControlType::DESTINATION, RTFKeyword::MMAXDIST, 0 },
+ { "mmblanklines", RTFControlType::FLAG, RTFKeyword::MMBLANKLINES, 0 },
+ { "mmc", RTFControlType::DESTINATION, RTFKeyword::MMC, 0 },
+ { "mmcJc", RTFControlType::DESTINATION, RTFKeyword::MMCJC, 0 },
+ { "mmconnectstr", RTFControlType::DESTINATION, RTFKeyword::MMCONNECTSTR, 0 },
+ { "mmconnectstrdata", RTFControlType::DESTINATION, RTFKeyword::MMCONNECTSTRDATA, 0 },
+ { "mmcPr", RTFControlType::DESTINATION, RTFKeyword::MMCPR, 0 },
+ { "mmcs", RTFControlType::DESTINATION, RTFKeyword::MMCS, 0 },
+ { "mmdatasource", RTFControlType::DESTINATION, RTFKeyword::MMDATASOURCE, 0 },
+ { "mmdatatypeaccess", RTFControlType::FLAG, RTFKeyword::MMDATATYPEACCESS, 0 },
+ { "mmdatatypeexcel", RTFControlType::FLAG, RTFKeyword::MMDATATYPEEXCEL, 0 },
+ { "mmdatatypefile", RTFControlType::FLAG, RTFKeyword::MMDATATYPEFILE, 0 },
+ { "mmdatatypeodbc", RTFControlType::FLAG, RTFKeyword::MMDATATYPEODBC, 0 },
+ { "mmdatatypeodso", RTFControlType::FLAG, RTFKeyword::MMDATATYPEODSO, 0 },
+ { "mmdatatypeqt", RTFControlType::FLAG, RTFKeyword::MMDATATYPEQT, 0 },
+ { "mmdefaultsql", RTFControlType::FLAG, RTFKeyword::MMDEFAULTSQL, 0 },
+ { "mmdestemail", RTFControlType::FLAG, RTFKeyword::MMDESTEMAIL, 0 },
+ { "mmdestfax", RTFControlType::FLAG, RTFKeyword::MMDESTFAX, 0 },
+ { "mmdestnewdoc", RTFControlType::FLAG, RTFKeyword::MMDESTNEWDOC, 0 },
+ { "mmdestprinter", RTFControlType::FLAG, RTFKeyword::MMDESTPRINTER, 0 },
+ { "mmerrors", RTFControlType::VALUE, RTFKeyword::MMERRORS, 0 },
+ { "mmfttypeaddress", RTFControlType::FLAG, RTFKeyword::MMFTTYPEADDRESS, 0 },
+ { "mmfttypebarcode", RTFControlType::FLAG, RTFKeyword::MMFTTYPEBARCODE, 0 },
+ { "mmfttypedbcolumn", RTFControlType::FLAG, RTFKeyword::MMFTTYPEDBCOLUMN, 0 },
+ { "mmfttypemapped", RTFControlType::FLAG, RTFKeyword::MMFTTYPEMAPPED, 0 },
+ { "mmfttypenull", RTFControlType::FLAG, RTFKeyword::MMFTTYPENULL, 0 },
+ { "mmfttypesalutation", RTFControlType::FLAG, RTFKeyword::MMFTTYPESALUTATION, 0 },
+ { "mmheadersource", RTFControlType::DESTINATION, RTFKeyword::MMHEADERSOURCE, 0 },
+ { "mmjdsotype", RTFControlType::VALUE, RTFKeyword::MMJDSOTYPE, 0 },
+ { "mmlinktoquery", RTFControlType::FLAG, RTFKeyword::MMLINKTOQUERY, 0 },
+ { "mmmailsubject", RTFControlType::DESTINATION, RTFKeyword::MMMAILSUBJECT, 0 },
+ { "mmmaintypecatalog", RTFControlType::FLAG, RTFKeyword::MMMAINTYPECATALOG, 0 },
+ { "mmmaintypeemail", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEEMAIL, 0 },
+ { "mmmaintypeenvelopes", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEENVELOPES, 0 },
+ { "mmmaintypefax", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEFAX, 0 },
+ { "mmmaintypelabels", RTFControlType::FLAG, RTFKeyword::MMMAINTYPELABELS, 0 },
+ { "mmmaintypeletters", RTFControlType::FLAG, RTFKeyword::MMMAINTYPELETTERS, 0 },
+ { "mmodso", RTFControlType::DESTINATION, RTFKeyword::MMODSO, 0 },
+ { "mmodsoactive", RTFControlType::VALUE, RTFKeyword::MMODSOACTIVE, 0 },
+ { "mmodsocoldelim", RTFControlType::VALUE, RTFKeyword::MMODSOCOLDELIM, 0 },
+ { "mmodsocolumn", RTFControlType::VALUE, RTFKeyword::MMODSOCOLUMN, 0 },
+ { "mmodsodynaddr", RTFControlType::VALUE, RTFKeyword::MMODSODYNADDR, 0 },
+ { "mmodsofhdr", RTFControlType::VALUE, RTFKeyword::MMODSOFHDR, 0 },
+ { "mmodsofilter", RTFControlType::DESTINATION, RTFKeyword::MMODSOFILTER, 0 },
+ { "mmodsofldmpdata", RTFControlType::DESTINATION, RTFKeyword::MMODSOFLDMPDATA, 0 },
+ { "mmodsofmcolumn", RTFControlType::VALUE, RTFKeyword::MMODSOFMCOLUMN, 0 },
+ { "mmodsohash", RTFControlType::VALUE, RTFKeyword::MMODSOHASH, 0 },
+ { "mmodsolid", RTFControlType::VALUE, RTFKeyword::MMODSOLID, 0 },
+ { "mmodsomappedname", RTFControlType::DESTINATION, RTFKeyword::MMODSOMAPPEDNAME, 0 },
+ { "mmodsoname", RTFControlType::DESTINATION, RTFKeyword::MMODSONAME, 0 },
+ { "mmodsorecipdata", RTFControlType::DESTINATION, RTFKeyword::MMODSORECIPDATA, 0 },
+ { "mmodsosort", RTFControlType::DESTINATION, RTFKeyword::MMODSOSORT, 0 },
+ { "mmodsosrc", RTFControlType::DESTINATION, RTFKeyword::MMODSOSRC, 0 },
+ { "mmodsotable", RTFControlType::DESTINATION, RTFKeyword::MMODSOTABLE, 0 },
+ { "mmodsoudl", RTFControlType::DESTINATION, RTFKeyword::MMODSOUDL, 0 },
+ { "mmodsoudldata", RTFControlType::DESTINATION, RTFKeyword::MMODSOUDLDATA, 0 },
+ { "mmodsouniquetag", RTFControlType::DESTINATION, RTFKeyword::MMODSOUNIQUETAG, 0 },
+ { "mmPr", RTFControlType::DESTINATION, RTFKeyword::MMPR, 0 },
+ { "mmquery", RTFControlType::DESTINATION, RTFKeyword::MMQUERY, 0 },
+ { "mmr", RTFControlType::DESTINATION, RTFKeyword::MMR, 0 },
+ { "mmreccur", RTFControlType::VALUE, RTFKeyword::MMRECCUR, 0 },
+ { "mmshowdata", RTFControlType::FLAG, RTFKeyword::MMSHOWDATA, 0 },
+ { "mnary", RTFControlType::DESTINATION, RTFKeyword::MNARY, 0 },
+ { "mnaryLim", RTFControlType::VALUE, RTFKeyword::MNARYLIM, 0 },
+ { "mnaryPr", RTFControlType::DESTINATION, RTFKeyword::MNARYPR, 0 },
+ { "mnoBreak", RTFControlType::DESTINATION, RTFKeyword::MNOBREAK, 0 },
+ { "mnor", RTFControlType::FLAG, RTFKeyword::MNOR, 0 },
+ { "mnum", RTFControlType::DESTINATION, RTFKeyword::MNUM, 0 },
+ { "mo", RTFControlType::VALUE, RTFKeyword::MO, 0 },
+ { "mobjDist", RTFControlType::DESTINATION, RTFKeyword::MOBJDIST, 0 },
+ { "moMath", RTFControlType::DESTINATION, RTFKeyword::MOMATH, 0 },
+ { "moMathPara", RTFControlType::DESTINATION, RTFKeyword::MOMATHPARA, 0 },
+ { "moMathParaPr", RTFControlType::DESTINATION, RTFKeyword::MOMATHPARAPR, 0 },
+ { "mopEmu", RTFControlType::DESTINATION, RTFKeyword::MOPEMU, 0 },
+ { "mphant", RTFControlType::DESTINATION, RTFKeyword::MPHANT, 0 },
+ { "mphantPr", RTFControlType::DESTINATION, RTFKeyword::MPHANTPR, 0 },
+ { "mplcHide", RTFControlType::DESTINATION, RTFKeyword::MPLCHIDE, 0 },
+ { "mpos", RTFControlType::DESTINATION, RTFKeyword::MPOS, 0 },
+ { "mpostSp", RTFControlType::VALUE, RTFKeyword::MPOSTSP, 0 },
+ { "mpreSp", RTFControlType::VALUE, RTFKeyword::MPRESP, 0 },
+ { "mr", RTFControlType::DESTINATION, RTFKeyword::MR, 0 },
+ { "mrad", RTFControlType::DESTINATION, RTFKeyword::MRAD, 0 },
+ { "mradPr", RTFControlType::DESTINATION, RTFKeyword::MRADPR, 0 },
+ { "mrMargin", RTFControlType::VALUE, RTFKeyword::MRMARGIN, 0 },
+ { "mrPr", RTFControlType::DESTINATION, RTFKeyword::MRPR, 0 },
+ { "mrSp", RTFControlType::VALUE, RTFKeyword::MRSP, 0 },
+ { "mrSpRule", RTFControlType::VALUE, RTFKeyword::MRSPRULE, 0 },
+ { "mscr", RTFControlType::VALUE, RTFKeyword::MSCR, 0 },
+ { "msepChr", RTFControlType::DESTINATION, RTFKeyword::MSEPCHR, 0 },
+ { "mshow", RTFControlType::DESTINATION, RTFKeyword::MSHOW, 0 },
+ { "mshp", RTFControlType::DESTINATION, RTFKeyword::MSHP, 0 },
+ { "msmallFrac", RTFControlType::VALUE, RTFKeyword::MSMALLFRAC, 0 },
+ { "msmcap", RTFControlType::FLAG, RTFKeyword::MSMCAP, 0 },
+ { "msPre", RTFControlType::DESTINATION, RTFKeyword::MSPRE, 0 },
+ { "msPrePr", RTFControlType::DESTINATION, RTFKeyword::MSPREPR, 0 },
+ { "msSub", RTFControlType::DESTINATION, RTFKeyword::MSSUB, 0 },
+ { "msSubPr", RTFControlType::DESTINATION, RTFKeyword::MSSUBPR, 0 },
+ { "msSubSup", RTFControlType::DESTINATION, RTFKeyword::MSSUBSUP, 0 },
+ { "msSubSupPr", RTFControlType::DESTINATION, RTFKeyword::MSSUBSUPPR, 0 },
+ { "msSup", RTFControlType::DESTINATION, RTFKeyword::MSSUP, 0 },
+ { "msSupPr", RTFControlType::DESTINATION, RTFKeyword::MSSUPPR, 0 },
+ { "mstrikeBLTR", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEBLTR, 0 },
+ { "mstrikeH", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEH, 0 },
+ { "mstrikeTLBR", RTFControlType::DESTINATION, RTFKeyword::MSTRIKETLBR, 0 },
+ { "mstrikeV", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEV, 0 },
+ { "msty", RTFControlType::VALUE, RTFKeyword::MSTY, 0 },
+ { "msub", RTFControlType::DESTINATION, RTFKeyword::MSUB, 0 },
+ { "msubHide", RTFControlType::DESTINATION, RTFKeyword::MSUBHIDE, 0 },
+ { "msup", RTFControlType::DESTINATION, RTFKeyword::MSUP, 0 },
+ { "msupHide", RTFControlType::DESTINATION, RTFKeyword::MSUPHIDE, 0 },
+ { "mtransp", RTFControlType::DESTINATION, RTFKeyword::MTRANSP, 0 },
+ { "mtype", RTFControlType::DESTINATION, RTFKeyword::MTYPE, 0 },
+ { "muser", RTFControlType::FLAG, RTFKeyword::MUSER, 0 },
+ { "mvauth", RTFControlType::VALUE, RTFKeyword::MVAUTH, 0 },
+ { "mvdate", RTFControlType::VALUE, RTFKeyword::MVDATE, 0 },
+ { "mvertJc", RTFControlType::DESTINATION, RTFKeyword::MVERTJC, 0 },
+ { "mvf", RTFControlType::FLAG, RTFKeyword::MVF, 0 },
+ { "mvfmf", RTFControlType::DESTINATION, RTFKeyword::MVFMF, 0 },
+ { "mvfml", RTFControlType::DESTINATION, RTFKeyword::MVFML, 0 },
+ { "mvt", RTFControlType::FLAG, RTFKeyword::MVT, 0 },
+ { "mvtof", RTFControlType::DESTINATION, RTFKeyword::MVTOF, 0 },
+ { "mvtol", RTFControlType::DESTINATION, RTFKeyword::MVTOL, 0 },
+ { "mwrapIndent", RTFControlType::VALUE, RTFKeyword::MWRAPINDENT, 1440 },
+ { "mwrapRight", RTFControlType::VALUE, RTFKeyword::MWRAPRIGHT, 0 },
+ { "mzeroAsc", RTFControlType::DESTINATION, RTFKeyword::MZEROASC, 0 },
+ { "mzeroDesc", RTFControlType::DESTINATION, RTFKeyword::MZERODESC, 0 },
+ { "mzeroWid", RTFControlType::DESTINATION, RTFKeyword::MZEROWID, 0 },
+ { "nestcell", RTFControlType::SYMBOL, RTFKeyword::NESTCELL, 0 },
+ { "nestrow", RTFControlType::SYMBOL, RTFKeyword::NESTROW, 0 },
+ { "nesttableprops", RTFControlType::DESTINATION, RTFKeyword::NESTTABLEPROPS, 0 },
+ { "newtblstyruls", RTFControlType::FLAG, RTFKeyword::NEWTBLSTYRULS, 0 },
+ { "nextfile", RTFControlType::DESTINATION, RTFKeyword::NEXTFILE, 0 },
+ { "noafcnsttbl", RTFControlType::FLAG, RTFKeyword::NOAFCNSTTBL, 0 },
+ { "nobrkwrptbl", RTFControlType::FLAG, RTFKeyword::NOBRKWRPTBL, 0 },
+ { "nocolbal", RTFControlType::FLAG, RTFKeyword::NOCOLBAL, 0 },
+ { "nocompatoptions", RTFControlType::FLAG, RTFKeyword::NOCOMPATOPTIONS, 0 },
+ { "nocwrap", RTFControlType::FLAG, RTFKeyword::NOCWRAP, 0 },
+ { "nocxsptable", RTFControlType::FLAG, RTFKeyword::NOCXSPTABLE, 0 },
+ { "noextrasprl", RTFControlType::FLAG, RTFKeyword::NOEXTRASPRL, 0 },
+ { "nofchars", RTFControlType::VALUE, RTFKeyword::NOFCHARS, 0 },
+ { "nofcharsws", RTFControlType::VALUE, RTFKeyword::NOFCHARSWS, 0 },
+ { "nofeaturethrottle", RTFControlType::FLAG, RTFKeyword::NOFEATURETHROTTLE, 0 },
+ { "nofpages", RTFControlType::VALUE, RTFKeyword::NOFPAGES, 0 },
+ { "nofwords", RTFControlType::VALUE, RTFKeyword::NOFWORDS, 0 },
+ { "nogrowautofit", RTFControlType::FLAG, RTFKeyword::NOGROWAUTOFIT, 0 },
+ { "noindnmbrts", RTFControlType::FLAG, RTFKeyword::NOINDNMBRTS, 0 },
+ { "nojkernpunct", RTFControlType::FLAG, RTFKeyword::NOJKERNPUNCT, 0 },
+ { "nolead", RTFControlType::FLAG, RTFKeyword::NOLEAD, 0 },
+ { "noline", RTFControlType::FLAG, RTFKeyword::NOLINE, 0 },
+ { "nolnhtadjtbl", RTFControlType::FLAG, RTFKeyword::NOLNHTADJTBL, 0 },
+ { "nonesttables", RTFControlType::DESTINATION, RTFKeyword::NONESTTABLES, 0 },
+ { "nonshppict", RTFControlType::FLAG, RTFKeyword::NONSHPPICT, 0 },
+ { "nooverflow", RTFControlType::FLAG, RTFKeyword::NOOVERFLOW, 0 },
+ { "noproof", RTFControlType::FLAG, RTFKeyword::NOPROOF, 0 },
+ { "noqfpromote", RTFControlType::FLAG, RTFKeyword::NOQFPROMOTE, 0 },
+ { "nosectexpand", RTFControlType::FLAG, RTFKeyword::NOSECTEXPAND, 0 },
+ { "nosnaplinegrid", RTFControlType::FLAG, RTFKeyword::NOSNAPLINEGRID, 0 },
+ { "nospaceforul", RTFControlType::FLAG, RTFKeyword::NOSPACEFORUL, 0 },
+ { "nosupersub", RTFControlType::FLAG, RTFKeyword::NOSUPERSUB, 0 },
+ { "notabind", RTFControlType::FLAG, RTFKeyword::NOTABIND, 0 },
+ { "notbrkcnstfrctbl", RTFControlType::FLAG, RTFKeyword::NOTBRKCNSTFRCTBL, 0 },
+ { "notcvasp", RTFControlType::FLAG, RTFKeyword::NOTCVASP, 0 },
+ { "notvatxbx", RTFControlType::FLAG, RTFKeyword::NOTVATXBX, 0 },
+ { "nouicompat", RTFControlType::FLAG, RTFKeyword::NOUICOMPAT, 0 },
+ { "noultrlspc", RTFControlType::FLAG, RTFKeyword::NOULTRLSPC, 0 },
+ { "nowidctlpar", RTFControlType::FLAG, RTFKeyword::NOWIDCTLPAR, 0 },
+ { "nowrap", RTFControlType::FLAG, RTFKeyword::NOWRAP, 0 },
+ { "nowwrap", RTFControlType::FLAG, RTFKeyword::NOWWRAP, 0 },
+ { "noxlattoyen", RTFControlType::FLAG, RTFKeyword::NOXLATTOYEN, 0 },
+ { "objalias", RTFControlType::DESTINATION, RTFKeyword::OBJALIAS, 0 },
+ { "objalign", RTFControlType::VALUE, RTFKeyword::OBJALIGN, 0 },
+ { "objattph", RTFControlType::FLAG, RTFKeyword::OBJATTPH, 0 },
+ { "objautlink", RTFControlType::FLAG, RTFKeyword::OBJAUTLINK, 0 },
+ { "objclass", RTFControlType::DESTINATION, RTFKeyword::OBJCLASS, 0 },
+ { "objcropb", RTFControlType::VALUE, RTFKeyword::OBJCROPB, 0 },
+ { "objcropl", RTFControlType::VALUE, RTFKeyword::OBJCROPL, 0 },
+ { "objcropr", RTFControlType::VALUE, RTFKeyword::OBJCROPR, 0 },
+ { "objcropt", RTFControlType::VALUE, RTFKeyword::OBJCROPT, 0 },
+ { "objdata", RTFControlType::DESTINATION, RTFKeyword::OBJDATA, 0 },
+ { "object", RTFControlType::DESTINATION, RTFKeyword::OBJECT, 0 },
+ { "objemb", RTFControlType::FLAG, RTFKeyword::OBJEMB, 0 },
+ { "objh", RTFControlType::VALUE, RTFKeyword::OBJH, 0 },
+ { "objhtml", RTFControlType::FLAG, RTFKeyword::OBJHTML, 0 },
+ { "objicemb", RTFControlType::FLAG, RTFKeyword::OBJICEMB, 0 },
+ { "objlink", RTFControlType::FLAG, RTFKeyword::OBJLINK, 0 },
+ { "objlock", RTFControlType::FLAG, RTFKeyword::OBJLOCK, 0 },
+ { "objname", RTFControlType::DESTINATION, RTFKeyword::OBJNAME, 0 },
+ { "objocx", RTFControlType::FLAG, RTFKeyword::OBJOCX, 0 },
+ { "objpub", RTFControlType::FLAG, RTFKeyword::OBJPUB, 0 },
+ { "objscalex", RTFControlType::VALUE, RTFKeyword::OBJSCALEX, 0 },
+ { "objscaley", RTFControlType::VALUE, RTFKeyword::OBJSCALEY, 0 },
+ { "objsect", RTFControlType::DESTINATION, RTFKeyword::OBJSECT, 0 },
+ { "objsetsize", RTFControlType::FLAG, RTFKeyword::OBJSETSIZE, 0 },
+ { "objsub", RTFControlType::FLAG, RTFKeyword::OBJSUB, 0 },
+ { "objtime", RTFControlType::DESTINATION, RTFKeyword::OBJTIME, 0 },
+ { "objtransy", RTFControlType::VALUE, RTFKeyword::OBJTRANSY, 0 },
+ { "objupdate", RTFControlType::FLAG, RTFKeyword::OBJUPDATE, 0 },
+ { "objw", RTFControlType::VALUE, RTFKeyword::OBJW, 0 },
+ { "ogutter", RTFControlType::VALUE, RTFKeyword::OGUTTER, 0 },
+ { "oldas", RTFControlType::FLAG, RTFKeyword::OLDAS, 0 },
+ { "oldcprops", RTFControlType::DESTINATION, RTFKeyword::OLDCPROPS, 0 },
+ { "oldlinewrap", RTFControlType::FLAG, RTFKeyword::OLDLINEWRAP, 0 },
+ { "oldpprops", RTFControlType::DESTINATION, RTFKeyword::OLDPPROPS, 0 },
+ { "oldsprops", RTFControlType::DESTINATION, RTFKeyword::OLDSPROPS, 0 },
+ { "oldtprops", RTFControlType::DESTINATION, RTFKeyword::OLDTPROPS, 0 },
+ { "oleclsid", RTFControlType::DESTINATION, RTFKeyword::OLECLSID, 0 },
+ { "operator", RTFControlType::DESTINATION, RTFKeyword::OPERATOR, 0 },
+ { "otblrul", RTFControlType::FLAG, RTFKeyword::OTBLRUL, 0 },
+ { "outl", RTFControlType::TOGGLE, RTFKeyword::OUTL, 1 },
+ { "outlinelevel", RTFControlType::VALUE, RTFKeyword::OUTLINELEVEL, 0 },
+ { "overlay", RTFControlType::FLAG, RTFKeyword::OVERLAY, 0 },
+ { "page", RTFControlType::SYMBOL, RTFKeyword::PAGE, 0 },
+ { "pagebb", RTFControlType::FLAG, RTFKeyword::PAGEBB, 0 },
+ { "panose", RTFControlType::DESTINATION, RTFKeyword::PANOSE, 0 },
+ { "paperh", RTFControlType::VALUE, RTFKeyword::PAPERH, 15840 },
+ { "paperw", RTFControlType::VALUE, RTFKeyword::PAPERW, 12240 },
+ { "par", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "pararsid", RTFControlType::VALUE, RTFKeyword::PARARSID, 0 },
+ { "pard", RTFControlType::FLAG, RTFKeyword::PARD, 0 },
+ { "password", RTFControlType::DESTINATION, RTFKeyword::PASSWORD, 0 },
+ { "passwordhash", RTFControlType::DESTINATION, RTFKeyword::PASSWORDHASH, 0 },
+ { "pc", RTFControlType::FLAG, RTFKeyword::PC, 0 },
+ { "pca", RTFControlType::FLAG, RTFKeyword::PCA, 0 },
+ { "pgbrdrb", RTFControlType::FLAG, RTFKeyword::PGBRDRB, 0 },
+ { "pgbrdrfoot", RTFControlType::FLAG, RTFKeyword::PGBRDRFOOT, 0 },
+ { "pgbrdrhead", RTFControlType::FLAG, RTFKeyword::PGBRDRHEAD, 0 },
+ { "pgbrdrl", RTFControlType::FLAG, RTFKeyword::PGBRDRL, 0 },
+ { "pgbrdropt", RTFControlType::VALUE, RTFKeyword::PGBRDROPT, 0 },
+ { "pgbrdrr", RTFControlType::FLAG, RTFKeyword::PGBRDRR, 0 },
+ { "pgbrdrsnap", RTFControlType::FLAG, RTFKeyword::PGBRDRSNAP, 0 },
+ { "pgbrdrt", RTFControlType::FLAG, RTFKeyword::PGBRDRT, 0 },
+ { "pghsxn", RTFControlType::VALUE, RTFKeyword::PGHSXN, 0 },
+ { "pgnbidia", RTFControlType::FLAG, RTFKeyword::PGNBIDIA, 0 },
+ { "pgnbidib", RTFControlType::FLAG, RTFKeyword::PGNBIDIB, 0 },
+ { "pgnchosung", RTFControlType::FLAG, RTFKeyword::PGNCHOSUNG, 0 },
+ { "pgncnum", RTFControlType::FLAG, RTFKeyword::PGNCNUM, 0 },
+ { "pgncont", RTFControlType::FLAG, RTFKeyword::PGNCONT, 0 },
+ { "pgndbnum", RTFControlType::FLAG, RTFKeyword::PGNDBNUM, 0 },
+ { "pgndbnumd", RTFControlType::FLAG, RTFKeyword::PGNDBNUMD, 0 },
+ { "pgndbnumk", RTFControlType::FLAG, RTFKeyword::PGNDBNUMK, 0 },
+ { "pgndbnumt", RTFControlType::FLAG, RTFKeyword::PGNDBNUMT, 0 },
+ { "pgndec", RTFControlType::FLAG, RTFKeyword::PGNDEC, 0 },
+ { "pgndecd", RTFControlType::FLAG, RTFKeyword::PGNDECD, 0 },
+ { "pgnganada", RTFControlType::FLAG, RTFKeyword::PGNGANADA, 0 },
+ { "pgngbnum", RTFControlType::FLAG, RTFKeyword::PGNGBNUM, 0 },
+ { "pgngbnumd", RTFControlType::FLAG, RTFKeyword::PGNGBNUMD, 0 },
+ { "pgngbnumk", RTFControlType::FLAG, RTFKeyword::PGNGBNUMK, 0 },
+ { "pgngbnuml", RTFControlType::FLAG, RTFKeyword::PGNGBNUML, 0 },
+ { "pgnhindia", RTFControlType::FLAG, RTFKeyword::PGNHINDIA, 0 },
+ { "pgnhindib", RTFControlType::FLAG, RTFKeyword::PGNHINDIB, 0 },
+ { "pgnhindic", RTFControlType::FLAG, RTFKeyword::PGNHINDIC, 0 },
+ { "pgnhindid", RTFControlType::FLAG, RTFKeyword::PGNHINDID, 0 },
+ { "pgnhn", RTFControlType::VALUE, RTFKeyword::PGNHN, 0 },
+ { "pgnhnsc", RTFControlType::FLAG, RTFKeyword::PGNHNSC, 0 },
+ { "pgnhnsh", RTFControlType::FLAG, RTFKeyword::PGNHNSH, 0 },
+ { "pgnhnsm", RTFControlType::FLAG, RTFKeyword::PGNHNSM, 0 },
+ { "pgnhnsn", RTFControlType::FLAG, RTFKeyword::PGNHNSN, 0 },
+ { "pgnhnsp", RTFControlType::FLAG, RTFKeyword::PGNHNSP, 0 },
+ { "pgnid", RTFControlType::FLAG, RTFKeyword::PGNID, 0 },
+ { "pgnlcltr", RTFControlType::FLAG, RTFKeyword::PGNLCLTR, 0 },
+ { "pgnlcrm", RTFControlType::FLAG, RTFKeyword::PGNLCRM, 0 },
+ { "pgnrestart", RTFControlType::FLAG, RTFKeyword::PGNRESTART, 0 },
+ { "pgnstart", RTFControlType::VALUE, RTFKeyword::PGNSTART, 1 },
+ { "pgnstarts", RTFControlType::VALUE, RTFKeyword::PGNSTARTS, 1 },
+ { "pgnthaia", RTFControlType::FLAG, RTFKeyword::PGNTHAIA, 0 },
+ { "pgnthaib", RTFControlType::FLAG, RTFKeyword::PGNTHAIB, 0 },
+ { "pgnthaic", RTFControlType::FLAG, RTFKeyword::PGNTHAIC, 0 },
+ { "pgnucltr", RTFControlType::FLAG, RTFKeyword::PGNUCLTR, 0 },
+ { "pgnucrm", RTFControlType::FLAG, RTFKeyword::PGNUCRM, 0 },
+ { "pgnvieta", RTFControlType::FLAG, RTFKeyword::PGNVIETA, 0 },
+ { "pgnx", RTFControlType::VALUE, RTFKeyword::PGNX, 720 },
+ { "pgny", RTFControlType::VALUE, RTFKeyword::PGNY, 720 },
+ { "pgnzodiac", RTFControlType::FLAG, RTFKeyword::PGNZODIAC, 0 },
+ { "pgnzodiacd", RTFControlType::FLAG, RTFKeyword::PGNZODIACD, 0 },
+ { "pgnzodiacl", RTFControlType::FLAG, RTFKeyword::PGNZODIACL, 0 },
+ { "pgp", RTFControlType::DESTINATION, RTFKeyword::PGP, 0 },
+ { "pgptbl", RTFControlType::DESTINATION, RTFKeyword::PGPTBL, 0 },
+ { "pgwsxn", RTFControlType::VALUE, RTFKeyword::PGWSXN, 0 },
+ { "phcol", RTFControlType::FLAG, RTFKeyword::PHCOL, 0 },
+ { "phmrg", RTFControlType::FLAG, RTFKeyword::PHMRG, 0 },
+ { "phpg", RTFControlType::FLAG, RTFKeyword::PHPG, 0 },
+ { "picbmp", RTFControlType::FLAG, RTFKeyword::PICBMP, 0 },
+ { "picbpp", RTFControlType::VALUE, RTFKeyword::PICBPP, 0 },
+ { "piccropb", RTFControlType::VALUE, RTFKeyword::PICCROPB, 0 },
+ { "piccropl", RTFControlType::VALUE, RTFKeyword::PICCROPL, 0 },
+ { "piccropr", RTFControlType::VALUE, RTFKeyword::PICCROPR, 0 },
+ { "piccropt", RTFControlType::VALUE, RTFKeyword::PICCROPT, 0 },
+ { "pich", RTFControlType::VALUE, RTFKeyword::PICH, 0 },
+ { "pichgoal", RTFControlType::VALUE, RTFKeyword::PICHGOAL, 0 },
+ { "pichGoal", RTFControlType::VALUE, RTFKeyword::PICHGOAL, 0 },
+ { "picprop", RTFControlType::DESTINATION, RTFKeyword::PICPROP, 0 },
+ { "picscaled", RTFControlType::FLAG, RTFKeyword::PICSCALED, 0 },
+ { "picscalex", RTFControlType::VALUE, RTFKeyword::PICSCALEX, 100 },
+ { "picscaley", RTFControlType::VALUE, RTFKeyword::PICSCALEY, 100 },
+ { "pict", RTFControlType::DESTINATION, RTFKeyword::PICT, 0 },
+ { "picw", RTFControlType::VALUE, RTFKeyword::PICW, 0 },
+ { "picwgoal", RTFControlType::VALUE, RTFKeyword::PICWGOAL, 0 },
+ { "picwGoal", RTFControlType::VALUE, RTFKeyword::PICWGOAL, 0 },
+ { "pindtabqc", RTFControlType::FLAG, RTFKeyword::PINDTABQC, 0 },
+ { "pindtabql", RTFControlType::FLAG, RTFKeyword::PINDTABQL, 0 },
+ { "pindtabqr", RTFControlType::FLAG, RTFKeyword::PINDTABQR, 0 },
+ { "plain", RTFControlType::FLAG, RTFKeyword::PLAIN, 0 },
+ { "pmartabqc", RTFControlType::FLAG, RTFKeyword::PMARTABQC, 0 },
+ { "pmartabql", RTFControlType::FLAG, RTFKeyword::PMARTABQL, 0 },
+ { "pmartabqr", RTFControlType::FLAG, RTFKeyword::PMARTABQR, 0 },
+ { "pmmetafile", RTFControlType::VALUE, RTFKeyword::PMMETAFILE, 0 },
+ { "pn", RTFControlType::DESTINATION, RTFKeyword::PN, 0 },
+ { "pnacross", RTFControlType::FLAG, RTFKeyword::PNACROSS, 0 },
+ { "pnaiu", RTFControlType::FLAG, RTFKeyword::PNAIU, 0 },
+ { "pnaiud", RTFControlType::FLAG, RTFKeyword::PNAIUD, 0 },
+ { "pnaiueo", RTFControlType::FLAG, RTFKeyword::PNAIUEO, 0 },
+ { "pnaiueod", RTFControlType::FLAG, RTFKeyword::PNAIUEOD, 0 },
+ { "pnb", RTFControlType::TOGGLE, RTFKeyword::PNB, 1 },
+ { "pnbidia", RTFControlType::FLAG, RTFKeyword::PNBIDIA, 0 },
+ { "pnbidib", RTFControlType::FLAG, RTFKeyword::PNBIDIB, 0 },
+ { "pncaps", RTFControlType::TOGGLE, RTFKeyword::PNCAPS, 1 },
+ { "pncard", RTFControlType::FLAG, RTFKeyword::PNCARD, 0 },
+ { "pncf", RTFControlType::VALUE, RTFKeyword::PNCF, 0 },
+ { "pnchosung", RTFControlType::FLAG, RTFKeyword::PNCHOSUNG, 0 },
+ { "pncnum", RTFControlType::FLAG, RTFKeyword::PNCNUM, 0 },
+ { "pndbnum", RTFControlType::FLAG, RTFKeyword::PNDBNUM, 0 },
+ { "pndbnumd", RTFControlType::FLAG, RTFKeyword::PNDBNUMD, 0 },
+ { "pndbnumk", RTFControlType::FLAG, RTFKeyword::PNDBNUMK, 0 },
+ { "pndbnuml", RTFControlType::FLAG, RTFKeyword::PNDBNUML, 0 },
+ { "pndbnumt", RTFControlType::FLAG, RTFKeyword::PNDBNUMT, 0 },
+ { "pndec", RTFControlType::FLAG, RTFKeyword::PNDEC, 0 },
+ { "pndecd", RTFControlType::FLAG, RTFKeyword::PNDECD, 0 },
+ { "pnf", RTFControlType::VALUE, RTFKeyword::PNF, 0 },
+ { "pnfs", RTFControlType::VALUE, RTFKeyword::PNFS, 0 },
+ { "pnganada", RTFControlType::FLAG, RTFKeyword::PNGANADA, 0 },
+ { "pngblip", RTFControlType::FLAG, RTFKeyword::PNGBLIP, 0 },
+ { "pngbnum", RTFControlType::FLAG, RTFKeyword::PNGBNUM, 0 },
+ { "pngbnumd", RTFControlType::FLAG, RTFKeyword::PNGBNUMD, 0 },
+ { "pngbnumk", RTFControlType::FLAG, RTFKeyword::PNGBNUMK, 0 },
+ { "pngbnuml", RTFControlType::FLAG, RTFKeyword::PNGBNUML, 0 },
+ { "pnhang", RTFControlType::FLAG, RTFKeyword::PNHANG, 0 },
+ { "pni", RTFControlType::TOGGLE, RTFKeyword::PNI, 1 },
+ { "pnindent", RTFControlType::VALUE, RTFKeyword::PNINDENT, 0 },
+ { "pniroha", RTFControlType::FLAG, RTFKeyword::PNIROHA, 0 },
+ { "pnirohad", RTFControlType::FLAG, RTFKeyword::PNIROHAD, 0 },
+ { "pnlcltr", RTFControlType::FLAG, RTFKeyword::PNLCLTR, 0 },
+ { "pnlcrm", RTFControlType::FLAG, RTFKeyword::PNLCRM, 0 },
+ { "pnlvl", RTFControlType::VALUE, RTFKeyword::PNLVL, 0 },
+ { "pnlvlblt", RTFControlType::FLAG, RTFKeyword::PNLVLBLT, 0 },
+ { "pnlvlbody", RTFControlType::FLAG, RTFKeyword::PNLVLBODY, 0 },
+ { "pnlvlcont", RTFControlType::FLAG, RTFKeyword::PNLVLCONT, 0 },
+ { "pnnumonce", RTFControlType::FLAG, RTFKeyword::PNNUMONCE, 0 },
+ { "pnord", RTFControlType::FLAG, RTFKeyword::PNORD, 0 },
+ { "pnordt", RTFControlType::FLAG, RTFKeyword::PNORDT, 0 },
+ { "pnprev", RTFControlType::FLAG, RTFKeyword::PNPREV, 0 },
+ { "pnqc", RTFControlType::FLAG, RTFKeyword::PNQC, 0 },
+ { "pnql", RTFControlType::FLAG, RTFKeyword::PNQL, 0 },
+ { "pnqr", RTFControlType::FLAG, RTFKeyword::PNQR, 0 },
+ { "pnrauth", RTFControlType::VALUE, RTFKeyword::PNRAUTH, 0 },
+ { "pnrdate", RTFControlType::VALUE, RTFKeyword::PNRDATE, 0 },
+ { "pnrestart", RTFControlType::FLAG, RTFKeyword::PNRESTART, 0 },
+ { "pnrnfc", RTFControlType::VALUE, RTFKeyword::PNRNFC, 0 },
+ { "pnrnot", RTFControlType::FLAG, RTFKeyword::PNRNOT, 0 },
+ { "pnrpnbr", RTFControlType::VALUE, RTFKeyword::PNRPNBR, 0 },
+ { "pnrrgb", RTFControlType::VALUE, RTFKeyword::PNRRGB, 0 },
+ { "pnrstart", RTFControlType::VALUE, RTFKeyword::PNRSTART, 0 },
+ { "pnrstop", RTFControlType::VALUE, RTFKeyword::PNRSTOP, 0 },
+ { "pnrxst", RTFControlType::VALUE, RTFKeyword::PNRXST, 0 },
+ { "pnscaps", RTFControlType::TOGGLE, RTFKeyword::PNSCAPS, 1 },
+ { "pnseclvl", RTFControlType::DESTINATION, RTFKeyword::PNSECLVL, 0 },
+ { "pnsp", RTFControlType::VALUE, RTFKeyword::PNSP, 0 },
+ { "pnstart", RTFControlType::VALUE, RTFKeyword::PNSTART, 0 },
+ { "pnstrike", RTFControlType::TOGGLE, RTFKeyword::PNSTRIKE, 1 },
+ { "pntext", RTFControlType::DESTINATION, RTFKeyword::PNTEXT, 0 },
+ { "pntxta", RTFControlType::DESTINATION, RTFKeyword::PNTXTA, 0 },
+ { "pntxtb", RTFControlType::DESTINATION, RTFKeyword::PNTXTB, 0 },
+ { "pnucltr", RTFControlType::FLAG, RTFKeyword::PNUCLTR, 0 },
+ { "pnucrm", RTFControlType::FLAG, RTFKeyword::PNUCRM, 0 },
+ { "pnul", RTFControlType::TOGGLE, RTFKeyword::PNUL, 1 },
+ { "pnuld", RTFControlType::FLAG, RTFKeyword::PNULD, 0 },
+ { "pnuldash", RTFControlType::FLAG, RTFKeyword::PNULDASH, 0 },
+ { "pnuldashd", RTFControlType::FLAG, RTFKeyword::PNULDASHD, 0 },
+ { "pnuldashdd", RTFControlType::FLAG, RTFKeyword::PNULDASHDD, 0 },
+ { "pnuldb", RTFControlType::FLAG, RTFKeyword::PNULDB, 0 },
+ { "pnulhair", RTFControlType::FLAG, RTFKeyword::PNULHAIR, 0 },
+ { "pnulnone", RTFControlType::FLAG, RTFKeyword::PNULNONE, 0 },
+ { "pnulth", RTFControlType::FLAG, RTFKeyword::PNULTH, 0 },
+ { "pnulw", RTFControlType::FLAG, RTFKeyword::PNULW, 0 },
+ { "pnulwave", RTFControlType::FLAG, RTFKeyword::PNULWAVE, 0 },
+ { "pnzodiac", RTFControlType::FLAG, RTFKeyword::PNZODIAC, 0 },
+ { "pnzodiacd", RTFControlType::FLAG, RTFKeyword::PNZODIACD, 0 },
+ { "pnzodiacl", RTFControlType::FLAG, RTFKeyword::PNZODIACL, 0 },
+ { "posnegx", RTFControlType::VALUE, RTFKeyword::POSNEGX, 0 },
+ { "posnegy", RTFControlType::VALUE, RTFKeyword::POSNEGY, 0 },
+ { "posx", RTFControlType::VALUE, RTFKeyword::POSX, 0 },
+ { "posxc", RTFControlType::FLAG, RTFKeyword::POSXC, 0 },
+ { "posxi", RTFControlType::FLAG, RTFKeyword::POSXI, 0 },
+ { "posxl", RTFControlType::FLAG, RTFKeyword::POSXL, 0 },
+ { "posxo", RTFControlType::FLAG, RTFKeyword::POSXO, 0 },
+ { "posxr", RTFControlType::FLAG, RTFKeyword::POSXR, 0 },
+ { "posy", RTFControlType::VALUE, RTFKeyword::POSY, 0 },
+ { "posyb", RTFControlType::FLAG, RTFKeyword::POSYB, 0 },
+ { "posyc", RTFControlType::FLAG, RTFKeyword::POSYC, 0 },
+ { "posyil", RTFControlType::FLAG, RTFKeyword::POSYIL, 0 },
+ { "posyin", RTFControlType::FLAG, RTFKeyword::POSYIN, 0 },
+ { "posyout", RTFControlType::FLAG, RTFKeyword::POSYOUT, 0 },
+ { "posyt", RTFControlType::FLAG, RTFKeyword::POSYT, 0 },
+ { "prauth", RTFControlType::VALUE, RTFKeyword::PRAUTH, 0 },
+ { "prcolbl", RTFControlType::FLAG, RTFKeyword::PRCOLBL, 0 },
+ { "prdate", RTFControlType::VALUE, RTFKeyword::PRDATE, 0 },
+ { "printdata", RTFControlType::FLAG, RTFKeyword::PRINTDATA, 0 },
+ { "printim", RTFControlType::DESTINATION, RTFKeyword::PRINTIM, 0 },
+ { "private", RTFControlType::DESTINATION, RTFKeyword::PRIVATE, 0 },
+ { "propname", RTFControlType::DESTINATION, RTFKeyword::PROPNAME, 0 },
+ { "proptype", RTFControlType::VALUE, RTFKeyword::PROPTYPE, 0 },
+ { "protect", RTFControlType::TOGGLE, RTFKeyword::PROTECT, 1 },
+ { "protend", RTFControlType::DESTINATION, RTFKeyword::PROTEND, 0 },
+ { "protlevel", RTFControlType::VALUE, RTFKeyword::PROTLEVEL, 0 },
+ { "protstart", RTFControlType::DESTINATION, RTFKeyword::PROTSTART, 0 },
+ { "protusertbl", RTFControlType::DESTINATION, RTFKeyword::PROTUSERTBL, 0 },
+ { "psover", RTFControlType::FLAG, RTFKeyword::PSOVER, 0 },
+ { "psz", RTFControlType::VALUE, RTFKeyword::PSZ, 0 },
+ { "ptabldot", RTFControlType::FLAG, RTFKeyword::PTABLDOT, 0 },
+ { "ptablmdot", RTFControlType::FLAG, RTFKeyword::PTABLMDOT, 0 },
+ { "ptablminus", RTFControlType::FLAG, RTFKeyword::PTABLMINUS, 0 },
+ { "ptablnone", RTFControlType::FLAG, RTFKeyword::PTABLNONE, 0 },
+ { "ptabluscore", RTFControlType::FLAG, RTFKeyword::PTABLUSCORE, 0 },
+ { "pubauto", RTFControlType::FLAG, RTFKeyword::PUBAUTO, 0 },
+ { "pvmrg", RTFControlType::FLAG, RTFKeyword::PVMRG, 0 },
+ { "pvpara", RTFControlType::FLAG, RTFKeyword::PVPARA, 0 },
+ { "pvpg", RTFControlType::FLAG, RTFKeyword::PVPG, 0 },
+ { "pwd", RTFControlType::VALUE, RTFKeyword::PWD, 0 },
+ { "pxe", RTFControlType::DESTINATION, RTFKeyword::PXE, 0 },
+ { "qc", RTFControlType::FLAG, RTFKeyword::QC, 0 },
+ { "qd", RTFControlType::FLAG, RTFKeyword::QD, 0 },
+ { "qj", RTFControlType::FLAG, RTFKeyword::QJ, 0 },
+ { "qk", RTFControlType::VALUE, RTFKeyword::QK, 0 },
+ { "ql", RTFControlType::FLAG, RTFKeyword::QL, 0 },
+ { "qmspace", RTFControlType::SYMBOL, RTFKeyword::QMSPACE, 0 },
+ { "qr", RTFControlType::FLAG, RTFKeyword::QR, 0 },
+ { "qt", RTFControlType::FLAG, RTFKeyword::QT, 0 },
+ { "rawclbgdkbdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKBDIAG, 0 },
+ { "rawclbgbdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGBDIAG, 0 },
+ { "rawclbgcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGCROSS, 0 },
+ { "rawclbgdcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDCROSS, 0 },
+ { "rawclbgdkcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKCROSS, 0 },
+ { "rawclbgdkdcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKDCROSS, 0 },
+ { "rawclbgdkfdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKFDIAG, 0 },
+ { "rawclbgdkhor", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKHOR, 0 },
+ { "rawclbgdkvert", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKVERT, 0 },
+ { "rawclbgfdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGFDIAG, 0 },
+ { "rawclbghoriz", RTFControlType::FLAG, RTFKeyword::RAWCLBGHORIZ, 0 },
+ { "rawclbgvert", RTFControlType::FLAG, RTFKeyword::RAWCLBGVERT, 0 },
+ { "rdblquote", RTFControlType::SYMBOL, RTFKeyword::RDBLQUOTE, 0 },
+ { "readonlyrecommended", RTFControlType::FLAG, RTFKeyword::READONLYRECOMMENDED, 0 },
+ { "readprot", RTFControlType::FLAG, RTFKeyword::READPROT, 0 },
+ { "red", RTFControlType::VALUE, RTFKeyword::RED, 0 },
+ { "relyonvml", RTFControlType::VALUE, RTFKeyword::RELYONVML, 0 },
+ { "remdttm", RTFControlType::FLAG, RTFKeyword::REMDTTM, 0 },
+ { "rempersonalinfo", RTFControlType::FLAG, RTFKeyword::REMPERSONALINFO, 0 },
+ { "result", RTFControlType::DESTINATION, RTFKeyword::RESULT, 0 },
+ { "revauth", RTFControlType::VALUE, RTFKeyword::REVAUTH, 0 },
+ { "revauthdel", RTFControlType::VALUE, RTFKeyword::REVAUTHDEL, 0 },
+ { "revbar", RTFControlType::VALUE, RTFKeyword::REVBAR, 3 },
+ { "revdttm", RTFControlType::VALUE, RTFKeyword::REVDTTM, 0 },
+ { "revdttmdel", RTFControlType::VALUE, RTFKeyword::REVDTTMDEL, 0 },
+ { "revised", RTFControlType::TOGGLE, RTFKeyword::REVISED, 1 },
+ { "revisions", RTFControlType::FLAG, RTFKeyword::REVISIONS, 0 },
+ { "revprop", RTFControlType::VALUE, RTFKeyword::REVPROP, 3 },
+ { "revprot", RTFControlType::FLAG, RTFKeyword::REVPROT, 0 },
+ { "revtbl", RTFControlType::DESTINATION, RTFKeyword::REVTBL, 0 },
+ { "revtim", RTFControlType::DESTINATION, RTFKeyword::REVTIM, 0 },
+ { "ri", RTFControlType::VALUE, RTFKeyword::RI, 0 },
+ { "rin", RTFControlType::VALUE, RTFKeyword::RIN, 0 },
+ { "row", RTFControlType::SYMBOL, RTFKeyword::ROW, 0 },
+ { "rquote", RTFControlType::SYMBOL, RTFKeyword::RQUOTE, 0 },
+ { "rsid", RTFControlType::VALUE, RTFKeyword::RSID, 0 },
+ { "rsidroot", RTFControlType::VALUE, RTFKeyword::RSIDROOT, 0 },
+ { "rsidtbl", RTFControlType::DESTINATION, RTFKeyword::RSIDTBL, 0 },
+ { "rsltbmp", RTFControlType::FLAG, RTFKeyword::RSLTBMP, 0 },
+ { "rslthtml", RTFControlType::FLAG, RTFKeyword::RSLTHTML, 0 },
+ { "rsltmerge", RTFControlType::FLAG, RTFKeyword::RSLTMERGE, 0 },
+ { "rsltpict", RTFControlType::FLAG, RTFKeyword::RSLTPICT, 0 },
+ { "rsltrtf", RTFControlType::FLAG, RTFKeyword::RSLTRTF, 0 },
+ { "rslttxt", RTFControlType::FLAG, RTFKeyword::RSLTTXT, 0 },
+ { "rtf", RTFControlType::DESTINATION, RTFKeyword::RTF, 0 },
+ { "rtlch", RTFControlType::FLAG, RTFKeyword::RTLCH, 0 },
+ { "rtldoc", RTFControlType::FLAG, RTFKeyword::RTLDOC, 0 },
+ { "rtlgutter", RTFControlType::FLAG, RTFKeyword::RTLGUTTER, 0 },
+ { "rtlmark", RTFControlType::SYMBOL, RTFKeyword::RTLMARK, 0 },
+ { "rtlpar", RTFControlType::FLAG, RTFKeyword::RTLPAR, 0 },
+ { "rtlrow", RTFControlType::FLAG, RTFKeyword::RTLROW, 0 },
+ { "rtlsect", RTFControlType::FLAG, RTFKeyword::RTLSECT, 0 },
+ { "rxe", RTFControlType::DESTINATION, RTFKeyword::RXE, 0 },
+ { "s", RTFControlType::VALUE, RTFKeyword::S, 0 },
+ { "sa", RTFControlType::VALUE, RTFKeyword::SA, 0 },
+ { "saauto", RTFControlType::TOGGLE, RTFKeyword::SAAUTO, 1 },
+ { "saftnnalc", RTFControlType::FLAG, RTFKeyword::SAFTNNALC, 0 },
+ { "saftnnar", RTFControlType::FLAG, RTFKeyword::SAFTNNAR, 0 },
+ { "saftnnauc", RTFControlType::FLAG, RTFKeyword::SAFTNNAUC, 0 },
+ { "saftnnchi", RTFControlType::FLAG, RTFKeyword::SAFTNNCHI, 0 },
+ { "saftnnchosung", RTFControlType::FLAG, RTFKeyword::SAFTNNCHOSUNG, 0 },
+ { "saftnncnum", RTFControlType::FLAG, RTFKeyword::SAFTNNCNUM, 0 },
+ { "saftnndbar", RTFControlType::FLAG, RTFKeyword::SAFTNNDBAR, 0 },
+ { "saftnndbnum", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUM, 0 },
+ { "saftnndbnumd", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMD, 0 },
+ { "saftnndbnumk", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMK, 0 },
+ { "saftnndbnumt", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMT, 0 },
+ { "saftnnganada", RTFControlType::FLAG, RTFKeyword::SAFTNNGANADA, 0 },
+ { "saftnngbnum", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUM, 0 },
+ { "saftnngbnumd", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUMD, 0 },
+ { "saftnngbnumk", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUMK, 0 },
+ { "saftnngbnuml", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUML, 0 },
+ { "saftnnrlc", RTFControlType::FLAG, RTFKeyword::SAFTNNRLC, 0 },
+ { "saftnnruc", RTFControlType::FLAG, RTFKeyword::SAFTNNRUC, 0 },
+ { "saftnnzodiac", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIAC, 0 },
+ { "saftnnzodiacd", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIACD, 0 },
+ { "saftnnzodiacl", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIACL, 0 },
+ { "saftnrestart", RTFControlType::FLAG, RTFKeyword::SAFTNRESTART, 0 },
+ { "saftnrstcont", RTFControlType::FLAG, RTFKeyword::SAFTNRSTCONT, 0 },
+ { "saftnstart", RTFControlType::VALUE, RTFKeyword::SAFTNSTART, 1 },
+ { "sautoupd", RTFControlType::FLAG, RTFKeyword::SAUTOUPD, 0 },
+ { "saveinvalidxml", RTFControlType::FLAG, RTFKeyword::SAVEINVALIDXML, 0 },
+ { "saveprevpict", RTFControlType::FLAG, RTFKeyword::SAVEPREVPICT, 0 },
+ { "sb", RTFControlType::VALUE, RTFKeyword::SB, 0 },
+ { "sbasedon", RTFControlType::VALUE, RTFKeyword::SBASEDON, 222 },
+ { "sbauto", RTFControlType::TOGGLE, RTFKeyword::SBAUTO, 1 },
+ { "sbkcol", RTFControlType::FLAG, RTFKeyword::SBKCOL, 0 },
+ { "sbkeven", RTFControlType::FLAG, RTFKeyword::SBKEVEN, 0 },
+ { "sbknone", RTFControlType::FLAG, RTFKeyword::SBKNONE, 0 },
+ { "sbkodd", RTFControlType::FLAG, RTFKeyword::SBKODD, 0 },
+ { "sbkpage", RTFControlType::FLAG, RTFKeyword::SBKPAGE, 0 },
+ { "sbys", RTFControlType::FLAG, RTFKeyword::SBYS, 0 },
+ { "scaps", RTFControlType::TOGGLE, RTFKeyword::SCAPS, 1 },
+ { "scompose", RTFControlType::FLAG, RTFKeyword::SCOMPOSE, 0 },
+ { "sec", RTFControlType::VALUE, RTFKeyword::SEC, 0 },
+ { "sect", RTFControlType::SYMBOL, RTFKeyword::SECT, 0 },
+ { "sectd", RTFControlType::FLAG, RTFKeyword::SECTD, 0 },
+ { "sectdefaultcl", RTFControlType::FLAG, RTFKeyword::SECTDEFAULTCL, 0 },
+ { "sectexpand", RTFControlType::VALUE, RTFKeyword::SECTEXPAND, 0 },
+ { "sectlinegrid", RTFControlType::VALUE, RTFKeyword::SECTLINEGRID, 0 },
+ { "sectnum", RTFControlType::SYMBOL, RTFKeyword::SECTNUM, 0 },
+ { "sectrsid", RTFControlType::VALUE, RTFKeyword::SECTRSID, 0 },
+ { "sectspecifycl", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYCL, 0 },
+ { "sectspecifygenN", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYGENN, 0 },
+ { "sectspecifyl", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYL, 0 },
+ { "sectunlocked", RTFControlType::FLAG, RTFKeyword::SECTUNLOCKED, 0 },
+ { "sftnbj", RTFControlType::FLAG, RTFKeyword::SFTNBJ, 0 },
+ { "sftnnalc", RTFControlType::FLAG, RTFKeyword::SFTNNALC, 0 },
+ { "sftnnar", RTFControlType::FLAG, RTFKeyword::SFTNNAR, 0 },
+ { "sftnnauc", RTFControlType::FLAG, RTFKeyword::SFTNNAUC, 0 },
+ { "sftnnchi", RTFControlType::FLAG, RTFKeyword::SFTNNCHI, 0 },
+ { "sftnnchosung", RTFControlType::FLAG, RTFKeyword::SFTNNCHOSUNG, 0 },
+ { "sftnncnum", RTFControlType::FLAG, RTFKeyword::SFTNNCNUM, 0 },
+ { "sftnndbar", RTFControlType::FLAG, RTFKeyword::SFTNNDBAR, 0 },
+ { "sftnndbnum", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUM, 0 },
+ { "sftnndbnumd", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMD, 0 },
+ { "sftnndbnumk", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMK, 0 },
+ { "sftnndbnumt", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMT, 0 },
+ { "sftnnganada", RTFControlType::FLAG, RTFKeyword::SFTNNGANADA, 0 },
+ { "sftnngbnum", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUM, 0 },
+ { "sftnngbnumd", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUMD, 0 },
+ { "sftnngbnumk", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUMK, 0 },
+ { "sftnngbnuml", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUML, 0 },
+ { "sftnnrlc", RTFControlType::FLAG, RTFKeyword::SFTNNRLC, 0 },
+ { "sftnnruc", RTFControlType::FLAG, RTFKeyword::SFTNNRUC, 0 },
+ { "sftnnzodiac", RTFControlType::FLAG, RTFKeyword::SFTNNZODIAC, 0 },
+ { "sftnnzodiacd", RTFControlType::FLAG, RTFKeyword::SFTNNZODIACD, 0 },
+ { "sftnnzodiacl", RTFControlType::FLAG, RTFKeyword::SFTNNZODIACL, 0 },
+ { "sftnrestart", RTFControlType::FLAG, RTFKeyword::SFTNRESTART, 0 },
+ { "sftnrstcont", RTFControlType::FLAG, RTFKeyword::SFTNRSTCONT, 0 },
+ { "sftnrstpg", RTFControlType::FLAG, RTFKeyword::SFTNRSTPG, 0 },
+ { "sftnstart", RTFControlType::VALUE, RTFKeyword::SFTNSTART, 1 },
+ { "sftntj", RTFControlType::FLAG, RTFKeyword::SFTNTJ, 0 },
+ { "shad", RTFControlType::TOGGLE, RTFKeyword::SHAD, 1 },
+ { "shading", RTFControlType::VALUE, RTFKeyword::SHADING, 0 },
+ { "shidden", RTFControlType::FLAG, RTFKeyword::SHIDDEN, 0 },
+ { "shift", RTFControlType::FLAG, RTFKeyword::SHIFT, 0 },
+ { "showplaceholdtext", RTFControlType::VALUE, RTFKeyword::SHOWPLACEHOLDTEXT, 0 },
+ { "showxmlerrors", RTFControlType::VALUE, RTFKeyword::SHOWXMLERRORS, 0 },
+ { "shp", RTFControlType::DESTINATION, RTFKeyword::SHP, 0 },
+ { "shpbottom", RTFControlType::VALUE, RTFKeyword::SHPBOTTOM, 0 },
+ { "shpbxcolumn", RTFControlType::FLAG, RTFKeyword::SHPBXCOLUMN, 0 },
+ { "shpbxignore", RTFControlType::FLAG, RTFKeyword::SHPBXIGNORE, 0 },
+ { "shpbxmargin", RTFControlType::FLAG, RTFKeyword::SHPBXMARGIN, 0 },
+ { "shpbxpage", RTFControlType::FLAG, RTFKeyword::SHPBXPAGE, 0 },
+ { "shpbyignore", RTFControlType::FLAG, RTFKeyword::SHPBYIGNORE, 0 },
+ { "shpbymargin", RTFControlType::FLAG, RTFKeyword::SHPBYMARGIN, 0 },
+ { "shpbypage", RTFControlType::FLAG, RTFKeyword::SHPBYPAGE, 0 },
+ { "shpbypara", RTFControlType::FLAG, RTFKeyword::SHPBYPARA, 0 },
+ { "shpfblwtxt", RTFControlType::VALUE, RTFKeyword::SHPFBLWTXT, 0 },
+ { "shpfhdr", RTFControlType::VALUE, RTFKeyword::SHPFHDR, 0 },
+ { "shpgrp", RTFControlType::DESTINATION, RTFKeyword::SHPGRP, 0 },
+ { "shpinst", RTFControlType::DESTINATION, RTFKeyword::SHPINST, 0 },
+ { "shpleft", RTFControlType::VALUE, RTFKeyword::SHPLEFT, 0 },
+ { "shplid", RTFControlType::VALUE, RTFKeyword::SHPLID, 0 },
+ { "shplockanchor", RTFControlType::FLAG, RTFKeyword::SHPLOCKANCHOR, 0 },
+ { "shppict", RTFControlType::DESTINATION, RTFKeyword::SHPPICT, 0 },
+ { "shpright", RTFControlType::VALUE, RTFKeyword::SHPRIGHT, 0 },
+ { "shprslt", RTFControlType::DESTINATION, RTFKeyword::SHPRSLT, 0 },
+ { "shptop", RTFControlType::VALUE, RTFKeyword::SHPTOP, 0 },
+ { "shptxt", RTFControlType::DESTINATION, RTFKeyword::SHPTXT, 0 },
+ { "shpwrk", RTFControlType::VALUE, RTFKeyword::SHPWRK, 0 },
+ { "shpwr", RTFControlType::VALUE, RTFKeyword::SHPWR, 0 },
+ { "shpz", RTFControlType::VALUE, RTFKeyword::SHPZ, 0 },
+ { "sl", RTFControlType::VALUE, RTFKeyword::SL, 0 },
+ { "slink", RTFControlType::VALUE, RTFKeyword::SLINK, 0 },
+ { "slmult", RTFControlType::VALUE, RTFKeyword::SLMULT, 0 },
+ { "slocked", RTFControlType::FLAG, RTFKeyword::SLOCKED, 0 },
+ { "sn", RTFControlType::DESTINATION, RTFKeyword::SN, 0 },
+ { "snaptogridincell", RTFControlType::FLAG, RTFKeyword::SNAPTOGRIDINCELL, 0 },
+ { "snext", RTFControlType::VALUE, RTFKeyword::SNEXT, 0 },
+ { "softcol", RTFControlType::FLAG, RTFKeyword::SOFTCOL, 0 },
+ { "softlheight", RTFControlType::VALUE, RTFKeyword::SOFTLHEIGHT, 0 },
+ { "softline", RTFControlType::FLAG, RTFKeyword::SOFTLINE, 0 },
+ { "softpage", RTFControlType::FLAG, RTFKeyword::SOFTPAGE, 0 },
+ { "sp", RTFControlType::DESTINATION, RTFKeyword::SP, 0 },
+ { "spersonal", RTFControlType::FLAG, RTFKeyword::SPERSONAL, 0 },
+ { "spltpgpar", RTFControlType::FLAG, RTFKeyword::SPLTPGPAR, 0 },
+ { "splytwnine", RTFControlType::FLAG, RTFKeyword::SPLYTWNINE, 0 },
+ { "spriority", RTFControlType::VALUE, RTFKeyword::SPRIORITY, 0 },
+ { "sprsbsp", RTFControlType::FLAG, RTFKeyword::SPRSBSP, 0 },
+ { "sprslnsp", RTFControlType::FLAG, RTFKeyword::SPRSLNSP, 0 },
+ { "sprsspbf", RTFControlType::FLAG, RTFKeyword::SPRSSPBF, 0 },
+ { "sprstsm", RTFControlType::FLAG, RTFKeyword::SPRSTSM, 0 },
+ { "sprstsp", RTFControlType::FLAG, RTFKeyword::SPRSTSP, 0 },
+ { "spv", RTFControlType::FLAG, RTFKeyword::SPV, 0 },
+ { "sqformat", RTFControlType::FLAG, RTFKeyword::SQFORMAT, 0 },
+ { "srauth", RTFControlType::VALUE, RTFKeyword::SRAUTH, 0 },
+ { "srdate", RTFControlType::VALUE, RTFKeyword::SRDATE, 0 },
+ { "sreply", RTFControlType::FLAG, RTFKeyword::SREPLY, 0 },
+ { "ssemihidden", RTFControlType::VALUE, RTFKeyword::SSEMIHIDDEN, 0 },
+ { "staticval", RTFControlType::DESTINATION, RTFKeyword::STATICVAL, 0 },
+ { "stextflow", RTFControlType::VALUE, RTFKeyword::STEXTFLOW, 0 },
+ { "strike", RTFControlType::TOGGLE, RTFKeyword::STRIKE, 1 },
+ { "striked", RTFControlType::TOGGLE, RTFKeyword::STRIKED, 1 },
+ { "stshfbi", RTFControlType::VALUE, RTFKeyword::STSHFBI, 0 },
+ { "stshfdbch", RTFControlType::VALUE, RTFKeyword::STSHFDBCH, 0 },
+ { "stshfhich", RTFControlType::VALUE, RTFKeyword::STSHFHICH, 0 },
+ { "stshfloch", RTFControlType::VALUE, RTFKeyword::STSHFLOCH, 0 },
+ { "stylelock", RTFControlType::FLAG, RTFKeyword::STYLELOCK, 0 },
+ { "stylelockbackcomp", RTFControlType::FLAG, RTFKeyword::STYLELOCKBACKCOMP, 0 },
+ { "stylelockenforced", RTFControlType::FLAG, RTFKeyword::STYLELOCKENFORCED, 0 },
+ { "stylelockqfset", RTFControlType::FLAG, RTFKeyword::STYLELOCKQFSET, 0 },
+ { "stylelocktheme", RTFControlType::FLAG, RTFKeyword::STYLELOCKTHEME, 0 },
+ { "stylesheet", RTFControlType::DESTINATION, RTFKeyword::STYLESHEET, 0 },
+ { "stylesortmethod", RTFControlType::VALUE, RTFKeyword::STYLESORTMETHOD, 1 },
+ { "styrsid", RTFControlType::VALUE, RTFKeyword::STYRSID, 0 },
+ { "sub", RTFControlType::FLAG, RTFKeyword::SUB, 0 },
+ { "subdocument", RTFControlType::VALUE, RTFKeyword::SUBDOCUMENT, 0 },
+ { "subfontbysize", RTFControlType::FLAG, RTFKeyword::SUBFONTBYSIZE, 0 },
+ { "subject", RTFControlType::DESTINATION, RTFKeyword::SUBJECT, 0 },
+ { "sunhideused", RTFControlType::VALUE, RTFKeyword::SUNHIDEUSED, 0 },
+ { "super", RTFControlType::FLAG, RTFKeyword::SUPER, 0 },
+ { "sv", RTFControlType::DESTINATION, RTFKeyword::SV, 0 },
+ { "svb", RTFControlType::DESTINATION, RTFKeyword::SVB, 0 },
+ { "swpbdr", RTFControlType::FLAG, RTFKeyword::SWPBDR, 0 },
+ { "tab", RTFControlType::SYMBOL, RTFKeyword::TAB, 0 },
+ { "tabsnoovrlp", RTFControlType::FLAG, RTFKeyword::TABSNOOVRLP, 0 },
+ { "taprtl", RTFControlType::FLAG, RTFKeyword::TAPRTL, 0 },
+ { "tb", RTFControlType::VALUE, RTFKeyword::TB, 0 },
+ { "tblind", RTFControlType::VALUE, RTFKeyword::TBLIND, 0 },
+ { "tblindtype", RTFControlType::VALUE, RTFKeyword::TBLINDTYPE, 0 },
+ { "tbllkbestfit", RTFControlType::FLAG, RTFKeyword::TBLLKBESTFIT, 0 },
+ { "tbllkborder", RTFControlType::FLAG, RTFKeyword::TBLLKBORDER, 0 },
+ { "tbllkcolor", RTFControlType::FLAG, RTFKeyword::TBLLKCOLOR, 0 },
+ { "tbllkfont", RTFControlType::FLAG, RTFKeyword::TBLLKFONT, 0 },
+ { "tbllkhdrcols", RTFControlType::FLAG, RTFKeyword::TBLLKHDRCOLS, 0 },
+ { "tbllkhdrrows", RTFControlType::FLAG, RTFKeyword::TBLLKHDRROWS, 0 },
+ { "tbllklastcol", RTFControlType::FLAG, RTFKeyword::TBLLKLASTCOL, 0 },
+ { "tbllklastrow", RTFControlType::FLAG, RTFKeyword::TBLLKLASTROW, 0 },
+ { "tbllknocolband", RTFControlType::FLAG, RTFKeyword::TBLLKNOCOLBAND, 0 },
+ { "tbllknorowband", RTFControlType::FLAG, RTFKeyword::TBLLKNOROWBAND, 0 },
+ { "tbllkshading", RTFControlType::FLAG, RTFKeyword::TBLLKSHADING, 0 },
+ { "tblrsid", RTFControlType::VALUE, RTFKeyword::TBLRSID, 0 },
+ { "tc", RTFControlType::DESTINATION, RTFKeyword::TC, 0 },
+ { "tcelld", RTFControlType::FLAG, RTFKeyword::TCELLD, 0 },
+ { "tcf", RTFControlType::VALUE, RTFKeyword::TCF, 67 },
+ { "tcl", RTFControlType::VALUE, RTFKeyword::TCL, 0 },
+ { "tcn", RTFControlType::FLAG, RTFKeyword::TCN, 0 },
+ { "tdfrmtxtBottom", RTFControlType::VALUE, RTFKeyword::TDFRMTXTBOTTOM, 0 },
+ { "tdfrmtxtLeft", RTFControlType::VALUE, RTFKeyword::TDFRMTXTLEFT, 0 },
+ { "tdfrmtxtRight", RTFControlType::VALUE, RTFKeyword::TDFRMTXTRIGHT, 0 },
+ { "tdfrmtxtTop", RTFControlType::VALUE, RTFKeyword::TDFRMTXTTOP, 0 },
+ { "template", RTFControlType::DESTINATION, RTFKeyword::TEMPLATE, 0 },
+ { "themedata", RTFControlType::DESTINATION, RTFKeyword::THEMEDATA, 0 },
+ { "themelang", RTFControlType::VALUE, RTFKeyword::THEMELANG, 0 },
+ { "themelangcs", RTFControlType::VALUE, RTFKeyword::THEMELANGCS, 0 },
+ { "themelangfe", RTFControlType::VALUE, RTFKeyword::THEMELANGFE, 0 },
+ { "time", RTFControlType::FLAG, RTFKeyword::TIME, 0 },
+ { "title", RTFControlType::DESTINATION, RTFKeyword::TITLE, 0 },
+ { "titlepg", RTFControlType::FLAG, RTFKeyword::TITLEPG, 0 },
+ { "tldot", RTFControlType::FLAG, RTFKeyword::TLDOT, 0 },
+ { "tleq", RTFControlType::FLAG, RTFKeyword::TLEQ, 0 },
+ { "tlhyph", RTFControlType::FLAG, RTFKeyword::TLHYPH, 0 },
+ { "tlmdot", RTFControlType::FLAG, RTFKeyword::TLMDOT, 0 },
+ { "tlth", RTFControlType::FLAG, RTFKeyword::TLTH, 0 },
+ { "tlul", RTFControlType::FLAG, RTFKeyword::TLUL, 0 },
+ { "toplinepunct", RTFControlType::FLAG, RTFKeyword::TOPLINEPUNCT, 0 },
+ { "tphcol", RTFControlType::FLAG, RTFKeyword::TPHCOL, 0 },
+ { "tphmrg", RTFControlType::FLAG, RTFKeyword::TPHMRG, 0 },
+ { "tphpg", RTFControlType::FLAG, RTFKeyword::TPHPG, 0 },
+ { "tposnegx", RTFControlType::VALUE, RTFKeyword::TPOSNEGX, 0 },
+ { "tposnegy", RTFControlType::VALUE, RTFKeyword::TPOSNEGY, 0 },
+ { "tposxc", RTFControlType::FLAG, RTFKeyword::TPOSXC, 0 },
+ { "tposxi", RTFControlType::FLAG, RTFKeyword::TPOSXI, 0 },
+ { "tposxl", RTFControlType::FLAG, RTFKeyword::TPOSXL, 0 },
+ { "tposx", RTFControlType::VALUE, RTFKeyword::TPOSX, 0 },
+ { "tposxo", RTFControlType::FLAG, RTFKeyword::TPOSXO, 0 },
+ { "tposxr", RTFControlType::FLAG, RTFKeyword::TPOSXR, 0 },
+ { "tposy", RTFControlType::VALUE, RTFKeyword::TPOSY, 0 },
+ { "tposyb", RTFControlType::FLAG, RTFKeyword::TPOSYB, 0 },
+ { "tposyc", RTFControlType::FLAG, RTFKeyword::TPOSYC, 0 },
+ { "tposyil", RTFControlType::FLAG, RTFKeyword::TPOSYIL, 0 },
+ { "tposyin", RTFControlType::FLAG, RTFKeyword::TPOSYIN, 0 },
+ { "tposyout", RTFControlType::FLAG, RTFKeyword::TPOSYOUT, 0 },
+ { "tposyt", RTFControlType::FLAG, RTFKeyword::TPOSYT, 0 },
+ { "tpvmrg", RTFControlType::FLAG, RTFKeyword::TPVMRG, 0 },
+ { "tpvpara", RTFControlType::FLAG, RTFKeyword::TPVPARA, 0 },
+ { "tpvpg", RTFControlType::FLAG, RTFKeyword::TPVPG, 0 },
+ { "tqc", RTFControlType::FLAG, RTFKeyword::TQC, 0 },
+ { "tqdec", RTFControlType::FLAG, RTFKeyword::TQDEC, 0 },
+ { "tqr", RTFControlType::FLAG, RTFKeyword::TQR, 0 },
+ { "trackformatting", RTFControlType::VALUE, RTFKeyword::TRACKFORMATTING, 0 },
+ { "trackmoves", RTFControlType::VALUE, RTFKeyword::TRACKMOVES, 0 },
+ { "transmf", RTFControlType::FLAG, RTFKeyword::TRANSMF, 0 },
+ { "trauth", RTFControlType::VALUE, RTFKeyword::TRAUTH, 0 },
+ { "trautofit", RTFControlType::TOGGLE, RTFKeyword::TRAUTOFIT, 1 },
+ { "trbgbdiag", RTFControlType::FLAG, RTFKeyword::TRBGBDIAG, 0 },
+ { "trbgcross", RTFControlType::FLAG, RTFKeyword::TRBGCROSS, 0 },
+ { "trbgdcross", RTFControlType::FLAG, RTFKeyword::TRBGDCROSS, 0 },
+ { "trbgdkbdiag", RTFControlType::FLAG, RTFKeyword::TRBGDKBDIAG, 0 },
+ { "trbgdkcross", RTFControlType::FLAG, RTFKeyword::TRBGDKCROSS, 0 },
+ { "trbgdkdcross", RTFControlType::FLAG, RTFKeyword::TRBGDKDCROSS, 0 },
+ { "trbgdkfdiag", RTFControlType::FLAG, RTFKeyword::TRBGDKFDIAG, 0 },
+ { "trbgdkhor", RTFControlType::FLAG, RTFKeyword::TRBGDKHOR, 0 },
+ { "trbgdkvert", RTFControlType::FLAG, RTFKeyword::TRBGDKVERT, 0 },
+ { "trbgfdiag", RTFControlType::FLAG, RTFKeyword::TRBGFDIAG, 0 },
+ { "trbghoriz", RTFControlType::FLAG, RTFKeyword::TRBGHORIZ, 0 },
+ { "trbgvert", RTFControlType::FLAG, RTFKeyword::TRBGVERT, 0 },
+ { "trbrdrb", RTFControlType::FLAG, RTFKeyword::TRBRDRB, 0 },
+ { "trbrdrh", RTFControlType::FLAG, RTFKeyword::TRBRDRH, 0 },
+ { "trbrdrl", RTFControlType::FLAG, RTFKeyword::TRBRDRL, 0 },
+ { "trbrdrr", RTFControlType::FLAG, RTFKeyword::TRBRDRR, 0 },
+ { "trbrdrt", RTFControlType::FLAG, RTFKeyword::TRBRDRT, 0 },
+ { "trbrdrv", RTFControlType::FLAG, RTFKeyword::TRBRDRV, 0 },
+ { "trcbpat", RTFControlType::VALUE, RTFKeyword::TRCBPAT, 0 },
+ { "trcfpat", RTFControlType::VALUE, RTFKeyword::TRCFPAT, 0 },
+ { "trdate", RTFControlType::VALUE, RTFKeyword::TRDATE, 0 },
+ { "trftsWidthA", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTHA, 0 },
+ { "trftsWidthB", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTHB, 0 },
+ { "trftsWidth", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTH, 0 },
+ { "trgaph", RTFControlType::VALUE, RTFKeyword::TRGAPH, 0 },
+ { "trhdr", RTFControlType::FLAG, RTFKeyword::TRHDR, 0 },
+ { "trkeep", RTFControlType::FLAG, RTFKeyword::TRKEEP, 0 },
+ { "trkeepfollow", RTFControlType::FLAG, RTFKeyword::TRKEEPFOLLOW, 0 },
+ { "trleft", RTFControlType::VALUE, RTFKeyword::TRLEFT, 0 },
+ { "trowd", RTFControlType::FLAG, RTFKeyword::TROWD, 0 },
+ { "trpaddb", RTFControlType::VALUE, RTFKeyword::TRPADDB, 0 },
+ { "trpaddfb", RTFControlType::VALUE, RTFKeyword::TRPADDFB, 0 },
+ { "trpaddfl", RTFControlType::VALUE, RTFKeyword::TRPADDFL, 0 },
+ { "trpaddfr", RTFControlType::VALUE, RTFKeyword::TRPADDFR, 0 },
+ { "trpaddft", RTFControlType::VALUE, RTFKeyword::TRPADDFT, 0 },
+ { "trpaddl", RTFControlType::VALUE, RTFKeyword::TRPADDL, 0 },
+ { "trpaddr", RTFControlType::VALUE, RTFKeyword::TRPADDR, 0 },
+ { "trpaddt", RTFControlType::VALUE, RTFKeyword::TRPADDT, 0 },
+ { "trpadob", RTFControlType::VALUE, RTFKeyword::TRPADOB, 0 },
+ { "trpadofb", RTFControlType::VALUE, RTFKeyword::TRPADOFB, 0 },
+ { "trpadofl", RTFControlType::VALUE, RTFKeyword::TRPADOFL, 0 },
+ { "trpadofr", RTFControlType::VALUE, RTFKeyword::TRPADOFR, 0 },
+ { "trpadoft", RTFControlType::VALUE, RTFKeyword::TRPADOFT, 0 },
+ { "trpadol", RTFControlType::VALUE, RTFKeyword::TRPADOL, 0 },
+ { "trpador", RTFControlType::VALUE, RTFKeyword::TRPADOR, 0 },
+ { "trpadot", RTFControlType::VALUE, RTFKeyword::TRPADOT, 0 },
+ { "trpat", RTFControlType::VALUE, RTFKeyword::TRPAT, 0 },
+ { "trqc", RTFControlType::FLAG, RTFKeyword::TRQC, 0 },
+ { "trql", RTFControlType::FLAG, RTFKeyword::TRQL, 0 },
+ { "trqr", RTFControlType::FLAG, RTFKeyword::TRQR, 0 },
+ { "trrh", RTFControlType::VALUE, RTFKeyword::TRRH, 0 },
+ { "trshdng", RTFControlType::VALUE, RTFKeyword::TRSHDNG, 0 },
+ { "trspdb", RTFControlType::VALUE, RTFKeyword::TRSPDB, 0 },
+ { "trspdfb", RTFControlType::VALUE, RTFKeyword::TRSPDFB, 0 },
+ { "trspdfl", RTFControlType::VALUE, RTFKeyword::TRSPDFL, 0 },
+ { "trspdfr", RTFControlType::VALUE, RTFKeyword::TRSPDFR, 0 },
+ { "trspdft", RTFControlType::VALUE, RTFKeyword::TRSPDFT, 0 },
+ { "trspdl", RTFControlType::VALUE, RTFKeyword::TRSPDL, 0 },
+ { "trspdr", RTFControlType::VALUE, RTFKeyword::TRSPDR, 0 },
+ { "trspdt", RTFControlType::VALUE, RTFKeyword::TRSPDT, 0 },
+ { "trspob", RTFControlType::VALUE, RTFKeyword::TRSPOB, 0 },
+ { "trspofb", RTFControlType::VALUE, RTFKeyword::TRSPOFB, 0 },
+ { "trspofl", RTFControlType::VALUE, RTFKeyword::TRSPOFL, 0 },
+ { "trspofr", RTFControlType::VALUE, RTFKeyword::TRSPOFR, 0 },
+ { "trspoft", RTFControlType::VALUE, RTFKeyword::TRSPOFT, 0 },
+ { "trspol", RTFControlType::VALUE, RTFKeyword::TRSPOL, 0 },
+ { "trspor", RTFControlType::VALUE, RTFKeyword::TRSPOR, 0 },
+ { "trspot", RTFControlType::VALUE, RTFKeyword::TRSPOT, 0 },
+ { "truncatefontheight", RTFControlType::FLAG, RTFKeyword::TRUNCATEFONTHEIGHT, 0 },
+ { "truncex", RTFControlType::FLAG, RTFKeyword::TRUNCEX, 0 },
+ { "trwWidthA", RTFControlType::VALUE, RTFKeyword::TRWWIDTHA, 0 },
+ { "trwWidthB", RTFControlType::VALUE, RTFKeyword::TRWWIDTHB, 0 },
+ { "trwWidth", RTFControlType::VALUE, RTFKeyword::TRWWIDTH, 0 },
+ { "ts", RTFControlType::VALUE, RTFKeyword::TS, 0 },
+ { "tsbgbdiag", RTFControlType::FLAG, RTFKeyword::TSBGBDIAG, 0 },
+ { "tsbgcross", RTFControlType::FLAG, RTFKeyword::TSBGCROSS, 0 },
+ { "tsbgdcross", RTFControlType::FLAG, RTFKeyword::TSBGDCROSS, 0 },
+ { "tsbgdkbdiag", RTFControlType::FLAG, RTFKeyword::TSBGDKBDIAG, 0 },
+ { "tsbgdkcross", RTFControlType::FLAG, RTFKeyword::TSBGDKCROSS, 0 },
+ { "tsbgdkdcross", RTFControlType::FLAG, RTFKeyword::TSBGDKDCROSS, 0 },
+ { "tsbgdkfdiag", RTFControlType::FLAG, RTFKeyword::TSBGDKFDIAG, 0 },
+ { "tsbgdkhor", RTFControlType::FLAG, RTFKeyword::TSBGDKHOR, 0 },
+ { "tsbgdkvert", RTFControlType::FLAG, RTFKeyword::TSBGDKVERT, 0 },
+ { "tsbgfdiag", RTFControlType::FLAG, RTFKeyword::TSBGFDIAG, 0 },
+ { "tsbghoriz", RTFControlType::FLAG, RTFKeyword::TSBGHORIZ, 0 },
+ { "tsbgvert", RTFControlType::FLAG, RTFKeyword::TSBGVERT, 0 },
+ { "tsbrdrb", RTFControlType::FLAG, RTFKeyword::TSBRDRB, 0 },
+ { "tsbrdrdgl", RTFControlType::FLAG, RTFKeyword::TSBRDRDGL, 0 },
+ { "tsbrdrdgr", RTFControlType::FLAG, RTFKeyword::TSBRDRDGR, 0 },
+ { "tsbrdrh", RTFControlType::FLAG, RTFKeyword::TSBRDRH, 0 },
+ { "tsbrdrl", RTFControlType::FLAG, RTFKeyword::TSBRDRL, 0 },
+ { "tsbrdrr", RTFControlType::FLAG, RTFKeyword::TSBRDRR, 0 },
+ { "tsbrdrt", RTFControlType::FLAG, RTFKeyword::TSBRDRT, 0 },
+ { "tsbrdrv", RTFControlType::FLAG, RTFKeyword::TSBRDRV, 0 },
+ { "tscbandhorzeven", RTFControlType::FLAG, RTFKeyword::TSCBANDHORZEVEN, 0 },
+ { "tscbandhorzodd", RTFControlType::FLAG, RTFKeyword::TSCBANDHORZODD, 0 },
+ { "tscbandsh", RTFControlType::VALUE, RTFKeyword::TSCBANDSH, 0 },
+ { "tscbandsv", RTFControlType::VALUE, RTFKeyword::TSCBANDSV, 0 },
+ { "tscbandverteven", RTFControlType::FLAG, RTFKeyword::TSCBANDVERTEVEN, 0 },
+ { "tscbandvertodd", RTFControlType::FLAG, RTFKeyword::TSCBANDVERTODD, 0 },
+ { "tscellcbpat", RTFControlType::VALUE, RTFKeyword::TSCELLCBPAT, 0 },
+ { "tscellcfpat", RTFControlType::VALUE, RTFKeyword::TSCELLCFPAT, 0 },
+ { "tscellpaddb", RTFControlType::VALUE, RTFKeyword::TSCELLPADDB, 0 },
+ { "tscellpaddfb", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFB, 0 },
+ { "tscellpaddfl", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFL, 0 },
+ { "tscellpaddfr", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFR, 0 },
+ { "tscellpaddft", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFT, 0 },
+ { "tscellpaddl", RTFControlType::VALUE, RTFKeyword::TSCELLPADDL, 0 },
+ { "tscellpaddr", RTFControlType::VALUE, RTFKeyword::TSCELLPADDR, 0 },
+ { "tscellpaddt", RTFControlType::VALUE, RTFKeyword::TSCELLPADDT, 0 },
+ { "tscellpct", RTFControlType::VALUE, RTFKeyword::TSCELLPCT, 0 },
+ { "tscellwidth", RTFControlType::VALUE, RTFKeyword::TSCELLWIDTH, 0 },
+ { "tscellwidthfts", RTFControlType::VALUE, RTFKeyword::TSCELLWIDTHFTS, 0 },
+ { "tscfirstcol", RTFControlType::FLAG, RTFKeyword::TSCFIRSTCOL, 0 },
+ { "tscfirstrow", RTFControlType::FLAG, RTFKeyword::TSCFIRSTROW, 0 },
+ { "tsclastcol", RTFControlType::FLAG, RTFKeyword::TSCLASTCOL, 0 },
+ { "tsclastrow", RTFControlType::FLAG, RTFKeyword::TSCLASTROW, 0 },
+ { "tscnecell", RTFControlType::FLAG, RTFKeyword::TSCNECELL, 0 },
+ { "tscnwcell", RTFControlType::FLAG, RTFKeyword::TSCNWCELL, 0 },
+ { "tscsecell", RTFControlType::FLAG, RTFKeyword::TSCSECELL, 0 },
+ { "tscswcell", RTFControlType::FLAG, RTFKeyword::TSCSWCELL, 0 },
+ { "tsd", RTFControlType::FLAG, RTFKeyword::TSD, 0 },
+ { "tsnowrap", RTFControlType::FLAG, RTFKeyword::TSNOWRAP, 0 },
+ { "tsrowd", RTFControlType::FLAG, RTFKeyword::TSROWD, 0 },
+ { "tsvertalb", RTFControlType::FLAG, RTFKeyword::TSVERTALB, 0 },
+ { "tsvertalc", RTFControlType::FLAG, RTFKeyword::TSVERTALC, 0 },
+ { "tsvertalt", RTFControlType::FLAG, RTFKeyword::TSVERTALT, 0 },
+ { "twoinone", RTFControlType::VALUE, RTFKeyword::TWOINONE, 0 },
+ { "twoonone", RTFControlType::FLAG, RTFKeyword::TWOONONE, 0 },
+ { "tx", RTFControlType::VALUE, RTFKeyword::TX, 0 },
+ { "txbxtwalways", RTFControlType::FLAG, RTFKeyword::TXBXTWALWAYS, 0 },
+ { "txbxtwfirst", RTFControlType::FLAG, RTFKeyword::TXBXTWFIRST, 0 },
+ { "txbxtwfirstlast", RTFControlType::FLAG, RTFKeyword::TXBXTWFIRSTLAST, 0 },
+ { "txbxtwlast", RTFControlType::FLAG, RTFKeyword::TXBXTWLAST, 0 },
+ { "txbxtwno", RTFControlType::FLAG, RTFKeyword::TXBXTWNO, 0 },
+ { "txe", RTFControlType::DESTINATION, RTFKeyword::TXE, 0 },
+ { "u", RTFControlType::VALUE, RTFKeyword::U, 0 },
+ { "uc", RTFControlType::VALUE, RTFKeyword::UC, 1 },
+ { "ud", RTFControlType::DESTINATION, RTFKeyword::UD, 0 },
+ { "ul", RTFControlType::TOGGLE, RTFKeyword::UL, 1 },
+ { "ulc", RTFControlType::VALUE, RTFKeyword::ULC, 0 },
+ { "uld", RTFControlType::FLAG, RTFKeyword::ULD, 0 },
+ { "uldash", RTFControlType::TOGGLE, RTFKeyword::ULDASH, 1 },
+ { "uldashd", RTFControlType::TOGGLE, RTFKeyword::ULDASHD, 1 },
+ { "uldashdd", RTFControlType::TOGGLE, RTFKeyword::ULDASHDD, 1 },
+ { "uldb", RTFControlType::TOGGLE, RTFKeyword::ULDB, 1 },
+ { "ulhair", RTFControlType::TOGGLE, RTFKeyword::ULHAIR, 1 },
+ { "ulhwave", RTFControlType::TOGGLE, RTFKeyword::ULHWAVE, 1 },
+ { "ulldash", RTFControlType::TOGGLE, RTFKeyword::ULLDASH, 1 },
+ { "ulnone", RTFControlType::FLAG, RTFKeyword::ULNONE, 0 },
+ { "ulth", RTFControlType::TOGGLE, RTFKeyword::ULTH, 1 },
+ { "ulthd", RTFControlType::TOGGLE, RTFKeyword::ULTHD, 1 },
+ { "ulthdash", RTFControlType::TOGGLE, RTFKeyword::ULTHDASH, 1 },
+ { "ulthdashd", RTFControlType::TOGGLE, RTFKeyword::ULTHDASHD, 1 },
+ { "ulthdashdd", RTFControlType::TOGGLE, RTFKeyword::ULTHDASHDD, 1 },
+ { "ulthldash", RTFControlType::TOGGLE, RTFKeyword::ULTHLDASH, 1 },
+ { "ululdbwave", RTFControlType::TOGGLE, RTFKeyword::ULULDBWAVE, 1 },
+ { "ulw", RTFControlType::FLAG, RTFKeyword::ULW, 0 },
+ { "ulwave", RTFControlType::TOGGLE, RTFKeyword::ULWAVE, 1 },
+ { "up", RTFControlType::VALUE, RTFKeyword::UP, 6 },
+ { "upr", RTFControlType::DESTINATION, RTFKeyword::UPR, 0 },
+ { "urtf", RTFControlType::VALUE, RTFKeyword::URTF, 0 },
+ { "useltbaln", RTFControlType::FLAG, RTFKeyword::USELTBALN, 0 },
+ { "usenormstyforlist", RTFControlType::FLAG, RTFKeyword::USENORMSTYFORLIST, 0 },
+ { "userprops", RTFControlType::DESTINATION, RTFKeyword::USERPROPS, 0 },
+ { "usexform", RTFControlType::FLAG, RTFKeyword::USEXFORM, 0 },
+ { "utinl", RTFControlType::FLAG, RTFKeyword::UTINL, 0 },
+ { "v", RTFControlType::TOGGLE, RTFKeyword::V, 1 },
+ { "validatexml", RTFControlType::VALUE, RTFKeyword::VALIDATEXML, 0 },
+ { "vern", RTFControlType::VALUE, RTFKeyword::VERN, 0 },
+ { "version", RTFControlType::VALUE, RTFKeyword::VERSION, 0 },
+ { "vertal", RTFControlType::FLAG, RTFKeyword::VERTAL, 0 },
+ { "vertalb", RTFControlType::FLAG, RTFKeyword::VERTALB, 0 },
+ { "vertalc", RTFControlType::FLAG, RTFKeyword::VERTALC, 0 },
+ { "vertalj", RTFControlType::FLAG, RTFKeyword::VERTALJ, 0 },
+ { "vertalt", RTFControlType::FLAG, RTFKeyword::VERTALT, 0 },
+ { "vertdoc", RTFControlType::FLAG, RTFKeyword::VERTDOC, 0 },
+ { "vertsect", RTFControlType::FLAG, RTFKeyword::VERTSECT, 0 },
+ { "viewbksp", RTFControlType::VALUE, RTFKeyword::VIEWBKSP, 0 },
+ { "viewkind", RTFControlType::VALUE, RTFKeyword::VIEWKIND, 0 },
+ { "viewnobound", RTFControlType::FLAG, RTFKeyword::VIEWNOBOUND, 0 },
+ { "viewscale", RTFControlType::VALUE, RTFKeyword::VIEWSCALE, 100 },
+ { "viewzk", RTFControlType::VALUE, RTFKeyword::VIEWZK, 0 },
+ { "wbitmap", RTFControlType::VALUE, RTFKeyword::WBITMAP, 0 },
+ { "wbmbitspixel", RTFControlType::VALUE, RTFKeyword::WBMBITSPIXEL, 1 },
+ { "wbmplanes", RTFControlType::VALUE, RTFKeyword::WBMPLANES, 0 },
+ { "wbmwidthbyte", RTFControlType::VALUE, RTFKeyword::WBMWIDTHBYTE, 0 },
+ { "webhidden", RTFControlType::FLAG, RTFKeyword::WEBHIDDEN, 0 },
+ { "wgrffmtfilter", RTFControlType::DESTINATION, RTFKeyword::WGRFFMTFILTER, 0 },
+ { "widctlpar", RTFControlType::FLAG, RTFKeyword::WIDCTLPAR, 0 },
+ { "widowctrl", RTFControlType::FLAG, RTFKeyword::WIDOWCTRL, 0 },
+ { "windowcaption", RTFControlType::DESTINATION, RTFKeyword::WINDOWCAPTION, 0 },
+ { "wmetafile", RTFControlType::VALUE, RTFKeyword::WMETAFILE, 1 },
+ { "wpeqn", RTFControlType::FLAG, RTFKeyword::WPEQN, 0 },
+ { "wpjst", RTFControlType::FLAG, RTFKeyword::WPJST, 0 },
+ { "wpsp", RTFControlType::FLAG, RTFKeyword::WPSP, 0 },
+ { "wraparound", RTFControlType::FLAG, RTFKeyword::WRAPAROUND, 0 },
+ { "wrapdefault", RTFControlType::FLAG, RTFKeyword::WRAPDEFAULT, 0 },
+ { "wrapthrough", RTFControlType::FLAG, RTFKeyword::WRAPTHROUGH, 0 },
+ { "wraptight", RTFControlType::FLAG, RTFKeyword::WRAPTIGHT, 0 },
+ { "wraptrsp", RTFControlType::FLAG, RTFKeyword::WRAPTRSP, 0 },
+ { "writereservation", RTFControlType::DESTINATION, RTFKeyword::WRITERESERVATION, 0 },
+ { "writereservhash", RTFControlType::DESTINATION, RTFKeyword::WRITERESERVHASH, 0 },
+ { "wrppunct", RTFControlType::FLAG, RTFKeyword::WRPPUNCT, 0 },
+ { "xe", RTFControlType::DESTINATION, RTFKeyword::XE, 0 },
+ { "xef", RTFControlType::VALUE, RTFKeyword::XEF, 0 },
+ { "xform", RTFControlType::DESTINATION, RTFKeyword::XFORM, 0 },
+ { "xmlattr", RTFControlType::FLAG, RTFKeyword::XMLATTR, 0 },
+ { "xmlattrname", RTFControlType::DESTINATION, RTFKeyword::XMLATTRNAME, 0 },
+ { "xmlattrns", RTFControlType::VALUE, RTFKeyword::XMLATTRNS, 0 },
+ { "xmlattrvalue", RTFControlType::DESTINATION, RTFKeyword::XMLATTRVALUE, 0 },
+ { "xmlclose", RTFControlType::DESTINATION, RTFKeyword::XMLCLOSE, 0 },
+ { "xmlname", RTFControlType::DESTINATION, RTFKeyword::XMLNAME, 0 },
+ { "xmlns", RTFControlType::VALUE, RTFKeyword::XMLNS, 0 },
+ { "xmlnstbl", RTFControlType::DESTINATION, RTFKeyword::XMLNSTBL, 0 },
+ { "xmlopen", RTFControlType::DESTINATION, RTFKeyword::XMLOPEN, 0 },
+ { "xmlsdttcell", RTFControlType::FLAG, RTFKeyword::XMLSDTTCELL, 0 },
+ { "xmlsdttpara", RTFControlType::FLAG, RTFKeyword::XMLSDTTPARA, 0 },
+ { "xmlsdttregular", RTFControlType::FLAG, RTFKeyword::XMLSDTTREGULAR, 0 },
+ { "xmlsdttrow", RTFControlType::FLAG, RTFKeyword::XMLSDTTROW, 0 },
+ { "xmlsdttunknown", RTFControlType::FLAG, RTFKeyword::XMLSDTTUNKNOWN, 0 },
+ { "yr", RTFControlType::VALUE, RTFKeyword::YR, 0 },
+ { "yts", RTFControlType::VALUE, RTFKeyword::YTS, 0 },
+ { "yxe", RTFControlType::FLAG, RTFKeyword::YXE, 0 },
+ { "zwbo", RTFControlType::SYMBOL, RTFKeyword::ZWBO, 0 },
+ { "zwj", RTFControlType::SYMBOL, RTFKeyword::ZWJ, 0 },
+ { "zwnbo", RTFControlType::SYMBOL, RTFKeyword::ZWNBO, 0 },
+ { "zwnj", RTFControlType::SYMBOL, RTFKeyword::ZWNJ, 0 },
+ { "flymaincnt", RTFControlType::DESTINATION, RTFKeyword::FLYMAINCNT, 0 },
+ { "flyvert", RTFControlType::VALUE, RTFKeyword::FLYVERT, 0 },
+ { "flyhorz", RTFControlType::VALUE, RTFKeyword::FLYHORZ, 0 },
+ { "flyanchor", RTFControlType::VALUE, RTFKeyword::FLYANCHOR, 0 },
+};
+const int nRTFControlWords = SAL_N_ELEMENTS(aRTFControlWords);
+
+RTFMathSymbol const aRTFMathControlWords[] = {
+ // eKeyword nToken eDestination
+ { RTFKeyword::MOMATH, M_TOKEN(oMath), Destination::MOMATH },
+ { RTFKeyword::MF, M_TOKEN(f), Destination::MF },
+ { RTFKeyword::MFPR, M_TOKEN(fPr), Destination::MFPR },
+ { RTFKeyword::MCTRLPR, M_TOKEN(ctrlPr), Destination::MCTRLPR },
+ { RTFKeyword::MNUM, M_TOKEN(num), Destination::MNUM },
+ { RTFKeyword::MDEN, M_TOKEN(den), Destination::MDEN },
+ { RTFKeyword::MACC, M_TOKEN(acc), Destination::MACC },
+ { RTFKeyword::MACCPR, M_TOKEN(accPr), Destination::MACCPR },
+ { RTFKeyword::MBAR, M_TOKEN(bar), Destination::MBAR },
+ { RTFKeyword::MBARPR, M_TOKEN(barPr), Destination::MBARPR },
+ { RTFKeyword::ME, M_TOKEN(e), Destination::ME },
+ { RTFKeyword::MD, M_TOKEN(d), Destination::MD },
+ { RTFKeyword::MDPR, M_TOKEN(dPr), Destination::MDPR },
+ { RTFKeyword::MFUNC, M_TOKEN(func), Destination::MFUNC },
+ { RTFKeyword::MFUNCPR, M_TOKEN(funcPr), Destination::MFUNCPR },
+ { RTFKeyword::MFNAME, M_TOKEN(fName), Destination::MFNAME },
+ { RTFKeyword::MLIMLOW, M_TOKEN(limLow), Destination::MLIMLOW },
+ { RTFKeyword::MLIMLOWPR, M_TOKEN(limLowPr), Destination::MLIMLOWPR },
+ { RTFKeyword::MLIM, M_TOKEN(lim), Destination::MLIM },
+ { RTFKeyword::MM, M_TOKEN(m), Destination::MM },
+ { RTFKeyword::MMPR, M_TOKEN(mPr), Destination::MMPR },
+ { RTFKeyword::MMR, M_TOKEN(mr), Destination::MMR },
+ { RTFKeyword::MNARY, M_TOKEN(nary), Destination::MNARY },
+ { RTFKeyword::MNARYPR, M_TOKEN(naryPr), Destination::MNARYPR },
+ { RTFKeyword::MSUB, M_TOKEN(sub), Destination::MSUB },
+ { RTFKeyword::MSUP, M_TOKEN(sup), Destination::MSUP },
+ { RTFKeyword::MLIMUPP, M_TOKEN(limUpp), Destination::MLIMUPP },
+ { RTFKeyword::MLIMUPPPR, M_TOKEN(limUppPr), Destination::MLIMUPPPR },
+ { RTFKeyword::MGROUPCHR, M_TOKEN(groupChr), Destination::MGROUPCHR },
+ { RTFKeyword::MGROUPCHRPR, M_TOKEN(groupChrPr), Destination::MGROUPCHRPR },
+ { RTFKeyword::MBORDERBOX, M_TOKEN(borderBox), Destination::MBORDERBOX },
+ { RTFKeyword::MBORDERBOXPR, M_TOKEN(borderBoxPr), Destination::MBORDERBOXPR },
+ { RTFKeyword::MRAD, M_TOKEN(rad), Destination::MRAD },
+ { RTFKeyword::MRADPR, M_TOKEN(radPr), Destination::MRADPR },
+ { RTFKeyword::MDEG, M_TOKEN(deg), Destination::MDEG },
+ { RTFKeyword::MSSUB, M_TOKEN(sSub), Destination::MSSUB },
+ { RTFKeyword::MSSUBPR, M_TOKEN(sSubPr), Destination::MSSUBPR },
+ { RTFKeyword::MSSUP, M_TOKEN(sSup), Destination::MSSUP },
+ { RTFKeyword::MSSUPPR, M_TOKEN(sSupPr), Destination::MSSUPPR },
+ { RTFKeyword::MSSUBSUP, M_TOKEN(sSubSup), Destination::MSSUBSUP },
+ { RTFKeyword::MSSUBSUPPR, M_TOKEN(sSubSupPr), Destination::MSSUBSUPPR },
+ { RTFKeyword::MSPRE, M_TOKEN(sPre), Destination::MSPRE },
+ { RTFKeyword::MSPREPR, M_TOKEN(sPrePr), Destination::MSPREPR },
+ { RTFKeyword::MBOX, M_TOKEN(box), Destination::MBOX },
+ { RTFKeyword::MEQARR, M_TOKEN(eqArr), Destination::MEQARR },
+};
+const int nRTFMathControlWords = SAL_N_ELEMENTS(aRTFMathControlWords);
+
+bool RTFMathSymbol::operator<(const RTFMathSymbol& rOther) const
+{
+ return m_eKeyword < rOther.m_eKeyword;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfcontrolwords.hxx b/writerfilter/source/rtftok/rtfcontrolwords.hxx
new file mode 100644
index 000000000..c1480ffb0
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx
@@ -0,0 +1,2049 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+/**
+ * An RTF destination state is the last open destination control word.
+ *
+ * Note that this is not a 1:1 mapping between destination control
+ * words, e.g. RTF_PICT gets mapped to Destination::PICT or
+ * Destination::SHAPEPROPERTYVALUEPICT.
+ */
+enum class Destination
+{
+ NORMAL,
+ SKIP,
+ FONTTABLE,
+ FONTENTRY,
+ COLORTABLE,
+ STYLESHEET,
+ STYLEENTRY,
+ FIELD,
+ FIELDINSTRUCTION,
+ FIELDRESULT,
+ LISTTABLE,
+ LISTPICTURE,
+ LISTENTRY,
+ LISTNAME,
+ LISTOVERRIDETABLE,
+ LISTOVERRIDEENTRY,
+ LISTLEVEL,
+ LEVELTEXT,
+ LEVELNUMBERS,
+ SHPPICT,
+ PICT,
+ PICPROP,
+ SHAPEPROPERTY,
+ SHAPEPROPERTYNAME,
+ SHAPEPROPERTYVALUE,
+ SHAPE,
+ SHAPEINSTRUCTION,
+ SHAPEPROPERTYVALUEPICT,
+ NESTEDTABLEPROPERTIES,
+ FOOTNOTE,
+ BOOKMARKSTART,
+ BOOKMARKEND,
+ REVISIONTABLE,
+ REVISIONENTRY,
+ SHAPETEXT,
+ FORMFIELD,
+ FORMFIELDNAME,
+ FORMFIELDLIST,
+ DATAFIELD,
+ INFO,
+ CREATIONTIME,
+ REVISIONTIME,
+ PRINTTIME,
+ AUTHOR,
+ KEYWORDS,
+ OPERATOR,
+ COMPANY,
+ COMMENT,
+ OBJECT,
+ OBJDATA,
+ OBJCLASS,
+ RESULT,
+ ANNOTATIONDATE,
+ ANNOTATIONAUTHOR,
+ ANNOTATIONREFERENCE,
+ FALT,
+ FLYMAINCONTENT,
+ DRAWINGOBJECT,
+ PARAGRAPHNUMBERING,
+ PARAGRAPHNUMBERING_TEXTBEFORE,
+ PARAGRAPHNUMBERING_TEXTAFTER,
+ TITLE,
+ SUBJECT,
+ DOCCOMM,
+ ATNID,
+ ANNOTATIONREFERENCESTART,
+ ANNOTATIONREFERENCEEND,
+ MOMATH,
+ MR,
+ MF,
+ MFPR,
+ MCTRLPR,
+ MNUM,
+ MDEN,
+ MACC,
+ MACCPR,
+ MCHR,
+ MPOS,
+ MVERTJC,
+ MSTRIKEH,
+ MDEGHIDE,
+ ME,
+ MBAR,
+ MBARPR,
+ MD,
+ MDPR,
+ MBEGCHR,
+ MSEPCHR,
+ MENDCHR,
+ MFUNC,
+ MFUNCPR,
+ MFNAME,
+ MLIMLOW,
+ MLIMLOWPR,
+ MLIM,
+ MM,
+ MMPR,
+ MMR,
+ MNARY,
+ MNARYPR,
+ MSUB,
+ MSUP,
+ MSUBHIDE,
+ MSUPHIDE,
+ MLIMUPP,
+ MLIMUPPPR,
+ MGROUPCHR,
+ MGROUPCHRPR,
+ MBORDERBOX,
+ MBORDERBOXPR,
+ MRAD,
+ MRADPR,
+ MDEG,
+ MSSUB,
+ MSSUBPR,
+ MSSUP,
+ MSSUPPR,
+ MSSUBSUP,
+ MSSUBSUPPR,
+ MSPRE,
+ MSPREPR,
+ MTYPE,
+ MGROW,
+ MBOX,
+ MEQARR,
+ UPR,
+ LFOLEVEL,
+ BACKGROUND,
+ SHAPEGROUP,
+ FOOTNOTESEPARATOR,
+ INDEXENTRY,
+ TOCENTRY,
+ USERPROPS,
+ PROPNAME,
+ STATICVAL,
+ GENERATOR,
+ DOCVAR,
+};
+
+enum class RTFKeyword
+{
+ invalid = -1,
+ HEXCHAR,
+ OPTHYPH,
+ IGNORE,
+ SUBENTRY,
+ BACKSLASH,
+ NOBRKHYPH,
+ LBRACE,
+ FORMULA,
+ RBRACE,
+ NOBREAK,
+ AB,
+ ABSH,
+ ABSLOCK,
+ ABSNOOVRLP,
+ ABSW,
+ ACAPS,
+ ACCCIRCLE,
+ ACCCOMMA,
+ ACCDOT,
+ ACCNONE,
+ ACCUNDERDOT,
+ ACF,
+ ADEFF,
+ ADDITIVE,
+ ADEFLANG,
+ ADJUSTRIGHT,
+ ADN,
+ AENDDOC,
+ AENDNOTES,
+ AEXPND,
+ AF,
+ AFELEV,
+ AFS,
+ AFTNBJ,
+ AFTNCN,
+ AFTNNALC,
+ AFTNNAR,
+ AFTNNAUC,
+ AFTNNCHI,
+ AFTNNCHOSUNG,
+ AFTNNCNUM,
+ AFTNNDBAR,
+ AFTNNDBNUM,
+ AFTNNDBNUMD,
+ AFTNNDBNUMK,
+ AFTNNDBNUMT,
+ AFTNNGANADA,
+ AFTNNGBNUM,
+ AFTNNGBNUMD,
+ AFTNNGBNUMK,
+ AFTNNGBNUML,
+ AFTNNRLC,
+ AFTNNRUC,
+ AFTNNZODIAC,
+ AFTNNZODIACD,
+ AFTNNZODIACL,
+ AFTNRESTART,
+ AFTNRSTCONT,
+ AFTNSEP,
+ AFTNSEPC,
+ AFTNSTART,
+ AFTNTJ,
+ AI,
+ ALANG,
+ ALLOWFIELDENDSEL,
+ ALLPROT,
+ ALNTBLIND,
+ ALT,
+ ANIMTEXT,
+ ANNOTATION,
+ ANNOTPROT,
+ ANSI,
+ ANSICPG,
+ AOUTL,
+ APPLYBRKRULES,
+ ASCAPS,
+ ASHAD,
+ ASIANBRKRULE,
+ ASPALPHA,
+ ASPNUM,
+ ASTRIKE,
+ ATNAUTHOR,
+ ATNDATE,
+ ATNICN,
+ ATNID,
+ ATNPARENT,
+ ATNREF,
+ ATNTIME,
+ ATRFEND,
+ ATRFSTART,
+ AUL,
+ AULD,
+ AULDB,
+ AULNONE,
+ AULW,
+ AUP,
+ AUTHOR,
+ AUTOFMTOVERRIDE,
+ B,
+ BACKGROUND,
+ BDBFHDR,
+ BDRRLSWSIX,
+ BGBDIAG,
+ BGCROSS,
+ BGDCROSS,
+ BGDKBDIAG,
+ BGDKCROSS,
+ BGDKDCROSS,
+ BGDKFDIAG,
+ BGDKHORIZ,
+ BGDKVERT,
+ BGFDIAG,
+ BGHORIZ,
+ BGVERT,
+ BIN,
+ BINFSXN,
+ BINSXN,
+ BKMKCOLF,
+ BKMKCOLL,
+ BKMKEND,
+ BKMKPUB,
+ BKMKSTART,
+ BLIPTAG,
+ BLIPUID,
+ BLIPUPI,
+ BLUE,
+ BOOKFOLD,
+ BOOKFOLDREV,
+ BOOKFOLDSHEETS,
+ BOX,
+ BRDRART,
+ BRDRB,
+ BRDRBAR,
+ BRDRBTW,
+ BRDRCF,
+ BRDRDASH,
+ BRDRDASHD,
+ BRDRDASHDD,
+ BRDRDASHDOTSTR,
+ BRDRDASHSM,
+ BRDRDB,
+ BRDRDOT,
+ BRDREMBOSS,
+ BRDRENGRAVE,
+ BRDRFRAME,
+ BRDRHAIR,
+ BRDRINSET,
+ BRDRL,
+ BRDRNIL,
+ BRDRNONE,
+ BRDROUTSET,
+ BRDRR,
+ BRDRS,
+ BRDRSH,
+ BRDRT,
+ BRDRTBL,
+ BRDRTH,
+ BRDRTHTNLG,
+ BRDRTHTNMG,
+ BRDRTHTNSG,
+ BRDRTNTHLG,
+ BRDRTNTHMG,
+ BRDRTNTHSG,
+ BRDRTNTHTNLG,
+ BRDRTNTHTNMG,
+ BRDRTNTHTNSG,
+ BRDRTRIPLE,
+ BRDRW,
+ BRDRWAVY,
+ BRDRWAVYDB,
+ BRKFRM,
+ BRSP,
+ BULLET,
+ BUPTIM,
+ BXE,
+ CACCENTFIVE,
+ CACCENTFOUR,
+ CACCENTONE,
+ CACCENTSIX,
+ CACCENTTHREE,
+ CACCENTTWO,
+ CACHEDCOLBAL,
+ CAPS,
+ CATEGORY,
+ CB,
+ CBACKGROUNDONE,
+ CBACKGROUNDTWO,
+ CBPAT,
+ CCHS,
+ CELL,
+ CELLX,
+ CF,
+ CFOLLOWEDHYPERLINK,
+ CFPAT,
+ CGRID,
+ CHARRSID,
+ CHARSCALEX,
+ CHATN,
+ CHBGBDIAG,
+ CHBGCROSS,
+ CHBGDCROSS,
+ CHBGDKBDIAG,
+ CHBGDKCROSS,
+ CHBGDKDCROSS,
+ CHBGDKFDIAG,
+ CHBGDKHORIZ,
+ CHBGDKVERT,
+ CHBGFDIAG,
+ CHBGHORIZ,
+ CHBGVERT,
+ CHBRDR,
+ CHCBPAT,
+ CHCFPAT,
+ CHDATE,
+ CHDPA,
+ CHDPL,
+ CHFTN,
+ CHFTNSEP,
+ CHFTNSEPC,
+ CHPGN,
+ CHHRES,
+ CHSHDNG,
+ CHTIME,
+ CHYPERLINK,
+ CLBGBDIAG,
+ CLBGCROSS,
+ CLBGDCROSS,
+ CLBGDKBDIAG,
+ CLBGDKCROSS,
+ CLBGDKDCROSS,
+ CLBGDKFDIAG,
+ CLBGDKHOR,
+ CLBGDKVERT,
+ CLBGFDIAG,
+ CLBGHORIZ,
+ CLBGVERT,
+ CLBRDRB,
+ CLBRDRL,
+ CLBRDRR,
+ CLBRDRT,
+ CLCBPAT,
+ CLCBPATRAW,
+ CLCFPAT,
+ CLCFPATRAW,
+ CLDEL,
+ CLDELAUTH,
+ CLDELDTTM,
+ CLDGLL,
+ CLDGLU,
+ CLFITTEXT,
+ CLFTSWIDTH,
+ CLHIDEMARK,
+ CLINS,
+ CLINSAUTH,
+ CLINSDTTM,
+ CLMGF,
+ CLMRG,
+ CLMRGD,
+ CLMRGDAUTH,
+ CLMRGDDTTM,
+ CLMRGDR,
+ CLNOWRAP,
+ CLPADB,
+ CLPADFB,
+ CLPADFL,
+ CLPADFR,
+ CLPADFT,
+ CLPADL,
+ CLPADR,
+ CLPADT,
+ CLSPB,
+ CLSPFB,
+ CLSPFL,
+ CLSPFR,
+ CLSPFT,
+ CLSPL,
+ CLSPR,
+ CLSPT,
+ CLSHDNG,
+ CLSHDNGRAW,
+ CLSHDRAWNIL,
+ CLSPLIT,
+ CLSPLITR,
+ CLTXBTLR,
+ CLTXLRTB,
+ CLTXLRTBV,
+ CLTXTBRL,
+ CLTXTBRLV,
+ CLVERTALB,
+ CLVERTALC,
+ CLVERTALT,
+ CLVMGF,
+ CLVMRG,
+ CLWWIDTH,
+ CMAINDARKONE,
+ CMAINDARKTWO,
+ CMAINLIGHTONE,
+ CMAINLIGHTTWO,
+ COLLAPSED,
+ COLNO,
+ COLORSCHEMEMAPPING,
+ COLORTBL,
+ COLS,
+ COLSR,
+ COLSX,
+ COLUMN,
+ COLW,
+ COMMENT,
+ COMPANY,
+ CONTEXTUALSPACE,
+ CPG,
+ CRAUTH,
+ CRDATE,
+ CREATIM,
+ CS,
+ CSHADE,
+ CTEXTONE,
+ CTEXTTWO,
+ CTINT,
+ CTRL,
+ CTS,
+ CUFI,
+ CULI,
+ CURI,
+ CVMME,
+ DATAFIELD,
+ DATASTORE,
+ DATE,
+ DBCH,
+ DEFCHP,
+ DEFF,
+ DEFFORMAT,
+ DEFLANG,
+ DEFLANGFE,
+ DEFPAP,
+ DEFSHP,
+ DEFTAB,
+ DELETED,
+ DELRSID,
+ DFRAUTH,
+ DFRDATE,
+ DFRMTXTX,
+ DFRMTXTY,
+ DFRSTART,
+ DFRSTOP,
+ DFRXST,
+ DGHORIGIN,
+ DGHSHOW,
+ DGHSPACE,
+ DGMARGIN,
+ DGSNAP,
+ DGVORIGIN,
+ DGVSHOW,
+ DGVSPACE,
+ DIBITMAP,
+ DISABLED,
+ DN,
+ DNTBLNSBDB,
+ DO,
+ DOBXCOLUMN,
+ DOBXMARGIN,
+ DOBXPAGE,
+ DOBYMARGIN,
+ DOBYPAGE,
+ DOBYPARA,
+ DOCCOMM,
+ DOCTEMP,
+ DOCTYPE,
+ DOCVAR,
+ DODHGT,
+ DOLOCK,
+ DONOTEMBEDLINGDATA,
+ DONOTEMBEDSYSFONT,
+ DONOTSHOWCOMMENTS,
+ DONOTSHOWINSDEL,
+ DONOTSHOWMARKUP,
+ DONOTSHOWPROPS,
+ DPAENDHOL,
+ DPAENDL,
+ DPAENDSOL,
+ DPAENDW,
+ DPARC,
+ DPARCFLIPX,
+ DPARCFLIPY,
+ DPASTARTHOL,
+ DPASTARTL,
+ DPASTARTSOL,
+ DPASTARTW,
+ DPCALLOUT,
+ DPCOA,
+ DPCOACCENT,
+ DPCOBESTFIT,
+ DPCOBORDER,
+ DPCODABS,
+ DPCODBOTTOM,
+ DPCODCENTER,
+ DPCODESCENT,
+ DPCODTOP,
+ DPCOLENGTH,
+ DPCOMINUSX,
+ DPCOMINUSY,
+ DPCOOFFSET,
+ DPCOSMARTA,
+ DPCOTDOUBLE,
+ DPCOTRIGHT,
+ DPCOTSINGLE,
+ DPCOTTRIPLE,
+ DPCOUNT,
+ DPELLIPSE,
+ DPENDGROUP,
+ DPFILLBGCB,
+ DPFILLBGCG,
+ DPFILLBGCR,
+ DPFILLBGGRAY,
+ DPFILLBGPAL,
+ DPFILLFGCB,
+ DPFILLFGCG,
+ DPFILLFGCR,
+ DPFILLFGGRAY,
+ DPFILLFGPAL,
+ DPFILLPAT,
+ DPGROUP,
+ DPLINE,
+ DPLINECOB,
+ DPLINECOG,
+ DPLINECOR,
+ DPLINEDADO,
+ DPLINEDADODO,
+ DPLINEDASH,
+ DPLINEDOT,
+ DPLINEGRAY,
+ DPLINEHOLLOW,
+ DPLINEPAL,
+ DPLINESOLID,
+ DPLINEW,
+ DPPOLYCOUNT,
+ DPPOLYGON,
+ DPPOLYLINE,
+ DPPTX,
+ DPPTY,
+ DPRECT,
+ DPROUNDR,
+ DPSHADOW,
+ DPSHADX,
+ DPSHADY,
+ DPTXBTLR,
+ DPTXBX,
+ DPTXBXMAR,
+ DPTXBXTEXT,
+ DPTXLRTB,
+ DPTXLRTBV,
+ DPTXTBRL,
+ DPTXTBRLV,
+ DPX,
+ DPXSIZE,
+ DPY,
+ DPYSIZE,
+ DROPCAPLI,
+ DROPCAPT,
+ DS,
+ DXFRTEXT,
+ DY,
+ EBCEND,
+ EBCSTART,
+ EDMINS,
+ EMBO,
+ EMDASH,
+ EMFBLIP,
+ EMSPACE,
+ ENDASH,
+ ENDDOC,
+ ENDNHERE,
+ ENDNOTES,
+ ENFORCEPROT,
+ ENSPACE,
+ EXPND,
+ EXPNDTW,
+ EXPSHRTN,
+ F,
+ FAAUTO,
+ FACENTER,
+ FACINGP,
+ FACTOIDNAME,
+ FAFIXED,
+ FAHANG,
+ FALT,
+ FAROMAN,
+ FAVAR,
+ FBIAS,
+ FBIDI,
+ FBIDIS,
+ FBIMAJOR,
+ FBIMINOR,
+ FCHARS,
+ FCHARSET,
+ FCS,
+ FDBMAJOR,
+ FDBMINOR,
+ FDECOR,
+ FELNBRELEV,
+ FET,
+ FETCH,
+ FFDEFRES,
+ FFDEFTEXT,
+ FFENTRYMCR,
+ FFEXITMCR,
+ FFFORMAT,
+ FFHASLISTBOX,
+ FFHELPTEXT,
+ FFHPS,
+ FFL,
+ FFMAXLEN,
+ FFNAME,
+ FFOWNHELP,
+ FFOWNSTAT,
+ FFPROT,
+ FFRECALC,
+ FFRES,
+ FFSIZE,
+ FFSTATTEXT,
+ FFTYPE,
+ FFTYPETXT,
+ FHIMAJOR,
+ FHIMINOR,
+ FI,
+ FID,
+ FIELD,
+ FILE,
+ FILETBL,
+ FITTEXT,
+ FJGOTHIC,
+ FJMINCHOU,
+ FLDALT,
+ FLDDIRTY,
+ FLDEDIT,
+ FLDINST,
+ FLDLOCK,
+ FLDPRIV,
+ FLDRSLT,
+ FLDTYPE,
+ FLOMAJOR,
+ FLOMINOR,
+ FMODERN,
+ FN,
+ FNAME,
+ FNETWORK,
+ FNIL,
+ FNONFILESYS,
+ FONTEMB,
+ FONTFILE,
+ FONTTBL,
+ FOOTER,
+ FOOTERF,
+ FOOTERL,
+ FOOTERR,
+ FOOTERY,
+ FOOTNOTE,
+ FORCEUPGRADE,
+ FORMDISP,
+ FORMFIELD,
+ FORMPROT,
+ FORMSHADE,
+ FOSNUM,
+ FPRQ,
+ FRACWIDTH,
+ FRELATIVE,
+ FRMTXBTLR,
+ FRMTXLRTB,
+ FRMTXLRTBV,
+ FRMTXTBRL,
+ FRMTXTBRLV,
+ FROMAN,
+ FROMHTML,
+ FROMTEXT,
+ FS,
+ FSCRIPT,
+ FSWISS,
+ FTECH,
+ FTNALT,
+ FTNBJ,
+ FTNCN,
+ FTNIL,
+ FTNLYTWNINE,
+ FTNNALC,
+ FTNNAR,
+ FTNNAUC,
+ FTNNCHI,
+ FTNNCHOSUNG,
+ FTNNCNUM,
+ FTNNDBAR,
+ FTNNDBNUM,
+ FTNNDBNUMD,
+ FTNNDBNUMK,
+ FTNNDBNUMT,
+ FTNNGANADA,
+ FTNNGBNUM,
+ FTNNGBNUMD,
+ FTNNGBNUMK,
+ FTNNGBNUML,
+ FTNNRLC,
+ FTNNRUC,
+ FTNNZODIAC,
+ FTNNZODIACD,
+ FTNNZODIACL,
+ FTNRESTART,
+ FTNRSTCONT,
+ FTNRSTPG,
+ FTNSEP,
+ FTNSEPC,
+ FTNSTART,
+ FTNTJ,
+ FTTRUETYPE,
+ FVALIDDOS,
+ FVALIDHPFS,
+ FVALIDMAC,
+ FVALIDNTFS,
+ G,
+ GCW,
+ GENERATOR,
+ GREEN,
+ GRFDOCEVENTS,
+ GRIDTBL,
+ GUTTER,
+ GUTTERPRL,
+ GUTTERSXN,
+ HEADER,
+ HEADERF,
+ HEADERL,
+ HEADERR,
+ HEADERY,
+ HICH,
+ HIGHLIGHT,
+ HL,
+ HLFR,
+ HLINKBASE,
+ HLLOC,
+ HLSRC,
+ HORZDOC,
+ HORZSECT,
+ HORZVERT,
+ HR,
+ HRES,
+ HRULE,
+ HSV,
+ HTMAUTSP,
+ HTMLBASE,
+ HTMLRTF,
+ HTMLTAG,
+ HWELEV,
+ HYPHAUTO,
+ HYPHCAPS,
+ HYPHCONSEC,
+ HYPHHOTZ,
+ HYPHPAR,
+ I,
+ ID,
+ IGNOREMIXEDCONTENT,
+ ILFOMACATCLNUP,
+ ILVL,
+ IMPR,
+ INDMIRROR,
+ INDRLSWELEVEN,
+ INFO,
+ INSRSID,
+ INTBL,
+ IPGP,
+ IROWBAND,
+ IROW,
+ ITAP,
+ IXE,
+ JCOMPRESS,
+ JEXPAND,
+ JIS,
+ JPEGBLIP,
+ JSKSU,
+ KEEP,
+ KEEPN,
+ KERNING,
+ KEYCODE,
+ KEYWORDS,
+ KRNPRSNET,
+ KSULANG,
+ JCLISTTAB,
+ LANDSCAPE,
+ LANG,
+ LANGFE,
+ LANGFENP,
+ LANGNP,
+ LASTROW,
+ LATENTSTYLES,
+ LBR,
+ LCHARS,
+ LDBLQUOTE,
+ LEVEL,
+ LEVELFOLLOW,
+ LEVELINDENT,
+ LEVELJC,
+ LEVELJCN,
+ LEVELLEGAL,
+ LEVELNFC,
+ LEVELNFCN,
+ LEVELNORESTART,
+ LEVELNUMBERS,
+ LEVELOLD,
+ LEVELPICTURE,
+ LEVELPICTURENOSIZE,
+ LEVELPREV,
+ LEVELPREVSPACE,
+ LEVELSPACE,
+ LEVELSTARTAT,
+ LEVELTEMPLATEID,
+ LEVELTEXT,
+ LFOLEVEL,
+ LI,
+ LINE,
+ LINEBETCOL,
+ LINECONT,
+ LINEMOD,
+ LINEPPAGE,
+ LINERESTART,
+ LINESTART,
+ LINESTARTS,
+ LINEX,
+ LINKSELF,
+ LINKSTYLES,
+ LINKVAL,
+ LIN,
+ LISA,
+ LISB,
+ LIST,
+ LISTHYBRID,
+ LISTID,
+ LISTLEVEL,
+ LISTNAME,
+ LISTOVERRIDE,
+ LISTOVERRIDECOUNT,
+ LISTOVERRIDEFORMAT,
+ LISTOVERRIDESTARTAT,
+ LISTOVERRIDETABLE,
+ LISTPICTURE,
+ LISTRESTARTHDN,
+ LISTSIMPLE,
+ LISTSTYLEID,
+ LISTSTYLENAME,
+ LISTTABLE,
+ LISTTEMPLATEID,
+ LISTTEXT,
+ LNBRKRULE,
+ LNDSCPSXN,
+ LNONGRID,
+ LOCH,
+ LQUOTE,
+ LS,
+ LSDLOCKED,
+ LSDLOCKEDDEF,
+ LSDLOCKEDEXCEPT,
+ LSDPRIORITY,
+ LSDPRIORITYDEF,
+ LSDQFORMAT,
+ LSDQFORMATDEF,
+ LSDSEMIHIDDEN,
+ LSDSEMIHIDDENDEF,
+ LSDSTIMAX,
+ LSDUNHIDEUSED,
+ LSDUNHIDEUSEDDEF,
+ LTRCH,
+ LTRDOC,
+ LTRMARK,
+ LTRPAR,
+ LTRROW,
+ LTRSECT,
+ LVLTENTATIVE,
+ LYTCALCTBLWD,
+ LYTEXCTTP,
+ LYTPRTMET,
+ LYTTBLRTGR,
+ MAC,
+ MACC,
+ MACCPR,
+ MACPICT,
+ MAILMERGE,
+ MAKEBACKUP,
+ MALN,
+ MALNSCR,
+ MANAGER,
+ MARGB,
+ MARGBSXN,
+ MARGL,
+ MARGLSXN,
+ MARGMIRROR,
+ MARGMIRSXN,
+ MARGPR,
+ MARGR,
+ MARGRSXN,
+ MARGSZ,
+ MARGT,
+ MARGTSXN,
+ MBAR,
+ MBARPR,
+ MBASEJC,
+ MBEGCHR,
+ MBORDERBOX,
+ MBORDERBOXPR,
+ MBOX,
+ MBOXPR,
+ MBRK,
+ MBRKBIN,
+ MBRKBINSUB,
+ MCGP,
+ MCGPRULE,
+ MCHR,
+ MCOUNT,
+ MCSP,
+ MCTRLPR,
+ MD,
+ MDEFJC,
+ MDEG,
+ MDEGHIDE,
+ MDEN,
+ MDIFF,
+ MDIFFSTY,
+ MDISPDEF,
+ MDPR,
+ ME,
+ MENDCHR,
+ MEQARR,
+ MEQARRPR,
+ MF,
+ MFNAME,
+ MFPR,
+ MFUNC,
+ MFUNCPR,
+ MGROUPCHR,
+ MGROUPCHRPR,
+ MGROW,
+ MHIDEBOT,
+ MHIDELEFT,
+ MHIDERIGHT,
+ MHIDETOP,
+ MHTMLTAG,
+ MIN,
+ MINTERSP,
+ MINTLIM,
+ MINTRASP,
+ MJC,
+ MLIM,
+ MLIMLOC,
+ MLIMLOW,
+ MLIMLOWPR,
+ MLIMUPP,
+ MLIMUPPPR,
+ MLIT,
+ MLMARGIN,
+ MM,
+ MMADDFIELDNAME,
+ MMATH,
+ MMATHFONT,
+ MMATHPICT,
+ MMATHPR,
+ MMATTACH,
+ MMAXDIST,
+ MMBLANKLINES,
+ MMC,
+ MMCJC,
+ MMCONNECTSTR,
+ MMCONNECTSTRDATA,
+ MMCPR,
+ MMCS,
+ MMDATASOURCE,
+ MMDATATYPEACCESS,
+ MMDATATYPEEXCEL,
+ MMDATATYPEFILE,
+ MMDATATYPEODBC,
+ MMDATATYPEODSO,
+ MMDATATYPEQT,
+ MMDEFAULTSQL,
+ MMDESTEMAIL,
+ MMDESTFAX,
+ MMDESTNEWDOC,
+ MMDESTPRINTER,
+ MMERRORS,
+ MMFTTYPEADDRESS,
+ MMFTTYPEBARCODE,
+ MMFTTYPEDBCOLUMN,
+ MMFTTYPEMAPPED,
+ MMFTTYPENULL,
+ MMFTTYPESALUTATION,
+ MMHEADERSOURCE,
+ MMJDSOTYPE,
+ MMLINKTOQUERY,
+ MMMAILSUBJECT,
+ MMMAINTYPECATALOG,
+ MMMAINTYPEEMAIL,
+ MMMAINTYPEENVELOPES,
+ MMMAINTYPEFAX,
+ MMMAINTYPELABELS,
+ MMMAINTYPELETTERS,
+ MMODSO,
+ MMODSOACTIVE,
+ MMODSOCOLDELIM,
+ MMODSOCOLUMN,
+ MMODSODYNADDR,
+ MMODSOFHDR,
+ MMODSOFILTER,
+ MMODSOFLDMPDATA,
+ MMODSOFMCOLUMN,
+ MMODSOHASH,
+ MMODSOLID,
+ MMODSOMAPPEDNAME,
+ MMODSONAME,
+ MMODSORECIPDATA,
+ MMODSOSORT,
+ MMODSOSRC,
+ MMODSOTABLE,
+ MMODSOUDL,
+ MMODSOUDLDATA,
+ MMODSOUNIQUETAG,
+ MMPR,
+ MMQUERY,
+ MMR,
+ MMRECCUR,
+ MMSHOWDATA,
+ MNARY,
+ MNARYLIM,
+ MNARYPR,
+ MNOBREAK,
+ MNOR,
+ MNUM,
+ MO,
+ MOBJDIST,
+ MOMATH,
+ MOMATHPARA,
+ MOMATHPARAPR,
+ MOPEMU,
+ MPHANT,
+ MPHANTPR,
+ MPLCHIDE,
+ MPOS,
+ MPOSTSP,
+ MPRESP,
+ MR,
+ MRAD,
+ MRADPR,
+ MRMARGIN,
+ MRPR,
+ MRSP,
+ MRSPRULE,
+ MSCR,
+ MSEPCHR,
+ MSHOW,
+ MSHP,
+ MSMALLFRAC,
+ MSMCAP,
+ MSPRE,
+ MSPREPR,
+ MSSUB,
+ MSSUBPR,
+ MSSUBSUP,
+ MSSUBSUPPR,
+ MSSUP,
+ MSSUPPR,
+ MSTRIKEBLTR,
+ MSTRIKEH,
+ MSTRIKETLBR,
+ MSTRIKEV,
+ MSTY,
+ MSUB,
+ MSUBHIDE,
+ MSUP,
+ MSUPHIDE,
+ MTRANSP,
+ MTYPE,
+ MUSER,
+ MVAUTH,
+ MVDATE,
+ MVERTJC,
+ MVF,
+ MVFMF,
+ MVFML,
+ MVT,
+ MVTOF,
+ MVTOL,
+ MWRAPINDENT,
+ MWRAPRIGHT,
+ MZEROASC,
+ MZERODESC,
+ MZEROWID,
+ NESTCELL,
+ NESTROW,
+ NESTTABLEPROPS,
+ NEWTBLSTYRULS,
+ NEXTFILE,
+ NOAFCNSTTBL,
+ NOBRKWRPTBL,
+ NOCOLBAL,
+ NOCOMPATOPTIONS,
+ NOCWRAP,
+ NOCXSPTABLE,
+ NOEXTRASPRL,
+ NOFCHARS,
+ NOFCHARSWS,
+ NOFEATURETHROTTLE,
+ NOFPAGES,
+ NOFWORDS,
+ NOGROWAUTOFIT,
+ NOINDNMBRTS,
+ NOJKERNPUNCT,
+ NOLEAD,
+ NOLINE,
+ NOLNHTADJTBL,
+ NONESTTABLES,
+ NONSHPPICT,
+ NOOVERFLOW,
+ NOPROOF,
+ NOQFPROMOTE,
+ NOSECTEXPAND,
+ NOSNAPLINEGRID,
+ NOSPACEFORUL,
+ NOSUPERSUB,
+ NOTABIND,
+ NOTBRKCNSTFRCTBL,
+ NOTCVASP,
+ NOTVATXBX,
+ NOUICOMPAT,
+ NOULTRLSPC,
+ NOWIDCTLPAR,
+ NOWRAP,
+ NOWWRAP,
+ NOXLATTOYEN,
+ OBJALIAS,
+ OBJALIGN,
+ OBJATTPH,
+ OBJAUTLINK,
+ OBJCLASS,
+ OBJCROPB,
+ OBJCROPL,
+ OBJCROPR,
+ OBJCROPT,
+ OBJDATA,
+ OBJECT,
+ OBJEMB,
+ OBJH,
+ OBJHTML,
+ OBJICEMB,
+ OBJLINK,
+ OBJLOCK,
+ OBJNAME,
+ OBJOCX,
+ OBJPUB,
+ OBJSCALEX,
+ OBJSCALEY,
+ OBJSECT,
+ OBJSETSIZE,
+ OBJSUB,
+ OBJTIME,
+ OBJTRANSY,
+ OBJUPDATE,
+ OBJW,
+ OGUTTER,
+ OLDAS,
+ OLDCPROPS,
+ OLDLINEWRAP,
+ OLDPPROPS,
+ OLDSPROPS,
+ OLDTPROPS,
+ OLECLSID,
+ OPERATOR,
+ OTBLRUL,
+ OUTL,
+ OUTLINELEVEL,
+ OVERLAY,
+ PAGE,
+ PAGEBB,
+ PANOSE,
+ PAPERH,
+ PAPERW,
+ PAR,
+ PARARSID,
+ PARD,
+ PASSWORD,
+ PASSWORDHASH,
+ PC,
+ PCA,
+ PGBRDRB,
+ PGBRDRFOOT,
+ PGBRDRHEAD,
+ PGBRDRL,
+ PGBRDROPT,
+ PGBRDRR,
+ PGBRDRSNAP,
+ PGBRDRT,
+ PGHSXN,
+ PGNBIDIA,
+ PGNBIDIB,
+ PGNCHOSUNG,
+ PGNCNUM,
+ PGNCONT,
+ PGNDBNUM,
+ PGNDBNUMD,
+ PGNDBNUMK,
+ PGNDBNUMT,
+ PGNDEC,
+ PGNDECD,
+ PGNGANADA,
+ PGNGBNUM,
+ PGNGBNUMD,
+ PGNGBNUMK,
+ PGNGBNUML,
+ PGNHINDIA,
+ PGNHINDIB,
+ PGNHINDIC,
+ PGNHINDID,
+ PGNHN,
+ PGNHNSC,
+ PGNHNSH,
+ PGNHNSM,
+ PGNHNSN,
+ PGNHNSP,
+ PGNID,
+ PGNLCLTR,
+ PGNLCRM,
+ PGNRESTART,
+ PGNSTART,
+ PGNSTARTS,
+ PGNTHAIA,
+ PGNTHAIB,
+ PGNTHAIC,
+ PGNUCLTR,
+ PGNUCRM,
+ PGNVIETA,
+ PGNX,
+ PGNY,
+ PGNZODIAC,
+ PGNZODIACD,
+ PGNZODIACL,
+ PGP,
+ PGPTBL,
+ PGWSXN,
+ PHCOL,
+ PHMRG,
+ PHPG,
+ PICBMP,
+ PICBPP,
+ PICCROPB,
+ PICCROPL,
+ PICCROPR,
+ PICCROPT,
+ PICH,
+ PICHGOAL,
+ PICPROP,
+ PICSCALED,
+ PICSCALEX,
+ PICSCALEY,
+ PICT,
+ PICW,
+ PICWGOAL,
+ PINDTABQC,
+ PINDTABQL,
+ PINDTABQR,
+ PLAIN,
+ PMARTABQC,
+ PMARTABQL,
+ PMARTABQR,
+ PMMETAFILE,
+ PN,
+ PNACROSS,
+ PNAIU,
+ PNAIUD,
+ PNAIUEO,
+ PNAIUEOD,
+ PNB,
+ PNBIDIA,
+ PNBIDIB,
+ PNCAPS,
+ PNCARD,
+ PNCF,
+ PNCHOSUNG,
+ PNCNUM,
+ PNDBNUM,
+ PNDBNUMD,
+ PNDBNUMK,
+ PNDBNUML,
+ PNDBNUMT,
+ PNDEC,
+ PNDECD,
+ PNF,
+ PNFS,
+ PNGANADA,
+ PNGBLIP,
+ PNGBNUM,
+ PNGBNUMD,
+ PNGBNUMK,
+ PNGBNUML,
+ PNHANG,
+ PNI,
+ PNINDENT,
+ PNIROHA,
+ PNIROHAD,
+ PNLCLTR,
+ PNLCRM,
+ PNLVL,
+ PNLVLBLT,
+ PNLVLBODY,
+ PNLVLCONT,
+ PNNUMONCE,
+ PNORD,
+ PNORDT,
+ PNPREV,
+ PNQC,
+ PNQL,
+ PNQR,
+ PNRAUTH,
+ PNRDATE,
+ PNRESTART,
+ PNRNFC,
+ PNRNOT,
+ PNRPNBR,
+ PNRRGB,
+ PNRSTART,
+ PNRSTOP,
+ PNRXST,
+ PNSCAPS,
+ PNSECLVL,
+ PNSP,
+ PNSTART,
+ PNSTRIKE,
+ PNTEXT,
+ PNTXTA,
+ PNTXTB,
+ PNUCLTR,
+ PNUCRM,
+ PNUL,
+ PNULD,
+ PNULDASH,
+ PNULDASHD,
+ PNULDASHDD,
+ PNULDB,
+ PNULHAIR,
+ PNULNONE,
+ PNULTH,
+ PNULW,
+ PNULWAVE,
+ PNZODIAC,
+ PNZODIACD,
+ PNZODIACL,
+ POSNEGX,
+ POSNEGY,
+ POSX,
+ POSXC,
+ POSXI,
+ POSXL,
+ POSXO,
+ POSXR,
+ POSY,
+ POSYB,
+ POSYC,
+ POSYIL,
+ POSYIN,
+ POSYOUT,
+ POSYT,
+ PRAUTH,
+ PRCOLBL,
+ PRDATE,
+ PRINTDATA,
+ PRINTIM,
+ PRIVATE,
+ PROPNAME,
+ PROPTYPE,
+ PROTECT,
+ PROTEND,
+ PROTLEVEL,
+ PROTSTART,
+ PROTUSERTBL,
+ PSOVER,
+ PSZ,
+ PTABLDOT,
+ PTABLMDOT,
+ PTABLMINUS,
+ PTABLNONE,
+ PTABLUSCORE,
+ PUBAUTO,
+ PVMRG,
+ PVPARA,
+ PVPG,
+ PWD,
+ PXE,
+ QC,
+ QD,
+ QJ,
+ QK,
+ QL,
+ QMSPACE,
+ QR,
+ QT,
+ RAWCLBGDKBDIAG,
+ RAWCLBGBDIAG,
+ RAWCLBGCROSS,
+ RAWCLBGDCROSS,
+ RAWCLBGDKCROSS,
+ RAWCLBGDKDCROSS,
+ RAWCLBGDKFDIAG,
+ RAWCLBGDKHOR,
+ RAWCLBGDKVERT,
+ RAWCLBGFDIAG,
+ RAWCLBGHORIZ,
+ RAWCLBGVERT,
+ RDBLQUOTE,
+ READONLYRECOMMENDED,
+ READPROT,
+ RED,
+ RELYONVML,
+ REMDTTM,
+ REMPERSONALINFO,
+ RESULT,
+ REVAUTH,
+ REVAUTHDEL,
+ REVBAR,
+ REVDTTM,
+ REVDTTMDEL,
+ REVISED,
+ REVISIONS,
+ REVPROP,
+ REVPROT,
+ REVTBL,
+ REVTIM,
+ RI,
+ RIN,
+ ROW,
+ RQUOTE,
+ RSID,
+ RSIDROOT,
+ RSIDTBL,
+ RSLTBMP,
+ RSLTHTML,
+ RSLTMERGE,
+ RSLTPICT,
+ RSLTRTF,
+ RSLTTXT,
+ RTF,
+ RTLCH,
+ RTLDOC,
+ RTLGUTTER,
+ RTLMARK,
+ RTLPAR,
+ RTLROW,
+ RTLSECT,
+ RXE,
+ S,
+ SA,
+ SAAUTO,
+ SAFTNNALC,
+ SAFTNNAR,
+ SAFTNNAUC,
+ SAFTNNCHI,
+ SAFTNNCHOSUNG,
+ SAFTNNCNUM,
+ SAFTNNDBAR,
+ SAFTNNDBNUM,
+ SAFTNNDBNUMD,
+ SAFTNNDBNUMK,
+ SAFTNNDBNUMT,
+ SAFTNNGANADA,
+ SAFTNNGBNUM,
+ SAFTNNGBNUMD,
+ SAFTNNGBNUMK,
+ SAFTNNGBNUML,
+ SAFTNNRLC,
+ SAFTNNRUC,
+ SAFTNNZODIAC,
+ SAFTNNZODIACD,
+ SAFTNNZODIACL,
+ SAFTNRESTART,
+ SAFTNRSTCONT,
+ SAFTNSTART,
+ SAUTOUPD,
+ SAVEINVALIDXML,
+ SAVEPREVPICT,
+ SB,
+ SBASEDON,
+ SBAUTO,
+ SBKCOL,
+ SBKEVEN,
+ SBKNONE,
+ SBKODD,
+ SBKPAGE,
+ SBYS,
+ SCAPS,
+ SCOMPOSE,
+ SEC,
+ SECT,
+ SECTD,
+ SECTDEFAULTCL,
+ SECTEXPAND,
+ SECTLINEGRID,
+ SECTNUM,
+ SECTRSID,
+ SECTSPECIFYCL,
+ SECTSPECIFYGENN,
+ SECTSPECIFYL,
+ SECTUNLOCKED,
+ SFTNBJ,
+ SFTNNALC,
+ SFTNNAR,
+ SFTNNAUC,
+ SFTNNCHI,
+ SFTNNCHOSUNG,
+ SFTNNCNUM,
+ SFTNNDBAR,
+ SFTNNDBNUM,
+ SFTNNDBNUMD,
+ SFTNNDBNUMK,
+ SFTNNDBNUMT,
+ SFTNNGANADA,
+ SFTNNGBNUM,
+ SFTNNGBNUMD,
+ SFTNNGBNUMK,
+ SFTNNGBNUML,
+ SFTNNRLC,
+ SFTNNRUC,
+ SFTNNZODIAC,
+ SFTNNZODIACD,
+ SFTNNZODIACL,
+ SFTNRESTART,
+ SFTNRSTCONT,
+ SFTNRSTPG,
+ SFTNSTART,
+ SFTNTJ,
+ SHAD,
+ SHADING,
+ SHIDDEN,
+ SHIFT,
+ SHOWPLACEHOLDTEXT,
+ SHOWXMLERRORS,
+ SHP,
+ SHPBOTTOM,
+ SHPBXCOLUMN,
+ SHPBXIGNORE,
+ SHPBXMARGIN,
+ SHPBXPAGE,
+ SHPBYIGNORE,
+ SHPBYMARGIN,
+ SHPBYPAGE,
+ SHPBYPARA,
+ SHPFBLWTXT,
+ SHPFHDR,
+ SHPGRP,
+ SHPINST,
+ SHPLEFT,
+ SHPLID,
+ SHPLOCKANCHOR,
+ SHPPICT,
+ SHPRIGHT,
+ SHPRSLT,
+ SHPTOP,
+ SHPTXT,
+ SHPWRK,
+ SHPWR,
+ SHPZ,
+ SL,
+ SLINK,
+ SLMULT,
+ SLOCKED,
+ SN,
+ SNAPTOGRIDINCELL,
+ SNEXT,
+ SOFTCOL,
+ SOFTLHEIGHT,
+ SOFTLINE,
+ SOFTPAGE,
+ SP,
+ SPERSONAL,
+ SPLTPGPAR,
+ SPLYTWNINE,
+ SPRIORITY,
+ SPRSBSP,
+ SPRSLNSP,
+ SPRSSPBF,
+ SPRSTSM,
+ SPRSTSP,
+ SPV,
+ SQFORMAT,
+ SRAUTH,
+ SRDATE,
+ SREPLY,
+ SSEMIHIDDEN,
+ STATICVAL,
+ STEXTFLOW,
+ STRIKE,
+ STRIKED,
+ STSHFBI,
+ STSHFDBCH,
+ STSHFHICH,
+ STSHFLOCH,
+ STYLELOCK,
+ STYLELOCKBACKCOMP,
+ STYLELOCKENFORCED,
+ STYLELOCKQFSET,
+ STYLELOCKTHEME,
+ STYLESHEET,
+ STYLESORTMETHOD,
+ STYRSID,
+ SUB,
+ SUBDOCUMENT,
+ SUBFONTBYSIZE,
+ SUBJECT,
+ SUNHIDEUSED,
+ SUPER,
+ SV,
+ SVB,
+ SWPBDR,
+ TAB,
+ TABSNOOVRLP,
+ TAPRTL,
+ TB,
+ TBLIND,
+ TBLINDTYPE,
+ TBLLKBESTFIT,
+ TBLLKBORDER,
+ TBLLKCOLOR,
+ TBLLKFONT,
+ TBLLKHDRCOLS,
+ TBLLKHDRROWS,
+ TBLLKLASTCOL,
+ TBLLKLASTROW,
+ TBLLKNOCOLBAND,
+ TBLLKNOROWBAND,
+ TBLLKSHADING,
+ TBLRSID,
+ TC,
+ TCELLD,
+ TCF,
+ TCL,
+ TCN,
+ TDFRMTXTBOTTOM,
+ TDFRMTXTLEFT,
+ TDFRMTXTRIGHT,
+ TDFRMTXTTOP,
+ TEMPLATE,
+ THEMEDATA,
+ THEMELANG,
+ THEMELANGCS,
+ THEMELANGFE,
+ TIME,
+ TITLE,
+ TITLEPG,
+ TLDOT,
+ TLEQ,
+ TLHYPH,
+ TLMDOT,
+ TLTH,
+ TLUL,
+ TOPLINEPUNCT,
+ TPHCOL,
+ TPHMRG,
+ TPHPG,
+ TPOSNEGX,
+ TPOSNEGY,
+ TPOSXC,
+ TPOSXI,
+ TPOSXL,
+ TPOSX,
+ TPOSXO,
+ TPOSXR,
+ TPOSY,
+ TPOSYB,
+ TPOSYC,
+ TPOSYIL,
+ TPOSYIN,
+ TPOSYOUT,
+ TPOSYT,
+ TPVMRG,
+ TPVPARA,
+ TPVPG,
+ TQC,
+ TQDEC,
+ TQR,
+ TRACKFORMATTING,
+ TRACKMOVES,
+ TRANSMF,
+ TRAUTH,
+ TRAUTOFIT,
+ TRBGBDIAG,
+ TRBGCROSS,
+ TRBGDCROSS,
+ TRBGDKBDIAG,
+ TRBGDKCROSS,
+ TRBGDKDCROSS,
+ TRBGDKFDIAG,
+ TRBGDKHOR,
+ TRBGDKVERT,
+ TRBGFDIAG,
+ TRBGHORIZ,
+ TRBGVERT,
+ TRBRDRB,
+ TRBRDRH,
+ TRBRDRL,
+ TRBRDRR,
+ TRBRDRT,
+ TRBRDRV,
+ TRCBPAT,
+ TRCFPAT,
+ TRDATE,
+ TRFTSWIDTHA,
+ TRFTSWIDTHB,
+ TRFTSWIDTH,
+ TRGAPH,
+ TRHDR,
+ TRKEEP,
+ TRKEEPFOLLOW,
+ TRLEFT,
+ TROWD,
+ TRPADDB,
+ TRPADDFB,
+ TRPADDFL,
+ TRPADDFR,
+ TRPADDFT,
+ TRPADDL,
+ TRPADDR,
+ TRPADDT,
+ TRPADOB,
+ TRPADOFB,
+ TRPADOFL,
+ TRPADOFR,
+ TRPADOFT,
+ TRPADOL,
+ TRPADOR,
+ TRPADOT,
+ TRPAT,
+ TRQC,
+ TRQL,
+ TRQR,
+ TRRH,
+ TRSHDNG,
+ TRSPDB,
+ TRSPDFB,
+ TRSPDFL,
+ TRSPDFR,
+ TRSPDFT,
+ TRSPDL,
+ TRSPDR,
+ TRSPDT,
+ TRSPOB,
+ TRSPOFB,
+ TRSPOFL,
+ TRSPOFR,
+ TRSPOFT,
+ TRSPOL,
+ TRSPOR,
+ TRSPOT,
+ TRUNCATEFONTHEIGHT,
+ TRUNCEX,
+ TRWWIDTHA,
+ TRWWIDTHB,
+ TRWWIDTH,
+ TS,
+ TSBGBDIAG,
+ TSBGCROSS,
+ TSBGDCROSS,
+ TSBGDKBDIAG,
+ TSBGDKCROSS,
+ TSBGDKDCROSS,
+ TSBGDKFDIAG,
+ TSBGDKHOR,
+ TSBGDKVERT,
+ TSBGFDIAG,
+ TSBGHORIZ,
+ TSBGVERT,
+ TSBRDRB,
+ TSBRDRDGL,
+ TSBRDRDGR,
+ TSBRDRH,
+ TSBRDRL,
+ TSBRDRR,
+ TSBRDRT,
+ TSBRDRV,
+ TSCBANDHORZEVEN,
+ TSCBANDHORZODD,
+ TSCBANDSH,
+ TSCBANDSV,
+ TSCBANDVERTEVEN,
+ TSCBANDVERTODD,
+ TSCELLCBPAT,
+ TSCELLCFPAT,
+ TSCELLPADDB,
+ TSCELLPADDFB,
+ TSCELLPADDFL,
+ TSCELLPADDFR,
+ TSCELLPADDFT,
+ TSCELLPADDL,
+ TSCELLPADDR,
+ TSCELLPADDT,
+ TSCELLPCT,
+ TSCELLWIDTH,
+ TSCELLWIDTHFTS,
+ TSCFIRSTCOL,
+ TSCFIRSTROW,
+ TSCLASTCOL,
+ TSCLASTROW,
+ TSCNECELL,
+ TSCNWCELL,
+ TSCSECELL,
+ TSCSWCELL,
+ TSD,
+ TSNOWRAP,
+ TSROWD,
+ TSVERTALB,
+ TSVERTALC,
+ TSVERTALT,
+ TWOINONE,
+ TWOONONE,
+ TX,
+ TXBXTWALWAYS,
+ TXBXTWFIRST,
+ TXBXTWFIRSTLAST,
+ TXBXTWLAST,
+ TXBXTWNO,
+ TXE,
+ U,
+ UC,
+ UD,
+ UL,
+ ULC,
+ ULD,
+ ULDASH,
+ ULDASHD,
+ ULDASHDD,
+ ULDB,
+ ULHAIR,
+ ULHWAVE,
+ ULLDASH,
+ ULNONE,
+ ULTH,
+ ULTHD,
+ ULTHDASH,
+ ULTHDASHD,
+ ULTHDASHDD,
+ ULTHLDASH,
+ ULULDBWAVE,
+ ULW,
+ ULWAVE,
+ UP,
+ UPR,
+ URTF,
+ USELTBALN,
+ USENORMSTYFORLIST,
+ USERPROPS,
+ USEXFORM,
+ UTINL,
+ V,
+ VALIDATEXML,
+ VERN,
+ VERSION,
+ VERTAL,
+ VERTALB,
+ VERTALC,
+ VERTALJ,
+ VERTALT,
+ VERTDOC,
+ VERTSECT,
+ VIEWBKSP,
+ VIEWKIND,
+ VIEWNOBOUND,
+ VIEWSCALE,
+ VIEWZK,
+ WBITMAP,
+ WBMBITSPIXEL,
+ WBMPLANES,
+ WBMWIDTHBYTE,
+ WEBHIDDEN,
+ WGRFFMTFILTER,
+ WIDCTLPAR,
+ WIDOWCTRL,
+ WINDOWCAPTION,
+ WMETAFILE,
+ WPEQN,
+ WPJST,
+ WPSP,
+ WRAPAROUND,
+ WRAPDEFAULT,
+ WRAPTHROUGH,
+ WRAPTIGHT,
+ WRAPTRSP,
+ WRITERESERVATION,
+ WRITERESERVHASH,
+ WRPPUNCT,
+ XE,
+ XEF,
+ XFORM,
+ XMLATTR,
+ XMLATTRNAME,
+ XMLATTRNS,
+ XMLATTRVALUE,
+ XMLCLOSE,
+ XMLNAME,
+ XMLNS,
+ XMLNSTBL,
+ XMLOPEN,
+ XMLSDTTCELL,
+ XMLSDTTPARA,
+ XMLSDTTREGULAR,
+ XMLSDTTROW,
+ XMLSDTTUNKNOWN,
+ YR,
+ YTS,
+ YXE,
+ ZWBO,
+ ZWJ,
+ ZWNBO,
+ ZWNJ,
+ FLYMAINCNT,
+ FLYVERT,
+ FLYHORZ,
+ FLYANCHOR
+};
+const char* keywordToString(RTFKeyword nKeyword);
+
+/// Types of an RTF Control Word
+enum class RTFControlType
+{
+ FLAG, // eg \sbknone takes no parameter
+ DESTINATION, // eg \fonttbl, if ignored, the whole group should be skipped
+ SYMBOL, // eg \tab
+ TOGGLE, // eg \b (between on and off)
+ VALUE // eg \fs (requires parameter)
+};
+
+/// Represents an RTF Control Word
+class RTFSymbol
+{
+ const char* m_sKeyword;
+ RTFControlType m_eControlType;
+ RTFKeyword m_nIndex;
+
+ int m_nDefValue; ///< Most of the control words default to 0.
+
+public:
+ RTFSymbol(const char* sKeyword, RTFControlType nControlType, RTFKeyword nIndex, int nDefValue)
+ : m_sKeyword(sKeyword)
+ , m_eControlType(nControlType)
+ , m_nIndex(nIndex)
+ , m_nDefValue(nDefValue)
+ {
+ }
+
+ const char* GetKeyword() const { return m_sKeyword; }
+
+ RTFControlType GetControlType() const { return m_eControlType; }
+
+ RTFKeyword GetIndex() const { return m_nIndex; }
+
+ int GetDefValue() const { return m_nDefValue; }
+};
+
+extern RTFSymbol const aRTFControlWords[];
+extern const int nRTFControlWords;
+
+/// Represents an RTF Math Control Word
+class RTFMathSymbol
+{
+ RTFKeyword m_eKeyword;
+ int m_nToken; ///< This is the OOXML token equivalent.
+ Destination m_eDestination;
+
+public:
+ RTFMathSymbol(RTFKeyword eKeyword, int nToken = 0,
+ Destination eDestination = Destination::NORMAL)
+ : m_eKeyword(eKeyword)
+ , m_nToken(nToken)
+ , m_eDestination(eDestination)
+ {
+ }
+
+ int GetToken() const { return m_nToken; }
+
+ Destination GetDestination() const { return m_eDestination; }
+
+ bool operator<(const RTFMathSymbol& rOther) const;
+};
+
+extern RTFMathSymbol const aRTFMathControlWords[];
+extern const int nRTFMathControlWords;
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchdestination.cxx b/writerfilter/source/rtftok/rtfdispatchdestination.cxx
new file mode 100644
index 000000000..8789c3f85
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchdestination.cxx
@@ -0,0 +1,684 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/document/DocumentProperties.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <filter/msfilter/escherex.hxx>
+#include <rtl/character.hxx>
+#include <tools/stream.hxx>
+#include <sal/log.hxx>
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include <ooxml/resourceids.hxx>
+
+#include "rtflookahead.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfsdrimport.hxx"
+#include "rtfskipdestination.hxx"
+#include "rtftokenizer.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ // special case \upr: ignore everything except nested \ud
+ if (Destination::UPR == m_aStates.top().getDestination() && RTFKeyword::UD != nKeyword)
+ {
+ m_aStates.top().setDestination(Destination::SKIP);
+ aSkip.setParsed(false);
+ }
+ else
+ switch (nKeyword)
+ {
+ case RTFKeyword::RTF:
+ break;
+ case RTFKeyword::FONTTBL:
+ m_aStates.top().setDestination(Destination::FONTTABLE);
+ break;
+ case RTFKeyword::COLORTBL:
+ m_aStates.top().setDestination(Destination::COLORTABLE);
+ break;
+ case RTFKeyword::STYLESHEET:
+ m_aStates.top().setDestination(Destination::STYLESHEET);
+ break;
+ case RTFKeyword::FIELD:
+ m_aStates.top().setDestination(Destination::FIELD);
+ m_aStates.top().setFieldLocked(false);
+ break;
+ case RTFKeyword::DOCVAR:
+ m_aStates.top().setDestination(Destination::DOCVAR);
+ break;
+ case RTFKeyword::FLDINST:
+ {
+ // Look for the field type
+ sal_uInt64 const nPos = Strm().Tell();
+ OStringBuffer aBuf;
+ char ch = 0;
+ bool bFoundCode = false;
+ bool bInKeyword = false;
+ while (!bFoundCode && ch != '}')
+ {
+ Strm().ReadChar(ch);
+ if ('\\' == ch)
+ bInKeyword = true;
+ if (!bInKeyword && rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
+ aBuf.append(ch);
+ else if (bInKeyword && rtl::isAsciiWhiteSpace(static_cast<unsigned char>(ch)))
+ bInKeyword = false;
+ if (!aBuf.isEmpty()
+ && !rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
+ bFoundCode = true;
+ }
+
+ if (std::string_view(aBuf) == "INCLUDEPICTURE")
+ {
+ // Extract the field argument of INCLUDEPICTURE: we handle that
+ // at a tokenizer level, as DOCX has no such field.
+ aBuf.append(ch);
+ while (true)
+ {
+ Strm().ReadChar(ch);
+ if (ch == '}')
+ break;
+ aBuf.append(ch);
+ }
+ OUString aFieldCommand = OStringToOUString(aBuf, RTL_TEXTENCODING_UTF8);
+ std::tuple<OUString, std::vector<OUString>, std::vector<OUString>> aResult
+ = writerfilter::dmapper::splitFieldCommand(aFieldCommand);
+ m_aPicturePath
+ = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front();
+ }
+
+ Strm().Seek(nPos);
+
+ // Form data should be handled only for form fields if any
+ if (aBuf.toString().indexOf("FORM") != -1)
+ m_bFormField = true;
+
+ singleChar(cFieldStart);
+ m_aStates.top().setDestination(Destination::FIELDINSTRUCTION);
+ }
+ break;
+ case RTFKeyword::FLDRSLT:
+ m_aStates.top().setDestination(Destination::FIELDRESULT);
+ break;
+ case RTFKeyword::LISTTABLE:
+ m_aStates.top().setDestination(Destination::LISTTABLE);
+ break;
+ case RTFKeyword::LISTPICTURE:
+ m_aStates.top().setDestination(Destination::LISTPICTURE);
+ m_aStates.top().setInListpicture(true);
+ break;
+ case RTFKeyword::LIST:
+ m_aStates.top().setDestination(Destination::LISTENTRY);
+ break;
+ case RTFKeyword::LISTNAME:
+ m_aStates.top().setDestination(Destination::LISTNAME);
+ break;
+ case RTFKeyword::LFOLEVEL:
+ m_aStates.top().setDestination(Destination::LFOLEVEL);
+ m_aStates.top().getTableSprms().clear();
+ break;
+ case RTFKeyword::LISTOVERRIDETABLE:
+ m_aStates.top().setDestination(Destination::LISTOVERRIDETABLE);
+ break;
+ case RTFKeyword::LISTOVERRIDE:
+ m_aStates.top().setDestination(Destination::LISTOVERRIDEENTRY);
+ break;
+ case RTFKeyword::LISTLEVEL:
+ m_aStates.top().setDestination(Destination::LISTLEVEL);
+ ++m_nListLevel;
+ break;
+ case RTFKeyword::LEVELTEXT:
+ m_aStates.top().setDestination(Destination::LEVELTEXT);
+ break;
+ case RTFKeyword::LEVELNUMBERS:
+ m_aStates.top().setDestination(Destination::LEVELNUMBERS);
+ break;
+ case RTFKeyword::SHPPICT:
+ resetFrame();
+ m_aStates.top().setDestination(Destination::SHPPICT);
+ break;
+ case RTFKeyword::PICT:
+ if (m_aStates.top().getDestination() != Destination::SHAPEPROPERTYVALUE)
+ m_aStates.top().setDestination(Destination::PICT); // as character
+ else
+ m_aStates.top().setDestination(
+ Destination::SHAPEPROPERTYVALUEPICT); // anchored inside a shape
+ break;
+ case RTFKeyword::PICPROP:
+ m_aStates.top().setDestination(Destination::PICPROP);
+ break;
+ case RTFKeyword::SP:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTY);
+ break;
+ case RTFKeyword::SN:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTYNAME);
+ break;
+ case RTFKeyword::SV:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTYVALUE);
+ break;
+ case RTFKeyword::SHP:
+ m_bNeedCrOrig = m_bNeedCr;
+ m_aStates.top().setDestination(Destination::SHAPE);
+ m_aStates.top().setInShape(true);
+ break;
+ case RTFKeyword::SHPINST:
+ m_aStates.top().setDestination(Destination::SHAPEINSTRUCTION);
+ break;
+ case RTFKeyword::NESTTABLEPROPS:
+ // do not set any properties of outer table at nested table!
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+ m_aNestedTableCellsSprms.clear();
+ m_aNestedTableCellsAttributes.clear();
+ m_nNestedCells = 0;
+ m_aStates.top().setDestination(Destination::NESTEDTABLEPROPERTIES);
+ break;
+ case RTFKeyword::HEADER:
+ case RTFKeyword::FOOTER:
+ case RTFKeyword::HEADERL:
+ case RTFKeyword::HEADERR:
+ case RTFKeyword::HEADERF:
+ case RTFKeyword::FOOTERL:
+ case RTFKeyword::FOOTERR:
+ case RTFKeyword::FOOTERF:
+ if (!m_pSuperstream)
+ {
+ Id nId = 0;
+ std::size_t nPos = m_nGroupStartPos - 1;
+ switch (nKeyword)
+ {
+ case RTFKeyword::HEADER:
+ if (!m_hasRHeader)
+ {
+ nId = NS_ooxml::LN_headerr;
+ m_hasRHeader = true;
+ }
+ break;
+ case RTFKeyword::FOOTER:
+ if (!m_hasRFooter)
+ {
+ nId = NS_ooxml::LN_footerr;
+ m_hasRFooter = true;
+ }
+ break;
+ case RTFKeyword::HEADERL:
+ nId = NS_ooxml::LN_headerl;
+ break;
+ case RTFKeyword::HEADERR:
+ nId = NS_ooxml::LN_headerr;
+ break;
+ case RTFKeyword::HEADERF:
+ if (!m_hasFHeader)
+ {
+ nId = NS_ooxml::LN_headerf;
+ m_hasFHeader = true;
+ }
+ break;
+ case RTFKeyword::FOOTERL:
+ nId = NS_ooxml::LN_footerl;
+ break;
+ case RTFKeyword::FOOTERR:
+ nId = NS_ooxml::LN_footerr;
+ break;
+ case RTFKeyword::FOOTERF:
+ if (!m_hasFFooter)
+ {
+ nId = NS_ooxml::LN_footerf;
+ m_hasFFooter = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nId != 0)
+ m_nHeaderFooterPositions.push(std::make_pair(nId, nPos));
+
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ break;
+ case RTFKeyword::FOOTNOTE:
+ checkFirstRun();
+ if (!m_pSuperstream)
+ {
+ Id nId = NS_ooxml::LN_footnote;
+
+ // Check if this is an endnote.
+ OStringBuffer aBuf;
+ char ch;
+ sal_uInt64 const nCurrent = Strm().Tell();
+ for (int i = 0; i < 7; ++i)
+ {
+ Strm().ReadChar(ch);
+ aBuf.append(ch);
+ }
+ Strm().Seek(nCurrent);
+ OString aKeyword = aBuf.makeStringAndClear();
+ if (aKeyword == "\\ftnalt")
+ nId = NS_ooxml::LN_endnote;
+
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ m_aStates.top().setCurrentBuffer(nullptr);
+ bool bCustomMark = false;
+ OUString aCustomMark;
+ for (auto const& elem : m_aSuperBuffer)
+ {
+ if (std::get<0>(elem) == BUFFER_UTEXT)
+ {
+ aCustomMark = std::get<1>(elem)->getString();
+ bCustomMark = true;
+ }
+ }
+ m_aSuperBuffer.clear();
+ m_aStates.top().setDestination(Destination::FOOTNOTE);
+ Mapper().startCharacterGroup();
+ runProps();
+ if (!m_aStates.top().getCurrentBuffer())
+ resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark);
+ else
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
+ aAttributes.set(Id(1), new RTFValue(nId));
+ aAttributes.set(Id(2), new RTFValue(aCustomMark));
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
+ }
+ if (bCustomMark)
+ {
+ m_aStates.top().getCharacterAttributes().clear();
+ m_aStates.top().getCharacterSprms().clear();
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue);
+ text(aCustomMark);
+ }
+ Mapper().endCharacterGroup();
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ break;
+ case RTFKeyword::BKMKSTART:
+ m_aStates.top().setDestination(Destination::BOOKMARKSTART);
+ break;
+ case RTFKeyword::BKMKEND:
+ m_aStates.top().setDestination(Destination::BOOKMARKEND);
+ break;
+ case RTFKeyword::XE:
+ m_aStates.top().setDestination(Destination::INDEXENTRY);
+ break;
+ case RTFKeyword::TC:
+ case RTFKeyword::TCN:
+ m_aStates.top().setDestination(Destination::TOCENTRY);
+ break;
+ case RTFKeyword::REVTBL:
+ m_aStates.top().setDestination(Destination::REVISIONTABLE);
+ break;
+ case RTFKeyword::ANNOTATION:
+ if (!m_pSuperstream)
+ {
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ resolveSubstream(m_nGroupStartPos - 1, NS_ooxml::LN_annotation);
+ }
+ else
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
+ aAttributes.set(Id(1), new RTFValue(NS_ooxml::LN_annotation));
+ aAttributes.set(Id(2), new RTFValue(OUString()));
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
+ }
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ else
+ {
+ // If there is an author set, emit it now.
+ if (!m_aAuthor.isEmpty() || !m_aAuthorInitials.isEmpty())
+ {
+ RTFSprms aAttributes;
+ if (!m_aAuthor.isEmpty())
+ {
+ auto pValue = new RTFValue(m_aAuthor);
+ aAttributes.set(NS_ooxml::LN_CT_TrackChange_author, pValue);
+ }
+ if (!m_aAuthorInitials.isEmpty())
+ {
+ auto pValue = new RTFValue(m_aAuthorInitials);
+ aAttributes.set(NS_ooxml::LN_CT_Comment_initials, pValue);
+ }
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes));
+ Mapper().props(pProperties);
+ }
+ }
+ break;
+ case RTFKeyword::SHPTXT:
+ case RTFKeyword::DPTXBXTEXT:
+ {
+ bool bPictureFrame = false;
+ for (const auto& rProperty : m_aStates.top().getShape().getProperties())
+ {
+ if (rProperty.first == "shapeType"
+ && rProperty.second
+ == std::u16string_view(
+ OUString::number(ESCHER_ShpInst_PictureFrame)))
+ {
+ bPictureFrame = true;
+ break;
+ }
+ }
+ if (bPictureFrame)
+ // Skip text on picture frames.
+ m_aStates.top().setDestination(Destination::SKIP);
+ else
+ {
+ m_aStates.top().setDestination(Destination::SHAPETEXT);
+ checkFirstRun();
+ dispatchFlag(RTFKeyword::PARD);
+ m_bNeedPap = true;
+ if (nKeyword == RTFKeyword::SHPTXT)
+ {
+ if (!m_aStates.top().getCurrentBuffer())
+ m_pSdrImport->resolve(m_aStates.top().getShape(), false,
+ RTFSdrImport::SHAPE);
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getShape());
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_STARTSHAPE, pValue, nullptr));
+ }
+ }
+ }
+ }
+ break;
+ case RTFKeyword::FORMFIELD:
+ if (m_aStates.top().getDestination() == Destination::FIELDINSTRUCTION)
+ m_aStates.top().setDestination(Destination::FORMFIELD);
+ break;
+ case RTFKeyword::FFNAME:
+ m_aStates.top().setDestination(Destination::FORMFIELDNAME);
+ break;
+ case RTFKeyword::FFL:
+ m_aStates.top().setDestination(Destination::FORMFIELDLIST);
+ break;
+ case RTFKeyword::DATAFIELD:
+ m_aStates.top().setDestination(Destination::DATAFIELD);
+ break;
+ case RTFKeyword::INFO:
+ m_aStates.top().setDestination(Destination::INFO);
+ break;
+ case RTFKeyword::CREATIM:
+ m_aStates.top().setDestination(Destination::CREATIONTIME);
+ break;
+ case RTFKeyword::REVTIM:
+ m_aStates.top().setDestination(Destination::REVISIONTIME);
+ break;
+ case RTFKeyword::PRINTIM:
+ m_aStates.top().setDestination(Destination::PRINTTIME);
+ break;
+ case RTFKeyword::AUTHOR:
+ m_aStates.top().setDestination(Destination::AUTHOR);
+ break;
+ case RTFKeyword::KEYWORDS:
+ m_aStates.top().setDestination(Destination::KEYWORDS);
+ break;
+ case RTFKeyword::OPERATOR:
+ m_aStates.top().setDestination(Destination::OPERATOR);
+ break;
+ case RTFKeyword::COMPANY:
+ m_aStates.top().setDestination(Destination::COMPANY);
+ break;
+ case RTFKeyword::COMMENT:
+ m_aStates.top().setDestination(Destination::COMMENT);
+ break;
+ case RTFKeyword::OBJECT:
+ {
+ // beginning of an OLE Object
+ m_aStates.top().setDestination(Destination::OBJECT);
+
+ // check if the object is in a special container (e.g. a table)
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ // the object is in a table or another container.
+ // Don't try to treat it as an OLE object (fdo#53594).
+ // Use the \result (RTFKeyword::RESULT) element of the object instead,
+ // the result element contain picture representing the OLE Object.
+ m_bObject = true;
+ }
+ }
+ break;
+ case RTFKeyword::OBJDATA:
+ // check if the object is in a special container (e.g. a table)
+ if (m_aStates.top().getCurrentBuffer())
+ {
+ // the object is in a table or another container.
+ // Use the \result (RTFKeyword::RESULT) element of the object instead,
+ // of the \objdata.
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ else
+ {
+ m_aStates.top().setDestination(Destination::OBJDATA);
+ }
+ break;
+ case RTFKeyword::OBJCLASS:
+ m_aStates.top().setDestination(Destination::OBJCLASS);
+ break;
+ case RTFKeyword::RESULT:
+ m_aStates.top().setDestination(Destination::RESULT);
+ break;
+ case RTFKeyword::ATNDATE:
+ m_aStates.top().setDestination(Destination::ANNOTATIONDATE);
+ break;
+ case RTFKeyword::ATNAUTHOR:
+ m_aStates.top().setDestination(Destination::ANNOTATIONAUTHOR);
+ break;
+ case RTFKeyword::ATNREF:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCE);
+ break;
+ case RTFKeyword::FALT:
+ m_aStates.top().setDestination(Destination::FALT);
+ break;
+ case RTFKeyword::FLYMAINCNT:
+ m_aStates.top().setDestination(Destination::FLYMAINCONTENT);
+ break;
+ case RTFKeyword::LISTTEXT:
+ // Should be ignored by any reader that understands Word 97 through Word 2007 numbering.
+ case RTFKeyword::NONESTTABLES:
+ // This destination should be ignored by readers that support nested tables.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::DO:
+ m_aStates.top().setDestination(Destination::DRAWINGOBJECT);
+ break;
+ case RTFKeyword::PN:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING);
+ break;
+ case RTFKeyword::PNTEXT:
+ // This destination should be ignored by readers that support paragraph numbering.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::PNTXTA:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTAFTER);
+ break;
+ case RTFKeyword::PNTXTB:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTBEFORE);
+ break;
+ case RTFKeyword::TITLE:
+ m_aStates.top().setDestination(Destination::TITLE);
+ break;
+ case RTFKeyword::SUBJECT:
+ m_aStates.top().setDestination(Destination::SUBJECT);
+ break;
+ case RTFKeyword::DOCCOMM:
+ m_aStates.top().setDestination(Destination::DOCCOMM);
+ break;
+ case RTFKeyword::ATRFSTART:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCESTART);
+ break;
+ case RTFKeyword::ATRFEND:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCEEND);
+ break;
+ case RTFKeyword::ATNID:
+ m_aStates.top().setDestination(Destination::ATNID);
+ break;
+ case RTFKeyword::MMATH:
+ case RTFKeyword::MOMATHPARA:
+ // Nothing to do here (just enter the destination) till RTFKeyword::MMATHPR is implemented.
+ break;
+ case RTFKeyword::MR:
+ m_aStates.top().setDestination(Destination::MR);
+ break;
+ case RTFKeyword::MCHR:
+ m_aStates.top().setDestination(Destination::MCHR);
+ break;
+ case RTFKeyword::MPOS:
+ m_aStates.top().setDestination(Destination::MPOS);
+ break;
+ case RTFKeyword::MVERTJC:
+ m_aStates.top().setDestination(Destination::MVERTJC);
+ break;
+ case RTFKeyword::MSTRIKEH:
+ m_aStates.top().setDestination(Destination::MSTRIKEH);
+ break;
+ case RTFKeyword::MDEGHIDE:
+ m_aStates.top().setDestination(Destination::MDEGHIDE);
+ break;
+ case RTFKeyword::MTYPE:
+ m_aStates.top().setDestination(Destination::MTYPE);
+ break;
+ case RTFKeyword::MGROW:
+ m_aStates.top().setDestination(Destination::MGROW);
+ break;
+ case RTFKeyword::MHIDETOP:
+ case RTFKeyword::MHIDEBOT:
+ case RTFKeyword::MHIDELEFT:
+ case RTFKeyword::MHIDERIGHT:
+ // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::MSUBHIDE:
+ m_aStates.top().setDestination(Destination::MSUBHIDE);
+ break;
+ case RTFKeyword::MSUPHIDE:
+ m_aStates.top().setDestination(Destination::MSUPHIDE);
+ break;
+ case RTFKeyword::MBEGCHR:
+ m_aStates.top().setDestination(Destination::MBEGCHR);
+ break;
+ case RTFKeyword::MSEPCHR:
+ m_aStates.top().setDestination(Destination::MSEPCHR);
+ break;
+ case RTFKeyword::MENDCHR:
+ m_aStates.top().setDestination(Destination::MENDCHR);
+ break;
+ case RTFKeyword::UPR:
+ m_aStates.top().setDestination(Destination::UPR);
+ break;
+ case RTFKeyword::UD:
+ // Anything inside \ud is just normal Unicode content.
+ m_aStates.top().setDestination(Destination::NORMAL);
+ break;
+ case RTFKeyword::BACKGROUND:
+ m_aStates.top().setDestination(Destination::BACKGROUND);
+ m_aStates.top().setInBackground(true);
+ break;
+ case RTFKeyword::SHPGRP:
+ {
+ RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
+ if (!aLookahead.hasTable())
+ {
+ uno::Reference<drawing::XShapes> xGroupShape(
+ m_xModelFactory->createInstance("com.sun.star.drawing.GroupShape"),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc,
+ uno::UNO_QUERY);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShape> xShape(xGroupShape, uno::UNO_QUERY);
+ // set default VertOrient before inserting
+ uno::Reference<beans::XPropertySet>(xShape, uno::UNO_QUERY_THROW)
+ ->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
+ xDrawSupplier->getDrawPage()->add(xShape);
+ }
+ m_pSdrImport->pushParent(xGroupShape);
+ m_aStates.top().setCreatedShapeGroup(true);
+ }
+ m_aStates.top().setDestination(Destination::SHAPEGROUP);
+ m_aStates.top().setInShapeGroup(true);
+ }
+ break;
+ case RTFKeyword::FTNSEP:
+ m_aStates.top().setDestination(Destination::FOOTNOTESEPARATOR);
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_FtnEdn_type,
+ new RTFValue(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
+ break;
+ case RTFKeyword::USERPROPS:
+ // Container of all user-defined properties.
+ m_aStates.top().setDestination(Destination::USERPROPS);
+ if (m_xDocumentProperties.is())
+ // Create a custom document properties to be able to process them later all at once.
+ m_xDocumentProperties = document::DocumentProperties::create(m_xContext);
+ break;
+ case RTFKeyword::PROPNAME:
+ m_aStates.top().setDestination(Destination::PROPNAME);
+ break;
+ case RTFKeyword::STATICVAL:
+ m_aStates.top().setDestination(Destination::STATICVAL);
+ break;
+ case RTFKeyword::GENERATOR:
+ m_aStates.top().setDestination(Destination::GENERATOR);
+ break;
+ default:
+ {
+ // Check if it's a math token.
+ RTFMathSymbol aSymbol(nKeyword);
+ if (RTFTokenizer::lookupMathKeyword(aSymbol))
+ {
+ m_aMathBuffer.appendOpeningTag(aSymbol.GetToken());
+ m_aStates.top().setDestination(aSymbol.GetDestination());
+ return RTFError::OK;
+ }
+
+ SAL_INFO("writerfilter",
+ "TODO handle destination '" << keywordToString(nKeyword) << "'");
+ // Make sure we skip destinations (even without \*) till we don't handle them
+ m_aStates.top().setDestination(Destination::SKIP);
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+
+ // new destination => use new destination text
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+
+ return RTFError::OK;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchflag.cxx b/writerfilter/source/rtftok/rtfdispatchflag.cxx
new file mode 100644
index 000000000..0ef4f2172
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx
@@ -0,0 +1,1258 @@
+/* -*- 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 <sal/config.h>
+
+#include <string_view>
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <filter/msfilter/escherex.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+#include "rtfsdrimport.hxx"
+#include "rtfskipdestination.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nParam = -1;
+ int nSprm = -1;
+
+ // Underline flags.
+ switch (nKeyword)
+ {
+ case RTFKeyword::ULD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotted;
+ break;
+ case RTFKeyword::ULW:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_words;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue = new RTFValue(nSprm);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Indentation
+ switch (nKeyword)
+ {
+ case RTFKeyword::QC:
+ nParam = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case RTFKeyword::QJ:
+ nParam = NS_ooxml::LN_Value_ST_Jc_both;
+ break;
+ case RTFKeyword::QL:
+ nParam = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case RTFKeyword::QR:
+ nParam = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ case RTFKeyword::QD:
+ nParam = NS_ooxml::LN_Value_ST_Jc_distribute;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_jc, pValue);
+ m_bNeedPap = true;
+ return RTFError::OK;
+ }
+
+ // Font Alignment
+ switch (nKeyword)
+ {
+ case RTFKeyword::FAFIXED:
+ case RTFKeyword::FAAUTO:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_auto;
+ break;
+ case RTFKeyword::FAHANG:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_top;
+ break;
+ case RTFKeyword::FACENTER:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_center;
+ break;
+ case RTFKeyword::FAROMAN:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline;
+ break;
+ case RTFKeyword::FAVAR:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_bottom;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_textAlignment, pValue);
+ return RTFError::OK;
+ }
+
+ // Tab kind.
+ switch (nKeyword)
+ {
+ case RTFKeyword::TQR:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_right;
+ break;
+ case RTFKeyword::TQC:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_center;
+ break;
+ case RTFKeyword::TQDEC:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_decimal;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Tab lead.
+ switch (nKeyword)
+ {
+ case RTFKeyword::TLDOT:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_dot;
+ break;
+ case RTFKeyword::TLMDOT:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_middleDot;
+ break;
+ case RTFKeyword::TLHYPH:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_hyphen;
+ break;
+ case RTFKeyword::TLUL:
+ case RTFKeyword::TLTH:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_underscore;
+ break;
+ case RTFKeyword::TLEQ:
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_leader, pValue);
+ return RTFError::OK;
+ }
+
+ // Border types
+ {
+ switch (nKeyword)
+ {
+ // brdrhair and brdrs are the same, brdrw will make a difference
+ // map to values in ooxml/model.xml resource ST_Border
+ case RTFKeyword::BRDRHAIR:
+ case RTFKeyword::BRDRS:
+ nParam = NS_ooxml::LN_Value_ST_Border_single;
+ break;
+ case RTFKeyword::BRDRDOT:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotted;
+ break;
+ case RTFKeyword::BRDRDASH:
+ nParam = NS_ooxml::LN_Value_ST_Border_dashed;
+ break;
+ case RTFKeyword::BRDRDB:
+ nParam = NS_ooxml::LN_Value_ST_Border_double;
+ break;
+ case RTFKeyword::BRDRTNTHSG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickSmallGap;
+ break;
+ case RTFKeyword::BRDRTNTHMG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickMediumGap;
+ break;
+ case RTFKeyword::BRDRTNTHLG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickLargeGap;
+ break;
+ case RTFKeyword::BRDRTHTNSG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinSmallGap;
+ break;
+ case RTFKeyword::BRDRTHTNMG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinMediumGap;
+ break;
+ case RTFKeyword::BRDRTHTNLG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinLargeGap;
+ break;
+ case RTFKeyword::BRDREMBOSS:
+ nParam = NS_ooxml::LN_Value_ST_Border_threeDEmboss;
+ break;
+ case RTFKeyword::BRDRENGRAVE:
+ nParam = NS_ooxml::LN_Value_ST_Border_threeDEngrave;
+ break;
+ case RTFKeyword::BRDROUTSET:
+ nParam = NS_ooxml::LN_Value_ST_Border_outset;
+ break;
+ case RTFKeyword::BRDRINSET:
+ nParam = NS_ooxml::LN_Value_ST_Border_inset;
+ break;
+ case RTFKeyword::BRDRDASHSM:
+ nParam = NS_ooxml::LN_Value_ST_Border_dashSmallGap;
+ break;
+ case RTFKeyword::BRDRDASHD:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotDash;
+ break;
+ case RTFKeyword::BRDRDASHDD:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotDotDash;
+ break;
+ case RTFKeyword::BRDRNONE:
+ nParam = NS_ooxml::LN_Value_ST_Border_none;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_val, pValue);
+ return RTFError::OK;
+ }
+ }
+
+ // Section breaks
+ switch (nKeyword)
+ {
+ case RTFKeyword::SBKNONE:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_continuous;
+ break;
+ case RTFKeyword::SBKCOL:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_nextColumn;
+ break;
+ case RTFKeyword::SBKPAGE:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ break;
+ case RTFKeyword::SBKEVEN:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_evenPage;
+ break;
+ case RTFKeyword::SBKODD:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_oddPage;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid)
+ {
+ m_nResetBreakOnSectBreak = nKeyword;
+ }
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pValue);
+ return RTFError::OK;
+ }
+
+ // Footnote numbering
+ switch (nKeyword)
+ {
+ case RTFKeyword::FTNNAR:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal;
+ break;
+ case RTFKeyword::FTNNALC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter;
+ break;
+ case RTFKeyword::FTNNAUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter;
+ break;
+ case RTFKeyword::FTNNRLC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman;
+ break;
+ case RTFKeyword::FTNNRUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman;
+ break;
+ case RTFKeyword::FTNNCHI:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pInner = new RTFValue(nParam);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumFmt_val, pInner);
+ auto pOuter = new RTFValue(aAttributes);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr, NS_ooxml::LN_CT_FtnProps_numFmt,
+ pOuter);
+ return RTFError::OK;
+ }
+
+ // Footnote restart type
+ switch (nKeyword)
+ {
+ case RTFKeyword::FTNRSTPG:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachPage;
+ break;
+ case RTFKeyword::FTNRESTART:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachSect;
+ break;
+ case RTFKeyword::FTNRSTCONT:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_continuous;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue);
+ return RTFError::OK;
+ }
+
+ // Endnote numbering
+ switch (nKeyword)
+ {
+ case RTFKeyword::AFTNNAR:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal;
+ break;
+ case RTFKeyword::AFTNNALC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter;
+ break;
+ case RTFKeyword::AFTNNAUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter;
+ break;
+ case RTFKeyword::AFTNNRLC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman;
+ break;
+ case RTFKeyword::AFTNNRUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman;
+ break;
+ case RTFKeyword::AFTNNCHI:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pInner = new RTFValue(nParam);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumFmt_val, pInner);
+ auto pOuter = new RTFValue(aAttributes);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(), NS_ooxml::LN_EG_SectPrContents_endnotePr,
+ NS_ooxml::LN_CT_EdnProps_numFmt, pOuter);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRQL:
+ nParam = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case RTFKeyword::TRQC:
+ nParam = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case RTFKeyword::TRQR:
+ nParam = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_jc, pValue);
+ return RTFError::OK;
+ }
+
+ // Cell Text Flow
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLTXLRTB:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
+ break;
+ case RTFKeyword::CLTXTBRL:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
+ break;
+ case RTFKeyword::CLTXBTLR:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_btLr;
+ break;
+ case RTFKeyword::CLTXLRTBV:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTbV;
+ break;
+ case RTFKeyword::CLTXTBRLV:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRlV;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_textDirection, pValue);
+ }
+
+ // Trivial paragraph flags
+ switch (nKeyword)
+ {
+ case RTFKeyword::KEEP:
+ if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
+ nParam = NS_ooxml::LN_CT_PPrBase_keepLines;
+ break;
+ case RTFKeyword::KEEPN:
+ nParam = NS_ooxml::LN_CT_PPrBase_keepNext;
+ break;
+ case RTFKeyword::INTBL:
+ {
+ m_aStates.top().setCurrentBuffer(&m_aTableBufferStack.back());
+ nParam = NS_ooxml::LN_inTbl;
+ }
+ break;
+ case RTFKeyword::PAGEBB:
+ nParam = NS_ooxml::LN_CT_PPrBase_pageBreakBefore;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getParagraphSprms().set(nParam, pValue);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::FNIL:
+ case RTFKeyword::FROMAN:
+ case RTFKeyword::FSWISS:
+ case RTFKeyword::FMODERN:
+ case RTFKeyword::FSCRIPT:
+ case RTFKeyword::FDECOR:
+ case RTFKeyword::FTECH:
+ case RTFKeyword::FBIDI:
+ // TODO ooxml:CT_Font_family seems to be ignored by the domain mapper
+ break;
+ case RTFKeyword::ANSI:
+ m_aStates.top().setCurrentEncoding(RTL_TEXTENCODING_MS_1252);
+ break;
+ case RTFKeyword::MAC:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_APPLE_ROMAN);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PC:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_437);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PCA:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_850);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PLAIN:
+ {
+ m_aStates.top().getCharacterSprms() = getDefaultState().getCharacterSprms();
+ m_aStates.top().setCurrentEncoding(getEncoding(getFontIndex(m_nDefaultFontIndex)));
+ m_aStates.top().getCharacterAttributes() = getDefaultState().getCharacterAttributes();
+ m_aStates.top().setCurrentCharacterStyleIndex(-1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ }
+ break;
+ case RTFKeyword::PARD:
+ {
+ if (m_bHadPicture)
+ dispatchSymbol(RTFKeyword::PAR);
+ // \pard is allowed between \cell and \row, but in that case it should not reset the fact that we're inside a table.
+ // It should not reset the paragraph style, either, so remember the old paragraph style.
+ RTFValue::Pointer_t pOldStyle
+ = m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pStyle);
+ m_aStates.top().getParagraphSprms() = m_aDefaultState.getParagraphSprms();
+ m_aStates.top().getParagraphAttributes() = m_aDefaultState.getParagraphAttributes();
+
+ if (m_nTopLevelCells == 0 && m_nNestedCells == 0)
+ {
+ // Reset that we're in a table.
+ m_aStates.top().setCurrentBuffer(nullptr);
+ }
+ else
+ {
+ // We are still in a table.
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_inTbl, new RTFValue(1));
+ if (m_bAfterCellBeforeRow && pOldStyle)
+ // And we still have the same paragraph style.
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ pOldStyle);
+ // Ideally getDefaultSPRM() would take care of this, but it would not when we're buffering.
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_tabs,
+ new RTFValue());
+ }
+ resetFrame();
+
+ // Reset currently selected paragraph style as well, unless we are in the special "after \cell, before \row" state.
+ // By default the style with index 0 is applied.
+ if (!m_bAfterCellBeforeRow)
+ {
+ OUString const aName = getStyleName(0);
+ // But only in case it's not a character style.
+ if (!aName.isEmpty()
+ && getStyleType(0) != NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ new RTFValue(aName));
+ }
+ m_aStates.top().setCurrentStyleIndex(0);
+ }
+ // Need to send paragraph properties again, if there will be any.
+ m_bNeedPap = true;
+ break;
+ }
+ case RTFKeyword::SECTD:
+ {
+ m_aStates.top().getSectionSprms() = m_aDefaultState.getSectionSprms();
+ m_aStates.top().getSectionAttributes() = m_aDefaultState.getSectionAttributes();
+ }
+ break;
+ case RTFKeyword::TROWD:
+ {
+ // Back these up, in case later we still need this info.
+ backupTableRowProperties();
+ resetTableRowProperties();
+ // In case the table definition is in the middle of the row
+ // (invalid), make sure table definition is emitted.
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::WIDCTLPAR:
+ case RTFKeyword::NOWIDCTLPAR:
+ {
+ auto pValue = new RTFValue(int(nKeyword == RTFKeyword::WIDCTLPAR));
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_widowControl, pValue);
+ }
+ break;
+ case RTFKeyword::BOX:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(aAttributes);
+ for (int i = 0; i < 4; i++)
+ m_aStates.top().getParagraphSprms().set(getParagraphBorder(i), pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH_BOX);
+ }
+ break;
+ case RTFKeyword::LTRSECT:
+ case RTFKeyword::RTLSECT:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LTRSECT ? 0 : 1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
+ pValue);
+ }
+ break;
+ case RTFKeyword::LTRPAR:
+ case RTFKeyword::RTLPAR:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LTRPAR ? 0 : 1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_bidi, pValue);
+ }
+ break;
+ case RTFKeyword::LTRROW:
+ case RTFKeyword::RTLROW:
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getTableRowSprms().set(
+ NS_ooxml::LN_CT_TblPrBase_bidiVisual,
+ new RTFValue(int(nKeyword == RTFKeyword::RTLROW)));
+ break;
+ case RTFKeyword::LTRCH:
+ // dmapper does not support this.
+ if (m_aStates.top().getRunType() == RTFParserState::RunType::RTLCH_LTRCH_1)
+ m_aStates.top().setRunType(RTFParserState::RunType::RTLCH_LTRCH_2);
+ else
+ m_aStates.top().setRunType(RTFParserState::RunType::LTRCH_RTLCH_1);
+ break;
+ case RTFKeyword::RTLCH:
+ if (m_aStates.top().getRunType() == RTFParserState::RunType::LTRCH_RTLCH_1)
+ m_aStates.top().setRunType(RTFParserState::RunType::LTRCH_RTLCH_2);
+ else
+ m_aStates.top().setRunType(RTFParserState::RunType::RTLCH_LTRCH_1);
+
+ if (m_aDefaultState.getCurrentEncoding() == RTL_TEXTENCODING_MS_1255)
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::ULNONE:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ }
+ break;
+ case RTFKeyword::NONSHPPICT:
+ case RTFKeyword::MMATHPICT: // Picture group used by readers not understanding \moMath group
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::CLBRDRT:
+ case RTFKeyword::CLBRDRL:
+ case RTFKeyword::CLBRDRB:
+ case RTFKeyword::CLBRDRR:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLBRDRT:
+ nSprm = NS_ooxml::LN_CT_TcBorders_top;
+ break;
+ case RTFKeyword::CLBRDRL:
+ nSprm = NS_ooxml::LN_CT_TcBorders_left;
+ break;
+ case RTFKeyword::CLBRDRB:
+ nSprm = NS_ooxml::LN_CT_TcBorders_bottom;
+ break;
+ case RTFKeyword::CLBRDRR:
+ nSprm = NS_ooxml::LN_CT_TcBorders_right;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcBorders,
+ nSprm, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::CELL);
+ }
+ break;
+ case RTFKeyword::PGBRDRT:
+ case RTFKeyword::PGBRDRL:
+ case RTFKeyword::PGBRDRB:
+ case RTFKeyword::PGBRDRR:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::PGBRDRT:
+ nSprm = NS_ooxml::LN_CT_PageBorders_top;
+ break;
+ case RTFKeyword::PGBRDRL:
+ nSprm = NS_ooxml::LN_CT_PageBorders_left;
+ break;
+ case RTFKeyword::PGBRDRB:
+ nSprm = NS_ooxml::LN_CT_PageBorders_bottom;
+ break;
+ case RTFKeyword::PGBRDRR:
+ nSprm = NS_ooxml::LN_CT_PageBorders_right;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders, nSprm, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PAGE);
+ }
+ break;
+ case RTFKeyword::BRDRT:
+ case RTFKeyword::BRDRL:
+ case RTFKeyword::BRDRB:
+ case RTFKeyword::BRDRR:
+ case RTFKeyword::BRDRBTW:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::BRDRT:
+ nSprm = getParagraphBorder(0);
+ break;
+ case RTFKeyword::BRDRL:
+ nSprm = getParagraphBorder(1);
+ break;
+ case RTFKeyword::BRDRB:
+ nSprm = getParagraphBorder(2);
+ break;
+ case RTFKeyword::BRDRR:
+ nSprm = getParagraphBorder(3);
+ break;
+ case RTFKeyword::BRDRBTW:
+ nSprm = getParagraphBorder(4);
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nSprm,
+ pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH);
+ }
+ break;
+ case RTFKeyword::CHBRDR:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(aAttributes);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_bdr, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::CHARACTER);
+ }
+ break;
+ case RTFKeyword::CLMGF:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLMRG:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVMGF:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVMRG:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVERTALT:
+ case RTFKeyword::CLVERTALC:
+ case RTFKeyword::CLVERTALB:
+ {
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLVERTALT:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_top;
+ break;
+ case RTFKeyword::CLVERTALC:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_center;
+ break;
+ case RTFKeyword::CLVERTALB:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_bottom;
+ break;
+ default:
+ break;
+ }
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vAlign, pValue);
+ }
+ break;
+ case RTFKeyword::TRKEEP:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_cantSplit, pValue);
+ }
+ break;
+ case RTFKeyword::SECTUNLOCKED:
+ {
+ auto pValue = new RTFValue(0);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_formProt, pValue);
+ }
+ break;
+ case RTFKeyword::PGNBIDIA:
+ case RTFKeyword::PGNBIDIB:
+ // These should be mapped to NS_ooxml::LN_EG_SectPrContents_pgNumType, but dmapper has no API for that at the moment.
+ break;
+ case RTFKeyword::LOCH:
+ m_aStates.top().setRunType(RTFParserState::RunType::LOCH);
+ break;
+ case RTFKeyword::HICH:
+ m_aStates.top().setRunType(RTFParserState::RunType::HICH);
+ break;
+ case RTFKeyword::DBCH:
+ m_aStates.top().setRunType(RTFParserState::RunType::DBCH);
+ break;
+ case RTFKeyword::TITLEPG:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_titlePg, pValue);
+ }
+ break;
+ case RTFKeyword::SUPER:
+ {
+ // Make sure character properties are not lost if the document
+ // starts with a footnote.
+ if (!isStyleSheetImport())
+ {
+ checkFirstRun();
+ checkNeedPap();
+ }
+
+ if (!m_aStates.top().getCurrentBuffer())
+ m_aStates.top().setCurrentBuffer(&m_aSuperBuffer);
+
+ auto pValue = new RTFValue("superscript");
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue);
+ }
+ break;
+ case RTFKeyword::SUB:
+ {
+ auto pValue = new RTFValue("subscript");
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue);
+ }
+ break;
+ case RTFKeyword::NOSUPERSUB:
+ {
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ {
+ replayBuffer(m_aSuperBuffer, nullptr, nullptr);
+ m_aStates.top().setCurrentBuffer(nullptr);
+ }
+ m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_EG_RPrBase_vertAlign);
+ }
+ break;
+ case RTFKeyword::LINEPPAGE:
+ case RTFKeyword::LINECONT:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LINEPPAGE
+ ? NS_ooxml::LN_Value_ST_LineNumberRestart_newPage
+ : NS_ooxml::LN_Value_ST_LineNumberRestart_continuous);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_restart, pValue);
+ }
+ break;
+ case RTFKeyword::AENDDOC:
+ // Noop, this is the default in Writer.
+ case RTFKeyword::AENDNOTES:
+ // Noop
+ case RTFKeyword::AFTNRSTCONT:
+ // Noop, this is the default in Writer.
+ case RTFKeyword::AFTNRESTART:
+ // Noop
+ case RTFKeyword::FTNBJ:
+ // Noop, this is the default in Writer.
+ break;
+ case RTFKeyword::ENDDOC:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_RestartNumber_eachSect);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue);
+ }
+ break;
+ case RTFKeyword::NOLINE:
+ eraseNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_distance);
+ break;
+ case RTFKeyword::FORMSHADE:
+ // Noop, this is the default in Writer.
+ break;
+ case RTFKeyword::PNGBLIP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::PNG;
+ break;
+ case RTFKeyword::JPEGBLIP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::JPEG;
+ break;
+ case RTFKeyword::POSYT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_top);
+ break;
+ case RTFKeyword::POSYB:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_bottom);
+ break;
+ case RTFKeyword::POSYC:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_center);
+ break;
+ case RTFKeyword::POSYIN:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_inside);
+ break;
+ case RTFKeyword::POSYOUT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_outside);
+ break;
+ case RTFKeyword::POSYIL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_inline);
+ break;
+
+ case RTFKeyword::PHMRG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_margin);
+ break;
+ case RTFKeyword::PVMRG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_margin);
+ break;
+ case RTFKeyword::PHPG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_page);
+ break;
+ case RTFKeyword::PVPG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_page);
+ break;
+ case RTFKeyword::PHCOL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_text);
+ break;
+ case RTFKeyword::PVPARA:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_text);
+ break;
+
+ case RTFKeyword::POSXC:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_center);
+ break;
+ case RTFKeyword::POSXI:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_inside);
+ break;
+ case RTFKeyword::POSXO:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_outside);
+ break;
+ case RTFKeyword::POSXL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_left);
+ break;
+ case RTFKeyword::POSXR:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_right);
+ break;
+
+ case RTFKeyword::DPLINE:
+ case RTFKeyword::DPRECT:
+ case RTFKeyword::DPELLIPSE:
+ case RTFKeyword::DPTXBX:
+ case RTFKeyword::DPPOLYLINE:
+ case RTFKeyword::DPPOLYGON:
+ {
+ sal_Int32 nType = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::DPLINE:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.LineShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPPOLYLINE:
+ {
+ // The reason this is not a simple CustomShape is that in the old syntax we have no ViewBox info.
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.PolyLineShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPPOLYGON:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.PolyPolygonShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPRECT:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.RectangleShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPELLIPSE:
+ nType = ESCHER_ShpInst_Ellipse;
+ break;
+ case RTFKeyword::DPTXBX:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.text.TextFrame"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ std::vector<beans::PropertyValue> aDefaults
+ = RTFSdrImport::getTextFrameDefaults(false);
+ for (const auto& rDefault : aDefaults)
+ {
+ if (!findPropertyName(
+ m_aStates.top().getDrawingObject().getPendingProperties(),
+ rDefault.Name))
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(
+ rDefault);
+ }
+ checkFirstRun();
+ Mapper().startShape(m_aStates.top().getDrawingObject().getShape());
+ m_aStates.top().getDrawingObject().setHadShapeText(true);
+ }
+ break;
+ default:
+ break;
+ }
+ if (nType)
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.CustomShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ }
+ uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(
+ m_aStates.top().getDrawingObject().getShape(), uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setPropertySet(xPropertySet);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
+ if (xShapes.is() && nKeyword != RTFKeyword::DPTXBX)
+ {
+ // set default VertOrient before inserting
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ "VertOrient", uno::Any(text::VertOrientation::NONE));
+ xShapes->add(m_aStates.top().getDrawingObject().getShape());
+ }
+ }
+ if (nType)
+ {
+ uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(
+ m_aStates.top().getDrawingObject().getShape(), uno::UNO_QUERY);
+ xDefaulter->createCustomShapeDefaults(OUString::number(nType));
+ }
+ std::vector<beans::PropertyValue>& rPendingProperties
+ = m_aStates.top().getDrawingObject().getPendingProperties();
+ for (const auto& rPendingProperty : rPendingProperties)
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ rPendingProperty.Name, rPendingProperty.Value);
+ m_pSdrImport->resolveDhgt(m_aStates.top().getDrawingObject().getPropertySet(),
+ m_aStates.top().getDrawingObject().getDhgt(),
+ /*bOldStyle=*/true);
+ }
+ break;
+ case RTFKeyword::DOBXMARGIN:
+ case RTFKeyword::DOBYMARGIN:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name
+ = (nKeyword == RTFKeyword::DOBXMARGIN ? std::u16string_view(u"HoriOrientRelation")
+ : std::u16string_view(u"VertOrientRelation"));
+ aPropertyValue.Value <<= text::RelOrientation::PAGE_PRINT_AREA;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::DOBXPAGE:
+ case RTFKeyword::DOBYPAGE:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name
+ = (nKeyword == RTFKeyword::DOBXPAGE ? std::u16string_view(u"HoriOrientRelation")
+ : std::u16string_view(u"VertOrientRelation"));
+ aPropertyValue.Value <<= text::RelOrientation::PAGE_FRAME;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::DOBYPARA:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name = "VertOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::CONTEXTUALSPACE:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_contextualSpacing,
+ pValue);
+ }
+ break;
+ case RTFKeyword::LINKSTYLES:
+ {
+ auto pValue = new RTFValue(1);
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_linkStyles, pValue);
+ }
+ break;
+ case RTFKeyword::PNLVLBODY:
+ {
+ auto pValue = new RTFValue(2);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid, pValue);
+ }
+ break;
+ case RTFKeyword::PNDEC:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_decimal);
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val, pValue);
+ }
+ break;
+ case RTFKeyword::PNLVLBLT:
+ {
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
+ new RTFValue(1));
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_bullet));
+ }
+ break;
+ case RTFKeyword::LANDSCAPE:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_PageOrientation_landscape);
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient,
+ pValue);
+ [[fallthrough]]; // set the default + current value
+ }
+ case RTFKeyword::LNDSCPSXN:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_PageOrientation_landscape);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient,
+ pValue);
+ }
+ break;
+ case RTFKeyword::SHPBXPAGE:
+ m_aStates.top().getShape().setHoriOrientRelation(text::RelOrientation::PAGE_FRAME);
+ m_aStates.top().getShape().setHoriOrientRelationToken(
+ NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page);
+ break;
+ case RTFKeyword::SHPBYPAGE:
+ m_aStates.top().getShape().setVertOrientRelation(text::RelOrientation::PAGE_FRAME);
+ m_aStates.top().getShape().setVertOrientRelationToken(
+ NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page);
+ break;
+ case RTFKeyword::DPLINEHOLLOW:
+ m_aStates.top().getDrawingObject().setFLine(0);
+ break;
+ case RTFKeyword::DPROUNDR:
+ if (m_aStates.top().getDrawingObject().getPropertySet().is())
+ // Seems this old syntax has no way to specify a custom radius, and this is the default
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ "CornerRadius", uno::Any(sal_Int32(83)));
+ break;
+ case RTFKeyword::NOWRAP:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_notBeside);
+ break;
+ case RTFKeyword::MNOR:
+ m_bMathNor = true;
+ break;
+ case RTFKeyword::REVISIONS:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_trackRevisions, new RTFValue(1));
+ break;
+ case RTFKeyword::BRDRSH:
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_shadow, new RTFValue(1));
+ break;
+ case RTFKeyword::NOCOLBAL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_noColumnBalance, new RTFValue(1));
+ break;
+ case RTFKeyword::MARGMIRROR:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_mirrorMargins, new RTFValue(1));
+ break;
+ case RTFKeyword::SAUTOUPD:
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_autoRedefine,
+ new RTFValue(1));
+ break;
+ case RTFKeyword::WIDOWCTRL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_widowControl, new RTFValue(1));
+ break;
+ case RTFKeyword::LINEBETCOL:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_sep,
+ new RTFValue(1));
+ break;
+ case RTFKeyword::PGNRESTART:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_start, new RTFValue(1));
+ break;
+ case RTFKeyword::PGNUCLTR:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_upperLetter);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNLCLTR:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNUCRM:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_upperRoman);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNLCRM:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNDEC:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_decimal);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::HTMAUTSP:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_doNotUseHTMLParagraphAutoSpacing,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::DNTBLNSBDB:
+ // tdf#128428 switch off longer space sequence
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::GUTTERPRL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_gutterAtTop, new RTFValue(1));
+ break;
+ case RTFKeyword::RTLGUTTER:
+ {
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_rtlGutter,
+ new RTFValue(1));
+ }
+ break;
+ case RTFKeyword::FLDLOCK:
+ {
+ if (m_aStates.top().getDestination() == Destination::FIELD)
+ m_aStates.top().setFieldLocked(true);
+ }
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter", "TODO handle flag '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchsymbol.cxx b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
new file mode 100644
index 000000000..3f9ed20bf
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx
@@ -0,0 +1,442 @@
+/* -*- 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 "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <svl/lngmisc.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ if (nKeyword != RTFKeyword::HEXCHAR)
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ else
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
+ RTFSkipDestination aSkip(*this);
+
+ if (RTFKeyword::LINE == nKeyword)
+ {
+ // very special handling since text() will eat lone '\n'
+ singleChar('\n', /*bRunProps=*/true);
+ return RTFError::OK;
+ }
+ // Trivial symbols
+ sal_uInt8 cCh = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::TAB:
+ cCh = '\t';
+ break;
+ case RTFKeyword::BACKSLASH:
+ cCh = '\\';
+ break;
+ case RTFKeyword::LBRACE:
+ cCh = '{';
+ break;
+ case RTFKeyword::RBRACE:
+ cCh = '}';
+ break;
+ case RTFKeyword::EMDASH:
+ cCh = 151;
+ break;
+ case RTFKeyword::ENDASH:
+ cCh = 150;
+ break;
+ case RTFKeyword::BULLET:
+ cCh = 149;
+ break;
+ case RTFKeyword::LQUOTE:
+ cCh = 145;
+ break;
+ case RTFKeyword::RQUOTE:
+ cCh = 146;
+ break;
+ case RTFKeyword::LDBLQUOTE:
+ cCh = 147;
+ break;
+ case RTFKeyword::RDBLQUOTE:
+ cCh = 148;
+ break;
+ default:
+ break;
+ }
+ if (cCh > 0)
+ {
+ OUString aStr(OStringToOUString(OStringChar(char(cCh)), RTL_TEXTENCODING_MS_1252));
+ text(aStr);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::IGNORE:
+ {
+ m_bSkipUnknown = true;
+ aSkip.setReset(false);
+ return RTFError::OK;
+ }
+ break;
+ case RTFKeyword::PAR:
+ {
+ if (m_aStates.top().getDestination() == Destination::FOOTNOTESEPARATOR)
+ break; // just ignore it - only thing we read in here is CHFTNSEP
+ checkFirstRun();
+ bool bNeedPap = m_bNeedPap;
+ checkNeedPap();
+ if (bNeedPap)
+ runProps();
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ parBreak();
+ // Not in table? Reset max width.
+ if (m_nCellxMax)
+ {
+ // Was in table, but not anymore -> tblEnd.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblEnd, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+ m_nCellxMax = 0;
+ }
+ else if (m_aStates.top().getDestination() != Destination::SHAPETEXT)
+ {
+ RTFValue::Pointer_t pValue;
+ m_aStates.top().getCurrentBuffer()->push_back(Buf_t(BUFFER_PAR, pValue, nullptr));
+ }
+ // but don't emit properties yet, since they may change till the first text token arrives
+ m_bNeedPap = true;
+ if (!m_aStates.top().getFrame().inFrame())
+ m_bNeedPar = false;
+ m_bNeedFinalPar = false;
+ }
+ break;
+ case RTFKeyword::SECT:
+ {
+ if (m_bNeedCr)
+ dispatchSymbol(RTFKeyword::PAR);
+
+ m_bHadSect = true;
+ if (m_bIgnoreNextContSectBreak)
+ m_bIgnoreNextContSectBreak = false;
+ else
+ {
+ sectBreak();
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid)
+ {
+ // this should run on _second_ \sect after \page
+ dispatchSymbol(m_nResetBreakOnSectBreak); // lazy reset
+ m_nResetBreakOnSectBreak = RTFKeyword::invalid;
+ m_bNeedSect = false; // dispatchSymbol set it
+ }
+ }
+ }
+ break;
+ case RTFKeyword::NOBREAK:
+ {
+ OUString aStr(SVT_HARD_SPACE);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::NOBRKHYPH:
+ {
+ OUString aStr(SVT_HARD_HYPHEN);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::OPTHYPH:
+ {
+ OUString aStr(SVT_SOFT_HYPHEN);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::HEXCHAR:
+ m_aStates.top().setInternalState(RTFInternalState::HEX);
+ break;
+ case RTFKeyword::CELL:
+ case RTFKeyword::NESTCELL:
+ {
+ if (nKeyword == RTFKeyword::CELL)
+ m_bAfterCellBeforeRow = true;
+
+ checkFirstRun();
+ if (m_bNeedPap)
+ {
+ // There were no runs in the cell, so we need to send paragraph and character properties here.
+ auto pPValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ bufferProperties(m_aTableBufferStack.back(), pPValue, nullptr);
+ auto pCValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+ bufferProperties(m_aTableBufferStack.back(), pCValue, nullptr);
+ }
+
+ RTFValue::Pointer_t pValue;
+ m_aTableBufferStack.back().emplace_back(Buf_t(BUFFER_CELLEND, pValue, nullptr));
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::NESTROW:
+ {
+ tools::SvRef<TableRowBuffer> const pBuffer(
+ new TableRowBuffer(m_aTableBufferStack.back(), m_aNestedTableCellsSprms,
+ m_aNestedTableCellsAttributes, m_nNestedCells));
+ prepareProperties(m_aStates.top(), pBuffer->GetParaProperties(),
+ pBuffer->GetFrameProperties(), pBuffer->GetRowProperties(),
+ m_nNestedCells, m_nNestedCurrentCellX - m_nNestedTRLeft);
+
+ if (m_aTableBufferStack.size() == 1 || !m_aStates.top().getCurrentBuffer())
+ {
+ throw io::WrongFormatException("mismatch between \\itap and number of \\nestrow",
+ nullptr);
+ }
+ assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
+ // note: there may be several states pointing to table buffer!
+ for (std::size_t i = 0; i < m_aStates.size(); ++i)
+ {
+ if (m_aStates[i].getCurrentBuffer() == &m_aTableBufferStack.back())
+ {
+ m_aStates[i].setCurrentBuffer(
+ &m_aTableBufferStack[m_aTableBufferStack.size() - 2]);
+ }
+ }
+ m_aTableBufferStack.pop_back();
+ m_aTableBufferStack.back().emplace_back(
+ Buf_t(BUFFER_NESTROW, RTFValue::Pointer_t(), pBuffer));
+
+ m_aNestedTableCellsSprms.clear();
+ m_aNestedTableCellsAttributes.clear();
+ m_nNestedCells = 0;
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::ROW:
+ {
+ m_bAfterCellBeforeRow = false;
+ if (m_aStates.top().getTableRowWidthAfter() > 0)
+ {
+ // Add fake cellx / cell, RTF equivalent of
+ // OOXMLFastContextHandlerTextTableRow::handleGridAfter().
+ auto pXValue = new RTFValue(m_aStates.top().getTableRowWidthAfter());
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ dispatchSymbol(RTFKeyword::CELL);
+
+ // Adjust total width, which is done in the \cellx handler for normal cells.
+ m_nTopLevelCurrentCellX += m_aStates.top().getTableRowWidthAfter();
+
+ m_aStates.top().setTableRowWidthAfter(0);
+ }
+
+ bool bRestored = false;
+ // Ending a row, but no cells defined?
+ // See if there was an invalid table row reset, so we can restore cell infos to help invalid documents.
+ if (!m_nTopLevelCurrentCellX && m_nBackupTopLevelCurrentCellX)
+ {
+ restoreTableRowProperties();
+ bRestored = true;
+ }
+
+ // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell
+ const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
+ if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY)
+ {
+ auto pXValueLast = m_aStates.top().getTableRowSprms().find(
+ NS_ooxml::LN_CT_TblGridBase_gridCol, false);
+ const int nXValueLast = pXValueLast ? pXValueLast->getInt() : 0;
+ auto pXValue = new RTFValue(nXValueLast + m_nCellxMax - m_nTopLevelCurrentCellX);
+ m_aStates.top().getTableRowSprms().eraseLast(NS_ooxml::LN_CT_TblGridBase_gridCol);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ m_nTopLevelCurrentCellX = m_nCellxMax;
+ }
+
+ if (m_nTopLevelCells)
+ {
+ // Make a backup before we start popping elements
+ m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms;
+ m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes;
+ m_nInheritingCells = m_nTopLevelCells;
+ }
+ else
+ {
+ // No table definition? Then inherit from the previous row
+ m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms;
+ m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes;
+ m_nTopLevelCells = m_nInheritingCells;
+ }
+
+ while (m_aTableBufferStack.size() > 1)
+ {
+ SAL_WARN("writerfilter.rtf", "dropping extra table buffer");
+ // note: there may be several states pointing to table buffer!
+ for (std::size_t i = 0; i < m_aStates.size(); ++i)
+ {
+ if (m_aStates[i].getCurrentBuffer() == &m_aTableBufferStack.back())
+ {
+ m_aStates[i].setCurrentBuffer(&m_aTableBufferStack.front());
+ }
+ }
+ m_aTableBufferStack.pop_back();
+ }
+
+ replayRowBuffer(m_aTableBufferStack.back(), m_aTopLevelTableCellsSprms,
+ m_aTopLevelTableCellsAttributes, m_nTopLevelCells);
+
+ // The scope of the table cell defaults is one row.
+ m_aDefaultState.getTableCellSprms().clear();
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+
+ writerfilter::Reference<Properties>::Pointer_t paraProperties;
+ writerfilter::Reference<Properties>::Pointer_t frameProperties;
+ writerfilter::Reference<Properties>::Pointer_t rowProperties;
+ prepareProperties(m_aStates.top(), paraProperties, frameProperties, rowProperties,
+ m_nTopLevelCells, m_nTopLevelCurrentCellX - m_nTopLevelTRLeft);
+ sendProperties(paraProperties, frameProperties, rowProperties);
+
+ m_bNeedPap = true;
+ m_bNeedFinalPar = true;
+ m_aTableBufferStack.back().clear();
+ m_nTopLevelCells = 0;
+
+ if (bRestored)
+ // We restored cell definitions, clear these now.
+ // This is necessary, as later cell definitions want to overwrite the restored ones.
+ resetTableRowProperties();
+ }
+ break;
+ case RTFKeyword::COLUMN:
+ {
+ bool bColumns = false; // If we have multiple columns
+ RTFValue::Pointer_t pCols
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_cols);
+ if (pCols)
+ {
+ RTFValue::Pointer_t pNum = pCols->getAttributes().find(NS_ooxml::LN_CT_Columns_num);
+ if (pNum && pNum->getInt() > 1)
+ bColumns = true;
+ }
+ checkFirstRun();
+ if (bColumns)
+ {
+ sal_uInt8 const sBreak[] = { 0xe };
+ Mapper().startCharacterGroup();
+ Mapper().text(sBreak, 1);
+ Mapper().endCharacterGroup();
+ }
+ else
+ dispatchSymbol(RTFKeyword::PAGE);
+ }
+ break;
+ case RTFKeyword::CHFTN:
+ {
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ // Stop buffering, there will be no custom mark for this footnote or endnote.
+ m_aStates.top().setCurrentBuffer(nullptr);
+ break;
+ }
+ case RTFKeyword::PAGE:
+ {
+ // Ignore page breaks inside tables.
+ if (m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back())
+ break;
+
+ // If we're inside a continuous section, we should send a section break, not a page one.
+ RTFValue::Pointer_t pBreak
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ // Unless we're on a title page.
+ RTFValue::Pointer_t pTitlePg
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_titlePg);
+ if (((pBreak
+ && pBreak->getInt()
+ == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous))
+ || m_nResetBreakOnSectBreak == RTFKeyword::SBKNONE)
+ && !(pTitlePg && pTitlePg->getInt()))
+ {
+ if (m_bWasInFrame)
+ {
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bWasInFrame = false;
+ }
+ sectBreak();
+ // note: this will not affect the following section break
+ // but the one just pushed
+ dispatchFlag(RTFKeyword::SBKPAGE);
+ if (m_bNeedPar)
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bIgnoreNextContSectBreak = true;
+ // arrange to clean up the synthetic RTFKeyword::SBKPAGE
+ m_nResetBreakOnSectBreak = RTFKeyword::SBKNONE;
+ }
+ else
+ {
+ bool bFirstRun = m_bFirstRun;
+ checkFirstRun();
+ checkNeedPap();
+ sal_uInt8 const sBreak[] = { 0xc };
+ Mapper().text(sBreak, 1);
+ if (bFirstRun || m_bNeedCr)
+ {
+ // If we don't have content in the document yet (so the break-before can't move
+ // to a second layout page) or we already have characters sent (so the paragraph
+ // properties are already finalized), then continue inserting a fake paragraph.
+ if (!m_bNeedPap)
+ {
+ parBreak();
+ m_bNeedPap = true;
+ }
+ }
+ m_bNeedCr = true;
+ }
+ }
+ break;
+ case RTFKeyword::CHPGN:
+ {
+ OUString aStr("PAGE");
+ singleChar(cFieldStart);
+ text(aStr);
+ singleChar(cFieldSep, true);
+ singleChar(cFieldEnd);
+ }
+ break;
+ case RTFKeyword::CHFTNSEP:
+ {
+ static const sal_Unicode uFtnEdnSep = 0x3;
+ Mapper().utext(reinterpret_cast<const sal_uInt8*>(&uFtnEdnSep), 1);
+ }
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter.rtf",
+ "TODO handle symbol '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
new file mode 100644
index 000000000..2bea9dc9e
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
@@ -0,0 +1,1832 @@
+/* -*- 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 "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <comphelper/sequence.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+#include <rtl/tencinfo.h>
+#include <tools/UnitConversion.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include "rtfcharsets.hxx"
+#include "rtffly.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+
+#include <unotools/defaultencoding.hxx>
+#include <unotools/wincodepage.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter
+{
+static int getNumberFormat(int nParam)
+{
+ static const int aMap[]
+ = { NS_ooxml::LN_Value_ST_NumberFormat_decimal,
+ NS_ooxml::LN_Value_ST_NumberFormat_upperRoman,
+ NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman,
+ NS_ooxml::LN_Value_ST_NumberFormat_upperLetter,
+ NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter,
+ NS_ooxml::LN_Value_ST_NumberFormat_ordinal,
+ NS_ooxml::LN_Value_ST_NumberFormat_cardinalText,
+ NS_ooxml::LN_Value_ST_NumberFormat_ordinalText,
+ NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
+ NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_aiueo,
+ NS_ooxml::LN_Value_ST_NumberFormat_iroha,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2,
+ NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalZero,
+ NS_ooxml::LN_Value_ST_NumberFormat_bullet,
+ NS_ooxml::LN_Value_ST_NumberFormat_ganada,
+ NS_ooxml::LN_Value_ST_NumberFormat_chosung,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimal,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2,
+ NS_ooxml::LN_Value_ST_NumberFormat_hebrew1,
+ NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha,
+ NS_ooxml::LN_Value_ST_NumberFormat_hebrew2,
+ NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad };
+ const int nLen = SAL_N_ELEMENTS(aMap);
+ int nValue = 0;
+ if (nParam >= 0 && nParam < nLen)
+ nValue = aMap[nParam];
+ else // 255 and the other cases.
+ nValue = NS_ooxml::LN_Value_ST_NumberFormat_none;
+ return nValue;
+}
+
+namespace rtftok
+{
+bool RTFDocumentImpl::dispatchTableSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+ switch (nKeyword)
+ {
+ case RTFKeyword::LEVELJC:
+ {
+ nSprm = NS_ooxml::LN_CT_Lvl_lvlJc;
+ int nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ }
+ pIntValue = new RTFValue(nValue);
+ break;
+ }
+ case RTFKeyword::LEVELSTARTAT:
+ nSprm = NS_ooxml::LN_CT_Lvl_start;
+ break;
+ case RTFKeyword::LEVELPICTURE:
+ nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId;
+ break;
+ case RTFKeyword::SBASEDON:
+ nSprm = NS_ooxml::LN_CT_Style_basedOn;
+ pIntValue = new RTFValue(getStyleName(nParam));
+ break;
+ case RTFKeyword::SNEXT:
+ nSprm = NS_ooxml::LN_CT_Style_next;
+ pIntValue = new RTFValue(getStyleName(nParam));
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ return true;
+ }
+ if (nKeyword == RTFKeyword::LEVELNFC)
+ {
+ pIntValue = new RTFValue(getNumberFormat(nParam));
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val, pIntValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::FS:
+ case RTFKeyword::AFS:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_szCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_sz;
+ break;
+ }
+ break;
+ case RTFKeyword::EXPNDTW:
+ nSprm = NS_ooxml::LN_EG_RPrBase_spacing;
+ break;
+ case RTFKeyword::KERNING:
+ nSprm = NS_ooxml::LN_EG_RPrBase_kern;
+ break;
+ case RTFKeyword::CHARSCALEX:
+ nSprm = NS_ooxml::LN_EG_RPrBase_w;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pIntValue);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::LANG:
+ case RTFKeyword::ALANG:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_CT_Language_bidi;
+ break;
+ case RTFParserState::RunType::DBCH:
+ nSprm = NS_ooxml::LN_CT_Language_eastAsia;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ default:
+ nSprm = NS_ooxml::LN_CT_Language_val;
+ break;
+ }
+ break;
+ case RTFKeyword::LANGFE: // this one is always CJK apparently
+ nSprm = NS_ooxml::LN_CT_Language_eastAsia;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
+ auto pValue = new RTFValue(aTag.getBcp47());
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_lang, nSprm,
+ pValue);
+ // Language is a character property, but we should store it at a paragraph level as well for fields.
+ if (nKeyword == RTFKeyword::LANG && m_bNeedPap)
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_EG_RPrBase_lang,
+ nSprm, pValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::ITAP:
+ nSprm = NS_ooxml::LN_tblDepth;
+ // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then
+ // use the default value (1), as Word apparently does
+ if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0))
+ {
+ nParam = 1;
+ pIntValue = new RTFValue(nParam);
+ }
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ m_aStates.top().getParagraphSprms().set(nSprm, pIntValue);
+ if (nKeyword == RTFKeyword::ITAP && nParam > 0)
+ {
+ while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam))
+ {
+ m_aTableBufferStack.emplace_back();
+ }
+ // Invalid tables may omit INTBL after ITAP
+ dispatchFlag(RTFKeyword::INTBL); // sets newly pushed buffer as current
+ assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchInfoValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::YR:
+ {
+ m_aStates.top().setYear(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::MO:
+ {
+ m_aStates.top().setMonth(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::DY:
+ {
+ m_aStates.top().setDay(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::HR:
+ {
+ m_aStates.top().setHour(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::MIN:
+ {
+ m_aStates.top().setMinute(nParam);
+ nSprm = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return nSprm > 0;
+}
+
+bool RTFDocumentImpl::dispatchFrameValue(RTFKeyword nKeyword, int nParam)
+{
+ Id nId = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::ABSW:
+ nId = NS_ooxml::LN_CT_FramePr_w;
+ break;
+ case RTFKeyword::ABSH:
+ nId = NS_ooxml::LN_CT_FramePr_h;
+ break;
+ case RTFKeyword::POSX:
+ {
+ nId = NS_ooxml::LN_CT_FramePr_x;
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0);
+ }
+ break;
+ case RTFKeyword::POSY:
+ {
+ nId = NS_ooxml::LN_CT_FramePr_y;
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_bNeedPap = true;
+ // Don't try to support text frames inside tables for now.
+ if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
+ m_aStates.top().getFrame().setSprm(nId, nParam);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::CELLX:
+ {
+ int& rCurrentCellX(
+ (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ ? m_nNestedCurrentCellX
+ : m_nTopLevelCurrentCellX);
+ int nCellX = nParam - rCurrentCellX;
+ const int COL_DFLT_WIDTH
+ = 41; // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells.
+ if (!nCellX)
+ nCellX = COL_DFLT_WIDTH;
+
+ // If there is a negative left margin, then the first cellx is relative to that.
+ RTFValue::Pointer_t pTblInd
+ = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd);
+ if (rCurrentCellX == 0 && pTblInd)
+ {
+ RTFValue::Pointer_t pWidth
+ = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
+ if (pWidth && pWidth->getInt() < 0)
+ nCellX = -1 * (pWidth->getInt() - nParam);
+ }
+
+ rCurrentCellX = nParam;
+ auto pXValue = new RTFValue(nCellX);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ {
+ m_nNestedCells++;
+ // Push cell properties.
+ m_aNestedTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_aNestedTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ }
+ else
+ {
+ m_nTopLevelCells++;
+ // Push cell properties.
+ m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ }
+
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+ // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token
+ dispatchFlag(RTFKeyword::INTBL);
+ if (!m_nCellxMax)
+ {
+ // Wasn't in table, but now is -> tblStart.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+ m_nCellxMax = std::max(m_nCellxMax, nParam);
+ return true;
+ }
+ break;
+ case RTFKeyword::TRRH:
+ {
+ OUString hRule("auto");
+ if (nParam < 0)
+ {
+ tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam));
+ std::swap(pIntValue, pAbsValue);
+
+ hRule = "exact";
+ }
+ else if (nParam > 0)
+ hRule = "atLeast";
+
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val,
+ pIntValue);
+
+ auto pHRule = new RTFValue(hRule);
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_hRule,
+ pHRule);
+ return true;
+ }
+ break;
+ case RTFKeyword::TRLEFT:
+ {
+ // the value is in twips
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
+ NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
+ NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ auto const aDestination = m_aStates.top().getDestination();
+ int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination)
+ ? m_nNestedTRLeft
+ : m_nTopLevelTRLeft);
+ int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == aDestination)
+ ? m_nNestedCurrentCellX
+ : m_nTopLevelCurrentCellX);
+ rCurrentTRLeft = rCurrentCellX = nParam;
+ return true;
+ }
+ break;
+ case RTFKeyword::CLSHDNG:
+ {
+ int nValue = -1;
+
+ if (nParam < 1)
+ nValue = NS_ooxml::LN_Value_ST_Shd_clear;
+ else if (nParam < 750)
+ // Values in between 1 and 250 visually closer to 0% shading (white)
+ // But this will mean "no shading" while cell actually have some.
+ // So lets use minimal available value.
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
+ else if (nParam < 1100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
+ else if (nParam < 1350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
+ else if (nParam < 1750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
+ else if (nParam < 2250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
+ else if (nParam < 2750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
+ else if (nParam < 3250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
+ else if (nParam < 3600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
+ else if (nParam < 3850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
+ else if (nParam < 4250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
+ else if (nParam < 4750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
+ else if (nParam < 5250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
+ else if (nParam < 5750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
+ else if (nParam < 6100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
+ else if (nParam < 6350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
+ else if (nParam < 6750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
+ else if (nParam < 7250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
+ else if (nParam < 7750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
+ else if (nParam < 8250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
+ else if (nParam < 8600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
+ else if (nParam < 8850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
+ else if (nParam < 9250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
+ else if (nParam < 9750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
+ else
+ // Solid fill
+ nValue = NS_ooxml::LN_Value_ST_Shd_solid;
+
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_val, new RTFValue(nValue));
+ return true;
+ }
+ break;
+ case RTFKeyword::CLPADB:
+ case RTFKeyword::CLPADL:
+ case RTFKeyword::CLPADR:
+ case RTFKeyword::CLPADT:
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ // Top and left is swapped, that's what Word does.
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLPADB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::CLPADL:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ case RTFKeyword::CLPADR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::CLPADT:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ break;
+ case RTFKeyword::TRPADDFB:
+ case RTFKeyword::TRPADDFL:
+ case RTFKeyword::TRPADDFR:
+ case RTFKeyword::TRPADDFT:
+ {
+ RTFSprms aAttributes;
+ switch (nParam)
+ {
+ case 3:
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ break;
+ }
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRPADDFB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::TRPADDFL:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ case RTFKeyword::TRPADDFR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::TRPADDFT:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ default:
+ break;
+ }
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar, nSprm,
+ new RTFValue(aAttributes));
+ // tdf#74795 also set on current cell, and as default for table cells
+ // (why isn't this done by domainmapper?)
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ putNestedAttribute(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ break;
+ case RTFKeyword::TRPADDB:
+ case RTFKeyword::TRPADDL:
+ case RTFKeyword::TRPADDR:
+ case RTFKeyword::TRPADDT:
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRPADDB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::TRPADDL:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ case RTFKeyword::TRPADDR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::TRPADDT:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ nSprm, new RTFValue(aAttributes));
+ // tdf#74795 also set on current cell, and as default for table cells
+ // (why isn't this done by domainmapper?)
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ putNestedSprm(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ case RTFKeyword::TRGAPH:
+ // Half of the space between the cells of a table row: default left/right table cell margin.
+ if (nParam > 0)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue);
+ // FIXME: this is wrong, it is half-gap, needs to be distinguished from margin! depending on TRPADDFL/TRPADDFR
+ putNestedSprm(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left,
+ new RTFValue(aAttributes));
+ putNestedSprm(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
+ }
+ return true;
+ case RTFKeyword::TRFTSWIDTH:
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_type, pIntValue);
+ return true;
+ case RTFKeyword::TRWWIDTH:
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_w, pIntValue);
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/nKeyword != RTFKeyword::U, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+ // Trivial table sprms.
+ if (dispatchTableSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial character sprms.
+ if (dispatchCharacterSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial character attributes.
+ if (dispatchCharacterAttributeValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial paragraph sprms.
+ if (dispatchParagraphSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Info group.
+ if (dispatchInfoValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Frame size / position.
+ if (dispatchFrameValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Table-related values.
+ if (dispatchTableValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Then check for the more complex ones.
+ switch (nKeyword)
+ {
+ case RTFKeyword::F:
+ case RTFKeyword::AF:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_CT_Fonts_cs;
+ break;
+ case RTFParserState::RunType::DBCH:
+ nSprm = NS_ooxml::LN_CT_Fonts_eastAsia;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ default:
+ nSprm = NS_ooxml::LN_CT_Fonts_ascii;
+ break;
+ }
+
+ if (m_aStates.top().getDestination() == Destination::FONTTABLE
+ || m_aStates.top().getDestination() == Destination::FONTENTRY)
+ {
+ // Some text in buffer? It is font name. So previous font definition is complete
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ m_aFontIndexes.push_back(nParam);
+ m_nCurrentFontIndex = getFontIndex(nParam);
+ }
+ else if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ RTFSprms aFontAttributes;
+ aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)]));
+ RTFSprms aRunPropsSprms;
+ aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes));
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_rPr,
+ new RTFValue(RTFSprms(), aRunPropsSprms),
+ RTFOverwrite::NO_APPEND);
+ }
+ else
+ {
+ m_nCurrentFontIndex = getFontIndex(nParam);
+ auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex));
+ putNestedAttribute(m_aStates.top().getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue);
+ if (nKeyword == RTFKeyword::F)
+ m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex));
+ }
+ break;
+ case RTFKeyword::RED:
+ m_aStates.top().getCurrentColor().SetRed(nParam);
+ break;
+ case RTFKeyword::GREEN:
+ m_aStates.top().getCurrentColor().SetGreen(nParam);
+ break;
+ case RTFKeyword::BLUE:
+ m_aStates.top().getCurrentColor().SetBlue(nParam);
+ break;
+ case RTFKeyword::FCHARSET:
+ {
+ // we always send text to the domain mapper in OUString, so no
+ // need to send encoding info
+ int i;
+ for (i = 0; i < nRTFEncodings; i++)
+ {
+ if (aRTFEncodings[i].charset == nParam)
+ break;
+ }
+ if (i == nRTFEncodings)
+ // not found
+ return RTFError::OK;
+
+ m_nCurrentEncoding
+ = aRTFEncodings[i].codepage == 0 // Default (CP_ACP)
+ ? osl_getThreadTextEncoding()
+ : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage);
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ break;
+ case RTFKeyword::ANSICPG:
+ case RTFKeyword::CPG:
+ {
+ rtl_TextEncoding nEncoding
+ = (nParam == 0)
+ ? utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding())
+ : rtl_getTextEncodingFromWindowsCodePage(nParam);
+ if (nKeyword == RTFKeyword::ANSICPG)
+ m_aDefaultState.setCurrentEncoding(nEncoding);
+ else
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(nEncoding);
+ }
+ break;
+ case RTFKeyword::CF:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_color,
+ new RTFValue(aAttributes));
+ }
+ break;
+ case RTFKeyword::S:
+ {
+ m_aStates.top().setCurrentStyleIndex(nParam);
+
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // paragraph style
+ }
+ else
+ {
+ OUString aName = getStyleName(nParam);
+ if (!aName.isEmpty())
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_pStyle,
+ new RTFValue(aName));
+ else
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ new RTFValue(aName));
+ }
+ }
+ }
+ break;
+ case RTFKeyword::CS:
+ m_aStates.top().setCurrentCharacterStyleIndex(nParam);
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // character style
+ }
+ else
+ {
+ OUString aName = getStyleName(nParam);
+ if (!aName.isEmpty())
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_rStyle,
+ new RTFValue(aName));
+ }
+ break;
+ case RTFKeyword::DS:
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(0); // TODO no value in enum StyleType?
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // section style
+ }
+ break;
+ case RTFKeyword::TS:
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ // FIXME the correct value would be NS_ooxml::LN_Value_ST_StyleType_table but maybe table styles mess things up in dmapper, be cautious and disable them for now
+ auto pValue = new RTFValue(0);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // table style
+ }
+ break;
+ case RTFKeyword::DEFF:
+ m_nDefaultFontIndex = nParam;
+ break;
+ case RTFKeyword::STSHFDBCH:
+ // tdf#123703 switch off longer space sequence except in the case of the fixed compatibility setting font id 31505
+ if (nParam != 31505)
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::DEFLANG:
+ case RTFKeyword::ADEFLANG:
+ {
+ LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
+ auto pValue = new RTFValue(aTag.getBcp47());
+ putNestedAttribute(m_aStates.top().getCharacterSprms(),
+ (nKeyword == RTFKeyword::DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang
+ : NS_ooxml::LN_CT_Language_bidi),
+ nSprm, pValue);
+ }
+ break;
+ case RTFKeyword::CHCBPAT:
+ {
+ auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::CLCBPAT:
+ case RTFKeyword::CLCBPATRAW:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::CBPAT:
+ if (nParam)
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::ULC:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ m_aStates.top().getCharacterSprms().set(0x6877, pValue);
+ }
+ break;
+ case RTFKeyword::HIGHLIGHT:
+ {
+ auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_highlight, pValue);
+ }
+ break;
+ case RTFKeyword::UP:
+ case RTFKeyword::DN:
+ {
+ auto pValue = new RTFValue(nParam * (nKeyword == RTFKeyword::UP ? 1 : -1));
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue);
+ }
+ break;
+ case RTFKeyword::HORZVERT:
+ {
+ auto pValue = new RTFValue(int(true));
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_vert,
+ pValue);
+ if (nParam)
+ // rotate fits to a single line
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue);
+ }
+ break;
+ case RTFKeyword::EXPND:
+ {
+ // Convert quarter-points to twentieths of a point
+ auto pValue = new RTFValue(nParam * 5);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_spacing, pValue);
+ }
+ break;
+ case RTFKeyword::TWOINONE:
+ {
+ auto pValue = new RTFValue(int(true));
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_combine,
+ pValue);
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_none;
+ break;
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_round;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_square;
+ break;
+ case 3:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle;
+ break;
+ case 4:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly;
+ break;
+ }
+ if (nId > 0)
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId));
+ }
+ break;
+ case RTFKeyword::SL:
+ {
+ // This is similar to RTFKeyword::ABSH, negative value means 'exact', positive means 'at least'.
+ tools::SvRef<RTFValue> pValue(
+ new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast));
+ if (nParam < 0)
+ {
+ pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact);
+ pIntValue = new RTFValue(-nParam);
+ }
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, pValue);
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_line, pIntValue);
+ }
+ break;
+ case RTFKeyword::SLMULT:
+ if (nParam > 0)
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule,
+ pValue);
+ }
+ break;
+ case RTFKeyword::BRDRW:
+ {
+ // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0
+ if (nParam > 1)
+ nParam = nParam * 2 / 5;
+ auto pValue = new RTFValue(nParam);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue);
+ }
+ break;
+ case RTFKeyword::BRDRCF:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue);
+ }
+ break;
+ case RTFKeyword::BRSP:
+ {
+ // dmapper expects it in points, we have it in twip
+ auto pValue = new RTFValue(nParam / 20);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue);
+ }
+ break;
+ case RTFKeyword::TX:
+ {
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_pos, pIntValue);
+ auto pValue = new RTFValue(m_aStates.top().getTabAttributes());
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
+ NS_ooxml::LN_CT_Tabs_tab, pValue);
+ else
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
+ NS_ooxml::LN_CT_Tabs_tab, pValue);
+ m_aStates.top().getTabAttributes().clear();
+ }
+ break;
+ case RTFKeyword::ILVL:
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_ilvl, pIntValue);
+ break;
+ case RTFKeyword::LISTTEMPLATEID:
+ // This one is not referenced anywhere, so it's pointless to store it at the moment.
+ break;
+ case RTFKeyword::LISTID:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTENTRY)
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_abstractNumId,
+ pIntValue);
+ else if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue);
+ m_aStates.top().setCurrentListIndex(nParam);
+ }
+ break;
+ case RTFKeyword::LS:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ {
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
+ pIntValue);
+ m_aStates.top().setCurrentListOverrideIndex(nParam);
+ }
+ else
+ {
+ // Insert at the start, so properties inherited from the list
+ // can be overridden by direct formatting. But still allow the
+ // case when old-style paragraph numbering is already
+ // tokenized.
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND);
+ }
+ }
+ break;
+ case RTFKeyword::UC:
+ if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16))
+ m_aStates.top().setUc(nParam);
+ break;
+ case RTFKeyword::U:
+ // sal_Unicode is unsigned 16-bit, RTF may represent that as a
+ // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The
+ // static_cast() will do the right thing.
+ if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_UINT16))
+ {
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
+ {
+ if (nParam != ';')
+ m_aStates.top().getLevelNumbers().push_back(sal_Int32(nParam));
+ else
+ // ';' in \u form is not considered valid.
+ m_aStates.top().setLevelNumbersValid(false);
+ }
+ else
+ m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam));
+ m_aStates.top().getCharsToSkip() = m_aStates.top().getUc();
+ }
+ break;
+ case RTFKeyword::LEVELFOLLOW:
+ {
+ OUString sValue;
+ switch (nParam)
+ {
+ case 0:
+ sValue = "tab";
+ break;
+ case 1:
+ sValue = "space";
+ break;
+ case 2:
+ sValue = "nothing";
+ break;
+ }
+ if (!sValue.isEmpty())
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue));
+ }
+ break;
+ case RTFKeyword::FPRQ:
+ {
+ sal_Int32 nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_default;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_fixed;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_variable;
+ break;
+ }
+ if (nValue)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue));
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Font_pitch,
+ new RTFValue(aAttributes));
+ }
+ }
+ break;
+ case RTFKeyword::LISTOVERRIDECOUNT:
+ // Ignore this for now, the exporter always emits it with a zero parameter.
+ break;
+ case RTFKeyword::PICSCALEX:
+ m_aStates.top().getPicture().nScaleX = nParam;
+ break;
+ case RTFKeyword::PICSCALEY:
+ m_aStates.top().getPicture().nScaleY = nParam;
+ break;
+ case RTFKeyword::PICW:
+ m_aStates.top().getPicture().nWidth = nParam;
+ break;
+ case RTFKeyword::PICH:
+ m_aStates.top().getPicture().nHeight = nParam;
+ break;
+ case RTFKeyword::PICWGOAL:
+ m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICHGOAL:
+ m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPL:
+ m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPR:
+ m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPT:
+ m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPB:
+ m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::SHPWRK:
+ {
+ int nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right;
+ break;
+ case 3:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest;
+ break;
+ default:
+ break;
+ }
+ auto pValue = new RTFValue(nValue);
+ RTFValue::Pointer_t pTight
+ = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_WrapType_wrapTight);
+ if (pTight)
+ pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue);
+ else
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_WrapSquare_wrapText,
+ pValue);
+ }
+ break;
+ case RTFKeyword::SHPWR:
+ {
+ switch (nParam)
+ {
+ case 1:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_NONE);
+ break;
+ case 2:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
+ break;
+ case 3:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapNone,
+ new RTFValue());
+ break;
+ case 4:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapTight,
+ new RTFValue());
+ break;
+ case 5:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
+ break;
+ }
+ }
+ break;
+ case RTFKeyword::COLS:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num,
+ pIntValue);
+ break;
+ case RTFKeyword::COLSX:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space,
+ pIntValue);
+ break;
+ case RTFKeyword::COLNO:
+ putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols,
+ NS_ooxml::LN_CT_Columns_col, pIntValue);
+ break;
+ case RTFKeyword::COLW:
+ case RTFKeyword::COLSR:
+ {
+ RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols);
+ rAttributes.set((nKeyword == RTFKeyword::COLW ? NS_ooxml::LN_CT_Column_w
+ : NS_ooxml::LN_CT_Column_space),
+ pIntValue);
+ }
+ break;
+ case RTFKeyword::PAPERH:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::PGHSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
+ pIntValue);
+ break;
+ case RTFKeyword::PAPERW:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::PGWSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGL:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGLSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGR:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGRSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGT:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGTSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGB:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGBSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
+ pIntValue);
+ break;
+ case RTFKeyword::HEADERY:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header,
+ pIntValue);
+ break;
+ case RTFKeyword::FOOTERY:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer,
+ pIntValue);
+ break;
+ case RTFKeyword::GUTTER:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_gutter,
+ pIntValue);
+ break;
+ case RTFKeyword::DEFTAB:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue);
+ break;
+ case RTFKeyword::LINEMOD:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_countBy, pIntValue);
+ break;
+ case RTFKeyword::LINEX:
+ if (nParam)
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_distance, pIntValue);
+ break;
+ case RTFKeyword::LINESTARTS:
+ {
+ // OOXML <w:lnNumType w:start="..."/> is 0-based, RTF is 1-based.
+ auto pStart = tools::make_ref<RTFValue>(nParam - 1);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_start, pStart);
+ }
+ break;
+ case RTFKeyword::REVAUTH:
+ case RTFKeyword::REVAUTHDEL:
+ {
+ auto pValue = new RTFValue(m_aAuthors[nParam]);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_CT_TrackChange_author, pValue);
+ }
+ break;
+ case RTFKeyword::REVDTTM:
+ case RTFKeyword::REVDTTMDEL:
+ {
+ OUString aStr(
+ OStringToOUString(DTTM22OString(nParam), m_aStates.top().getCurrentEncoding()));
+ auto pValue = new RTFValue(aStr);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_CT_TrackChange_date, pValue);
+ }
+ break;
+ case RTFKeyword::SHPLEFT:
+ m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPTOP:
+ m_aStates.top().getShape().setTop(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPRIGHT:
+ m_aStates.top().getShape().setRight(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPBOTTOM:
+ m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPZ:
+ m_aStates.top().getShape().setZ(nParam);
+ break;
+ case RTFKeyword::FFTYPE:
+ switch (nParam)
+ {
+ case 0:
+ m_nFormFieldType = RTFFormFieldType::TEXT;
+ break;
+ case 1:
+ m_nFormFieldType = RTFFormFieldType::CHECKBOX;
+ break;
+ case 2:
+ m_nFormFieldType = RTFFormFieldType::LIST;
+ break;
+ default:
+ m_nFormFieldType = RTFFormFieldType::NONE;
+ break;
+ }
+ break;
+ case RTFKeyword::FFDEFRES:
+ if (m_nFormFieldType == RTFFormFieldType::CHECKBOX)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue);
+ else if (m_nFormFieldType == RTFFormFieldType::LIST)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue);
+ break;
+ case RTFKeyword::FFRES:
+ // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits.
+ if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue);
+ else if (m_nFormFieldType == RTFFormFieldType::LIST)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue);
+ break;
+ case RTFKeyword::EDMINS:
+ if (m_xDocumentProperties.is())
+ {
+ // tdf#116851 some RTF may be malformed
+ if (nParam < 0)
+ nParam = -nParam;
+ m_xDocumentProperties->setEditingDuration(nParam);
+ }
+ break;
+ case RTFKeyword::NOFPAGES:
+ case RTFKeyword::NOFWORDS:
+ case RTFKeyword::NOFCHARS:
+ case RTFKeyword::NOFCHARSWS:
+ if (m_xDocumentProperties.is())
+ {
+ comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics();
+ OUString aName;
+ switch (nKeyword)
+ {
+ case RTFKeyword::NOFPAGES:
+ aName = "PageCount";
+ nParam = 99;
+ break;
+ case RTFKeyword::NOFWORDS:
+ aName = "WordCount";
+ break;
+ case RTFKeyword::NOFCHARS:
+ aName = "CharacterCount";
+ break;
+ case RTFKeyword::NOFCHARSWS:
+ aName = "NonWhitespaceCharacterCount";
+ break;
+ default:
+ break;
+ }
+ if (!aName.isEmpty())
+ {
+ aSeq[aName] <<= sal_Int32(nParam);
+ m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList());
+ }
+ }
+ break;
+ case RTFKeyword::VERSION:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setEditingCycles(nParam);
+ break;
+ case RTFKeyword::VERN:
+ // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers.
+ break;
+ case RTFKeyword::FTNSTART:
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
+ break;
+ case RTFKeyword::AFTNSTART:
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_endnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
+ break;
+ case RTFKeyword::DFRMTXTX:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
+ break;
+ case RTFKeyword::DFRMTXTY:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
+ break;
+ case RTFKeyword::DXFRTEXT:
+ {
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
+ }
+ break;
+ case RTFKeyword::FLYVERT:
+ {
+ RTFVertOrient aVertOrient(nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ aVertOrient.GetAlign());
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ aVertOrient.GetAnchor());
+ }
+ break;
+ case RTFKeyword::FLYHORZ:
+ {
+ RTFHoriOrient aHoriOrient(nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ aHoriOrient.GetAlign());
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ aHoriOrient.GetAnchor());
+ }
+ break;
+ case RTFKeyword::FLYANCHOR:
+ break;
+ case RTFKeyword::WMETAFILE:
+ m_aStates.top().getPicture().eWMetafile = nParam;
+ break;
+ case RTFKeyword::SB:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_before, pIntValue);
+ break;
+ case RTFKeyword::SA:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_after, pIntValue);
+ break;
+ case RTFKeyword::DPX:
+ m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPY:
+ m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPXSIZE:
+ m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPYSIZE:
+ m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::PNSTART:
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue);
+ break;
+ case RTFKeyword::PNF:
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue);
+ putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_rPr,
+ NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes));
+ }
+ break;
+ case RTFKeyword::VIEWSCALE:
+ m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue);
+ break;
+ case RTFKeyword::BIN:
+ {
+ m_aStates.top().setInternalState(RTFInternalState::BIN);
+ m_aStates.top().setBinaryToRead(nParam);
+ }
+ break;
+ case RTFKeyword::DPLINECOR:
+ m_aStates.top().getDrawingObject().setLineColorR(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPLINECOG:
+ m_aStates.top().getDrawingObject().setLineColorG(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPLINECOB:
+ m_aStates.top().getDrawingObject().setLineColorB(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCR:
+ m_aStates.top().getDrawingObject().setFillColorR(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCG:
+ m_aStates.top().getDrawingObject().setFillColorG(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCB:
+ m_aStates.top().getDrawingObject().setFillColorB(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DODHGT:
+ m_aStates.top().getDrawingObject().setDhgt(nParam);
+ break;
+ case RTFKeyword::DPPOLYCOUNT:
+ if (nParam >= 0)
+ {
+ m_aStates.top().getDrawingObject().setPolyLineCount(nParam);
+ }
+ break;
+ case RTFKeyword::DPPTX:
+ {
+ RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
+
+ if (rDrawingObject.getPolyLinePoints().empty())
+ dispatchValue(RTFKeyword::DPPOLYCOUNT, 2);
+
+ rDrawingObject.getPolyLinePoints().emplace_back(convertTwipToMm100(nParam), 0);
+ }
+ break;
+ case RTFKeyword::DPPTY:
+ {
+ RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
+ if (!rDrawingObject.getPolyLinePoints().empty())
+ {
+ rDrawingObject.getPolyLinePoints().back().Y = convertTwipToMm100(nParam);
+ rDrawingObject.setPolyLineCount(rDrawingObject.getPolyLineCount() - 1);
+ if (rDrawingObject.getPolyLineCount() == 0 && rDrawingObject.getPropertySet().is())
+ {
+ uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence
+ = { comphelper::containerToSequence(rDrawingObject.getPolyLinePoints()) };
+ rDrawingObject.getPropertySet()->setPropertyValue(
+ "PolyPolygon", uno::Any(aPointSequenceSequence));
+ }
+ }
+ }
+ break;
+ case RTFKeyword::SHPFBLWTXT:
+ // Shape is below text -> send it to the background.
+ m_aStates.top().getShape().setInBackground(nParam != 0);
+ break;
+ case RTFKeyword::FI:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ if (m_aStates.top().getLevelNumbersValid())
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
+ else
+ m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam;
+ }
+ else
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
+ break;
+ }
+ case RTFKeyword::LI:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ if (m_aStates.top().getLevelNumbersValid())
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_left, pIntValue);
+ }
+ else
+ {
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_left, pIntValue);
+ }
+ // It turns out \li should reset the \fi inherited from the stylesheet.
+ // So set the direct formatting to zero, if we don't have such direct formatting yet.
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0),
+ RTFOverwrite::NO_IGNORE);
+ }
+ break;
+ case RTFKeyword::RI:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_right, pIntValue);
+ break;
+ case RTFKeyword::LIN:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_start, pIntValue);
+ break;
+ case RTFKeyword::RIN:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_end, pIntValue);
+ break;
+ case RTFKeyword::OUTLINELEVEL:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue);
+ break;
+ case RTFKeyword::PROPTYPE:
+ {
+ switch (nParam)
+ {
+ case 3:
+ m_aStates.top().setPropType(cppu::UnoType<sal_Int32>::get());
+ break;
+ case 5:
+ m_aStates.top().setPropType(cppu::UnoType<double>::get());
+ break;
+ case 11:
+ m_aStates.top().setPropType(cppu::UnoType<bool>::get());
+ break;
+ case 30:
+ m_aStates.top().setPropType(cppu::UnoType<OUString>::get());
+ break;
+ case 64:
+ m_aStates.top().setPropType(cppu::UnoType<util::DateTime>::get());
+ break;
+ }
+ }
+ break;
+ case RTFKeyword::DIBITMAP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP;
+ break;
+ case RTFKeyword::TRWWIDTHA:
+ m_aStates.top().setTableRowWidthAfter(nParam);
+ break;
+ case RTFKeyword::ANIMTEXT:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_TextEffect_none;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground;
+ break;
+ }
+
+ if (nId > 0)
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_effect,
+ new RTFValue(nId));
+ break;
+ }
+ case RTFKeyword::VIEWBKSP:
+ {
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue);
+ // Send this token immediately, if it only appears before the first
+ // run, it will be too late, we ignored the background shape already by then.
+ outputSettingsTable();
+ break;
+ }
+ case RTFKeyword::STEXTFLOW:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
+ break;
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
+ new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::LBR:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_BrClear_left;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_BrClear_right;
+ break;
+ case 3:
+ nId = NS_ooxml::LN_Value_ST_BrClear_all;
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Br_clear,
+ new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::PGBRDROPT:
+ {
+ sal_Int16 nOffsetFrom = (nParam & 0xe0) >> 5;
+ bool bFromEdge = nOffsetFrom == 1;
+ if (bFromEdge)
+ {
+ Id nId = NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page;
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders,
+ NS_ooxml::LN_CT_PageBorders_offsetFrom, new RTFValue(nId));
+ }
+ }
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter", "TODO handle value '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+} // namespace rtftok
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdocumentfactory.cxx b/writerfilter/source/rtftok/rtfdocumentfactory.cxx
new file mode 100644
index 000000000..75b109b68
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdocumentfactory.cxx
@@ -0,0 +1,28 @@
+/* -*- 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 "rtfdocumentimpl.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFDocument::Pointer_t RTFDocumentFactory::createDocument(
+ css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor)
+{
+ return new RTFDocumentImpl(xContext, xInputStream, xDstDoc, xFrame, xStatusIndicator,
+ rMediaDescriptor);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.cxx b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
new file mode 100644
index 000000000..4011a17d5
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx
@@ -0,0 +1,3992 @@
+/* -*- 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 "rtfdocumentimpl.hxx"
+#include <algorithm>
+#include <memory>
+#include <string_view>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XDependentTextField.hpp>
+#include <i18nlangtag/languagetag.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/rtfutil.hxx>
+#include <comphelper/string.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/globname.hxx>
+#include <tools/datetimeutils.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <svl/lngmisc.hxx>
+#include <sfx2/sfxbasemodel.hxx>
+#include <sfx2/classificationhelper.hxx>
+#include <oox/mathml/import.hxx>
+#include <ooxml/resourceids.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <rtl/uri.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <oox/helper/graphichelper.hxx>
+#include <vcl/wmfexternal.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include "rtfsdrimport.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+#include "rtftokenizer.hxx"
+#include "rtflookahead.hxx"
+#include "rtfcharsets.hxx"
+
+using namespace com::sun::star;
+
+namespace
+{
+/// Returns an util::DateTime from a 'YYYY. MM. DD.' string.
+util::DateTime getDateTimeFromUserProp(const OUString& rString)
+{
+ util::DateTime aRet;
+ sal_Int32 nLen = rString.getLength();
+ if (nLen >= 4)
+ {
+ aRet.Year = o3tl::toInt32(rString.subView(0, 4));
+
+ if (nLen >= 8 && rString.match(". ", 4))
+ {
+ aRet.Month = o3tl::toInt32(rString.subView(6, 2));
+
+ if (nLen >= 12 && rString.match(". ", 8))
+ aRet.Day = o3tl::toInt32(rString.subView(10, 2));
+ }
+ }
+ return aRet;
+}
+} // anonymous namespace
+
+namespace writerfilter::rtftok
+{
+Id getParagraphBorder(sal_uInt32 nIndex)
+{
+ static const Id aBorderIds[]
+ = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left, NS_ooxml::LN_CT_PBdr_bottom,
+ NS_ooxml::LN_CT_PBdr_right, NS_ooxml::LN_CT_PBdr_between };
+
+ return aBorderIds[nIndex];
+}
+
+void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite, bool bAttribute)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent, /*bFirst=*/true, /*bForWrite=*/true);
+ if (!pParent)
+ {
+ RTFSprms aAttributes;
+ if (nParent == NS_ooxml::LN_CT_TcPrBase_shd)
+ {
+ // RTF default is 'auto', see writerfilter::dmapper::CellColorHandler
+ aAttributes.set(NS_ooxml::LN_CT_Shd_color, new RTFValue(sal_uInt32(COL_AUTO)));
+ aAttributes.set(NS_ooxml::LN_CT_Shd_fill, new RTFValue(sal_uInt32(COL_AUTO)));
+ }
+ auto pParentValue = new RTFValue(aAttributes);
+ rSprms.set(nParent, pParentValue, eOverwrite);
+ pParent = pParentValue;
+ }
+ RTFSprms& rAttributes = (bAttribute ? pParent->getAttributes() : pParent->getSprms());
+ rAttributes.set(nId, pValue, eOverwrite);
+}
+
+void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite)
+{
+ putNestedAttribute(rSprms, nParent, nId, pValue, eOverwrite, false);
+}
+
+RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ return RTFValue::Pointer_t();
+ RTFSprms& rAttributes = pParent->getAttributes();
+ return rAttributes.find(nId);
+}
+
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ return RTFValue::Pointer_t();
+ RTFSprms& rInner = pParent->getSprms();
+ return rInner.find(nId);
+}
+
+bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ // It doesn't even have a parent, we're done.
+ return false;
+ RTFSprms& rAttributes = pParent->getAttributes();
+ return rAttributes.erase(nId);
+}
+
+RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId)
+{
+ RTFValue::Pointer_t p = rSprms.find(nId);
+ if (p && !p->getSprms().empty())
+ return p->getSprms().back().second->getAttributes();
+
+ SAL_WARN("writerfilter.rtf", "trying to set property when no type is defined");
+ return rSprms;
+}
+
+void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue)
+{
+ RTFSprms* pAttributes = nullptr;
+ if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH_BOX)
+ for (int i = 0; i < 4; i++)
+ {
+ RTFValue::Pointer_t p = aStates.top().getParagraphSprms().find(getParagraphBorder(i));
+ if (p)
+ {
+ RTFSprms& rAttributes = p->getAttributes();
+ rAttributes.set(nId, pValue);
+ }
+ }
+ else if (aStates.top().getBorderState() == RTFBorderState::CHARACTER)
+ {
+ RTFValue::Pointer_t pPointer
+ = aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_RPrBase_bdr);
+ if (pPointer)
+ {
+ RTFSprms& rAttributes = pPointer->getAttributes();
+ rAttributes.set(nId, pValue);
+ }
+ }
+ // Attributes of the last border type
+ else if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH)
+ pAttributes
+ = &getLastAttributes(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr);
+ else if (aStates.top().getBorderState() == RTFBorderState::CELL)
+ pAttributes = &getLastAttributes(aStates.top().getTableCellSprms(),
+ NS_ooxml::LN_CT_TcPrBase_tcBorders);
+ else if (aStates.top().getBorderState() == RTFBorderState::PAGE)
+ pAttributes = &getLastAttributes(aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders);
+ else if (aStates.top().getBorderState() == RTFBorderState::NONE)
+ {
+ // this is invalid, but Word apparently clears or overrides all paragraph borders now
+ for (int i = 0; i < 4; ++i)
+ {
+ auto const nBorder = getParagraphBorder(i);
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aAttributes.set(NS_ooxml::LN_CT_Border_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+ putNestedSprm(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nBorder,
+ new RTFValue(aAttributes, aSprms), RTFOverwrite::YES);
+ }
+ }
+
+ if (pAttributes)
+ pAttributes->set(nId, pValue);
+}
+
+OString DTTM22OString(tools::Long nDTTM)
+{
+ return DateTimeToOString(msfilter::util::DTTM2DateTime(nDTTM));
+}
+
+static RTFSprms lcl_getBookmarkProperties(int nPos, const OUString& rString)
+{
+ RTFSprms aAttributes;
+ auto pPos = new RTFValue(nPos);
+ if (!rString.isEmpty())
+ {
+ // If present, this should be sent first.
+ auto pString = new RTFValue(rString);
+ aAttributes.set(NS_ooxml::LN_CT_Bookmark_name, pString);
+ }
+ aAttributes.set(NS_ooxml::LN_CT_MarkupRangeBookmark_id, pPos);
+ return aAttributes;
+}
+
+const char* keywordToString(RTFKeyword nKeyword)
+{
+ for (int i = 0; i < nRTFControlWords; i++)
+ {
+ if (nKeyword == aRTFControlWords[i].GetIndex())
+ return aRTFControlWords[i].GetKeyword();
+ }
+ return nullptr;
+}
+
+static util::DateTime lcl_getDateTime(RTFParserState const& aState)
+{
+ return { 0 /*100sec*/,
+ 0 /*sec*/,
+ aState.getMinute(),
+ aState.getHour(),
+ aState.getDay(),
+ aState.getMonth(),
+ static_cast<sal_Int16>(aState.getYear()),
+ false };
+}
+
+static void lcl_DestinationToMath(OUStringBuffer* pDestinationText,
+ oox::formulaimport::XmlStreamBuilder& rMathBuffer, bool& rMathNor)
+{
+ if (!pDestinationText)
+ return;
+ OUString aStr = pDestinationText->makeStringAndClear();
+ if (aStr.isEmpty())
+ return;
+ rMathBuffer.appendOpeningTag(M_TOKEN(r));
+ if (rMathNor)
+ {
+ rMathBuffer.appendOpeningTag(M_TOKEN(rPr));
+ // Same as M_TOKEN(lit)
+ rMathBuffer.appendOpeningTag(M_TOKEN(nor));
+ rMathBuffer.appendClosingTag(M_TOKEN(nor));
+ rMathBuffer.appendClosingTag(M_TOKEN(rPr));
+ rMathNor = false;
+ }
+ rMathBuffer.appendOpeningTag(M_TOKEN(t));
+ rMathBuffer.appendCharacters(aStr);
+ rMathBuffer.appendClosingTag(M_TOKEN(t));
+ rMathBuffer.appendClosingTag(M_TOKEN(r));
+}
+
+RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& xContext,
+ uno::Reference<io::XInputStream> const& xInputStream,
+ uno::Reference<lang::XComponent> const& xDstDoc,
+ uno::Reference<frame::XFrame> const& xFrame,
+ uno::Reference<task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor)
+ : m_xContext(xContext)
+ , m_xInputStream(xInputStream)
+ , m_xDstDoc(xDstDoc)
+ , m_xFrame(xFrame)
+ , m_xStatusIndicator(xStatusIndicator)
+ , m_pMapperStream(nullptr)
+ , m_aDefaultState(this)
+ , m_bSkipUnknown(false)
+ , m_bFirstRun(true)
+ , m_bFirstRunException(false)
+ , m_bNeedPap(true)
+ , m_bNeedCr(false)
+ , m_bNeedCrOrig(false)
+ , m_bNeedPar(true)
+ , m_bNeedFinalPar(false)
+ , m_nNestedCells(0)
+ , m_nTopLevelCells(0)
+ , m_nInheritingCells(0)
+ , m_nNestedTRLeft(0)
+ , m_nTopLevelTRLeft(0)
+ , m_nNestedCurrentCellX(0)
+ , m_nTopLevelCurrentCellX(0)
+ , m_nBackupTopLevelCurrentCellX(0)
+ , m_aTableBufferStack(1) // create top-level buffer already
+ , m_pSuperstream(nullptr)
+ , m_nStreamType(0)
+ , m_nGroupStartPos(0)
+ , m_nFormFieldType(RTFFormFieldType::NONE)
+ , m_bObject(false)
+ , m_nCurrentFontIndex(0)
+ , m_nCurrentEncoding(-1)
+ , m_nDefaultFontIndex(-1)
+ , m_pStyleTableEntries(new RTFReferenceTable::Entries_t)
+ , m_nCurrentStyleIndex(0)
+ , m_bFormField(false)
+ , m_bMathNor(false)
+ , m_bIgnoreNextContSectBreak(false)
+ , m_nResetBreakOnSectBreak(RTFKeyword::invalid)
+ , m_bNeedSect(false) // done by checkFirstRun
+ , m_bWasInFrame(false)
+ , m_bHadPicture(false)
+ , m_bHadSect(false)
+ , m_nCellxMax(0)
+ , m_nListPictureId(0)
+ , m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault("InsertMode", false))
+ , m_rMediaDescriptor(rMediaDescriptor)
+ , m_hasRHeader(false)
+ , m_hasFHeader(false)
+ , m_hasRFooter(false)
+ , m_hasFFooter(false)
+ , m_bAfterCellBeforeRow(false)
+{
+ OSL_ASSERT(xInputStream.is());
+ m_pInStream = utl::UcbStreamHelper::CreateStream(xInputStream, true);
+
+ m_xModelFactory.set(m_xDstDoc, uno::UNO_QUERY);
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
+ m_xDstDoc, uno::UNO_QUERY);
+ if (xDocumentPropertiesSupplier.is())
+ m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+
+ m_pGraphicHelper = std::make_shared<oox::GraphicHelper>(m_xContext, xFrame, oox::StorageRef());
+
+ m_pTokenizer = new RTFTokenizer(*this, m_pInStream.get(), m_xStatusIndicator);
+ m_pSdrImport = new RTFSdrImport(*this, m_xDstDoc);
+}
+
+RTFDocumentImpl::~RTFDocumentImpl() = default;
+
+SvStream& RTFDocumentImpl::Strm() { return *m_pInStream; }
+
+void RTFDocumentImpl::setSuperstream(RTFDocumentImpl* pSuperstream)
+{
+ m_pSuperstream = pSuperstream;
+}
+
+bool RTFDocumentImpl::isSubstream() const { return m_pSuperstream != nullptr; }
+
+void RTFDocumentImpl::finishSubstream() { checkUnicode(/*bUnicode =*/true, /*bHex =*/true); }
+
+void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId)
+{
+ resolveSubstream(nPos, nId, OUString());
+}
+void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst)
+{
+ sal_uInt64 const nCurrent = Strm().Tell();
+ // Seek to header position, parse, then seek back.
+ auto pImpl = new RTFDocumentImpl(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame,
+ m_xStatusIndicator, m_rMediaDescriptor);
+ pImpl->setSuperstream(this);
+ pImpl->m_nStreamType = nId;
+ pImpl->m_aIgnoreFirst = rIgnoreFirst;
+ if (!m_aAuthor.isEmpty())
+ {
+ pImpl->m_aAuthor = m_aAuthor;
+ m_aAuthor.clear();
+ }
+ if (!m_aAuthorInitials.isEmpty())
+ {
+ pImpl->m_aAuthorInitials = m_aAuthorInitials;
+ m_aAuthorInitials.clear();
+ }
+ pImpl->m_nDefaultFontIndex = m_nDefaultFontIndex;
+ pImpl->m_pStyleTableEntries = m_pStyleTableEntries;
+ pImpl->Strm().Seek(nPos);
+ SAL_INFO("writerfilter.rtf", "substream start");
+ Mapper().substream(nId, pImpl);
+ SAL_INFO("writerfilter.rtf", "substream end");
+ Strm().Seek(nCurrent);
+}
+
+void RTFDocumentImpl::outputSettingsTable()
+{
+ // tdf#136740: do not change target document settings when pasting
+ if (!m_bIsNewDoc)
+ return;
+ writerfilter::Reference<Properties>::Pointer_t pProp
+ = new RTFReferenceProperties(m_aSettingsTableAttributes, m_aSettingsTableSprms);
+ RTFReferenceTable::Entries_t aSettingsTableEntries;
+ aSettingsTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t pTable
+ = new RTFReferenceTable(std::move(aSettingsTableEntries));
+ Mapper().table(NS_ooxml::LN_settings_settings, pTable);
+}
+
+void RTFDocumentImpl::checkFirstRun()
+{
+ if (!m_bFirstRun)
+ return;
+
+ outputSettingsTable();
+ // start initial paragraph
+ m_bFirstRun = false;
+ assert(!m_bNeedSect || m_bFirstRunException);
+ setNeedSect(true); // first call that succeeds
+
+ // set the requested default font, if there are none for each state in stack
+ RTFValue::Pointer_t pFont
+ = getNestedAttribute(m_aDefaultState.getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pFont)
+ return;
+
+ for (size_t i = 0; i < m_aStates.size(); i++)
+ {
+ RTFValue::Pointer_t pCurrentFont
+ = getNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pCurrentFont)
+ putNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii, pFont);
+ }
+}
+
+void RTFDocumentImpl::setNeedPar(bool bNeedPar) { m_bNeedPar = bNeedPar; }
+
+void RTFDocumentImpl::setNeedSect(bool bNeedSect)
+{
+ if (!m_bNeedSect && bNeedSect && m_bFirstRun)
+ {
+ RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
+ if (aLookahead.hasTable() && aLookahead.hasColumns())
+ {
+ m_bFirstRunException = true;
+ }
+ }
+
+ // ignore setting before checkFirstRun - every keyword calls setNeedSect!
+ // except the case of a table in a multicolumn section
+ if (!m_bNeedSect && bNeedSect && (!m_bFirstRun || m_bFirstRunException))
+ {
+ if (!m_pSuperstream) // no sections in header/footer!
+ {
+ Mapper().startSectionGroup();
+ }
+ // set flag in substream too - otherwise multiple startParagraphGroup
+ m_bNeedSect = bNeedSect;
+ Mapper().startParagraphGroup();
+ setNeedPar(true);
+ }
+ else if (m_bNeedSect && !bNeedSect)
+ {
+ m_bNeedSect = bNeedSect;
+ }
+}
+
+/// Copy rProps to rStyleAttributes and rStyleSprms, but in case of nested sprms, copy their children as toplevel sprms/attributes.
+static void lcl_copyFlatten(RTFReferenceProperties& rProps, RTFSprms& rStyleAttributes,
+ RTFSprms& rStyleSprms)
+{
+ for (auto& rSprm : rProps.getSprms())
+ {
+ // createStyleProperties() puts properties to rPr, but here we need a flat list.
+ if (rSprm.first == NS_ooxml::LN_CT_Style_rPr)
+ {
+ // rPr can have both attributes and SPRMs, copy over both types.
+ RTFSprms& rRPrSprms = rSprm.second->getSprms();
+ for (const auto& rRPrSprm : rRPrSprms)
+ rStyleSprms.set(rRPrSprm.first, rRPrSprm.second);
+
+ RTFSprms& rRPrAttributes = rSprm.second->getAttributes();
+ for (const auto& rRPrAttribute : rRPrAttributes)
+ rStyleAttributes.set(rRPrAttribute.first, rRPrAttribute.second);
+ }
+ else
+ rStyleSprms.set(rSprm.first, rSprm.second);
+ }
+
+ RTFSprms& rAttributes = rProps.getAttributes();
+ for (const auto& rAttribute : rAttributes)
+ rStyleAttributes.set(rAttribute.first, rAttribute.second);
+}
+
+writerfilter::Reference<Properties>::Pointer_t
+RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType)
+{
+ RTFSprms aSprms(rSprms);
+ RTFValue::Pointer_t pAbstractList;
+ int nAbstractListId = -1;
+ RTFValue::Pointer_t pNumId
+ = getNestedSprm(aSprms, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_numId);
+ if (pNumId)
+ {
+ // We have a numbering, look up the abstract list for property
+ // deduplication and duplication.
+ auto itNumId = m_aListOverrideTable.find(pNumId->getInt());
+ if (itNumId != m_aListOverrideTable.end())
+ {
+ nAbstractListId = itNumId->second;
+ auto itAbstract = m_aListTable.find(nAbstractListId);
+ if (itAbstract != m_aListTable.end())
+ pAbstractList = itAbstract->second;
+ }
+ }
+
+ if (pAbstractList)
+ {
+ auto it = m_aInvalidListTableFirstIndents.find(nAbstractListId);
+ if (it != m_aInvalidListTableFirstIndents.end())
+ aSprms.deduplicateList(it->second);
+ }
+
+ int nStyle = 0;
+ if (!m_aStates.empty())
+ nStyle = m_aStates.top().getCurrentStyleIndex();
+ auto it = m_pStyleTableEntries->find(nStyle);
+ if (it != m_pStyleTableEntries->end())
+ {
+ // cloneAndDeduplicate() wants to know about only a single "style", so
+ // let's merge paragraph and character style properties here.
+ auto itChar = m_pStyleTableEntries->end();
+ if (!m_aStates.empty())
+ {
+ int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex();
+ itChar = m_pStyleTableEntries->find(nCharStyle);
+ }
+
+ RTFSprms aStyleSprms;
+ RTFSprms aStyleAttributes;
+ // Ensure the paragraph style is a flat list.
+ // Take paragraph style into account for character properties as well,
+ // as paragraph style may contain character properties.
+ RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get());
+ lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms);
+
+ if (itChar != m_pStyleTableEntries->end())
+ {
+ // Found active character style, then update aStyleSprms/Attributes.
+ if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ RTFReferenceProperties& rCharProps
+ = *static_cast<RTFReferenceProperties*>(itChar->second.get());
+ lcl_copyFlatten(rCharProps, aStyleAttributes, aStyleSprms);
+ }
+ }
+
+ // Get rid of direct formatting what is already in the style.
+ RTFSprms sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true, &aSprms));
+ RTFSprms attributes(rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true));
+ return new RTFReferenceProperties(std::move(attributes), std::move(sprms));
+ }
+
+ if (pAbstractList)
+ aSprms.duplicateList(pAbstractList);
+ writerfilter::Reference<Properties>::Pointer_t pRet
+ = new RTFReferenceProperties(rAttributes, std::move(aSprms));
+ return pRet;
+}
+
+void RTFDocumentImpl::checkNeedPap()
+{
+ if (!m_bNeedPap)
+ return;
+
+ m_bNeedPap = false; // reset early, so we can avoid recursion when calling ourselves
+
+ if (m_aStates.empty())
+ return;
+
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties(getProperties(
+ m_aStates.top().getParagraphAttributes(), m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_paragraph));
+
+ // Writer will ignore a page break before a text frame, so guard it with empty paragraphs
+ bool hasBreakBeforeFrame
+ = m_aStates.top().getFrame().hasProperties()
+ && m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore);
+ if (hasBreakBeforeFrame)
+ {
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedPap = false;
+ }
+ Mapper().props(pParagraphProperties);
+ if (hasBreakBeforeFrame)
+ dispatchSymbol(RTFKeyword::PAR);
+
+ if (m_aStates.top().getFrame().hasProperties())
+ {
+ writerfilter::Reference<Properties>::Pointer_t const pFrameProperties(
+ new RTFReferenceProperties(RTFSprms(), m_aStates.top().getFrame().getSprms()));
+ Mapper().props(pFrameProperties);
+ }
+ }
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+}
+
+void RTFDocumentImpl::runProps()
+{
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ Reference<Properties>::Pointer_t const pProperties = getProperties(
+ m_aStates.top().getCharacterAttributes(), m_aStates.top().getCharacterSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_character);
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+
+ // Delete the sprm, so the trackchange range will be started only once.
+ // OTOH set a boolean flag, so we'll know we need to end the range later.
+ RTFValue::Pointer_t pTrackchange
+ = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_trackchange);
+ if (pTrackchange)
+ {
+ m_aStates.top().setStartedTrackchange(true);
+ m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_trackchange);
+ }
+}
+
+void RTFDocumentImpl::runBreak()
+{
+ sal_uInt8 const sBreak[] = { 0xd };
+ Mapper().text(sBreak, 1);
+ m_bNeedCr = false;
+}
+
+void RTFDocumentImpl::tableBreak()
+{
+ runBreak();
+ Mapper().endParagraphGroup();
+ Mapper().startParagraphGroup();
+}
+
+void RTFDocumentImpl::parBreak()
+{
+ checkFirstRun();
+ checkNeedPap();
+ // end previous paragraph
+ Mapper().startCharacterGroup();
+ runBreak();
+ Mapper().endCharacterGroup();
+ Mapper().endParagraphGroup();
+
+ m_bHadPicture = false;
+
+ // start new one
+ Mapper().startParagraphGroup();
+}
+
+void RTFDocumentImpl::sectBreak(bool bFinal)
+{
+ SAL_INFO("writerfilter.rtf", __func__ << ": final? " << bFinal << ", needed? " << m_bNeedSect);
+ bool bNeedSect = m_bNeedSect;
+ RTFValue::Pointer_t pBreak
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ bool bContinuous = pBreak && pBreak->getInt() == NS_ooxml::LN_Value_ST_SectionMark_continuous;
+ // If there is no paragraph in this section, then insert a dummy one, as required by Writer,
+ // unless this is the end of the doc, we had nothing since the last section break and this is not a continuous one.
+ // Also, when pasting, it's fine to not have any paragraph inside the document at all.
+ if (m_bNeedPar && (!bFinal || m_bNeedSect || bContinuous) && !isSubstream() && m_bIsNewDoc)
+ dispatchSymbol(RTFKeyword::PAR);
+ // It's allowed to not have a non-table paragraph at the end of an RTF doc, add it now if required.
+ if (m_bNeedFinalPar && bFinal)
+ {
+ dispatchFlag(RTFKeyword::PARD);
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedSect = bNeedSect;
+ }
+ while (!m_nHeaderFooterPositions.empty())
+ {
+ std::pair<Id, std::size_t> aPair = m_nHeaderFooterPositions.front();
+ m_nHeaderFooterPositions.pop();
+ resolveSubstream(aPair.second, aPair.first);
+ }
+
+ // Normally a section break at the end of the doc is necessary. Unless the
+ // last control word in the document is a section break itself.
+ if (!bNeedSect || !m_bHadSect)
+ {
+ // In case the last section is a continuous one, we don't need to output a section break.
+ if (bFinal && bContinuous)
+ m_aStates.top().getSectionSprms().erase(NS_ooxml::LN_EG_SectPrContents_type);
+ }
+
+ // Section properties are a paragraph sprm.
+ auto pValue
+ = new RTFValue(m_aStates.top().getSectionAttributes(), m_aStates.top().getSectionSprms());
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_CT_PPr_sectPr, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+
+ if (bFinal && !m_pSuperstream)
+ // This is the end of the document, not just the end of e.g. a header.
+ // This makes sure that dmapper can set DontBalanceTextColumns=true for this section if necessary.
+ Mapper().markLastSectionGroup();
+
+ // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects.
+ Mapper().props(pProperties);
+ Mapper().endParagraphGroup();
+
+ // End Section
+ if (!m_pSuperstream)
+ {
+ m_hasFHeader = false;
+ m_hasRHeader = false;
+ m_hasRFooter = false;
+ m_hasFFooter = false;
+ Mapper().endSectionGroup();
+ }
+ m_bNeedPar = false;
+ m_bNeedSect = false;
+}
+
+Color RTFDocumentImpl::getColorTable(sal_uInt32 nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ if (nIndex < m_aColorTable.size())
+ return m_aColorTable[nIndex];
+ return 0;
+ }
+
+ return m_pSuperstream->getColorTable(nIndex);
+}
+
+rtl_TextEncoding RTFDocumentImpl::getEncoding(int nFontIndex)
+{
+ if (!m_pSuperstream)
+ {
+ auto it = m_aFontEncodings.find(nFontIndex);
+ if (it != m_aFontEncodings.end())
+ // We have a font encoding associated to this font.
+ return it->second;
+ if (m_aDefaultState.getCurrentEncoding() != rtl_getTextEncodingFromWindowsCharset(0))
+ // We have a default encoding.
+ return m_aDefaultState.getCurrentEncoding();
+ // Guess based on locale.
+ return msfilter::util::getBestTextEncodingFromLocale(
+ Application::GetSettings().GetLanguageTag().getLocale());
+ }
+
+ return m_pSuperstream->getEncoding(nFontIndex);
+}
+
+OUString RTFDocumentImpl::getFontName(int nIndex)
+{
+ if (!m_pSuperstream)
+ return m_aFontNames[nIndex];
+
+ return m_pSuperstream->getFontName(nIndex);
+}
+
+int RTFDocumentImpl::getFontIndex(int nIndex)
+{
+ if (!m_pSuperstream)
+ return std::find(m_aFontIndexes.begin(), m_aFontIndexes.end(), nIndex)
+ - m_aFontIndexes.begin();
+
+ return m_pSuperstream->getFontIndex(nIndex);
+}
+
+OUString RTFDocumentImpl::getStyleName(int nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ OUString aRet;
+ if (m_aStyleNames.find(nIndex) != m_aStyleNames.end())
+ aRet = m_aStyleNames[nIndex];
+ return aRet;
+ }
+
+ return m_pSuperstream->getStyleName(nIndex);
+}
+
+Id RTFDocumentImpl::getStyleType(int nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ Id nRet = 0;
+ if (m_aStyleTypes.find(nIndex) != m_aStyleTypes.end())
+ nRet = m_aStyleTypes[nIndex];
+ return nRet;
+ }
+
+ return m_pSuperstream->getStyleType(nIndex);
+}
+
+RTFParserState& RTFDocumentImpl::getDefaultState()
+{
+ if (!m_pSuperstream)
+ return m_aDefaultState;
+
+ return m_pSuperstream->getDefaultState();
+}
+
+oox::GraphicHelper& RTFDocumentImpl::getGraphicHelper() { return *m_pGraphicHelper; }
+
+bool RTFDocumentImpl::isStyleSheetImport()
+{
+ if (m_aStates.empty())
+ return false;
+ Destination eDestination = m_aStates.top().getDestination();
+ return eDestination == Destination::STYLESHEET || eDestination == Destination::STYLEENTRY;
+}
+
+void RTFDocumentImpl::resolve(Stream& rMapper)
+{
+ m_pMapperStream = &rMapper;
+ switch (m_pTokenizer->resolveParse())
+ {
+ case RTFError::OK:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: finished without errors");
+ break;
+ case RTFError::GROUP_UNDER:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '}'");
+ break;
+ case RTFError::GROUP_OVER:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unmatched '{'");
+ throw io::WrongFormatException(m_pTokenizer->getPosition());
+ break;
+ case RTFError::UNEXPECTED_EOF:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: unexpected end of file");
+ throw io::WrongFormatException(m_pTokenizer->getPosition());
+ break;
+ case RTFError::HEX_INVALID:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: invalid hex char");
+ throw io::WrongFormatException(m_pTokenizer->getPosition());
+ break;
+ case RTFError::CHAR_OVER:
+ SAL_INFO("writerfilter.rtf", "RTFDocumentImpl::resolve: characters after last '}'");
+ break;
+ case RTFError::CLASSIFICATION:
+ SAL_INFO("writerfilter.rtf",
+ "RTFDocumentImpl::resolve: classification prevented paste");
+ break;
+ }
+}
+
+void RTFDocumentImpl::resolvePict(bool const bInline, uno::Reference<drawing::XShape> const& rShape)
+{
+ SvMemoryStream aStream;
+ SvStream* pStream = nullptr;
+ if (!m_pBinaryData)
+ {
+ pStream = &aStream;
+ int b = 0;
+ int count = 2;
+
+ // Feed the destination text to a stream.
+ OString aStr = OUStringToOString(m_aStates.top().getDestinationText().makeStringAndClear(),
+ RTL_TEXTENCODING_ASCII_US);
+ for (int i = 0; i < aStr.getLength(); ++i)
+ {
+ char ch = aStr[i];
+ if (ch != 0x0d && ch != 0x0a && ch != 0x20)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aStream.WriteChar(static_cast<char>(b));
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+ }
+ else
+ pStream = m_pBinaryData.get();
+
+ if (!pStream->Tell())
+ // No destination text? Then we'll get it later.
+ return;
+
+ SvMemoryStream aDIBStream;
+ if (m_aStates.top().getPicture().eStyle == RTFBmpStyle::DIBITMAP)
+ {
+ // Construct a BITMAPFILEHEADER structure before the real data.
+ SvStream& rBodyStream = *pStream;
+ aDIBStream.WriteChar('B');
+ aDIBStream.WriteChar('M');
+ // The size of the real data.
+ aDIBStream.WriteUInt32(rBodyStream.Tell());
+ // Reserved.
+ aDIBStream.WriteUInt32(0);
+ // The offset of the real data, i.e. the size of the header, including this number.
+ aDIBStream.WriteUInt32(14);
+ rBodyStream.Seek(0);
+ aDIBStream.WriteStream(rBodyStream);
+ pStream = &aDIBStream;
+ }
+
+ // Store, and get its URL.
+ pStream->Seek(0);
+ uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream));
+ WmfExternal aExtHeader;
+ aExtHeader.mapMode = m_aStates.top().getPicture().eWMetafile;
+ if (m_aStates.top().getPicture().nGoalWidth == 0
+ || m_aStates.top().getPicture().nGoalHeight == 0)
+ {
+ // Don't use the values provided by picw and pich if the desired size is provided.
+
+ aExtHeader.xExt = sal_uInt16(std::clamp<sal_Int32>(
+ m_aStates.top().getPicture().nWidth, 0,
+ SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
+ aExtHeader.yExt = sal_uInt16(std::clamp<sal_Int32>(
+ m_aStates.top().getPicture().nHeight, 0,
+ SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
+ }
+ WmfExternal* pExtHeader = &aExtHeader;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_aStates.top().getDrawingObject().getShape(),
+ uno::UNO_QUERY);
+ if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ pExtHeader = nullptr;
+
+ uno::Reference<graphic::XGraphic> xGraphic
+ = m_pGraphicHelper->importGraphic(xInputStream, pExtHeader);
+
+ if (m_aStates.top().getPicture().eStyle != RTFBmpStyle::NONE)
+ {
+ // In case of PNG/JPEG, the real size is known, don't use the values
+ // provided by picw and pich.
+
+ Graphic aGraphic(xGraphic);
+ Size aSize(aGraphic.GetPrefSize());
+ MapMode aMap(MapUnit::Map100thMM);
+ if (aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMap);
+ else
+ aSize = OutputDevice::LogicToLogic(aSize, aGraphic.GetPrefMapMode(), aMap);
+ m_aStates.top().getPicture().nWidth = aSize.Width();
+ m_aStates.top().getPicture().nHeight = aSize.Height();
+ }
+
+ uno::Reference<drawing::XShape> xShape(rShape);
+ if (m_aStates.top().getInShape() && xShape.is())
+ {
+ awt::Size aSize = xShape->getSize();
+ if (aSize.Width || aSize.Height)
+ {
+ // resolvePict() is processing pib structure inside shape
+ // So if shape has dimensions we should use them instead of
+ // \picwN, \pichN, \picscalexN, \picscaleyN given with picture
+ m_aStates.top().getPicture().nGoalWidth = aSize.Width;
+ m_aStates.top().getPicture().nGoalHeight = aSize.Height;
+ m_aStates.top().getPicture().nScaleX = 100;
+ m_aStates.top().getPicture().nScaleY = 100;
+ }
+ }
+
+ // Wrap it in an XShape.
+ if (xShape.is())
+ {
+ uno::Reference<lang::XServiceInfo> xSI(xShape, uno::UNO_QUERY_THROW);
+ if (!xSI->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ // it's sometimes an error to get here - but it's possible to have
+ // a \pict inside the \shptxt of a \shp of shapeType 202 "TextBox"
+ // and in that case xShape is the text frame; we actually need a
+ // new GraphicObject then (example: fdo37691-1.rtf)
+ SAL_INFO("writerfilter.rtf",
+ "cannot set graphic on existing shape, creating a new GraphicObjectShape");
+ xShape.clear();
+ }
+ }
+ if (!xShape.is())
+ {
+ if (m_xModelFactory.is())
+ xShape.set(m_xModelFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPageSupplier> const xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
+ if (xShapes.is())
+ xShapes->add(xShape);
+ }
+ }
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("Graphic", uno::Any(xGraphic));
+
+ // check if the picture is in an OLE object and if the \objdata element is used
+ // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
+ if (m_bObject)
+ {
+ // Set the object size
+ awt::Size aSize;
+ aSize.Width
+ = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
+ : m_aStates.top().getPicture().nWidth);
+ aSize.Height
+ = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
+ : m_aStates.top().getPicture().nHeight);
+ xShape->setSize(aSize);
+
+ // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert().
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+
+ auto pShapeValue = new RTFValue(xShape);
+ m_aObjectAttributes.set(NS_ooxml::LN_shape, pShapeValue);
+ return;
+ }
+
+ if (m_aStates.top().getInListpicture())
+ {
+ // Send the shape directly, no section is started, to additional properties will be ignored anyway.
+ Mapper().startShape(xShape);
+ Mapper().endShape();
+ return;
+ }
+
+ // Send it to the dmapper.
+ RTFSprms aSprms;
+ RTFSprms aAttributes;
+ // shape attribute
+ RTFSprms aPicAttributes;
+ auto pShapeValue = new RTFValue(xShape);
+ aPicAttributes.set(NS_ooxml::LN_shape, pShapeValue);
+ // pic sprm
+ RTFSprms aGraphicDataAttributes;
+ RTFSprms aGraphicDataSprms;
+ auto pPicValue = new RTFValue(aPicAttributes);
+ aGraphicDataSprms.set(NS_ooxml::LN_pic_pic, pPicValue);
+ // graphicData sprm
+ RTFSprms aGraphicAttributes;
+ RTFSprms aGraphicSprms;
+ auto pGraphicDataValue = new RTFValue(aGraphicDataAttributes, aGraphicDataSprms);
+ aGraphicSprms.set(NS_ooxml::LN_CT_GraphicalObject_graphicData, pGraphicDataValue);
+ // graphic sprm
+ auto pGraphicValue = new RTFValue(aGraphicAttributes, aGraphicSprms);
+ // extent sprm
+ RTFSprms aExtentAttributes;
+ int nXExt = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
+ : m_aStates.top().getPicture().nWidth);
+ int nYExt = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
+ : m_aStates.top().getPicture().nHeight);
+ if (m_aStates.top().getPicture().nScaleX != 100)
+ nXExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleX)
+ * (nXExt
+ - (m_aStates.top().getPicture().nCropL + m_aStates.top().getPicture().nCropR)))
+ / 100L;
+ if (m_aStates.top().getPicture().nScaleY != 100)
+ nYExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleY)
+ * (nYExt
+ - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB)))
+ / 100L;
+ auto pXExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nXExt));
+ auto pYExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nYExt));
+ aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cx, pXExtValue);
+ aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cy, pYExtValue);
+ auto pExtentValue = new RTFValue(aExtentAttributes);
+ // docpr sprm
+ RTFSprms aDocprAttributes;
+ for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
+ if (rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_name
+ || rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_descr)
+ aDocprAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
+ auto pDocprValue = new RTFValue(aDocprAttributes);
+ if (bInline)
+ {
+ RTFSprms aInlineAttributes;
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distT, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distB, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distL, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distR, new RTFValue(0));
+ RTFSprms aInlineSprms;
+ aInlineSprms.set(NS_ooxml::LN_CT_Inline_extent, pExtentValue);
+ aInlineSprms.set(NS_ooxml::LN_CT_Inline_docPr, pDocprValue);
+ aInlineSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
+ // inline sprm
+ auto pValue = new RTFValue(aInlineAttributes, aInlineSprms);
+ aSprms.set(NS_ooxml::LN_inline_inline, pValue);
+ }
+ else // anchored
+ {
+ // wrap sprm
+ RTFSprms aAnchorWrapAttributes;
+ m_aStates.top().getShape().getAnchorAttributes().set(
+ NS_ooxml::LN_CT_Anchor_behindDoc,
+ new RTFValue((m_aStates.top().getShape().getInBackground()) ? 1 : 0));
+ RTFSprms aAnchorSprms;
+ for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
+ {
+ if (rCharacterAttribute.first == NS_ooxml::LN_CT_WrapSquare_wrapText)
+ aAnchorWrapAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
+ }
+ sal_Int32 nWrap = -1;
+ for (auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
+ {
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
+ || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
+ {
+ nWrap = rCharacterSprm.first;
+
+ // If there is a wrap polygon prepared by RTFSdrImport, pick it up here.
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight
+ && !m_aStates.top().getShape().getWrapPolygonSprms().empty())
+ rCharacterSprm.second->getSprms().set(
+ NS_ooxml::LN_CT_WrapTight_wrapPolygon,
+ new RTFValue(RTFSprms(), m_aStates.top().getShape().getWrapPolygonSprms()));
+
+ aAnchorSprms.set(rCharacterSprm.first, rCharacterSprm.second);
+ }
+ }
+
+ if (m_aStates.top().getShape().getWrapSprm().first != 0)
+ // Replay of a buffered shape, wrap sprm there has priority over
+ // character sprms of the current state.
+ aAnchorSprms.set(m_aStates.top().getShape().getWrapSprm().first,
+ m_aStates.top().getShape().getWrapSprm().second);
+
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_extent, pExtentValue);
+ if (!aAnchorWrapAttributes.empty() && nWrap == -1)
+ aAnchorSprms.set(NS_ooxml::LN_EG_WrapType_wrapSquare,
+ new RTFValue(aAnchorWrapAttributes));
+
+ // See OOXMLFastContextHandler::positionOffset(), we can't just put offset values in an RTFValue.
+ RTFSprms aPoshAttributes;
+ RTFSprms aPoshSprms;
+ if (m_aStates.top().getShape().getHoriOrientRelationToken() > 0)
+ aPoshAttributes.set(
+ NS_ooxml::LN_CT_PosH_relativeFrom,
+ new RTFValue(m_aStates.top().getShape().getHoriOrientRelationToken()));
+ if (m_aStates.top().getShape().getLeft() != 0)
+ {
+ Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
+ m_aStates.top().getShape().getLeft())),
+ /*bVertical=*/false);
+ aPoshSprms.set(NS_ooxml::LN_CT_PosH_posOffset, new RTFValue());
+ }
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionH,
+ new RTFValue(aPoshAttributes, aPoshSprms));
+
+ RTFSprms aPosvAttributes;
+ RTFSprms aPosvSprms;
+ if (m_aStates.top().getShape().getVertOrientRelationToken() > 0)
+ aPosvAttributes.set(
+ NS_ooxml::LN_CT_PosV_relativeFrom,
+ new RTFValue(m_aStates.top().getShape().getVertOrientRelationToken()));
+ if (m_aStates.top().getShape().getTop() != 0)
+ {
+ Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
+ m_aStates.top().getShape().getTop())),
+ /*bVertical=*/true);
+ aPosvSprms.set(NS_ooxml::LN_CT_PosV_posOffset, new RTFValue());
+ }
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionV,
+ new RTFValue(aPosvAttributes, aPosvSprms));
+
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_docPr, pDocprValue);
+ aAnchorSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
+ // anchor sprm
+ auto pValue = new RTFValue(m_aStates.top().getShape().getAnchorAttributes(), aAnchorSprms);
+ aSprms.set(NS_ooxml::LN_anchor_anchor, pValue);
+ }
+ checkFirstRun();
+
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ // Make sure we don't lose these properties with a too early reset.
+ m_bHadPicture = true;
+ }
+ else
+ {
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+}
+
+RTFError RTFDocumentImpl::resolveChars(char ch)
+{
+ if (m_aStates.top().getInternalState() == RTFInternalState::BIN)
+ {
+ m_pBinaryData = std::make_shared<SvMemoryStream>();
+ m_pBinaryData->WriteChar(ch);
+ for (int i = 0; i < m_aStates.top().getBinaryToRead() - 1; ++i)
+ {
+ Strm().ReadChar(ch);
+ m_pBinaryData->WriteChar(ch);
+ }
+ m_aStates.top().setInternalState(RTFInternalState::NORMAL);
+ return RTFError::OK;
+ }
+
+ OStringBuffer aBuf(512);
+
+ bool bUnicodeChecked = false;
+ bool bSkipped = false;
+
+ while (!Strm().eof()
+ && (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ || (ch != '{' && ch != '}' && ch != '\\')))
+ {
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ || (ch != 0x0d && ch != 0x0a))
+ {
+ if (m_aStates.top().getCharsToSkip() == 0)
+ {
+ if (!bUnicodeChecked)
+ {
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
+ bUnicodeChecked = true;
+ }
+ aBuf.append(ch);
+ }
+ else
+ {
+ bSkipped = true;
+ m_aStates.top().getCharsToSkip()--;
+ }
+ }
+
+ // read a single char if we're in hex mode
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX)
+ break;
+
+ if (RTL_TEXTENCODING_MS_932 == m_aStates.top().getCurrentEncoding())
+ {
+ unsigned char uch = ch;
+ if ((uch >= 0x80 && uch <= 0x9F) || uch >= 0xE0)
+ {
+ // read second byte of 2-byte Shift-JIS - may be \ { }
+ Strm().ReadChar(ch);
+ if (m_aStates.top().getCharsToSkip() == 0)
+ {
+ // fdo#79384: Word will reject Shift-JIS following \loch
+ // but apparently OOo could read and (worse) write such documents
+ SAL_INFO_IF(m_aStates.top().getRunType() != RTFParserState::RunType::DBCH,
+ "writerfilter.rtf", "invalid Shift-JIS without DBCH");
+ assert(bUnicodeChecked);
+ aBuf.append(ch);
+ }
+ else
+ {
+ assert(bSkipped);
+ // anybody who uses \ucN with Shift-JIS is insane
+ m_aStates.top().getCharsToSkip()--;
+ }
+ }
+ }
+
+ Strm().ReadChar(ch);
+ }
+ if (m_aStates.top().getInternalState() != RTFInternalState::HEX && !Strm().eof())
+ Strm().SeekRel(-1);
+
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ && m_aStates.top().getDestination() != Destination::LEVELNUMBERS)
+ {
+ if (!bSkipped)
+ {
+ // note: apparently \'0d\'0a is interpreted as 2 breaks, not 1
+ if ((ch == '\r' || ch == '\n')
+ && m_aStates.top().getDestination() != Destination::DOCCOMM
+ && m_aStates.top().getDestination() != Destination::LEVELNUMBERS
+ && m_aStates.top().getDestination() != Destination::LEVELTEXT)
+ {
+ checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
+ dispatchSymbol(RTFKeyword::PAR);
+ }
+ else
+ {
+ m_aHexBuffer.append(ch);
+ }
+ }
+ return RTFError::OK;
+ }
+
+ if (m_aStates.top().getDestination() == Destination::SKIP)
+ return RTFError::OK;
+ OString aStr = aBuf.makeStringAndClear();
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
+ {
+ if (aStr.toChar() != ';')
+ m_aStates.top().getLevelNumbers().push_back(sal_Int32(ch));
+ return RTFError::OK;
+ }
+
+ SAL_INFO("writerfilter.rtf",
+ "RTFDocumentImpl::resolveChars: collected '"
+ << OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()) << "'");
+
+ if (m_aStates.top().getDestination() == Destination::COLORTABLE)
+ {
+ // we hit a ';' at the end of each color entry
+ m_aColorTable.push_back(m_aStates.top().getCurrentColor().GetColor());
+ // set components back to zero
+ m_aStates.top().getCurrentColor() = RTFColorTableEntry();
+ }
+ else if (!aStr.isEmpty())
+ m_aHexBuffer.append(aStr);
+
+ checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
+ return RTFError::OK;
+}
+
+bool RTFFrame::inFrame() const { return m_nW > 0 || m_nH > 0 || m_nX > 0 || m_nY > 0; }
+
+void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
+{
+ sal_uInt8 sValue[] = { nValue };
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+
+ if (!pCurrentBuffer)
+ {
+ Mapper().startCharacterGroup();
+ }
+ else
+ {
+ pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, nullptr, nullptr));
+ }
+
+ // Should we send run properties?
+ if (bRunProps)
+ runProps();
+
+ if (!pCurrentBuffer)
+ {
+ Mapper().text(sValue, 1);
+ Mapper().endCharacterGroup();
+ }
+ else
+ {
+ auto pValue = new RTFValue(*sValue);
+ pCurrentBuffer->push_back(Buf_t(BUFFER_TEXT, pValue, nullptr));
+ pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, nullptr, nullptr));
+ }
+}
+
+void RTFDocumentImpl::handleFontTableEntry()
+{
+ OUString aName = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ if (aName.isEmpty())
+ return;
+
+ if (aName.endsWith(";"))
+ {
+ aName = aName.copy(0, aName.getLength() - 1);
+ }
+
+ // Old documents can contain no encoding information in fontinfo,
+ // but there can be font name suffixes: Arial CE is not a special
+ // font, it is ordinal Arial, but with used cp 1250 encoding.
+ // Moreover these suffixes have priority over \cpgN and \fcharsetN
+ // in MS Word.
+ OUString aFontSuffix;
+ OUString aNameNoSuffix(aName);
+ sal_Int32 nLastSpace = aName.lastIndexOf(' ');
+ if (nLastSpace >= 0)
+ {
+ aFontSuffix = aName.copy(nLastSpace + 1);
+ aNameNoSuffix = aName.copy(0, nLastSpace);
+ sal_Int32 nEncoding = RTL_TEXTENCODING_DONTKNOW;
+ for (int i = 0; aRTFFontNameSuffixes[i].codepage != RTL_TEXTENCODING_DONTKNOW; i++)
+ {
+ if (aFontSuffix.equalsAscii(aRTFFontNameSuffixes[i].suffix))
+ {
+ nEncoding = aRTFFontNameSuffixes[i].codepage;
+ break;
+ }
+ }
+ if (nEncoding > RTL_TEXTENCODING_DONTKNOW)
+ {
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ else
+ {
+ // Unknown suffix: looks like it is just a part of font name, restore it
+ aNameNoSuffix = aName;
+ }
+ }
+
+ m_aFontNames[m_nCurrentFontIndex] = aNameNoSuffix;
+ if (m_nCurrentEncoding >= 0)
+ {
+ m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
+ m_nCurrentEncoding = -1;
+ }
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
+ new RTFValue(aNameNoSuffix));
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+
+ //See fdo#47347 initial invalid font entry properties are inserted first,
+ //so when we attempt to insert the correct ones, there's already an
+ //entry in the map for them, so the new ones aren't inserted.
+ auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
+ if (lb != m_aFontTableEntries.end()
+ && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
+ lb->second = pProp;
+ else
+ m_aFontTableEntries.insert(lb, std::make_pair(m_nCurrentFontIndex, pProp));
+}
+
+void RTFDocumentImpl::text(OUString& rString)
+{
+ if (rString.getLength() == 1 && m_aStates.top().getDestination() != Destination::DOCCOMM)
+ {
+ // No cheating! Tokenizer ignores bare \r and \n, their hex \'0d / \'0a form doesn't count, either.
+ sal_Unicode ch = rString[0];
+ if (ch == 0x0d || ch == 0x0a)
+ return;
+ }
+
+ bool bRet = true;
+ switch (m_aStates.top().getDestination())
+ {
+ // Note: in stylesheet and revtbl groups are mandatory
+ case Destination::STYLEENTRY:
+ case Destination::LISTNAME:
+ case Destination::REVISIONENTRY:
+ {
+ // ; is the end of the entry
+ bool bEnd = false;
+ if (rString.endsWith(";"))
+ {
+ rString = rString.copy(0, rString.getLength() - 1);
+ bEnd = true;
+ }
+ m_aStates.top().appendDestinationText(rString);
+ if (bEnd)
+ {
+ // always clear, necessary in case of group-less fonttable
+ OUString const aName
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ switch (m_aStates.top().getDestination())
+ {
+ case Destination::STYLEENTRY:
+ {
+ RTFValue::Pointer_t pType
+ = m_aStates.top().getTableAttributes().find(NS_ooxml::LN_CT_Style_type);
+ if (pType)
+ {
+ // Word strips whitespace around style names.
+ m_aStyleNames[m_nCurrentStyleIndex] = aName.trim();
+ m_aStyleTypes[m_nCurrentStyleIndex] = pType->getInt();
+ auto pValue = new RTFValue(aName.trim());
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_styleId,
+ pValue);
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_name, pValue);
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(
+ createStyleProperties());
+ m_pStyleTableEntries->insert(
+ std::make_pair(m_nCurrentStyleIndex, pProp));
+ }
+ else
+ SAL_INFO("writerfilter.rtf", "no RTF style type defined, ignoring");
+ break;
+ }
+ case Destination::LISTNAME:
+ // TODO: what can be done with a list name?
+ break;
+ case Destination::REVISIONENTRY:
+ m_aAuthors[m_aAuthors.size()] = aName;
+ break;
+ default:
+ break;
+ }
+ resetAttributes();
+ resetSprms();
+ }
+ }
+ break;
+ case Destination::DOCVAR:
+ {
+ m_aStates.top().appendDocVar(rString);
+ }
+ break;
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
+ case Destination::LEVELTEXT:
+ case Destination::SHAPEPROPERTYNAME:
+ case Destination::SHAPEPROPERTYVALUE:
+ case Destination::BOOKMARKEND:
+ case Destination::PICT:
+ case Destination::SHAPEPROPERTYVALUEPICT:
+ case Destination::FORMFIELDNAME:
+ case Destination::FORMFIELDLIST:
+ case Destination::DATAFIELD:
+ case Destination::AUTHOR:
+ case Destination::KEYWORDS:
+ case Destination::OPERATOR:
+ case Destination::COMPANY:
+ case Destination::COMMENT:
+ case Destination::OBJDATA:
+ case Destination::OBJCLASS:
+ case Destination::ANNOTATIONDATE:
+ case Destination::ANNOTATIONAUTHOR:
+ case Destination::ANNOTATIONREFERENCE:
+ case Destination::FALT:
+ case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
+ case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
+ case Destination::TITLE:
+ case Destination::SUBJECT:
+ case Destination::DOCCOMM:
+ case Destination::ATNID:
+ case Destination::ANNOTATIONREFERENCESTART:
+ case Destination::ANNOTATIONREFERENCEEND:
+ case Destination::MR:
+ case Destination::MCHR:
+ case Destination::MPOS:
+ case Destination::MVERTJC:
+ case Destination::MSTRIKEH:
+ case Destination::MDEGHIDE:
+ case Destination::MBEGCHR:
+ case Destination::MSEPCHR:
+ case Destination::MENDCHR:
+ case Destination::MSUBHIDE:
+ case Destination::MSUPHIDE:
+ case Destination::MTYPE:
+ case Destination::MGROW:
+ case Destination::INDEXENTRY:
+ case Destination::TOCENTRY:
+ case Destination::PROPNAME:
+ case Destination::STATICVAL:
+ m_aStates.top().appendDestinationText(rString);
+ break;
+ case Destination::GENERATOR:
+ // don't enlarge space sequences, eg. it was saved in LibreOffice
+ if (!rString.startsWithIgnoreAsciiCase("Microsoft"))
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ default:
+ bRet = false;
+ break;
+ }
+ if (bRet)
+ return;
+
+ if (!m_aIgnoreFirst.isEmpty() && m_aIgnoreFirst == rString)
+ {
+ m_aIgnoreFirst.clear();
+ return;
+ }
+
+ // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
+ if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign)
+ && m_nTopLevelCells == 0)
+ {
+ m_aTableBufferStack.back().emplace_back(BUFFER_UTEXT, new RTFValue(rString), nullptr);
+ return;
+ }
+
+ checkFirstRun();
+ checkNeedPap();
+
+ // Don't return earlier, a bookmark start has to be in a paragraph group.
+ if (m_aStates.top().getDestination() == Destination::BOOKMARKSTART)
+ {
+ m_aStates.top().appendDestinationText(rString);
+ return;
+ }
+
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+
+ if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
+ Mapper().startCharacterGroup();
+ else if (pCurrentBuffer)
+ {
+ RTFValue::Pointer_t pValue;
+ pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, pValue, nullptr));
+ }
+
+ if (m_aStates.top().getDestination() == Destination::NORMAL
+ || m_aStates.top().getDestination() == Destination::FIELDRESULT
+ || m_aStates.top().getDestination() == Destination::SHAPETEXT)
+ runProps();
+
+ if (!pCurrentBuffer)
+ Mapper().utext(reinterpret_cast<sal_uInt8 const*>(rString.getStr()), rString.getLength());
+ else
+ {
+ auto pValue = new RTFValue(rString);
+ pCurrentBuffer->push_back(Buf_t(BUFFER_UTEXT, pValue, nullptr));
+ }
+
+ m_bNeedCr = true;
+
+ if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
+ Mapper().endCharacterGroup();
+ else if (pCurrentBuffer)
+ {
+ RTFValue::Pointer_t pValue;
+ pCurrentBuffer->push_back(Buf_t(BUFFER_ENDRUN, pValue, nullptr));
+ }
+}
+
+void RTFDocumentImpl::prepareProperties(
+ RTFParserState& rState, writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties, int const nCells,
+ int const nCurrentCellX)
+{
+ o_rpParagraphProperties
+ = getProperties(rState.getParagraphAttributes(), rState.getParagraphSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_paragraph);
+
+ if (rState.getFrame().hasProperties())
+ {
+ o_rpFrameProperties = new RTFReferenceProperties(RTFSprms(), rState.getFrame().getSprms());
+ }
+
+ // Table width.
+ RTFValue::Pointer_t const pTableWidthProps
+ = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblW);
+ if (!pTableWidthProps)
+ {
+ auto pUnitValue = new RTFValue(3);
+ putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_type, pUnitValue);
+ auto pWValue = new RTFValue(nCurrentCellX);
+ putNestedAttribute(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_w, pWValue);
+ }
+
+ if (nCells > 0)
+ rState.getTableRowSprms().set(NS_ooxml::LN_tblRow, new RTFValue(1));
+
+ RTFValue::Pointer_t const pCellMar
+ = rState.getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
+ if (!pCellMar)
+ {
+ // If no cell margins are defined, the default left/right margin is 0 in Word, but not in Writer.
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(0));
+ putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_left, new RTFValue(aAttributes));
+ putNestedSprm(rState.getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
+ }
+
+ o_rpTableRowProperties
+ = new RTFReferenceProperties(rState.getTableRowAttributes(), rState.getTableRowSprms());
+}
+
+void RTFDocumentImpl::sendProperties(
+ writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties)
+{
+ Mapper().props(pParagraphProperties);
+
+ if (pFrameProperties)
+ {
+ Mapper().props(pFrameProperties);
+ }
+
+ Mapper().props(pTableRowProperties);
+
+ tableBreak();
+}
+
+void RTFDocumentImpl::replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSrpms,
+ ::std::deque<RTFSprms>& rCellsAttributes, int const nCells)
+{
+ for (int i = 0; i < nCells; ++i)
+ {
+ replayBuffer(rBuffer, &rCellsSrpms.front(), &rCellsAttributes.front());
+ rCellsSrpms.pop_front();
+ rCellsAttributes.pop_front();
+ }
+ for (Buf_t& i : rBuffer)
+ {
+ SAL_WARN_IF(BUFFER_CELLEND == std::get<0>(i), "writerfilter.rtf", "dropping table cell!");
+ }
+ assert(rCellsSrpms.empty());
+ assert(rCellsAttributes.empty());
+}
+
+void RTFDocumentImpl::replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* const pSprms,
+ RTFSprms const* const pAttributes)
+{
+ while (!rBuffer.empty())
+ {
+ Buf_t aTuple(rBuffer.front());
+ rBuffer.pop_front();
+ if (std::get<0>(aTuple) == BUFFER_PROPS)
+ {
+ // Construct properties via getProperties() and not directly, to take care of deduplication.
+ writerfilter::Reference<Properties>::Pointer_t const pProp(getProperties(
+ std::get<1>(aTuple)->getAttributes(), std::get<1>(aTuple)->getSprms(), 0));
+ Mapper().props(pProp);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_NESTROW)
+ {
+ TableRowBuffer& rRowBuffer(*std::get<2>(aTuple));
+
+ replayRowBuffer(rRowBuffer.GetBuffer(), rRowBuffer.GetCellsSprms(),
+ rRowBuffer.GetCellsAttributes(), rRowBuffer.GetCells());
+
+ sendProperties(rRowBuffer.GetParaProperties(), rRowBuffer.GetFrameProperties(),
+ rRowBuffer.GetRowProperties());
+ }
+ else if (std::get<0>(aTuple) == BUFFER_CELLEND)
+ {
+ assert(pSprms && pAttributes);
+ auto pValue = new RTFValue(1);
+ pSprms->set(NS_ooxml::LN_tblCell, pValue);
+ writerfilter::Reference<Properties>::Pointer_t const pTableCellProperties(
+ new RTFReferenceProperties(*pAttributes, *pSprms));
+ Mapper().props(pTableCellProperties);
+ tableBreak();
+ break;
+ }
+ else if (std::get<0>(aTuple) == BUFFER_STARTRUN)
+ Mapper().startCharacterGroup();
+ else if (std::get<0>(aTuple) == BUFFER_TEXT)
+ {
+ sal_uInt8 const nValue = std::get<1>(aTuple)->getInt();
+ Mapper().text(&nValue, 1);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_UTEXT)
+ {
+ OUString const aString(std::get<1>(aTuple)->getString());
+ Mapper().utext(reinterpret_cast<sal_uInt8 const*>(aString.getStr()),
+ aString.getLength());
+ }
+ else if (std::get<0>(aTuple) == BUFFER_ENDRUN)
+ Mapper().endCharacterGroup();
+ else if (std::get<0>(aTuple) == BUFFER_PAR)
+ parBreak();
+ else if (std::get<0>(aTuple) == BUFFER_STARTSHAPE)
+ m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), false, RTFSdrImport::SHAPE);
+ else if (std::get<0>(aTuple) == BUFFER_RESOLVESHAPE)
+ {
+ // Make sure there is no current buffer while replaying the shape,
+ // otherwise it gets re-buffered.
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+ m_aStates.top().setCurrentBuffer(nullptr);
+
+ // Set current shape during replay, needed by e.g. wrap in
+ // background.
+ RTFShape aShape = m_aStates.top().getShape();
+ m_aStates.top().getShape() = std::get<1>(aTuple)->getShape();
+
+ m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), true, RTFSdrImport::SHAPE);
+ m_aStates.top().getShape() = aShape;
+ m_aStates.top().setCurrentBuffer(pCurrentBuffer);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_ENDSHAPE)
+ m_pSdrImport->close();
+ else if (std::get<0>(aTuple) == BUFFER_RESOLVESUBSTREAM)
+ {
+ RTFSprms& rAttributes = std::get<1>(aTuple)->getAttributes();
+ std::size_t nPos = rAttributes.find(0)->getInt();
+ Id nId = rAttributes.find(1)->getInt();
+ OUString aCustomMark = rAttributes.find(2)->getString();
+ resolveSubstream(nPos, nId, aCustomMark);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_PICTURE)
+ m_aStates.top().getPicture() = std::get<1>(aTuple)->getPicture();
+ else if (std::get<0>(aTuple) == BUFFER_SETSTYLE)
+ {
+ if (!m_aStates.empty())
+ m_aStates.top().setCurrentStyleIndex(std::get<1>(aTuple)->getInt());
+ }
+ else
+ assert(false);
+ }
+}
+
+bool findPropertyName(const std::vector<beans::PropertyValue>& rProperties, const OUString& rName)
+{
+ return std::any_of(
+ rProperties.begin(), rProperties.end(),
+ [&rName](const beans::PropertyValue& rProperty) { return rProperty.Name == rName; });
+}
+
+void RTFDocumentImpl::backupTableRowProperties()
+{
+ if (m_nTopLevelCurrentCellX)
+ {
+ m_aBackupTableRowSprms = m_aStates.top().getTableRowSprms();
+ m_aBackupTableRowAttributes = m_aStates.top().getTableRowAttributes();
+ m_nBackupTopLevelCurrentCellX = m_nTopLevelCurrentCellX;
+ }
+}
+
+void RTFDocumentImpl::restoreTableRowProperties()
+{
+ m_aStates.top().getTableRowSprms() = m_aBackupTableRowSprms;
+ m_aStates.top().getTableRowAttributes() = m_aBackupTableRowAttributes;
+ m_nTopLevelCurrentCellX = m_nBackupTopLevelCurrentCellX;
+}
+
+void RTFDocumentImpl::resetTableRowProperties()
+{
+ m_aStates.top().getTableRowSprms() = m_aDefaultState.getTableRowSprms();
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, new RTFValue(-1),
+ RTFOverwrite::NO_APPEND);
+ m_aStates.top().getTableRowAttributes() = m_aDefaultState.getTableRowAttributes();
+ if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ {
+ m_nNestedTRLeft = 0;
+ m_nNestedCurrentCellX = 0;
+ }
+ else
+ {
+ m_nTopLevelTRLeft = 0;
+ m_nTopLevelCurrentCellX = 0;
+ }
+}
+
+RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nSprm = -1;
+ tools::SvRef<RTFValue> pBoolValue(new RTFValue(int(!bParam || nParam != 0)));
+
+ // Underline toggles.
+ switch (nKeyword)
+ {
+ case RTFKeyword::UL:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_single;
+ break;
+ case RTFKeyword::ULDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dash;
+ break;
+ case RTFKeyword::ULDASHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash;
+ break;
+ case RTFKeyword::ULDASHDD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash;
+ break;
+ case RTFKeyword::ULDB:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_double;
+ break;
+ case RTFKeyword::ULHWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy;
+ break;
+ case RTFKeyword::ULLDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong;
+ break;
+ case RTFKeyword::ULTH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_thick;
+ break;
+ case RTFKeyword::ULTHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy;
+ break;
+ case RTFKeyword::ULTHDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy;
+ break;
+ case RTFKeyword::ULTHDASHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy;
+ break;
+ case RTFKeyword::ULTHDASHDD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy;
+ break;
+ case RTFKeyword::ULTHLDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy;
+ break;
+ case RTFKeyword::ULULDBWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble;
+ break;
+ case RTFKeyword::ULWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wave;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue
+ = new RTFValue((!bParam || nParam != 0) ? nSprm : NS_ooxml::LN_Value_ST_Underline_none);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Accent characters (over dot / over comma).
+ switch (nKeyword)
+ {
+ case RTFKeyword::ACCNONE:
+ nSprm = NS_ooxml::LN_Value_ST_Em_none;
+ break;
+ case RTFKeyword::ACCDOT:
+ nSprm = NS_ooxml::LN_Value_ST_Em_dot;
+ break;
+ case RTFKeyword::ACCCOMMA:
+ nSprm = NS_ooxml::LN_Value_ST_Em_comma;
+ break;
+ case RTFKeyword::ACCCIRCLE:
+ nSprm = NS_ooxml::LN_Value_ST_Em_circle;
+ break;
+ case RTFKeyword::ACCUNDERDOT:
+ nSprm = NS_ooxml::LN_Value_ST_Em_underDot;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue = new RTFValue((!bParam || nParam != 0) ? nSprm : 0);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_em, pValue);
+ return RTFError::OK;
+ }
+
+ // Trivial character sprms.
+ switch (nKeyword)
+ {
+ case RTFKeyword::B:
+ case RTFKeyword::AB:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_bCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_b;
+ break;
+ }
+ break;
+ case RTFKeyword::I:
+ case RTFKeyword::AI:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_iCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_i;
+ break;
+ }
+ break;
+ case RTFKeyword::OUTL:
+ nSprm = NS_ooxml::LN_EG_RPrBase_outline;
+ break;
+ case RTFKeyword::SHAD:
+ nSprm = NS_ooxml::LN_EG_RPrBase_shadow;
+ break;
+ case RTFKeyword::V:
+ nSprm = NS_ooxml::LN_EG_RPrBase_vanish;
+ break;
+ case RTFKeyword::STRIKE:
+ nSprm = NS_ooxml::LN_EG_RPrBase_strike;
+ break;
+ case RTFKeyword::STRIKED:
+ nSprm = NS_ooxml::LN_EG_RPrBase_dstrike;
+ break;
+ case RTFKeyword::SCAPS:
+ nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps;
+ break;
+ case RTFKeyword::IMPR:
+ nSprm = NS_ooxml::LN_EG_RPrBase_imprint;
+ break;
+ case RTFKeyword::CAPS:
+ nSprm = NS_ooxml::LN_EG_RPrBase_caps;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pBoolValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
+ }
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::ASPALPHA:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE,
+ pBoolValue);
+ break;
+ case RTFKeyword::DELETED:
+ case RTFKeyword::REVISED:
+ {
+ auto pValue
+ = new RTFValue(nKeyword == RTFKeyword::DELETED ? oox::XML_del : oox::XML_ins);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_token, pValue);
+ }
+ break;
+ case RTFKeyword::SBAUTO:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue);
+ break;
+ case RTFKeyword::SAAUTO:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue);
+ break;
+ case RTFKeyword::FACINGP:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue);
+ break;
+ case RTFKeyword::HYPHAUTO:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue);
+ break;
+ case RTFKeyword::HYPHPAR:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens,
+ new RTFValue(int(bParam && nParam == 0)));
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter.rtf",
+ "TODO handle toggle '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+RTFError RTFDocumentImpl::pushState()
+{
+ //SAL_INFO("writerfilter.rtf", __func__ << " before push: " << m_pTokenizer->getGroup());
+
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ m_nGroupStartPos = Strm().Tell();
+
+ if (m_aStates.empty())
+ m_aStates.push(m_aDefaultState);
+ else
+ {
+ // fdo#85812 group resets run type of _current_ and new state (but not RTL)
+ if (m_aStates.top().getRunType() != RTFParserState::RunType::LTRCH_RTLCH_2
+ && m_aStates.top().getRunType() != RTFParserState::RunType::RTLCH_LTRCH_2)
+ {
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ }
+
+ if (m_aStates.top().getDestination() == Destination::MR)
+ lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
+ m_bMathNor);
+ m_aStates.push(m_aStates.top());
+ }
+ m_aStates.top().getDestinationText().setLength(0); // was copied: always reset!
+
+ m_pTokenizer->pushGroup();
+
+ switch (m_aStates.top().getDestination())
+ {
+ case Destination::FONTTABLE:
+ // this is a "faked" destination for the font entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::FONTENTRY);
+ break;
+ case Destination::STYLESHEET:
+ // this is a "faked" destination for the style sheet entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::STYLEENTRY);
+ {
+ // the *default* is \s0 i.e. paragraph style default
+ // this will be overwritten by \sN \csN \dsN \tsN
+ m_nCurrentStyleIndex = 0;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, pValue);
+ }
+ break;
+ case Destination::FIELDRESULT:
+ case Destination::SHAPETEXT:
+ case Destination::FORMFIELD:
+ case Destination::FIELDINSTRUCTION:
+ case Destination::PICT:
+ m_aStates.top().setDestination(Destination::NORMAL);
+ break;
+ case Destination::MNUM:
+ case Destination::MDEN:
+ case Destination::ME:
+ case Destination::MFNAME:
+ case Destination::MLIM:
+ case Destination::MSUB:
+ case Destination::MSUP:
+ case Destination::MDEG:
+ case Destination::MOMATH:
+ m_aStates.top().setDestination(Destination::MR);
+ break;
+ case Destination::REVISIONTABLE:
+ // this is a "faked" destination for the revision table entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::REVISIONENTRY);
+ break;
+ default:
+ break;
+ }
+
+ // If this is true, then ooxml:endtrackchange will be generated. Make sure
+ // we don't generate more ooxml:endtrackchange than ooxml:trackchange: new
+ // state does not inherit this flag.
+ m_aStates.top().setStartedTrackchange(false);
+
+ return RTFError::OK;
+}
+
+writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStyleProperties()
+{
+ int nBasedOn = 0;
+ RTFValue::Pointer_t pBasedOn
+ = m_aStates.top().getTableSprms().find(NS_ooxml::LN_CT_Style_basedOn);
+ if (pBasedOn)
+ nBasedOn = pBasedOn->getInt();
+ if (nBasedOn == 0)
+ {
+ // No parent style, then mimic what Word does: ignore attributes which
+ // would set a margin as formatting, but with a default value.
+ for (const auto& nId :
+ { NS_ooxml::LN_CT_Ind_firstLine, NS_ooxml::LN_CT_Ind_left, NS_ooxml::LN_CT_Ind_right,
+ NS_ooxml::LN_CT_Ind_start, NS_ooxml::LN_CT_Ind_end })
+ {
+ RTFValue::Pointer_t pValue = getNestedAttribute(m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_CT_PPrBase_ind, nId);
+ if (pValue && pValue->getInt() == 0)
+ eraseNestedAttribute(m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_CT_PPrBase_ind, nId);
+ }
+ }
+
+ RTFValue::Pointer_t pParaProps = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ RTFValue::Pointer_t pCharProps = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+
+ // resetSprms will clean up this modification
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_pPr, pParaProps);
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_rPr, pCharProps);
+
+ writerfilter::Reference<Properties>::Pointer_t pProps(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+ return pProps;
+}
+
+/** 2 different representations of the styles are needed:
+
+ 1) flat content, as read from the input file:
+ stored in m_pStyleTableEntries, used as reference input for
+ deduplication both here and for hard formatting in getProperties()
+
+ 2) real content, with proper override of sprms/attributes where it differs
+ from parent style; this is produced here and sent to domain mapper
+ */
+RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
+{
+ RTFReferenceTable::Entries_t ret;
+ for (auto const& it : *m_pStyleTableEntries)
+ {
+ auto pStyle = it.second;
+ ret[it.first] = pStyle;
+ // ugly downcasts here, but can't easily replace the members with
+ // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway
+ RTFValue::Pointer_t const pBasedOn(
+ static_cast<RTFReferenceProperties&>(*pStyle).getSprms().find(
+ NS_ooxml::LN_CT_Style_basedOn));
+ if (pBasedOn)
+ {
+ int const nBasedOn(pBasedOn->getInt());
+ // don't deduplicate yourself - especially a potential problem for the default style.
+ if (it.first == nBasedOn)
+ continue;
+
+ auto const itParent(m_pStyleTableEntries->find(nBasedOn)); // definition as read!
+ if (itParent != m_pStyleTableEntries->end())
+ {
+ auto const pStyleType(
+ static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find(
+ NS_ooxml::LN_CT_Style_type));
+ assert(pStyleType);
+ int const nStyleType(pStyleType->getInt());
+ RTFSprms sprms(
+ static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate(
+ static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(),
+ nStyleType));
+ RTFSprms attributes(
+ static_cast<RTFReferenceProperties&>(*pStyle)
+ .getAttributes()
+ .cloneAndDeduplicate(
+ static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(),
+ nStyleType));
+
+ ret[it.first] = new RTFReferenceProperties(std::move(attributes), std::move(sprms));
+ }
+ else
+ {
+ SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn);
+ }
+ }
+ }
+ assert(ret.size() == m_pStyleTableEntries->size());
+ return ret;
+}
+
+void RTFDocumentImpl::resetSprms()
+{
+ m_aStates.top().getTableSprms().clear();
+ m_aStates.top().getCharacterSprms().clear();
+ m_aStates.top().getParagraphSprms().clear();
+}
+
+void RTFDocumentImpl::resetAttributes()
+{
+ m_aStates.top().getTableAttributes().clear();
+ m_aStates.top().getCharacterAttributes().clear();
+ m_aStates.top().getParagraphAttributes().clear();
+}
+
+static bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties,
+ std::u16string_view rName)
+{
+ return std::any_of(rProperties.begin(), rProperties.end(),
+ [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
+}
+
+RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState)
+{
+ switch (rState.getDestination())
+ {
+ //Note: in fonttbl there may or may not be groups, so process it as no groups
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
+ {
+ // Some text unhandled? Seems it is last font name
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ if (rState.getDestination() == Destination::FONTTABLE)
+ {
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(m_aFontTableEntries));
+ Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
+ if (m_nDefaultFontIndex >= 0)
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
+ putNestedAttribute(m_aDefaultState.getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
+ pValue);
+ }
+ }
+ }
+ break;
+ case Destination::STYLESHEET:
+ {
+ RTFReferenceTable::Entries_t pStyleTableDeduplicated(deduplicateStyleTable());
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(pStyleTableDeduplicated)));
+ Mapper().table(NS_ooxml::LN_STYLESHEET, pTable);
+ }
+ break;
+ case Destination::LISTOVERRIDETABLE:
+ {
+ RTFSprms aListTableAttributes;
+ writerfilter::Reference<Properties>::Pointer_t pProp
+ = new RTFReferenceProperties(std::move(aListTableAttributes), m_aListTableSprms);
+ RTFReferenceTable::Entries_t aListTableEntries;
+ aListTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(aListTableEntries)));
+ Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
+ }
+ break;
+ case Destination::LISTENTRY:
+ for (const auto& rListLevelEntry : rState.getListLevelEntries())
+ rState.getTableSprms().set(rListLevelEntry.first, rListLevelEntry.second,
+ RTFOverwrite::NO_APPEND);
+ break;
+ case Destination::FIELDINSTRUCTION:
+ {
+ auto pValue = new RTFValue(m_aFormfieldAttributes, m_aFormfieldSprms);
+ RTFSprms aFFAttributes;
+ RTFSprms aFFSprms;
+ aFFSprms.set(NS_ooxml::LN_ffdata, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aFFAttributes), std::move(aFFSprms));
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto pFFValue = new RTFValue(aFFAttributes, aFFSprms);
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pFFValue, nullptr);
+ }
+ m_aFormfieldAttributes.clear();
+ m_aFormfieldSprms.clear();
+
+ if (m_aStates.top().isFieldLocked())
+ singleChar(cFieldLock);
+ singleChar(cFieldSep);
+ }
+ break;
+ case Destination::FIELDRESULT:
+ singleChar(cFieldEnd);
+
+ if (!m_aPicturePath.isEmpty())
+ {
+ // Read the picture into m_aStates.top().aDestinationText.
+ pushState();
+ dispatchDestination(RTFKeyword::PICT);
+ if (m_aPicturePath.endsWith(".png"))
+ dispatchFlag(RTFKeyword::PNGBLIP);
+ OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_URL, OUString());
+ OUString aPictureURL;
+ try
+ {
+ aPictureURL = rtl::Uri::convertRelToAbs(aFileURL, m_aPicturePath);
+ }
+ catch (const rtl::MalformedUriException& rException)
+ {
+ SAL_WARN("writerfilter.rtf",
+ "rtl::Uri::convertRelToAbs() failed: " << rException.getMessage());
+ }
+
+ if (!aPictureURL.isEmpty())
+ {
+ SvFileStream aStream(aPictureURL, StreamMode::READ);
+ if (aStream.IsOpen())
+ {
+ OUStringBuffer aBuf;
+ while (aStream.good())
+ {
+ unsigned char ch = 0;
+ aStream.ReadUChar(ch);
+ if (ch < 16)
+ aBuf.append("0");
+ aBuf.append(static_cast<sal_Int32>(ch), 16);
+ }
+ m_aStates.top().getDestinationText() = aBuf;
+ }
+ }
+ popState();
+ m_aPicturePath.clear();
+ }
+
+ break;
+ case Destination::LEVELTEXT:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ // The first character is the length of the string (the rest should be ignored).
+ sal_Int32 nLength(aStr.toChar());
+ OUString aValue;
+ if (nLength < aStr.getLength())
+ aValue = aStr.copy(1, nLength);
+ else
+ aValue = aStr;
+ auto pValue = new RTFValue(aValue, true);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
+ }
+ break;
+ case Destination::LEVELNUMBERS:
+ {
+ bool bNestedLevelNumbers = false;
+ if (m_aStates.size() > 1)
+ // Current destination is levelnumbers and parent destination is levelnumbers as well.
+ bNestedLevelNumbers
+ = m_aStates[m_aStates.size() - 2].getDestination() == Destination::LEVELNUMBERS;
+ if (!bNestedLevelNumbers && rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText))
+ {
+ RTFSprms& rAttributes
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText)->getAttributes();
+ RTFValue::Pointer_t pValue = rAttributes.find(NS_ooxml::LN_CT_LevelText_val);
+ if (pValue && rState.getLevelNumbersValid())
+ {
+ OUString aOrig = pValue->getString();
+
+ OUStringBuffer aBuf(aOrig.getLength() * 2);
+ sal_Int32 nReplaces = 1;
+ for (int i = 0; i < aOrig.getLength(); i++)
+ {
+ if (std::find(rState.getLevelNumbers().begin(),
+ rState.getLevelNumbers().end(), i + 1)
+ != rState.getLevelNumbers().end())
+ {
+ aBuf.append('%');
+ // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2.
+ aBuf.append(sal_Int32(nReplaces++ + rState.getListLevelNum() + 1
+ - rState.getLevelNumbers().size()));
+ }
+ else
+ aBuf.append(aOrig[i]);
+ }
+
+ pValue->setString(aBuf.makeStringAndClear());
+ }
+ else if (pValue)
+ // Have a value, but levelnumbers is not valid -> ignore it.
+ pValue->setString(OUString());
+ }
+ break;
+ }
+ case Destination::SHAPEPROPERTYNAME:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ rState.getShape().getProperties().emplace_back(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), OUString());
+ break;
+ case Destination::SHAPEPROPERTYVALUE:
+ if (!rState.getShape().getProperties().empty())
+ {
+ rState.getShape().getProperties().back().second
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ if (m_aStates.top().getHadShapeText())
+ m_pSdrImport->append(rState.getShape().getProperties().back().first,
+ rState.getShape().getProperties().back().second);
+ else if (rState.getInShapeGroup() && !rState.getInShape()
+ && rState.getShape().getProperties().back().first == "rotation")
+ {
+ // Rotation should be applied on the groupshape itself, not on each shape.
+ rState.getShape().getGroupProperties().push_back(
+ rState.getShape().getProperties().back());
+ rState.getShape().getProperties().pop_back();
+ }
+ }
+ break;
+ case Destination::PICPROP:
+ case Destination::SHAPEINSTRUCTION:
+ if (m_aStates.size() > 1
+ && m_aStates[m_aStates.size() - 2].getDestination()
+ == Destination::SHAPEINSTRUCTION)
+ {
+ // Do not resolve shape if shape instruction destination is inside other shape instruction
+ }
+ else if (!m_bObject && !rState.getInListpicture() && !rState.getHadShapeText()
+ && (!rState.getInShapeGroup() || rState.getInShape()))
+ {
+ // Don't trigger a shape import in case we're only leaving the \shpinst of the groupshape itself.
+ RTFSdrImport::ShapeOrPict eType
+ = (rState.getDestination() == Destination::SHAPEINSTRUCTION)
+ ? RTFSdrImport::SHAPE
+ : RTFSdrImport::PICT;
+ if (!m_aStates.top().getCurrentBuffer() || eType != RTFSdrImport::SHAPE)
+ m_pSdrImport->resolve(m_aStates.top().getShape(), true, eType);
+ else
+ {
+ // Shape inside table: buffer the import to have correct anchor position.
+ // Also buffer the RTFPicture of the state stack as it contains
+ // the shape size.
+ auto pPictureValue = new RTFValue(m_aStates.top().getPicture());
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_PICTURE, pPictureValue, nullptr));
+ auto pValue = new RTFValue(m_aStates.top().getShape());
+
+ // Buffer wrap type.
+ for (const auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
+ {
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
+ || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
+ {
+ m_aStates.top().getShape().getWrapSprm() = rCharacterSprm;
+ break;
+ }
+ }
+
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESHAPE, pValue, nullptr));
+ }
+ }
+ else if (rState.getInShapeGroup() && !rState.getInShape())
+ {
+ // End of a groupshape, as we're in shapegroup, but not in a real shape.
+ for (const auto& rGroupProperty : rState.getShape().getGroupProperties())
+ m_pSdrImport->appendGroupProperty(rGroupProperty.first, rGroupProperty.second);
+ rState.getShape().getGroupProperties().clear();
+ }
+ break;
+ case Destination::BOOKMARKSTART:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ int nPos = m_aBookmarks.size();
+ m_aBookmarks[aStr] = nPos;
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(lcl_getBookmarkProperties(nPos, aStr)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(lcl_getBookmarkProperties(nPos, aStr)), nullptr);
+ }
+ break;
+ case Destination::BOOKMARKEND:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(
+ lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)),
+ nullptr);
+ }
+ break;
+ case Destination::INDEXENTRY:
+ case Destination::TOCENTRY:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString str(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ // dmapper expects this as a field, so let's fake something...
+ auto const field((Destination::INDEXENTRY == rState.getDestination())
+ ? std::u16string_view(u"XE")
+ : std::u16string_view(u"TC"));
+ str = OUString::Concat(field) + " \"" + str.replaceAll("\"", "\\\"") + "\"";
+ singleChar(cFieldStart);
+ Mapper().utext(reinterpret_cast<sal_uInt8 const*>(str.getStr()), str.getLength());
+ singleChar(cFieldSep);
+ // no result
+ singleChar(cFieldEnd);
+ }
+ break;
+ case Destination::FORMFIELDNAME:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pValue);
+ }
+ break;
+ case Destination::FORMFIELDLIST:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ // OOXML puts these into a LN_CT_FFData_ddList but FFDataHandler should handle this too
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ break;
+ case Destination::DATAFIELD:
+ {
+ if (m_bFormField)
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OString aStr = OUStringToOString(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear(),
+ rState.getCurrentEncoding());
+ // decode hex dump
+ OStringBuffer aBuf;
+ int b = 0;
+ int count = 2;
+ for (int i = 0; i < aStr.getLength(); ++i)
+ {
+ char ch = aStr[i];
+ if (ch != 0x0d && ch != 0x0a)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return RTFError::HEX_INVALID;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aBuf.append(static_cast<char>(b));
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+ aStr = aBuf.makeStringAndClear();
+
+ // ignore the first bytes
+ if (aStr.getLength() > 8)
+ aStr = aStr.copy(8);
+ // extract name
+ sal_Int32 nLength = aStr.toChar();
+ if (!aStr.isEmpty())
+ aStr = aStr.copy(1);
+ nLength = std::min(nLength, aStr.getLength());
+ OString aName = aStr.copy(0, nLength);
+ if (aStr.getLength() > nLength)
+ aStr = aStr.copy(nLength + 1); // zero-terminated string
+ else
+ aStr.clear();
+ // extract default text
+ nLength = aStr.toChar();
+ if (!aStr.isEmpty())
+ aStr = aStr.copy(1);
+ auto pNValue = new RTFValue(OStringToOUString(aName, rState.getCurrentEncoding()));
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pNValue);
+ if (nLength > 0)
+ {
+ OString aDefaultText = aStr.copy(0, std::min(nLength, aStr.getLength()));
+ auto pDValue = new RTFValue(
+ OStringToOUString(aDefaultText, rState.getCurrentEncoding()));
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFTextInput_default, pDValue);
+ }
+
+ m_bFormField = false;
+ }
+ }
+ break;
+ case Destination::CREATIONTIME:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setCreationDate(lcl_getDateTime(rState));
+ break;
+ case Destination::REVISIONTIME:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setModificationDate(lcl_getDateTime(rState));
+ break;
+ case Destination::PRINTTIME:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setPrintDate(lcl_getDateTime(rState));
+ break;
+ case Destination::AUTHOR:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setAuthor(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::KEYWORDS:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setKeywords(comphelper::string::convertCommaSeparated(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear()));
+ break;
+ case Destination::COMMENT:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setGenerator(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::SUBJECT:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setSubject(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::TITLE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setTitle(
+ rState.getCurrentDestinationText()->makeStringAndClear());
+ }
+ break;
+
+ case Destination::DOCCOMM:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setDescription(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::OPERATOR:
+ case Destination::COMPANY:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aName = rState.getDestination() == Destination::OPERATOR ? OUString("Operator")
+ : OUString("Company");
+ uno::Any aValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ if (m_xDocumentProperties.is())
+ {
+ uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
+ = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo
+ = xPropertySet->getPropertySetInfo();
+ if (xPropertySetInfo->hasPropertyByName(aName))
+ xPropertySet->setPropertyValue(aName, aValue);
+ else
+ xUserDefinedProperties->addProperty(aName, beans::PropertyAttribute::REMOVABLE,
+ aValue);
+ }
+ }
+ break;
+ case Destination::OBJDATA:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+
+ RTFError eError = handleEmbeddedObject();
+ if (eError != RTFError::OK)
+ return eError;
+ }
+ break;
+ case Destination::OBJCLASS:
+ {
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ m_aOLEAttributes.set(NS_ooxml::LN_CT_OLEObject_ProgID, pValue);
+ break;
+ }
+ case Destination::OBJECT:
+ {
+ if (!m_bObject)
+ {
+ // if the object is in a special container we will use the \result
+ // element instead of the \objdata
+ // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
+ break;
+ }
+
+ RTFSprms aObjectSprms;
+ auto pOLEValue = new RTFValue(m_aOLEAttributes);
+ aObjectSprms.set(NS_ooxml::LN_OLEObject_OLEObject, pOLEValue);
+
+ RTFSprms aObjAttributes;
+ RTFSprms aObjSprms;
+ auto pValue = new RTFValue(m_aObjectAttributes, aObjectSprms);
+ aObjSprms.set(NS_ooxml::LN_object, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aObjAttributes), std::move(aObjSprms));
+ uno::Reference<drawing::XShape> xShape;
+ RTFValue::Pointer_t pShape = m_aObjectAttributes.find(NS_ooxml::LN_shape);
+ OSL_ASSERT(pShape);
+ if (pShape)
+ pShape->getAny() >>= xShape;
+ if (xShape.is())
+ {
+ Mapper().startShape(xShape);
+ Mapper().props(pProperties);
+ Mapper().endShape();
+ }
+ m_aObjectAttributes.clear();
+ m_aOLEAttributes.clear();
+ m_bObject = false;
+ }
+ break;
+ case Destination::ANNOTATIONDATE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr(OStringToOUString(
+ DTTM22OString(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear().toInt32()),
+ rState.getCurrentEncoding()));
+ auto pValue = new RTFValue(aStr);
+ RTFSprms aAnnAttributes;
+ aAnnAttributes.set(NS_ooxml::LN_CT_TrackChange_date, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAnnAttributes));
+ Mapper().props(pProperties);
+ }
+ break;
+ case Destination::ANNOTATIONAUTHOR:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ m_aAuthor = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ break;
+ case Destination::ATNID:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ m_aAuthorInitials = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ break;
+ case Destination::ANNOTATIONREFERENCESTART:
+ case Destination::ANNOTATIONREFERENCEEND:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ auto pValue = new RTFValue(aStr.toInt32());
+ RTFSprms aAttributes;
+ if (rState.getDestination() == Destination::ANNOTATIONREFERENCESTART)
+ aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart, pValue);
+ else
+ aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes));
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto const pValue2 = new RTFValue(aAttributes, RTFSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue2, nullptr);
+ }
+ }
+ break;
+ case Destination::ANNOTATIONREFERENCE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ RTFSprms aAnnAttributes;
+ aAnnAttributes.set(NS_ooxml::LN_CT_Markup_id, new RTFValue(aStr.toInt32()));
+ Mapper().props(new RTFReferenceProperties(std::move(aAnnAttributes)));
+ }
+ break;
+ case Destination::FALT:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ auto pValue = new RTFValue(aStr);
+ rState.getTableSprms().set(NS_ooxml::LN_CT_Font_altName, pValue);
+ }
+ break;
+ case Destination::DRAWINGOBJECT:
+ if (m_aStates.top().getDrawingObject().getShape().is())
+ {
+ RTFDrawingObject& rDrawing = m_aStates.top().getDrawingObject();
+ const uno::Reference<drawing::XShape>& xShape(rDrawing.getShape());
+ const uno::Reference<beans::XPropertySet>& xPropertySet(rDrawing.getPropertySet());
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
+ bool bTextFrame = xServiceInfo->supportsService("com.sun.star.text.TextFrame");
+
+ // The default is certainly not inline, but then what Word supports is just at-character.
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+
+ if (bTextFrame)
+ {
+ xPropertySet->setPropertyValue("HoriOrientPosition",
+ uno::Any(rDrawing.getLeft()));
+ xPropertySet->setPropertyValue("VertOrientPosition",
+ uno::Any(rDrawing.getTop()));
+ }
+ else
+ {
+ xShape->setPosition(awt::Point(rDrawing.getLeft(), rDrawing.getTop()));
+ }
+ xShape->setSize(awt::Size(rDrawing.getRight(), rDrawing.getBottom()));
+
+ if (rDrawing.getHasLineColor())
+ {
+ uno::Any aLineColor(sal_uInt32((rDrawing.getLineColorR() << 16)
+ + (rDrawing.getLineColorG() << 8)
+ + rDrawing.getLineColorB()));
+ uno::Any aLineWidth;
+ RTFSdrImport::resolveLineColorAndWidth(bTextFrame, xPropertySet, aLineColor,
+ aLineWidth);
+ }
+ if (rDrawing.getHasFillColor())
+ xPropertySet->setPropertyValue(
+ "FillColor", uno::Any(sal_uInt32((rDrawing.getFillColorR() << 16)
+ + (rDrawing.getFillColorG() << 8)
+ + rDrawing.getFillColorB())));
+ else if (!bTextFrame)
+ // If there is no fill, the Word default is 100% transparency.
+ xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_Int32(100)));
+
+ RTFSdrImport::resolveFLine(xPropertySet, rDrawing.getFLine());
+
+ if (!m_aStates.top().getDrawingObject().getHadShapeText())
+ {
+ Mapper().startShape(xShape);
+ }
+ Mapper().endShape();
+ }
+ break;
+ case Destination::PICT:
+ // fdo#79319 ignore picture data if it's really a shape
+ if (!m_pSdrImport->isFakePict())
+ {
+ resolvePict(true, m_pSdrImport->getCurrentShape());
+ }
+ m_bNeedFinalPar = true;
+ break;
+ case Destination::SHAPE:
+ m_bNeedFinalPar = true;
+ m_bNeedCr = m_bNeedCrOrig;
+ if (rState.getFrame().inFrame())
+ {
+ // parBreak() modifies m_aStates.top() so we can't apply resetFrame() directly on aState
+ resetFrame();
+ parBreak();
+ // Save this state for later use, so we only reset frame status only for the first shape inside a frame.
+ rState = m_aStates.top();
+ m_bNeedPap = true;
+ }
+ break;
+ case Destination::MOMATH:
+ {
+ m_aMathBuffer.appendClosingTag(M_TOKEN(oMath));
+
+ SvGlobalName aGlobalName(SO3_SM_CLASSID);
+ comphelper::EmbeddedObjectContainer aContainer;
+ OUString aName;
+ uno::Reference<embed::XEmbeddedObject> xObject
+ = aContainer.CreateEmbeddedObject(aGlobalName.GetByteSequence(), aName);
+ if (xObject) // rhbz#1766990 starmath might not be available
+ {
+ uno::Reference<util::XCloseable> xComponent(xObject->getComponent(),
+ uno::UNO_SET_THROW);
+ // gcc4.4 (and 4.3 and possibly older) have a problem with dynamic_cast directly to the target class,
+ // so help it with an intermediate cast. I'm not sure what exactly the problem is, seems to be unrelated
+ // to RTLD_GLOBAL, so most probably a gcc bug.
+ auto& rImport = dynamic_cast<oox::FormulaImportBase&>(
+ dynamic_cast<SfxBaseModel&>(*xComponent));
+ rImport.readFormulaOoxml(m_aMathBuffer);
+
+ auto pValue = new RTFValue(xObject);
+ RTFSprms aMathAttributes;
+ aMathAttributes.set(NS_ooxml::LN_starmath, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aMathAttributes));
+ Mapper().props(pProperties);
+ }
+
+ m_aMathBuffer = oox::formulaimport::XmlStreamBuilder();
+ }
+ break;
+ case Destination::MR:
+ lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
+ m_bMathNor);
+ break;
+ case Destination::MF:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(f));
+ break;
+ case Destination::MFPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(fPr));
+ break;
+ case Destination::MCTRLPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(ctrlPr));
+ break;
+ case Destination::MNUM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(num));
+ break;
+ case Destination::MDEN:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(den));
+ break;
+ case Destination::MACC:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(acc));
+ break;
+ case Destination::MACCPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(accPr));
+ break;
+ case Destination::MCHR:
+ case Destination::MPOS:
+ case Destination::MVERTJC:
+ case Destination::MSTRIKEH:
+ case Destination::MDEGHIDE:
+ case Destination::MBEGCHR:
+ case Destination::MSEPCHR:
+ case Destination::MENDCHR:
+ case Destination::MSUBHIDE:
+ case Destination::MSUPHIDE:
+ case Destination::MTYPE:
+ case Destination::MGROW:
+ {
+ sal_Int32 nMathToken = 0;
+ switch (rState.getDestination())
+ {
+ case Destination::MCHR:
+ nMathToken = M_TOKEN(chr);
+ break;
+ case Destination::MPOS:
+ nMathToken = M_TOKEN(pos);
+ break;
+ case Destination::MVERTJC:
+ nMathToken = M_TOKEN(vertJc);
+ break;
+ case Destination::MSTRIKEH:
+ nMathToken = M_TOKEN(strikeH);
+ break;
+ case Destination::MDEGHIDE:
+ nMathToken = M_TOKEN(degHide);
+ break;
+ case Destination::MBEGCHR:
+ nMathToken = M_TOKEN(begChr);
+ break;
+ case Destination::MSEPCHR:
+ nMathToken = M_TOKEN(sepChr);
+ break;
+ case Destination::MENDCHR:
+ nMathToken = M_TOKEN(endChr);
+ break;
+ case Destination::MSUBHIDE:
+ nMathToken = M_TOKEN(subHide);
+ break;
+ case Destination::MSUPHIDE:
+ nMathToken = M_TOKEN(supHide);
+ break;
+ case Destination::MTYPE:
+ nMathToken = M_TOKEN(type);
+ break;
+ case Destination::MGROW:
+ nMathToken = M_TOKEN(grow);
+ break;
+ default:
+ break;
+ }
+
+ oox::formulaimport::XmlStream::AttributeList aAttribs;
+ aAttribs[M_TOKEN(val)]
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ m_aMathBuffer.appendOpeningTag(nMathToken, aAttribs);
+ m_aMathBuffer.appendClosingTag(nMathToken);
+ }
+ break;
+ case Destination::ME:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(e));
+ break;
+ case Destination::MBAR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(bar));
+ break;
+ case Destination::MBARPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(barPr));
+ break;
+ case Destination::MD:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(d));
+ break;
+ case Destination::MDPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(dPr));
+ break;
+ case Destination::MFUNC:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(func));
+ break;
+ case Destination::MFUNCPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(funcPr));
+ break;
+ case Destination::MFNAME:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(fName));
+ break;
+ case Destination::MLIMLOW:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limLow));
+ break;
+ case Destination::MLIMLOWPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limLowPr));
+ break;
+ case Destination::MLIM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(lim));
+ break;
+ case Destination::MM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(m));
+ break;
+ case Destination::MMPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(mPr));
+ break;
+ case Destination::MMR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(mr));
+ break;
+ case Destination::MNARY:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(nary));
+ break;
+ case Destination::MNARYPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(naryPr));
+ break;
+ case Destination::MSUB:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sub));
+ break;
+ case Destination::MSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sup));
+ break;
+ case Destination::MLIMUPP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limUpp));
+ break;
+ case Destination::MLIMUPPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limUppPr));
+ break;
+ case Destination::MGROUPCHR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(groupChr));
+ break;
+ case Destination::MGROUPCHRPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(groupChrPr));
+ break;
+ case Destination::MBORDERBOX:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(borderBox));
+ break;
+ case Destination::MBORDERBOXPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(borderBoxPr));
+ break;
+ case Destination::MRAD:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(rad));
+ break;
+ case Destination::MRADPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(radPr));
+ break;
+ case Destination::MDEG:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(deg));
+ break;
+ case Destination::MSSUB:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSub));
+ break;
+ case Destination::MSSUBPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubPr));
+ break;
+ case Destination::MSSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSup));
+ break;
+ case Destination::MSSUPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSupPr));
+ break;
+ case Destination::MSSUBSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSup));
+ break;
+ case Destination::MSSUBSUPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSupPr));
+ break;
+ case Destination::MSPRE:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sPre));
+ break;
+ case Destination::MSPREPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sPrePr));
+ break;
+ case Destination::MBOX:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(box));
+ break;
+ case Destination::MEQARR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(eqArr));
+ break;
+ case Destination::SHAPEGROUP:
+ if (rState.getCreatedShapeGroup())
+ m_pSdrImport->popParent();
+ break;
+ case Destination::PROPNAME:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ rState.setPropName(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::STATICVAL:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ {
+ // Find out what is the key, value type and value we want to set.
+ uno::Reference<beans::XPropertyContainer> xPropertyContainer
+ = m_xDocumentProperties->getUserDefinedProperties();
+ const OUString& rKey = m_aStates.top().getPropName();
+ OUString aStaticVal
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ uno::Any aAny;
+ if (m_aStates.top().getPropType() == cppu::UnoType<OUString>::get())
+ aAny <<= aStaticVal;
+ else if (m_aStates.top().getPropType() == cppu::UnoType<sal_Int32>::get())
+ aAny <<= aStaticVal.toInt32();
+ else if (m_aStates.top().getPropType() == cppu::UnoType<bool>::get())
+ aAny <<= aStaticVal.toBoolean();
+ else if (m_aStates.top().getPropType() == cppu::UnoType<util::DateTime>::get())
+ aAny <<= getDateTimeFromUserProp(aStaticVal);
+ else if (m_aStates.top().getPropType() == cppu::UnoType<double>::get())
+ aAny <<= aStaticVal.toDouble();
+
+ xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
+ }
+ break;
+ case Destination::USERPROPS:
+ {
+ // These are the imported properties.
+ uno::Reference<document::XDocumentProperties> xDocumentProperties
+ = m_xDocumentProperties;
+
+ // These are the real document properties.
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
+ m_xDstDoc, uno::UNO_QUERY);
+ if (xDocumentPropertiesSupplier.is())
+ m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+
+ if (m_xDocumentProperties.is())
+ {
+ if (!m_bIsNewDoc)
+ {
+ // Check classification.
+ if (!SfxClassificationHelper::ShowPasteInfo(SfxClassificationHelper::CheckPaste(
+ xDocumentProperties, m_xDocumentProperties)))
+ return RTFError::CLASSIFICATION;
+ }
+
+ uno::Reference<beans::XPropertyContainer> xClipboardPropertyContainer
+ = xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertyContainer> xDocumentPropertyContainer
+ = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xClipboardPropertySet(
+ xClipboardPropertyContainer, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xDocumentPropertySet(xDocumentPropertyContainer,
+ uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aClipboardProperties
+ = xClipboardPropertySet->getPropertySetInfo()->getProperties();
+ uno::Sequence<beans::Property> aDocumentProperties
+ = xDocumentPropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aClipboardProperties)
+ {
+ const OUString& rKey = rProperty.Name;
+ uno::Any aValue = xClipboardPropertySet->getPropertyValue(rKey);
+
+ try
+ {
+ if (lcl_containsProperty(aDocumentProperties, rKey))
+ {
+ // When pasting, don't update existing properties.
+ if (!m_bIsNewDoc)
+ xDocumentPropertySet->setPropertyValue(rKey, aValue);
+ }
+ else
+ xDocumentPropertyContainer->addProperty(
+ rKey, beans::PropertyAttribute::REMOVABLE, aValue);
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.rtf", "failed to set property " << rKey);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return RTFError::OK;
+}
+
+void RTFDocumentImpl::afterPopState(RTFParserState& rState)
+{
+ // list table
+ switch (rState.getDestination())
+ {
+ case Destination::LISTENTRY:
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pValue,
+ RTFOverwrite::NO_APPEND);
+ m_aListTable[rState.getCurrentListIndex()] = pValue;
+ m_nListLevel = -1;
+ m_aInvalidListTableFirstIndents[rState.getCurrentListIndex()]
+ = m_aInvalidListLevelFirstIndents;
+ m_aInvalidListLevelFirstIndents.clear();
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING:
+ {
+ RTFValue::Pointer_t pIdValue
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_AbstractNum_nsid);
+ if (pIdValue && !m_aStates.empty())
+ {
+ // Abstract numbering
+ RTFSprms aLeveltextAttributes;
+ OUString aTextValue;
+ RTFValue::Pointer_t pTextBefore
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelText_val);
+ if (pTextBefore)
+ aTextValue += pTextBefore->getString();
+ aTextValue += "%1";
+ RTFValue::Pointer_t pTextAfter
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelSuffix_val);
+ if (pTextAfter)
+ aTextValue += pTextAfter->getString();
+ auto pTextValue = new RTFValue(aTextValue);
+ aLeveltextAttributes.set(NS_ooxml::LN_CT_LevelText_val, pTextValue);
+
+ RTFSprms aLevelAttributes;
+ RTFSprms aLevelSprms;
+ auto pIlvlValue = new RTFValue(0);
+ aLevelAttributes.set(NS_ooxml::LN_CT_Lvl_ilvl, pIlvlValue);
+
+ RTFValue::Pointer_t pFmtValue
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_numFmt);
+ if (pFmtValue)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, pFmtValue);
+
+ RTFValue::Pointer_t pStartatValue
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_start);
+ if (pStartatValue)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_start, pStartatValue);
+
+ auto pLeveltextValue = new RTFValue(aLeveltextAttributes);
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_lvlText, pLeveltextValue);
+ RTFValue::Pointer_t pRunProps
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_rPr);
+ if (pRunProps)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_rPr, pRunProps);
+
+ RTFSprms aAbstractAttributes;
+ RTFSprms aAbstractSprms;
+ aAbstractAttributes.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, pIdValue);
+ auto pLevelValue = new RTFValue(aLevelAttributes, aLevelSprms);
+ aAbstractSprms.set(NS_ooxml::LN_CT_AbstractNum_lvl, pLevelValue,
+ RTFOverwrite::NO_APPEND);
+
+ RTFSprms aListTableSprms;
+ auto pAbstractValue = new RTFValue(aAbstractAttributes, aAbstractSprms);
+ // It's important that Numbering_abstractNum and Numbering_num never overwrites previous values.
+ aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pAbstractValue,
+ RTFOverwrite::NO_APPEND);
+
+ // Numbering
+ RTFSprms aNumberingAttributes;
+ RTFSprms aNumberingSprms;
+ aNumberingAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pIdValue);
+ aNumberingSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIdValue);
+ auto pNumberingValue = new RTFValue(aNumberingAttributes, aNumberingSprms);
+ aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pNumberingValue,
+ RTFOverwrite::NO_APPEND);
+
+ // Table
+ RTFSprms aListTableAttributes;
+ writerfilter::Reference<Properties>::Pointer_t pProp = new RTFReferenceProperties(
+ std::move(aListTableAttributes), std::move(aListTableSprms));
+
+ RTFReferenceTable::Entries_t aListTableEntries;
+ aListTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(aListTableEntries)));
+ Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
+
+ // Use it
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_ilvl, pIlvlValue, RTFOverwrite::YES_PREPEND);
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_numId, pIdValue, RTFOverwrite::YES_PREPEND);
+ }
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
+ if (!m_aStates.empty())
+ {
+ // FIXME: don't use pDestinationText, points to popped state
+ auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelSuffix_val, pValue);
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
+ if (!m_aStates.empty())
+ {
+ // FIXME: don't use pDestinationText, points to popped state
+ auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
+ }
+ break;
+ case Destination::LISTNAME:
+ break;
+ case Destination::LISTLEVEL:
+ if (!m_aStates.empty())
+ {
+ auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_Lvl_ilvl, pInnerValue);
+
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ if (m_aStates.top().getDestination() != Destination::LFOLEVEL)
+ m_aStates.top().getListLevelEntries().set(NS_ooxml::LN_CT_AbstractNum_lvl,
+ pValue, RTFOverwrite::NO_APPEND);
+ else
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_NumLvl_lvl, pValue);
+ }
+ break;
+ case Destination::LFOLEVEL:
+ if (!m_aStates.empty())
+ {
+ auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_NumLvl_ilvl, pInnerValue);
+
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_lvlOverride, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ break;
+ // list override table
+ case Destination::LISTOVERRIDEENTRY:
+ if (!m_aStates.empty())
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ {
+ // copy properties upwards so upper popState() inserts it
+ m_aStates.top().getTableAttributes() = rState.getTableAttributes();
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ }
+ else
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pValue,
+ RTFOverwrite::NO_APPEND);
+ m_aListOverrideTable[rState.getCurrentListOverrideIndex()]
+ = rState.getCurrentListIndex();
+ }
+ }
+ break;
+ case Destination::LEVELTEXT:
+ if (!m_aStates.empty())
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes());
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_lvlText, pValue);
+ }
+ break;
+ case Destination::LEVELNUMBERS:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS
+ || m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ // Parent state is level number or list level, current state is
+ // level numbers: mark parent as invalid as well if necessary.
+ m_aStates.top().setLevelNumbersValid(rState.getLevelNumbersValid());
+ }
+ break;
+ case Destination::FIELDINSTRUCTION:
+ if (!m_aStates.empty())
+ m_aStates.top().setFieldStatus(RTFFieldStatus::INSTRUCTION);
+ break;
+ case Destination::FIELDRESULT:
+ if (!m_aStates.empty())
+ m_aStates.top().setFieldStatus(RTFFieldStatus::RESULT);
+ break;
+ case Destination::FIELD:
+ if (rState.getFieldStatus() == RTFFieldStatus::INSTRUCTION)
+ singleChar(cFieldEnd);
+ break;
+ case Destination::DOCVAR:
+ if (!m_aStates.empty())
+ {
+ OUString docvar(rState.getDocVar());
+ if (m_aStates.top().getDocVarName().isEmpty())
+ {
+ m_aStates.top().setDocVarName(docvar);
+ }
+ else
+ {
+ uno::Reference<beans::XPropertySet> xMaster(
+ m_xModelFactory->createInstance("com.sun.star.text.FieldMaster.User"),
+ uno::UNO_QUERY_THROW);
+ xMaster->setPropertyValue("Name", uno::Any(m_aStates.top().getDocVarName()));
+ uno::Reference<text::XDependentTextField> xField(
+ m_xModelFactory->createInstance("com.sun.star.text.TextField.User"),
+ uno::UNO_QUERY);
+ xField->attachTextFieldMaster(xMaster);
+ xField->getTextFieldMaster()->setPropertyValue("Content", uno::Any(docvar));
+
+ m_aStates.top().clearDocVarName();
+ }
+ }
+ break;
+ case Destination::SHAPEPROPERTYVALUEPICT:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getPicture() = rState.getPicture();
+ // both \sp and \sv are destinations, copy the text up-ward for later
+ m_aStates.top().getDestinationText() = rState.getDestinationText();
+ }
+ break;
+ case Destination::FALT:
+ if (!m_aStates.empty())
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ break;
+ case Destination::SHAPEPROPERTYNAME:
+ case Destination::SHAPEPROPERTYVALUE:
+ case Destination::SHAPEPROPERTY:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getShape() = rState.getShape();
+ m_aStates.top().getPicture() = rState.getPicture();
+ m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
+ }
+ break;
+ case Destination::SHAPEINSTRUCTION:
+ if (!m_aStates.empty()
+ && m_aStates.top().getDestination() == Destination::SHAPEINSTRUCTION)
+ {
+ // Shape instruction inside other shape instruction: just copy new shape settings:
+ // it will be resolved on end of topmost shape instruction destination
+ m_aStates.top().getShape() = rState.getShape();
+ m_aStates.top().getPicture() = rState.getPicture();
+ m_aStates.top().getCharacterSprms() = rState.getCharacterSprms();
+ m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
+ }
+ break;
+ case Destination::FLYMAINCONTENT:
+ case Destination::SHPPICT:
+ case Destination::SHAPE:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getFrame() = rState.getFrame();
+ if (rState.getDestination() == Destination::SHPPICT
+ && m_aStates.top().getDestination() == Destination::LISTPICTURE)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumPicBullet_numPicBulletId,
+ new RTFValue(m_nListPictureId++));
+ RTFSprms aSprms;
+ // Dummy value, real picture is already sent to dmapper.
+ aSprms.set(NS_ooxml::LN_CT_NumPicBullet_pict, new RTFValue(0));
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_numPicBullet, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ }
+ break;
+ case Destination::SHAPETEXT:
+ if (!m_aStates.empty())
+ {
+ // If we're leaving the shapetext group (it may have nested ones) and this is a shape, not an old drawingobject.
+ if (m_aStates.top().getDestination() != Destination::SHAPETEXT
+ && !m_aStates.top().getDrawingObject().getHadShapeText())
+ {
+ m_aStates.top().setHadShapeText(true);
+ if (!m_aStates.top().getCurrentBuffer())
+ m_pSdrImport->close();
+ else
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_ENDSHAPE, nullptr, nullptr));
+ }
+
+ // It's allowed to declare these inside the shape text, and they
+ // are expected to have an effect for the whole shape.
+ if (rState.getDrawingObject().getLeft())
+ m_aStates.top().getDrawingObject().setLeft(rState.getDrawingObject().getLeft());
+ if (rState.getDrawingObject().getTop())
+ m_aStates.top().getDrawingObject().setTop(rState.getDrawingObject().getTop());
+ if (rState.getDrawingObject().getRight())
+ m_aStates.top().getDrawingObject().setRight(
+ rState.getDrawingObject().getRight());
+ if (rState.getDrawingObject().getBottom())
+ m_aStates.top().getDrawingObject().setBottom(
+ rState.getDrawingObject().getBottom());
+ }
+ break;
+ case Destination::PROPNAME:
+ if (m_aStates.top().getDestination() == Destination::USERPROPS)
+ m_aStates.top().setPropName(rState.getPropName());
+ break;
+ default:
+ {
+ if (!m_aStates.empty() && m_aStates.top().getDestination() == Destination::PICT)
+ m_aStates.top().getPicture() = rState.getPicture();
+ }
+ break;
+ }
+}
+
+RTFError RTFDocumentImpl::popState()
+{
+ //SAL_INFO("writerfilter", __func__ << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
+ // ", dest state: " << m_aStates.top().eDestination);
+
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFParserState aState(m_aStates.top());
+ m_bWasInFrame = aState.getFrame().inFrame();
+
+ // dmapper expects some content in header/footer, so if there would be nothing, add an empty paragraph.
+ if (m_pTokenizer->getGroup() == 1 && m_bFirstRun)
+ {
+ switch (m_nStreamType)
+ {
+ case NS_ooxml::LN_headerl:
+ case NS_ooxml::LN_headerr:
+ case NS_ooxml::LN_headerf:
+ case NS_ooxml::LN_footerl:
+ case NS_ooxml::LN_footerr:
+ case NS_ooxml::LN_footerf:
+ dispatchSymbol(RTFKeyword::PAR);
+ break;
+ }
+ }
+
+ RTFError eError = beforePopState(aState);
+ if (eError != RTFError::OK)
+ return eError;
+
+ // See if we need to end a track change
+ if (aState.getStartedTrackchange())
+ {
+ RTFSprms aTCSprms;
+ auto pValue = new RTFValue(0);
+ aTCSprms.set(NS_ooxml::LN_endtrackchange, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(RTFSprms(), std::move(aTCSprms)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(RTFSprms(), aTCSprms), nullptr);
+ }
+
+ // This is the end of the doc, see if we need to close the last section.
+ if (m_pTokenizer->getGroup() == 1 && !m_bFirstRun)
+ {
+ // \par means an empty paragraph at the end of footnotes/endnotes, but
+ // not in case of other substreams, like headers.
+ if (m_bNeedCr && m_nStreamType != NS_ooxml::LN_footnote
+ && m_nStreamType != NS_ooxml::LN_endnote && m_bIsNewDoc)
+ dispatchSymbol(RTFKeyword::PAR);
+ if (m_bNeedSect) // may be set by dispatchSymbol above!
+ sectBreak(true);
+ }
+
+ m_aStates.pop();
+
+ m_pTokenizer->popGroup();
+
+ afterPopState(aState);
+
+ if (aState.getCurrentBuffer() == &m_aSuperBuffer)
+ {
+ OSL_ASSERT(!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr);
+
+ if (!m_aSuperBuffer.empty())
+ replayBuffer(m_aSuperBuffer, nullptr, nullptr);
+ }
+
+ if (!m_aStates.empty() && m_aStates.top().getTableRowWidthAfter() > 0
+ && aState.getTableRowWidthAfter() == 0)
+ // An RTFKeyword::ROW in the inner group already parsed nTableRowWidthAfter,
+ // don't do it again in the outer state later.
+ m_aStates.top().setTableRowWidthAfter(0);
+
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid && !m_aStates.empty())
+ {
+ // Section break type created for \page still has an effect in the
+ // outer state as well.
+ RTFValue::Pointer_t pType
+ = aState.getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ if (pType)
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pType);
+ }
+
+ return RTFError::OK;
+}
+
+RTFError RTFDocumentImpl::handleEmbeddedObject()
+{
+ OString aStr
+ = OUStringToOString(m_aStates.top().getCurrentDestinationText()->makeStringAndClear(),
+ RTL_TEXTENCODING_ASCII_US);
+ std::unique_ptr<SvStream> pStream(new SvMemoryStream());
+ if (!msfilter::rtfutil::ExtractOLE2FromObjdata(aStr, *pStream))
+ return RTFError::HEX_INVALID;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(pStream.release(), /*_bOwner=*/true));
+ auto pStreamValue = new RTFValue(xInputStream);
+ m_aOLEAttributes.set(NS_ooxml::LN_inputstream, pStreamValue);
+
+ return RTFError::OK;
+}
+
+bool RTFDocumentImpl::isInBackground() { return m_aStates.top().getInBackground(); }
+
+RTFInternalState RTFDocumentImpl::getInternalState() { return m_aStates.top().getInternalState(); }
+
+void RTFDocumentImpl::setInternalState(RTFInternalState nInternalState)
+{
+ m_aStates.top().setInternalState(nInternalState);
+}
+
+Destination RTFDocumentImpl::getDestination() { return m_aStates.top().getDestination(); }
+
+void RTFDocumentImpl::setDestination(Destination eDestination)
+{
+ m_aStates.top().setDestination(eDestination);
+}
+
+// this is a questionably named method that is used only in a very special
+// situation where it looks like the "current" buffer is needed?
+void RTFDocumentImpl::setDestinationText(std::u16string_view rString)
+{
+ m_aStates.top().getDestinationText().setLength(0);
+ m_aStates.top().getDestinationText().append(rString);
+}
+
+bool RTFDocumentImpl::getSkipUnknown() { return m_bSkipUnknown; }
+
+void RTFDocumentImpl::setSkipUnknown(bool bSkipUnknown) { m_bSkipUnknown = bSkipUnknown; }
+
+static auto FilterControlChars(Destination const destination, OUString const& rString) -> OUString
+{
+ if (destination == Destination::LEVELNUMBERS || destination == Destination::LEVELTEXT)
+ { // control characters are magic here!
+ return rString;
+ }
+ OUStringBuffer buf(rString.getLength());
+ for (sal_Int32 i = 0; i < rString.getLength(); ++i)
+ {
+ sal_Unicode const ch(rString[i]);
+ if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
+ {
+ buf.append(ch);
+ }
+ else
+ {
+ SAL_INFO("writerfilter.rtf", "filtering control character");
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+void RTFDocumentImpl::checkUnicode(bool bUnicode, bool bHex)
+{
+ if (bUnicode && !m_aUnicodeBuffer.isEmpty())
+ {
+ OUString aString = m_aUnicodeBuffer.toString();
+ m_aUnicodeBuffer.setLength(0);
+ aString = FilterControlChars(m_aStates.top().getDestination(), aString);
+ text(aString);
+ }
+ if (bHex && !m_aHexBuffer.isEmpty())
+ {
+ rtl_TextEncoding nEncoding = m_aStates.top().getCurrentEncoding();
+ if (m_aStates.top().getDestination() == Destination::FONTENTRY
+ && m_aStates.top().getCurrentEncoding() == RTL_TEXTENCODING_SYMBOL)
+ nEncoding = RTL_TEXTENCODING_MS_1252;
+ OUString aString = OStringToOUString(m_aHexBuffer, nEncoding);
+ m_aHexBuffer.setLength(0);
+ aString = FilterControlChars(m_aStates.top().getDestination(), aString);
+ text(aString);
+ }
+}
+
+RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl)
+ : m_pDocumentImpl(pDocumentImpl)
+ , m_nInternalState(RTFInternalState::NORMAL)
+ , m_eDestination(Destination::NORMAL)
+ , m_eFieldStatus(RTFFieldStatus::NONE)
+ , m_bFieldLocked(false)
+ , m_nBorderState(RTFBorderState::NONE)
+ , m_nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0))
+ , m_nUc(1)
+ , m_nCharsToSkip(0)
+ , m_nBinaryToRead(0)
+ , m_nListLevelNum(0)
+ , m_bLevelNumbersValid(true)
+ , m_aFrame(this)
+ , m_eRunType(RunType::NONE)
+ , m_nYear(0)
+ , m_nMonth(0)
+ , m_nDay(0)
+ , m_nHour(0)
+ , m_nMinute(0)
+ , m_pCurrentDestinationText(nullptr)
+ , m_nCurrentStyleIndex(0)
+ , m_nCurrentCharacterStyleIndex(-1)
+ , m_pCurrentBuffer(nullptr)
+ , m_bInListpicture(false)
+ , m_bInBackground(false)
+ , m_bHadShapeText(false)
+ , m_bInShapeGroup(false)
+ , m_bInShape(false)
+ , m_bCreatedShapeGroup(false)
+ , m_bStartedTrackchange(false)
+ , m_nTableRowWidthAfter(0)
+{
+}
+
+void RTFDocumentImpl::resetFrame() { m_aStates.top().getFrame() = RTFFrame(&m_aStates.top()); }
+
+void RTFDocumentImpl::bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
+ const tools::SvRef<TableRowBuffer>& pTableProperties)
+{
+ rBuffer.emplace_back(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()),
+ nullptr);
+ rBuffer.emplace_back(BUFFER_PROPS, pValue, pTableProperties);
+}
+
+RTFShape::RTFShape() = default;
+
+RTFDrawingObject::RTFDrawingObject() = default;
+
+RTFFrame::RTFFrame(RTFParserState* pParserState)
+ : m_pDocumentImpl(pParserState->getDocumentImpl())
+ , m_nX(0)
+ , m_nY(0)
+ , m_nW(0)
+ , m_nH(0)
+ , m_nHoriPadding(0)
+ , m_nVertPadding(0)
+ , m_nHoriAlign(0)
+ , m_nHoriAnchor(0)
+ , m_nVertAlign(0)
+ , m_nVertAnchor(0)
+ , m_nHRule(NS_ooxml::LN_Value_doc_ST_HeightRule_auto)
+{
+}
+
+void RTFFrame::setSprm(Id nId, Id nValue)
+{
+ if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport())
+ {
+ m_pDocumentImpl->checkFirstRun();
+ m_pDocumentImpl->setNeedPar(false);
+ }
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_FramePr_w:
+ m_nW = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ m_nH = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_x:
+ m_nX = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_y:
+ m_nY = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ m_nHoriPadding = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ m_nVertPadding = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_xAlign:
+ m_nHoriAlign = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_hAnchor:
+ m_nHoriAnchor = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_yAlign:
+ m_nVertAlign = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_vAnchor:
+ m_nVertAnchor = nValue;
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ m_oWrap = nValue;
+ break;
+ default:
+ break;
+ }
+}
+
+RTFSprms RTFFrame::getSprms()
+{
+ RTFSprms sprms;
+
+ static const Id pNames[]
+ = { NS_ooxml::LN_CT_FramePr_x, NS_ooxml::LN_CT_FramePr_y,
+ NS_ooxml::LN_CT_FramePr_hRule, // Make sure nHRule is processed before nH
+ NS_ooxml::LN_CT_FramePr_h, NS_ooxml::LN_CT_FramePr_w,
+ NS_ooxml::LN_CT_FramePr_hSpace, NS_ooxml::LN_CT_FramePr_vSpace,
+ NS_ooxml::LN_CT_FramePr_hAnchor, NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_CT_FramePr_xAlign, NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_CT_FramePr_wrap, NS_ooxml::LN_CT_FramePr_dropCap,
+ NS_ooxml::LN_CT_FramePr_lines };
+
+ for (Id nId : pNames)
+ {
+ RTFValue::Pointer_t pValue;
+
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_FramePr_x:
+ if (m_nX != 0)
+ pValue = new RTFValue(m_nX);
+ break;
+ case NS_ooxml::LN_CT_FramePr_y:
+ if (m_nY != 0)
+ pValue = new RTFValue(m_nY);
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ if (m_nH != 0)
+ {
+ if (m_nHRule == NS_ooxml::LN_Value_doc_ST_HeightRule_exact)
+ pValue = new RTFValue(-m_nH); // The negative value just sets nHRule
+ else
+ pValue = new RTFValue(m_nH);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_w:
+ if (m_nW != 0)
+ pValue = new RTFValue(m_nW);
+ break;
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ if (m_nHoriPadding != 0)
+ pValue = new RTFValue(m_nHoriPadding);
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ if (m_nVertPadding != 0)
+ pValue = new RTFValue(m_nVertPadding);
+ break;
+ case NS_ooxml::LN_CT_FramePr_hAnchor:
+ {
+ if (m_nHoriAnchor == 0)
+ m_nHoriAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin;
+ pValue = new RTFValue(m_nHoriAnchor);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_vAnchor:
+ {
+ if (m_nVertAnchor == 0)
+ m_nVertAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
+ pValue = new RTFValue(m_nVertAnchor);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_xAlign:
+ pValue = new RTFValue(m_nHoriAlign);
+ break;
+ case NS_ooxml::LN_CT_FramePr_yAlign:
+ pValue = new RTFValue(m_nVertAlign);
+ break;
+ case NS_ooxml::LN_CT_FramePr_hRule:
+ {
+ if (m_nH < 0)
+ m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_exact;
+ else if (m_nH > 0)
+ m_nHRule = NS_ooxml::LN_Value_doc_ST_HeightRule_atLeast;
+ pValue = new RTFValue(m_nHRule);
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ if (m_oWrap)
+ pValue = new RTFValue(*m_oWrap);
+ break;
+ default:
+ break;
+ }
+
+ if (pValue)
+ sprms.set(nId, pValue);
+ }
+
+ RTFSprms frameprSprms;
+ frameprSprms.set(NS_ooxml::LN_CT_PPrBase_framePr, new RTFValue(sprms));
+ return frameprSprms;
+}
+
+bool RTFFrame::hasProperties() const
+{
+ return m_nX != 0 || m_nY != 0 || m_nW != 0 || m_nH != 0 || m_nHoriPadding != 0
+ || m_nVertPadding != 0 || m_nHoriAlign != 0 || m_nHoriAnchor != 0 || m_nVertAlign != 0
+ || m_nVertAnchor != 0;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
new file mode 100644
index 000000000..e859c01c9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -0,0 +1,994 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <queue>
+#include <tuple>
+#include <vector>
+#include <optional>
+
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <oox/mathml/importutils.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/color.hxx>
+#include <tools/long.hxx>
+
+#include <rtftok/RTFDocument.hxx>
+#include "rtfreferencetable.hxx"
+#include "rtfsprm.hxx"
+#include "rtflistener.hxx"
+
+class SvStream;
+namespace oox
+{
+class GraphicHelper;
+}
+namespace com::sun::star
+{
+namespace beans
+{
+class XPropertySet;
+}
+namespace document
+{
+class XDocumentProperties;
+}
+namespace lang
+{
+class XMultiServiceFactory;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFParserState;
+class RTFDocumentImpl;
+class RTFTokenizer;
+class RTFSdrImport;
+class TableRowBuffer;
+
+enum class RTFBorderState
+{
+ NONE,
+ PARAGRAPH,
+ PARAGRAPH_BOX,
+ CELL,
+ PAGE,
+ CHARACTER
+};
+
+/// Different kind of buffers for table cell contents.
+enum RTFBufferTypes
+{
+ BUFFER_SETSTYLE,
+ /// Stores properties, should be created only in bufferProperties().
+ BUFFER_PROPS,
+ BUFFER_NESTROW,
+ BUFFER_CELLEND,
+ BUFFER_STARTRUN,
+ BUFFER_TEXT,
+ BUFFER_UTEXT,
+ BUFFER_ENDRUN,
+ BUFFER_PAR,
+ BUFFER_STARTSHAPE,
+ /// Imports a shape.
+ BUFFER_RESOLVESHAPE,
+ BUFFER_ENDSHAPE,
+ BUFFER_RESOLVESUBSTREAM,
+ /// Restores RTFParserState::aPicture.
+ BUFFER_PICTURE
+};
+
+/// Form field types
+enum class RTFFormFieldType
+{
+ NONE,
+ TEXT,
+ CHECKBOX,
+ LIST
+};
+
+enum class RTFBmpStyle
+{
+ NONE,
+ PNG,
+ JPEG,
+ DIBITMAP
+};
+
+enum class RTFFieldStatus
+{
+ NONE,
+ INSTRUCTION,
+ RESULT
+};
+
+/// A buffer storing dmapper calls.
+using Buf_t = std::tuple<RTFBufferTypes, RTFValue::Pointer_t, tools::SvRef<TableRowBuffer>>;
+using RTFBuffer_t = std::deque<Buf_t>;
+
+/// holds one nested table row
+class TableRowBuffer : public virtual SvRefBase
+{
+ RTFBuffer_t m_aBuffer;
+ ::std::deque<RTFSprms> m_aCellsSprms;
+ ::std::deque<RTFSprms> m_aCellsAttributes;
+ int m_nCells;
+ writerfilter::Reference<Properties>::Pointer_t m_pParaProperties;
+ writerfilter::Reference<Properties>::Pointer_t m_pFrameProperties;
+ writerfilter::Reference<Properties>::Pointer_t m_pRowProperties;
+
+public:
+ TableRowBuffer(RTFBuffer_t aBuffer, std::deque<RTFSprms> aSprms,
+ std::deque<RTFSprms> aAttributes, int const nCells)
+ : m_aBuffer(std::move(aBuffer))
+ , m_aCellsSprms(std::move(aSprms))
+ , m_aCellsAttributes(std::move(aAttributes))
+ , m_nCells(nCells)
+ {
+ }
+
+ RTFBuffer_t& GetBuffer() { return m_aBuffer; }
+ std::deque<RTFSprms>& GetCellsSprms() { return m_aCellsSprms; }
+ std::deque<RTFSprms>& GetCellsAttributes() { return m_aCellsAttributes; }
+ int GetCells() const { return m_nCells; }
+ writerfilter::Reference<Properties>::Pointer_t& GetParaProperties()
+ {
+ return m_pParaProperties;
+ }
+ writerfilter::Reference<Properties>::Pointer_t& GetFrameProperties()
+ {
+ return m_pFrameProperties;
+ }
+ writerfilter::Reference<Properties>::Pointer_t& GetRowProperties() { return m_pRowProperties; }
+};
+
+/// An entry in the color table.
+class RTFColorTableEntry
+{
+public:
+ void SetRed(sal_uInt8 nRed)
+ {
+ m_bAuto = false;
+ m_nR = nRed;
+ }
+ void SetGreen(sal_uInt8 nGreen)
+ {
+ m_bAuto = false;
+ m_nG = nGreen;
+ }
+ void SetBlue(sal_uInt8 nBlue)
+ {
+ m_bAuto = false;
+ m_nB = nBlue;
+ }
+ Color GetColor() const { return m_bAuto ? COL_AUTO : Color(m_nR, m_nG, m_nB); }
+
+private:
+ bool m_bAuto = true;
+ sal_uInt8 m_nR = 0;
+ sal_uInt8 m_nG = 0;
+ sal_uInt8 m_nB = 0;
+};
+
+/// Stores the properties of a shape.
+class RTFShape : public virtual SvRefBase
+{
+public:
+ RTFShape();
+
+ std::vector<std::pair<OUString, OUString>>& getProperties() { return m_aProperties; }
+
+ const std::vector<std::pair<OUString, OUString>>& getProperties() const
+ {
+ return m_aProperties;
+ }
+
+ std::vector<std::pair<OUString, OUString>>& getGroupProperties() { return m_aGroupProperties; }
+
+ void setLeft(sal_Int32 nLeft) { m_nLeft = nLeft; }
+
+ sal_Int32 getLeft() const { return m_nLeft; }
+
+ void setTop(sal_Int32 nTop) { m_nTop = nTop; }
+
+ sal_Int32 getTop() const { return m_nTop; }
+
+ void setRight(sal_Int32 nRight) { m_nRight = nRight; }
+
+ sal_Int32 getRight() const { return m_nRight; }
+
+ void setBottom(sal_Int32 nBottom) { m_nBottom = nBottom; }
+
+ sal_Int32 getBottom() const { return m_nBottom; }
+
+ void setZ(sal_Int32 nZ) { m_oZ = nZ; }
+
+ bool hasZ() const { return bool(m_oZ); }
+
+ sal_Int32 getZ() const { return *m_oZ; }
+
+ void setHoriOrientRelation(sal_Int16 nHoriOrientRelation)
+ {
+ m_nHoriOrientRelation = nHoriOrientRelation;
+ }
+
+ sal_Int16 getHoriOrientRelation() const { return m_nHoriOrientRelation; }
+
+ void setVertOrientRelation(sal_Int16 nVertOrientRelation)
+ {
+ m_nVertOrientRelation = nVertOrientRelation;
+ }
+
+ sal_Int16 getVertOrientRelation() const { return m_nVertOrientRelation; }
+
+ void setHoriOrientRelationToken(sal_uInt32 nHoriOrientRelationToken)
+ {
+ m_nHoriOrientRelationToken = nHoriOrientRelationToken;
+ }
+
+ sal_uInt32 getHoriOrientRelationToken() const { return m_nHoriOrientRelationToken; }
+
+ void setVertOrientRelationToken(sal_uInt32 nVertOrientRelationToken)
+ {
+ m_nVertOrientRelationToken = nVertOrientRelationToken;
+ }
+
+ sal_uInt32 getVertOrientRelationToken() const { return m_nVertOrientRelationToken; }
+
+ void setWrap(css::text::WrapTextMode nWrap) { m_nWrap = nWrap; }
+
+ css::text::WrapTextMode getWrap() const { return m_nWrap; }
+
+ void setInBackground(bool bInBackground) { m_bInBackground = bInBackground; }
+
+ bool getInBackground() const { return m_bInBackground; }
+
+ RTFSprms& getWrapPolygonSprms() { return m_aWrapPolygonSprms; }
+
+ RTFSprms& getAnchorAttributes() { return m_aAnchorAttributes; }
+
+ std::pair<Id, RTFValue::Pointer_t>& getWrapSprm() { return m_aWrapSprm; }
+
+private:
+ std::vector<std::pair<OUString, OUString>> m_aProperties; ///< Properties of a single shape.
+ std::vector<std::pair<OUString, OUString>>
+ m_aGroupProperties; ///< Properties applied on the groupshape.
+ sal_Int32 m_nLeft = 0;
+ sal_Int32 m_nTop = 0;
+ sal_Int32 m_nRight = 0;
+ sal_Int32 m_nBottom = 0;
+ std::optional<sal_Int32> m_oZ; ///< Z-Order of the shape.
+ sal_Int16 m_nHoriOrientRelation
+ = 0; ///< Horizontal text::RelOrientation for drawinglayer shapes.
+ sal_Int16 m_nVertOrientRelation = 0; ///< Vertical text::RelOrientation for drawinglayer shapes.
+ sal_uInt32 m_nHoriOrientRelationToken = 0; ///< Horizontal dmapper token for Writer pictures.
+ sal_uInt32 m_nVertOrientRelationToken = 0; ///< Vertical dmapper token for Writer pictures.
+ css::text::WrapTextMode m_nWrap = css::text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE;
+ /// If shape is below text (true) or text is below shape (false).
+ bool m_bInBackground = false;
+ /// Wrap polygon, written by RTFSdrImport::resolve(), read by RTFDocumentImpl::resolvePict().
+ RTFSprms m_aWrapPolygonSprms;
+ /// Anchor attributes like wrap distance, written by RTFSdrImport::resolve(), read by RTFDocumentImpl::resolvePict().
+ RTFSprms m_aAnchorAttributes;
+ /// Wrap type, written by RTFDocumentImpl::popState(), read by RTFDocumentImpl::resolvePict().
+ std::pair<Id, RTFValue::Pointer_t> m_aWrapSprm{ 0, nullptr };
+};
+
+/// Stores the properties of a drawing object.
+class RTFDrawingObject : public RTFShape
+{
+public:
+ RTFDrawingObject();
+
+ void setShape(const css::uno::Reference<css::drawing::XShape>& xShape) { m_xShape = xShape; }
+ const css::uno::Reference<css::drawing::XShape>& getShape() const { return m_xShape; }
+ void setPropertySet(const css::uno::Reference<css::beans::XPropertySet>& xPropertySet)
+ {
+ m_xPropertySet = xPropertySet;
+ }
+ const css::uno::Reference<css::beans::XPropertySet>& getPropertySet() const
+ {
+ return m_xPropertySet;
+ }
+ std::vector<css::beans::PropertyValue>& getPendingProperties() { return m_aPendingProperties; }
+ void setLineColorR(sal_uInt8 nLineColorR) { m_nLineColorR = nLineColorR; }
+ sal_uInt8 getLineColorR() const { return m_nLineColorR; }
+ void setLineColorG(sal_uInt8 nLineColorG) { m_nLineColorG = nLineColorG; }
+ sal_uInt8 getLineColorG() const { return m_nLineColorG; }
+ void setLineColorB(sal_uInt8 nLineColorB) { m_nLineColorB = nLineColorB; }
+ sal_uInt8 getLineColorB() const { return m_nLineColorB; }
+ void setHasLineColor(bool bHasLineColor) { m_bHasLineColor = bHasLineColor; }
+ bool getHasLineColor() const { return m_bHasLineColor; }
+ void setFillColorR(sal_uInt8 nFillColorR) { m_nFillColorR = nFillColorR; }
+ sal_uInt8 getFillColorR() const { return m_nFillColorR; }
+ void setFillColorG(sal_uInt8 nFillColorG) { m_nFillColorG = nFillColorG; }
+ sal_uInt8 getFillColorG() const { return m_nFillColorG; }
+ void setFillColorB(sal_uInt8 nFillColorB) { m_nFillColorB = nFillColorB; }
+ sal_uInt8 getFillColorB() const { return m_nFillColorB; }
+ void setHasFillColor(bool bHasFillColor) { m_bHasFillColor = bHasFillColor; }
+ bool getHasFillColor() const { return m_bHasFillColor; }
+ void setDhgt(sal_Int32 nDhgt) { m_nDhgt = nDhgt; }
+ sal_Int32 getDhgt() const { return m_nDhgt; }
+ void setFLine(sal_Int32 nFLine) { m_nFLine = nFLine; }
+ sal_Int32 getFLine() const { return m_nFLine; }
+ void setPolyLineCount(sal_Int32 nPolyLineCount) { m_nPolyLineCount = nPolyLineCount; }
+ sal_Int32 getPolyLineCount() const { return m_nPolyLineCount; }
+ std::vector<css::awt::Point>& getPolyLinePoints() { return m_aPolyLinePoints; }
+ void setHadShapeText(bool bHadShapeText) { m_bHadShapeText = bHadShapeText; }
+ bool getHadShapeText() const { return m_bHadShapeText; }
+
+private:
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ css::uno::Reference<css::beans::XPropertySet> m_xPropertySet;
+ std::vector<css::beans::PropertyValue> m_aPendingProperties;
+ sal_uInt8 m_nLineColorR = 0;
+ sal_uInt8 m_nLineColorG = 0;
+ sal_uInt8 m_nLineColorB = 0;
+ bool m_bHasLineColor = false;
+ sal_uInt8 m_nFillColorR = 0;
+ sal_uInt8 m_nFillColorG = 0;
+ sal_uInt8 m_nFillColorB = 0;
+ bool m_bHasFillColor = false;
+ sal_Int32 m_nDhgt = 0;
+ sal_Int32 m_nFLine = -1;
+ sal_Int32 m_nPolyLineCount = 0;
+ std::vector<css::awt::Point> m_aPolyLinePoints;
+ bool m_bHadShapeText = false;
+};
+
+/// Stores the properties of a picture.
+class RTFPicture : public virtual SvRefBase
+{
+public:
+ sal_Int32 nWidth = 0;
+ sal_Int32 nHeight = 0;
+ sal_Int32 nGoalWidth = 0;
+ sal_Int32 nGoalHeight = 0;
+ sal_uInt16 nScaleX = 100;
+ sal_uInt16 nScaleY = 100;
+ short nCropT = 0;
+ short nCropB = 0;
+ short nCropL = 0;
+ short nCropR = 0;
+ sal_uInt16 eWMetafile = 0;
+ RTFBmpStyle eStyle = RTFBmpStyle::NONE;
+};
+
+/// Stores the properties of a frame
+class RTFFrame
+{
+private:
+ RTFDocumentImpl* m_pDocumentImpl;
+ sal_Int32 m_nX, m_nY, m_nW, m_nH;
+ sal_Int32 m_nHoriPadding, m_nVertPadding;
+ sal_Int32 m_nHoriAlign, m_nHoriAnchor, m_nVertAlign, m_nVertAnchor;
+ Id m_nHRule;
+ std::optional<Id> m_oWrap;
+
+public:
+ explicit RTFFrame(RTFParserState* pParserState);
+
+ /// Convert the stored properties to Sprms
+ RTFSprms getSprms();
+ /// Store a property
+ void setSprm(Id nId, Id nValue);
+ bool hasProperties() const;
+ /// If we got tokens indicating we're in a frame.
+ bool inFrame() const;
+};
+
+/// State of the parser, which gets saved / restored when changing groups.
+class RTFParserState
+{
+public:
+ /// Maps to OOXML's ascii, cs or eastAsia.
+ enum class RunType
+ {
+ NONE,
+ LOCH,
+ HICH,
+ DBCH,
+ LTRCH_RTLCH_1,
+ LTRCH_RTLCH_2,
+ RTLCH_LTRCH_1,
+ RTLCH_LTRCH_2
+ };
+
+ explicit RTFParserState(RTFDocumentImpl* pDocumentImpl);
+
+ void appendDestinationText(std::u16string_view rString)
+ {
+ if (m_pCurrentDestinationText)
+ m_pCurrentDestinationText->append(rString);
+ }
+
+ void setPropName(const OUString& rPropName) { m_aPropName = rPropName; }
+ OUString const& getPropName() const { return m_aPropName; }
+ void setPropType(const css::uno::Type& rPropType) { m_aPropType = rPropType; }
+ css::uno::Type const& getPropType() const { return m_aPropType; }
+ void setTableRowWidthAfter(int nTableRowWidthAfter)
+ {
+ m_nTableRowWidthAfter = nTableRowWidthAfter;
+ }
+ int getTableRowWidthAfter() const { return m_nTableRowWidthAfter; }
+ void setStartedTrackchange(bool bStartedTrackchange)
+ {
+ m_bStartedTrackchange = bStartedTrackchange;
+ }
+ bool getStartedTrackchange() const { return m_bStartedTrackchange; }
+ void setCreatedShapeGroup(bool bCreatedShapeGroup)
+ {
+ m_bCreatedShapeGroup = bCreatedShapeGroup;
+ }
+ bool getCreatedShapeGroup() const { return m_bCreatedShapeGroup; }
+ void setInShape(bool bInShape) { m_bInShape = bInShape; }
+ bool getInShape() const { return m_bInShape; }
+ void setInShapeGroup(bool bInShapeGroup) { m_bInShapeGroup = bInShapeGroup; }
+ bool getInShapeGroup() const { return m_bInShapeGroup; }
+ void setHadShapeText(bool bHadShapeText) { m_bHadShapeText = bHadShapeText; }
+ bool getHadShapeText() const { return m_bHadShapeText; }
+ void setInBackground(bool bInBackground) { m_bInBackground = bInBackground; }
+ bool getInBackground() const { return m_bInBackground; }
+ void setInListpicture(bool bInListpicture) { m_bInListpicture = bInListpicture; }
+ bool getInListpicture() const { return m_bInListpicture; }
+ void setCurrentBuffer(RTFBuffer_t* pCurrentBuffer) { m_pCurrentBuffer = pCurrentBuffer; }
+ RTFBuffer_t* getCurrentBuffer() const { return m_pCurrentBuffer; }
+ void setCurrentListOverrideIndex(int nCurrentListOverrideIndex)
+ {
+ m_nCurrentListOverrideIndex = nCurrentListOverrideIndex;
+ }
+ int getCurrentListOverrideIndex() const { return m_nCurrentListOverrideIndex; }
+ void setCurrentListIndex(int nCurrentListIndex) { m_nCurrentListIndex = nCurrentListIndex; }
+ int getCurrentListIndex() const { return m_nCurrentListIndex; }
+ void setCurrentCharacterStyleIndex(int nCurrentCharacterStyleIndex)
+ {
+ m_nCurrentCharacterStyleIndex = nCurrentCharacterStyleIndex;
+ }
+ int getCurrentCharacterStyleIndex() const { return m_nCurrentCharacterStyleIndex; }
+ void setCurrentStyleIndex(int nCurrentStyleIndex) { m_nCurrentStyleIndex = nCurrentStyleIndex; }
+ int getCurrentStyleIndex() const { return m_nCurrentStyleIndex; }
+ void setCurrentDestinationText(OUStringBuffer* pDestinationText)
+ {
+ m_pCurrentDestinationText = pDestinationText;
+ }
+ OUStringBuffer* getCurrentDestinationText() const { return m_pCurrentDestinationText; }
+ OUStringBuffer& getDestinationText() { return m_aDestinationText; }
+ void setMinute(sal_uInt16 nMinute) { m_nMinute = nMinute; }
+ sal_uInt16 getMinute() const { return m_nMinute; }
+ void setHour(sal_uInt16 nHour) { m_nHour = nHour; }
+ sal_uInt16 getHour() const { return m_nHour; }
+ void setDay(sal_uInt16 nDay) { m_nDay = nDay; }
+ sal_uInt16 getDay() const { return m_nDay; }
+ void setMonth(sal_uInt16 nMonth) { m_nMonth = nMonth; }
+ sal_uInt16 getMonth() const { return m_nMonth; }
+ void setYear(sal_uInt16 nYear) { m_nYear = nYear; }
+ sal_uInt16 getYear() const { return m_nYear; }
+ void setRunType(RunType eRunType) { m_eRunType = eRunType; }
+ RunType getRunType() const { return m_eRunType; }
+ RTFFrame& getFrame() { return m_aFrame; }
+ RTFDrawingObject& getDrawingObject() { return m_aDrawingObject; }
+ RTFShape& getShape() { return m_aShape; }
+ RTFPicture& getPicture() { return m_aPicture; }
+ void setLevelNumbersValid(bool bLevelNumbersValid)
+ {
+ m_bLevelNumbersValid = bLevelNumbersValid;
+ }
+ bool getLevelNumbersValid() const { return m_bLevelNumbersValid; }
+ std::vector<sal_Int32>& getLevelNumbers() { return m_aLevelNumbers; }
+ RTFSprms& getListLevelEntries() { return m_aListLevelEntries; }
+ int& getListLevelNum() { return m_nListLevelNum; }
+ void setBinaryToRead(int nBinaryToRead) { m_nBinaryToRead = nBinaryToRead; }
+ int getBinaryToRead() const { return m_nBinaryToRead; }
+ int& getCharsToSkip() { return m_nCharsToSkip; }
+ void setUc(int nUc) { m_nUc = nUc; }
+ int getUc() const { return m_nUc; }
+ void setCurrentEncoding(rtl_TextEncoding nCurrentEncoding)
+ {
+ m_nCurrentEncoding = nCurrentEncoding;
+ }
+ rtl_TextEncoding getCurrentEncoding() const { return m_nCurrentEncoding; }
+ RTFColorTableEntry& getCurrentColor() { return m_aCurrentColor; }
+ RTFSprms& getTabAttributes() { return m_aTabAttributes; }
+ RTFSprms& getTableCellAttributes() { return m_aTableCellAttributes; }
+ RTFSprms& getTableCellSprms() { return m_aTableCellSprms; }
+ RTFSprms& getTableRowAttributes() { return m_aTableRowAttributes; }
+ RTFSprms& getTableRowSprms() { return m_aTableRowSprms; }
+ RTFSprms& getSectionAttributes() { return m_aSectionAttributes; }
+ RTFSprms& getSectionSprms() { return m_aSectionSprms; }
+ RTFSprms& getParagraphAttributes() { return m_aParagraphAttributes; }
+ RTFSprms& getParagraphSprms() { return m_aParagraphSprms; }
+ RTFSprms& getCharacterAttributes() { return m_aCharacterAttributes; }
+ RTFSprms& getCharacterSprms() { return m_aCharacterSprms; }
+ RTFSprms& getTableAttributes() { return m_aTableAttributes; }
+ RTFSprms& getTableSprms() { return m_aTableSprms; }
+ void setBorderState(RTFBorderState nBorderState) { m_nBorderState = nBorderState; }
+ RTFBorderState getBorderState() const { return m_nBorderState; }
+ void setFieldStatus(RTFFieldStatus eFieldStatus) { m_eFieldStatus = eFieldStatus; }
+ RTFFieldStatus getFieldStatus() const { return m_eFieldStatus; }
+ void setFieldLocked(bool bSet) { m_bFieldLocked = bSet; }
+ bool isFieldLocked() const { return m_bFieldLocked; }
+ void setDestination(Destination eDestination) { m_eDestination = eDestination; }
+ Destination getDestination() const { return m_eDestination; }
+ void setInternalState(RTFInternalState nInternalState) { m_nInternalState = nInternalState; }
+ RTFInternalState getInternalState() const { return m_nInternalState; }
+ RTFDocumentImpl* getDocumentImpl() { return m_pDocumentImpl; }
+ OUString getDocVar() { return m_aDocVar; }
+ void appendDocVar(OUString& aDocVar) { m_aDocVar += aDocVar; };
+ OUString getDocVarName() { return m_aDocVarName; }
+ void setDocVarName(OUString& aDocVarName) { m_aDocVarName = aDocVarName; }
+ void clearDocVarName() { m_aDocVarName = ""; }
+
+private:
+ RTFDocumentImpl* m_pDocumentImpl;
+ RTFInternalState m_nInternalState;
+ Destination m_eDestination;
+ RTFFieldStatus m_eFieldStatus;
+ bool m_bFieldLocked;
+ RTFBorderState m_nBorderState;
+ // font table, stylesheet table
+ RTFSprms m_aTableSprms;
+ RTFSprms m_aTableAttributes;
+ // reset by plain
+ RTFSprms m_aCharacterSprms;
+ RTFSprms m_aCharacterAttributes;
+ // reset by pard
+ RTFSprms m_aParagraphSprms;
+ RTFSprms m_aParagraphAttributes;
+ // reset by sectd
+ RTFSprms m_aSectionSprms;
+ RTFSprms m_aSectionAttributes;
+ // reset by trowd
+ RTFSprms m_aTableRowSprms;
+ RTFSprms m_aTableRowAttributes;
+ // reset by cellx
+ RTFSprms m_aTableCellSprms;
+ RTFSprms m_aTableCellAttributes;
+ // reset by tx
+ RTFSprms m_aTabAttributes;
+
+ RTFColorTableEntry m_aCurrentColor;
+
+ rtl_TextEncoding m_nCurrentEncoding;
+
+ /// Current \uc value.
+ int m_nUc;
+ /// Characters to skip, set to nUc by \u.
+ int m_nCharsToSkip;
+ /// Characters to read, once in binary mode.
+ int m_nBinaryToRead;
+
+ /// Next list level index to use when parsing list table.
+ int m_nListLevelNum;
+ /// List level entries, which will form a list entry later.
+ RTFSprms m_aListLevelEntries;
+ /// List of character positions in leveltext to replace.
+ std::vector<sal_Int32> m_aLevelNumbers;
+ /// If aLevelNumbers should be read at all.
+ bool m_bLevelNumbersValid;
+
+ RTFPicture m_aPicture;
+ RTFShape m_aShape;
+ RTFDrawingObject m_aDrawingObject;
+ RTFFrame m_aFrame;
+
+ RunType m_eRunType;
+
+ // Info group.
+ sal_Int16 m_nYear;
+ sal_uInt16 m_nMonth;
+ sal_uInt16 m_nDay;
+ sal_uInt16 m_nHour;
+ sal_uInt16 m_nMinute;
+
+ /// Text from special destinations.
+ OUStringBuffer m_aDestinationText{ 512 };
+ /// point to the buffer of the current destination
+ OUStringBuffer* m_pCurrentDestinationText;
+
+ /// Index of the current style.
+ int m_nCurrentStyleIndex;
+ /// Index of the current character style.
+ int m_nCurrentCharacterStyleIndex;
+ /// Current listid, points to a listtable entry.
+ int m_nCurrentListIndex = -1;
+ /// Current ls, points to a listoverridetable entry.
+ int m_nCurrentListOverrideIndex = -1;
+
+ /// Points to the active buffer, if there is one.
+ RTFBuffer_t* m_pCurrentBuffer;
+
+ /// If we're inside a \listpicture group.
+ bool m_bInListpicture;
+
+ /// If we're inside a \background group.
+ bool m_bInBackground;
+
+ bool m_bHadShapeText;
+ bool m_bInShapeGroup; ///< If we're inside a \shpgrp group.
+ bool m_bInShape; ///< If we're inside a \shp group.
+ bool m_bCreatedShapeGroup; ///< A GroupShape was created and pushed to the parent stack.
+ bool m_bStartedTrackchange; ///< Track change is started, need to end it before popping.
+
+ /// User-defined property: key name.
+ OUString m_aPropName;
+ /// User-defined property: value type.
+ css::uno::Type m_aPropType;
+
+ /// Width of invisible cell at the end of the row.
+ int m_nTableRowWidthAfter;
+
+ /// For importing document variables which are not referenced in the document
+ OUString m_aDocVar;
+ OUString m_aDocVarName;
+};
+
+/// An RTF stack is similar to std::stack, except that it has an operator[].
+struct RTFStack
+{
+private:
+ std::deque<RTFParserState> m_Impl;
+
+public:
+ RTFParserState& top()
+ {
+ if (m_Impl.empty())
+ throw css::io::WrongFormatException(
+ "Parser state is empty! Invalid usage of destination braces in RTF?", nullptr);
+ return m_Impl.back();
+ }
+ void pop()
+ {
+ if (m_Impl.empty())
+ throw css::io::WrongFormatException(
+ "Parser state is empty! Invalid usage of destination braces in RTF?", nullptr);
+ return m_Impl.pop_back();
+ }
+ void push(RTFParserState const& rState) { return m_Impl.push_back(rState); }
+ bool empty() const { return m_Impl.empty(); }
+ size_t size() const { return m_Impl.size(); }
+ const RTFParserState& operator[](size_t nIndex) const { return m_Impl[nIndex]; }
+ RTFParserState& operator[](size_t nIndex) { return m_Impl[nIndex]; }
+};
+
+void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue);
+void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::NO_APPEND);
+Id getParagraphBorder(sal_uInt32 nIndex);
+void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::YES, bool bAttribute = true);
+bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Looks up the nParent then the nested nId attribute in rSprms.
+RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Looks up the nParent then the nested nId sprm in rSprms.
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Checks if rName is contained at least once in rProperties as a key.
+bool findPropertyName(const std::vector<css::beans::PropertyValue>& rProperties,
+ const OUString& rName);
+RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId);
+OString DTTM22OString(tools::Long nDTTM);
+
+/// Implementation of the RTFDocument interface.
+class RTFDocumentImpl : public RTFDocument, public RTFListener
+{
+public:
+ using Pointer_t = tools::SvRef<RTFDocumentImpl>;
+ RTFDocumentImpl(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor);
+ ~RTFDocumentImpl() override;
+
+ // RTFDocument
+ void resolve(Stream& rMapper) override;
+
+ // RTFListener
+ RTFError dispatchDestination(RTFKeyword nKeyword) override;
+ RTFError dispatchFlag(RTFKeyword nKeyword) override;
+ RTFError dispatchSymbol(RTFKeyword nKeyword) override;
+ RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) override;
+ RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
+ bool dispatchTableSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchInfoValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchFrameValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchTableValue(RTFKeyword nKeyword, int nParam);
+ RTFError resolveChars(char ch) override;
+ RTFError pushState() override;
+ RTFError beforePopState(RTFParserState& rState);
+ RTFError popState() override;
+ void afterPopState(RTFParserState& rState);
+ Destination getDestination() override;
+ void setDestination(Destination eDestination) override;
+ RTFInternalState getInternalState() override;
+ void setInternalState(RTFInternalState nInternalState) override;
+ bool getSkipUnknown() override;
+ void setSkipUnknown(bool bSkipUnknown) override;
+ void finishSubstream() override;
+ bool isSubstream() const override;
+
+ Stream& Mapper() { return *m_pMapperStream; }
+ void setSuperstream(RTFDocumentImpl* pSuperstream);
+ const css::uno::Reference<css::lang::XMultiServiceFactory>& getModelFactory() const
+ {
+ return m_xModelFactory;
+ }
+ bool isInBackground();
+ void setDestinationText(std::u16string_view rString);
+ /// Resolve a picture: If not inline, then anchored.
+ void resolvePict(bool bInline, css::uno::Reference<css::drawing::XShape> const& rShape);
+
+ /// If this is the first run of the document, starts the initial paragraph.
+ void checkFirstRun();
+ /// Send NS_ooxml::LN_settings_settings to dmapper.
+ void outputSettingsTable();
+ /// If the initial paragraph is started.
+ bool getFirstRun() const { return m_bFirstRun; }
+ /// If we need to add a dummy paragraph before a section break.
+ void setNeedPar(bool bNeedPar);
+ /// Return the dmapper index of an RTF index for fonts.
+ int getFontIndex(int nIndex);
+ /// Return the name of the font, based on a dmapper index.
+ OUString getFontName(int nIndex);
+ /// Return the style name of an RTF style index.
+ OUString getStyleName(int nIndex);
+ /// Return the style type of an RTF style index.
+ Id getStyleType(int nIndex);
+ /// Return the encoding associated with a font index.
+ rtl_TextEncoding getEncoding(int nFontIndex);
+ /// Get the default parser state.
+ RTFParserState& getDefaultState();
+ oox::GraphicHelper& getGraphicHelper();
+ /// Are we inside the stylesheet table?
+ bool isStyleSheetImport();
+ /// Resets m_aStates.top().aFrame.
+ void resetFrame();
+ /// Buffers properties to be sent later.
+ void bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
+ const tools::SvRef<TableRowBuffer>& pTableProperties);
+ /// implement non-obvious RTF specific style inheritance
+ RTFReferenceTable::Entries_t deduplicateStyleTable();
+
+private:
+ SvStream& Strm();
+ Color getColorTable(sal_uInt32 nIndex);
+ writerfilter::Reference<Properties>::Pointer_t createStyleProperties();
+ void resetSprms();
+ void resetAttributes();
+ void resolveSubstream(std::size_t nPos, Id nId);
+ void resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst);
+
+ void text(OUString& rString);
+ // Sends a single character to dmapper, taking care of buffering.
+ void singleChar(sal_uInt8 nValue, bool bRunProps = false);
+ // Sends run properties to dmapper, taking care of buffering.
+ void runProps();
+ void runBreak();
+ void parBreak();
+ void tableBreak();
+ writerfilter::Reference<Properties>::Pointer_t
+ getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType);
+ void checkNeedPap();
+ void handleFontTableEntry();
+ void sectBreak(bool bFinal = false);
+ void prepareProperties(RTFParserState& rState,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties,
+ int nCells, int nCurrentCellX);
+ /// Send the passed properties to dmapper.
+ void sendProperties(writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties);
+ void replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSrpms,
+ ::std::deque<RTFSprms>& rCellsAttributes, int nCells);
+ void replayBuffer(RTFBuffer_t& rBuffer, RTFSprms* pSprms, RTFSprms const* pAttributes);
+ /// If we have some unicode or hex characters to send.
+ void checkUnicode(bool bUnicode, bool bHex);
+ /// If we need a final section break at the end of the document.
+ void setNeedSect(bool bNeedSect);
+ void resetTableRowProperties();
+ void backupTableRowProperties();
+ void restoreTableRowProperties();
+ /// Turns the destination text into an input stream of the current OLE attributes.
+ RTFError handleEmbeddedObject();
+
+ css::uno::Reference<css::uno::XComponentContext> const& m_xContext;
+ css::uno::Reference<css::io::XInputStream> const& m_xInputStream;
+ css::uno::Reference<css::lang::XComponent> const& m_xDstDoc;
+ css::uno::Reference<css::frame::XFrame> const& m_xFrame;
+ css::uno::Reference<css::task::XStatusIndicator> const& m_xStatusIndicator;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xModelFactory;
+ css::uno::Reference<css::document::XDocumentProperties> m_xDocumentProperties;
+ std::unique_ptr<SvStream> m_pInStream;
+ Stream* m_pMapperStream;
+ tools::SvRef<RTFSdrImport> m_pSdrImport;
+ tools::SvRef<RTFTokenizer> m_pTokenizer;
+ RTFStack m_aStates;
+ /// Read by RTF_PARD.
+ RTFParserState m_aDefaultState;
+ bool m_bSkipUnknown;
+ /// Font index <-> encoding map, *not* part of the parser state
+ std::map<int, rtl_TextEncoding> m_aFontEncodings;
+ /// Font index <-> name map.
+ std::map<int, OUString> m_aFontNames;
+ /// Maps the non-continuous font indexes to the continuous dmapper indexes.
+ std::vector<int> m_aFontIndexes;
+ /// Maps style indexes to style names.
+ std::map<int, OUString> m_aStyleNames;
+ /// Maps style indexes to style types.
+ std::map<int, Id> m_aStyleTypes;
+ /// Color index <-> RGB color value map
+ std::vector<Color> m_aColorTable;
+ /// to start initial paragraph / section after font/style tables
+ bool m_bFirstRun;
+ /// except in the case of tables in initial multicolumn section (global for assertion)
+ bool m_bFirstRunException;
+ /// If paragraph properties should be emitted on next run.
+ bool m_bNeedPap;
+ /// If we need to emit a CR at the end of substream.
+ bool m_bNeedCr;
+ /// Original value of m_bNeedCr -- saved/restored before/after textframes.
+ bool m_bNeedCrOrig;
+ bool m_bNeedPar;
+ /// If set, an empty paragraph will be added at the end of the document.
+ bool m_bNeedFinalPar;
+ /// The list table and list override table combined.
+ RTFSprms m_aListTableSprms;
+ /// Maps between listoverridetable and listtable indexes.
+ std::map<int, int> m_aListOverrideTable;
+ /// Maps listtable indexes to listtable entries.
+ std::map<int, RTFValue::Pointer_t> m_aListTable;
+ /// Index of the current list level in a list table entry.
+ int m_nListLevel = -1;
+ /// Maps List level indexes to removed values in the current list entry.
+ std::map<int, int> m_aInvalidListLevelFirstIndents;
+ /// Maps list table indexes to levels (and their removed values).
+ std::map<int, std::map<int, int>> m_aInvalidListTableFirstIndents;
+ /// The settings table attributes.
+ RTFSprms m_aSettingsTableAttributes;
+ /// The settings table sprms.
+ RTFSprms m_aSettingsTableSprms;
+
+ std::shared_ptr<oox::GraphicHelper> m_pGraphicHelper;
+
+ /// cell props buffer for nested tables, reset by \nestrow
+ /// the \nesttableprops is a destination and must follow the
+ /// nested cells, so it should be sufficient to store the
+ /// currently active one, no need for a stack of them
+ int m_nNestedCells;
+ std::deque<RTFSprms> m_aNestedTableCellsSprms;
+ std::deque<RTFSprms> m_aNestedTableCellsAttributes;
+ /// cell props buffer for top-level table, reset by \row
+ int m_nTopLevelCells;
+ std::deque<RTFSprms> m_aTopLevelTableCellsSprms;
+ std::deque<RTFSprms> m_aTopLevelTableCellsAttributes;
+ /// backup of top-level props, to support inheriting cell props
+ int m_nInheritingCells;
+ std::deque<RTFSprms> m_aTableInheritingCellsSprms;
+ std::deque<RTFSprms> m_aTableInheritingCellsAttributes;
+
+ // Left row margin (for nested and top-level rows)
+ int m_nNestedTRLeft;
+ int m_nTopLevelTRLeft;
+
+ /// Current cellx value (nested table)
+ int m_nNestedCurrentCellX;
+ /// Current cellx value (top-level table)
+ int m_nTopLevelCurrentCellX;
+
+ // Backup of what \trowd clears, to work around invalid input.
+ RTFSprms m_aBackupTableRowSprms;
+ RTFSprms m_aBackupTableRowAttributes;
+ int m_nBackupTopLevelCurrentCellX;
+
+ /// Buffered table cells, till cell definitions are not reached.
+ /// for nested table, one buffer per table level
+ std::deque<RTFBuffer_t> m_aTableBufferStack;
+ /// Buffered superscript, till footnote is reached (or not).
+ RTFBuffer_t m_aSuperBuffer;
+
+ /// Superstream of this substream.
+ RTFDocumentImpl* m_pSuperstream;
+ /// Type of the stream: header, footer, footnote, etc.
+ Id m_nStreamType;
+ std::queue<std::pair<Id, std::size_t>> m_nHeaderFooterPositions;
+ std::size_t m_nGroupStartPos;
+ /// Ignore the first occurrence of this text.
+ OUString m_aIgnoreFirst;
+ /// Bookmark name <-> index map.
+ std::map<OUString, int> m_aBookmarks;
+ /// Revision index <-> author map.
+ std::map<int, OUString> m_aAuthors;
+ /// Annotation author of the next annotation.
+ OUString m_aAuthor;
+ /// Initials of author of the next annotation.
+ OUString m_aAuthorInitials;
+
+ RTFSprms m_aFormfieldSprms;
+ RTFSprms m_aFormfieldAttributes;
+ RTFFormFieldType m_nFormFieldType;
+
+ /// OLE attributes are attributes of the ooxml:OLEObject_OLEObject sprm.
+ RTFSprms m_aOLEAttributes;
+ RTFSprms m_aObjectAttributes;
+ /** If we are in an object group and if the we use its
+ * \objdata element.
+ * (if we don't use the \objdata we use the \result element)*/
+ bool m_bObject;
+ /// If the data for a picture is a binary one, it's stored here.
+ std::shared_ptr<SvStream> m_pBinaryData;
+
+ RTFReferenceTable::Entries_t m_aFontTableEntries;
+ int m_nCurrentFontIndex;
+ /// Used only during font table parsing till we don't know the font name.
+ int m_nCurrentEncoding;
+ /// Raw default font index, use getFont() on it to get a real one.
+ int m_nDefaultFontIndex;
+
+ /// To avoid copying entries between DomainMapper instances it is stored as pointer
+ std::shared_ptr<RTFReferenceTable::Entries_t> m_pStyleTableEntries;
+ int m_nCurrentStyleIndex;
+ bool m_bFormField;
+ /// For the INCLUDEPICTURE field's argument.
+ OUString m_aPicturePath;
+ // Unicode characters are collected here so we don't have to send them one by one.
+ OUStringBuffer m_aUnicodeBuffer{ 512 };
+ /// Same for hex characters.
+ OStringBuffer m_aHexBuffer{ 512 };
+ /// Formula import.
+ oox::formulaimport::XmlStreamBuilder m_aMathBuffer;
+ /// Normal text property, that is math italic and math spacing are not applied to the current run.
+ bool m_bMathNor;
+ /// If the next continuous section break should be ignored.
+ bool m_bIgnoreNextContSectBreak;
+ /// clean up a synthetic page break, see RTF_PAGE
+ /// if inactive value is -1, otherwise the RTF_SKB* to restore
+ RTFKeyword m_nResetBreakOnSectBreak;
+ /// If a section break is needed before the end of the doc (false right after a section break).
+ bool m_bNeedSect;
+ /// If aFrame.inFrame() was true in the previous state.
+ bool m_bWasInFrame;
+ /// A picture was seen in the current paragraph.
+ bool m_bHadPicture;
+ /// The document has multiple sections.
+ bool m_bHadSect;
+ /// Max width of the rows in the current table.
+ int m_nCellxMax;
+ /// ID of the next \listlevel picture.
+ int m_nListPictureId;
+
+ /// New document means not pasting into an existing one.
+ bool m_bIsNewDoc;
+ /// The media descriptor contains e.g. the base URL of the document.
+ const utl::MediaDescriptor& m_rMediaDescriptor;
+
+ /// Flags for ensuring that only one header and footer is added per section
+ bool m_hasRHeader;
+ bool m_hasFHeader;
+ bool m_hasRFooter;
+ bool m_hasFFooter;
+
+ /// Are we after a \cell, but before a \row?
+ bool m_bAfterCellBeforeRow;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtffly.hxx b/writerfilter/source/rtftok/rtffly.hxx
new file mode 100644
index 000000000..b1dec0c77
--- /dev/null
+++ b/writerfilter/source/rtftok/rtffly.hxx
@@ -0,0 +1,138 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+
+#include <ooxml/resourceids.hxx>
+#include <osl/endian.h>
+
+namespace writerfilter::rtftok
+{
+/// Stores the vertical orientation properties of an RTF fly frame.
+class RTFVertOrient
+{
+public:
+ explicit RTFVertOrient(sal_uInt16 nValue)
+ : m_nVal(nValue)
+ {
+ }
+
+ sal_uInt16 GetOrient() const { return OSL_LONIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_uInt16 GetRelation() const { return OSL_HINIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_Int32 GetAlign() const
+ {
+ sal_Int32 nAlign = 0;
+ switch (GetOrient())
+ {
+ case css::text::VertOrientation::CENTER:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_center;
+ break;
+ case css::text::VertOrientation::TOP:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_top;
+ break;
+ case css::text::VertOrientation::BOTTOM:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_bottom;
+ break;
+ }
+
+ return nAlign;
+ }
+
+ sal_Int32 GetAnchor() const
+ {
+ sal_Int32 nAnchor = 0;
+ switch (GetRelation())
+ {
+ case css::text::RelOrientation::FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_text;
+ break;
+ case css::text::RelOrientation::PAGE_FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_page;
+ break;
+ case css::text::RelOrientation::PAGE_PRINT_AREA:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
+ break;
+ }
+
+ return nAnchor;
+ }
+
+private:
+ sal_uInt16 m_nVal;
+};
+
+/// Stores the horizontal orientation properties of an RTF fly frame.
+class RTFHoriOrient
+{
+public:
+ explicit RTFHoriOrient(sal_uInt16 nValue)
+ : m_nVal(nValue)
+ {
+ }
+
+ sal_uInt16 GetOrient() const { return OSL_LONIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_uInt16 GetRelation() const { return OSL_LONIBBLE(OSL_HIBYTE(m_nVal)); }
+
+ sal_Int32 GetAlign() const
+ {
+ sal_Int32 nAlign = 0;
+ switch (GetOrient())
+ {
+ case css::text::HoriOrientation::CENTER:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_center;
+ break;
+ case css::text::HoriOrientation::RIGHT:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_right;
+ break;
+ case css::text::HoriOrientation::LEFT:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_left;
+ break;
+ case css::text::HoriOrientation::INSIDE:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_inside;
+ break;
+ case css::text::HoriOrientation::OUTSIDE:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_outside;
+ break;
+ }
+
+ return nAlign;
+ }
+
+ sal_Int32 GetAnchor() const
+ {
+ sal_Int32 nAnchor = 0;
+ switch (GetRelation())
+ {
+ case css::text::RelOrientation::FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_text;
+ break;
+ case css::text::RelOrientation::PAGE_FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_page;
+ break;
+ case css::text::RelOrientation::PAGE_PRINT_AREA:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin;
+ break;
+ }
+
+ return nAnchor;
+ }
+
+private:
+ sal_uInt16 m_nVal;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtflistener.hxx b/writerfilter/source/rtftok/rtflistener.hxx
new file mode 100644
index 000000000..150440afb
--- /dev/null
+++ b/writerfilter/source/rtftok/rtflistener.hxx
@@ -0,0 +1,69 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include "rtfcontrolwords.hxx"
+
+namespace writerfilter::rtftok
+{
+enum class RTFInternalState
+{
+ NORMAL,
+ BIN,
+ HEX
+};
+
+enum class RTFError
+{
+ OK,
+ GROUP_UNDER,
+ GROUP_OVER,
+ UNEXPECTED_EOF,
+ HEX_INVALID,
+ CHAR_OVER,
+ CLASSIFICATION
+};
+
+/**
+ * RTFTokenizer needs a class implementing this interface. While
+ * RTFTokenizer separates control words (and their arguments) from
+ * text, the class implementing this interface is expected to map the
+ * raw RTF tokens to dmapper tokens.
+ */
+class RTFListener
+{
+public:
+ virtual ~RTFListener() = default;
+ // Dispatching of control words and characters.
+ virtual RTFError dispatchDestination(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchFlag(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchSymbol(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) = 0;
+ virtual RTFError dispatchValue(RTFKeyword nKeyword, int nParam) = 0;
+ virtual RTFError resolveChars(char ch) = 0;
+
+ // State handling.
+ virtual RTFError pushState() = 0;
+ virtual RTFError popState() = 0;
+
+ virtual Destination getDestination() = 0;
+ virtual void setDestination(Destination eDestination) = 0;
+ virtual RTFInternalState getInternalState() = 0;
+ virtual void setInternalState(RTFInternalState nInternalState) = 0;
+ virtual bool getSkipUnknown() = 0;
+ virtual void setSkipUnknown(bool bSkipUnknown) = 0;
+
+ // Substream handling.
+ virtual void finishSubstream() = 0;
+ virtual bool isSubstream() const = 0;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtflookahead.cxx b/writerfilter/source/rtftok/rtflookahead.cxx
new file mode 100644
index 000000000..033feacce
--- /dev/null
+++ b/writerfilter/source/rtftok/rtflookahead.cxx
@@ -0,0 +1,101 @@
+/* -*- 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 "rtflookahead.hxx"
+#include <com/sun/star/uno/Reference.hxx>
+#include <tools/stream.hxx>
+#include "rtftokenizer.hxx"
+
+namespace com::sun::star::task
+{
+class XStatusIndicator;
+}
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFLookahead::RTFLookahead(SvStream& rStream, sal_uInt64 nGroupStart)
+ : m_rStream(rStream)
+ , m_bHasTable(false)
+ , m_bHasColumns(false)
+{
+ sal_uInt64 const nPos = m_rStream.Tell();
+ m_rStream.Seek(nGroupStart);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+ m_pTokenizer = new RTFTokenizer(*this, &m_rStream, xStatusIndicator);
+ m_pTokenizer->resolveParse();
+ m_rStream.Seek(nPos);
+}
+
+RTFLookahead::~RTFLookahead() = default;
+
+RTFError RTFLookahead::dispatchDestination(RTFKeyword /*nKeyword*/) { return RTFError::OK; }
+
+RTFError RTFLookahead::dispatchFlag(RTFKeyword nKeyword)
+{
+ if (nKeyword == RTFKeyword::INTBL)
+ m_bHasTable = true;
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::dispatchSymbol(RTFKeyword /*nKeyword*/) { return RTFError::OK; }
+
+RTFError RTFLookahead::dispatchToggle(RTFKeyword /*nKeyword*/, bool /*bParam*/, int /*nParam*/)
+{
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::dispatchValue(RTFKeyword nKeyword, int nParam)
+{
+ if (nKeyword == RTFKeyword::COLS && nParam >= 2)
+ m_bHasColumns = true;
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::resolveChars(char ch)
+{
+ while (!m_rStream.eof() && (ch != '{' && ch != '}' && ch != '\\'))
+ m_rStream.ReadChar(ch);
+ if (!m_rStream.eof())
+ m_rStream.SeekRel(-1);
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::pushState()
+{
+ m_pTokenizer->pushGroup();
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::popState()
+{
+ m_pTokenizer->popGroup();
+ return RTFError::OK;
+}
+
+Destination RTFLookahead::getDestination() { return Destination::NORMAL; }
+
+void RTFLookahead::setDestination(Destination /*eDestination*/) {}
+
+RTFInternalState RTFLookahead::getInternalState() { return RTFInternalState::NORMAL; }
+
+void RTFLookahead::setInternalState(RTFInternalState /*nInternalState*/) {}
+
+bool RTFLookahead::getSkipUnknown() { return false; }
+
+void RTFLookahead::setSkipUnknown(bool /*bSkipUnknown*/) {}
+
+void RTFLookahead::finishSubstream() {}
+
+bool RTFLookahead::isSubstream() const { return false; }
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtflookahead.hxx b/writerfilter/source/rtftok/rtflookahead.hxx
new file mode 100644
index 000000000..9ec213f62
--- /dev/null
+++ b/writerfilter/source/rtftok/rtflookahead.hxx
@@ -0,0 +1,57 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <tools/ref.hxx>
+#include "rtflistener.hxx"
+
+class SvStream;
+
+namespace writerfilter::rtftok
+{
+class RTFTokenizer;
+/**
+ * This acts like an importer, but used for looking ahead, e.g. to
+ * determine if the current group contains a table, etc.
+ */
+class RTFLookahead : public RTFListener
+{
+public:
+ RTFLookahead(SvStream& rStream, sal_uInt64 nGroupStart);
+ ~RTFLookahead() override;
+ RTFError dispatchDestination(RTFKeyword nKeyword) override;
+ RTFError dispatchFlag(RTFKeyword nKeyword) override;
+ RTFError dispatchSymbol(RTFKeyword nKeyword) override;
+ RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) override;
+ RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
+ RTFError resolveChars(char ch) override;
+ RTFError pushState() override;
+ RTFError popState() override;
+ Destination getDestination() override;
+ void setDestination(Destination eDestination) override;
+ RTFInternalState getInternalState() override;
+ void setInternalState(RTFInternalState nInternalState) override;
+ bool getSkipUnknown() override;
+ void setSkipUnknown(bool bSkipUnknown) override;
+ void finishSubstream() override;
+ bool isSubstream() const override;
+ bool hasTable() const { return m_bHasTable; }
+ bool hasColumns() const { return m_bHasColumns; }
+
+private:
+ tools::SvRef<RTFTokenizer> m_pTokenizer;
+ SvStream& m_rStream;
+ bool m_bHasTable;
+ bool m_bHasColumns;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferenceproperties.cxx b/writerfilter/source/rtftok/rtfreferenceproperties.cxx
new file mode 100644
index 000000000..d32557bc7
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferenceproperties.cxx
@@ -0,0 +1,40 @@
+/* -*- 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 "rtfreferenceproperties.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFReferenceProperties::RTFReferenceProperties(RTFSprms aAttributes, RTFSprms aSprms)
+ : m_aAttributes(std::move(aAttributes))
+ , m_aSprms(std::move(aSprms))
+{
+}
+
+RTFReferenceProperties::RTFReferenceProperties(RTFSprms aAttributes)
+ : m_aAttributes(std::move(aAttributes))
+{
+}
+
+RTFReferenceProperties::~RTFReferenceProperties() = default;
+
+void RTFReferenceProperties::resolve(Properties& rHandler)
+{
+ for (auto& rAttribute : m_aAttributes)
+ rHandler.attribute(rAttribute.first, *rAttribute.second);
+ for (auto& rSprm : m_aSprms)
+ {
+ RTFSprm aSprm(rSprm.first, rSprm.second);
+ rHandler.sprm(aSprm);
+ }
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferenceproperties.hxx b/writerfilter/source/rtftok/rtfreferenceproperties.hxx
new file mode 100644
index 000000000..6a5e5618b
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferenceproperties.hxx
@@ -0,0 +1,33 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include "rtfsprm.hxx"
+
+namespace writerfilter::rtftok
+{
+/// Sends RTFSprm instances to DomainMapper.
+class RTFReferenceProperties : public writerfilter::Reference<Properties>
+{
+public:
+ RTFReferenceProperties(RTFSprms aAttributes, RTFSprms aSprms);
+ explicit RTFReferenceProperties(RTFSprms aAttributes);
+ ~RTFReferenceProperties() override;
+ void resolve(Properties& rHandler) override;
+ RTFSprms& getAttributes() { return m_aAttributes; }
+ RTFSprms& getSprms() { return m_aSprms; }
+
+private:
+ RTFSprms m_aAttributes;
+ RTFSprms m_aSprms;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferencetable.cxx b/writerfilter/source/rtftok/rtfreferencetable.cxx
new file mode 100644
index 000000000..1a70a93d9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferencetable.cxx
@@ -0,0 +1,29 @@
+/* -*- 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 "rtfreferencetable.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFReferenceTable::RTFReferenceTable(Entries_t aEntries)
+ : m_aEntries(std::move(aEntries))
+{
+}
+
+RTFReferenceTable::~RTFReferenceTable() = default;
+
+void RTFReferenceTable::resolve(Table& rHandler)
+{
+ for (const auto& rEntry : m_aEntries)
+ rHandler.entry(rEntry.first, rEntry.second);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfreferencetable.hxx b/writerfilter/source/rtftok/rtfreferencetable.hxx
new file mode 100644
index 000000000..76cbaacf2
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfreferencetable.hxx
@@ -0,0 +1,32 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <map>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::rtftok
+{
+/// Sends tables (e.g. font table) to the domain mapper.
+class RTFReferenceTable : public writerfilter::Reference<Table>
+{
+public:
+ using Entries_t = std::map<int, writerfilter::Reference<Properties>::Pointer_t>;
+ using Entry_t = std::pair<int, writerfilter::Reference<Properties>::Pointer_t>;
+ explicit RTFReferenceTable(Entries_t aEntries);
+ ~RTFReferenceTable() override;
+ void resolve(Table& rHandler) override;
+
+private:
+ Entries_t m_aEntries;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsdrimport.cxx b/writerfilter/source/rtftok/rtfsdrimport.cxx
new file mode 100644
index 000000000..e928377f9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsdrimport.cxx
@@ -0,0 +1,1182 @@
+/* -*- 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 "rtfsdrimport.hxx"
+#include <cmath>
+#include <optional>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <ooxml/resourceids.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/rtfutil.hxx>
+#include <sal/log.hxx>
+#include <svx/svdtrans.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertysequence.hxx>
+#include "rtfreferenceproperties.hxx"
+#include <oox/vml/vmlformatting.hxx>
+#include <oox/helper/modelobjecthelper.hxx>
+#include <oox/drawingml/shapepropertymap.hxx>
+#include <oox/helper/propertyset.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/UnitConversion.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include "rtfdocumentimpl.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument,
+ uno::Reference<lang::XComponent> const& xDstDoc)
+ : m_rImport(rDocument)
+ , m_bTextFrame(false)
+ , m_bTextGraphicObject(false)
+ , m_bFakePict(false)
+{
+ uno::Reference<drawing::XDrawPageSupplier> xDrawings(xDstDoc, uno::UNO_QUERY);
+ if (xDrawings.is())
+ m_aParents.push(xDrawings->getDrawPage());
+ m_aGraphicZOrderHelpers.push(writerfilter::dmapper::GraphicZOrderHelper());
+}
+
+RTFSdrImport::~RTFSdrImport()
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ m_aGraphicZOrderHelpers.pop();
+ if (!m_aParents.empty())
+ m_aParents.pop();
+}
+
+void RTFSdrImport::createShape(const OUString& rService, uno::Reference<drawing::XShape>& xShape,
+ uno::Reference<beans::XPropertySet>& xPropertySet)
+{
+ if (m_rImport.getModelFactory().is())
+ xShape.set(m_rImport.getModelFactory()->createInstance(rService), uno::UNO_QUERY);
+ xPropertySet.set(xShape, uno::UNO_QUERY);
+}
+
+std::vector<beans::PropertyValue> RTFSdrImport::getTextFrameDefaults(bool bNew)
+{
+ std::vector<beans::PropertyValue> aRet;
+ beans::PropertyValue aPropertyValue;
+
+ aPropertyValue.Name = "HoriOrient";
+ aPropertyValue.Value <<= text::HoriOrientation::NONE;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "HoriOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "VertOrient";
+ aPropertyValue.Value <<= text::VertOrientation::NONE;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "VertOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ aRet.push_back(aPropertyValue);
+ if (!bNew)
+ {
+ aPropertyValue.Name = "BackColorTransparency";
+ aPropertyValue.Value <<= sal_Int32(100);
+ aRet.push_back(aPropertyValue);
+ }
+ // See the spec, new-style frame default margins are specified in EMUs.
+ aPropertyValue.Name = "LeftBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "RightBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "TopBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "BottomBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "SizeType";
+ aPropertyValue.Value <<= text::SizeType::FIX;
+ aRet.push_back(aPropertyValue);
+ return aRet;
+}
+
+void RTFSdrImport::pushParent(uno::Reference<drawing::XShapes> const& xParent)
+{
+ m_aParents.push(xParent);
+ m_aGraphicZOrderHelpers.push(writerfilter::dmapper::GraphicZOrderHelper());
+}
+
+void RTFSdrImport::popParent()
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ m_aGraphicZOrderHelpers.pop();
+ if (!m_aParents.empty())
+ m_aParents.pop();
+}
+
+void RTFSdrImport::resolveDhgt(uno::Reference<beans::XPropertySet> const& xPropertySet,
+ sal_Int32 const nZOrder, bool const bOldStyle)
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ {
+ writerfilter::dmapper::GraphicZOrderHelper& rHelper = m_aGraphicZOrderHelpers.top();
+ xPropertySet->setPropertyValue("ZOrder", uno::Any(rHelper.findZOrder(nZOrder, bOldStyle)));
+ rHelper.addItem(xPropertySet, nZOrder);
+ }
+}
+
+void RTFSdrImport::resolveLineColorAndWidth(bool bTextFrame,
+ const uno::Reference<beans::XPropertySet>& xPropertySet,
+ uno::Any const& rLineColor, uno::Any const& rLineWidth)
+{
+ if (!bTextFrame)
+ {
+ xPropertySet->setPropertyValue("LineColor", rLineColor);
+ xPropertySet->setPropertyValue("LineWidth", rLineWidth);
+ }
+ else
+ {
+ static const char* aBorders[]
+ = { "TopBorder", "LeftBorder", "BottomBorder", "RightBorder" };
+ for (const char* pBorder : aBorders)
+ {
+ auto aBorderLine = xPropertySet->getPropertyValue(OUString::createFromAscii(pBorder))
+ .get<table::BorderLine2>();
+ if (rLineColor.hasValue())
+ aBorderLine.Color = rLineColor.get<sal_Int32>();
+ if (rLineWidth.hasValue())
+ aBorderLine.LineWidth = rLineWidth.get<sal_Int32>();
+ xPropertySet->setPropertyValue(OUString::createFromAscii(pBorder),
+ uno::Any(aBorderLine));
+ }
+ }
+}
+
+void RTFSdrImport::resolveFLine(uno::Reference<beans::XPropertySet> const& xPropertySet,
+ sal_Int32 const nFLine)
+{
+ if (nFLine == 0)
+ xPropertySet->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE));
+ else
+ xPropertySet->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_SOLID));
+}
+
+void RTFSdrImport::applyProperty(uno::Reference<drawing::XShape> const& xShape,
+ std::u16string_view aKey, std::u16string_view aValue) const
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ sal_Int16 nHoriOrient = 0;
+ sal_Int16 nVertOrient = 0;
+ std::optional<bool> obFitShapeToText;
+ bool bFilled = true;
+
+ if (aKey == u"posh")
+ {
+ switch (o3tl::toInt32(aValue))
+ {
+ case 1:
+ nHoriOrient = text::HoriOrientation::LEFT;
+ break;
+ case 2:
+ nHoriOrient = text::HoriOrientation::CENTER;
+ break;
+ case 3:
+ nHoriOrient = text::HoriOrientation::RIGHT;
+ break;
+ case 4:
+ nHoriOrient = text::HoriOrientation::INSIDE;
+ break;
+ case 5:
+ nHoriOrient = text::HoriOrientation::OUTSIDE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (aKey == u"posv")
+ {
+ switch (o3tl::toInt32(aValue))
+ {
+ case 1:
+ nVertOrient = text::VertOrientation::TOP;
+ break;
+ case 2:
+ nVertOrient = text::VertOrientation::CENTER;
+ break;
+ case 3:
+ nVertOrient = text::VertOrientation::BOTTOM;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (aKey == u"fFitShapeToText")
+ obFitShapeToText = o3tl::toInt32(aValue) == 1;
+ else if (aKey == u"fFilled")
+ bFilled = o3tl::toInt32(aValue) == 1;
+ else if (aKey == u"rotation")
+ {
+ // See DffPropertyReader::Fix16ToAngle(): in RTF, positive rotation angles are clockwise, we have them as counter-clockwise.
+ // Additionally, RTF type is 0..360*2^16, our is 0..360*100.
+ sal_Int32 nRotation = o3tl::toInt32(aValue) * 100 / RTF_MULTIPLIER;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
+ if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ xPropertySet->setPropertyValue(
+ "RotateAngle", uno::Any(NormAngle36000(Degree100(nRotation * -1)).get()));
+ }
+
+ if (nHoriOrient != 0 && xPropertySet.is())
+ xPropertySet->setPropertyValue("HoriOrient", uno::Any(nHoriOrient));
+ if (nVertOrient != 0 && xPropertySet.is())
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(nVertOrient));
+ if (obFitShapeToText.has_value() && xPropertySet.is())
+ {
+ xPropertySet->setPropertyValue(
+ "SizeType", uno::Any(*obFitShapeToText ? text::SizeType::MIN : text::SizeType::FIX));
+ xPropertySet->setPropertyValue("FrameIsAutomaticHeight", uno::Any(*obFitShapeToText));
+ }
+ if (!bFilled && xPropertySet.is())
+ {
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("BackColorTransparency", uno::Any(sal_Int32(100)));
+ else
+ xPropertySet->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE));
+ }
+}
+
+int RTFSdrImport::initShape(uno::Reference<drawing::XShape>& o_xShape,
+ uno::Reference<beans::XPropertySet>& o_xPropSet, bool& o_rIsCustomShape,
+ RTFShape const& rShape, bool const bClose,
+ ShapeOrPict const shapeOrPict)
+{
+ assert(!o_xShape.is());
+ assert(!o_xPropSet.is());
+ o_rIsCustomShape = false;
+ m_bFakePict = false;
+
+ // first, find the shape type
+ int nType = -1;
+ auto iter = std::find_if(rShape.getProperties().begin(), rShape.getProperties().end(),
+ [](const std::pair<OUString, OUString>& rProperty) {
+ return rProperty.first == "shapeType";
+ });
+
+ if (iter == rShape.getProperties().end())
+ {
+ if (SHAPE == shapeOrPict)
+ {
+ // The spec doesn't state what is the default for shapeType,
+ // Word seems to implement it as a rectangle.
+ nType = ESCHER_ShpInst_Rectangle;
+ }
+ else
+ {
+ // pict is picture by default but can be a rectangle too fdo#79319
+ nType = ESCHER_ShpInst_PictureFrame;
+ }
+ }
+ else
+ {
+ nType = iter->second.toInt32();
+ if (PICT == shapeOrPict && ESCHER_ShpInst_PictureFrame != nType)
+ {
+ m_bFakePict = true;
+ }
+ }
+
+ switch (nType)
+ {
+ case ESCHER_ShpInst_PictureFrame:
+ createShape("com.sun.star.drawing.GraphicObjectShape", o_xShape, o_xPropSet);
+ m_bTextGraphicObject = true;
+ break;
+ case ESCHER_ShpInst_Line:
+ createShape("com.sun.star.drawing.LineShape", o_xShape, o_xPropSet);
+ break;
+ case ESCHER_ShpInst_Rectangle:
+ case ESCHER_ShpInst_TextBox:
+ // If we're inside a groupshape, can't use text frames.
+ if (!bClose && m_aParents.size() == 1)
+ {
+ createShape("com.sun.star.text.TextFrame", o_xShape, o_xPropSet);
+ m_bTextFrame = true;
+ std::vector<beans::PropertyValue> aDefaults = getTextFrameDefaults(true);
+ for (const beans::PropertyValue& i : aDefaults)
+ o_xPropSet->setPropertyValue(i.Name, i.Value);
+ break;
+ }
+ [[fallthrough]];
+ default:
+ createShape("com.sun.star.drawing.CustomShape", o_xShape, o_xPropSet);
+ o_rIsCustomShape = true;
+ break;
+ }
+
+ // Defaults
+ if (o_xPropSet.is() && !m_bTextFrame)
+ {
+ o_xPropSet->setPropertyValue(
+ "FillColor",
+ uno::Any(sal_uInt32(0xffffff))); // White in Word, kind of blue in Writer.
+ o_xPropSet->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
+ }
+
+ return nType;
+}
+
+void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, ShapeOrPict const shapeOrPict)
+{
+ bool bPib = false;
+ m_bTextFrame = false;
+ m_bTextGraphicObject = false;
+
+ uno::Reference<drawing::XShape> xShape;
+ uno::Reference<beans::XPropertySet> xPropertySet;
+ uno::Any aAny;
+ beans::PropertyValue aPropertyValue;
+ awt::Rectangle aViewBox;
+ std::vector<beans::PropertyValue> aPath;
+ // Default line color is black in Word, blue in Writer.
+ uno::Any aLineColor(COL_BLACK);
+ // Default line width is 0.75 pt (26 mm100) in Word, 0 in Writer.
+ uno::Any aLineWidth(sal_Int32(26));
+ sal_Int16 eWritingMode = text::WritingMode2::LR_TB;
+ // Groupshape support
+ std::optional<sal_Int32> oGroupLeft;
+ std::optional<sal_Int32> oGroupTop;
+ std::optional<sal_Int32> oGroupRight;
+ std::optional<sal_Int32> oGroupBottom;
+ std::optional<sal_Int32> oRelLeft;
+ std::optional<sal_Int32> oRelTop;
+ std::optional<sal_Int32> oRelRight;
+ std::optional<sal_Int32> oRelBottom;
+
+ // Importing these are not trivial, let the VML import do the hard work.
+ oox::vml::FillModel aFillModel; // Gradient.
+ oox::vml::ShadowModel aShadowModel; // Shadow.
+
+ bool bOpaque = true;
+
+ std::optional<sal_Int16> oRelativeWidth;
+ std::optional<sal_Int16> oRelativeHeight;
+ sal_Int16 nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ sal_Int16 nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ std::optional<bool> obRelFlipV;
+ bool obFlipH(false);
+ bool obFlipV(false);
+
+ OUString aShapeText = "";
+ OUString aFontFamily = "";
+ float nFontSize = 1.0;
+
+ sal_Int32 nContrast = 0x10000;
+ sal_Int16 nBrightness = 0;
+
+ bool bCustom(false);
+ int const nType = initShape(xShape, xPropertySet, bCustom, rShape, bClose, shapeOrPict);
+
+ for (auto& rProperty : rShape.getProperties())
+ {
+ if (rProperty.first == "shapeType")
+ {
+ continue; // ignore: already handled by initShape
+ }
+ if (rProperty.first == "wzName")
+ {
+ if (m_bTextFrame)
+ {
+ uno::Reference<container::XNamed> xNamed(xShape, uno::UNO_QUERY);
+ xNamed->setName(rProperty.second);
+ }
+ else
+ xPropertySet->setPropertyValue("Name", uno::Any(rProperty.second));
+ }
+ else if (rProperty.first == "wzDescription")
+ xPropertySet->setPropertyValue("Description", uno::Any(rProperty.second));
+ else if (rProperty.first == "gtextUNICODE")
+ aShapeText = rProperty.second;
+ else if (rProperty.first == "gtextFont")
+ aFontFamily = rProperty.second;
+ else if (rProperty.first == "gtextSize")
+ {
+ // RTF size is multiplied by 2^16
+ nFontSize = static_cast<float>(rProperty.second.toUInt32()) / RTF_MULTIPLIER;
+ }
+ else if (rProperty.first == "pib")
+ {
+ m_rImport.setDestinationText(rProperty.second);
+ bPib = true;
+ }
+ else if (rProperty.first == "fillColor" && xPropertySet.is())
+ {
+ aAny <<= msfilter::util::BGRToRGB(rProperty.second.toUInt32());
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("BackColor", aAny);
+ else
+ xPropertySet->setPropertyValue("FillColor", aAny);
+
+ // fillType will decide, possible it'll be the start color of a gradient.
+ aFillModel.moColor.set(
+ "#"
+ + msfilter::util::ConvertColorOU(Color(ColorTransparency, aAny.get<sal_Int32>())));
+ }
+ else if (rProperty.first == "fillBackColor")
+ // fillType will decide, possible it'll be the end color of a gradient.
+ aFillModel.moColor2.set("#"
+ + msfilter::util::ConvertColorOU(
+ msfilter::util::BGRToRGB(rProperty.second.toInt32())));
+ else if (rProperty.first == "lineColor")
+ aLineColor <<= msfilter::util::BGRToRGB(rProperty.second.toInt32());
+ else if (rProperty.first == "lineBackColor")
+ ; // Ignore: complementer of lineColor
+ else if (rProperty.first == "txflTextFlow" && xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1: // Top to bottom ASCII font
+ case 3: // Top to bottom non-ASCII font
+ eWritingMode = text::WritingMode2::TB_RL;
+ break;
+ case 2: // Bottom to top non-ASCII font
+ eWritingMode = text::WritingMode2::BT_LR;
+ break;
+ }
+ }
+ else if (rProperty.first == "fLine" && xPropertySet.is())
+ resolveFLine(xPropertySet, rProperty.second.toInt32());
+ else if (rProperty.first == "fillOpacity" && xPropertySet.is())
+ {
+ int opacity = 100 - (rProperty.second.toInt32()) * 100 / RTF_MULTIPLIER;
+ xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_uInt32(opacity)));
+ }
+ else if (rProperty.first == "lineWidth")
+ aLineWidth <<= rProperty.second.toInt32() / 360;
+ else if (rProperty.first == "pVerticies")
+ {
+ std::vector<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
+ sal_Int32 nSize = 0; // Size of a token (its value is hardwired in the exporter)
+ sal_Int32 nCount = 0; // Number of tokens
+ sal_Int32 nCharIndex = 0; // Character index
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(rProperty.second, 0, ';', nCharIndex);
+ if (!nSize)
+ nSize = o3tl::toInt32(aToken);
+ else if (!nCount)
+ nCount = o3tl::toInt32(aToken);
+ else if (!aToken.empty())
+ {
+ // The coordinates are in an (x,y) form.
+ aToken = aToken.substr(1, aToken.size() - 2);
+ sal_Int32 nI = 0;
+ sal_Int32 nX = o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI));
+ sal_Int32 nY
+ = (nI >= 0) ? o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI)) : 0;
+ drawing::EnhancedCustomShapeParameterPair aPair;
+ aPair.First.Value <<= nX;
+ aPair.Second.Value <<= nY;
+ aCoordinates.push_back(aPair);
+ }
+ } while (nCharIndex >= 0);
+ aPropertyValue.Name = "Coordinates";
+ aPropertyValue.Value <<= comphelper::containerToSequence(aCoordinates);
+ aPath.push_back(aPropertyValue);
+ }
+ else if (rProperty.first == "pSegmentInfo")
+ {
+ std::vector<drawing::EnhancedCustomShapeSegment> aSegments;
+ sal_Int32 nSize = 0;
+ sal_Int32 nCount = 0;
+ sal_Int32 nCharIndex = 0;
+ do
+ {
+ sal_Int32 nSeg
+ = o3tl::toInt32(o3tl::getToken(rProperty.second, 0, ';', nCharIndex));
+ if (!nSize)
+ nSize = nSeg;
+ else if (!nCount)
+ nCount = nSeg;
+ else
+ {
+ sal_Int32 nPoints = 1;
+ if (nSeg >= 0x2000 && nSeg < 0x20FF)
+ {
+ nPoints = nSeg & 0x0FFF;
+ nSeg &= 0xFF00;
+ }
+
+ drawing::EnhancedCustomShapeSegment aSegment;
+ switch (nSeg)
+ {
+ case 0x0001: // lineto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
+ aSegment.Count = sal_Int32(1);
+ aSegments.push_back(aSegment);
+ break;
+ case 0x4000: // moveto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
+ aSegment.Count = sal_Int32(1);
+ aSegments.push_back(aSegment);
+ break;
+ case 0x2000: // curveto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
+ aSegment.Count = nPoints;
+ aSegments.push_back(aSegment);
+ break;
+ case 0xb300: // arcto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
+ aSegment.Count = sal_Int32(0);
+ aSegments.push_back(aSegment);
+ break;
+ case 0xac00:
+ case 0xaa00: // nofill
+ case 0xab00: // nostroke
+ case 0x6001: // close
+ break;
+ case 0x8000: // end
+ aSegment.Command
+ = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
+ aSegment.Count = sal_Int32(0);
+ aSegments.push_back(aSegment);
+ break;
+ default: // given number of lineto elements
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
+ aSegment.Count = nSeg;
+ aSegments.push_back(aSegment);
+ break;
+ }
+ }
+ } while (nCharIndex >= 0);
+ aPropertyValue.Name = "Segments";
+ aPropertyValue.Value <<= comphelper::containerToSequence(aSegments);
+ aPath.push_back(aPropertyValue);
+ }
+ else if (rProperty.first == "geoLeft")
+ aViewBox.X = rProperty.second.toInt32();
+ else if (rProperty.first == "geoTop")
+ aViewBox.Y = rProperty.second.toInt32();
+ else if (rProperty.first == "geoRight")
+ aViewBox.Width = rProperty.second.toInt32();
+ else if (rProperty.first == "geoBottom")
+ aViewBox.Height = rProperty.second.toInt32();
+ else if (rProperty.first == "dhgt")
+ {
+ // dhgt is Word 2007, \shpz is Word 97-2003, the later has priority.
+ if (!rShape.hasZ())
+ resolveDhgt(xPropertySet, rProperty.second.toInt32(), /*bOldStyle=*/false);
+ }
+ // These are in EMU, convert to mm100.
+ else if (rProperty.first == "dxTextLeft")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("LeftBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyTextTop")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("TopBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxTextRight")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("RightBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyTextBottom")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("BottomBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxWrapDistLeft")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distL,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("LeftMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyWrapDistTop")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distT,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("TopMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxWrapDistRight")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distR,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("RightMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyWrapDistBottom")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distB,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("BottomMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "fillType")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 7: // Shade using the fillAngle
+ aFillModel.moType.set(oox::XML_gradient);
+ break;
+ default:
+ SAL_INFO("writerfilter",
+ "TODO handle fillType value '" << rProperty.second << "'");
+ break;
+ }
+ }
+ else if (rProperty.first == "fillFocus")
+ aFillModel.moFocus.set(rProperty.second.toDouble() / 100); // percent
+ else if (rProperty.first == "fShadow" && xPropertySet.is())
+ {
+ if (rProperty.second.toInt32() == 1)
+ aShadowModel.mbHasShadow = true;
+ }
+ else if (rProperty.first == "shadowColor")
+ aShadowModel.moColor.set("#"
+ + msfilter::util::ConvertColorOU(
+ msfilter::util::BGRToRGB(rProperty.second.toInt32())));
+ else if (rProperty.first == "shadowOffsetX")
+ // EMUs to points
+ aShadowModel.moOffset.set(OUString::number(rProperty.second.toDouble() / 12700) + "pt");
+ else if (rProperty.first == "posh" || rProperty.first == "posv"
+ || rProperty.first == "fFitShapeToText" || rProperty.first == "fFilled"
+ || rProperty.first == "rotation")
+ applyProperty(xShape, rProperty.first, rProperty.second);
+ else if (rProperty.first == "posrelh")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1:
+ rShape.setHoriOrientRelation(text::RelOrientation::PAGE_FRAME);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rProperty.first == "posrelv")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1:
+ rShape.setVertOrientRelation(text::RelOrientation::PAGE_FRAME);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rProperty.first == "groupLeft")
+ oGroupLeft = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupTop")
+ oGroupTop = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupRight")
+ oGroupRight = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupBottom")
+ oGroupBottom = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relLeft")
+ oRelLeft = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relTop")
+ oRelTop = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relRight")
+ oRelRight = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relBottom")
+ oRelBottom = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "fBehindDocument")
+ bOpaque = !rProperty.second.toInt32();
+ else if (rProperty.first == "pctHoriz" || rProperty.first == "pctVert")
+ {
+ sal_Int16 nPercentage = rtl::math::round(rProperty.second.toDouble() / 10);
+ if (nPercentage)
+ {
+ std::optional<sal_Int16>& rPercentage
+ = rProperty.first == "pctHoriz" ? oRelativeWidth : oRelativeHeight;
+ rPercentage = nPercentage;
+ }
+ }
+ else if (rProperty.first == "sizerelh")
+ {
+ if (xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 0: // margin
+ nRelativeWidthRelation = text::RelOrientation::FRAME;
+ break;
+ case 1: // page
+ nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+ default:
+ SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelh value: "
+ << rProperty.second);
+ break;
+ }
+ }
+ }
+ else if (rProperty.first == "sizerelv")
+ {
+ if (xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 0: // margin
+ nRelativeHeightRelation = text::RelOrientation::FRAME;
+ break;
+ case 1: // page
+ nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+ default:
+ SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelv value: "
+ << rProperty.second);
+ break;
+ }
+ }
+ }
+ else if (rProperty.first == "fHorizRule") // TODO: what does "fStandardHR" do?
+ {
+ // horizontal rule: relative width defaults to 100% of paragraph
+ // TODO: does it have a default height?
+ if (!oRelativeWidth)
+ {
+ oRelativeWidth = 100;
+ }
+ nRelativeWidthRelation = text::RelOrientation::FRAME;
+ if (xPropertySet.is())
+ {
+ sal_Int16 const nVertOrient = text::VertOrientation::CENTER;
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(nVertOrient));
+ }
+ }
+ else if (rProperty.first == "pctHR")
+ {
+ // horizontal rule relative width in permille
+ oRelativeWidth = rProperty.second.toInt32() / 10;
+ }
+ else if (rProperty.first == "dxHeightHR")
+ {
+ // horizontal rule height
+ sal_uInt32 const nHeight(convertTwipToMm100(rProperty.second.toInt32()));
+ rShape.setBottom(rShape.getTop() + nHeight);
+ }
+ else if (rProperty.first == "dxWidthHR")
+ {
+ // horizontal rule width
+ sal_uInt32 const nWidth(convertTwipToMm100(rProperty.second.toInt32()));
+ rShape.setRight(rShape.getLeft() + nWidth);
+ }
+ else if (rProperty.first == "alignHR")
+ {
+ // horizontal orientation *for horizontal rule*
+ sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
+ switch (rProperty.second.toInt32())
+ {
+ case 0:
+ nHoriOrient = text::HoriOrientation::LEFT;
+ break;
+ case 1:
+ nHoriOrient = text::HoriOrientation::CENTER;
+ break;
+ case 2:
+ nHoriOrient = text::HoriOrientation::RIGHT;
+ break;
+ }
+ if (xPropertySet.is() && text::HoriOrientation::NONE != nHoriOrient)
+ {
+ xPropertySet->setPropertyValue("HoriOrient", uno::Any(nHoriOrient));
+ }
+ }
+ else if (rProperty.first == "pWrapPolygonVertices")
+ {
+ RTFSprms aPolygonSprms;
+ sal_Int32 nSize = 0; // Size of a token
+ sal_Int32 nCount = 0; // Number of tokens
+ sal_Int32 nCharIndex = 0; // Character index
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(rProperty.second, 0, ';', nCharIndex);
+ if (!nSize)
+ nSize = o3tl::toInt32(aToken);
+ else if (!nCount)
+ nCount = o3tl::toInt32(aToken);
+ else if (!aToken.empty())
+ {
+ // The coordinates are in an (x,y) form.
+ aToken = aToken.substr(1, aToken.size() - 2);
+ sal_Int32 nI = 0;
+ sal_Int32 nX = o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI));
+ sal_Int32 nY
+ = (nI >= 0) ? o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI)) : 0;
+ RTFSprms aPathAttributes;
+ aPathAttributes.set(NS_ooxml::LN_CT_Point2D_x, new RTFValue(nX));
+ aPathAttributes.set(NS_ooxml::LN_CT_Point2D_y, new RTFValue(nY));
+ aPolygonSprms.set(NS_ooxml::LN_CT_WrapPath_lineTo,
+ new RTFValue(aPathAttributes), RTFOverwrite::NO_APPEND);
+ }
+ } while (nCharIndex >= 0);
+ rShape.getWrapPolygonSprms() = aPolygonSprms;
+ }
+ else if (rProperty.first == "fRelFlipV")
+ obRelFlipV = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "fFlipH")
+ obFlipH = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "fFlipV")
+ obFlipV = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "pictureContrast")
+ {
+ // Gain / contrast.
+ nContrast = rProperty.second.toInt32();
+ if (nContrast < 0x10000)
+ {
+ nContrast *= 101; // 100 + 1 to round
+ nContrast /= 0x10000;
+ nContrast -= 100;
+ }
+ }
+ else if (rProperty.first == "pictureBrightness")
+ {
+ // Blacklevel / brightness.
+ nBrightness = rProperty.second.toInt32();
+ if (nBrightness != 0)
+ {
+ nBrightness /= 327;
+ }
+ }
+ else
+ SAL_INFO("writerfilter", "TODO handle shape property '" << rProperty.first << "':'"
+ << rProperty.second << "'");
+ }
+
+ if (xPropertySet.is())
+ {
+ resolveLineColorAndWidth(m_bTextFrame, xPropertySet, aLineColor, aLineWidth);
+ if (rShape.hasZ())
+ {
+ bool bOldStyle = m_aParents.size() > 1;
+ resolveDhgt(xPropertySet, rShape.getZ(), bOldStyle);
+ }
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("WritingMode", uno::Any(eWritingMode));
+ else
+ // Only Writer textframes implement text::WritingMode2.
+ xPropertySet->setPropertyValue("TextWritingMode",
+ uno::Any(text::WritingMode(eWritingMode)));
+ }
+
+ if (!m_aParents.empty() && m_aParents.top().is() && !m_bTextFrame)
+ m_aParents.top()->add(xShape);
+
+ if (nContrast == -70 && nBrightness == 70 && xPropertySet.is())
+ {
+ // Map MSO 'washout' to our watermark colormode.
+ xPropertySet->setPropertyValue("GraphicColorMode", uno::Any(drawing::ColorMode_WATERMARK));
+ }
+
+ if (bCustom && xShape.is() && !bPib)
+ {
+ uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
+ xDefaulter->createCustomShapeDefaults(OUString::number(nType));
+ }
+
+ // Set shape text
+ if (bCustom && !aShapeText.isEmpty())
+ {
+ uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
+ if (xTextRange.is())
+ xTextRange->setString(aShapeText);
+
+ xPropertySet->setPropertyValue("CharFontName", uno::Any(aFontFamily));
+ xPropertySet->setPropertyValue("CharHeight", uno::Any(nFontSize));
+ }
+
+ // Creating CustomShapeGeometry property
+ if (bCustom && xPropertySet.is())
+ {
+ bool bChanged = false;
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+
+ if (aViewBox.X || aViewBox.Y || aViewBox.Width || aViewBox.Height)
+ {
+ aViewBox.Width -= aViewBox.X;
+ aViewBox.Height -= aViewBox.Y;
+ aCustomShapeGeometry["ViewBox"] <<= aViewBox;
+ bChanged = true;
+ }
+
+ if (!aPath.empty())
+ {
+ aCustomShapeGeometry["Path"] <<= comphelper::containerToSequence(aPath);
+ bChanged = true;
+ }
+
+ if (!aShapeText.isEmpty())
+ {
+ uno::Sequence<beans::PropertyValue> aSequence(comphelper::InitPropertySequence({
+ { "TextPath", uno::Any(true) },
+ }));
+ aCustomShapeGeometry["TextPath"] <<= aSequence;
+ xPropertySet->setPropertyValue("TextAutoGrowHeight", uno::Any(false));
+ xPropertySet->setPropertyValue("TextAutoGrowWidth", uno::Any(false));
+ bChanged = true;
+ }
+
+ if (bChanged)
+ {
+ xPropertySet->setPropertyValue(
+ "CustomShapeGeometry",
+ uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ }
+ }
+
+ if (obRelFlipV.has_value() && xPropertySet.is())
+ {
+ if (nType == ESCHER_ShpInst_Line)
+ {
+ // Line shape inside group shape: get the polygon sequence and transform it.
+ uno::Sequence<uno::Sequence<awt::Point>> aPolyPolySequence;
+ if ((xPropertySet->getPropertyValue("PolyPolygon") >>= aPolyPolySequence)
+ && aPolyPolySequence.hasElements())
+ {
+ uno::Sequence<awt::Point>& rPolygon = aPolyPolySequence.getArray()[0];
+ basegfx::B2DPolygon aPoly;
+ for (const awt::Point& rPoint : std::as_const(rPolygon))
+ {
+ aPoly.append(basegfx::B2DPoint(rPoint.X, rPoint.Y));
+ }
+ basegfx::B2DHomMatrix aTransformation;
+ aTransformation.scale(1.0, *obRelFlipV ? -1.0 : 1.0);
+ aPoly.transform(aTransformation);
+ auto pPolygon = rPolygon.getArray();
+ for (sal_Int32 i = 0; i < rPolygon.getLength(); ++i)
+ {
+ basegfx::B2DPoint aPoint(aPoly.getB2DPoint(i));
+ pPolygon[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()),
+ static_cast<sal_Int32>(aPoint.getY()));
+ }
+ xPropertySet->setPropertyValue("PolyPolygon", uno::Any(aPolyPolySequence));
+ }
+ }
+ }
+
+ // Set position and size
+ if (xShape.is())
+ {
+ sal_Int32 nLeft = rShape.getLeft();
+ sal_Int32 nTop = rShape.getTop();
+
+ bool bInShapeGroup = oGroupLeft && oGroupTop && oGroupRight && oGroupBottom && oRelLeft
+ && oRelTop && oRelRight && oRelBottom;
+ awt::Size aSize;
+ if (bInShapeGroup)
+ {
+ // See lclGetAbsPoint() in the VML import: rShape is the group shape, oGroup is its coordinate system, oRel is the relative child shape.
+ sal_Int32 nShapeWidth = rShape.getRight() - rShape.getLeft();
+ sal_Int32 nShapeHeight = rShape.getBottom() - rShape.getTop();
+ sal_Int32 nCoordSysWidth = *oGroupRight - *oGroupLeft;
+ sal_Int32 nCoordSysHeight = *oGroupBottom - *oGroupTop;
+ double fWidthRatio = static_cast<double>(nShapeWidth) / nCoordSysWidth;
+ double fHeightRatio = static_cast<double>(nShapeHeight) / nCoordSysHeight;
+ nLeft = static_cast<sal_Int32>(rShape.getLeft()
+ + fWidthRatio * (*oRelLeft - *oGroupLeft));
+ nTop = static_cast<sal_Int32>(rShape.getTop() + fHeightRatio * (*oRelTop - *oGroupTop));
+
+ // See lclGetAbsRect() in the VML import.
+ aSize.Width = std::lround(fWidthRatio * (*oRelRight - *oRelLeft));
+ aSize.Height = std::lround(fHeightRatio * (*oRelBottom - *oRelTop));
+ }
+
+ if (m_bTextFrame)
+ {
+ xPropertySet->setPropertyValue("HoriOrientPosition", uno::Any(nLeft));
+ xPropertySet->setPropertyValue("VertOrientPosition", uno::Any(nTop));
+ }
+ else
+ xShape->setPosition(awt::Point(nLeft, nTop));
+
+ if (bInShapeGroup)
+ xShape->setSize(aSize);
+ else
+ xShape->setSize(awt::Size(rShape.getRight() - rShape.getLeft(),
+ rShape.getBottom() - rShape.getTop()));
+
+ if (obFlipH || obFlipV)
+ {
+ if (bCustom)
+ {
+ // This has to be set after position and size is set, otherwise flip will affect the position.
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+ if (obFlipH)
+ aCustomShapeGeometry["MirroredX"] <<= true;
+ if (obFlipV)
+ aCustomShapeGeometry["MirroredY"] <<= true;
+ xPropertySet->setPropertyValue(
+ "CustomShapeGeometry",
+ uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ }
+ else if (SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape))
+ {
+ Point aRef1 = pObject->GetSnapRect().Center();
+ Point aRef2(aRef1);
+ if (obFlipH)
+ {
+ // Horizontal mirror means a vertical reference line.
+ aRef2.AdjustY(1);
+ }
+ if (obFlipV)
+ {
+ // Vertical mirror means a horizontal reference line.
+ aRef2.AdjustX(1);
+ }
+ pObject->Mirror(aRef1, aRef2);
+ }
+ }
+
+ if (rShape.getHoriOrientRelation() != 0)
+ xPropertySet->setPropertyValue("HoriOrientRelation",
+ uno::Any(rShape.getHoriOrientRelation()));
+ if (rShape.getVertOrientRelation() != 0)
+ xPropertySet->setPropertyValue("VertOrientRelation",
+ uno::Any(rShape.getVertOrientRelation()));
+ if (rShape.getWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE)
+ xPropertySet->setPropertyValue("Surround", uno::Any(rShape.getWrap()));
+ oox::ModelObjectHelper aModelObjectHelper(m_rImport.getModelFactory());
+ if (aFillModel.moType.has())
+ {
+ oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
+ aFillModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
+ // Sets the FillStyle and FillGradient UNO properties.
+ oox::PropertySet(xShape).setProperties(aPropMap);
+ }
+
+ if (aShadowModel.mbHasShadow)
+ {
+ oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
+ aShadowModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
+ // Sets the ShadowFormat UNO property.
+ oox::PropertySet(xShape).setProperties(aPropMap);
+ }
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ xPropertySet->setPropertyValue("Opaque", uno::Any(bOpaque));
+ if (oRelativeWidth)
+ {
+ xPropertySet->setPropertyValue("RelativeWidth", uno::Any(*oRelativeWidth));
+ xPropertySet->setPropertyValue("RelativeWidthRelation",
+ uno::Any(nRelativeWidthRelation));
+ }
+ if (oRelativeHeight)
+ {
+ xPropertySet->setPropertyValue("RelativeHeight", uno::Any(*oRelativeHeight));
+ xPropertySet->setPropertyValue("RelativeHeightRelation",
+ uno::Any(nRelativeHeightRelation));
+ }
+ }
+
+ if (bPib)
+ {
+ m_rImport.resolvePict(false, xShape);
+ }
+
+ if (nType == ESCHER_ShpInst_PictureFrame) // picture frame
+ {
+ assert(!m_bTextFrame);
+ if (!bPib) // ??? not sure if the early return should be removed on else?
+ {
+ m_xShape = xShape; // store it for later resolvePict call
+ }
+
+ // Handle horizontal flip.
+ if (obFlipH && xPropertySet.is())
+ xPropertySet->setPropertyValue("IsMirrored", uno::Any(true));
+ return;
+ }
+
+ if (m_rImport.isInBackground())
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Background_color,
+ new RTFValue(xPropertySet->getPropertyValue("FillColor").get<sal_Int32>()));
+ m_rImport.Mapper().props(new RTFReferenceProperties(std::move(aAttributes)));
+
+ uno::Reference<lang::XComponent> xComponent(xShape, uno::UNO_QUERY);
+ xComponent->dispose();
+ return;
+ }
+
+ // Send it to dmapper
+ if (xShape.is())
+ {
+ m_rImport.Mapper().startShape(xShape);
+ if (bClose)
+ {
+ m_rImport.Mapper().endShape();
+ }
+ }
+
+ // If the shape has an inner shape, the inner object's properties should not be influenced by
+ // the outer one.
+ rShape.getProperties().clear();
+
+ m_xShape = xShape;
+}
+
+void RTFSdrImport::close() { m_rImport.Mapper().endShape(); }
+
+void RTFSdrImport::append(std::u16string_view aKey, std::u16string_view aValue)
+{
+ applyProperty(m_xShape, aKey, aValue);
+}
+
+void RTFSdrImport::appendGroupProperty(std::u16string_view aKey, std::u16string_view aValue)
+{
+ if (m_aParents.empty())
+ return;
+ uno::Reference<drawing::XShape> xShape(m_aParents.top(), uno::UNO_QUERY);
+ if (xShape.is())
+ applyProperty(xShape, aKey, aValue);
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsdrimport.hxx b/writerfilter/source/rtftok/rtfsdrimport.hxx
new file mode 100644
index 000000000..16f7f9c31
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsdrimport.hxx
@@ -0,0 +1,103 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <stack>
+#include <vector>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star
+{
+namespace beans
+{
+class XPropertySet;
+struct PropertyValue;
+}
+namespace drawing
+{
+class XShape;
+class XShapes;
+}
+namespace lang
+{
+class XComponent;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFDocumentImpl;
+class RTFShape;
+
+/// Handles the import of drawings using RTF markup.
+class RTFSdrImport final : public virtual SvRefBase
+{
+public:
+ RTFSdrImport(RTFDocumentImpl& rDocument,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc);
+ ~RTFSdrImport() override;
+
+ enum ShapeOrPict
+ {
+ SHAPE,
+ PICT
+ };
+ void resolve(RTFShape& rShape, bool bClose, ShapeOrPict shapeOrPict);
+ void close();
+ void append(std::u16string_view aKey, std::u16string_view aValue);
+ /// Append property on the current parent.
+ void appendGroupProperty(std::u16string_view aKey, std::u16string_view aValue);
+ void resolveDhgt(css::uno::Reference<css::beans::XPropertySet> const& xPropertySet,
+ sal_Int32 nZOrder, bool bOldStyle);
+ /// Set line color and line width on the shape, using the relevant API depending on if the shape is a text frame or not.
+ static void
+ resolveLineColorAndWidth(bool bTextFrame,
+ const css::uno::Reference<css::beans::XPropertySet>& xPropertySet,
+ css::uno::Any const& rLineColor, css::uno::Any const& rLineWidth);
+ static void resolveFLine(css::uno::Reference<css::beans::XPropertySet> const& xPropertySet,
+ sal_Int32 nFLine);
+ /**
+ * These are the default in Word, but not in Writer.
+ *
+ * @param bNew if the frame is new-style or old-style.
+ */
+ static std::vector<css::beans::PropertyValue> getTextFrameDefaults(bool bNew);
+ /// Push a new group shape to the parent stack.
+ void pushParent(css::uno::Reference<css::drawing::XShapes> const& xParent);
+ /// Pop the current group shape from the parent stack.
+ void popParent();
+ css::uno::Reference<css::drawing::XShape> const& getCurrentShape() const { return m_xShape; }
+ bool isFakePict() const { return m_bFakePict; }
+
+private:
+ void createShape(const OUString& rService, css::uno::Reference<css::drawing::XShape>& xShape,
+ css::uno::Reference<css::beans::XPropertySet>& xPropertySet);
+ void applyProperty(css::uno::Reference<css::drawing::XShape> const& xShape,
+ std::u16string_view aKey, std::u16string_view aValue) const;
+ int initShape(css::uno::Reference<css::drawing::XShape>& o_xShape,
+ css::uno::Reference<css::beans::XPropertySet>& o_xPropSet, bool& o_rIsCustomShape,
+ RTFShape const& rShape, bool bClose, ShapeOrPict shapeOrPict);
+
+ RTFDocumentImpl& m_rImport;
+ std::stack<css::uno::Reference<css::drawing::XShapes>> m_aParents;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ /// If m_xShape is imported as a Writer text frame (instead of a drawinglayer rectangle).
+ bool m_bTextFrame;
+ /// If m_xShape is imported as a Writer text graphic object (instead of a drawinglayer shape).
+ bool m_bTextGraphicObject;
+ /// if inside \pict, but actually it's a shape (not a picture)
+ bool m_bFakePict;
+ std::stack<writerfilter::dmapper::GraphicZOrderHelper> m_aGraphicZOrderHelpers;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfskipdestination.cxx b/writerfilter/source/rtftok/rtfskipdestination.cxx
new file mode 100644
index 000000000..ad2122318
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfskipdestination.cxx
@@ -0,0 +1,42 @@
+/* -*- 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 "rtfskipdestination.hxx"
+#include <sal/log.hxx>
+#include "rtflistener.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFSkipDestination::RTFSkipDestination(RTFListener& rImport)
+ : m_rImport(rImport)
+ , m_bParsed(true)
+ , m_bReset(true)
+{
+}
+
+RTFSkipDestination::~RTFSkipDestination()
+{
+ if (m_rImport.getSkipUnknown() && m_bReset)
+ {
+ if (!m_bParsed)
+ {
+ SAL_INFO("writerfilter", __func__ << ": skipping destination");
+ m_rImport.setDestination(Destination::SKIP);
+ }
+ m_rImport.setSkipUnknown(false);
+ }
+}
+
+void RTFSkipDestination::setParsed(bool bParsed) { m_bParsed = bParsed; }
+
+void RTFSkipDestination::setReset(bool bReset) { m_bReset = bReset; }
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfskipdestination.hxx b/writerfilter/source/rtftok/rtfskipdestination.hxx
new file mode 100644
index 000000000..4a894373f
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfskipdestination.hxx
@@ -0,0 +1,33 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+class RTFListener;
+
+/// Skips a destination after a not parsed control word if it was prefixed with \*
+class RTFSkipDestination final
+{
+public:
+ explicit RTFSkipDestination(RTFListener& rImport);
+ ~RTFSkipDestination();
+ void setParsed(bool bParsed);
+ void setReset(bool bReset);
+
+private:
+ RTFListener& m_rImport;
+ bool m_bParsed;
+ /// If false, the destructor is a noop, required by the \* symbol itself.
+ bool m_bReset;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsprm.cxx b/writerfilter/source/rtftok/rtfsprm.cxx
new file mode 100644
index 000000000..90bc97001
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsprm.cxx
@@ -0,0 +1,476 @@
+/* -*- 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 "rtfsprm.hxx"
+#include <ooxml/resourceids.hxx>
+#include <ooxml/QNameToString.hxx>
+#include <rtl/strbuf.hxx>
+#include "rtfdocumentimpl.hxx"
+#include <algorithm>
+
+namespace writerfilter::rtftok
+{
+RTFSprm::RTFSprm(Id nKeyword, RTFValue::Pointer_t& pValue)
+ : m_nKeyword(nKeyword)
+ , m_pValue(pValue)
+{
+}
+
+sal_uInt32 RTFSprm::getId() const { return m_nKeyword; }
+
+Value::Pointer_t RTFSprm::getValue() { return Value::Pointer_t(m_pValue->Clone()); }
+
+writerfilter::Reference<Properties>::Pointer_t RTFSprm::getProps()
+{
+ return m_pValue->getProperties();
+}
+
+#ifdef DBG_UTIL
+std::string RTFSprm::getName() const { return "RTFSprm"; }
+#endif
+
+#ifdef DBG_UTIL
+std::string RTFSprm::toString() const
+{
+ OStringBuffer aBuf("RTFSprm");
+
+ std::string sResult = QNameToString(m_nKeyword);
+
+ aBuf.append(" ('");
+ if (sResult.length() == 0)
+ aBuf.append(sal_Int32(m_nKeyword));
+ else
+ aBuf.append(sResult.c_str());
+ aBuf.append("', '");
+ aBuf.append(m_pValue->toString().c_str());
+ aBuf.append("')");
+
+ return aBuf.makeStringAndClear().getStr();
+}
+#endif
+
+namespace
+{
+class RTFSprms_compare
+{
+ Id keyword;
+
+public:
+ RTFSprms_compare(Id kw)
+ : keyword{ kw }
+ {
+ }
+ bool operator()(const std::pair<Id, RTFValue::Pointer_t>& raPair) const
+ {
+ return raPair.first == keyword;
+ }
+};
+}
+
+RTFValue::Pointer_t RTFSprms::find(Id nKeyword, bool bFirst, bool bForWrite)
+{
+ if (bForWrite)
+ ensureCopyBeforeWrite();
+
+ RTFSprms_compare cmp{ nKeyword };
+
+ if (bFirst)
+ {
+ auto it = std::find_if(m_pSprms->begin(), m_pSprms->end(), cmp);
+ if (it != m_pSprms->end())
+ return it->second;
+ }
+ else
+ // find last
+ {
+ auto rit = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), cmp);
+ if (rit != m_pSprms->rend())
+ return rit->second;
+ }
+
+ return RTFValue::Pointer_t{};
+}
+
+void RTFSprms::set(Id nKeyword, const RTFValue::Pointer_t& pValue, RTFOverwrite eOverwrite)
+{
+ ensureCopyBeforeWrite();
+
+ switch (eOverwrite)
+ {
+ case RTFOverwrite::YES_PREPEND:
+ {
+ m_pSprms->erase(
+ std::remove_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword }),
+ m_pSprms->end());
+ m_pSprms->emplace(m_pSprms->cbegin(), nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::YES:
+ {
+ auto it
+ = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword });
+ if (it != m_pSprms->end())
+ it->second = pValue;
+ else
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::NO_IGNORE:
+ {
+ if (std::none_of(m_pSprms->cbegin(), m_pSprms->cend(), RTFSprms_compare{ nKeyword }))
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::NO_APPEND:
+ {
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ }
+}
+
+bool RTFSprms::erase(Id nKeyword)
+{
+ ensureCopyBeforeWrite();
+
+ auto i = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword });
+ if (i != m_pSprms->end())
+ {
+ m_pSprms->erase(i);
+ return true;
+ }
+ return false;
+}
+
+void RTFSprms::eraseLast(Id nKeyword)
+{
+ ensureCopyBeforeWrite();
+
+ auto i = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), RTFSprms_compare{ nKeyword });
+ if (i != m_pSprms->rend())
+ m_pSprms->erase(std::next(i).base());
+}
+
+static RTFValue::Pointer_t getDefaultSPRM(Id const id, Id nStyleType)
+{
+ if (nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ switch (id)
+ {
+ case NS_ooxml::LN_EG_RPrBase_szCs:
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ return new RTFValue(24);
+ case NS_ooxml::LN_CT_Color_val:
+ return new RTFValue(0);
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_i:
+ return new RTFValue(0);
+ case NS_ooxml::LN_CT_Underline_val:
+ return new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ case NS_ooxml::LN_CT_Fonts_ascii:
+ case NS_ooxml::LN_CT_Fonts_eastAsia:
+ case NS_ooxml::LN_CT_Fonts_cs:
+ return new RTFValue("Times New Roman");
+ default:
+ break;
+ }
+ }
+
+ if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_paragraph)
+ {
+ switch (id)
+ {
+ case NS_ooxml::LN_CT_Spacing_before:
+ case NS_ooxml::LN_CT_Spacing_after:
+ case NS_ooxml::LN_CT_Ind_left:
+ case NS_ooxml::LN_CT_Ind_right:
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ return new RTFValue(0);
+
+ case NS_ooxml::LN_CT_Spacing_lineRule:
+ return new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
+ case NS_ooxml::LN_CT_Spacing_line:
+ // presumably this means 100%, cf. static const int nSingleLineSpacing = 240;
+ return new RTFValue(240);
+
+ case NS_ooxml::LN_CT_PrBase_pBdr:
+ { // tdf#150382 default all paragraph borders to none
+ RTFSprms attributes;
+ RTFSprms sprms;
+ for (int i = 0; i < 4; ++i)
+ {
+ auto const nBorder = getParagraphBorder(i);
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aAttributes.set(NS_ooxml::LN_CT_Border_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+ sprms.set(nBorder, new RTFValue(aAttributes, aSprms));
+ }
+ return new RTFValue(attributes, sprms);
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return RTFValue::Pointer_t();
+}
+
+/// Is it problematic to deduplicate this SPRM?
+static bool isSPRMDeduplicateDenylist(Id nId, RTFSprms* pDirect)
+{
+ switch (nId)
+ {
+ // See the NS_ooxml::LN_CT_PPrBase_tabs handler in DomainMapper,
+ // deduplication is explicitly not wanted for these tokens.
+ case NS_ooxml::LN_CT_TabStop_val:
+ case NS_ooxml::LN_CT_TabStop_leader:
+ case NS_ooxml::LN_CT_TabStop_pos:
+ // \htmautsp arrives after the style table, so only the non-style value is
+ // correct, keep these.
+ case NS_ooxml::LN_CT_Spacing_beforeAutospacing:
+ case NS_ooxml::LN_CT_Spacing_afterAutospacing:
+ // \chbrdr requires *all* of the border settings to be present,
+ // otherwise a default (NONE) border is created from the removed
+ // attributes which then overrides the style-defined border.
+ // See BorderHandler.cxx and NS_ooxml::LN_EG_RPrBase_bdr in DomainMapper.
+ // This also is needed for NS_ooxml::LN_CT_PBdr_top etc.
+ case NS_ooxml::LN_CT_Border_sz:
+ case NS_ooxml::LN_CT_Border_val:
+ case NS_ooxml::LN_CT_Border_color:
+ case NS_ooxml::LN_CT_Border_space:
+ case NS_ooxml::LN_CT_Border_shadow:
+ case NS_ooxml::LN_CT_Border_frame:
+ case NS_ooxml::LN_CT_Border_themeTint:
+ case NS_ooxml::LN_CT_Border_themeColor:
+ return true;
+ // Removing \fi and \li if the style has the same value would mean taking these values from
+ // \ls, while deduplication would be done to take the values from the style.
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ case NS_ooxml::LN_CT_Ind_left:
+ return pDirect && pDirect->find(NS_ooxml::LN_CT_PPrBase_numPr);
+
+ default:
+ return false;
+ }
+}
+
+/// Should this SPRM be removed if all its children are removed?
+static bool isSPRMChildrenExpected(Id nId)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_PBdr_top:
+ case NS_ooxml::LN_CT_PBdr_left:
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ case NS_ooxml::LN_CT_PBdr_right:
+ // Expected children are NS_ooxml::LN_CT_Border_*.
+ case NS_ooxml::LN_CT_PrBase_shd:
+ // Expected children are NS_ooxml::LN_CT_Shd_*.
+ case NS_ooxml::LN_CT_PPrBase_ind:
+ // Expected children are NS_ooxml::LN_CT_Ind_*.
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/// Does the clone / deduplication of a single sprm.
+static void cloneAndDeduplicateSprm(std::pair<Id, RTFValue::Pointer_t> const& rSprm, RTFSprms& ret,
+ Id nStyleType, RTFSprms* pDirect = nullptr)
+{
+ RTFValue::Pointer_t const pValue(ret.find(rSprm.first));
+ if (pValue)
+ {
+ if (rSprm.second->equals(*pValue))
+ {
+ if (!isSPRMDeduplicateDenylist(rSprm.first, pDirect))
+ {
+ ret.erase(rSprm.first); // duplicate to style
+ }
+ }
+ else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty())
+ {
+ RTFSprms const sprms(pValue->getSprms().cloneAndDeduplicate(
+ rSprm.second->getSprms(), nStyleType, /*bImplicitPPr =*/false, pDirect));
+ RTFSprms const attributes(pValue->getAttributes().cloneAndDeduplicate(
+ rSprm.second->getAttributes(), nStyleType, /*bImplicitPPr =*/false, pDirect));
+ // Don't copy the sprm in case we expect it to have children but it doesn't have some.
+ if (!isSPRMChildrenExpected(rSprm.first) || !sprms.empty() || !attributes.empty())
+ ret.set(rSprm.first,
+ RTFValue::Pointer_t(pValue->CloneWithSprms(attributes, sprms)));
+ }
+ }
+ else
+ {
+ // not found - try to override style with default
+ RTFValue::Pointer_t const pDefault(getDefaultSPRM(rSprm.first, nStyleType));
+ if (pDefault)
+ {
+ ret.set(rSprm.first, pDefault);
+ }
+ else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty())
+ {
+ RTFSprms const sprms(
+ RTFSprms().cloneAndDeduplicate(rSprm.second->getSprms(), nStyleType));
+ RTFSprms const attributes(
+ RTFSprms().cloneAndDeduplicate(rSprm.second->getAttributes(), nStyleType));
+ if (!sprms.empty() || !attributes.empty())
+ {
+ ret.set(rSprm.first, new RTFValue(attributes, sprms));
+ }
+ }
+ }
+}
+
+/// Extracts the list level matching nLevel from pAbstract.
+static RTFValue::Pointer_t getListLevel(const RTFValue::Pointer_t& pAbstract, int nLevel)
+{
+ for (const auto& rPair : pAbstract->getSprms())
+ {
+ if (rPair.first != NS_ooxml::LN_CT_AbstractNum_lvl)
+ continue;
+
+ RTFValue::Pointer_t pLevel = rPair.second->getAttributes().find(NS_ooxml::LN_CT_Lvl_ilvl);
+ if (!pLevel)
+ continue;
+
+ if (pLevel->getInt() != nLevel)
+ continue;
+
+ return rPair.second;
+ }
+
+ return RTFValue::Pointer_t();
+}
+
+void RTFSprms::deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents)
+{
+ int nLevel = 0;
+ RTFValue::Pointer_t pLevelId
+ = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl);
+ if (pLevelId)
+ nLevel = pLevelId->getInt();
+
+ auto it = rInvalidListLevelFirstIndents.find(nLevel);
+ if (it == rInvalidListLevelFirstIndents.end())
+ return;
+
+ int nListValue = it->second;
+
+ RTFValue::Pointer_t pParagraphValue
+ = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine);
+ if (!pParagraphValue)
+ return;
+
+ int nParagraphValue = pParagraphValue->getInt();
+
+ if (nParagraphValue == nListValue)
+ eraseNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine);
+}
+
+void RTFSprms::duplicateList(const RTFValue::Pointer_t& pAbstract)
+{
+ int nLevel = 0;
+ RTFValue::Pointer_t pLevelId
+ = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl);
+ if (pLevelId)
+ nLevel = pLevelId->getInt();
+
+ RTFValue::Pointer_t pLevel = getListLevel(pAbstract, nLevel);
+ if (!pLevel)
+ return;
+
+ RTFValue::Pointer_t pLevelInd = pLevel->getSprms().find(NS_ooxml::LN_CT_PPrBase_ind);
+ if (!pLevelInd)
+ return;
+
+ for (const auto& rListLevelPair : pLevelInd->getAttributes())
+ {
+ switch (rListLevelPair.first)
+ {
+ case NS_ooxml::LN_CT_Ind_left:
+ case NS_ooxml::LN_CT_Ind_right:
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ RTFValue::Pointer_t pParagraphValue
+ = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first);
+ if (!pParagraphValue)
+ putNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first,
+ getDefaultSPRM(rListLevelPair.first, 0));
+
+ break;
+ }
+ }
+}
+
+RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id const nStyleType,
+ bool const bImplicitPPr, RTFSprms* pDirect) const
+{
+ RTFSprms ret(*this);
+ ret.ensureCopyBeforeWrite();
+
+ // Note: apparently some attributes are set with OVERWRITE_NO_APPEND;
+ // it is probably a bad idea to mess with those in any way here?
+ for (auto& rSprm : rReference)
+ {
+ // Paragraph formatting sprms are directly contained in case of
+ // paragraphs, but they are below NS_ooxml::LN_CT_Style_pPr in case of
+ // styles. So handle those children directly, to avoid unexpected
+ // addition of direct formatting sprms at the paragraph level.
+ if (bImplicitPPr && rSprm.first == NS_ooxml::LN_CT_Style_pPr)
+ {
+ for (const auto& i : rSprm.second->getSprms())
+ cloneAndDeduplicateSprm(i, ret, nStyleType, pDirect);
+ }
+ else
+ cloneAndDeduplicateSprm(rSprm, ret, nStyleType, pDirect);
+ }
+ return ret;
+}
+
+bool RTFSprms::equals(const RTFValue& rOther) const
+{
+ return std::all_of(m_pSprms->cbegin(), m_pSprms->cend(),
+ [&](const std::pair<Id, RTFValue::Pointer_t>& raPair) -> bool {
+ return raPair.second->equals(rOther);
+ });
+}
+
+void RTFSprms::ensureCopyBeforeWrite()
+{
+ if (m_pSprms->GetRefCount() > 1)
+ {
+ tools::SvRef<RTFSprmsImpl> pClone(new RTFSprmsImpl);
+ for (auto& rSprm : *m_pSprms)
+ pClone->push_back(
+ std::make_pair(rSprm.first, RTFValue::Pointer_t(rSprm.second->Clone())));
+ m_pSprms = pClone;
+ }
+}
+
+RTFSprms::RTFSprms()
+ : m_pSprms(new RTFSprmsImpl)
+{
+}
+
+RTFSprms::~RTFSprms() = default;
+
+void RTFSprms::clear()
+{
+ if (m_pSprms->GetRefCount() == 1)
+ return m_pSprms->clear();
+
+ m_pSprms = tools::SvRef<RTFSprmsImpl>(new RTFSprmsImpl);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfsprm.hxx b/writerfilter/source/rtftok/rtfsprm.hxx
new file mode 100644
index 000000000..9f3bbd78b
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfsprm.hxx
@@ -0,0 +1,101 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+#include <map>
+
+#include <tools/ref.hxx>
+#include "rtfvalue.hxx"
+
+namespace writerfilter::rtftok
+{
+using RTFSprmsImplBase = std::vector<std::pair<Id, RTFValue::Pointer_t>>;
+
+/// The payload of RTFSprms which is only copied on write.
+class RTFSprmsImpl : public RTFSprmsImplBase, public virtual SvRefBase
+{
+};
+
+enum class RTFOverwrite
+{
+ YES, ///< Yes, if an existing key is found, overwrite it.
+ NO_APPEND, ///< No, always append the value to the end of the list.
+ NO_IGNORE, ///< No, if the key is already in the list, then ignore, otherwise append.
+ YES_PREPEND ///< Yes, always prepend the value to the start of the list and remove existing entries.
+};
+
+/// A list of RTFSprm with a copy constructor that performs a deep copy.
+class RTFSprms : public virtual SvRefBase
+{
+public:
+ using Pointer_t = tools::SvRef<RTFSprms>;
+ using Entry_t = std::pair<Id, RTFValue::Pointer_t>;
+ using Iterator_t = std::vector<Entry_t>::iterator;
+ using ReverseIterator_t = std::vector<Entry_t>::reverse_iterator;
+ RTFSprms();
+ ~RTFSprms() override;
+
+ RTFSprms(RTFSprms const&) = default;
+ RTFSprms(RTFSprms&&) = default;
+ RTFSprms& operator=(RTFSprms const&) = default;
+ RTFSprms& operator=(RTFSprms&&) = default;
+
+ RTFValue::Pointer_t find(Id nKeyword, bool bFirst = true, bool bForWrite = false);
+ /// Does the same as ->push_back(), except that it can overwrite or ignore existing entries.
+ void set(Id nKeyword, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::YES);
+ bool erase(Id nKeyword);
+ void eraseLast(Id nKeyword);
+ /// Removes elements which are already in the reference set.
+ /// Also insert default values to override attributes of style
+ /// (yes, really; that's what Word does).
+ /// @param bImplicitPPr implicit dereference of top-level pPr SPRM
+ /// @param pDirect pointer to the root of the direct formatting SPRM tree, if any
+ RTFSprms cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType, bool bImplicitPPr = false,
+ RTFSprms* pDirect = nullptr) const;
+ /// Inserts default values to override attributes of pAbstract.
+ void duplicateList(const RTFValue::Pointer_t& pAbstract);
+ /// Removes duplicated values based on in-list properties.
+ void deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents);
+ std::size_t size() const { return m_pSprms->size(); }
+ bool empty() const { return m_pSprms->empty(); }
+ Entry_t& back() { return m_pSprms->back(); }
+ Iterator_t begin() { return m_pSprms->begin(); }
+ Iterator_t end() { return m_pSprms->end(); }
+ void clear();
+ bool equals(const RTFValue& rOther) const;
+
+private:
+ void ensureCopyBeforeWrite();
+ tools::SvRef<RTFSprmsImpl> m_pSprms;
+};
+
+/// RTF keyword with a parameter
+class RTFSprm : public Sprm
+{
+public:
+ RTFSprm(Id nKeyword, RTFValue::Pointer_t& pValue);
+ sal_uInt32 getId() const override;
+ Value::Pointer_t getValue() override;
+ writerfilter::Reference<Properties>::Pointer_t getProps() override;
+#ifdef DBG_UTIL
+ std::string getName() const override;
+ std::string toString() const override;
+#endif
+private:
+ Id m_nKeyword;
+ RTFValue::Pointer_t& m_pValue;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtftokenizer.cxx b/writerfilter/source/rtftok/rtftokenizer.cxx
new file mode 100644
index 000000000..4dc80416c
--- /dev/null
+++ b/writerfilter/source/rtftok/rtftokenizer.cxx
@@ -0,0 +1,329 @@
+/* -*- 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 "rtftokenizer.hxx"
+#include <tools/stream.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <rtl/strbuf.hxx>
+#include <rtl/character.hxx>
+#include <sal/log.hxx>
+#include "rtfskipdestination.hxx"
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <filter/msfilter/rtfutil.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+std::unordered_map<OString, RTFSymbol> RTFTokenizer::s_aRTFControlWords;
+bool RTFTokenizer::s_bControlWordsInitialised;
+std::vector<RTFMathSymbol> RTFTokenizer::s_aRTFMathControlWords;
+bool RTFTokenizer::s_bMathControlWordsSorted;
+
+RTFTokenizer::RTFTokenizer(RTFListener& rImport, SvStream* pInStream,
+ uno::Reference<task::XStatusIndicator> const& xStatusIndicator)
+ : m_rImport(rImport)
+ , m_pInStream(pInStream)
+ , m_xStatusIndicator(xStatusIndicator)
+ , m_nGroup(0)
+ , m_nLineNumber(0)
+ , m_nLineStartPos(0)
+ , m_nGroupStart(0)
+{
+ if (!RTFTokenizer::s_bControlWordsInitialised)
+ {
+ RTFTokenizer::s_bControlWordsInitialised = true;
+ for (int i = 0; i < nRTFControlWords; ++i)
+ s_aRTFControlWords.emplace(OString(aRTFControlWords[i].GetKeyword()),
+ aRTFControlWords[i]);
+ }
+ if (!RTFTokenizer::s_bMathControlWordsSorted)
+ {
+ RTFTokenizer::s_bMathControlWordsSorted = true;
+ s_aRTFMathControlWords = std::vector<RTFMathSymbol>(
+ aRTFMathControlWords, aRTFMathControlWords + nRTFMathControlWords);
+ std::sort(s_aRTFMathControlWords.begin(), s_aRTFMathControlWords.end());
+ }
+}
+
+RTFTokenizer::~RTFTokenizer() = default;
+
+RTFError RTFTokenizer::resolveParse()
+{
+ SAL_INFO("writerfilter.rtf", __func__);
+ char ch;
+ RTFError ret;
+ // for hex chars
+ int b = 0;
+ int count = 2;
+ std::size_t nPercentSize = 0;
+ sal_uInt64 nLastPos = 0;
+
+ if (m_xStatusIndicator.is())
+ {
+ OUString sDocLoad(SvxResId(RID_SVXSTR_DOC_LOAD));
+
+ sal_uInt64 const nCurrentPos = Strm().Tell();
+ sal_uInt64 const nEndPos = nCurrentPos + Strm().remainingSize();
+ m_xStatusIndicator->start(sDocLoad, nEndPos);
+ nPercentSize = nEndPos / 100;
+
+ nLastPos = nCurrentPos;
+ m_xStatusIndicator->setValue(nLastPos);
+ }
+
+ while (Strm().ReadChar(ch), !Strm().eof())
+ {
+ //SAL_INFO("writerfilter", __func__ << ": parsing character '" << ch << "'");
+
+ sal_uInt64 const nCurrentPos = Strm().Tell();
+ if (m_xStatusIndicator.is() && nCurrentPos > (nLastPos + nPercentSize))
+ {
+ nLastPos = nCurrentPos;
+ m_xStatusIndicator->setValue(nLastPos);
+ }
+
+ if (m_nGroup < 0)
+ return RTFError::GROUP_UNDER;
+ if (m_nGroup > 0 && m_rImport.getInternalState() == RTFInternalState::BIN)
+ {
+ ret = m_rImport.resolveChars(ch);
+ if (ret != RTFError::OK)
+ return ret;
+ }
+ else
+ {
+ switch (ch)
+ {
+ case '{':
+ m_nGroupStart = Strm().Tell() - 1;
+ ret = m_rImport.pushState();
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case '}':
+ ret = m_rImport.popState();
+ if (ret != RTFError::OK)
+ return ret;
+ if (m_nGroup == 0)
+ {
+ if (m_rImport.isSubstream())
+ m_rImport.finishSubstream();
+ return RTFError::OK;
+ }
+ break;
+ case '\\':
+ ret = resolveKeyword();
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case 0x0d:
+ break; // ignore this
+ case 0x0a:
+ m_nLineNumber++;
+ m_nLineStartPos = nCurrentPos;
+ break;
+ default:
+ if (m_nGroup == 0)
+ return RTFError::CHAR_OVER;
+ if (m_rImport.getInternalState() == RTFInternalState::NORMAL)
+ {
+ ret = m_rImport.resolveChars(ch);
+ if (ret != RTFError::OK)
+ return ret;
+ }
+ else
+ {
+ SAL_INFO("writerfilter.rtf", __func__ << ": hex internal state");
+ // Assume that \'<number><junk> means \'0<number>.
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch))
+ || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return RTFError::HEX_INVALID;
+ b += parsed;
+ }
+ count--;
+ if (!count)
+ {
+ ret = m_rImport.resolveChars(b);
+ if (ret != RTFError::OK)
+ return ret;
+ count = 2;
+ b = 0;
+ m_rImport.setInternalState(RTFInternalState::NORMAL);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (m_nGroup < 0)
+ return RTFError::GROUP_UNDER;
+ if (m_nGroup > 0)
+ return RTFError::GROUP_OVER;
+ return RTFError::OK;
+}
+
+void RTFTokenizer::pushGroup() { m_nGroup++; }
+
+void RTFTokenizer::popGroup() { m_nGroup--; }
+
+RTFError RTFTokenizer::resolveKeyword()
+{
+ char ch;
+
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ return RTFError::UNEXPECTED_EOF;
+
+ if (!rtl::isAsciiAlpha(static_cast<unsigned char>(ch)))
+ {
+ // control symbols aren't followed by a space, so we can return here
+ // without doing any SeekRel()
+ return dispatchKeyword(OString(ch), false, 0);
+ }
+ OStringBuffer aBuf(32);
+ while (rtl::isAsciiAlpha(static_cast<unsigned char>(ch)))
+ {
+ aBuf.append(ch);
+ if (aBuf.getLength() > 32)
+ // See RTF spec v1.9.1, page 7
+ // A control word's name cannot be longer than 32 letters.
+ throw io::BufferSizeExceededException();
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ {
+ ch = ' ';
+ break;
+ }
+ }
+
+ bool bNeg = false;
+ if (ch == '-')
+ {
+ // in case we'll have a parameter, that will be negative
+ bNeg = true;
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ return RTFError::UNEXPECTED_EOF;
+ }
+ bool bParam = false;
+ int nParam = 0;
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ {
+ OStringBuffer aParameter;
+
+ // we have a parameter
+ bParam = true;
+ while (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ {
+ aParameter.append(ch);
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ {
+ ch = ' ';
+ break;
+ }
+ }
+ nParam = aParameter.makeStringAndClear().toInt32();
+ if (bNeg)
+ nParam = -nParam;
+ }
+ if (ch != ' ')
+ Strm().SeekRel(-1);
+ OString aKeyword = aBuf.makeStringAndClear();
+ return dispatchKeyword(aKeyword, bParam, nParam);
+}
+
+bool RTFTokenizer::lookupMathKeyword(RTFMathSymbol& rSymbol)
+{
+ auto low
+ = std::lower_bound(s_aRTFMathControlWords.begin(), s_aRTFMathControlWords.end(), rSymbol);
+ if (low == s_aRTFMathControlWords.end() || rSymbol < *low)
+ return false;
+ rSymbol = *low;
+ return true;
+}
+
+RTFError RTFTokenizer::dispatchKeyword(OString const& rKeyword, bool bParam, int nParam)
+{
+ if (m_rImport.getDestination() == Destination::SKIP)
+ {
+ // skip binary data explicitly, to not trip over rtf markup
+ // control characters
+ if (rKeyword == "bin" && nParam > 0)
+ Strm().SeekRel(nParam);
+ return RTFError::OK;
+ }
+ SAL_INFO("writerfilter.rtf", __func__ << ": keyword '\\" << rKeyword << "' with param? "
+ << (bParam ? 1 : 0) << " param val: '"
+ << (bParam ? nParam : 0) << "'");
+ auto findIt = s_aRTFControlWords.find(rKeyword);
+ if (findIt == s_aRTFControlWords.end())
+ {
+ SAL_INFO("writerfilter.rtf", __func__ << ": unknown keyword '\\" << rKeyword << "'");
+ RTFSkipDestination aSkip(m_rImport);
+ aSkip.setParsed(false);
+ return RTFError::OK;
+ }
+
+ RTFError ret;
+ RTFSymbol const& rSymbol = findIt->second;
+ switch (rSymbol.GetControlType())
+ {
+ case RTFControlType::FLAG:
+ // flags ignore any parameter by definition
+ ret = m_rImport.dispatchFlag(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::DESTINATION:
+ // same for destinations
+ ret = m_rImport.dispatchDestination(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::SYMBOL:
+ // and symbols
+ ret = m_rImport.dispatchSymbol(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::TOGGLE:
+ ret = m_rImport.dispatchToggle(rSymbol.GetIndex(), bParam, nParam);
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::VALUE:
+ if (!bParam)
+ nParam = rSymbol.GetDefValue();
+ ret = m_rImport.dispatchValue(rSymbol.GetIndex(), nParam);
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ }
+
+ return RTFError::OK;
+}
+
+OUString RTFTokenizer::getPosition()
+{
+ return OUString::number(m_nLineNumber + 1) + ","
+ + OUString::number(Strm().Tell() - m_nLineStartPos + 1);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtftokenizer.hxx b/writerfilter/source/rtftok/rtftokenizer.hxx
new file mode 100644
index 000000000..feb74fc63
--- /dev/null
+++ b/writerfilter/source/rtftok/rtftokenizer.hxx
@@ -0,0 +1,72 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include "rtflistener.hxx"
+
+#include <vector>
+#include <unordered_map>
+
+#include <com/sun/star/uno/Reference.h>
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star::task
+{
+class XStatusIndicator;
+}
+class SvStream;
+
+namespace writerfilter::rtftok
+{
+/// RTF tokenizer that separates control words from text.
+class RTFTokenizer final : public virtual SvRefBase
+{
+public:
+ RTFTokenizer(RTFListener& rImport, SvStream* pInStream,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator);
+ ~RTFTokenizer() override;
+
+ RTFError resolveParse();
+ /// Number of states on the stack.
+ int getGroup() const { return m_nGroup; }
+ /// To be invoked by the pushState() callback to signal when the importer enters a group.
+ void pushGroup();
+ /// To be invoked by the popState() callback to signal when the importer leaves a group.
+ void popGroup();
+ OUString getPosition();
+ std::size_t getGroupStart() const { return m_nGroupStart; }
+ /// To look up additional properties of a math symbol.
+ static bool lookupMathKeyword(RTFMathSymbol& rSymbol);
+
+private:
+ SvStream& Strm() { return *m_pInStream; }
+ RTFError resolveKeyword();
+ RTFError dispatchKeyword(OString const& rKeyword, bool bParam, int nParam);
+
+ RTFListener& m_rImport;
+ SvStream* m_pInStream;
+ css::uno::Reference<css::task::XStatusIndicator> const& m_xStatusIndicator;
+ // This is the same as aRTFControlWords, but mapped by token name for fast lookup
+ static std::unordered_map<OString, RTFSymbol> s_aRTFControlWords;
+ static bool s_bControlWordsInitialised;
+ // This is the same as aRTFMathControlWords, but sorted
+ static std::vector<RTFMathSymbol> s_aRTFMathControlWords;
+ static bool s_bMathControlWordsSorted;
+ /// Same as the size of the importer's states, except that this can be negative for invalid input.
+ int m_nGroup;
+ sal_Int32 m_nLineNumber;
+ std::size_t m_nLineStartPos;
+ std::size_t m_nGroupStart;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfvalue.cxx b/writerfilter/source/rtftok/rtfvalue.cxx
new file mode 100644
index 000000000..42f60a1c9
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfvalue.cxx
@@ -0,0 +1,222 @@
+/* -*- 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 "rtfreferenceproperties.hxx"
+#include "rtfdocumentimpl.hxx"
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFValue::RTFValue(int nValue, OUString sValue, const RTFSprms* pAttributes, const RTFSprms* pSprms,
+ uno::Reference<drawing::XShape> xShape, uno::Reference<io::XInputStream> xStream,
+ uno::Reference<embed::XEmbeddedObject> xObject, bool bForceString,
+ const RTFShape* pShape, const RTFPicture* pPicture)
+ : m_nValue(nValue)
+ , m_sValue(std::move(sValue))
+ , m_xShape(std::move(xShape))
+ , m_xStream(std::move(xStream))
+ , m_xObject(std::move(xObject))
+ , m_bForceString(bForceString)
+{
+ if (pAttributes)
+ m_pAttributes = new RTFSprms(*pAttributes);
+ if (pSprms)
+ m_pSprms = new RTFSprms(*pSprms);
+ if (pShape)
+ m_pShape = new RTFShape(*pShape);
+ if (pPicture)
+ m_pPicture = new RTFPicture(*pPicture);
+}
+
+RTFValue::RTFValue() {}
+
+RTFValue::RTFValue(int nValue)
+ : m_nValue(nValue)
+{
+}
+
+RTFValue::RTFValue(OUString sValue, bool bForce)
+ : m_sValue(std::move(sValue))
+ , m_bForceString(bForce)
+{
+}
+
+RTFValue::RTFValue(const RTFSprms& rAttributes)
+ : m_pAttributes(new RTFSprms(rAttributes))
+{
+}
+
+RTFValue::RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms)
+ : m_pAttributes(new RTFSprms(rAttributes))
+ , m_pSprms(new RTFSprms(rSprms))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<drawing::XShape> xShape)
+ : m_xShape(std::move(xShape))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<io::XInputStream> xStream)
+ : m_xStream(std::move(xStream))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<embed::XEmbeddedObject> xObject)
+ : m_xObject(std::move(xObject))
+{
+}
+
+RTFValue::RTFValue(const RTFShape& aShape)
+ : m_pShape(new RTFShape(aShape))
+{
+}
+
+RTFValue::RTFValue(const RTFPicture& rPicture)
+ : m_pPicture(new RTFPicture(rPicture))
+{
+}
+
+RTFValue::~RTFValue() = default;
+
+int RTFValue::getInt() const { return m_nValue; }
+
+OUString RTFValue::getString() const
+{
+ if (!m_sValue.isEmpty() || m_bForceString)
+ return m_sValue;
+
+ return OUString::number(m_nValue);
+}
+
+void RTFValue::setString(const OUString& sValue) { m_sValue = sValue; }
+
+uno::Any RTFValue::getAny() const
+{
+ uno::Any ret;
+ if (!m_sValue.isEmpty() || m_bForceString)
+ ret <<= m_sValue;
+ else if (m_xShape.is())
+ ret <<= m_xShape;
+ else if (m_xStream.is())
+ ret <<= m_xStream;
+ else if (m_xObject.is())
+ ret <<= m_xObject;
+ else
+ ret <<= static_cast<sal_Int32>(m_nValue);
+ return ret;
+}
+
+RTFShape& RTFValue::getShape() const
+{
+ if (!m_pShape)
+ m_pShape = new RTFShape();
+ return *m_pShape;
+}
+
+RTFPicture& RTFValue::getPicture() const
+{
+ if (!m_pPicture)
+ m_pPicture = new RTFPicture;
+ return *m_pPicture;
+}
+
+writerfilter::Reference<Properties>::Pointer_t RTFValue::getProperties()
+{
+ return new RTFReferenceProperties(getAttributes(), getSprms());
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t RTFValue::getBinary()
+{
+ return writerfilter::Reference<BinaryObj>::Pointer_t();
+}
+
+#ifdef DBG_UTIL
+std::string RTFValue::toString() const
+{
+ if (!m_sValue.isEmpty() || m_bForceString)
+ return OUStringToOString(m_sValue, RTL_TEXTENCODING_UTF8).getStr();
+
+ return OString::number(m_nValue).getStr();
+}
+#endif
+
+RTFValue* RTFValue::Clone() const
+{
+ return new RTFValue(m_nValue, m_sValue, m_pAttributes.get(), m_pSprms.get(), m_xShape,
+ m_xStream, m_xObject, m_bForceString, m_pShape.get(), m_pPicture.get());
+}
+
+RTFValue* RTFValue::CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) const
+{
+ return new RTFValue(m_nValue, m_sValue, &rAttributes, &rSprms, m_xShape, m_xStream, m_xObject,
+ m_bForceString, m_pShape.get(), m_pPicture.get());
+}
+
+bool RTFValue::equals(const RTFValue& rOther) const
+{
+ if (m_nValue != rOther.m_nValue)
+ return false;
+ if (m_sValue != rOther.m_sValue)
+ return false;
+
+ if (m_pAttributes && rOther.m_pAttributes)
+ {
+ if (m_pAttributes->size() != rOther.m_pAttributes->size())
+ return false;
+ if (!m_pAttributes->equals(rOther))
+ return false;
+ }
+ else if (m_pAttributes && m_pAttributes->size())
+ {
+ return false;
+ }
+ else if (rOther.m_pAttributes && rOther.m_pAttributes->size())
+ {
+ return false;
+ }
+
+ if (m_pSprms && rOther.m_pSprms)
+ {
+ if (m_pSprms->size() != rOther.m_pSprms->size())
+ return false;
+ if (!m_pSprms->equals(rOther))
+ return false;
+ }
+ else if (m_pSprms && m_pSprms->size())
+ {
+ return false;
+ }
+ else if (rOther.m_pSprms && rOther.m_pSprms->size())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+RTFSprms& RTFValue::getAttributes() const
+{
+ if (!m_pAttributes)
+ m_pAttributes = new RTFSprms();
+ return *m_pAttributes;
+}
+
+RTFSprms& RTFValue::getSprms() const
+{
+ if (!m_pSprms)
+ m_pSprms = new RTFSprms();
+ return *m_pSprms;
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfvalue.hxx b/writerfilter/source/rtftok/rtfvalue.hxx
new file mode 100644
index 000000000..4f37a5dcb
--- /dev/null
+++ b/writerfilter/source/rtftok/rtfvalue.hxx
@@ -0,0 +1,85 @@
+/* -*- 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/.
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace com::sun::star
+{
+namespace embed
+{
+class XEmbeddedObject;
+}
+namespace io
+{
+class XInputStream;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFSprms;
+class RTFShape;
+class RTFPicture;
+/// Value of an RTF keyword
+class RTFValue : public Value
+{
+ RTFValue(int nValue, OUString sValue, const RTFSprms* pAttributes, const RTFSprms* pSprms,
+ css::uno::Reference<css::drawing::XShape> xShape,
+ css::uno::Reference<css::io::XInputStream> xStream,
+ css::uno::Reference<css::embed::XEmbeddedObject> xObject, bool bForceString,
+ const RTFShape* pShape, const RTFPicture* pPicture);
+
+public:
+ using Pointer_t = tools::SvRef<RTFValue>;
+ RTFValue();
+ explicit RTFValue(int nValue);
+ RTFValue(OUString sValue, bool bForce = false);
+ explicit RTFValue(const RTFSprms& rAttributes);
+ RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms);
+ explicit RTFValue(css::uno::Reference<css::drawing::XShape> xShape);
+ explicit RTFValue(css::uno::Reference<css::io::XInputStream> xStream);
+ explicit RTFValue(css::uno::Reference<css::embed::XEmbeddedObject> xObject);
+ explicit RTFValue(const RTFShape& aShape);
+ explicit RTFValue(const RTFPicture& rPicture);
+ ~RTFValue() override;
+ void setString(const OUString& sValue);
+ int getInt() const override;
+ OUString getString() const override;
+ css::uno::Any getAny() const override;
+ writerfilter::Reference<Properties>::Pointer_t getProperties() override;
+ writerfilter::Reference<BinaryObj>::Pointer_t getBinary() override;
+#ifdef DBG_UTIL
+ std::string toString() const override;
+#endif
+ RTFValue* Clone() const;
+ RTFValue* CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) const;
+ RTFSprms& getAttributes() const;
+ RTFSprms& getSprms() const;
+ RTFShape& getShape() const;
+ RTFPicture& getPicture() const;
+ bool equals(const RTFValue& rOther) const;
+ RTFValue& operator=(RTFValue const& rOther) = delete;
+
+private:
+ int m_nValue = 0;
+ OUString m_sValue;
+ mutable tools::SvRef<RTFSprms> m_pAttributes;
+ mutable tools::SvRef<RTFSprms> m_pSprms;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ css::uno::Reference<css::io::XInputStream> m_xStream;
+ css::uno::Reference<css::embed::XEmbeddedObject> m_xObject;
+ bool m_bForceString = false;
+ mutable tools::SvRef<RTFShape> m_pShape;
+ mutable tools::SvRef<RTFPicture> m_pPicture;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/util/writerfilter.component b/writerfilter/util/writerfilter.component
new file mode 100644
index 000000000..63e5931e8
--- /dev/null
+++ b/writerfilter/util/writerfilter.component
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.Writer.WriterFilter"
+ constructor="com_sun_star_comp_Writer_WriterFilter_get_implementation">
+ <service name="com.sun.star.document.ExportFilter"/>
+ <service name="com.sun.star.document.ImportFilter"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.Writer.RtfFilter"
+ constructor="com_sun_star_comp_Writer_RtfFilter_get_implementation">
+ <service name="com.sun.star.document.ImportFilter"/>
+ <service name="com.sun.star.document.ExportFilter"/>
+ </implementation>
+</component>