diff options
Diffstat (limited to 'writerfilter')
309 files changed, 87359 insertions, 0 deletions
diff --git a/writerfilter/CppunitTest_writerfilter_dmapper.mk b/writerfilter/CppunitTest_writerfilter_dmapper.mk new file mode 100644 index 000000000..7fe8b9035 --- /dev/null +++ b/writerfilter/CppunitTest_writerfilter_dmapper.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_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 \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,writerfilter_dmapper, \ + basegfx \ + comphelper \ + cppu \ + oox \ + sal \ + test \ + unotest \ +)) + +$(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..db038292e --- /dev/null +++ b/writerfilter/CppunitTest_writerfilter_rtftok.mk @@ -0,0 +1,50 @@ +# -*- 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/rtfsdrimport \ + writerfilter/qa/cppunittests/rtftok/rtfsprm \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,writerfilter_rtftok, \ + basegfx \ + comphelper \ + cppu \ + oox \ + sal \ + test \ + unotest \ +)) + +$(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..8d7b3d22b --- /dev/null +++ b/writerfilter/CustomTarget_source.mk @@ -0,0 +1,110 @@ +# -*- 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 \ + 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..2dd4de4a4 --- /dev/null +++ b/writerfilter/IwyuFilter_writerfilter.yaml @@ -0,0 +1,66 @@ +--- +assumeFilename: writerfilter/source/filter/WriterFilter.cxx +blacklist: + 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..add7c20bb --- /dev/null +++ b/writerfilter/Library_writerfilter.mk @@ -0,0 +1,136 @@ +# -*- 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)) + +$(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/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/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 b/writerfilter/README new file mode 100644 index 000000000..7a9c8cc57 --- /dev/null +++ b/writerfilter/README @@ -0,0 +1,20 @@ +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 Binary files differnew file mode 100644 index 000000000..15adb9670 --- /dev/null +++ b/writerfilter/documentation/doxygen/images/doctok.png diff --git a/writerfilter/documentation/doxygen/images/ooxmlimportchain.png b/writerfilter/documentation/doxygen/images/ooxmlimportchain.png Binary files differnew file mode 100644 index 000000000..509f1cab5 --- /dev/null +++ b/writerfilter/documentation/doxygen/images/ooxmlimportchain.png diff --git a/writerfilter/documentation/ooxml/model.rng b/writerfilter/documentation/ooxml/model.rng new file mode 100644 index 000000000..a29e14992 --- /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 subelemenents 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/DomainMapperFactory.hxx b/writerfilter/inc/dmapper/DomainMapperFactory.hxx new file mode 100644 index 000000000..624805cad --- /dev/null +++ b/writerfilter/inc/dmapper/DomainMapperFactory.hxx @@ -0,0 +1,54 @@ +/* + * 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_INC_DMAPPER_DOMAINMAPPERFACTORY_HXX +#define INCLUDED_WRITERFILTER_INC_DMAPPER_DOMAINMAPPERFACTORY_HXX + +#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 +{ +namespace 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 dmapper +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_INC_DMAPPER_DOMAINMAPPERFACTORY_HXX + +/* 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..c566eec17 --- /dev/null +++ b/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx @@ -0,0 +1,36 @@ +/* + * 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_INC_DMAPPER_GRAPHICZORDERHELPER_HXX +#define INCLUDED_WRITERFILTER_INC_DMAPPER_GRAPHICZORDERHELPER_HXX + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <map> + +namespace writerfilter +{ +namespace 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 dmapper +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_INC_DMAPPER_GRAPHICZORDERHELPER_HXX + +/* 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..284e9982f --- /dev/null +++ b/writerfilter/inc/dmapper/resourcemodel.hxx @@ -0,0 +1,406 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_INC_DMAPPER_RESOURCEMODEL_HXX +#define INCLUDED_WRITERFILTER_INC_DMAPPER_RESOURCEMODEL_HXX + +#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 { + +/** + 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 cFieldStart = 0x13; +const sal_uInt8 cFieldSep = 0x14; +const sal_uInt8 cFieldEnd = 0x15; + +/** + 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( ) { }; + + /** + 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 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; + +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; + +} + +#endif // INCLUDED_WRITERFILTER_INC_DMAPPER_RESOURCEMODEL_HXX + +/* 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..82dd78c77 --- /dev/null +++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx @@ -0,0 +1,258 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_INC_OOXML_OOXMLDOCUMENT_HXX +#define INCLUDED_WRITERFILTER_INC_OOXML_OOXMLDOCUMENT_HXX + +#include <sal/types.h> +#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/sax/XFastShapeContextHandler.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> + +/** + @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 { +namespace ooxml +{ + +class OOXMLStream : public virtual SvRefBase +{ +public: + enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING, + FOOTNOTES, ENDNOTES, COMMENTS, 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 css::uno::Reference<css::xml::sax::XFastShapeContextHandler> getShapeContext( ) = 0; + virtual void setShapeContext( css::uno::Reference<css::xml::sax::XFastShapeContextHandler> 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::uno::Any> > 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); + +}} +#endif // INCLUDED_WRITERFILTER_INC_OOXML_OOXMLDOCUMENT_HXX + +/* 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..9cdf13de1 --- /dev/null +++ b/writerfilter/inc/ooxml/QNameToString.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_INC_OOXML_QNAMETOSTRING_HXX +#define INCLUDED_WRITERFILTER_INC_OOXML_QNAMETOSTRING_HXX + +#include <string> +#include <dmapper/resourcemodel.hxx> + +namespace writerfilter +{ + +#ifdef DBG_UTIL + std::string QNameToString(Id); +#endif + +} + +#endif // INCLUDED_WRITERFILTER_INC_OOXML_QNAMETOSTRING_HXX + +/* 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..165ea77c7 --- /dev/null +++ b/writerfilter/inc/pch/precompiled_writerfilter.hxx @@ -0,0 +1,115 @@ +/* -*- 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 2020-04-25 20:56:04 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 +*/ + +#if PCH_LEVEL >= 1 +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <functional> +#include <iomanip> +#include <memory> +#include <ostream> +#include <type_traits> +#include <utility> +#include <vector> +#include <boost/logic/tribool.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/strbuf.h> +#include <rtl/string.hxx> +#include <rtl/stringconcat.hxx> +#include <rtl/stringutils.hxx> +#include <rtl/tencinfo.h> +#include <rtl/textenc.h> +#include <rtl/uri.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/config.h> +#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 <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/comphelperdllapi.h> +#include <comphelper/propertysequence.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/sequenceashashmap.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/typed_flags_set.hxx> +#include <oox/dllapi.h> +#include <oox/drawingml/drawingmltypes.hxx> +#include <ooxml/resourceids.hxx> +#include <sfx2/dllapi.h> +#include <tools/color.hxx> +#include <tools/diagnose_ex.h> +#include <tools/gen.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..55b1fbee3 --- /dev/null +++ b/writerfilter/inc/rtftok/RTFDocument.hxx @@ -0,0 +1,52 @@ +/* + * 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_INC_RTFTOK_RTFDOCUMENT_HXX +#define INCLUDED_WRITERFILTER_INC_RTFTOK_RTFDOCUMENT_HXX + +#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 +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_INC_RTFTOK_RTFDOCUMENT_HXX + +/* 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..646d0968b --- /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(); +} + +char const DATA_DIRECTORY[] = "/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..d6e6830b8 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper.cxx @@ -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/. + */ + +#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 <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(); +} + +char const DATA_DIRECTORY[] = "/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); +} +} + +/* 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..a1a7595ce --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapperTableHandler.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/table/BorderLine2.hpp> +#include <com/sun/star/text/XTextTable.hpp> +#include <com/sun/star/text/XTextTablesSupplier.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(); +} + +char const DATA_DIRECTORY[] = "/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_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..ade216411 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx @@ -0,0 +1,109 @@ +/* -*- 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> + +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(); +} + +char const DATA_DIRECTORY[] = "/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; + OUStringLiteral aProp("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>()); +} +} + +/* 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..28a0cc178 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx @@ -0,0 +1,170 @@ +/* -*- 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/container/XNamed.hpp> +#include <com/sun/star/text/RelOrientation.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(); +} + +char const DATA_DIRECTORY[] = "/writerfilter/qa/cppunittests/dmapper/data/"; + +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()); +} +} + +/* 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..71b3ab80e --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/PropertyMap.cxx @@ -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/. + */ + +#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> + +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(); +} + +char const DATA_DIRECTORY[] = "/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()); +} +} + +/* 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..d48a35e25 --- /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(); +} + +char const DATA_DIRECTORY[] = "/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 Binary files differnew file mode 100644 index 000000000..d0bc40e23 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/1cell-insidev-rightborder.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docx b/writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docx Binary files differnew file mode 100644 index 000000000..3eb5b0e2f --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/draw-shape-inline-effect.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docx b/writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docx Binary files differnew file mode 100644 index 000000000..3840b2550 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/floating-table-header.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docx b/writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docx Binary files differnew file mode 100644 index 000000000..c9fee726b --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/group-shape-rotation.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docx b/writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docx Binary files differnew file mode 100644 index 000000000..93932c470 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/inline-anchored-zorder.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docx b/writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docx Binary files differnew file mode 100644 index 000000000..3792285f4 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/inline-inshape-anchored-zorder.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docx b/writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docx Binary files differnew file mode 100644 index 000000000..34f24a3e2 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/large-para-top-margin.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docx b/writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docx Binary files differnew file mode 100644 index 000000000..f908d94b5 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/num-restart-style-parent.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docx b/writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docx Binary files differnew file mode 100644 index 000000000..376a1fb1e --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/page-break-footer-table.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docx b/writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docx Binary files differnew file mode 100644 index 000000000..1f7a281e8 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/relfromh-insidemargin.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docx b/writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docx Binary files differnew file mode 100644 index 000000000..6c0f8a79c --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/semi-transparent-text.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf129205.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf129205.docx Binary files differnew file mode 100644 index 000000000..4289254d0 --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/tdf129205.docx diff --git a/writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docx b/writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docx Binary files differnew file mode 100644 index 000000000..1835a130d --- /dev/null +++ b/writerfilter/qa/cppunittests/dmapper/data/wrap-poly-crop.docx 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 Binary files differnew file mode 100644 index 000000000..5cd42052c --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2005-2971-1.rtf 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 Binary files differnew file mode 100644 index 000000000..0c639810d --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/CVE-2010-3451-1.rtf 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 Binary files differnew file mode 100644 index 000000000..18795f5be --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/EDB-18749-1.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtf Binary files differnew file mode 100644 index 000000000..63465b073 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-1.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtf Binary files differnew file mode 100644 index 000000000..f0152b0fa --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/destinationtest-2.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtf Binary files differnew file mode 100644 index 000000000..59c3630a7 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/nopropertyset-1.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtf Binary files differnew file mode 100644 index 000000000..041891713 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/popstate-1.rtf 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 Binary files differnew file mode 100644 index 000000000..130ff3f23 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/propheight-1.rtf 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 Binary files differnew file mode 100644 index 000000000..a03be130d --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-5.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtf Binary files differnew file mode 100644 index 000000000..67a0ea175 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-6.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtf Binary files differnew file mode 100644 index 000000000..df41b1f88 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/tablemanager-7.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtf Binary files differnew file mode 100644 index 000000000..7cdb94ab2 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-1.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtf Binary files differnew file mode 100644 index 000000000..c0bd2691c --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/fail/topcontext-2.rtf 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 Binary files differnew file mode 100644 index 000000000..da97fba57 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2964-1.rtf 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 Binary files differnew file mode 100644 index 000000000..70321707f --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-1.rtf 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 Binary files differnew file mode 100644 index 000000000..c5ea695bc --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2005-2972-2.rtf 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 Binary files differnew file mode 100644 index 000000000..757cfe62e --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2007-0245-1.rtf 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 Binary files differnew file mode 100644 index 000000000..4dac58c0c --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2010-3333-1.rtf 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 Binary files differnew file mode 100644 index 000000000..44d28adcb --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-1.rtf 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 Binary files differnew file mode 100644 index 000000000..64109fbe2 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-2014-1761-2.rtf 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 Binary files differnew file mode 100644 index 000000000..44ed96982 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/CVE-pseudo-2009-0238-1.rtf 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 Binary files differnew file mode 100644 index 000000000..f4a736920 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18754-1.rtf 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 Binary files differnew file mode 100644 index 000000000..794f325c5 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/EDB-18940-1.rtf 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 Binary files differnew file mode 100644 index 000000000..3fe4b2876 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/parser-state-1.rtf 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 Binary files differnew file mode 100644 index 000000000..0925203f8 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/sf_edeb1eb341ad4c8608af9396952724a0-41170.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtf Binary files differnew file mode 100644 index 000000000..5b34e7f61 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-1.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtf Binary files differnew file mode 100644 index 000000000..58328edc9 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-2.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtf Binary files differnew file mode 100644 index 000000000..9fd589214 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-3.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtf Binary files differnew file mode 100644 index 000000000..28093f25a --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/tablemanager-4.rtf diff --git a/writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtf b/writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtf Binary files differnew file mode 100644 index 000000000..847e165c5 --- /dev/null +++ b/writerfilter/qa/cppunittests/filters-test/data/pass/valuelist-1.rtf 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..cd1863259 --- /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::makeAny(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("/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..983e6fc87 --- /dev/null +++ b/writerfilter/qa/cppunittests/misc/misc.cxx @@ -0,0 +1,178 @@ +/* -*- 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/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/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/rtfsdrimport.cxx b/writerfilter/qa/cppunittests/rtftok/rtfsdrimport.cxx new file mode 100644 index 000000000..64c679f6e --- /dev/null +++ b/writerfilter/qa/cppunittests/rtftok/rtfsdrimport.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 <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/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(); +} + +char const DATA_DIRECTORY[] = "/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_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..9f5ec63e8 --- /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(); +} + +char const DATA_DIRECTORY[] = "/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/documents/Bookmark1.doc b/writerfilter/qa/documents/Bookmark1.doc Binary files differnew file mode 100644 index 000000000..71565d979 --- /dev/null +++ b/writerfilter/qa/documents/Bookmark1.doc diff --git a/writerfilter/qa/documents/Bookmark1.docx b/writerfilter/qa/documents/Bookmark1.docx Binary files differnew file mode 100644 index 000000000..a00eab97a --- /dev/null +++ b/writerfilter/qa/documents/Bookmark1.docx diff --git a/writerfilter/qa/documents/CellAlignment.doc b/writerfilter/qa/documents/CellAlignment.doc Binary files differnew file mode 100644 index 000000000..57a6745b4 --- /dev/null +++ b/writerfilter/qa/documents/CellAlignment.doc diff --git a/writerfilter/qa/documents/Footnote.doc b/writerfilter/qa/documents/Footnote.doc Binary files differnew file mode 100644 index 000000000..9098c91a9 --- /dev/null +++ b/writerfilter/qa/documents/Footnote.doc diff --git a/writerfilter/qa/documents/Footnote.docx b/writerfilter/qa/documents/Footnote.docx Binary files differnew file mode 100644 index 000000000..a20d2747a --- /dev/null +++ b/writerfilter/qa/documents/Footnote.docx diff --git a/writerfilter/qa/documents/HeaderFooter.doc b/writerfilter/qa/documents/HeaderFooter.doc Binary files differnew file mode 100644 index 000000000..9b023b485 --- /dev/null +++ b/writerfilter/qa/documents/HeaderFooter.doc diff --git a/writerfilter/qa/documents/HeaderFooter.docx b/writerfilter/qa/documents/HeaderFooter.docx Binary files differnew file mode 100644 index 000000000..1c550b4d5 --- /dev/null +++ b/writerfilter/qa/documents/HeaderFooter.docx diff --git a/writerfilter/qa/documents/IndentedTable.doc b/writerfilter/qa/documents/IndentedTable.doc Binary files differnew file mode 100644 index 000000000..b96ca77b0 --- /dev/null +++ b/writerfilter/qa/documents/IndentedTable.doc diff --git a/writerfilter/qa/documents/IndentedTable1.docx b/writerfilter/qa/documents/IndentedTable1.docx Binary files differnew file mode 100644 index 000000000..2499549d3 --- /dev/null +++ b/writerfilter/qa/documents/IndentedTable1.docx diff --git a/writerfilter/qa/documents/MergedTable.doc b/writerfilter/qa/documents/MergedTable.doc Binary files differnew file mode 100644 index 000000000..0061045f6 --- /dev/null +++ b/writerfilter/qa/documents/MergedTable.doc diff --git a/writerfilter/qa/documents/MergedTable.docx b/writerfilter/qa/documents/MergedTable.docx Binary files differnew file mode 100644 index 000000000..f379c0704 --- /dev/null +++ b/writerfilter/qa/documents/MergedTable.docx diff --git a/writerfilter/qa/documents/MergedTable_3_3.doc b/writerfilter/qa/documents/MergedTable_3_3.doc Binary files differnew file mode 100644 index 000000000..13b727590 --- /dev/null +++ b/writerfilter/qa/documents/MergedTable_3_3.doc diff --git a/writerfilter/qa/documents/MergedTable_3_3.docx b/writerfilter/qa/documents/MergedTable_3_3.docx Binary files differnew file mode 100644 index 000000000..6fd7447bd --- /dev/null +++ b/writerfilter/qa/documents/MergedTable_3_3.docx diff --git a/writerfilter/qa/documents/MultiMergedTable.docx b/writerfilter/qa/documents/MultiMergedTable.docx Binary files differnew file mode 100644 index 000000000..34fcdac2d --- /dev/null +++ b/writerfilter/qa/documents/MultiMergedTable.docx diff --git a/writerfilter/qa/documents/MultiWrapping1.docx b/writerfilter/qa/documents/MultiWrapping1.docx Binary files differnew file mode 100644 index 000000000..ce58b09b8 --- /dev/null +++ b/writerfilter/qa/documents/MultiWrapping1.docx diff --git a/writerfilter/qa/documents/Paragraph with footnote.doc b/writerfilter/qa/documents/Paragraph with footnote.doc Binary files differnew file mode 100644 index 000000000..eaf22b5ef --- /dev/null +++ b/writerfilter/qa/documents/Paragraph with footnote.doc diff --git a/writerfilter/qa/documents/Paragraph with footnote.docx b/writerfilter/qa/documents/Paragraph with footnote.docx Binary files differnew file mode 100644 index 000000000..fbaac59dc --- /dev/null +++ b/writerfilter/qa/documents/Paragraph with footnote.docx diff --git a/writerfilter/qa/documents/Picture1.docx b/writerfilter/qa/documents/Picture1.docx Binary files differnew file mode 100644 index 000000000..0a55180a9 --- /dev/null +++ b/writerfilter/qa/documents/Picture1.docx diff --git a/writerfilter/qa/documents/RedlineTest.docx b/writerfilter/qa/documents/RedlineTest.docx Binary files differnew file mode 100644 index 000000000..dda53c63f --- /dev/null +++ b/writerfilter/qa/documents/RedlineTest.docx diff --git a/writerfilter/qa/documents/RowHeight.doc b/writerfilter/qa/documents/RowHeight.doc Binary files differnew file mode 100644 index 000000000..5db85a486 --- /dev/null +++ b/writerfilter/qa/documents/RowHeight.doc diff --git a/writerfilter/qa/documents/RowHeight.docx b/writerfilter/qa/documents/RowHeight.docx Binary files differnew file mode 100644 index 000000000..ffdb7808b --- /dev/null +++ b/writerfilter/qa/documents/RowHeight.docx diff --git a/writerfilter/qa/documents/StandardFontAlbertus.doc b/writerfilter/qa/documents/StandardFontAlbertus.doc Binary files differnew file mode 100644 index 000000000..f68d3d6cd --- /dev/null +++ b/writerfilter/qa/documents/StandardFontAlbertus.doc diff --git a/writerfilter/qa/documents/Table5CellBorders.doc b/writerfilter/qa/documents/Table5CellBorders.doc Binary files differnew file mode 100644 index 000000000..ab72e558b --- /dev/null +++ b/writerfilter/qa/documents/Table5CellBorders.doc diff --git a/writerfilter/qa/documents/Table5CellBorders.docx b/writerfilter/qa/documents/Table5CellBorders.docx Binary files differnew file mode 100644 index 000000000..6b2781756 --- /dev/null +++ b/writerfilter/qa/documents/Table5CellBorders.docx diff --git a/writerfilter/qa/documents/TableDifferentColumns.doc b/writerfilter/qa/documents/TableDifferentColumns.doc Binary files differnew file mode 100644 index 000000000..b1871cf3f --- /dev/null +++ b/writerfilter/qa/documents/TableDifferentColumns.doc diff --git a/writerfilter/qa/documents/TableDifferentColumns.docx b/writerfilter/qa/documents/TableDifferentColumns.docx Binary files differnew file mode 100644 index 000000000..0503327dd --- /dev/null +++ b/writerfilter/qa/documents/TableDifferentColumns.docx diff --git a/writerfilter/qa/documents/TablePreferredWidth.doc b/writerfilter/qa/documents/TablePreferredWidth.doc Binary files differnew file mode 100644 index 000000000..a436d441c --- /dev/null +++ b/writerfilter/qa/documents/TablePreferredWidth.doc diff --git a/writerfilter/qa/documents/TablePreferredWidth.docx b/writerfilter/qa/documents/TablePreferredWidth.docx Binary files differnew file mode 100644 index 000000000..719b3888a --- /dev/null +++ b/writerfilter/qa/documents/TablePreferredWidth.docx diff --git a/writerfilter/qa/documents/TableRowProperties.doc b/writerfilter/qa/documents/TableRowProperties.doc Binary files differnew file mode 100644 index 000000000..ee3e845ad --- /dev/null +++ b/writerfilter/qa/documents/TableRowProperties.doc diff --git a/writerfilter/qa/documents/TableRowProperties.docx b/writerfilter/qa/documents/TableRowProperties.docx Binary files differnew file mode 100644 index 000000000..775d63c97 --- /dev/null +++ b/writerfilter/qa/documents/TableRowProperties.docx diff --git a/writerfilter/qa/documents/VertAlign1.doc b/writerfilter/qa/documents/VertAlign1.doc Binary files differnew file mode 100644 index 000000000..57158b6f2 --- /dev/null +++ b/writerfilter/qa/documents/VertAlign1.doc diff --git a/writerfilter/qa/documents/WordOLE.docx b/writerfilter/qa/documents/WordOLE.docx Binary files differnew file mode 100644 index 000000000..4cf08d425 --- /dev/null +++ b/writerfilter/qa/documents/WordOLE.docx diff --git a/writerfilter/qa/documents/align1.doc b/writerfilter/qa/documents/align1.doc Binary files differnew file mode 100644 index 000000000..9317432b3 --- /dev/null +++ b/writerfilter/qa/documents/align1.doc diff --git a/writerfilter/qa/documents/bookmark2.doc b/writerfilter/qa/documents/bookmark2.doc Binary files differnew file mode 100644 index 000000000..83cdcadff --- /dev/null +++ b/writerfilter/qa/documents/bookmark2.doc diff --git a/writerfilter/qa/documents/docx/numbering/num-1.docx b/writerfilter/qa/documents/docx/numbering/num-1.docx Binary files differnew file mode 100644 index 000000000..b5e5ffb0b --- /dev/null +++ b/writerfilter/qa/documents/docx/numbering/num-1.docx diff --git a/writerfilter/qa/documents/docx/pictures/Word DocumentOffice 2007 Format Sample6.docx b/writerfilter/qa/documents/docx/pictures/Word DocumentOffice 2007 Format Sample6.docx Binary files differnew file mode 100644 index 000000000..eb0d4c256 --- /dev/null +++ b/writerfilter/qa/documents/docx/pictures/Word DocumentOffice 2007 Format Sample6.docx diff --git a/writerfilter/qa/documents/docx/pictures/i97645 New example.docx b/writerfilter/qa/documents/docx/pictures/i97645 New example.docx Binary files differnew file mode 100644 index 000000000..6cda8590a --- /dev/null +++ b/writerfilter/qa/documents/docx/pictures/i97645 New example.docx diff --git a/writerfilter/qa/documents/docx/pictures/test-image.docx b/writerfilter/qa/documents/docx/pictures/test-image.docx Binary files differnew file mode 100644 index 000000000..fff642451 --- /dev/null +++ b/writerfilter/qa/documents/docx/pictures/test-image.docx diff --git a/writerfilter/qa/documents/docx/pictures/test-image1.docx b/writerfilter/qa/documents/docx/pictures/test-image1.docx Binary files differnew file mode 100644 index 000000000..bdcc8e088 --- /dev/null +++ b/writerfilter/qa/documents/docx/pictures/test-image1.docx diff --git a/writerfilter/qa/documents/docx/pictures/test.docx b/writerfilter/qa/documents/docx/pictures/test.docx Binary files differnew file mode 100644 index 000000000..72e3c01f3 --- /dev/null +++ b/writerfilter/qa/documents/docx/pictures/test.docx diff --git a/writerfilter/qa/documents/docx/redlines/test-review-brk.docx b/writerfilter/qa/documents/docx/redlines/test-review-brk.docx Binary files differnew file mode 100644 index 000000000..7c884505f --- /dev/null +++ b/writerfilter/qa/documents/docx/redlines/test-review-brk.docx diff --git a/writerfilter/qa/documents/docx/redlines/test-review-para.docx b/writerfilter/qa/documents/docx/redlines/test-review-para.docx Binary files differnew file mode 100644 index 000000000..9bb87be94 --- /dev/null +++ b/writerfilter/qa/documents/docx/redlines/test-review-para.docx diff --git a/writerfilter/qa/documents/docx/redlines/test-review-stack.docx b/writerfilter/qa/documents/docx/redlines/test-review-stack.docx Binary files differnew file mode 100644 index 000000000..18b3e3063 --- /dev/null +++ b/writerfilter/qa/documents/docx/redlines/test-review-stack.docx diff --git a/writerfilter/qa/documents/docx/tables/Table in B2.docx b/writerfilter/qa/documents/docx/tables/Table in B2.docx Binary files differnew file mode 100644 index 000000000..4295cec35 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/Table in B2.docx diff --git a/writerfilter/qa/documents/docx/tables/nested-tables.docx b/writerfilter/qa/documents/docx/tables/nested-tables.docx Binary files differnew file mode 100644 index 000000000..844b29de8 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/nested-tables.docx diff --git a/writerfilter/qa/documents/docx/tables/nested-tables2.docx b/writerfilter/qa/documents/docx/tables/nested-tables2.docx Binary files differnew file mode 100644 index 000000000..0602ba4fa --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/nested-tables2.docx diff --git a/writerfilter/qa/documents/docx/tables/nested-tables3.docx b/writerfilter/qa/documents/docx/tables/nested-tables3.docx Binary files differnew file mode 100644 index 000000000..7b61d1472 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/nested-tables3.docx diff --git a/writerfilter/qa/documents/docx/tables/nested-tables4.docx b/writerfilter/qa/documents/docx/tables/nested-tables4.docx Binary files differnew file mode 100644 index 000000000..6a17180a4 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/nested-tables4.docx diff --git a/writerfilter/qa/documents/docx/tables/nested-tables5.docx b/writerfilter/qa/documents/docx/tables/nested-tables5.docx Binary files differnew file mode 100644 index 000000000..2247b64a7 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/nested-tables5.docx diff --git a/writerfilter/qa/documents/docx/tables/parentinvguid.docx b/writerfilter/qa/documents/docx/tables/parentinvguid.docx Binary files differnew file mode 100644 index 000000000..8f859fe43 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/parentinvguid.docx diff --git a/writerfilter/qa/documents/docx/tables/table in A1.docx b/writerfilter/qa/documents/docx/tables/table in A1.docx Binary files differnew file mode 100644 index 000000000..d4161eaaa --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/table in A1.docx diff --git a/writerfilter/qa/documents/docx/tables/table-styles.docx b/writerfilter/qa/documents/docx/tables/table-styles.docx Binary files differnew file mode 100644 index 000000000..2136f9d0f --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/table-styles.docx diff --git a/writerfilter/qa/documents/docx/tables/test-grid.docx b/writerfilter/qa/documents/docx/tables/test-grid.docx Binary files differnew file mode 100644 index 000000000..09f95d1a0 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/test-grid.docx diff --git a/writerfilter/qa/documents/docx/tables/test-paras.docx b/writerfilter/qa/documents/docx/tables/test-paras.docx Binary files differnew file mode 100644 index 000000000..0cef4ae05 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/test-paras.docx diff --git a/writerfilter/qa/documents/docx/tables/test-simple.docx b/writerfilter/qa/documents/docx/tables/test-simple.docx Binary files differnew file mode 100644 index 000000000..2c0c08427 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/test-simple.docx diff --git a/writerfilter/qa/documents/docx/tables/two-tables.docx b/writerfilter/qa/documents/docx/tables/two-tables.docx Binary files differnew file mode 100644 index 000000000..d2e99d3ac --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/two-tables.docx diff --git a/writerfilter/qa/documents/docx/tables/updatejpegprocessing.docx b/writerfilter/qa/documents/docx/tables/updatejpegprocessing.docx Binary files differnew file mode 100644 index 000000000..f62eb61df --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/updatejpegprocessing.docx diff --git a/writerfilter/qa/documents/docx/tables/~$sted-tables3.docx b/writerfilter/qa/documents/docx/tables/~$sted-tables3.docx Binary files differnew file mode 100644 index 000000000..bfea337b7 --- /dev/null +++ b/writerfilter/qa/documents/docx/tables/~$sted-tables3.docx diff --git a/writerfilter/qa/documents/docx/test-page-format.docx b/writerfilter/qa/documents/docx/test-page-format.docx Binary files differnew file mode 100644 index 000000000..eba8dea3e --- /dev/null +++ b/writerfilter/qa/documents/docx/test-page-format.docx diff --git a/writerfilter/qa/documents/fields.doc b/writerfilter/qa/documents/fields.doc Binary files differnew file mode 100644 index 000000000..8ad1a3738 --- /dev/null +++ b/writerfilter/qa/documents/fields.doc diff --git a/writerfilter/qa/documents/fields.docx b/writerfilter/qa/documents/fields.docx new file mode 100644 index 000000000..4eaa60393 --- /dev/null +++ b/writerfilter/qa/documents/fields.docx @@ -0,0 +1 @@ +PK\"%ã·øåÙƒÑÚšl µw%ë=–“^i7+ÙÇä%¿g&á”0ÞAÉ6€l4¼¾
\ No newline at end of file diff --git a/writerfilter/qa/documents/multimerge2.docx b/writerfilter/qa/documents/multimerge2.docx new file mode 100644 index 000000000..8f594c137 --- /dev/null +++ b/writerfilter/qa/documents/multimerge2.docx @@ -0,0 +1,2 @@ +PKÀQ¥òÑ +¤×8ãAÈO1~ÛëÝqé‚Ãk6<A%³ç5}Þ*‰`Ë·k®’‰Œ–I)_:õƒ%ß1ÔÙœIsÒ
É`ü C]9N°ë{#k¢VEÄWaI_ù¨¸òrai†¢æ€N_UZBÛ_£…è%¤Dž[S´+´Ûë?ª#áÆ@ú[Ü.zÒ9Ž>$N{9›êÍ+P9Y ¢†vuÇGD²ìÃï»ÆoR€”wàͳ¶
ÌIÊŠ~‰‰˜
\ No newline at end of file diff --git a/writerfilter/qa/documents/runProperties.doc b/writerfilter/qa/documents/runProperties.doc Binary files differnew file mode 100644 index 000000000..b8b5854df --- /dev/null +++ b/writerfilter/qa/documents/runProperties.doc diff --git a/writerfilter/qa/documents/runProperties.docx b/writerfilter/qa/documents/runProperties.docx Binary files differnew file mode 100644 index 000000000..8e14dc923 --- /dev/null +++ b/writerfilter/qa/documents/runProperties.docx diff --git a/writerfilter/qa/documents/table_4_4.doc b/writerfilter/qa/documents/table_4_4.doc Binary files differnew file mode 100644 index 000000000..ad8500dc2 --- /dev/null +++ b/writerfilter/qa/documents/table_4_4.doc diff --git a/writerfilter/qa/documents/table_4_4.docx b/writerfilter/qa/documents/table_4_4.docx Binary files differnew file mode 100644 index 000000000..484d7f150 --- /dev/null +++ b/writerfilter/qa/documents/table_4_4.docx diff --git a/writerfilter/qa/documents/table_style.docx b/writerfilter/qa/documents/table_style.docx Binary files differnew file mode 100644 index 000000000..3cf6e9fbd --- /dev/null +++ b/writerfilter/qa/documents/table_style.docx diff --git a/writerfilter/qa/ooxml/watch-generated-code.sh b/writerfilter/qa/ooxml/watch-generated-code.sh new file mode 100755 index 000000000..22dc44011 --- /dev/null +++ b/writerfilter/qa/ooxml/watch-generated-code.sh @@ -0,0 +1,50 @@ +#!/bin/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..5769daa5b --- /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", OUString::fromUtf8(msfilter::util::ConvertColor(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::makeAny( 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..6eec32327 --- /dev/null +++ b/writerfilter/source/dmapper/BorderHandler.hxx @@ -0,0 +1,81 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_BORDERHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_BORDERHANDLER_HXX + +#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 { +namespace 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;} + bool getShadow() const { return m_bShadow;} + void enableInteropGrabBag(const OUString& aName); + css::beans::PropertyValue getInteropGrabBag(const OUString& aName = OUString()); +}; +}} + +#endif + +/* 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..805f6e1bb --- /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::makeAny(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::makeAny(OUString::fromUtf8(msfilter::util::ConvertColor(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::makeAny(OUString::fromUtf8(msfilter::util::ConvertColor(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::makeAny(TDefTableHandler::getThemeColorTypeString(nIntValue))); + break; + case NS_ooxml::LN_CT_Shd_themeFillShade: + createGrabBag("themeFillShade", uno::makeAny(OUString::number(nIntValue, 16))); + break; + case NS_ooxml::LN_CT_Shd_themeFillTint: + createGrabBag("themeFillTint", uno::makeAny(OUString::number(nIntValue, 16))); + break; + case NS_ooxml::LN_CT_Shd_themeColor: + createGrabBag("themeColor", uno::makeAny(TDefTableHandler::getThemeColorTypeString(nIntValue))); + break; + case NS_ooxml::LN_CT_Shd_themeShade: + createGrabBag("themeShade", uno::makeAny(OUString::number(nIntValue, 16))); + break; + case NS_ooxml::LN_CT_Shd_themeTint: + createGrabBag("themeTint", uno::makeAny(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::makeAny( nShadingPattern )); + } + + if (m_OutputFormat == Paragraph && m_nShadingPattern != NS_ooxml::LN_Value_ST_Shd_nil) + { + if (nWW8BrushStyle || !m_bAutoFillColor) + pPropertyMap->Insert(PROP_FILL_STYLE, uno::makeAny(drawing::FillStyle_SOLID)); + else if (m_bFillSpecified) // m_bAutoFillColor == true + pPropertyMap->Insert(PROP_FILL_STYLE, uno::makeAny(drawing::FillStyle_NONE)); + + pPropertyMap->Insert(PROP_FILL_COLOR, uno::makeAny(nApplyColor)); + } + else if ( nWW8BrushStyle || !m_bAutoFillColor || m_bFillSpecified ) + pPropertyMap->Insert( m_OutputFormat == Form ? PROP_BACK_COLOR + : PROP_CHAR_BACK_COLOR, uno::makeAny( nApplyColor )); + + createGrabBag("originalColor", uno::makeAny(OUString::fromUtf8(msfilter::util::ConvertColor(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..4ec63c217 --- /dev/null +++ b/writerfilter/source/dmapper/CellColorHandler.hxx @@ -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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_CELLCOLORHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_CELLCOLORHANDLER_HXX + +#include "LoggedResources.hxx" +#include "PropertyMap.hxx" +#include <vector> + +#include <com/sun/star/beans/PropertyValue.hpp> + +namespace writerfilter { +namespace 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; +}; +}} + +#endif + +/* 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..349611b10 --- /dev/null +++ b/writerfilter/source/dmapper/CellMarginHandler.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/. + * + * 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_CELLMARGINHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_CELLMARGINHANDLER_HXX + +#include "LoggedResources.hxx" +#include <vector> +#include <com/sun/star/beans/PropertyValue.hpp> + +namespace writerfilter { +namespace 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(); + +}; +}} + +#endif + +/* 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..9baac3034 --- /dev/null +++ b/writerfilter/source/dmapper/ConversionHelper.cxx @@ -0,0 +1,669 @@ +/* -*- 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> + +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') + ) + ); +} +} + +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); + sal_Int32 nLen = sFormat.getLength(); + sal_Int32 nI = 0; +// const sal_Unicode* pFormat = sFormat.getStr(); + OUStringBuffer aNewFormat( sFormat ); + while (nI < nLen) + { + if (aNewFormat[nI] == '\\') + nI++; + else if (aNewFormat[nI] == '\"') + { + ++nI; + //While not at the end and not at an unescaped end quote + while ((nI < nLen) && ((aNewFormat[nI] != '\"') && (aNewFormat[nI-1] != '\\'))) + ++nI; + } + else //normal unquoted section + { + sal_Unicode nChar = aNewFormat[nI]; + if (nChar == 'O') + { + aNewFormat[nI] = 'M'; + bForceNatNum = true; + } + else if (nChar == 'o') + { + aNewFormat[nI] = 'm'; + bForceNatNum = true; + } + else if ((nChar == 'A') && lcl_IsNotAM(sFormat, nI)) + { + aNewFormat[nI] = '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) && (aNewFormat[nI+1] == 'E')) + { + //todo: this cannot be the right way to replace a part of the string! + aNewFormat[nI] = 'Y'; + aNewFormat[nI + 1] = 'Y'; + aNewFormat.insert(nI + 2, "YY"); + nLen+=2; + nI+=3; + } + bForceJapanese = true; + } + else if (nChar == 'e') + { + if ((nI != nLen-1) && (aNewFormat[nI+1] == 'e')) + { + //todo: this cannot be the right way to replace a part of the string! + aNewFormat[nI] = 'y'; + aNewFormat[nI + 1] = 'y'; + aNewFormat.insert(nI + 2, "yy"); + nLen+=2; + nI+=3; + } + bForceJapanese = true; + } + else if (nChar == '/') + { + // 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] = '\\'; + aNewFormat.insert(nI + 1, "/"); + nI++; + nLen++; + } + } + ++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 ); +} + +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 _t * 254.0 / 144.0; +} + +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; +} + +sal_Int16 ConvertNumberingType(sal_Int32 nFmt) +{ + 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: + case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital: + case NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting: + case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2: + nRet = style::NumberingType::NUMBER_HANGUL_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_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 = style::NumberingType::ARABIC; + } +/* 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_decimalFullWidth = 91691; + 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_chineseLegalSimplified = 91715; + NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand = 91716; + NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal = 91719; + NS_ooxml::LN_Value_ST_NumberFormat_vietnameseCounting = 91721; + NS_ooxml::LN_Value_ST_NumberFormat_numberInDash = 91725; + NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad: + 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(const OUString& rFormat) +{ + sal_Int16 nRet = -1; + + if (rFormat == "001, 002, 003, ...") + { + nRet = style::NumberingType::ARABIC_ZERO3; + } + else if (rFormat == "0001, 0002, 0003, ...") + { + nRet = style::NumberingType::ARABIC_ZERO4; + } + else if (rFormat == "00001, 00002, 00003, ...") + { + nRet = style::NumberingType::ARABIC_ZERO5; + } + + return nRet; +} + +util::DateTime ConvertDateStringToDateTime( const OUString& 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; + OUString sDate = rDateTime.getToken( 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) + OUString sTime = rDateTime.getToken( 0, 'Z', nIndex ); + nIndex = 0; + aDateTime.Year = sal_uInt16( sDate.getToken( 0, '-', nIndex ).toInt32() ); + aDateTime.Month = sal_uInt16( sDate.getToken( 0, '-', nIndex ).toInt32() ); + if (nIndex != -1) + aDateTime.Day = sal_uInt16( sDate.copy( nIndex ).toInt32() ); + + nIndex = 0; + aDateTime.Hours = sal_uInt16( sTime.getToken( 0, ':', nIndex ).toInt32() ); + aDateTime.Minutes = sal_uInt16( sTime.getToken( 0, ':', nIndex ).toInt32() ); + if (nIndex != -1) + aDateTime.Seconds = sal_uInt16( sTime.copy( nIndex ).toInt32() ); + + 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..707ac7424 --- /dev/null +++ b/writerfilter/source/dmapper/ConversionHelper.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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_CONVERSIONHELPER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_CONVERSIONHELPER_HXX + +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <com/sun/star/util/DateTime.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 { +namespace dmapper{ +namespace 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_DLLPUBLIC_EXPORT 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(sal_Int32 nFmt); + sal_Int16 ConvertCustomNumberFormat(const OUString& rFormat); + + css::util::DateTime ConvertDateStringToDateTime(const OUString& rDateTime); +} // namespace ConversionHelper +} //namespace dmapper +} // namespace writerfilter +#endif + +/* 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..76fc96b9f --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -0,0 +1,4017 @@ +/* -*- 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/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) +{ + // #i24363# tab stops relative to indent + m_pImpl->SetDocumentSettingsProperty( + getPropertyName( PROP_TABS_RELATIVE_TO_INDENT ), + uno::makeAny( false ) ); + m_pImpl->SetDocumentSettingsProperty( + getPropertyName( PROP_SURROUND_TEXT_WRAP_SMALL ), + uno::makeAny( true ) ); + m_pImpl->SetDocumentSettingsProperty( + getPropertyName( PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING ), + uno::makeAny( true ) ); + + // Don't load the default style definitions to avoid weird mix + m_pImpl->SetDocumentSettingsProperty("StylesNoDefault", uno::makeAny(true)); + m_pImpl->SetDocumentSettingsProperty("MsWordCompTrailingBlanks", uno::makeAny(true)); + m_pImpl->SetDocumentSettingsProperty("HeaderSpacingBelowLastPara", + uno::makeAny(true)); + + m_pImpl->SetDocumentSettingsProperty("TabAtLeftIndentForParagraphsInList", uno::makeAny(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, OUString())); + 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 + { + uno::Reference< embed::XStorage > 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( xDocumentStorage, xPropSupplier->getDocumentProperties() ); + } + catch( const uno::Exception& ) {} +} + +DomainMapper::~DomainMapper() +{ + try + { + 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 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::makeAny(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:hypenationZone setting + aProperties["HyphenationZone"] <<= m_pImpl->GetSettingsTable()->GetHypenationZone(); + + // 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())); + } + } + 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::makeAny( nIntValue ) ); + m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "val", OUString::fromUtf8(msfilter::util::ConvertColor(nIntValue))); + break; + case NS_ooxml::LN_CT_Underline_color: + if (m_pImpl->GetTopContext()) + { + m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_HAS_COLOR, uno::makeAny( true ) ); + m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_COLOR, uno::makeAny( 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::makeAny( sStringValue )); + if (m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH) && m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->isSet(PROP_NUMBERING_RULES)) + { + // Font of the paragraph mark should be used for the numbering as well. + uno::Reference<beans::XPropertySet> xCharStyle(m_pImpl->GetCurrentNumberingCharStyle()); + if (xCharStyle.is()) + xCharStyle->setPropertyValue("CharFontName", uno::makeAny(sStringValue)); + } + } + break; + case NS_ooxml::LN_CT_Fonts_asciiTheme: + m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "asciiTheme", ThemeTable::getStringForTheme(nIntValue)); + if (m_pImpl->GetTopContext()) + { + uno::Any aPropValue = uno::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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 = uno::makeAny( 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::makeAny( 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::makeAny( 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 = uno::makeAny( 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::makeAny( 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::makeAny(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::makeAny(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::makeAny( 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::makeAny(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::makeAny( 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::makeAny(nFirstLineIndent), /*bOverwrite=*/false); + + m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN, + uno::makeAny(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::makeAny(nFirstLineIndent), /*bOverwrite=*/false); + if (nParaLeftMargin != 0) + m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN, uno::makeAny(nParaLeftMargin), /*bOverwrite=*/false); + + m_pImpl->GetTopContext()->Insert( + PROP_PARA_RIGHT_MARGIN, uno::makeAny( 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::makeAny( - 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::makeAny(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::makeAny(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::makeAny ( 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::makeAny ( sCombinePrefix )); + m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_SUFFIX, uno::makeAny ( 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::makeAny ( 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::makeAny ( nIntValue != 0 )); + break; + + case NS_ooxml::LN_CT_PageSz_code: + break; + case NS_ooxml::LN_CT_PageSz_h: + { + sal_Int32 nHeight = ConversionHelper::convertTwipToMM100(nIntValue); + CT_PageSz.h = PaperInfo::sloppyFitPageDimension(nHeight); + } + break; + case NS_ooxml::LN_CT_PageSz_orient: + CT_PageSz.orient = (nIntValue != static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_PageOrientation_portrait)); + break; + case NS_ooxml::LN_CT_PageSz_w: + { + sal_Int32 nWidth = ConversionHelper::convertTwipToMM100(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 + { + 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( 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::makeAny( 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::makeAny(ConversionHelper::convertTwipToMM100(default_spacing))); + } + m_pImpl->GetTopContext()->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::makeAny( 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::makeAny(ConversionHelper::convertTwipToMM100(default_spacing))); + } + m_pImpl->GetTopContext()->Insert( PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, uno::makeAny( 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 : + //TODO: attributes for break (0x12) are not supported + 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 == static_cast<sal_Int32>(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: + m_pImpl->SetSdt(true); + break; + case NS_ooxml::LN_CT_SdtBlock_sdtEndContent: + 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); + + if (m_pImpl->m_pSdtHelper->isInsideDropDownControl()) + m_pImpl->m_pSdtHelper->createDropDownControl(); + else if (m_pImpl->m_pSdtHelper->validateDateFormat()) + m_pImpl->m_pSdtHelper->createDateContentControl(); + break; + case NS_ooxml::LN_CT_SdtListItem_displayText: + // TODO handle when this is != value + 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) + pSectionContext->SetPageNumber(nIntValue); + break; + case NS_ooxml::LN_CT_PageNumber_fmt: + if (pSectionContext) + { + switch (nIntValue) + { + case NS_ooxml::LN_Value_ST_NumberFormat_decimal: + // 1, 2, ... + pSectionContext->SetPageNumberType(style::NumberingType::ARABIC); + break; + case NS_ooxml::LN_Value_ST_NumberFormat_upperLetter: + // A, B, ... + pSectionContext->SetPageNumberType(style::NumberingType::CHARS_UPPER_LETTER_N); + break; + case NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter: + // a, b, ... + pSectionContext->SetPageNumberType(style::NumberingType::CHARS_LOWER_LETTER_N); + break; + case NS_ooxml::LN_Value_ST_NumberFormat_upperRoman: + // I, II, ... + pSectionContext->SetPageNumberType(style::NumberingType::ROMAN_UPPER); + break; + case NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman: + // i, ii, ... + pSectionContext->SetPageNumberType(style::NumberingType::ROMAN_LOWER); + break; + } + } + 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->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_prefixMappings", sStringValue); + break; + case NS_ooxml::LN_CT_DataBinding_xpath: + m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_xpath", sStringValue); + break; + case NS_ooxml::LN_CT_DataBinding_storeItemID: + m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_storeItemID", sStringValue); + break; + case NS_ooxml::LN_CT_PTab_leader: + case NS_ooxml::LN_CT_PTab_relativeTo: + case NS_ooxml::LN_CT_PTab_alignment: + 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::makeAny(nNumType)); + } + } + catch (const uno::Exception&) + { + } + } + 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; + break; + default: + break; + } + + OSL_ENSURE(rContext.get(), "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::makeAny(nIntValue == 0)); + break; + case NS_ooxml::LN_CT_PPrBase_keepNext: + rContext->Insert(PROP_PARA_KEEP_TOGETHER, uno::makeAny( nIntValue != 0 ) ); + break; + case NS_ooxml::LN_CT_PPrBase_pageBreakBefore: + rContext->Insert(PROP_BREAK_TYPE, uno::makeAny(nIntValue ? style::BreakType_PAGE_BEFORE : style::BreakType_NONE)); + break; + case NS_ooxml::LN_CT_NumPr_ilvl: + if (nIntValue < 0 || 10 <= nIntValue) // Writer can't do everything + { + 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) ); + } + else + rContext->Insert( PROP_NUMBERING_LEVEL, uno::makeAny( 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 = uno::makeAny( 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::makeAny( OUString() ) ); + // disable inheritance of indentation of parent styles + rContext->Insert( PROP_PARA_LEFT_MARGIN, uno::makeAny( sal_Int32(0) ), /*bOverwrite=*/false); + rContext->Insert( PROP_PARA_FIRST_LINE_INDENT, + uno::makeAny( sal_Int32(0) ), /*bOverwrite=*/false); + } + } + } + break; + case NS_ooxml::LN_CT_PPrBase_suppressLineNumbers: + rContext->Insert(PROP_PARA_LINE_NUMBER_COUNT, uno::makeAny( 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: + //not supported + break; + default:; + } + if( eBorderId ) + rContext->Insert( eBorderId, uno::makeAny( pBorderHandler->getBorderLine()) ); + if(eBorderDistId) + rContext->Insert(eBorderDistId, uno::makeAny( 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::makeAny(aFormat)); + } + } + } + break; + case NS_ooxml::LN_CT_PBdr_bar: + break; + case NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens: + rContext->Insert(PROP_PARA_IS_HYPHENATION, uno::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( nAlignment) ); + } + break; + case NS_ooxml::LN_CT_PPrBase_textDirection: + break; + case NS_ooxml::LN_CT_PPrBase_outlineLvl: + { + sal_Int16 nLvl = static_cast< sal_Int16 >( nIntValue ); + if( IsStyleSheetImport() ) + { + + StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() ); + if (pStyleSheetPropertyMap) + pStyleSheetPropertyMap->SetOutlineLevel( nLvl ); + } + else + { + nLvl = nLvl >= WW_OUTLINE_MIN && nLvl < WW_OUTLINE_MAX? nLvl+1 : 0; //0 means no outline level set on + rContext->Insert(PROP_OUTLINE_LEVEL, uno::makeAny ( 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::makeAny( 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::makeAny( style::ParagraphAdjust_LEFT )); + else if ( eAdjust == style::ParagraphAdjust_LEFT ) + rContext->Insert(PROP_PARA_ADJUST, uno::makeAny( style::ParagraphAdjust_RIGHT )); + } + } + rContext->Insert(PROP_WRITING_MODE, uno::makeAny( 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::makeAny(writingMode)); + } + break; + case NS_ooxml::LN_EG_RPrBase_highlight: + { + // OOXML import uses an ID + if( IsOOXMLImport() ) + { + sal_Int32 nColor = 0; + if( getColorFromId(nIntValue, nColor) ) + rContext->Insert(PROP_CHAR_HIGHLIGHT, uno::makeAny( nColor )); + } + // RTF import uses the actual color value + else if( IsRTFImport() ) + { + rContext->Insert(PROP_CHAR_HIGHLIGHT, uno::makeAny( nIntValue )); + } + } + break; + case NS_ooxml::LN_EG_RPrBase_em: + rContext->Insert(PROP_CHAR_EMPHASIS, uno::makeAny ( 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::makeAny( 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 ); + + uno::Reference<beans::XPropertySet> xCharStyle(m_pImpl->GetCurrentNumberingCharStyle()); + if (xCharStyle.is()) + xCharStyle->setPropertyValue(getPropertyName(PROP_CHAR_WEIGHT), 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::makeAny( 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::makeAny( nIntValue ? awt::FontStrikeout::SINGLE : awt::FontStrikeout::NONE ) ); + break; + case NS_ooxml::LN_EG_RPrBase_dstrike: + rContext->Insert(ePropertyId, + uno::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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 = uno::makeAny( 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 ); + + uno::Reference<beans::XPropertySet> xCharStyle(m_pImpl->GetCurrentNumberingCharStyle()); + if (xCharStyle.is()) + xCharStyle->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT), 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() ) + m_pImpl->deferCharacterProperty( nSprmId, uno::makeAny( nIntValue )); + else + { + // 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::makeAny( nEscapement ) ); + rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::makeAny( 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::makeAny(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::makeAny( 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::makeAny( sal_Int16(nIntValue) )); + } + else + { + rContext->Insert(PROP_CHAR_SCALE_WIDTH, + uno::makeAny( sal_Int16(100) )); + } + break; + case NS_ooxml::LN_EG_RPrBase_imprint: + // FontRelief: NONE, EMBOSSED, ENGRAVED + rContext->Insert(PROP_CHAR_RELIEF, + uno::makeAny( 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::makeAny( true )); + else + rContext->Insert(PROP_CHAR_FLASH, uno::makeAny( 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::makeAny(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 != static_cast<sal_Int32>(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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( pBorderHandler->getBorderLine())); + rContext->Insert( PROP_CHAR_BOTTOM_BORDER, uno::makeAny( pBorderHandler->getBorderLine())); + rContext->Insert( PROP_CHAR_LEFT_BORDER, uno::makeAny( pBorderHandler->getBorderLine())); + rContext->Insert( PROP_CHAR_RIGHT_BORDER, uno::makeAny( pBorderHandler->getBorderLine())); + + rContext->Insert( PROP_CHAR_TOP_BORDER_DISTANCE, uno::makeAny( pBorderHandler->getLineDistance())); + rContext->Insert( PROP_CHAR_BOTTOM_BORDER_DISTANCE, uno::makeAny( pBorderHandler->getLineDistance())); + rContext->Insert( PROP_CHAR_LEFT_BORDER_DISTANCE, uno::makeAny( pBorderHandler->getLineDistance())); + rContext->Insert( PROP_CHAR_RIGHT_BORDER_DISTANCE, uno::makeAny( 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::makeAny(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::makeAny(false) ); + else + { + xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_IS_ON ), uno::makeAny(true) ); + if( aSettings.nInterval ) + xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_INTERVAL ), uno::makeAny(static_cast<sal_Int16>(aSettings.nInterval)) ); + if( aSettings.nDistance != -1 ) + xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_DISTANCE ), uno::makeAny(aSettings.nDistance) ); + else + { + // set Auto value (0.5 cm) + xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_DISTANCE ), uno::makeAny(static_cast<sal_Int32>(500)) ); + if( pSectionContext ) + pSectionContext->SetdxaLnn( static_cast<sal_Int32>(283) ); + } + xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::makeAny(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::makeAny(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 + } + 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) + { + pSectionContext->Insert( PROP_HEIGHT, uno::makeAny( CT_PageSz.h ) ); + pSectionContext->Insert( PROP_IS_LANDSCAPE, uno::makeAny( CT_PageSz.orient )); + pSectionContext->Insert( PROP_WIDTH, uno::makeAny( 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 ); + } + 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()) + { + if( pSectHdl->IsEqualWidth() ) + { + pSectionContext->SetEvenlySpaced( true ); + pSectionContext->SetColumnCount( static_cast<sal_Int16>(pSectHdl->GetNum() - 1) ); + pSectionContext->SetColumnDistance( pSectHdl->GetSpace() ); + pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() ); + } + else if( !pSectHdl->GetColumns().empty() ) + { + pSectionContext->SetEvenlySpaced( false ); + pSectionContext->SetColumnDistance( pSectHdl->GetSpace() ); + pSectionContext->SetColumnCount( static_cast<sal_Int16>(pSectHdl->GetColumns().size() -1)); + 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( pSectHdl->GetNum() > 0 ) + { + pSectionContext->SetColumnCount( static_cast<sal_Int16>(pSectHdl->GetNum()) - 1 ); + 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::makeAny( pSectHdl->GetSpace() )); + xTOC->setPropertyValue( getPropertyName( PROP_TEXT_COLUMNS ), uno::makeAny( 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::makeAny(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::makeAny( sConvertedStyleName )); + } + break; + case NS_ooxml::LN_EG_RPrBase_rStyle: + { + OUString sConvertedName( m_pImpl->GetStyleSheetTable()->ConvertStyleName( sStringValue, true ) ); + if (m_pImpl->CheckFootnoteStyle()) + 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::makeAny( 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::makeAny(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::makeAny(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::makeAny( nEscapement ) ); + rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::makeAny( 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::makeAny( 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::makeAny( nFootnoteCounting )); + } + else if (xFtnEdnSettings.is()) + { + sal_Int16 nNumType = ConversionHelper::ConvertNumberingType( nIntValue ); + xFtnEdnSettings->setPropertyValue( + getPropertyName( PROP_NUMBERING_TYPE), + uno::makeAny( nNumType )); + } + } + catch( const uno::Exception& ) + { + } + } + 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::makeAny( nIntValue != 0 )); + break; + case NS_ooxml::LN_CT_PPrBase_mirrorIndents: // mirrorIndents + rContext->Insert(PROP_MIRROR_INDENTS, uno::makeAny( nIntValue != 0 ), true, PARA_GRAB_BAG); + break; + case NS_ooxml::LN_EG_SectPrContents_formProt: //section protection + { + if( pSectionContext ) + pSectionContext->Insert( PROP_IS_PROTECTED, uno::makeAny( 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::makeAny( 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.get() != nullptr) + { + 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->setInsideDropDownControl(true); + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties.get() != nullptr) + pProperties->resolve(*this); + } + break; + case NS_ooxml::LN_CT_SdtDropDownList_listItem: + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties.get() != nullptr) + pProperties->resolve(*this); + } + break; + case NS_ooxml::LN_CT_SdtPr_date: + { + 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_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_text: + case NS_ooxml::LN_CT_SdtPr_id: + case NS_ooxml::LN_CT_SdtPr_alias: + { + // 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_text: sName = "ooxml:CT_SdtPr_text"; 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; + default: assert(false); + }; + enableInteropGrabBag(sName); + + // process subitems + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties.get() != nullptr) + 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: + m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtCheckbox_checked", sStringValue); + break; + case NS_ooxml::LN_CT_SdtCheckbox_checkedState: + m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtCheckbox_checkedState", sStringValue); + break; + case NS_ooxml::LN_CT_SdtCheckbox_uncheckedState: + 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 = uno::makeAny(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::makeAny(aGrabBag), true, CHAR_GRAB_BAG); + + sal_Int16 nTransparency = TextEffectsHandler::GetTextFillSolidFillAlpha(aGrabBag); + if (nTransparency != 0) + { + rContext->Insert(PROP_CHAR_TRANSPARENCE, uno::makeAny(nTransparency)); + } + } + } + } + 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::makeAny(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::makeAny(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::makeAny(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 = uno::makeAny( 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::makeAny(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::makeAny(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::makeAny(aInfo.sRubyText)); + rContext->Insert(PROP_RUBY_STYLE, uno::makeAny(aInfo.sRubyStyle)); + rContext->Insert(PROP_RUBY_ADJUST, uno::makeAny(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign)))); + if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical ) + rContext->Insert(PROP_RUBY_POSITION, uno::makeAny(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.get() != nullptr) + pProperties->resolve(*this); + } + break; + case NS_ooxml::LN_CT_DocPartPr_category: + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties.get() != nullptr) + pProperties->resolve(*this); + } + break; + case NS_ooxml::LN_CT_DocPartCategory_gallery: + { + writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps(); + if (pProperties.get() != nullptr) + 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::makeAny( sal_Int16(nEscapement) ) ); + rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::makeAny( 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()) + { + 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::makeAny( sDefaultParaStyle ) ); + m_pImpl->SetCurrentParaStyleName( sDefaultParaStyle ); + } + if (m_pImpl->isBreakDeferred(PAGE_BREAK)) + m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_PAGE_BEFORE)); + else if (m_pImpl->isBreakDeferred(COLUMN_BREAK)) + m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_COLUMN_BEFORE)); + + if (m_pImpl->isParaSdtEndDeferred()) + m_pImpl->GetTopContext()->Insert(PROP_PARA_SDT_END_BEFORE, uno::makeAny(true), true, PARA_GRAB_BAG); + } + m_pImpl->SetIsFirstRun(true); + m_pImpl->SetIsOutsideAParagraph(false); + m_pImpl->clearDeferredBreaks(); + m_pImpl->setParaSdtEndDeferred(false); +} + +void DomainMapper::lcl_endParagraphGroup() +{ + 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()); + + 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::makeAny(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); + +} + +void DomainMapper::lcl_endShape( ) +{ + if (m_pImpl->GetTopContext()) + { + // 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::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::makeAny(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 + m_pImpl->deferBreak(PAGE_BREAK); + return; + case 0x0e: //column break + m_pImpl->deferBreak(COLUMN_BREAK); + return; + 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::makeAny(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(); + if (!m_pImpl->GetFootnoteContext()) + { + if (m_pImpl->isBreakDeferred(PAGE_BREAK)) + m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_PAGE_BEFORE)); + else if (m_pImpl->isBreakDeferred(COLUMN_BREAK)) + m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(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(); + + 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_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) + { + // 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::makeAny(true), true, CHAR_GRAB_BAG); + m_pImpl->setSdtEndDeferred(false); + } + + bool bNewLine = len == 1 && (sText[0] == 0x0d || sText[0] == 0x07); + if (m_pImpl->m_pSdtHelper->isInsideDropDownControl()) + { + 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->isInteropGrabBagEmpty()) + { + // Ignore grabbag when we have a date field, it can conflict during export + if(m_pImpl->m_pSdtHelper->validateDateFormat()) + { + m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear(); + } + else + { + + // 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(); + + pContext->Insert(PROP_SDTPR, uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), true, CHAR_GRAB_BAG); + } + else + m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->Insert(PROP_SDTPR, + uno::makeAny(m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear()), 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] == '\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; + } + } + else if (m_pImpl->m_pSdtHelper->validateDateFormat()) + { + if(IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter()) + { + m_pImpl->m_pSdtHelper->getDateFormat().truncate(); + m_pImpl->m_pSdtHelper->getLocale().truncate(); + 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 + { + m_pImpl->getTableManager().utext(data_, len); + + if (bNewLine) + { + const bool bSingleParagraph = m_pImpl->GetIsFirstParagraphInSection() && m_pImpl->GetIsLastParagraphInSection(); + const bool bSingleParagraphAfterRedline = m_pImpl->GetIsFirstParagraphInSection(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::makeAny(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::makeAny(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. + SectionPropertyMap* pSectionContext = m_pImpl->GetSectionContext(); + bool bRemove = (!m_pImpl->GetParaChanged() && m_pImpl->GetRemoveThisPara()) || + (!m_pImpl->GetParaChanged() && m_pImpl->GetParaSectpr() + && !bSingleParagraphAfterRedline + && !m_pImpl->GetIsDummyParaAddedForTableInSection() + && !( pSectionContext && pSectionContext->GetBreakType() != -1 && pContext && pContext->isSet(PROP_BREAK_TYPE) ) + && !m_pImpl->GetIsPreviousParagraphFramed()); + + 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); + } + m_pImpl->SetParaSectpr(false); + finishParagraph(bRemove); + if (bRemove) + m_pImpl->RemoveLastParagraph(); + } + 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::makeAny(style::BreakType_PAGE_BEFORE)); + } + else if (m_pImpl->isBreakDeferred(COLUMN_BREAK)) + { + if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun()) + { + mbIsSplitPara = true; + finishParagraph(); + lcl_startParagraphGroup(); + } + m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::makeAny(style::BreakType_COLUMN_BEFORE)); + } + m_pImpl->clearDeferredBreaks(); + } + + if (pContext && pContext->GetFootnote().is()) + { + pContext->GetFootnote()->setLabel( sText ); + //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(); + + 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: + { + + //the same for list tables + ref->resolve( *m_pImpl->GetListTable() ); + m_pImpl->GetListTable( )->CreateNumberingRules( ); + } + 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::makeAny(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::makeAny(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::makeAny( nAdjust ) ); + rContext->Insert( PROP_PARA_LAST_LINE_ADJUST, uno::makeAny( 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_lightGray)) + 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; + 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( ); +} + +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 ); +} + +bool DomainMapper::IsStyleSheetImport() const +{ + return m_pImpl->IsStyleSheetImport(); +} + +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) +{ + if (m_pImpl->m_pSdtHelper->validateDateFormat()) + m_pImpl->m_pSdtHelper->createDateContentControl(); + m_pImpl->finishParagraph(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH), bRemove); +} + +} //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..c8281f933 --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapper.hxx @@ -0,0 +1,184 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPER_HXX + +#include <dmapper/DomainMapperFactory.hxx> +#include "LoggedResources.hxx" +#include "PropertyMap.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 { +namespace 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; + + // 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; + + 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( ); + 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; + bool IsStyleSheetImport() 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 ); + +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_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; + + // 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); + + 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; + std::unique_ptr< GraphicZOrderHelper > zOrderHelper; + std::unique_ptr<GraphicNamingHelper> m_pGraphicNamingHelper; + OUString m_sGlossaryEntryName; +}; + +} // namespace dmapper +} // namespace writerfilter +#endif + +/* 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..c32b33af1 --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx @@ -0,0 +1,1496 @@ +/* -*- 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 "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/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> + +#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 + +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.get() != nullptr) + 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_Int32 nCell, sal_Int32 nRow, bool bIsEndCol, bool bIsEndRow, bool bMergedVertically ) +{ + 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 ( nCell == 0 ) + { + lcl_mergeBorder( PROP_LEFT_BORDER, pTableBorders, pCellProps ); + // <w:insideV> counts if there are multiple cells in this row. + if (pVerticalVal && !bIsEndCol) + pCellProps->Insert( PROP_RIGHT_BORDER, aVertProp, false ); + } + + if ( bIsEndCol ) + { + lcl_mergeBorder( PROP_RIGHT_BORDER, pTableBorders, pCellProps ); + if ( pVerticalVal ) + pCellProps->Insert( PROP_LEFT_BORDER, aVertProp, false ); + } + + if ( nCell > 0 && !bIsEndCol ) + { + if ( pVerticalVal ) + { + pCellProps->Insert( PROP_RIGHT_BORDER, aVertProp, false ); + 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::makeAny( 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) +{ + // 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( 10 ); + + aGrabBagTS[0].Name = "bottomFromText"; + aGrabBagTS[0].Value <<= pTablePositions->getBottomFromText(); + + aGrabBagTS[1].Name = "horzAnchor"; + aGrabBagTS[1].Value <<= pTablePositions->getHorzAnchor(); + + aGrabBagTS[2].Name = "leftFromText"; + aGrabBagTS[2].Value <<= pTablePositions->getLeftFromText(); + + aGrabBagTS[3].Name = "rightFromText"; + aGrabBagTS[3].Value <<= pTablePositions->getRightFromText(); + + aGrabBagTS[4].Name = "tblpX"; + aGrabBagTS[4].Value <<= pTablePositions->getX(); + + aGrabBagTS[5].Name = "tblpXSpec"; + aGrabBagTS[5].Value <<= pTablePositions->getXSpec(); + + aGrabBagTS[6].Name = "tblpY"; + aGrabBagTS[6].Value <<= pTablePositions->getY(); + + aGrabBagTS[7].Name = "tblpYSpec"; + aGrabBagTS[7].Value <<= pTablePositions->getYSpec(); + + aGrabBagTS[8].Name = "topFromText"; + aGrabBagTS[8].Value <<= pTablePositions->getTopFromText(); + + aGrabBagTS[9].Name = "vertAnchor"; + aGrabBagTS[9].Value <<= pTablePositions->getVertAnchor(); + + aGrabBag["TablePosition"] <<= aGrabBagTS; + } + + 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::makeAny( 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::makeAny( 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::makeAny( aDistances ) ); + + if (!rFrameProperties.empty()) + lcl_DecrementHoriOrientPosition(rFrameProperties, rInfo.nLeftBorderDistance); + + // Set table above/bottom spacing to 0. + m_aTableProperties->Insert( PROP_TOP_MARGIN, uno::makeAny( sal_Int32( 0 ) ) ); + m_aTableProperties->Insert( PROP_BOTTOM_MARGIN, uno::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( sal_Int16( nTableWidth ) ) ); + m_aTableProperties->Insert( PROP_IS_WIDTH_RELATIVE, uno::makeAny( 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::makeAny( sal_Int16(nHoriOrient) ) ); + //fill default value - if not available + m_aTableProperties->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( 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::makeAny(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; + } + } + + 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> oRowCellBorder; + 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. + bool bMergedVertically = bool(m_aCellProperties[nRow][nCell]->getProperty(PROP_VERTICAL_MERGE)); + + for (size_t i = nRow + 1; bMergedVertically && i < m_aCellProperties.size(); i++) + if ( m_aCellProperties[i].size() > sal::static_int_cast<std::size_t>(nCell) ) + bMergedVertically = bool(m_aCellProperties[i][nCell]->getProperty(PROP_VERTICAL_MERGE)); + + lcl_computeCellBorders( rInfo.pTableBorders, *aCellIterator, nCell, nRow, bIsEndCol, 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::makeAny(rInfo.nLeftBorderDistance ), false); + aCellIterator->get()->Insert( PROP_RIGHT_BORDER_DISTANCE, + uno::makeAny(rInfo.nRightBorderDistance ), false); + aCellIterator->get()->Insert( PROP_TOP_BORDER_DISTANCE, + uno::makeAny(rInfo.nTopBorderDistance ), false); + aCellIterator->get()->Insert( PROP_BOTTOM_BORDER_DISTANCE, + uno::makeAny(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; + } + + 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() ); + 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::makeAny(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::makeAny(text::SizeType::FIX)); + } + + aRowProperties[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, 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 + if ( !rParaProp.m_pPropertyMap->isSet(eId) ) + { + 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::makeAny(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("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 ) + { + 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::makeAny(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"); + } + } + } + } +} + +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; + aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties); + // 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; + + bool bFloating = !aFrameProperties.empty(); + + // 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) + { + 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); + 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()) + { + 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<OUStringLiteral> aBorderNames + = { "TopBorder", "LeftBorder", "BottomBorder", "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(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( + aBorderNames[i], uno::makeAny(aBorderValues[i])); + } + } + } + } + } + } + } + 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::makeAny(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::makeAny(sal_Int32(0))); + + // 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); + 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..545f60919 --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapperTableHandler.hxx @@ -0,0 +1,128 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEHANDLER_HXX + +#include "PropertyMap.hxx" +#include <vector> + +#include <com/sun/star/text/XTextAppendAndConvert.hpp> + +namespace writerfilter { +namespace 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); + 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, 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(); +}; + +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEHANDLER_HXX + +/* 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..a19b9395e --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapperTableManager.cxx @@ -0,0 +1,863 @@ +/* -*- 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> + +namespace writerfilter::dmapper { + +using namespace ::com::sun::star; +using namespace ::std; + +DomainMapperTableManager::DomainMapperTableManager() : + m_nRow(0), + m_nCell(), + m_nGridSpan(1), + m_aGridBefore(), + m_nGridAfter(0), + m_nHeaderRepeat(0), + m_nTableWidth(0), + m_bIsInShape(false), + m_aTmpPosition(), + m_aTmpTableProperties(), + m_bPushCurrentWidth(false), + m_bTableSizeTypeInserted(false), + m_nLayoutType(0), + m_aParagraphsToEndTable(), + 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::makeAny<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::makeAny(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.get() != nullptr) ? 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::makeAny(sal_Int32(0))); + } + else + { + ++m_nHeaderRepeat; + pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( 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::makeAny(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::makeAny(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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( text::WritingMode2::BT_LR )); + break; + case NS_ooxml::LN_Value_ST_TextDirection_lrTbV: + pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::LR_TB )); + break; + case NS_ooxml::LN_Value_ST_TextDirection_tbRlV: + pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( 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() > 0) + 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: + m_aGridBefore.back( ) = nIntValue; + break; + case NS_ooxml::LN_CT_TrPrBase_gridAfter: + m_nGridAfter = 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::makeAny(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( ) +{ + return m_aTableGrid.back( ); +} + +sal_uInt32 DomainMapperTableManager::getCurrentGridBefore( ) +{ + return m_aGridBefore.back( ); +} + +DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentSpans( ) +{ + return m_aGridSpans.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; +} + +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 pNewSpans = std::make_shared<vector<sal_Int32>>(); + IntVectorPtr pNewCellWidths = std::make_shared<vector<sal_Int32>>(); + TablePositionHandlerPtr pNewPositionHandler; + m_aTableGrid.push_back( pNewGrid ); + m_aGridSpans.push_back( pNewSpans ); + 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() ); + + TablePositionHandlerPtr pTmpPosition; + TablePropertyMapPtr pTmpProperties( new TablePropertyMap( ) ); + m_aTmpPosition.push_back( pTmpPosition ); + m_aTmpTableProperties.push_back( pTmpProperties ); + m_nCell.push_back( 0 ); + m_aGridBefore.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( ); + m_aGridSpans.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_aGridBefore.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.get() != nullptr) + 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_aParagraphsToEndTable.pop(); +} + +void DomainMapperTableManager::endOfCellAction() +{ +#ifdef DBG_UTIL + TagLogger::getInstance().element("endOFCellAction"); +#endif + + if (m_aGridSpans.empty()) + throw std::out_of_range("empty spans"); + m_aGridSpans.back()->push_back(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 + m_nGridAfter)) + return true; + rIsIncompleteGrid = true; + return nGrids + m_nGridAfter > 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. + 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 pTmpGridSpans = m_aGridSpans.back(); + IntVectorPtr pTmpCellWidths = m_aCellWidths.back(); + sal_uInt32 nTmpCell = m_nCell.back(); + sal_uInt32 nTmpGridBefore = m_aGridBefore.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_aGridSpans.pop_back(); + m_aCellWidths.pop_back(); + m_nCell.pop_back(); + m_aGridBefore.pop_back(); + m_aTableGrid.push_back(pTmpTableGrid); + m_aGridSpans.push_back(pTmpGridSpans); + m_aCellWidths.push_back(pTmpCellWidths); + m_nCell.push_back(nTmpCell); + m_aGridBefore.push_back(nTmpGridBefore); + 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 + } + + IntVectorPtr pCurrentSpans = getCurrentSpans( ); + + if( m_aGridBefore.back() > 0 ) + { + //fill missing gridBefore elements with '1' + pCurrentSpans->insert( pCurrentSpans->begin( ), m_aGridBefore.back(), 1 ); + } + if( pCurrentSpans->size() < m_aGridBefore.back() + m_nCell.back( )) + { + //fill missing elements with '1' + pCurrentSpans->insert( pCurrentSpans->end( ), m_aGridBefore.back() + m_nCell.back( ) - pCurrentSpans->size(), 1 ); + } + +#ifdef DBG_UTIL + TagLogger::getInstance().startElement("gridSpans"); + { + for (const auto& rGridSpan : *pCurrentSpans) + { + 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(pCurrentSpans->begin(), pCurrentSpans->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_nGridAfter ) && 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( m_aGridBefore.back() + m_nCell.back( ) - 1 ); + text::TableColumnSeparator* pSeparators = aSeparators.getArray(); + double nLastRelPos = 0.0; + sal_uInt32 nBorderGridIndex = 0; + + size_t nWidthsBound = m_aGridBefore.back() + m_nCell.back() - 1; + if (nWidthsBound) + { + if (nFullWidthRelative == 0) + throw o3tl::divide_by_zero(); + + ::std::vector< sal_Int32 >::const_iterator aSpansIter = pCurrentSpans->begin( ); + for( size_t nBorder = 0; nBorder < nWidthsBound; ++nBorder ) + { + double fGridWidth = 0.; + for ( sal_Int32 nGridCount = *aSpansIter; nGridCount > 0; --nGridCount ) + fGridWidth += (*pTableGrid)[nBorderGridIndex++]; + + double 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::makeAny( aSeparators ) ); + +#ifdef DBG_UTIL + TagLogger::getInstance().startElement("rowProperties"); + pPropMap->dumpXml(); + TagLogger::getInstance().endElement(); +#endif + 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) + { + if (nFullWidthRelative == 0) + throw o3tl::divide_by_zero(); + + // 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 && pCurrentSpans->size()-1 == nWidthsBound ) + { + auto aSpansIter = std::next(pCurrentSpans->begin( ), nWidthsBound - 1); + sal_Int32 nFixLastCellWidth = (*pCellWidths)[nWidthsBound-1] / *aSpansIter * *std::next(aSpansIter); + if (nFixLastCellWidth > (*pCellWidths)[nWidthsBound]) + nFullWidthRelative += nFixLastCellWidth - (*pCellWidths)[nWidthsBound]; + } + + 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::makeAny( 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; + m_aGridBefore.back( ) = 0; + getCurrentGrid()->clear(); + pCurrentSpans->clear(); + pCellWidths->clear(); + + m_nGridAfter = 0; + 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..50d5f2ff2 --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapperTableManager.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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEMANAGER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEMANAGER_HXX + +#include "TablePropertiesHandler.hxx" +#include "TablePositionHandler.hxx" + +#include "TableManager.hxx" +#include "PropertyMap.hxx" +#include <vector> +#include <memory> +#include <comphelper/sequenceashashmap.hxx> + +namespace writerfilter { +namespace 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; + ::std::vector< sal_uInt32 > m_aGridBefore; ///< 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 + 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; + /// 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; + ::std::vector< IntVectorPtr > m_aGridSpans; + /// 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 & getCurrentSpans( ); + IntVectorPtr const & getCurrentCellWidths( ); + sal_uInt32 getCurrentGridBefore( ); + 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); + +}; + +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPERTABLEMANAGER_HXX + +/* 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..12aa623de --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -0,0 +1,7319 @@ +/* -*- 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 <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/document/IndexedPropertyValues.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/embed/XEmbeddedObject.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/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 <editeng/flditem.hxx> +#include <editeng/unotext.hxx> +#include <o3tl/temporary.hxx> +#include <oox/mathml/import.hxx> +#include <xmloff/odffields.hxx> +#include <rtl/uri.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 <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 = dynamic_cast<const StyleSheetPropertyMap*>( 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::makeAny( 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() ) + { + if ( !pFFDataHandler->getName().isEmpty() ) + rxFieldProps->setPropertyValue( "Name", uno::makeAny( pFFDataHandler->getName() ) ); + + const FFDataHandler::DropDownEntries_t& rEntries = pFFDataHandler->getDropDownEntries(); + uno::Sequence< OUString > sItems( rEntries.size() ); + ::std::copy( rEntries.begin(), rEntries.end(), sItems.begin()); + if ( sItems.hasElements() ) + rxFieldProps->setPropertyValue( "Items", uno::makeAny( sItems ) ); + + sal_Int32 nResult = pFFDataHandler->getDropDownResult().toInt32(); + if ( nResult ) + rxFieldProps->setPropertyValue( "SelectedItem", uno::makeAny( sItems[ nResult ] ) ); + if ( !pFFDataHandler->getHelpText().isEmpty() ) + rxFieldProps->setPropertyValue( "Help", uno::makeAny( 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::makeAny(pFFDataHandler->getStatusText())); + rxFieldProps->setPropertyValue + (getPropertyName(PROP_HELP), + uno::makeAny(pFFDataHandler->getHelpText())); + rxFieldProps->setPropertyValue + (getPropertyName(PROP_CONTENT), + uno::makeAny(pFFDataHandler->getTextDefault())); + } +} + +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) +{ + if (!pOuter->GetFieldId()) + { + return true; + } + + if (!pInner->GetFieldId()) + { + return true; + } + + switch (*pOuter->GetFieldId()) + { + case FIELD_IF: + { + switch (*pInner->GetFieldId()) + { + case FIELD_MERGEFIELD: + { + return false; + } + default: + break; + } + break; + } + default: + break; + } + + return true; +} + +uno::Any FloatingTableInfo::getPropertyValue(const OUString &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_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_xComponentContext)), + m_bSetUserFieldContent( false ), + m_bSetCitation( false ), + m_bSetDateValue( false ), + m_bIsFirstSection( true ), + m_bIsColumnBreakDeferred( false ), + m_bIsPageBreakDeferred( false ), + 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_pLastSectionContext( ), + m_pLastCharacterContext(), + m_sCurrentParaStyleName(), + m_sDefaultParaStyleName(), + m_bInStyleSheetImport( false ), + m_bInAnyTableImport( false ), + m_eInHeaderFooterImport( HeaderFooterImportState::none ), + m_bDiscardHeaderFooter( false ), + m_bInFootOrEndnote(false), + m_bHasFootnoteStyle(false), + m_bCheckFootnoteStyle(false), + m_eSkipFootnoteState(SkipFootnoteSeparator::OFF), + m_bLineNumberingSet( false ), + m_bIsInFootnoteProperties( false ), + m_bIsParaMarkerChange( false ), + m_bParaChanged( false ), + m_bIsFirstParaInSection( true ), + m_bIsFirstParaInSectionAfterRedline( true ), + m_bDummyParaAddedForTableInSection( 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_xAnnotationField(), + m_nAnnotationId( -1 ), + m_aAnnotationPositions(), + m_aSmartTagHandler(m_xComponentContext, m_xTextDocument), + m_xInsertTextRange(rMediaDesc.getUnpackedValueOrDefault("TextInsertModeRange", uno::Reference<text::XTextRange>())), + m_bIsNewDoc(!rMediaDesc.getUnpackedValueOrDefault("InsertMode", 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_vTextFramesForChaining(), + m_bParaHadField(false), + m_bParaAutoBefore(false), + m_bFirstParagraphInCell(true), + m_bSaveFirstParagraphInCell(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(); + 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_xComponentContext); + + m_pSdtHelper = new SdtHelper(*this); + + m_aRedlines.push(std::vector<RedlineParamsPtr>()); +} + + +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(); + } +} + +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 = rStyleName.copy( strlen( DEFAULT_STYLE ) ).toInt32(); + 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< 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 can't have sections. + if (IsInShape()) + 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); + } + } +} + +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); + 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); + const OUString aRecordChanges("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()); + + // restore 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; +} + + +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::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(); +} + +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 ( !m_bIsFirstParaInShape ) + 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 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 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 COLUMN_BREAK: + return m_bIsColumnBreakDeferred; + case PAGE_BREAK: + return m_bIsPageBreakDeferred; + default: + return false; + } +} + +void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType) +{ + switch (deferredBreakType) + { + case COLUMN_BREAK: + m_bIsColumnBreakDeferred = false; + break; + case PAGE_BREAK: + m_bIsPageBreakDeferred = false; + break; + default: + break; + } +} + +void DomainMapper_Impl::clearDeferredBreaks() +{ + 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::makeAny(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 +static constexpr sal_Int32 DEFAULT_FRAME_MIN_WIDTH = 0; +static constexpr sal_Int32 DEFAULT_FRAME_MIN_HEIGHT = 0; +static 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 ParagraphProperties* pStyleProperties = dynamic_cast<const ParagraphProperties*>( 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)); + + 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(), + 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 = dynamic_cast<const StyleSheetPropertyMap*>(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); +} + +void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove ) +{ + 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.get(), "no style sheet found" ); + const StyleSheetPropertyMap* pStyleSheetProperties = dynamic_cast<const StyleSheetPropertyMap*>(pEntry ? pEntry->pProperties.get() : nullptr); + bool isNumberingViaStyle(false); + bool isNumberingViaRule = pParaContext && pParaContext->GetListId() > -1; + sal_Int32 nListId = -1; + if ( !bRemove && pStyleSheetProperties && pParaContext ) + { + //apply numbering level/style to paragraph if it was set at the style, but only if the paragraph itself + //does not specify the numbering + const sal_Int16 nListLevel = pStyleSheetProperties->GetListLevel(); + if ( !isNumberingViaRule && nListLevel >= 0 ) + pParaContext->Insert( PROP_NUMBERING_LEVEL, uno::makeAny(nListLevel), false ); + + bool bNumberingFromBaseStyle = false; + nListId = pEntry ? lcl_getListId(pEntry, GetStyleSheetTable(), bNumberingFromBaseStyle) : -1; + auto const pList(GetListTable()->GetList(nListId)); + if (pList && nListId >= 0 && !pParaContext->isSet(PROP_NUMBERING_STYLE_NAME)) + { + 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. + // So we skip it only for default outline styles, which are recognized by NumberingManager. + if (!GetCurrentParaStyleName().startsWith("Heading ") || nListLevel >= pList->GetDefaultParentLevels()) + pParaContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::makeAny(pList->GetStyleName()), true ); + } + else if ( !pList->isOutlineNumbering(nListLevel) ) + { + // After ignoring anything related to the special Outline levels, + // 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 + if ( nListId == pParaContext->GetListId() ) + pParaContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::makeAny(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 = dynamic_cast<const StyleSheetPropertyMap*>(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::makeAny(nFirstLineIndent), /*bOverwrite=*/false); + if (nParaLeftMargin != 0) + pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::makeAny(nParaLeftMargin), /*bOverwrite=*/false); + + pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, uno::makeAny(nParaRightMargin), /*bOverwrite=*/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); + // apply INHERITED autospacing only if top margin is not set + if ( bIsAutoSet || (pParaContext && !pParaContext->isSet(PROP_PARA_TOP_MARGIN)) ) + GetAnyProperty(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, pPropertyMap) >>= nBeforeAutospacing; + if ( nBeforeAutospacing > -1 && pParaContext ) + { + if ( bAllowAdjustments ) + { + if ( GetIsFirstParagraphInShape() || + (GetIsFirstParagraphInSection() && GetSectionContext() && GetSectionContext()->IsFirstSection()) || + (m_bFirstParagraphInCell && m_nTableDepth > 0 && m_nTableDepth == m_nTableCellDepth) ) + { + nBeforeAutospacing = 0; + // export requires grabbag to match top_margin, so keep them in sync + if ( bIsAutoSet ) + pParaContext->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::makeAny( sal_Int32(0) ),true, PARA_GRAB_BAG ); + } + } + pParaContext->Insert(PROP_PARA_TOP_MARGIN, uno::makeAny(nBeforeAutospacing)); + } + + sal_Int32 nAfterAutospacing = -1; + bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING); + bool bApplyAutospacing = bIsAutoSet || (pParaContext && !pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN)); + if ( bApplyAutospacing ) + GetAnyProperty(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, pPropertyMap) >>= nAfterAutospacing; + if ( nAfterAutospacing > -1 && pParaContext ) + { + pParaContext->Insert(PROP_PARA_BOTTOM_MARGIN, uno::makeAny(nAfterAutospacing)); + bApplyAutospacing = bAllowAdjustments; + } + else + bApplyAutospacing = false; + + // tell TableManager to reset the bottom margin if it determines that this is the cell's last paragraph. + if ( hasTableManager() && getTableManager().isInCell() ) + getTableManager().setCellLastParaAfterAutospacing( bApplyAutospacing ); + + + 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()); + } + // TODO: this *should* work for RTF but there are test failures, maybe rtftok doesn't distinguish between formatting for the paragraph marker and for the paragraph as a whole; needs investigation + if (pPropertyMap && IsOOXMLImport()) + { + // 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::makeAny(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. + OUString const sMarker("X"); + xCursor = xTextAppend->getText()->createTextCursor(); + if (xCursor.is()) + xCursor->gotoEnd(false); + PropertyMapPtr pEmpty(new PropertyMap()); + appendTextPortion(sMarker, 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) + { + 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; + auto aPrevProperties = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aPrevPropertiesSeq); + bool bParaAutoBefore = m_bParaAutoBefore || std::any_of(aPrevProperties.begin(), aPrevProperties.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(aPrevProperties.begin(), aPrevProperties.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::makeAny(static_cast<sal_Int32>(0))); + } + } + } + + xTextRange = xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) ); + m_xPreviousParagraph.set(xTextRange, uno::UNO_QUERY); + + if (m_xPreviousParagraph.is() && // null for SvxUnoTextBase + (isNumberingViaStyle || isNumberingViaRule)) + { + assert(dynamic_cast<ParagraphPropertyMap*>(pPropertyMap.get())); + // Use lcl_getListId(), so we find the list ID in parent styles as well. + bool bNumberingFromBaseStyle = false; + sal_Int32 const nListId2( isNumberingViaStyle + ? lcl_getListId(pEntry, GetStyleSheetTable(), bNumberingFromBaseStyle) + : static_cast<ParagraphPropertyMap*>(pPropertyMap.get())->GetListId()); + if (ListDef::Pointer const& pList = m_pListTable->GetList(nListId2)) + { // 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::makeAny(listId)); + } + } + } + if (pList->GetCurrentLevel()) + { + sal_Int16 nOverrideLevel = pList->GetCurrentLevel()->GetStartOverride(); + if (nOverrideLevel != -1 && m_aListOverrideApplied.find(nListId2) == 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::makeAny(true)); + m_xPreviousParagraph->setPropertyValue("NumberingStartValue", uno::makeAny(nOverrideLevel)); + m_aListOverrideApplied.insert(nListId2); + } + } + } + } + + 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; + } + xCur->goRight(2, 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::makeAny(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, pStyleSheetProperties->GetListLevel(), "IndentAt"); + if (nParaLeftMargin != 0) + xParaProps->setPropertyValue("ParaLeftMargin", uno::makeAny(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, pStyleSheetProperties->GetListLevel(), "FirstLineIndent"); + if (nFirstLineIndent != 0) + xParaProps->setPropertyValue("ParaFirstLineIndent", uno::makeAny(nFirstLineIndent)); + } + } + } + } + + // fix table paragraph properties + if ( xTextRange.is() && xParaProps && m_nTableDepth > 0 ) + { + uno::Sequence< beans::PropertyValue > aParaProps = pParaContext->GetPropertyValues(false); + uno::Reference<text::XTextCursor> xCur = xTextRange->getText()->createTextCursorByRange(xTextRange); + uno::Reference< beans::XPropertyState > xRunProperties( xCur, uno::UNO_QUERY_THROW ); + // tdf#90069 in tables, apply paragraph level character style also on + // paragraph level to support its copy during insertion of new table rows + for( const auto& rParaProp : std::as_const(aParaProps) ) + { + if ( rParaProp.Name.startsWith("Char") && rParaProp.Name != "CharStyleName" && rParaProp.Name != "CharInteropGrabBag" && + // all text portions contain the same value, so next setPropertyValue() won't overwrite part of them + xRunProperties->getPropertyState(rParaProp.Name) == css::beans::PropertyState_DIRECT_VALUE ) + { + uno::Reference<beans::XPropertySet> xRunPropertySet(xCur, uno::UNO_QUERY); + xParaProps->setPropertyValue( rParaProp.Name, xRunPropertySet->getPropertyValue(rParaProp.Name) ); + } + } + + // tdf#128959 table paragraphs haven't got window and orphan controls + uno::Any aAny = uno::makeAny(static_cast<sal_Int8>(0)); + xParaProps->setPropertyValue("ParaOrphans", aAny); + xParaProps->setPropertyValue("ParaWidows", aAny); + } + } + if( !bKeepLastParagraphProperties ) + rAppendContext.pLastParagraphProperties = pToBeSavedProperties; + } + catch(const lang::IllegalArgumentException&) + { + OSL_FAIL( "IllegalArgumentException in 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_bParaChanged = 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); + // count first not deleted paragraph as first paragraph in section to avoid of + // its deletion later, resulting loss of the associated page break + if (!m_previousRedline) + { + SetIsFirstParagraphInSectionAfterRedline(false); + SetIsLastParagraphInSection(false); + } + } + m_previousRedline.clear(); + + 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; + +#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()) + { + 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 : aValues ) + { + if (rValue.Name == "CharHidden") + rValue.Value <<= 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 data of non-terminating runs of the paragraph + if ( m_pParaMarkerRedlineMoveFrom ) + { + m_pParaMarkerRedlineMoveFrom.clear(); + } + CheckRedline( xTextRange ); + m_bParaChanged = true; + + //getTableManager( ).handle(xTextRange); + } + catch(const lang::IllegalArgumentException&) + { + OSL_FAIL( "IllegalArgumentException in DomainMapper_Impl::appendTextPortion" ); + } + catch(const uno::Exception&) + { + OSL_FAIL( "Exception in 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()) + { + 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(m_xComponentContext); + if (aCLSID.isEmpty()) + xOLEProperties->setPropertyValue(getPropertyName( PROP_STREAM_NAME ), + uno::makeAny( rStreamName )); + else + xOLEProperties->setPropertyValue("CLSID", uno::makeAny(aCLSID)); + + OUString aDrawAspect = pOLEHandler->GetDrawAspect(); + if(!aDrawAspect.isEmpty()) + xOLEProperties->setPropertyValue("DrawAspect", uno::makeAny(aDrawAspect)); + + awt::Size aSize = pOLEHandler->getSize(); + if( !aSize.Width ) + aSize.Width = 1000; + if( !aSize.Height ) + aSize.Height = 1000; + xOLEProperties->setPropertyValue(getPropertyName( PROP_WIDTH ), + uno::makeAny(aSize.Width)); + xOLEProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ), + uno::makeAny(aSize.Height)); + + OUString aVisAreaWidth = pOLEHandler->GetVisAreaWidth(); + if(!aVisAreaWidth.isEmpty()) + xOLEProperties->setPropertyValue("VisibleAreaWidth", uno::makeAny(aVisAreaWidth)); + + OUString aVisAreaHeight = pOLEHandler->GetVisAreaHeight(); + if(!aVisAreaHeight.isEmpty()) + xOLEProperties->setPropertyValue("VisibleAreaHeight", uno::makeAny(aVisAreaHeight)); + + uno::Reference< graphic::XGraphic > xGraphic = pOLEHandler->getReplacement(); + xOLEProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC ), + uno::makeAny(xGraphic)); + uno::Reference<beans::XPropertySet> xReplacementProperties(pOLEHandler->getShape(), uno::UNO_QUERY); + if (xReplacementProperties.is()) + { + OUString pProperties[] = { + "AnchorType", + "Surround", + "SurroundContour", + "HoriOrient", + "HoriOrientPosition", + "VertOrient", + "VertOrientPosition", + "VertOrientRelation", + "HoriOrientRelation" + }; + for (const OUString & s : pProperties) + xOLEProperties->setPropertyValue(s, xReplacementProperties->getPropertyValue(s)); + } + else + // mimic the treatment of graphics here... it seems anchoring as character + // gives a better ( visually ) result + xOLEProperties->setPropertyValue(getPropertyName( PROP_ANCHOR_TYPE ), uno::makeAny( 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& ) + { + OSL_FAIL( "Exception in creation of OLE object" ); + } + +} + +void DomainMapper_Impl::appendStarMath( const Value& val ) +{ + uno::Reference< embed::XEmbeddedObject > formula; + val.getAny() >>= formula; + if( formula.is() ) + { + 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::makeAny(sal_Int32(0))); + xStarMathProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ), + uno::makeAny(sal_Int32(0))); + xStarMathProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ), + uno::makeAny(sal_Int32(0))); + xStarMathProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ), + uno::makeAny(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::makeAny(sal_Int32(0))); + xComponentProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ), + uno::makeAny(sal_Int32(0))); + xComponentProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ), + uno::makeAny(sal_Int32(0))); + xComponentProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ), + uno::makeAny(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::makeAny( sal_Int32(size.Width()))); + xStarMathProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ), + uno::makeAny( sal_Int32(size.Height()))); + xStarMathProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE), + uno::makeAny(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& ) + { + OSL_FAIL( "Exception in creation of StarMath object" ); + } + } +} + +void DomainMapper_Impl::adjustLastPara(sal_Int8 nAlign) +{ + PropertyMapPtr pLastPara = GetTopContextOfType(dmapper::CONTEXT_PARAGRAPH); + pLastPara->Insert(PROP_PARA_ADJUST, uno::makeAny(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::PushPageHeaderFooter(bool bHeader, SectionPropertyMap::PageType eType) +{ + 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) + { + // 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()) || (GetSettingsTable()->GetEvenAndOddHeaders())) + { + //switch on header/footer use + xPageStyle->setPropertyValue( + getPropertyName(ePropIsOn), + uno::makeAny(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::makeAny(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_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(); + } +} + +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_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 = pTopContext->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 ) + { + try + { + OUString sType; + switch ( pRedline->m_nToken & 0xffff ) + { + case XML_mod: + sType = getPropertyName( PROP_FORMAT ); + break; + case XML_moveTo: + case XML_ins: + sType = getPropertyName( PROP_INSERT ); + break; + case XML_moveFrom: + m_pParaMarkerRedlineMoveFrom = 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( 3 ); + 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 ); + pRedlineProperties[1].Value <<= ConversionHelper::ConvertDateStringToDateTime( pRedline->m_sDate ); + pRedlineProperties[2].Name = getPropertyName( PROP_REDLINE_REVERT_PROPERTIES ); + pRedlineProperties[2].Value <<= pRedline->m_aRevertProperties; + if (!m_bIsActualParagraphFramed) + { + uno::Reference < text::XRedline > xRedline( xRange, uno::UNO_QUERY_THROW ); + xRedline->makeRedline( sType, aRedlineProperties ); + } + else + { + aFramedRedlines.push_back( uno::makeAny(xRange) ); + aFramedRedlines.push_back( uno::makeAny(sType) ); + aFramedRedlines.push_back( uno::makeAny(aRedlineProperties) ); + } + } + catch( const uno::Exception & ) + { + OSL_FAIL( "Exception 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_pParaMarkerRedlineMoveFrom ) + { + // terminating moveFrom redline removes also the paragraph mark + m_pParaMarkerRedlineMoveFrom->m_nToken = XML_del; + CreateRedline( xRange, m_pParaMarkerRedlineMoveFrom ); + } + if ( m_pParaMarkerRedlineMoveFrom ) + { + m_pParaMarkerRedlineMoveFrom.clear(); + } +} + +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::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"); + } +} + + +void DomainMapper_Impl::PopFootOrEndnote() +{ + if (!IsRTFImport()) + 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 + { + // 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; +} + +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<beans::XPropertySet> xSyncedPropertySet(xShapes->getByIndex(i), uno::UNO_QUERY_THROW); + comphelper::SequenceAsHashMap aGrabBag( xSyncedPropertySet->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> xSyncedPropertyState(xSyncedPropertySet, 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 == xSyncedPropertyState->getPropertyState(sPropName) ) + { + const uno::Any aProp = GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true); + if ( aProp.hasValue() ) + xSyncedPropertySet->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::makeAny(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 > xShapeText( xShape, uno::UNO_QUERY_THROW); + // Add the shape to the text append stack + m_aTextAppendStack.push( TextAppendContext(uno::Reference< text::XTextAppend >( xShape, uno::UNO_QUERY_THROW ), + m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(xShapeText->getStart() ))); + + // 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::makeAny(pZOrderHelper->findZOrder(zOrder))); + pZOrderHelper->addItem(xShapePropertySet, zOrder); + xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::makeAny( 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::makeAny(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::makeAny(pZOrderHelper->findZOrder(zOrder))); + pZOrderHelper->addItem(xShapePropertySet, zOrder); + xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::makeAny( 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::makeAny(aShapeGrabBag)); + } + } + } + } + if (!IsInHeaderFooter() && !checkZOrderStatus) + xProps->setPropertyValue( + getPropertyName( PROP_OPAQUE ), + uno::makeAny( 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::makeAny(sal_Int32(aSize.Width))); + xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_HEIGHT), uno::makeAny(sal_Int32(aSize.Height))); +} + + +void DomainMapper_Impl::PopShapeContext() +{ + if (hasTableManager()) + { + getTableManager().endLevel(); + popTableManager(); + } + if ( !m_aAnchoredStack.empty() ) + { + // 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::makeAny(static_cast<sal_Int32>(0))); + } + + m_xPreviousParagraph.clear(); + + // next table paragraph will be first paragraph in a cell + m_bFirstParagraphInCell = true; +} + +static sal_Int16 lcl_ParseNumberingType( const OUString& 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("\\* "); + if (sal_Int32 nStartIndex = rCommand.indexOf(rSeparator); nStartIndex >= 0) + { + nStartIndex += rSeparator.getLength(); + sNumber = rCommand.getToken(0, ' ', nStartIndex); + } + + if( !sNumber.isEmpty() ) + { + //todo: might make sense to hash this list, too + struct NumberingPairs + { + const sal_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} +/* 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" + // Remove whitespace permitted by standard between \@ and " + OUString command; + sal_Int32 delimPos = rCommand.indexOf("\\@"); + if (delimPos != -1) + { + sal_Int32 wsChars = rCommand.indexOf('\"') - delimPos - 2; + command = rCommand.replaceAt(delimPos+2, wsChars, ""); + } + else + command = rCommand; + + return msfilter::util::findQuotedText(command, "\\@\"", '\"'); +} +/*------------------------------------------------------------------------- +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"; + } + 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_ExctractVariableAndHint( const OUString& 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 + sal_Int32 nIndex = rCommand.indexOf( ' ', 2); //find last space after 'ASK' + if (nIndex == -1) + return OUString(); + while(rCommand[nIndex] == ' ') + ++nIndex; + OUString sShortCommand( rCommand.copy( nIndex ) ); //cut off the " ASK " + + sShortCommand = sShortCommand.getToken(0, '\\'); + nIndex = 0; + OUString sRet = sShortCommand.getToken( 0, ' ', nIndex); + if( nIndex > 0) + rHint = sShortCommand.copy( nIndex ); + if( rHint.isEmpty() ) + rHint = sRet; + return 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; +} + + +void DomainMapper_Impl::GetCurrentLocale(lang::Locale& rLocale) +{ + PropertyMapPtr pTopContext = GetTopContext(); + std::optional<PropertyMap::Property> pLocale = pTopContext->getProperty(PROP_CHAR_LOCALE); + if( pLocale ) + pLocale->second >>= rLocale; + else + { + PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH); + pLocale = pParaContext->getProperty(PROP_CHAR_LOCALE); + if( pLocale ) + { + pLocale->second >>= rLocale; + } + } +} + +/*------------------------------------------------------------------------- + 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"; + + //determine current locale - todo: is it necessary to initialize this locale? + lang::Locale aCurrentLocale = aUSLocale; + GetCurrentLocale( aCurrentLocale ); + 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::makeAny( 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; + bool bShapeNameSet; + TextFramesForChaining(): nId(0), nSeq(0), bShapeNameSet(false) {} + } ; + typedef std::map <OUString, TextFramesForChaining> ChainMap; + + try + { + ChainMap aTextFramesForChainingHelper; + 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. + if( sShapeName.isEmpty() ) + aChainStruct.bShapeNameSet = false; + else + { + aChainStruct.bShapeNameSet = true; + sLinkChainName = sShapeName; + } + + if( !sLinkChainName.isEmpty() ) + { + aChainStruct.xShape = rTextFrame; + aTextFramesForChainingHelper[sLinkChainName] = 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.bShapeNameSet ) + { + uno::Reference< container::XNamed > xNamed( msoItem.second.xShape, uno::UNO_QUERY ); + if ( xNamed.is() ) + { + xNamed->setName( msoItem.first ); + msoItem.second.bShapeNameSet = true; + } + } + if( !nextFinder->second.bShapeNameSet ) + { + uno::Reference< container::XNamed > xNamed( nextFinder->second.xShape, uno::UNO_QUERY ); + if ( xNamed.is() ) + { + xNamed->setName( nextFinder->first ); + nextFinder->second.bShapeNameSet = true; + } + } + + 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::makeAny(nextFinder->first)); + + //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 : aTextFramesForChainingHelper) + { + if( rOuter.second.s_mso_next_textbox.isEmpty() ) //non-empty ones already handled earlier - so skipping them now. + { + for (const auto& rInner : aTextFramesForChainingHelper) + { + if ( rInner.second.nId == rOuter.second.nId ) + { + if ( rInner.second.nSeq == ( rOuter.second.nSeq + nDirection ) ) + { + uno::Reference<text::XTextContent> xTextContent(rOuter.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::makeAny(rInner.first)); + break ; //there cannot be more than one next frame + } + } + } + } + } + m_vTextFramesForChaining.clear(); //clear the vector + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper"); + } +} + +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::makeAny(rFieldMasterName)); + } else { + // set database data, based on the "databasename.tablename" of sDatabaseDataSourceName + xMaster->setPropertyValue( + getPropertyName(PROP_DATABASE_NAME), + uno::makeAny(sDatabaseDataSourceName.copy(0, sDatabaseDataSourceName.indexOf('.')))); + xMaster->setPropertyValue( + getPropertyName(PROP_COMMAND_TYPE), + uno::makeAny(sal_Int32(0))); + xMaster->setPropertyValue( + getPropertyName(PROP_DATATABLE_NAME), + uno::makeAny(sDatabaseDataSourceName.copy(sDatabaseDataSourceName.indexOf('.') + 1))); + xMaster->setPropertyValue( + getPropertyName(PROP_DATACOLUMN_NAME), + uno::makeAny(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::AppendCommand(const OUString& 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.get(), "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 }}, + {"REF", {"GetReference", FIELD_REF }}, + {"REVNUM", {"DocInfo.Revision", FIELD_REVNUM }}, + {"SAVEDATE", {"DocInfo.Change", 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_ExctractVariableAndHint(pContext->GetCommand(), sHint); + + // remove surrounding "" if exists + if(sHint.getLength() >= 2) + { + OUString sTmp = sHint.trim(); + if (sTmp.startsWith("\"") && sTmp.endsWith("\"")) + { + sHint = sTmp.copy(1, sTmp.getLength() - 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::makeAny(text::SetVariableType::STRING)); + + // attach the master to the field + uno::Reference< text::XDependentTextField > xDependentField + ( xFieldInterface, uno::UNO_QUERY_THROW ); + xDependentField->attachTextFieldMaster( xMaster ); + + xFieldProperties->setPropertyValue(getPropertyName(PROP_HINT), uno::makeAny( sHint )); + xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::makeAny( sHint )); + xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING)); + + // Mimic MS Word behavior (hide the SET) + xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::makeAny(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_ExctractVariableAndHint( 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::makeAny(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::makeAny( true )); + // set the prompt + xFieldProperties->setPropertyValue( + getPropertyName(PROP_HINT), + uno::makeAny( sHint )); + xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING)); + // The ASK has no field value to display + xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::makeAny(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) { + + 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 */ + icu::RegexMatcher rmatch3("<[a-z]{1,3}[0-9]+>", 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("DEFINED\\s*\\(<([A-Z]+[0-9]+)>\\)", usInput, rMatcherFlags, status); + usInput = rmatch5.replaceAll(icu::UnicodeString("DEFINED($1)"), 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, "").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)); + + // grab-bag the original and converted formula + if (getTableManager().isInTable()) + { + TablePropertyMapPtr pPropMap(new TablePropertyMap()); + pPropMap->Insert(PROP_CELL_FORMULA, uno::makeAny(command.copy(1)), true, CELL_GRAB_BAG); + pPropMap->Insert(PROP_CELL_FORMULA_CONVERTED, uno::makeAny(formula), true, CELL_GRAB_BAG); + getTableManager().cellProps(pPropMap); + } + xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::makeAny(formula)); + xFieldProperties->setPropertyValue(getPropertyName(PROP_NUMBER_FORMAT), uno::makeAny(sal_Int32(0))); + xFieldProperties->setPropertyValue("IsShowFormula", uno::makeAny(false)); +} + +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 = rCommand.getToken(0, ' ',nIndex).toInt32(); + 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 = rCommand.getToken(0, ' ',nIndex).toInt32(); + } + + 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; + + OUString sRubyParts = rCommand.copy(nIndex+1,nEnd-nIndex-1); + nIndex = 0; + OUString sPart1 = sRubyParts.getToken(0, ',', nIndex); + OUString sPart2 = sRubyParts.getToken(0, ',', nIndex); + if ((nIndex = sPart1.indexOf('(')) != -1 && (nEnd = sPart1.lastIndexOf(')'))!=-1 && nEnd > nIndex) + { + aInfo.sRubyText = sPart1.copy(nIndex+1,nEnd-nIndex-1); + } + + PropertyMapPtr pRubyContext(new PropertyMap()); + pRubyContext->InsertProps(GetTopContext()); + if (aInfo.nHps > 0) + { + double fVal = double(aInfo.nHps) / 2.; + uno::Any aVal = uno::makeAny( 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::makeAny( aInfo.sRubyText ) ); + pCharContext->Insert(PROP_RUBY_ADJUST, uno::makeAny(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign)))); + if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical ) + pCharContext->Insert(PROP_RUBY_POSITION, uno::makeAny(css::text::RubyPosition::INTER_CHARACTER)); + pCharContext->Insert(PROP_RUBY_STYLE, uno::makeAny(aInfo.sRubyStyle)); + appendTextPortion(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::makeAny(text::SetVariableType::SEQUENCE)); + + //apply the numbering type + xFieldProperties->setPropertyValue( + getPropertyName(PROP_NUMBERING_TYPE), + uno::makeAny( 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 + (OUString const& rFirstParam, + uno::Reference< beans::XPropertySet > const& xFieldProperties, + FieldId eFieldId ) +{ + if ( eFieldId != FIELD_USERINITIALS ) + xFieldProperties->setPropertyValue + ( getPropertyName(PROP_FULL_NAME), uno::makeAny( true )); + + if (!rFirstParam.isEmpty()) + { + xFieldProperties->setPropertyValue( + getPropertyName( PROP_IS_FIXED ), + uno::makeAny( 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 sal_Char* pDocPropertyName; + const sal_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; + for( ; nMap < SAL_N_ELEMENTS(aDocProperties); ++nMap ) + { + if ((rFirstParam.equalsAscii(aDocProperties[nMap].pDocPropertyName)) && (!xPropertySetInfo->hasPropertyByName(rFirstParam))) + { + sFieldServiceName = + OUString::createFromAscii + (aDocProperties[nMap].pServiceName); + break; + } + } + 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::makeAny(rFirstParam)); + pContext->SetCustomField( xFieldProperties ); + } + else + { + if(0 != (aDocProperties[nMap].nFlags & SET_ARABIC)) + xFieldProperties->setPropertyValue( + getPropertyName(PROP_NUMBERING_TYPE), + uno::makeAny( style::NumberingType::ARABIC )); + else if(0 != (aDocProperties[nMap].nFlags & SET_DATE)) + { + xFieldProperties->setPropertyValue( + getPropertyName(PROP_IS_DATE), + uno::makeAny( 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(1); + aHyperlink[0].Name = getPropertyName( PROP_TOKEN_TYPE ); + aHyperlink[0].Value <<= getPropertyName( PROP_TOKEN_HYPERLINK_START ); + pNewLevel[0] = aHyperlink; + aHyperlink[0].Value <<= getPropertyName( PROP_TOKEN_HYPERLINK_END ); + pNewLevel[aNewLevel.getLength() -1] = aHyperlink; + } + if( bChapterNoSeparator ) + { + beans::PropertyValues aChapterNo(2); + aChapterNo[0].Name = getPropertyName( PROP_TOKEN_TYPE ); + aChapterNo[0].Value <<= getPropertyName( PROP_TOKEN_CHAPTER_INFO ); + aChapterNo[1].Name = getPropertyName( PROP_CHAPTER_FORMAT ); + //todo: is ChapterFormat::Number correct? + aChapterNo[1].Value <<= sal_Int16(text::ChapterFormat::NUMBER); + pNewLevel[aNewLevel.getLength() - (bHyperlinks ? 4 : 2) ] = aChapterNo; + + beans::PropertyValues aChapterSeparator(2); + aChapterSeparator[0].Name = getPropertyName( PROP_TOKEN_TYPE ); + aChapterSeparator[0].Value <<= getPropertyName( PROP_TOKEN_TEXT ); + aChapterSeparator[1].Name = getPropertyName( PROP_TEXT ); + aChapterSeparator[1].Value <<= 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(aNewLevel.begin())); + //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; + sValue.getToken( 0, '-', nIndex ); + nMaxLevel = static_cast<sal_Int16>(nIndex != -1 ? sValue.copy(nIndex).toInt32() : 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 + const OUString aObjectType("com.sun.star.text.IndexHeaderSection"); + createSectionForRange(m_xSdtEntryStart, xTextRangeEndOfTocHeader, aObjectType, true); + } + } + + m_bStartTOC = true; + + if (xTOC.is()) + xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(aTocTitle)); + + if (!aBookmarkName.isEmpty()) + xTOC->setPropertyValue(getPropertyName(PROP_TOC_BOOKMARK), uno::makeAny(aBookmarkName)); + if( !bTableOfFigures && xTOC.is() ) + { + xTOC->setPropertyValue( getPropertyName( PROP_LEVEL ), uno::makeAny( nMaxLevel ) ); + xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_OUTLINE ), uno::makeAny( bFromOutline )); + xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_MARKS ), uno::makeAny( bFromEntries )); + xTOC->setPropertyValue( getPropertyName( PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS ), uno::makeAny( bHideTabLeaderPageNumbers )); + xTOC->setPropertyValue( getPropertyName( PROP_TAB_IN_TOC ), uno::makeAny( bIsTabEntry )); + xTOC->setPropertyValue( getPropertyName( PROP_TOC_NEW_LINE ), uno::makeAny( bNewLine )); + xTOC->setPropertyValue( getPropertyName( PROP_TOC_PARAGRAPH_OUTLINE_LEVEL ), uno::makeAny( 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 = sTemplate.getToken( 0, ',', nPosition ).toInt32(); + 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 ( sal_Int32 nStyle = 0; nStyle < nLevelCount; ++nStyle, ++aTOCStyleIter ) + { + aStyles[nStyle] = aTOCStyleIter->second; + } + xParaStyles->replaceByIndex(nLevel - 1, uno::makeAny(aStyles)); + } + } + xTOC->setPropertyValue(getPropertyName(PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES), uno::makeAny( 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::makeAny( aNewLevel ) ); + } + } + } + else if (bTableOfFigures && xTOC.is()) + { + if (!sFigureSequence.isEmpty()) + xTOC->setPropertyValue(getPropertyName(PROP_LABEL_CATEGORY), + uno::makeAny(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::makeAny( 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::makeAny(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) +{ + // Create section before setting m_bStartTOC and m_bStartIndex: finishing paragraph + // inside StartIndexSectionChecked could do the wrong thing otherwise + const auto xTOC = StartIndexSectionChecked(sTOCServiceName); + + m_bStartTOC = true; + m_bStartIndex = true; + OUString sValue; + OUString sIndexEntryType = "I"; // Default value for field flag '\f' is 'I'. + + if (xTOC.is()) + { + xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::makeAny(OUString())); + + if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue )) + { + xTOC->setPropertyValue("IsCommaSeparated", uno::makeAny(true)); + } + if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue )) + { + xTOC->setPropertyValue("UseAlphabeticalSeparators", uno::makeAny(true)); + } + if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue )) + { + if(!sValue.isEmpty()) + sIndexEntryType = sValue ; + xTOC->setPropertyValue(getPropertyName( PROP_INDEX_ENTRY_TYPE ), uno::makeAny(sIndexEntryType)); + } + } + 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::makeAny( 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.get(), "no field context available"); + if( pContext ) + { + 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::makeAny( true )); + m_bSetDateValue = true; + } + else + xFieldProperties->setPropertyValue( + getPropertyName(PROP_IS_FIXED), + uno::makeAny( false )); + + xFieldProperties->setPropertyValue( + getPropertyName(PROP_IS_DATE), + uno::makeAny( 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::makeAny( false )); + //PROP_CURRENT_PRESENTATION is set later anyway + } + break; + case FIELD_CREATEDATE : + { + xFieldProperties->setPropertyValue( + getPropertyName( PROP_IS_DATE ), uno::makeAny( true )); + SetNumberFormat( pContext->GetCommand(), xFieldProperties ); + } + break; + case FIELD_DOCPROPERTY : + handleDocProperty(pContext, sFirstParam, + xFieldInterface); + break; + case FIELD_DOCVARIABLE : + { + //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::makeAny(aResult.sResult)); + } + else + { + //merge Read_SubF_Ruby into filter/.../util.cxx and reuse that ? + sal_Int32 nSpaceIndex = aCommand.indexOf(' '); + if(nSpaceIndex > 0) + aCommand = aCommand.copy(nSpaceIndex).trim(); + 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 = aCommand.copy(0, nStartIndex).toInt32(); + 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::makeAny( 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::makeAny( 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::makeAny( nNumberingTypeIndex > 0 ? text::FilenameDisplayFormat::FULL : text::FilenameDisplayFormat::NAME_AND_EXT )); + } + break; + case FIELD_FILESIZE : break; + case FIELD_FORMULA : + handleFieldFormula(pContext, xFieldProperties); + break; + case FIELD_FORMCHECKBOX : + case FIELD_FORMDROPDOWN : + case FIELD_FORMTEXT : + { + uno::Reference< text::XTextField > xTextField( xFieldInterface, uno::UNO_QUERY ); + if ( !xTextField.is() ) + { + 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::makeAny( true )); + //PROP_CURRENT_PRESENTATION is set later anyway + } + } + break; + case FIELD_LASTSAVEDBY : break; + case FIELD_MACROBUTTON: + { + //extract macro name + sal_Int32 nIndex = sizeof(" MACROBUTTON "); + OUString sMacro = pContext->GetCommand().getToken( 0, ' ', nIndex); + if (xFieldProperties.is()) + xFieldProperties->setPropertyValue( + getPropertyName(PROP_MACRO_NAME), uno::makeAny( sMacro )); + + //extract quick help text + if(xFieldProperties.is() && pContext->GetCommand().getLength() > nIndex + 1) + { + xFieldProperties->setPropertyValue( + getPropertyName(PROP_HINT), + uno::makeAny( pContext->GetCommand().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::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) )); + xFieldProperties->setPropertyValue( + getPropertyName(PROP_SUB_TYPE), + uno::makeAny( 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::makeAny( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) ); + xFieldProperties->setPropertyValue( + getPropertyName(PROP_SOURCE_NAME), + uno::makeAny(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::makeAny( 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::makeAny(sFirstParam)); + xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::makeAny(text::SetVariableType::STRING)); + } + } + break; + case FIELD_REVNUM : break; + case FIELD_SAVEDATE : + SetNumberFormat( pContext->GetCommand(), xFieldProperties ); + 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" + OUString sSeqName = msfilter::util::findQuotedText(sCmd, "SEQ ", '\\'); + sSeqName = sSeqName.trim(); + + // create a sequence field master using the sequence name + uno::Reference< beans::XPropertySet > xMaster = FindOrCreateFieldMaster( + "com.sun.star.text.FieldMaster.SetExpression", + sSeqName); + + xMaster->setPropertyValue( + getPropertyName(PROP_SUB_TYPE), + uno::makeAny(text::SetVariableType::SEQUENCE)); + + // apply the numbering type + xFieldProperties->setPropertyValue( + getPropertyName(PROP_NUMBERING_TYPE), + uno::makeAny( 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 = 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::makeAny(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::makeAny(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::makeAny( 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") ? sFirstParam.copy(2).toUInt32(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::makeAny(awt::CharSet::SYMBOL)); + if(bHasFont) + { + uno::Any aVal = uno::makeAny( 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::makeAny( true )); + m_bSetDateValue = true; + } + SetNumberFormat( pContext->GetCommand(), xFieldProperties ); + } + break; + case FIELD_TITLE : + { + if (!sFirstParam.isEmpty()) + { + xFieldProperties->setPropertyValue( + getPropertyName( PROP_IS_FIXED ), uno::makeAny( 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; + + uno::Reference< beans::XPropertySet > xTC( + m_xTextFactory->createInstance( + OUString::createFromAscii(aIt->second.cFieldServiceName)), + uno::UNO_QUERY_THROW); + if (!sFirstParam.isEmpty()) + { + xTC->setPropertyValue("PrimaryKey", + uno::makeAny(sFirstParam)); + } + 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::makeAny(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::makeAny(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::makeAny( 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::makeAny( lcl_ParseNumberingType(pContext->GetCommand()) )); + break; + } + } + 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::makeAny(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::makeAny(OUString::number(id))); + } + } + else + m_bParaHadField = false; + } + //set the text field if there is any + pContext->SetTextField( uno::Reference< text::XTextField >( xFieldInterface, uno::UNO_QUERY ) ); + } + 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.get(), "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())) + { + // Child field has no backing SwField, but the parent has: append is still possible. + bRet = pOuter->GetTextField().is(); + } + } + } + return bRet; +} + +void DomainMapper_Impl::AppendFieldResult(OUString const& rString) +{ + assert(!m_aFieldStack.empty()); + FieldContextPtr pContext = m_aFieldStack.back(); + SAL_WARN_IF(!pContext, "writerfilter.dmapper", "no field context"); + if (pContext) + { + FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack); + if (pOuter) + { + if (!IsFieldNestingAllowed(pOuter, pContext)) + { + // Child can't host the field result, forward to parent. + pOuter->AppendResult(rString); + return; + } + } + + pContext->AppendResult(rString); + } +} + +// Calculates css::DateTime based on ddddd.sssss since 1900-1-0 +static util::DateTime lcl_dateTimeFromSerial(const double& dSerial) +{ + const sal_uInt32 secondsPerDay = 86400; + const sal_uInt16 secondsPerHour = 3600; + + DateTime d(Date(30, 12, 1899)); + d.AddDays( static_cast<sal_Int32>(dSerial) ); + + double frac = std::modf(dSerial, &o3tl::temporary(double())); + sal_uInt32 seconds = frac * secondsPerDay; + + util::DateTime date; + date.Year = d.GetYear(); + date.Month = d.GetMonth(); + date.Day = d.GetDay(); + date.Hours = seconds / secondsPerHour; + date.Minutes = (seconds % secondsPerHour) / 60; + date.Seconds = seconds % 60; + + return date; +} + +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.get(), "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 ) + { + 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::makeAny( 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[nTitleFoundIndex] = propertyVal; + } + else + { + aValues.realloc(aValues.getLength() + 1); + propertyVal.Name = "Title"; + propertyVal.Value <<= rResult; + aValues[aValues.getLength() - 1] = propertyVal; + } + xFieldProperties->setPropertyValue("Fields", + uno::makeAny(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::makeAny( 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::makeAny( rResult )); + } + } + 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.get(), "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::XTextCursor > xCrsr = xTextAppend->createTextCursorByRange(pContext->GetStartRange()); + 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(xTextAppend->getEnd()); + xCursor->gotoEnd(false); + xCursor->goLeft(1, true); + // delete + xCursor->setString(OUString()); + // But a new paragraph should be started after the index instead + xTextAppend->finishParagraph(css::beans::PropertyValues()); + } + 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 + { + FormControlHelper::Pointer_t pFormControlHelper(pContext->getFormControlHelper()); + if (pFormControlHelper.get() != nullptr) + { + uno::Reference< text::XFormField > xFormField( pContext->GetFormField() ); + assert(xCrsr.is()); + 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()) + { + 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:: + makeAny(pContext->GetHyperlinkURL())); + + if (!pContext->GetHyperlinkTarget().isEmpty()) + xCrsrProperties->setPropertyValue("HyperLinkTarget", uno::makeAny(pContext->GetHyperlinkTarget())); + + if (m_bStartTOC) { + OUString sDisplayName("Index Link"); + xCrsrProperties->setPropertyValue("VisitedCharStyleName",uno::makeAny(sDisplayName)); + xCrsrProperties->setPropertyValue("UnvisitedCharStyleName",uno::makeAny(sDisplayName)); + } + else + { + uno::Any aAny = xCrsrProperties->getPropertyValue("CharStyleName"); + OUString charStyle; + if (css::uno::fromAny(aAny, &charStyle)) + { + if (charStyle.isEmpty()) + { + xCrsrProperties->setPropertyValue("VisitedCharStyleName", uno::makeAny(OUString("Default Style"))); + xCrsrProperties->setPropertyValue("UnvisitedCharStyleName", uno::makeAny(OUString("Default Style"))); + } + else if (charStyle.equalsIgnoreAsciiCase("Internet Link")) + { + xCrsrProperties->setPropertyValue("CharStyleName", uno::makeAny(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&) + { + OSL_FAIL( "IllegalArgumentException in PopFieldContext()" ); + } + catch(const uno::Exception&) + { + OSL_FAIL( "exception in 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 = rBookmarkName; + } + else + m_sCurrentBkmkName = rBookmarkName; +} + +// 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()) + { + xCursor->goLeft( 1, false ); + } + uno::Reference< container::XNamed > xBkmNamed( xBookmark, uno::UNO_QUERY_THROW ); + assert(!aBookmarkIter->second.m_sBookmarkName.isEmpty()); + //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::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::makeAny(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::makeAny(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::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + 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")); + } + } + //insert it into the document at the current cursor position + OSL_ENSURE( xTextContent.is(), "DomainMapper_Impl::ImportGraphic"); + if( xTextContent.is()) + { + 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); + } + } + + // 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::makeAny( 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::makeAny( false ) ); + xProperties->setPropertyValue( getPropertyName( PROP_INTERVAL ), uno::makeAny( static_cast< sal_Int16 >( nLnnMod ))); + xProperties->setPropertyValue( getPropertyName( PROP_DISTANCE ), uno::makeAny( ConversionHelper::convertTwipToMM100(ndxaLnn) )); + xProperties->setPropertyValue( getPropertyName( PROP_NUMBER_POSITION ), uno::makeAny( style::LineNumberPosition::LEFT)); + xProperties->setPropertyValue( getPropertyName( PROP_NUMBERING_TYPE ), uno::makeAny( style::NumberingType::ARABIC)); + xProperties->setPropertyValue( getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::makeAny( 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 : 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) +{ +} + + +void DomainMapper_Impl::RegisterFrameConversion( + uno::Reference< text::XTextRange > const& xFrameStartRange, + uno::Reference< text::XTextRange > const& xFrameEndRange, + const std::vector<beans::PropertyValue>& rFrameProperties + ) +{ + OSL_ENSURE( + m_aFrameProperties.empty() && !m_xFrameStartRange.is() && !m_xFrameEndRange.is(), + "frame properties not removed"); + m_aFrameProperties = rFrameProperties; + m_xFrameStartRange = xFrameStartRange; + m_xFrameEndRange = xFrameEndRange; +} + + +void DomainMapper_Impl::ExecuteFrameConversion() +{ + if( m_xFrameStartRange.is() && m_xFrameEndRange.is() && !m_bDiscardHeaderFooter ) + { + try + { + uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( GetTopTextAppend(), uno::UNO_QUERY_THROW ); + // convert redline ranges to cursor movement and character length + std::vector<sal_Int32> redPos, redLen; + for( size_t i = 0; i < aFramedRedlines.size(); i+=3) + { + uno::Reference< text::XTextRange > xRange; + aFramedRedlines[i] >>= xRange; + uno::Reference<text::XTextCursor> xRangeCursor = GetTopTextAppend()->createTextCursorByRange( xRange ); + if (xRangeCursor.is()) + { + sal_Int32 nLen = xRange->getString().getLength(); + redLen.push_back(nLen); + xRangeCursor->gotoRange(m_xFrameStartRange, true); + redPos.push_back(xRangeCursor->getString().getLength() - nLen); + } + else + { + // failed createTextCursorByRange(), for example, table inside the frame + redLen.push_back(-1); + redPos.push_back(-1); + } + } + + const uno::Reference< text::XTextContent >& xTextContent = xTextAppendAndConvert->convertToTextFrame( + m_xFrameStartRange, + m_xFrameEndRange, + comphelper::containerToSequence(m_aFrameProperties) ); + + // create redlines in the previous frame + 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::XTextFrame > xFrame( xTextContent, uno::UNO_QUERY_THROW ); + uno::Reference< text::XTextCursor > xCrsr = xFrame->getText()->createTextCursor(); + xCrsr->goRight(redPos[i/3], false); + xCrsr->goRight(redLen[i/3], true); + uno::Reference < text::XRedline > xRedline( xCrsr, uno::UNO_QUERY_THROW ); + xRedline->makeRedline( sType, aRedlineProperties ); + } + } + catch( const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "writerfilter.dmapper", "Exception caught when converting to frame"); + } + + m_bIsActualParagraphFramed = false; + aFramedRedlines.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::makeAny(sAuthor)); +} + +void DomainMapper_Impl::SetCurrentRedlineInitials( const OUString& sInitials ) +{ + if (m_xAnnotationField.is()) + m_xAnnotationField->setPropertyValue("Initials", uno::makeAny(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::makeAny(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()) + { + 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()) + { + 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::makeAny(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::makeAny(ConversionHelper::convertTwipToMM100(200))); + style::LineSpacing aSpacing; + aSpacing.Mode = style::LineSpacingMode::PROP; + aSpacing.Height = sal_Int16(115); + xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_LINE_SPACING), uno::makeAny(aSpacing)); + } + + if (m_pSettingsTable->GetZoomFactor() || m_pSettingsTable->GetView()) + { + std::vector<beans::PropertyValue> aViewProps; + if (m_pSettingsTable->GetZoomFactor()) + { + aViewProps.emplace_back("ZoomFactor", -1, uno::makeAny(m_pSettingsTable->GetZoomFactor()), beans::PropertyState_DIRECT_VALUE); + aViewProps.emplace_back("VisibleBottom", -1, uno::makeAny(sal_Int32(0)), beans::PropertyState_DIRECT_VALUE); + aViewProps.emplace_back("ZoomType", -1, + uno::makeAny(m_pSettingsTable->GetZoomType()), + beans::PropertyState_DIRECT_VALUE); + } + uno::Reference<container::XIndexContainer> xBox = document::IndexedPropertyValues::create(m_xComponentContext); + xBox->insertByIndex(sal_Int32(0), uno::makeAny(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::makeAny(true) ); + if (m_pSettingsTable->GetUsePrinterMetrics()) + xSettings->setPropertyValue("PrinterIndependentLayout", uno::makeAny(document::PrinterIndependentLayout::DISABLED)); + if( m_pSettingsTable->GetEmbedTrueTypeFonts()) + xSettings->setPropertyValue( getPropertyName( PROP_EMBED_FONTS ), uno::makeAny(true) ); + if( m_pSettingsTable->GetEmbedSystemFonts()) + xSettings->setPropertyValue( getPropertyName( PROP_EMBED_SYSTEM_FONTS ), uno::makeAny(true) ); + xSettings->setPropertyValue("AddParaTableSpacing", uno::makeAny(m_pSettingsTable->GetDoNotUseHTMLParagraphAutoSpacing())); + if (m_pSettingsTable->GetNoLeading()) + { + xSettings->setPropertyValue("AddExternalLeading", uno::makeAny(!m_pSettingsTable->GetNoLeading())); + } + if( m_pSettingsTable->GetProtectForm() ) + xSettings->setPropertyValue("ProtectForm", uno::makeAny( true )); + if( m_pSettingsTable->GetReadOnly() ) + xSettings->setPropertyValue("LoadReadonly", uno::makeAny( true )); + } + catch(const uno::Exception&) + { + } + } +} + +uno::Reference<container::XIndexAccess> DomainMapper_Impl::GetCurrentNumberingRules(sal_Int32* pListLevel) +{ + uno::Reference<container::XIndexAccess> xRet; + try + { + OUString aStyle = GetCurrentParaStyleName(); + if (aStyle.isEmpty()) + return xRet; + const StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(aStyle); + if (!pEntry) + return xRet; + const StyleSheetPropertyMap* pStyleSheetProperties = dynamic_cast<const StyleSheetPropertyMap*>(pEntry->pProperties.get()); + if (!pStyleSheetProperties) + return xRet; + sal_Int32 nListId = pStyleSheetProperties->GetListId(); + if (nListId < 0) + return xRet; + if (pListLevel) + *pListLevel = pStyleSheetProperties->GetListLevel(); + + // So we are in a paragraph style and it has numbering. Look up the relevant numbering rules. + auto const pList(GetListTable()->GetList(nListId)); + OUString aListName; + if (pList) + { + aListName = pList->GetStyleName(); + } + uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies(); + uno::Reference<container::XNameAccess> xNumberingStyles; + xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles; + uno::Reference<beans::XPropertySet> xStyle(xNumberingStyles->getByName(aListName), uno::UNO_QUERY); + xRet.set(xStyle->getPropertyValue("NumberingRules"), uno::UNO_QUERY); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "GetCurrentNumberingRules: exception caught"); + } + return xRet; +} + +uno::Reference<beans::XPropertySet> DomainMapper_Impl::GetCurrentNumberingCharStyle() +{ + uno::Reference<beans::XPropertySet> xRet; + try + { + sal_Int32 nListLevel = -1; + uno::Reference<container::XIndexAccess> xLevels; + if ( GetTopContextType() == CONTEXT_PARAGRAPH ) + xLevels = GetCurrentNumberingRules(&nListLevel); + if (!xLevels.is()) + { + if (IsOOXMLImport()) + return xRet; + + PropertyMapPtr pContext = m_pTopContext; + if (IsRTFImport() && !IsOpenField()) + { + // Looking up the paragraph context explicitly (and not just taking + // the top context) is necessary for RTF, where formatting of a run + // and of the paragraph mark is not separated. + // We know that the formatting inside a field won't affect the + // paragraph marker formatting, though. + pContext = GetTopContextOfType(CONTEXT_PARAGRAPH); + if (!pContext) + return xRet; + } + + // In case numbering rules is not found via a style, try the direct formatting instead. + std::optional<PropertyMap::Property> oProp = pContext->getProperty(PROP_NUMBERING_RULES); + if (oProp) + { + xLevels.set(oProp->second, uno::UNO_QUERY); + // Found the rules, then also try to look up our numbering level. + oProp = pContext->getProperty(PROP_NUMBERING_LEVEL); + if (oProp) + oProp->second >>= nListLevel; + else + nListLevel = 0; + } + + if (!xLevels.is()) + return xRet; + } + uno::Sequence<beans::PropertyValue> aProps; + xLevels->getByIndex(nListLevel) >>= aProps; + auto pProp = std::find_if(aProps.begin(), aProps.end(), + [](const beans::PropertyValue& rProp) { return rProp.Name == "CharStyleName"; }); + if (pProp != aProps.end()) + { + OUString aCharStyle; + pProp->Value >>= aCharStyle; + uno::Reference<container::XNameAccess> xCharacterStyles; + uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY); + uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies(); + xStyleFamilies->getByName("CharacterStyles") >>= xCharacterStyles; + xRet.set(xCharacterStyles->getByName(aCharStyle), uno::UNO_QUERY_THROW); + } + } + catch( const uno::Exception& ) + { + } + return xRet; +} + +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(aProps.begin(), aProps.end(), + [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; }); + if (pProp != aProps.end()) + 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(aProps.begin(), aProps.end(), + [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; }); + if (pPropVal != aProps.end()) + 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; + } + ref->resolve(m_rDMapper); + + 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]); + } +} +} + +/* 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..dc0693eca --- /dev/null +++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx @@ -0,0 +1,1085 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPER_IMPL_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_DOMAINMAPPER_IMPL_HXX + +#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/style/TabStop.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <queue> +#include <stack> +#include <set> +#include <unordered_map> +#include <vector> +#include <optional> + +#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 XFormField; + } + namespace beans{ class XPropertySet;} +} + +namespace writerfilter { +namespace dmapper { + +class SdtHelper; + +struct PageMar +{ + sal_Int32 top; + sal_Int32 right; + sal_Int32 bottom; + sal_Int32 left; + sal_Int32 header; + sal_Int32 footer; + 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 +}; + +/** + * 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 +}; + +/** + * 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; + 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(const OUString& 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(OUString const& rResult) { m_sResult += rResult; } + const OUString& GetResult() const { return m_sResult; } + + 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) { m_xTextField = 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; + + 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; + } +}; + +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) + { + // same defaults as SvxXMLTabStopContext_Impl + FillChar = ' '; + DecimalChar = ','; + } + 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; + + 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) + : m_xStart(xStart), + m_xEnd(xEnd), + m_aFrameProperties(aFrameProperties), + m_nTableWidth(nTableWidth), + m_nTableWidthType(nTableWidthType) + { + } + css::uno::Any getPropertyValue(const OUString &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; +}; + +/// 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; + 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::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::deque<FieldContextPtr> m_aFieldStack; + bool m_bForceGenericFields; + bool m_bSetUserFieldContent; + bool m_bSetCitation; + bool m_bSetDateValue; + bool m_bIsFirstSection; + bool m_bIsColumnBreakDeferred; + bool m_bIsPageBreakDeferred; + /// 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; + + 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 + std::set<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; + 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_bInStyleSheetImport; //in import of fonts, styles, lists or lfos + 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; + PropertyMapPtr m_pFootnoteContext; + bool m_bHasFootnoteStyle; + bool m_bCheckFootnoteStyle; + /// Skip paragraphs from the <w:separator/> footnote + SkipFootnoteSeparator m_eSkipFootnoteState; + + 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; + // redline data of the terminating run, if it's a moveFrom deletion + RedlineParamsPtr m_pParaMarkerRedlineMoveFrom; + + /// 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_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; + std::unordered_map< sal_Int32, AnnotationPosition > m_aAnnotationPositions; + + void GetCurrentLocale(css::lang::Locale& rLocale); + 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; + +public: + css::uno::Reference<css::text::XTextRange> m_xInsertTextRange; +private: + bool m_bIsNewDoc; + bool m_bIsReadGlossaries; +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(); + + SectionPropertyMap* GetLastSectionContext( ) + { + return dynamic_cast< SectionPropertyMap* >( m_pLastSectionContext.get( ) ); + } + + css::uno::Reference<css::container::XNameContainer> const & GetPageStyles(); + OUString GetUnusedPageStyleName(); + 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 ChainTextFrames(); + + void RemoveDummyParaForTableInSection(); + void AddDummyParaForTableInSection(); + void RemoveLastParagraph( ); + 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;} + + /// 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); + /// Getter method for m_bSdt. + bool GetSdt() const { return m_bSdt;} + bool GetParaChanged() const { return m_bParaChanged;} + 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); + 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(); + + 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 SetStyleSheetImport( bool bSet ) { m_bInStyleSheetImport = bSet;} + bool IsStyleSheetImport()const { return m_bInStyleSheetImport;} + 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; } + + bool IsInTOC() const { return m_bStartTOC; } + + void PushFootOrEndnote( bool bIsFootnote ); + void PopFootOrEndnote(); + bool IsInFootOrEndnote() const { return m_bInFootOrEndnote; } + + 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; } + + 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 + (OUString const& 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(OUString const& 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 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, + const 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; + } + + SectionPropertyMap * GetSectionContext(); + /// If the current paragraph has a numbering style associated, this method returns its character style (part of the numbering rules) + css::uno::Reference<css::beans::XPropertySet> GetCurrentNumberingCharStyle(); + /// If the current paragraph has a numbering style associated, this method returns its numbering rules + css::uno::Reference<css::container::XIndexAccess> GetCurrentNumberingRules(sal_Int32* pListLevel); + + /** + 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;} + + /// 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(); + + /// Handle redline text portions in frames: + /// store their data, and create them after frame creation + bool m_bIsActualParagraphFramed; + std::vector<css::uno::Any> aFramedRedlines; + +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; + 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; +}; + +} //namespace dmapper +} //namespace writerfilter +#endif + +/* 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..84ac070e5 --- /dev/null +++ b/writerfilter/source/dmapper/FFDataHandler.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/. + * + * 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FFDATAHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FFDATAHANDLER_HXX +#include "LoggedResources.hxx" +#include <rtl/ustring.hxx> +#include <vector> +namespace writerfilter { +namespace 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; +}; + + +}} +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FFDATAHANDLER_HXX + +/* 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..af390fe20 --- /dev/null +++ b/writerfilter/source/dmapper/FieldTypes.hxx @@ -0,0 +1,307 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FIELDTYPES_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FIELDTYPES_HXX + +namespace writerfilter { +namespace 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 + /* 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 +}; + +}} +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FIELDTYPES_HXX + +/* 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..c98177db5 --- /dev/null +++ b/writerfilter/source/dmapper/FontTable.cxx @@ -0,0 +1,298 @@ +/* -*- 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 <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> 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(); +} + +bool FontTable::addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream, + const OUString& fontName, const char* extra, + std::vector<unsigned char> key) +{ + if (!m_pImpl->xEmbeddedFontHelper) + m_pImpl->xEmbeddedFontHelper.reset(new EmbeddedFontsHelper); + return 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..edb8b1480 --- /dev/null +++ b/writerfilter/source/dmapper/FontTable.hxx @@ -0,0 +1,108 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FONTTABLE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FONTTABLE_HXX + +#include <memory> +#include <vector> +#include "LoggedResources.hxx" +#include <com/sun/star/io/XInputStream.hpp> + +namespace writerfilter { +namespace 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); + + bool addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream, + const OUString& fontName, const char* extra, + std::vector<unsigned char> 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; +}; +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; +}; + + +}} + +#endif + +/* 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..9c89bc0ad --- /dev/null +++ b/writerfilter/source/dmapper/FormControlHelper.cxx @@ -0,0 +1,375 @@ +/* -*- 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 "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 const char sDOCXForm[] = "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() ) + { + OUString sTmp = m_pFFData->getEntryMacro(); + if ( !sTmp.isEmpty() ) + xNameCont->insertByName( "EntryMacro", uno::makeAny(sTmp) ); + sTmp = m_pFFData->getExitMacro(); + if ( !sTmp.isEmpty() ) + xNameCont->insertByName( "ExitMacro", uno::makeAny(sTmp) ); + + sTmp = m_pFFData->getHelpText(); + if ( !sTmp.isEmpty() ) + xNameCont->insertByName( "Help", uno::makeAny(sTmp) ); + + sTmp = m_pFFData->getStatusText(); + if ( !sTmp.isEmpty() ) + xNameCont->insertByName( "Hint", uno::makeAny(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::makeAny(sTmp) ); + + const sal_uInt16 nMaxLength = m_pFFData->getTextMaxLength(); + if ( nMaxLength ) + { + xNameCont->insertByName( "MaxLength", uno::makeAny(nMaxLength) ); + } + + sTmp = m_pFFData->getTextDefault(); + if ( !sTmp.isEmpty() ) + xNameCont->insertByName( "Content", uno::makeAny(sTmp) ); + + sTmp = m_pFFData->getTextFormat(); + if ( !sTmp.isEmpty() ) + xNameCont->insertByName( "Format", uno::makeAny(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::makeAny(comphelper::containerToSequence(rEntries))); + else + xNameCont->insertByName(ODF_FORMDROPDOWN_LISTENTRY, uno::makeAny(comphelper::containerToSequence(rEntries))); + + sal_Int32 nResult = m_pFFData->getDropDownResult().toInt32(); + if ( nResult ) + { + if ( xNameCont->hasByName(ODF_FORMDROPDOWN_RESULT) ) + xNameCont->replaceByName(ODF_FORMDROPDOWN_RESULT, uno::makeAny( nResult ) ); + else + xNameCont->insertByName(ODF_FORMDROPDOWN_RESULT, uno::makeAny( 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::makeAny<sal_uInt16>(nTmp)); + + nTmp = text::VertOrientation::CENTER; + xShapeProps->setPropertyValue("VertOrient", uno::makeAny<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..dd7f7d38c --- /dev/null +++ b/writerfilter/source/dmapper/FormControlHelper.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/. + * + * 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FORMCONTROLHELPER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FORMCONTROLHELPER_HXX + +#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 { +namespace 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); +}; + +} +} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_FORMCONTROLHELPER_HXX + +/* 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..a2275d95b --- /dev/null +++ b/writerfilter/source/dmapper/GraphicHelpers.cxx @@ -0,0 +1,330 @@ +/* -*- 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 <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: + case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_topMargin: // fallthrough intended + m_nRelation = text::RelOrientation::PAGE_FRAME; + 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_nOrient = text::VertOrientation::NONE; + else if (rAlign == "outside") + m_nOrient = text::VertOrientation::NONE; + 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 + } + // 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&) { + SAL_WARN("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..d28f2fb50 --- /dev/null +++ b/writerfilter/source/dmapper/GraphicHelpers.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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_GRAPHICHELPERS_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_GRAPHICHELPERS_HXX + +#include "LoggedResources.hxx" +#include <com/sun/star/text/WrapTextMode.hpp> + +#include <utility> + +namespace writerfilter { +namespace 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); +}; + +} } + +#endif + +/* 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..372e9f408 --- /dev/null +++ b/writerfilter/source/dmapper/GraphicImport.cxx @@ -0,0 +1,1585 @@ +/* -*- 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/svdobj.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/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> + +using namespace css; + +namespace +{ +bool isTopGroupObj(const uno::Reference<drawing::XShape>& xShape) +{ + SdrObject* pObject = 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 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) + ,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 isYSizeValis () const + { + return bYSizeValid; + } + + void applyMargins(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const + { + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ), uno::makeAny(nLeftMargin)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ), uno::makeAny(nRightMargin)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ), uno::makeAny(nTopMargin)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ), uno::makeAny(nBottomMargin)); + } + + void applyPosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const + { + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT ), + uno::makeAny(nHoriOrient)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT ), + uno::makeAny(nVertOrient)); + } + + void applyRelativePosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties, bool bRelativeOnly = false) const + { + if (!bRelativeOnly) + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_POSITION), + uno::makeAny(nLeftPosition)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_RELATION ), + uno::makeAny(nHoriRelation)); + xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_PAGE_TOGGLE), + uno::makeAny(bPageToggle)); + if (!bRelativeOnly) + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_POSITION), + uno::makeAny(nTopPosition)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_RELATION ), + uno::makeAny(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::makeAny(pZOrderHelper->findZOrder(nZOrder, bOldStyle))); + pZOrderHelper->addItem(xGraphicObjectProperties, nZOrder); + } + } + + void applyName(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const + { + try + { + // Ask the graphic naming helper to find out the name for this + // object: It's around till the end of the import, so it remembers + // what's the first free name. + uno::Reference< container::XNamed > xNamed( xGraphicObjectProperties, uno::UNO_QUERY_THROW ); + xNamed->setName(rDomainMapper.GetGraphicNamingHelper().NameGraphic(sName)); + + if ( sHyperlinkURL.getLength() > 0 ) + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HYPER_LINK_U_R_L ), + uno::makeAny ( sHyperlinkURL )); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_DESCRIPTION ), + uno::makeAny( sAlternativeText )); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TITLE ), + uno::makeAny( title )); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("writerfilter", "failed"); + } + } + + /// 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() +{ + return (com::sun::star::awt::Point(m_pImpl->nLeftPosition, m_pImpl->nTopPosition)); +} + +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::makeAny(comphelper::containerToSequence(aGrabBag))); + } +} + +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 + m_pImpl->bLayoutInCell = nIntValue != 0; + 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(aGrabBag.begin(), aGrabBag.end(), [](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::makeAny( aSize.Height ) ); + xGraphProps->setPropertyValue("Width", + uno::makeAny( 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::makeAny( 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::makeAny + (text::TextContentAnchorType_AS_CHARACTER)); + + // In Word, if a shape is anchored inline, that + // excludes being in the background. + xShapeProps->setPropertyValue("Opaque", uno::makeAny(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::makeAny + (m_pImpl->rDomainMapper.GetCurrentTextRange())); + } + + awt::Size aSize(m_xShape->getSize()); + + if (m_pImpl->isXSizeValid()) + aSize.Width = m_pImpl->getXSize(); + if (m_pImpl->isYSizeValis()) + aSize.Height = m_pImpl->getYSize(); + + sal_Int32 nRotation = 0; + if (bKeepRotation) + { + // Use internal API, getPropertyValue(RotateAngle) + // would use GetObjectRotation(), which is not what + // we want. + if (SdrObject* pShape = GetSdrObjectFromXShape(m_xShape)) + nRotation = pShape->GetRotateAngle(); + } + m_xShape->setSize(aSize); + if (bKeepRotation) + { + xShapeProps->setPropertyValue("RotateAngle", uno::makeAny(nRotation)); + if (nRotation == 0) + { + // Include effect extent in the margin to bring Writer layout closer + // to Word. But do this for non-rotated shapes only, where effect + // extents map to increased margins as-is. + 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); + } + } + } + + m_pImpl->bIsGraphic = true; + + if (!m_pImpl->sAnchorId.isEmpty()) + { + putPropertyToFrameGrabBag("AnchorId", uno::makeAny(m_pImpl->sAnchorId)); + } + } + + 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); + + // This needs to be AT_PARAGRAPH by default and not AT_CHARACTER, otherwise shape will move when the user inserts a new paragraph. + text::TextContentAnchorType eAnchorType = text::TextContentAnchorType_AT_PARAGRAPH; + + if (m_pImpl->bHidden) + { + xShapeProps->setPropertyValue("Visible", uno::makeAny(false)); + xShapeProps->setPropertyValue("Printable", uno::makeAny(false)); + } + + // Avoid setting AnchorType for TextBoxes till SwTextBoxHelper::syncProperty() doesn't handle transition. + bool bTextBox = false; + xShapeProps->getPropertyValue("TextBox") >>= bTextBox; + if (m_pImpl->nVertRelation == text::RelOrientation::TEXT_LINE && !bTextBox) + eAnchorType = text::TextContentAnchorType_AT_CHARACTER; + + xShapeProps->setPropertyValue("AnchorType", uno::makeAny(eAnchorType)); + 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::makeAny(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::makeAny(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::makeAny(nRotation)); + } + + + m_pImpl->applyRelativePosition(xShapeProps, /*bRelativeOnly=*/true); + + xShapeProps->setPropertyValue("SurroundContour", uno::makeAny(m_pImpl->bContour)); + m_pImpl->applyMargins(xShapeProps); + xShapeProps->setPropertyValue("Opaque", uno::makeAny(m_pImpl->bOpaque)); + xShapeProps->setPropertyValue("Surround", uno::makeAny(static_cast<sal_Int32>(m_pImpl->nWrap))); + m_pImpl->applyZOrder(xShapeProps); + m_pImpl->applyName(xShapeProps); + xShapeProps->setPropertyValue("AllowOverlap", + uno::makeAny(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::makeAny(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::makeAny(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::makeAny(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::makeAny(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::makeAny(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::makeAny(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::makeAny(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::makeAny(text::RelOrientation::PAGE_FRAME)); + } + 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::makeAny(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"); + } + 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::makeAny(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; + 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::makeAny(rxGraphic)); + xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE), + uno::makeAny( 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::makeAny(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::makeAny(aShadow)); + } + + // setting properties for all types + if( m_pImpl->bPositionProtected ) + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_POSITION_PROTECTED ), + uno::makeAny(true)); + if( m_pImpl->bSizeProtected ) + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SIZE_PROTECTED ), + uno::makeAny(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::makeAny(m_pImpl->bOpaque)); + } + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND ), + uno::makeAny(static_cast<sal_Int32>(m_pImpl->nWrap))); + if( m_pImpl->rDomainMapper.IsInTable()) + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_FOLLOW_TEXT_FLOW ), + uno::makeAny(m_pImpl->bLayoutInCell)); + + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND_CONTOUR ), + uno::makeAny(m_pImpl->bContour)); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_CONTOUR_OUTSIDE ), + uno::makeAny(m_pImpl->bContourOutside)); + m_pImpl->applyMargins(xGraphicObjectProperties); + } + + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_CONTRAST ), + uno::makeAny(static_cast<sal_Int16>(m_pImpl->nContrast))); + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_LUMINANCE ), + uno::makeAny(static_cast<sal_Int16>(m_pImpl->nBrightness))); + if(m_pImpl->eColorMode != drawing::ColorMode_STANDARD) + { + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC_COLOR_MODE ), + uno::makeAny(m_pImpl->eColorMode)); + } + + xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BACK_COLOR ), + uno::makeAny( 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.get() != nullptr) + { + 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::makeAny(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::makeAny( awt::Size( m_pImpl->getXSize(), m_pImpl->getYSize() ))); + m_pImpl->applyMargins(xGraphicObjectProperties); + m_pImpl->applyName(xGraphicObjectProperties); + } + + // Handle horizontal flip. + bool bMirrored = false; + xShapeProps->getPropertyValue("IsMirrored") >>= bMirrored; + if (bMirrored) + { + xGraphicObjectProperties->setPropertyValue("HoriMirroredOnEvenPages", + uno::makeAny(true)); + xGraphicObjectProperties->setPropertyValue("HoriMirroredOnOddPages", + uno::makeAny(true)); + } + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("writerfilter", ""); + } + return xGraphicObject; +} + + +void GraphicImport::data(const sal_uInt8* buf, size_t len) +{ + beans::PropertyValues aMediaProperties( 1 ); + aMediaProperties[0].Name = getPropertyName(PROP_INPUT_STREAM); + + uno::Reference< io::XInputStream > xIStream = new XInputStreamHelper( buf, len ); + aMediaProperties[0].Value <<= 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..a2495849b --- /dev/null +++ b/writerfilter/source/dmapper/GraphicImport.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/. + * + * 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_GRAPHICIMPORT_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_GRAPHICIMPORT_HXX + +#include <queue> +#include <memory> + +#include "LoggedResources.hxx" + +#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 +{ +namespace 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(); + + 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_endShape() override; + + void handleWrapTextValue(sal_uInt32 nVal); +}; + +typedef tools::SvRef<GraphicImport> GraphicImportPtr; + +}} + +#endif + +/* 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..00eb6005c --- /dev/null +++ b/writerfilter/source/dmapper/LatentStyleHandler.hxx @@ -0,0 +1,41 @@ +/* -*- 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/. + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_LATENTSTYLEHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_LATENTSTYLEHANDLER_HXX + +#include "LoggedResources.hxx" +#include <vector> +#include <com/sun/star/beans/PropertyValue.hpp> + +namespace writerfilter +{ +namespace 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 dmapper +} // namespace writerfilter + +#endif + +/* 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..d8857911e --- /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(const OUString & 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::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 +} + +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..0be0f2ba4 --- /dev/null +++ b/writerfilter/source/dmapper/LoggedResources.hxx @@ -0,0 +1,137 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_LOGGEDRESOURCES_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_LOGGEDRESOURCES_HXX + +#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(const OUString & 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 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; + +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_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() { } + +#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 +}; + +} +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_LOGGEDRESOURCES_HXX + +/* 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..abf4beb88 --- /dev/null +++ b/writerfilter/source/dmapper/MeasureHandler.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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_MEASUREHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_MEASUREHANDLER_HXX + +#include "LoggedResources.hxx" +#include <vector> +#include <com/sun/star/beans/PropertyValue.hpp> + +namespace writerfilter { +namespace 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; +}} + +#endif + +/* 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..3a5dab834 --- /dev/null +++ b/writerfilter/source/dmapper/ModelEventListener.hxx @@ -0,0 +1,45 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_MODELEVENTLISTENER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_MODELEVENTLISTENER_HXX + +#include <com/sun/star/document/XEventListener.hpp> +#include <cppuhelper/implbase.hxx> + +namespace writerfilter { +namespace 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 +}//namespace dmapper +#endif + +/* 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..805e95498 --- /dev/null +++ b/writerfilter/source/dmapper/NumberingManager.cxx @@ -0,0 +1,1166 @@ +/* -*- 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 <comphelper/sequence.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/string.hxx> + +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::makeAny(aValue), beans::PropertyState_DIRECT_VALUE}; +} + +static sal_Int32 lcl_findProperty( const uno::Sequence< beans::PropertyValue >& aProps, const OUString& 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[nPos] = rProp; + } + else + { + // Simply add the new value + aDst.realloc( aDst.getLength( ) + 1 ); + aDst[ 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; } + +bool ListLevel::HasValues() const +{ + return m_bHasValues; +} + +void ListLevel::SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle ) +{ + if (!pStyle) + return; + m_pParaStyle = pStyle; + // AFAICT .docx spec does not identify which numberings or paragraph + // styles are actually the ones to be used for outlines (chapter numbering), + // it only kind of says somewhere that they should be named Heading1 to Heading9. + const OUString styleId= pStyle->sConvertedStyleName; + m_outline = ( styleId.getLength() == RTL_CONSTASCII_LENGTH( "Heading 1" ) + && styleId.match( "Heading ", 0 ) + && styleId[ RTL_CONSTASCII_LENGTH( "Heading " ) ] >= '1' + && styleId[ RTL_CONSTASCII_LENGTH( "Heading " ) ] <= '9' ); +} + +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(const OUString& aStr, const bool bIsSymbol) +{ + //Names found in PropertyIds.cxx, Lines 56-396 + return (aStr=="Adjust" || aStr=="IndentAt" || aStr=="FirstLineIndent" + || aStr=="FirstLineOffset" || aStr=="LeftMargin" + || aStr=="CharInteropGrabBag" || aStr=="ParaInteropGrabBag" || + // 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=="CharFontName") + ); +} +uno::Sequence< beans::PropertyValue > ListLevel::GetCharStyleProperties( ) +{ + PropertyValueVector_t rProperties; + + uno::Sequence< beans::PropertyValue > vPropVals = PropertyMap::GetPropertyValues(); + beans::PropertyValue* aValIter = vPropVals.begin(); + beans::PropertyValue* aEndIter = vPropVals.end(); + const bool bIsSymbol(m_sBulletChar.getLength() <= 1); + for( ; aValIter != aEndIter; ++aValIter ) + if (! IgnoreForCharStyle(aValIter->Name, bIsSymbol)) + rProperties.emplace_back(aValIter->Name, 0, aValIter->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 (!m_sBulletChar.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::makeAny(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::makeAny(static_cast<sal_Int32>(0)), + beans::PropertyState_DIRECT_VALUE); + } + + std::optional<PropertyMap::Property> aPropFont = getProperty(PROP_CHAR_FONT_NAME); + if(aPropFont && !isOutlineNumbering()) + 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 ); + aProps[aProps.getLength( ) - 1] = rParaProp; + aProps[aProps.getLength( ) - 1].Name = sFirstLineIndent; + } + else if ( !hasIndentAt && rParaProp.Name == sParaLeftMargin ) + { + aProps.realloc( aProps.getLength() + 1 ); + aProps[aProps.getLength( ) - 1] = rParaProp; + aProps[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 ); + + ListLevel::Pointer pLevel( new ListLevel ); + m_pCurrentLevel = pLevel; + m_aLevels[nLvl] = pLevel; +} + +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( ) : AbstractListDef( ) +{ + m_nDefaultParentLevels = WW_OUTLINE_MAX + 1; +} + +ListDef::~ListDef( ) +{ +} + +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); + + // [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, aAbstract[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; +} + +void ListDef::CreateNumberingRules( DomainMapper& rDMapper, + uno::Reference<lang::XMultiServiceFactory> const& xFactory) +{ + // 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( ) ) + { + try + { + // Create the numbering style + uno::Reference< beans::XPropertySet > xStyle ( + xFactory->createInstance("com.sun.star.style.NumberingStyle"), + uno::UNO_QUERY_THROW ); + + OUString sStyleName = GetStyleName(GetId(), xStyles); + + xStyles->insertByName( sStyleName, makeAny( xStyle ) ); + + uno::Any oStyle = xStyles->getByName( sStyleName ); + 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 + uno::Sequence< beans::PropertyValue > aAbsCharStyleProps = pAbsLevel->GetCharStyleProperties( ); + 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 ); + } + + if( aAbsCharStyleProps.hasElements() ) + { + // 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)); + } + + // Get the prefix / suffix / Parent numbering + // and add them to the level properties + OUString sText = pAbsLevel->GetBulletChar( ); + // Inherit <w:lvlText> from the abstract level in case the override would be empty. + if (pLevel && !pLevel->GetBulletChar().isEmpty()) + sText = pLevel->GetBulletChar( ); + + aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_PREFIX), OUString(""))); + aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SUFFIX), OUString(""))); + aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LIST_FORMAT), sText)); + + // Total count of replacement holders is determining amount of required parent numbering to include + // TODO: not sure how "%" symbol is escaped. This is not supported yet + sal_Int16 nParentNum = comphelper::string::getTokenCount(sText, '%'); + aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_PARENT_NUMBERING), nParentNum)); + + 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::makeAny(comphelper::containerToSequence(aLvlProps))); + + // Handle the outline level here + if ( pAbsLevel->isOutlineNumbering()) + { + uno::Reference< text::XChapterNumberingSupplier > xOutlines ( + xFactory, uno::UNO_QUERY_THROW ); + uno::Reference< container::XIndexReplace > xOutlineRules = + xOutlines->getChapterNumberingRules( ); + + StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle( ); + aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEADING_STYLE_NAME), pParaStyle->sConvertedStyleName)); + + xOutlineRules->replaceByIndex(nLevel, uno::makeAny(comphelper::containerToSequence(aLvlProps))); + } + + // first level without default outline paragraph style + const tools::SvRef< StyleSheetEntry >& aParaStyle = pAbsLevel->GetParaStyle(); + if ( WW_OUTLINE_MAX + 1 == m_nDefaultParentLevels && ( !aParaStyle || + aParaStyle->sConvertedStyleName.getLength() != RTL_CONSTASCII_LENGTH( "Heading 1" ) || + !aParaStyle->sConvertedStyleName.startsWith("Heading ") || + aParaStyle->sConvertedStyleName[ RTL_CONSTASCII_LENGTH( "Heading " ) ] - u'1' != nLevel ) ) + { + m_nDefaultParentLevels = nLevel; + } + + nLevel++; + } + + // Create the numbering style for these rules + OUString sNumRulesName = getPropertyName( PROP_NUMBERING_RULES ); + xStyle->setPropertyValue( sNumRulesName, uno::makeAny( 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.get(), "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: + { + //this strings contains the definition of the level + //the level number is marked as %n + //these numbers can be mixed randomly together with separators pre- and suffixes + //the Writer supports only a number of upper levels to show, separators is always a dot + //and each level can have a prefix and a suffix + 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 + pCurrentLvl->SetBulletChar( rVal.getString().replace( 0xad, 0x2d ) ); + } + } + 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::makeAny( ConversionHelper::convertTwipToMM100( nIntValue ) )); + break; + case NS_ooxml::LN_CT_Ind_hanging: + if ( pCurrentLvl ) + pCurrentLvl->Insert( + PROP_FIRST_LINE_INDENT, uno::makeAny( - ConversionHelper::convertTwipToMM100( nIntValue ) )); + break; + case NS_ooxml::LN_CT_Ind_firstLine: + if ( pCurrentLvl ) + pCurrentLvl->Insert( + PROP_FIRST_LINE_INDENT, uno::makeAny( 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) + { + 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(); + // See SwDefBulletConfig::InitFont(), default height is 14. + const int nFontHeight = 14; + // Point -> mm100. + const int nHeight = nFontHeight * 35; + if ( aPrefSize.Height * aPrefSize.Width != 0 ) + { + int nWidth = (nHeight * aPrefSize.Width) / aPrefSize.Height; + + awt::Size aSize( convertMm100ToTwip(nWidth), convertMm100ToTwip(nHeight) ); + pCurrentLevel->SetGraphicSize( aSize ); + } + else + { + awt::Size aSize( convertMm100ToTwip(aPrefSize.Width), convertMm100ToTwip(aPrefSize.Height) ); + 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::makeAny( 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 = + dynamic_cast<const StyleSheetPropertyMap*>(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; + + int nLen = m_aLists.size( ); + int i = 0; + while ( !pList && i < nLen ) + { + if ( m_aLists[i]->GetId( ) == nId ) + pList = m_aLists[i]; + i++; + } + + return pList; +} + +void ListsManager::CreateNumberingRules( ) +{ + // Loop over the definitions + for ( const auto& rList : m_aLists ) + { + rList->CreateNumberingRules( m_rDMapper, m_xFactory ); + } + 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..29f139082 --- /dev/null +++ b/writerfilter/source/dmapper/NumberingManager.hxx @@ -0,0 +1,260 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_NUMBERINGMANAGER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_NUMBERINGMANAGER_HXX + +#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 { +namespace 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 + 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_outline; + bool m_bHasValues = false; + +public: + + typedef tools::SvRef< ListLevel > Pointer; + + ListLevel() : + m_nIStartAt(-1) + ,m_nStartOverride(-1) + ,m_nNFC(-1) + ,m_nXChFollow(SvxNumberFormat::LISTTAB) + ,m_outline(false) + {} + + // 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 + const OUString& GetBulletChar( ) const { return m_sBulletChar; }; + const tools::SvRef< StyleSheetEntry >& GetParaStyle( ) const { return m_pParaStyle; }; + bool isOutlineNumbering() const { return m_outline; } + 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); + bool isOutlineNumbering( sal_uInt16 nLvl ) { return GetLevel(nLvl) && GetLevel(nLvl)->isOutlineNumbering(); } +}; + +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; + + /// not custom outline parent levels + sal_Int16 m_nDefaultParentLevels; + +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 + OUString GetStyleName() const { return m_StyleName; }; + OUString GetStyleName(sal_Int32 nId, css::uno::Reference<css::container::XNameContainer> const& xStyles); + + sal_Int16 GetDefaultParentLevels() const { return m_nDefaultParentLevels; }; + + css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValue> > GetMergedPropertyValues(); + + void CreateNumberingRules(DomainMapper& rDMapper, css::uno::Reference<css::lang::XMultiServiceFactory> const& xFactory); + + 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( ); +}; + +} } + +#endif + +/* 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..ae1967a4a --- /dev/null +++ b/writerfilter/source/dmapper/OLEHandler.cxx @@ -0,0 +1,316 @@ +/* -*- 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 ); + uno::Reference< beans::XPropertySet > xShapeProps( xTempShape, uno::UNO_QUERY ); + + try + { + // Shapes in the header or footer should be in the background, since the default is WrapTextMode_THROUGH. + if (m_rDomainMapper.IsInHeaderFooter()) + xShapeProps->setPropertyValue("Opaque", uno::makeAny(false)); + + m_aShapeSize = xTempShape->getSize(); + + xShapeProps->getPropertyValue( getPropertyName( PROP_BITMAP ) ) >>= m_xReplacement; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("writerfilter", "Exception in OLE Handler"); + } + // No need to set the wrapping here as it's either set in oox or will be set later + } + } + break; + default: + OSL_FAIL( "unknown attribute"); + } +} + + +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::makeAny( 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::makeAny(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 uno::Reference<uno::XComponentContext>& xComponentContext) 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(xComponentContext)) + aRet = "8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6"; + } + else if (m_sProgId == "Excel.Sheet.12") + { + if (officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::get(xComponentContext)) + aRet = "47BBB4CB-CE4C-4E80-A591-42D9AE74950F"; + } + else if (m_sProgId == "Equation.3") + { + if (officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::get(xComponentContext)) + 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& ) + { + OSL_FAIL("exception in 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..e173ab40b --- /dev/null +++ b/writerfilter/source/dmapper/OLEHandler.hxx @@ -0,0 +1,102 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_OLEHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_OLEHANDLER_HXX + +#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 { +namespace 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::awt::Size m_aShapeSize; + + css::uno::Reference<css::graphic::XGraphic> m_xReplacement; + + 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 css::uno::Reference<css::uno::XComponentContext>& xComponentContext) const; + + OUString const & GetDrawAspect() const; + OUString const & GetVisAreaWidth() const; + OUString const & GetVisAreaHeight() const; + + OUString copyOLEOStream(css::uno::Reference<css::text::XTextDocument> const& xTextDocument); + + const css::awt::Size& getSize() const { return m_aShapeSize; } + const css::uno::Reference<css::graphic::XGraphic>& getReplacement() const { return m_xReplacement; } + +}; +}} + +#endif + +/* 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..d6a0fdd1f --- /dev/null +++ b/writerfilter/source/dmapper/PageBordersHandler.cxx @@ -0,0 +1,142 @@ +/* -*- 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(); + 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..3bfe23ee6 --- /dev/null +++ b/writerfilter/source/dmapper/PageBordersHandler.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/. + * + * 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PAGEBORDERSHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PAGEBORDERSHANDLER_HXX + +#include "PropertyMap.hxx" + +#include "LoggedResources.hxx" + +#include <com/sun/star/table/BorderLine2.hpp> + +#include <vector> + + +namespace writerfilter { +namespace 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 ); +}; + +} } + +#endif + +/* 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..3aafab2c9 --- /dev/null +++ b/writerfilter/source/dmapper/PropertyIds.cxx @@ -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 . + */ +#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_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_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_INDEX_ENTRY_TYPE : sName = "IndexEntryType"; 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; + } + 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..aa95e5383 --- /dev/null +++ b/writerfilter/source/dmapper/PropertyIds.hxx @@ -0,0 +1,376 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYIDS_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYIDS_HXX + +#include <rtl/ustring.hxx> + +namespace writerfilter { +namespace 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_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_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_INDEX_ENTRY_TYPE + ,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 + }; + +//Returns the UNO string equivalent to eId. +OUString getPropertyName(PropertyIds eId); + +bool isCharacterProperty(const PropertyIds eId); + +bool isParagraphProperty(const PropertyIds eId); + +} //namespace dmapper +} // namespace writerfilter +#endif + +/* 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..d510bfc8b --- /dev/null +++ b/writerfilter/source/dmapper/PropertyMap.cxx @@ -0,0 +1,2039 @@ +/* -*- 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 "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/XTextColumns.hpp> +#include <com/sun/star/text/XText.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> + +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() ) + { + 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; + + 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(aSeq.begin(), aSeq.end(), 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::makeAny( aCharGrabBagValues ) ) ); + + if ( nParaGrabBag ) + m_aValues.push_back( makePropertyValue( "ParaInteropGrabBag", uno::makeAny( aParaGrabBagValues ) ) ); + + if ( nCellGrabBag ) + m_aValues.push_back( makePropertyValue( "CellInteropGrabBag", uno::makeAny( aCellGrabBagValues ) ) ); + + if ( nRowGrabBag ) + m_aValues.push_back( makePropertyValue( "RowInteropGrabBag", uno::makeAny( 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", OUString() ); + } + catch ( ... ) + { + } + } + break; + } + + TagLogger::getInstance().endElement(); + } + + TagLogger::getInstance().endElement(); +} +#endif + +void PropertyMap::InsertProps( const PropertyMapPtr& rMap, const bool bOverwrite ) +{ + if ( rMap ) + { + 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( 2540 ) // page left margin, default 1 inch = 1440 twip -> 2540 1/100 mm + , m_nRightMargin( 2540 ) // page right margin, default 1 inch = 1440 twip -> 2540 1/100 mm + , m_nTopMargin( 2540 ) + , m_nBottomMargin( 2540 ) + , m_nHeaderTop( 1270 ) // 720 twip + , m_nHeaderBottom( 1270 ) // 720 twip + , 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_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::makeAny( static_cast<sal_Int32>(aLetter.getHeight()) ) ); + // page width, 1/100mm + Insert( PROP_WIDTH, uno::makeAny( static_cast<sal_Int32>(aLetter.getWidth()) ) ); + // page left margin, default 0x5a0 (1440) twip -> 2540 1/100 mm + Insert( PROP_LEFT_MARGIN, uno::makeAny( sal_Int32(2540) ) ); + // page right margin, default 0x5a0 (1440) twip -> 2540 1/100 mm + Insert( PROP_RIGHT_MARGIN, uno::makeAny( sal_Int32(2540) ) ); + // page top margin, default 0x5a0 (1440) twip -> 2540 1/100 mm + Insert( PROP_TOP_MARGIN, uno::makeAny( sal_Int32(2540) ) ); + // page bottom margin, default 0x5a0 (1440) twip -> 2540 1/100 mm + Insert( PROP_BOTTOM_MARGIN, uno::makeAny( sal_Int32(2540) ) ); + // page style layout + Insert( PROP_PAGE_STYLE_LAYOUT, uno::makeAny( style::PageStyleLayout_ALL ) ); + uno::Any aFalse( uno::makeAny( false ) ); + Insert( PROP_GRID_DISPLAY, aFalse ); + Insert( PROP_GRID_PRINT, aFalse ); + Insert( PROP_GRID_MODE, uno::makeAny( 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() ) + { + 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::makeAny( 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::makeAny( 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() ) + { + m_sFollowPageStyleName = rDM_Impl.GetUnusedPageStyleName(); + m_aFollowPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ), + uno::UNO_QUERY ); + xPageStyles->insertByName( m_sFollowPageStyleName, uno::makeAny( 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::makeAny( *m_oBorderLines[nBorder] ) ); + if ( xSecond.is() ) + xSecond->setPropertyValue( sBorderName, uno::makeAny( *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 ); + if ( xSecond.is() ) + SetBorderDistance( xSecond, aMarginIds[nBorder], aBorderDistanceIds[nBorder], + m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth ); + } + } + + if ( m_bBorderShadows[BORDER_RIGHT] ) + { + table::ShadowFormat aFormat = getShadowFromBorder( *m_oBorderLines[BORDER_RIGHT] ); + if ( xFirst.is() ) + xFirst->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::makeAny( aFormat ) ); + if ( xSecond.is() ) + xSecond->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::makeAny( 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 ) +{ + 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); + + // 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::makeAny( nMargin ), uno::makeAny( nDistance ) }; + xMultiSet->setPropertyValues( aProperties, aValues ); +} + +void SectionPropertyMap::DontBalanceTextColumns() +{ + try + { + if ( m_xColumnContainer.is() ) + m_xColumnContainer->setPropertyValue( "DontBalanceTextColumns", uno::makeAny( true ) ); + } + catch ( const uno::Exception& ) + { + OSL_FAIL( "Exception in 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::makeAny(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; + 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 + 1) ) && + ( (sal_Int32(m_aColDistance.size()) == m_nColumnCount) || (sal_Int32(m_aColDistance.size()) == m_nColumnCount + 1) ) ) + { + // 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 + 1 ); + 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 ? 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].Width += (nRefValue - nColSum); + assert( pColumn[m_nColumnCount].Width >= 0 ); + + xColumns->setColumns( aColumns ); + } + else + { + xColumns->setColumnCount( m_nColumnCount + 1 ); + xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::makeAny( m_nColumnDistance ) ); + } + + if ( m_bSeparatorLineIsOn ) + { + xColumnPropSet->setPropertyValue( "SeparatorLineIsOn", uno::makeAny( true ) ); + xColumnPropSet->setPropertyValue( "SeparatorLineVerticalAlignment", uno::makeAny( style::VerticalAlignment_TOP ) ); + xColumnPropSet->setPropertyValue( "SeparatorLineRelativeHeight", uno::makeAny( static_cast<sal_Int8>(100) ) ); + xColumnPropSet->setPropertyValue( "SeparatorLineColor", uno::makeAny( static_cast<sal_Int32>(COL_BLACK) ) ); + // 1 twip -> 2 mm100. + xColumnPropSet->setPropertyValue( "SeparatorLineWidth", uno::makeAny( static_cast<sal_Int32>(2) ) ); + } + xColumnContainer->setPropertyValue( sTextColumns, uno::makeAny( 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& ) + { + OSL_FAIL( "Exception in 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 uno::Reference< beans::XPropertySet >& xPrevStyle, + const uno::Reference< beans::XPropertySet >& xStyle, + bool bOmitRightHeader, + bool bOmitLeftHeader, + bool bOmitRightFooter, + bool bOmitLeftFooter ) +{ + 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::makeAny( true ), uno::makeAny( 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 ) + { + uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW ); + uno::Sequence<OUString> aProperties { sFooterIsOn, sFooterIsShared }; + uno::Sequence<uno::Any> aValues { uno::makeAny( true ), uno::makeAny( 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 ) + { + uno::Reference< beans::XPropertySet > xPrevStyle = pLastContext->GetPageStyle( rDM_Impl, + bFirstPage ); + uno::Reference< beans::XPropertySet > xStyle = GetPageStyle( rDM_Impl, + bFirstPage ); + + if ( bFirstPage ) + { + CopyHeaderFooter( xPrevStyle, xStyle, + !m_bFirstPageHeaderLinkToPrevious, true, + !m_bFirstPageFooterLinkToPrevious, true ); + } + else + { + CopyHeaderFooter( xPrevStyle, xStyle, + !m_bDefaultHeaderLinkToPrevious, + !m_bEvenPageHeaderLinkToPrevious, + !m_bDefaultFooterLinkToPrevious, + !m_bEvenPageFooterLinkToPrevious ); + } + } + 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 nHeaderTop = m_nHeaderTop; + if ( HasHeader( bFirstPage ) ) + { + nTopMargin = nHeaderTop; + if ( m_nTopMargin > 0 && m_nTopMargin > nHeaderTop ) + nHeaderTop = m_nTopMargin - nHeaderTop; + else + nHeaderTop = 0; + + // minimum header height 1mm + if ( nHeaderTop < MIN_HEAD_FOOT_HEIGHT ) + nHeaderTop = MIN_HEAD_FOOT_HEIGHT; + } + + + if ( m_nTopMargin >= 0 ) //fixed height header -> see WW8Par6.hxx + { + Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) ); + Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( true ) ); + Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( nHeaderTop - MIN_HEAD_FOOT_HEIGHT ) );// ULSpace.Top() + Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) ); + + if (bCopyFirstToFollow && HasHeader(/*bFirstPage=*/true)) + { + m_aFollowPageStyle->setPropertyValue("HeaderDynamicSpacing", + getProperty(PROP_HEADER_DYNAMIC_SPACING)->second); + m_aFollowPageStyle->setPropertyValue("HeaderHeight", + getProperty(PROP_HEADER_HEIGHT)->second); + } + } + else + { + //todo: old filter fakes a frame into the header/footer to support overlapping + //current setting is completely wrong! + Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) ); + Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( m_nTopMargin - nHeaderTop ) ); + Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) ); + Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( false ) ); + } + + sal_Int32 nBottomMargin = m_nBottomMargin; + sal_Int32 nHeaderBottom = m_nHeaderBottom; + if ( HasFooter( bFirstPage ) ) + { + nBottomMargin = nHeaderBottom; + if ( m_nBottomMargin > 0 && m_nBottomMargin > nHeaderBottom ) + nHeaderBottom = m_nBottomMargin - nHeaderBottom; + else + nHeaderBottom = 0; + if ( nHeaderBottom < MIN_HEAD_FOOT_HEIGHT ) + nHeaderBottom = MIN_HEAD_FOOT_HEIGHT; + } + + if ( m_nBottomMargin >= 0 ) //fixed height footer -> see WW8Par6.hxx + { + Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) ); + Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( true ) ); + Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom - MIN_HEAD_FOOT_HEIGHT ) ); + Insert( PROP_FOOTER_HEIGHT, uno::makeAny( nHeaderBottom ) ); + + if (bCopyFirstToFollow && HasFooter(/*bFirstPage=*/true)) + { + m_aFollowPageStyle->setPropertyValue("FooterDynamicSpacing", + getProperty(PROP_FOOTER_DYNAMIC_SPACING)->second); + m_aFollowPageStyle->setPropertyValue("FooterHeight", + getProperty(PROP_FOOTER_HEIGHT)->second); + } + } + else + { + //todo: old filter fakes a frame into the header/footer to support overlapping + //current setting is completely wrong! + Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) ); + Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( false ) ); + Insert( PROP_FOOTER_HEIGHT, uno::makeAny( m_nBottomMargin - nHeaderBottom ) ); + Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom ) ); + } + + //now set the top/bottom margin for the follow page style + Insert( PROP_TOP_MARGIN, uno::makeAny( std::max<sal_Int32>(nTopMargin, 0) ) ); + Insert( PROP_BOTTOM_MARGIN, uno::makeAny( std::max<sal_Int32>(nBottomMargin, 0) ) ); + + if (bCopyFirstToFollow) + { + if (HasHeader(/*bFirstPage=*/true)) + m_aFollowPageStyle->setPropertyValue("TopMargin", getProperty(PROP_TOP_MARGIN)->second); + if (HasFooter(/*bFirstPage=*/true)) + m_aFollowPageStyle->setPropertyValue("BottomMargin", + getProperty(PROP_BOTTOM_MARGIN)->second); + } +} + +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::makeAny( m_nLeftMargin ) ); + Insert( PROP_RIGHT_MARGIN, uno::makeAny( m_nRightMargin ) ); + + if ( rDM_Impl.m_oBackgroundColor ) + Insert( PROP_BACK_COLOR, uno::makeAny( *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::makeAny(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::makeAny( sal_Int16(text::HorizontalAdjust_RIGHT) ), false ); + else + Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::makeAny( 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 ); +} + +bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo ) +{ + // 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 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( "LeftMargin" ) >>= nLeftMargin ) + nTableWidth += nLeftMargin; + sal_Int32 nRightMargin = 0; + if ( rInfo.getPropertyValue( "RightMargin" ) >>= nRightMargin ) + nTableWidth += nRightMargin; + + sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue( "HoriOrientRelation" ).get<sal_Int16>(); + sal_Int16 nVertOrientRelation = rInfo.getPropertyValue( "VertOrientRelation" ).get<sal_Int16>(); + if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME && nVertOrientRelation == text::RelOrientation::PAGE_FRAME ) + { + sal_Int16 nHoriOrient = rInfo.getPropertyValue( "HoriOrient" ).get<sal_Int16>(); + sal_Int16 nVertOrient = rInfo.getPropertyValue( "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( "HoriOrientPosition" ).get<sal_Int32>(); + sal_Int32 nVertOrientPosition = rInfo.getPropertyValue( "VertOrientPosition" ).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 >= 2 ) + 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::makeAny( 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) + { + 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::makeAny(nTopMargin)); + } + } + rAnchoredObjectAnchors.clear(); +} + +void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl ) +{ + // The default section type is nextPage. + if ( m_nBreakType == -1 ) + m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage; + // if page orientation differs from previous section, it can't be treated as continuous + else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous ) + { + SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext(); + if ( pLastContext ) + { + bool bIsLandscape = false; + std::optional< PropertyMap::Property > pProp = getProperty( PROP_IS_LANDSCAPE ); + if ( pProp ) + pProp->second >>= bIsLandscape; + + bool bPrevIsLandscape = false; + pProp = pLastContext->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; + uno::Reference<text::XTextAppendAndConvert> xBodyText( rDM_Impl.GetBodyText(), uno::UNO_QUERY ); + for ( FloatingTableInfo & rInfo : rPendingFloatingTables ) + { + rInfo.m_nBreakType = m_nBreakType; + if ( FloatingTableConversion( rDM_Impl, rInfo ) ) + { + try + { + xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd, + rInfo.m_aFrameProperties); + } + catch (const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "convertToTextFrame() failed"); + } + } + } + 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::makeAny(m_nLnnMin + 1)); + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup"); + } + } + } + + if (m_nBreakType == static_cast<sal_Int32>(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 > 0 ) + 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::makeAny( 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::makeAny(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::makeAny(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::makeAny(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 == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_nextColumn) + && 0 < m_nColumnCount && !rDM_Impl.IsInComments()) + { + try + { + InheritOrFinalizePageStyles( rDM_Impl ); + 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::makeAny( 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 = GetPageStyle( rDM_Impl, false ); + + HandleMarginsHeaderFooter(/*bFirstPage=*/false, rDM_Impl ); + + if ( rDM_Impl.GetSettingsTable()->GetMirrorMarginSettings() ) + { + Insert( PROP_PAGE_STYLE_LAYOUT, uno::makeAny( style::PageStyleLayout_MIRRORED ) ); + } + uno::Reference< text::XTextColumns > xColumns; + if ( m_nColumnCount > 0 ) + { + // 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 + xColumns = ApplyColumnProperties( xFollowPageStyle, rDM_Impl ); + } + + // these BreakTypes are effectively page-breaks: don't evenly distribute text in columns before a page break; + SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext(); + if ( pLastContext && pLastContext->ColumnCount() ) + pLastContext->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; + + text::WritingMode eWritingMode = text::WritingMode_LR_TB; + pProp = getProperty( PROP_WRITING_MODE ); + if ( pProp ) + pProp->second >>= eWritingMode; + + sal_Int32 nTextAreaHeight = eWritingMode == text::WritingMode_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; + if ( nGridLines >= 0 && nGridLines <= SAL_MAX_INT16 ) + Insert( PROP_GRID_LINES, uno::makeAny( sal_Int16(nGridLines) ) ); + + // PROP_GRID_MODE + Insert( PROP_GRID_MODE, uno::makeAny( static_cast<sal_Int16> (m_nGridType) ) ); + if ( m_nGridType == text::TextGridMode::LINES_AND_CHARS ) + { + Insert( PROP_GRID_SNAP_TO_CHARS, uno::makeAny( m_bGridSnapToChars ) ); + } + + sal_Int32 nCharWidth = 423; //240 twip/ 12 pt + const StyleSheetEntryPtr pEntry = rDM_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( "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<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::makeAny( 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::makeAny(true)); + xDocProperties->setPropertyValue("DefaultPageMode", uno::makeAny(false)); + } + catch ( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup"); + } + + Insert( PROP_GRID_BASE_HEIGHT, uno::makeAny( nGridLinePitch ) ); + Insert( PROP_GRID_BASE_WIDTH, uno::makeAny( nCharWidth ) ); + Insert( PROP_GRID_RUBY_HEIGHT, uno::makeAny( sal_Int32( 0 ) ) ); + + if ( rDM_Impl.IsNewDoc() ) + 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::makeAny( 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 == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) || m_nBreakType == static_cast<sal_Int32>(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> aBlacklist + = { "FooterBackGraphicURL", "BackGraphicURL", "HeaderBackGraphicURL" }; + for ( const auto& rProperty : propertyList ) + { + if ( (rProperty.Attributes & beans::PropertyAttribute::READONLY) == 0 ) + { + if (aBlacklist.find(rProperty.Name) == aBlacklist.end()) + evenOddStyle->setPropertyValue( + rProperty.Name, + pageProperties->getPropertyValue(rProperty.Name)); + } + } + evenOddStyle->setPropertyValue( "FollowStyle", uno::makeAny( *pageStyle ) ); + rDM_Impl.GetPageStyles()->insertByName( evenOddStyleName, uno::makeAny( evenOddStyle ) ); + evenOddStyle->setPropertyValue( "HeaderIsOn", uno::makeAny( false ) ); + evenOddStyle->setPropertyValue( "FooterIsOn", uno::makeAny( false ) ); + CopyHeaderFooter( pageProperties, evenOddStyle ); + *pageStyle = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one). + if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) ) + evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_LEFT ) ); + else if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_oddPage) ) + evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_RIGHT ) ); + } + + if ( xRangeProperties.is() && rDM_Impl.IsNewDoc() ) + { + // 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. + if (!rDM_Impl.IsReadGlossaries() && !rDM_Impl.IsInFootOrEndnote()) + { + xRangeProperties->setPropertyValue( + getPropertyName( PROP_PAGE_DESC_NAME ), + uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName + : m_sFollowPageStyleName ) ); + } + + if (0 <= m_nPageNumber) + { + sal_Int16 nPageNumber = static_cast< sal_Int16 >(m_nPageNumber); + xRangeProperties->setPropertyValue(getPropertyName(PROP_PAGE_NUMBER_OFFSET), + uno::makeAny(nPageNumber)); + } + } + } + catch ( const uno::Exception& ) + { + OSL_FAIL( "Exception in 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 > 0 ) + { + // 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)) / (m_nColumnCount + 1); + } + 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.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 + 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; + beans::PropertyValue* pCharGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "CharInteropGrabBag" ) ); + if ( pCharGrabBag != vPropVals.end() ) + (pCharGrabBag->Value) >>= vCharVals; + beans::PropertyValue* pParaGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "ParaInteropGrabBag" ) ); + if ( pParaGrabBag != vPropVals.end() ) + (pParaGrabBag->Value) >>= vParaVals; + + for ( 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& ) + { + OSL_FAIL( "Exception in 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& ) + { + OSL_FAIL( "Exception in 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..2408b3fc0 --- /dev/null +++ b/writerfilter/source/dmapper/PropertyMap.hxx @@ -0,0 +1,607 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYMAP_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYMAP_HXX + +#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> + +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 { +namespace 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_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; + + 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 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 ); + + // 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_nTopMargin = nSet; } + void SetBottomMargin( sal_Int32 nSet ) { m_nBottomMargin = nSet; } + void SetHeaderTop( sal_Int32 nSet ) { m_nHeaderTop = nSet; } + void SetHeaderBottom( sal_Int32 nSet ) { m_nHeaderBottom = nSet; } + 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; + + 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; } + + 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 dmapper +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYMAP_HXX + +/* 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..59f59b1b2 --- /dev/null +++ b/writerfilter/source/dmapper/PropertyMapHelper.cxx @@ -0,0 +1,100 @@ +/* -*- 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..4b7bee2d7 --- /dev/null +++ b/writerfilter/source/dmapper/PropertyMapHelper.hxx @@ -0,0 +1,41 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYMAPHELPER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYMAPHELPER_HXX + +#include <com/sun/star/beans/PropertyValues.hpp> + +namespace writerfilter +{ +namespace 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 +} +} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_PROPERTYMAPHELPER_HXX + +/* 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..60153d4c6 --- /dev/null +++ b/writerfilter/source/dmapper/SdtHelper.cxx @@ -0,0 +1,253 @@ +/* -*- 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 <vcl/svapp.hxx> +#include <vcl/outdev.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> + +namespace writerfilter::dmapper +{ +using namespace ::com::sun::star; + +/// 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(PushFlags::FONT | 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) + : m_rDM_Impl(rDM_Impl) + , m_bInsideDropDownControl(false) + , m_bHasElements(false) + , m_bOutsideAParagraph(false) +{ +} + +SdtHelper::~SdtHelper() = default; + +void SdtHelper::createDropDownControl() +{ + assert(m_bInsideDropDownControl); + + 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::makeAny(aDefaultText)); + xPropertySet->setPropertyValue( + "Items", uno::makeAny(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::makeAny(aDefaultText)); + xPropertySet->setPropertyValue("Dropdown", uno::makeAny(true)); + xPropertySet->setPropertyValue( + "StringItemList", uno::makeAny(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 + m_aDropDownItems.clear(); + m_bInsideDropDownControl = false; +} + +bool SdtHelper::validateDateFormat() +{ + return !m_sDateFormat.toString().isEmpty() && !m_sLocale.toString().isEmpty(); +} + +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()) + { + 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()) + { + 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::makeAny(sDateFormat)); + xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT_LANGUAGE, + uno::makeAny(m_sLocale.makeStringAndClear())); + } + OUString sFullDate = m_sDate.makeStringAndClear(); + if (!sFullDate.isEmpty()) + { + sal_Int32 nTimeSep = sFullDate.indexOf("T"); + if (nTimeSep != -1) + sFullDate = sFullDate.copy(0, nTimeSep); + xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, uno::makeAny(sFullDate)); + } + } + } +} + +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::makeAny(text::VertOrientation::CENTER)); + + if (rGrabBag.hasElements()) + xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG, uno::makeAny(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) +{ + for (const beans::PropertyValue& i : m_aGrabBag) + if (i.Name == rValueName) + return true; + + return false; +} + +} // 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..3cce8e365 --- /dev/null +++ b/writerfilter/source/dmapper/SdtHelper.hxx @@ -0,0 +1,128 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SDTHELPER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SDTHELPER_HXX + +#include <vector> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +#include <rtl/ustrbuf.hxx> +#include <tools/ref.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace awt +{ +struct Size; +class XControlModel; +} +} +} +} + +namespace writerfilter +{ +namespace dmapper +{ +class DomainMapper_Impl; + +/** + * 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; + + /// Items of the drop-down control. + std::vector<OUString> m_aDropDownItems; + /// Indicator of a drop-down control + bool m_bInsideDropDownControl; + /// 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; + /// 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; + + /// 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); + +public: + explicit SdtHelper(DomainMapper_Impl& rDM_Impl); + ~SdtHelper() override; + + std::vector<OUString>& getDropDownItems() { return m_aDropDownItems; } + OUStringBuffer& getSdtTexts() { return m_aSdtTexts; } + + OUStringBuffer& getDate() { return m_sDate; } + + OUStringBuffer& getDateFormat() { return m_sDateFormat; } + + void setDateFieldStartRange(const css::uno::Reference<css::text::XTextRange>& xStartRange) + { + m_xDateFieldStartRange = xStartRange; + } + + /// Decides if we have enough information to create a date control. + bool validateDateFormat(); + + 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; } + + bool isInsideDropDownControl() const { return m_bInsideDropDownControl; } + void setInsideDropDownControl(bool bInside) { m_bInsideDropDownControl = bInside; } + + /// Create drop-down control from w:sdt's w:dropDownList. + void createDropDownControl(); + /// Create date control from w:sdt's w:date. + void createDateContentControl(); + + 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; +}; + +} // namespace dmapper +} // namespace writerfilter + +#endif + +/* 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..9ce0cdc85 --- /dev/null +++ b/writerfilter/source/dmapper/SectionColumnHandler.cxx @@ -0,0 +1,93 @@ +/* -*- 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..e05d54b80 --- /dev/null +++ b/writerfilter/source/dmapper/SectionColumnHandler.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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SECTIONCOLUMNHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SECTIONCOLUMNHANDLER_HXX + +#include "LoggedResources.hxx" +#include <vector> + +namespace writerfilter { +namespace 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;} + +}; + +}} + +#endif + +/* 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..412826d6a --- /dev/null +++ b/writerfilter/source/dmapper/SettingsTable.cxx @@ -0,0 +1,891 @@ +/* -*- 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 "TagLogger.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/sequence.hxx> +#include <ooxml/resourceids.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 +{ + namespace { + + /** 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. + */ + struct DocumentProtection_Impl + { + /** 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_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; + + DocumentProtection_Impl() + : m_nEdit(NS_ooxml::LN_Value_doc_ST_DocProtect_none) // Specifies that no editing restrictions have been applied to the document + , 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) + { + } + + css::uno::Sequence<css::beans::PropertyValue> toSequence() const; + + bool enabled() const + { + return ! isNone(); + } + + bool isNone() const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_none; }; + }; + + } + + css::uno::Sequence<css::beans::PropertyValue> DocumentProtection_Impl::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); + } + +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_bProtectForm; + bool m_bRedlineProtection; + OUString m_sRedlineProtectionKey; + bool m_bReadOnly; + 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; + + DocumentProtection_Impl m_DocumentProtection; + + 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_bProtectForm(false) + , m_bRedlineProtection(false) + , m_sRedlineProtectionKey() + , m_bReadOnly(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; + } +} + +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[0].Name = "val"; + m_pImpl->m_pThemeFontLangProps[0].Value <<= sStringValue; + break; + case NS_ooxml::LN_CT_Language_eastAsia: + m_pImpl->m_pThemeFontLangProps[1].Name = "eastAsia"; + m_pImpl->m_pThemeFontLangProps[1].Value <<= sStringValue; + break; + case NS_ooxml::LN_CT_Language_bidi: + m_pImpl->m_pThemeFontLangProps[2].Name = "bidi"; + m_pImpl->m_pThemeFontLangProps[2].Value <<= 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[0].Name = "name"; + m_pImpl->m_pCurrentCompatSetting[0].Value <<= sStringValue; + break; + case NS_ooxml::LN_CT_CompatSetting_uri: + m_pImpl->m_pCurrentCompatSetting[1].Name = "uri"; + m_pImpl->m_pCurrentCompatSetting[1].Value <<= sStringValue; + break; + case NS_ooxml::LN_CT_CompatSetting_val: + m_pImpl->m_pCurrentCompatSetting[2].Name = "val"; + m_pImpl->m_pCurrentCompatSetting[2].Value <<= sStringValue; + break; + case NS_ooxml::LN_CT_DocProtect_edit: // 92037 + m_pImpl->m_DocumentProtection.m_nEdit = nIntValue; + // multiple DocProtect_edits should not exist. If they do, last one wins + m_pImpl->m_bRedlineProtection = false; + m_pImpl->m_bProtectForm = false; + m_pImpl->m_bReadOnly = false; + switch (nIntValue) + { + case NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges: + { + m_pImpl->m_bRedlineProtection = true; + m_pImpl->m_sRedlineProtectionKey = m_pImpl->m_DocumentProtection.m_sHash; + break; + } + case NS_ooxml::LN_Value_doc_ST_DocProtect_forms: + m_pImpl->m_bProtectForm = true; + break; + case NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly: + m_pImpl->m_bReadOnly = true; + break; + } + break; + case NS_ooxml::LN_CT_DocProtect_enforcement: // 92039 + m_pImpl->m_DocumentProtection.m_bEnforcement = (nIntValue != 0); + break; + case NS_ooxml::LN_CT_DocProtect_formatting: // 92038 + m_pImpl->m_DocumentProtection.m_bFormatting = (nIntValue != 0); + break; + case NS_ooxml::LN_AG_Password_cryptProviderType: // 92025 + m_pImpl->m_DocumentProtection.m_nCryptProviderType = nIntValue; + break; + case NS_ooxml::LN_AG_Password_cryptAlgorithmClass: // 92026 + if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgClass_hash) // 92023 + m_pImpl->m_DocumentProtection.m_sCryptAlgorithmClass = "hash"; + break; + case NS_ooxml::LN_AG_Password_cryptAlgorithmType: // 92027 + if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgType_typeAny) // 92024 + m_pImpl->m_DocumentProtection.m_sCryptAlgorithmType = "typeAny"; + break; + case NS_ooxml::LN_AG_Password_cryptAlgorithmSid: // 92028 + m_pImpl->m_DocumentProtection.m_sCryptAlgorithmSid = sStringValue; + break; + case NS_ooxml::LN_AG_Password_cryptSpinCount: // 92029 + m_pImpl->m_DocumentProtection.m_CryptSpinCount = nIntValue; + break; + case NS_ooxml::LN_AG_Password_hash: // 92035 + m_pImpl->m_DocumentProtection.m_sHash = sStringValue; + break; + case NS_ooxml::LN_AG_Password_salt: // 92036 + m_pImpl->m_DocumentProtection.m_sSalt = 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(*this, 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 = sVal.copy(nSpace + 1, nDbo - nSpace - 1) + + sVal.copy(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; + 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_bProtectForm && m_pImpl->m_DocumentProtection.m_bEnforcement; +} + +bool SettingsTable::GetReadOnly() const +{ + return m_pImpl->m_bReadOnly && m_pImpl->m_DocumentProtection.m_bEnforcement; +} + +bool SettingsTable::GetNoHyphenateCaps() const +{ + return m_pImpl->m_bNoHyphenateCaps; +} + +sal_Int16 SettingsTable::GetHypenationZone() const +{ + return m_pImpl->m_nHyphenationZone; +} + +OUString SettingsTable::GetDecimalSymbol() const +{ + return m_pImpl->m_sDecimalSymbol; +} + +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); +} + +css::uno::Sequence<css::beans::PropertyValue> SettingsTable::GetDocumentProtectionSettings() const +{ + return m_pImpl->m_DocumentProtection.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 ); + + if (GetWordCompatibilityMode() <= 14) + { + 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("MsWordCompMinLineHeightByFly", uno::makeAny(true)); + } + + // Show changes value + if (xDocProps.is()) + { + bool bHideChanges = !m_pImpl->m_bShowInsDelChanges || !m_pImpl->m_bShowMarkupChanges; + xDocProps->setPropertyValue("ShowChanges", uno::makeAny( !bHideChanges || m_pImpl->m_bShowFormattingChanges ) ); + } + + // Record changes value + if (xDocProps.is()) + { + xDocProps->setPropertyValue("RecordChanges", uno::makeAny( m_pImpl->m_bRecordChanges ) ); + // Password protected Record changes + if ( m_pImpl->m_bRecordChanges && m_pImpl->m_bRedlineProtection && m_pImpl->m_DocumentProtection.m_bEnforcement ) + { + // 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); + aDummyKey[0] = 1; + xDocProps->setPropertyValue("RedlineProtectionKey", uno::makeAny( 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) + { + 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::makeAny(true)); + } + if (m_pImpl->m_bNoHyphenateCaps) + { + uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY); + xPropertySet->setPropertyValue("ParaHyphenationNoCaps", uno::makeAny(true)); + } + 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 = uno::makeAny(static_cast<sal_Int8>(2)); + xPropertySet->setPropertyValue("ParaWidows", aAny); + xPropertySet->setPropertyValue("ParaOrphans", aAny); + } + } +} + +bool SettingsTable::GetCompatSettingValue( const OUString& 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; +} + +}//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..6dd0545ad --- /dev/null +++ b/writerfilter/source/dmapper/SettingsTable.hxx @@ -0,0 +1,112 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SETTINGSTABLE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SETTINGSTABLE_HXX + +#include "LoggedResources.hxx" +#include <com/sun/star/text/XTextDocument.hpp> +#include <memory> + +namespace com::sun::star::lang { + class XMultiServiceFactory; + struct Locale; +} + +namespace writerfilter { +namespace 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 GetHypenationZone() const; + + OUString GetDecimalSymbol() 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; + + void ApplyProperties(css::uno::Reference<css::text::XTextDocument> const& xDoc); + + bool GetCompatSettingValue( const OUString& sCompatName ) const; + sal_Int32 GetWordCompatibilityMode() const; + + const OUString & GetCurrentDatabaseDataSource() 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; +}} + +#endif + +/* 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..2ea94a963 --- /dev/null +++ b/writerfilter/source/dmapper/SmartTagHandler.cxx @@ -0,0 +1,128 @@ +/* -*- 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()) + { + 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..29dbeeb3b --- /dev/null +++ b/writerfilter/source/dmapper/SmartTagHandler.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/. + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SMARTTAGHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_SMARTTAGHANDLER_HXX + +#include <vector> + +#include "LoggedResources.hxx" + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace rdf +{ +class XDocumentMetadataAccess; +} +namespace text +{ +class XTextDocument; +class XTextRange; +} +namespace uno +{ +class XComponentContext; +} +} +} +} + +namespace writerfilter +{ +namespace 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 dmapper +} // namespace writerfilter + +#endif + +/* 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..d03be9cba --- /dev/null +++ b/writerfilter/source/dmapper/StyleSheetTable.cxx @@ -0,0 +1,1645 @@ +/* -*- 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/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() : + sStyleIdentifierD() + ,bIsDefaultStyle(false) + ,bInvalidHeight(false) + ,bHasUPE(false) + ,nStyleTypeCode(STYLE_TYPE_UNKNOWN) + ,sBaseStyleIdentifier() + ,sNextStyleIdentifier() + ,pProperties(new StyleSheetPropertyMap) + ,bAutoRedefine(false) +{ +} + +StyleSheetEntry::~StyleSheetEntry() +{ +} + +TableStyleSheetEntry::TableStyleSheetEntry( StyleSheetEntry const & rEntry ): + StyleSheetEntry( ) +{ + bIsDefaultStyle = rEntry.bIsDefaultStyle; + bInvalidHeight = rEntry.bInvalidHeight; + bHasUPE = rEntry.bHasUPE; + nStyleTypeCode = STYLE_TYPE_TABLE; + sBaseStyleIdentifier = rEntry.sBaseStyleIdentifier; + sNextStyleIdentifier = rEntry.sNextStyleIdentifier; + 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); + + 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, const PropertyValueVector_t& rPropertyValues): + sCharStyleName( rCharStyleName ), + aPropertyValues( rPropertyValues ) + {} +}; + +} + +typedef std::vector< ListCharStylePropertyMap_t > ListCharStylePropertyVector_t; + + +struct StyleSheetTable_Impl +{ + DomainMapper& m_rDMapper; + uno::Reference< text::XTextDocument> m_xTextDocument; + uno::Reference< beans::XPropertySet> m_xTextDefaults; + std::vector< StyleSheetEntryPtr > m_aStyleSheetEntries; + StyleSheetEntryPtr m_pCurrentEntry; + PropertyMapPtr m_pDefaultParaProps, m_pDefaultCharProps; + OUString m_sDefaultParaStyleName; //WW8 name + ListCharStylePropertyVector_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_pCurrentEntry(), + 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 = uno::makeAny( 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(); + 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->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_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_link: + 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_link: + { + aValue.Name = "link"; + aValue.Value <<= sStringValue; + } + 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: + 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::makeAny( sal_Int32(0) ) ); + } + m_pImpl->m_rDMapper.PopStyleSheetProperties(); + applyDefaults( true ); + m_pImpl->m_bHasImportedDefaultParaProps = true; + break; + case NS_ooxml::LN_CT_RPrDefault_rPr: + case NS_ooxml::LN_CT_DocDefaults_rPrDefault: + m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultCharProps ); + resolveSprmProps( m_pImpl->m_rDMapper, rSprm ); + m_pImpl->m_rDMapper.PopStyleSheetProperties(); + applyDefaults( false ); + break; + case NS_ooxml::LN_CT_TblPrBase_jc: //table alignment - row properties! + m_pImpl->m_pCurrentEntry->pProperties->Insert( PROP_HORI_ORIENT, + uno::makeAny( 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 ); + if ( !pTblHandler->sprm( rSprm ) ) + { + m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->pProperties ); + + 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 ); + 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 ); + } + 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::makeAny(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 ( auto& pEntry : m_pImpl->m_aStyleSheetEntries ) + { + StyleSheetPropertyMap* pStyleSheetProperties = nullptr; + if ( pEntry->nStyleTypeCode == STYLE_TYPE_PARA && (pStyleSheetProperties = dynamic_cast<StyleSheetPropertyMap*>(pEntry->pProperties.get())) ) + { + // ListId 0 means turn off numbering - to cancel inheritance - so make sure that can be set. + // Ignore the special "chapter numbering" outline styles as they are handled internally. + if ( pStyleSheetProperties->GetListId() > -1 && pStyleSheetProperties->GetOutlineLevel() == -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::makeAny(sNumberingStyleName) ); + } + } + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying numbering style name 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<beans::PropertyValue> aTableStylesVec; + for( auto& pEntry : m_pImpl->m_aStyleSheetEntries ) + { + if( pEntry->nStyleTypeCode == STYLE_TYPE_CHAR || pEntry->nStyleTypeCode == STYLE_TYPE_PARA || pEntry->nStyleTypeCode == STYLE_TYPE_LIST ) + { + bool bParaStyle = pEntry->nStyleTypeCode == STYLE_TYPE_PARA; + 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::makeAny( xStyle ) ); + xStyle.set(xStyles->getByName(sConvertedStyleName), uno::UNO_QUERY_THROW); + + StyleSheetPropertyMap* pPropertyMap = dynamic_cast<StyleSheetPropertyMap*>(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(1); + aLvlProps[0].Name = "NumberingType"; + aLvlProps[0].Value <<= style::NumberingType::NUMBER_NONE; + xNumberingRules->replaceByIndex(i, uno::makeAny(aLvlProps)); + xPropertySet->setPropertyValue("NumberingRules", uno::makeAny(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.get() != nullptr && !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 = uno::makeAny(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::makeAny( sWesternFontName ), false); + + // CJK ... apply second font + const FontEntry::Pointer_t pCJKFontEntry(rFontTable->getFontEntry( 2 )); + pEntry->pProperties->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::makeAny( 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::makeAny( 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 ) + { + // 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 = dynamic_cast<StyleSheetPropertyMap*>(pEntry ? pEntry->pProperties.get() : nullptr); + + if ( pStyleSheetProperties ) + { + beans::PropertyValue aLvlVal( getPropertyName( PROP_OUTLINE_LEVEL ), 0, + uno::makeAny( sal_Int16( pStyleSheetProperties->GetOutlineLevel( ) + 1 ) ), + beans::PropertyState_DIRECT_VALUE ); + aPropValues.push_back(aLvlVal); + + // tdf#95495 missing list level settings in custom styles in old DOCX: apply settings of the parent style + if (pStyleSheetProperties->GetListLevel() == -1 && pStyleSheetProperties->GetOutlineLevel() == -1) + { + const beans::PropertyValues aPropGrabBag = pEntry->GetInteropGrabBagSeq(); + for (const auto& rVal : aPropGrabBag) + { + if (rVal.Name == "customStyle" && rVal.Value == true) + { + OUString sBaseId = pEntry->sBaseStyleIdentifier; + for (const auto& aSheetProps : m_pImpl->m_aStyleSheetEntries) + { + if (aSheetProps->sStyleIdentifierD == sBaseId) + { + StyleSheetPropertyMap& rStyleSheetProps + = dynamic_cast<StyleSheetPropertyMap&>(*aSheetProps->pProperties); + pStyleSheetProperties->SetListLevel(rStyleSheetProps.GetListLevel()); + pStyleSheetProperties->SetOutlineLevel(rStyleSheetProps.GetOutlineLevel()); + break; + } + } + } + } + } + } + + 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::makeAny( xStyle) ); + } + + beans::PropertyValues aGrabBag = pEntry->GetInteropGrabBagSeq(); + uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY); + if (aGrabBag.hasElements()) + { + xPropertySet->setPropertyValue("StyleInteropGrabBag", uno::makeAny(aGrabBag)); + } + + // Only paragraph styles support automatic updates. + if (pEntry->bAutoRedefine && bParaStyle) + xPropertySet->setPropertyValue("IsAutoUpdate", uno::makeAny(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::makeAny(iter.first) ); + } + catch( uno::Exception & ) {} + } + + 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::makeAny(comphelper::containerToSequence(aGrabBag))); + } + } + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("writerfilter", "Styles could not be imported completely"); + } +} + + +StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByISTD(const OUString& sIndex) +{ + StyleSheetEntryPtr pRet; + for(const StyleSheetEntryPtr & rpEntry : m_pImpl->m_aStyleSheetEntries) + { + if( rpEntry->sStyleIdentifierD == sIndex) + { + pRet = rpEntry; + break; + } + } + return pRet; +} + + +StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByConvertedStyleName(const OUString& 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 + //TODO: performance issue - put styles list into a map sorted by its sStyleIdentifierD members + for( const auto& rStyleSheetEntryPtr : m_pImpl->m_aStyleSheetEntries ) + { + if( rWWName == rStyleSheetEntryPtr->sStyleIdentifierD ) + sRet = rStyleSheetEntryPtr->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" }, + { "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 Characters" }, + { "Footnote Reference", "Footnote Characters" }, +// { "Annotation Reference", "" }, + { "Line Number", "Line numbering" }, + { "Page Number", "Page Number" }, + { "endnote reference", "Endnote Characters" }, + { "Endnote Reference", "Endnote Characters" }, + { "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::makeAny(sal_Int16(text::WritingMode_LR_TB))); + SetDefaultParaProps(PROP_PARA_ADJUST, uno::makeAny(sal_Int16(style::ParagraphAdjust_LEFT))); + + // Widow/Orphan -> set both to two if not already set + uno::Any aTwo = uno::makeAny(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& ) + { + OSL_FAIL( "setPropertyValue exception"); + } + } + } + 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& ) + { + OSL_FAIL( "setPropertyValue 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; + const char cListLabel[] = "ListLabel "; + uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW ); + uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies(); + uno::Reference<container::XNameContainer> xCharStyles; + xStyleFamilies->getByName("CharacterStyles") >>= xCharStyles; + //search for all character styles with the name sListLabel + <index> + sal_Int32 nStyleFound = 0; + const uno::Sequence< OUString > aStyleNames = xCharStyles->getElementNames(); + for( const auto& rStyleName : aStyleNames ) + { + OUString sSuffix; + if( rStyleName.startsWith( cListLabel, &sSuffix ) ) + { + sal_Int32 nSuffix = sSuffix.toInt32(); + if( nSuffix > 0 && nSuffix > nStyleFound ) + nStyleFound = nSuffix; + } + } + sListLabel = cListLabel + OUString::number( ++nStyleFound ); + //create a new one otherwise + 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& ) + { + OSL_FAIL( "Exception in StyleSheetTable::getOrCreateCharStyle - Style::setPropertyValue"); + } + } + xCharStyles->insertByName( sListLabel, uno::makeAny( xStyle) ); + m_pImpl->m_aListCharStylePropertyVector.emplace_back( sListLabel, rCharProperties ); + } + catch( const uno::Exception& ) + { + OSL_FAIL( "Exception in 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..9381b90ea --- /dev/null +++ b/writerfilter/source/dmapper/StyleSheetTable.hxx @@ -0,0 +1,151 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_STYLESHEETTABLE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_STYLESHEETTABLE_HXX + +#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 { +namespace 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 bInvalidHeight; + bool bHasUPE; //universal property expansion + StyleType nStyleTypeCode; //sgc + OUString sBaseStyleIdentifier; + OUString sNextStyleIdentifier; + OUString sStyleName; + const PropertyMapPtr pProperties; ///< always StyleSheetPropertyMap + 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 ApplyNumberingStyleNameToParaStyles(); + void ApplyStyleSheets( const FontTablePtr& rFontTable ); + StyleSheetEntryPtr FindStyleSheetByISTD(const OUString& sIndex); + StyleSheetEntryPtr FindStyleSheetByConvertedStyleName(const OUString& 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 ); +}; + + +}} + +#endif + +/* 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..acd29d5ac --- /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", OUString::fromUtf8(msfilter::util::ConvertColor(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 ) + { + 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::makeAny( m_aTopBorderLines[0] ) ); + if( !m_aLeftBorderLines.empty() ) + pCellProperties->Insert( PROP_LEFT_BORDER, uno::makeAny( m_aLeftBorderLines[0] ) ); + if( !m_aBottomBorderLines.empty() ) + pCellProperties->Insert( PROP_BOTTOM_BORDER, uno::makeAny( m_aBottomBorderLines[0] ) ); + if( !m_aRightBorderLines.empty() ) + pCellProperties->Insert( PROP_RIGHT_BORDER, uno::makeAny( m_aRightBorderLines[0] ) ); + if( !m_aInsideHBorderLines.empty() ) + pCellProperties->Insert( META_PROP_HORIZONTAL_BORDER, uno::makeAny( m_aInsideHBorderLines[0] ) ); + if( !m_aInsideVBorderLines.empty() ) + pCellProperties->Insert( META_PROP_VERTICAL_BORDER, uno::makeAny( 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..c7e74263f --- /dev/null +++ b/writerfilter/source/dmapper/TDefTableHandler.hxx @@ -0,0 +1,76 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TDEFTABLEHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TDEFTABLEHANDLER_HXX + +#include "LoggedResources.hxx" +#include <vector> +namespace com::sun::star{ + namespace table { + struct BorderLine2; + } + namespace beans { + struct PropertyValue; + } +} + +namespace writerfilter { +namespace 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); +}; +}} + +#endif + +/* 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..3140a00d7 --- /dev/null +++ b/writerfilter/source/dmapper/TableData.hxx @@ -0,0 +1,357 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEDATA_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEDATA_HXX + +#include <com/sun/star/text/XTextRange.hpp> + +#include "PropertyMap.hxx" + +#include <vector> + +namespace writerfilter +{ +namespace 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; + +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) + { + } + + /** + 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; } +}; + +/** + 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; + +public: + typedef tools::SvRef<RowData> Pointer_t; + + RowData() {} + + RowData(const RowData& rRowData) + : SvRefBase(), mCells(rRowData.mCells), mpProperties(rRowData.mpProperties) + { + } + + /** + 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; + } +}; + +/** + 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; + } +}; + +} +} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_RESOURCEMODEL_TABLEDATA_HXX + +/* 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..50e948b00 --- /dev/null +++ b/writerfilter/source/dmapper/TableManager.cxx @@ -0,0 +1,501 @@ +/* -*- 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(); } + +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) + { + 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)); + } + 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 + if (pTableData) + { + sal_uInt32 nGridBefore + = mpTableDataHandler->getDomainMapperImpl().getTableManager().getCurrentGridBefore(); + 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::makeAny(aBorderLine)); + pCellProperties->Insert(PROP_LEFT_BORDER, css::uno::makeAny(aBorderLine)); + pCellProperties->Insert(PROP_BOTTOM_BORDER, css::uno::makeAny(aBorderLine)); + pCellProperties->Insert(PROP_RIGHT_BORDER, css::uno::makeAny(aBorderLine)); + pTableData->getCurrentRow()->addCell(pTableData->getCurrentRow()->getCellStart(0), + pCellProperties, /*bAddBefore=*/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..5e18becab --- /dev/null +++ b/writerfilter/source/dmapper/TableManager.hxx @@ -0,0 +1,515 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEMANAGER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEMANAGER_HXX + +#include <memory> +#include <stack> + +#include "PropertyMap.hxx" +#include "TableData.hxx" + +#include <dmapper/resourcemodel.hxx> + +namespace writerfilter +{ +namespace 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() + { + mpCellProps = getTableExceptionProps(); + } + + 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; + } + + 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_uInt32 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; + + + void setTableStartsAtCellStart(bool bTableStartsAtCellStart); + void setCellLastParaAfterAutospacing(bool bIsAfterAutospacing); + bool isCellLastParaAfterAutospacing() const {return m_bCellLastParaAfterAutospacing;} +}; + +} + +} + +#endif // INCLUDED_WRITERFILTER_INC_RESOURCEMODEL_TABLEMANAGER_HXX + +/* 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..2bea7876a --- /dev/null +++ b/writerfilter/source/dmapper/TablePositionHandler.cxx @@ -0,0 +1,156 @@ +/* -*- 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") + , m_aVertAnchor("margin") + , m_aHorzAnchor("text") +{ +} + +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..1a7ab58d2 --- /dev/null +++ b/writerfilter/source/dmapper/TablePositionHandler.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/. + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPOSITIONHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPOSITIONHANDLER_HXX + +#include "LoggedResources.hxx" + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace beans +{ +struct PropertyValue; +} +} +} +} + +namespace writerfilter +{ +namespace dmapper +{ +/// Handler for floating table positioning +class TablePositionHandler : public LoggedProperties +{ + OUString m_aVertAnchor; + OUString m_aYSpec; + OUString m_aHorzAnchor; + 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 dmapper +} // namespace writerfilter + +#endif + +/* 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..8b5563669 --- /dev/null +++ b/writerfilter/source/dmapper/TablePropertiesHandler.cxx @@ -0,0 +1,394 @@ +/* -*- 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 "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.get() != nullptr) ? 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::makeAny( pMeasureHandler->GetRowHeightSizeType() ), false); + pPropMap->Insert( PROP_HEIGHT, uno::makeAny(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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny(pCellMarginHandler->m_nTopMargin)); + if (pCellMarginHandler->m_bLeftMarginValid) + pCellProperties->Insert(PROP_LEFT_BORDER_DISTANCE, uno::makeAny(pCellMarginHandler->m_nLeftMargin)); + if (pCellMarginHandler->m_bBottomMarginValid) + pCellProperties->Insert(PROP_BOTTOM_BORDER_DISTANCE, uno::makeAny(pCellMarginHandler->m_nBottomMargin)); + if (pCellMarginHandler->m_bRightMarginValid) + pCellProperties->Insert(PROP_RIGHT_BORDER_DISTANCE, uno::makeAny(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::makeAny(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 ? OUStringLiteral("tblStyleRowBandSize") : OUStringLiteral("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..514adbe12 --- /dev/null +++ b/writerfilter/source/dmapper/TablePropertiesHandler.hxx @@ -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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPROPERTIESHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TABLEPROPERTIESHANDLER_HXX + +#include "PropertyMap.hxx" + +#include "TableManager.hxx" +#include <dmapper/resourcemodel.hxx> + +#include <vector> + +namespace writerfilter { +namespace 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()); + }; +}; + +} } + +#endif + +/* 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..6c655589d --- /dev/null +++ b/writerfilter/source/dmapper/TagLogger.cxx @@ -0,0 +1,237 @@ +/* -*- 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); + xmlTextWriterSetIndentString(pWriter, BAD_CAST(" ")); + xmlTextWriterSetIndent( pWriter, 4 ); + } + + void TagLogger::startDocument() + { + if (!pWriter) + return; + xmlTextWriterStartDocument( pWriter, nullptr, nullptr, nullptr ); + xmlTextWriterStartElement( pWriter, BAD_CAST( "root" ) ); + } + + void TagLogger::endDocument() + { + if (!pWriter) + return; + xmlTextWriterEndDocument( pWriter ); + xmlFreeTextWriter( pWriter ); + pWriter = nullptr; + } + +#endif + +namespace { + +struct TheTagLogger: + public rtl::Static<TagLogger, TheTagLogger> +{}; + +} + + TagLogger& TagLogger::getInstance() + { + return TheTagLogger::get(); + } + +#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() ); + 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() ); + xmlTextWriterWriteAttribute( pWriter, xmlName, xmlValue ); + + xmlFree( xmlValue ); + xmlFree( xmlName ); + } + +#ifdef DBG_UTIL + void TagLogger::attribute(const std::string & name, const OUString & 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() ); + 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 ) + { + xmlTextWriterWriteFormatAttribute( pWriter, xmlName, + "%" SAL_PRIdINT32, nInt ); + } + else if ( aAny >>= nFloat ) + { + 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() ); + xmlTextWriterWriteString( pWriter, xmlChars ); + xmlFree( xmlChars ); + } + + void TagLogger::chars(const OUString & rChars) + { + chars(OUStringToOString(rChars, RTL_TEXTENCODING_ASCII_US).getStr()); + } + + void TagLogger::endElement() + { + if (!pWriter) + return; + 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..e61895a30 --- /dev/null +++ b/writerfilter/source/dmapper/TagLogger.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/. + * + * 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TAGLOGGER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TAGLOGGER_HXX + +#include <rtl/ustring.hxx> +#include <tools/ref.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <string> +#include <libxml/xmlwriter.h> + +namespace writerfilter +{ + + class TagLogger + { + private: + static tools::SvRef<TagLogger> instance; + + 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, const OUString & 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(const OUString & chars); + void endElement(); +#endif + }; +} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TAGLOGGER_HXX + +/* 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..001cecbd9 --- /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::makeAny(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::makeAny(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::makeAny(pCellMarginHandler->m_nTopMargin) ); + if( pCellMarginHandler->m_bBottomMarginValid ) + m_pProperties->Insert( META_PROP_CELL_MAR_BOTTOM, uno::makeAny(pCellMarginHandler->m_nBottomMargin) ); + if( pCellMarginHandler->m_bLeftMarginValid ) + m_pProperties->Insert( META_PROP_CELL_MAR_LEFT, uno::makeAny(pCellMarginHandler->m_nLeftMargin) ); + if( pCellMarginHandler->m_bRightMarginValid ) + m_pProperties->Insert( META_PROP_CELL_MAR_RIGHT, uno::makeAny(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..578b3a98a --- /dev/null +++ b/writerfilter/source/dmapper/TblStylePrHandler.hxx @@ -0,0 +1,86 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TBLSTYLEPRHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TBLSTYLEPRHANDLER_HXX + +#include "TablePropertiesHandler.hxx" + +#include "DomainMapper.hxx" +#include "LoggedResources.hxx" +#include <memory> +#include <vector> + +namespace writerfilter { +namespace 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); +}; + +}} + +#endif + +/* 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..13fed5237 --- /dev/null +++ b/writerfilter/source/dmapper/TextEffectsHandler.cxx @@ -0,0 +1,803 @@ +/* -*- 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"; + } + return aIdMap[aId]; +} + +const char constAttributesSequenceName[] = "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 = uno::makeAny(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 = uno::makeAny(getLineCapString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("cap", aAny); + } + break; + case NS_ooxml::LN_CT_TextOutlineEffect_cmpd: + { + uno::Any aAny = uno::makeAny(getCompoundLineString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("cmpd", aAny); + } + break; + case NS_ooxml::LN_CT_TextOutlineEffect_algn: + { + uno::Any aAny = uno::makeAny(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 = uno::makeAny(getOnOffString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("scaled", aAny); + } + break; + case NS_ooxml::LN_CT_PathShadeProperties_path: + { + uno::Any aAny = uno::makeAny(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 = uno::makeAny(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 = uno::makeAny(getPresetCameraTypeString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("prst", aAny); + } + break; + case NS_ooxml::LN_CT_LightRig_rig: + { + uno::Any aAny = uno::makeAny(getLightRigTypeString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("rig", aAny); + } + break; + case NS_ooxml::LN_CT_LightRig_dir: + { + uno::Any aAny = uno::makeAny(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 = uno::makeAny(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 = uno::makeAny(getBevelPresetTypeString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("prst", aAny); + } + break; + case NS_ooxml::LN_CT_Ligatures_val: + { + uno::Any aAny = uno::makeAny(getLigaturesString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("val", aAny); + } + break; + case NS_ooxml::LN_CT_NumForm_val: + { + uno::Any aAny = uno::makeAny(getNumFormString(sal_Int32(aValue.getInt()))); + mpGrabBagStack->appendElement("val", aAny); + } + break; + case NS_ooxml::LN_CT_NumSpacing_val: + { + uno::Any aAny = uno::makeAny(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 = uno::makeAny(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..60e98d64b --- /dev/null +++ b/writerfilter/source/dmapper/TextEffectsHandler.hxx @@ -0,0 +1,76 @@ +/* -*- 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/. + * + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TEXTEFFECTSHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TEXTEFFECTSHANDLER_HXX + +#include "LoggedResources.hxx" + +#include <com/sun/star/beans/PropertyValue.hpp> + +#include "PropertyIds.hxx" + +#include <oox/helper/grabbagstack.hxx> + +#include <memory> +#include <optional> + +namespace writerfilter { +namespace 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); + + // LoggedProperties + virtual void lcl_attribute(Id aName, Value& aValue) override; + virtual void lcl_sprm(Sprm& sprm) override; + +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); + +}; + +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TEXTEFFECTSHANDLER_HXX + +/* 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..ffa2262cd --- /dev/null +++ b/writerfilter/source/dmapper/ThemeTable.cxx @@ -0,0 +1,564 @@ +/* -*- 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_currentFontThemeEntry(), + 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..c72c53c9a --- /dev/null +++ b/writerfilter/source/dmapper/ThemeTable.hxx @@ -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/. + * + * 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_THEMETABLE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_THEMETABLE_HXX + +#include "LoggedResources.hxx" +#include <com/sun/star/beans/PropertyValue.hpp> +#include <i18nlangtag/lang.h> +#include <memory> + +namespace writerfilter { +namespace 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; +}} + +#endif + +/* 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..e57a1ac65 --- /dev/null +++ b/writerfilter/source/dmapper/TrackChangesHandler.hxx @@ -0,0 +1,44 @@ +/* -*- 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/. + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TRACKCHANGESHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_TRACKCHANGESHANDLER_HXX + +#include "LoggedResources.hxx" +#include <com/sun/star/beans/PropertyValue.hpp> +#include <dmapper/PropertyMap.hxx> + +namespace writerfilter { +namespace 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; +}; +}} + +#endif + +/* 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..0eec61089 --- /dev/null +++ b/writerfilter/source/dmapper/WrapPolygonHandler.cxx @@ -0,0 +1,217 @@ +/* -*- 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::iterator WrapPolygon::begin() +{ + return mPoints.begin(); +} + +WrapPolygon::Points_t::iterator WrapPolygon::end() +{ + return mPoints.end(); +} + +WrapPolygon::Pointer_t WrapPolygon::move(const awt::Point & rPoint) +{ + WrapPolygon::Pointer_t pResult(new WrapPolygon); + + Points_t::iterator aIt = begin(); + Points_t::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) +{ + WrapPolygon::Pointer_t pResult(new WrapPolygon); + + Points_t::iterator aIt = begin(); + Points_t::iterator aItEnd = end(); + + while (aIt != aItEnd) + { + awt::Point aPoint((Fraction(long(aIt->X)) * rFractionX).operator long(), (Fraction(long(aIt->Y)) * rFractionY).operator long()); + pResult->addPoint(aPoint); + ++aIt; + } + + return pResult; +} + +WrapPolygon::Pointer_t WrapPolygon::correctWordWrapPolygon(const awt::Size & rSrcSize) +{ + WrapPolygon::Pointer_t pResult; + + const 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) +{ + 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 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) +{ + 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 +{ + drawing::PointSequenceSequence aPolyPolygon(1); + drawing::PointSequence aPolygon = comphelper::containerToSequence(mPoints); + aPolyPolygon[0] = aPolygon; + return aPolyPolygon; +} + +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..e9e58dc09 --- /dev/null +++ b/writerfilter/source/dmapper/WrapPolygonHandler.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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_WRAPPOLYGONHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_WRAPPOLYGONHANDLER_HXX + +#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 { +namespace 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::iterator begin(); + Points_t::iterator end(); + + WrapPolygon::Pointer_t move(const css::awt::Point & rMove); + WrapPolygon::Pointer_t scale(const Fraction & rFractionX, const Fraction & rFractionY); + WrapPolygon::Pointer_t correctWordWrapPolygon(const css::awt::Size & rSrcSize); + WrapPolygon::Pointer_t correctWordWrapPolygonPixel(const css::awt::Size & rSrcSize); + WrapPolygon::Pointer_t correctCrop(const css::awt::Size& rGraphicSize, + const css::text::GraphicCrop& rGraphicCrop); + 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; + +}; + +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_WRAPPOLYGONHANDLER_HXX + +/* 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..1e52cfc36 --- /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 Stream::Pointer_t(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..d4389fce7 --- /dev/null +++ b/writerfilter/source/dmapper/util.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 <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..e7adfdade --- /dev/null +++ b/writerfilter/source/dmapper/util.hxx @@ -0,0 +1,38 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_DMAPPER_UTIL_HXX +#define INCLUDED_WRITERFILTER_SOURCE_DMAPPER_UTIL_HXX + +#include <com/sun/star/text/XTextRange.hpp> +#include <string> +#include <dmapper/resourcemodel.hxx> + +namespace writerfilter +{ +namespace dmapper +{ + std::string XTextRangeToString(css::uno::Reference< css::text::XTextRange > const & textRange); + void resolveSprmProps(Properties & rHandler, Sprm & rSprm); +} +} + +#endif // INCLUDED_WRITERFILTER_SOURCE_DMAPPER_UTIL_HXX + +/* 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..bfa9a2087 --- /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::makeAny(true)); + } + comphelper::ScopeGuard g([xDocProps] { + if (xDocProps.is()) // not in cppunittest? + { + // note: pStream.clear calls RemoveLastParagraph() + xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::makeAny(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..0f0fcdb63 --- /dev/null +++ b/writerfilter/source/filter/WriterFilter.cxx @@ -0,0 +1,366 @@ +/* -*- 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 OUString(); +} + +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::makeAny(true)); + comphelper::ScopeGuard g([xDocProps] { + xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::makeAny(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::makeAny(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::makeAny(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, "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 all the formats + 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("AddFrameOffsets", uno::makeAny(true)); + xSettings->setPropertyValue("AddVerticalFrameOffsets", uno::makeAny(true)); + xSettings->setPropertyValue("UseOldNumbering", uno::makeAny(false)); + xSettings->setPropertyValue("IgnoreFirstLineIndentInNumbering", uno::makeAny(false)); + xSettings->setPropertyValue("DoNotResetParaAttrsForNumFont", uno::makeAny(false)); + xSettings->setPropertyValue("UseFormerLineSpacing", uno::makeAny(false)); + xSettings->setPropertyValue("AddParaSpacingToTableCells", uno::makeAny(true)); + xSettings->setPropertyValue("AddParaLineSpacingToTableCells", uno::makeAny(true)); + xSettings->setPropertyValue("UseFormerObjectPositioning", uno::makeAny(false)); + xSettings->setPropertyValue("ConsiderTextWrapOnObjPos", uno::makeAny(true)); + xSettings->setPropertyValue("UseFormerTextWrapping", uno::makeAny(false)); + xSettings->setPropertyValue("TableRowKeep", uno::makeAny(true)); + xSettings->setPropertyValue("IgnoreTabsAndBlanksForLineCalculation", uno::makeAny(true)); + xSettings->setPropertyValue("InvertBorderSpacing", uno::makeAny(true)); + xSettings->setPropertyValue("CollapseEmptyCellPara", uno::makeAny(true)); + xSettings->setPropertyValue("TabOverflow", uno::makeAny(true)); + xSettings->setPropertyValue("UnbreakableNumberings", uno::makeAny(true)); + + xSettings->setPropertyValue("FloattableNomargins", uno::makeAny(true)); + xSettings->setPropertyValue("ClippedPictures", uno::makeAny(true)); + xSettings->setPropertyValue("BackgroundParaOverDrawings", uno::makeAny(true)); + xSettings->setPropertyValue("TabOverMargin", uno::makeAny(true)); + xSettings->setPropertyValue("TreatSingleColumnBreakAsPageBreak", uno::makeAny(true)); + xSettings->setPropertyValue("PropLineSpacingShrinksFirstLine", uno::makeAny(true)); + xSettings->setPropertyValue("DoNotCaptureDrawObjsOnPage", uno::makeAny(true)); + xSettings->setPropertyValue("DisableOffPagePositioning", uno::makeAny(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..c582b71ab --- /dev/null +++ b/writerfilter/source/ooxml/Handler.cxx @@ -0,0 +1,403 @@ +/* -*- 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), msStreamId(), 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), msStreamId(), 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(Stream &rStream) +: mnType(0), + mrStream(rStream) +{ +} + +OOXMLBreakHandler::~OOXMLBreakHandler() +{ + 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.get() != nullptr) + pProps->resolve(*this); + } +} + +void OOXMLPictureHandler::sprm(Sprm & rSprm) +{ + writerfilter::Reference<Properties>::Pointer_t pProps + (rSprm.getProps()); + + if (pProps.get() != nullptr) + 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*/) +{ +} + +} + +/* 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..47ae7d562 --- /dev/null +++ b/writerfilter/source/ooxml/Handler.hxx @@ -0,0 +1,163 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_HANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_HANDLER_HXX + +#include <dmapper/resourcemodel.hxx> +#include "OOXMLFastContextHandler.hxx" + +namespace writerfilter { +namespace 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; + Stream & mrStream; +public: + explicit OOXMLBreakHandler(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; +}; + + +}} +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_HANDLER_HXX + +/* 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..979998fec --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLBinaryObjectReference.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLBINARYOBJECTREFERENCE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLBINARYOBJECTREFERENCE_HXX + +#include <dmapper/resourcemodel.hxx> +#include <ooxml/OOXMLDocument.hxx> +#include <vector> + +namespace writerfilter { +namespace 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; +}; +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLBINARYOBJECTREFERENCE_HXX + +/* 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..285028cc9 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx @@ -0,0 +1,879 @@ +/* -*- 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 <ooxml/resourceids.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 <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) +{ + 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()); + OOXMLFastDocumentHandler * pDocHandler = + new OOXMLFastDocumentHandler(xContext, &rStreamHandler, this, mnXNoteId); + + uno::Reference<xml::sax::XFastDocumentHandler> xDocumentHandler(pDocHandler); + uno::Reference<xml::sax::XFastTokenHandler> xTokenHandler(mpStream->getFastTokenHandler()); + + xParser->setFastDocumentHandler(xDocumentHandler); + xParser->setTokenHandler(xTokenHandler); + + uno::Reference<io::XInputStream> xInputStream = pStream->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()) + { + // 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) +{ + writerfilter::Reference<Stream>::Pointer_t pStream = + 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, pStream, nId); +} + +void OOXMLDocumentImpl::resolveEndnote(Stream & rStream, + Id aType, + const sal_Int32 nNoteId) +{ + writerfilter::Reference<Stream>::Pointer_t pStream = + 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, pStream, nId); +} + +void OOXMLDocumentImpl::resolveComment(Stream & rStream, + const sal_Int32 nId) +{ + 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()) + { + uno::Reference<uno::XComponentContext> xContext(mpStream->getContext()); + + OOXMLFastDocumentHandler * pDocHandler = + new OOXMLFastDocumentHandler(xContext, &rStream, this, mnXNoteId); + pDocHandler->setIsSubstream( mbIsSubstream ); + uno::Reference < xml::sax::XFastDocumentHandler > xDocumentHandler(pDocHandler); + 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( xDocumentHandler ); + 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("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()) + { + 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); + } +} + +void OOXMLDocumentImpl::resolveGlossaryStream(Stream & /*rStream*/) +{ + static const char sSettingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"; + static const char sStylesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"; + static const char sFonttableType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"; + static const char sWebSettings[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings"; + static const char sSettingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/settings"; + static const char sStylesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/styles"; + static const char sFonttableTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable"; + static const char sWebSettingsStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings"; + + 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()) + { + + const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs = xRelationshipAccess->getAllRelationships(); + std::vector< uno::Sequence<uno::Any> > aGlossaryDomList; + for (const uno::Sequence< beans::StringPair >& aSeq : aSeqs) + { + OOXMLStream::Pointer_t gStream; + //Follows following aSeq[0] is Id, aSeq[1] is Type, aSeq[2] is Target + if (aSeq.getLength() < 3) + { + SAL_WARN("writerfilter.ooxml", "too short sequence"); + continue; + } + + OUString gId(aSeq[0].Second); + OUString gType(aSeq[1].Second); + OUString gTarget(aSeq[2].Second); + OUString contentType; + + OOXMLStream::StreamType_t nType(OOXMLStream::UNKNOWN); + bool bFound = true; + if(gType == sSettingsType || + gType == sSettingsTypeStrict) + { + nType = OOXMLStream::SETTINGS; + contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"; + } + else if(gType == sStylesType || + gType == sStylesTypeStrict) + { + nType = OOXMLStream::STYLES; + contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"; + } + else if(gType == sWebSettings || + gType == sWebSettingsStrict) + { + nType = OOXMLStream::WEBSETTINGS; + contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"; + } + else if(gType == sFonttableType || + gType == sFonttableTypeStrict) + { + nType = OOXMLStream::FONTTABLE; + contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"; + } + else + { + bFound = false; + //"Unhandled content-type while grab bagging Glossary Folder"); + } + + if (bFound) + { + uno::Reference<xml::dom::XDocument> xDom; + try + { + gStream = OOXMLDocumentFactory::createStream(pStream, nType); + uno::Reference<io::XInputStream> xInputStream = gStream->getDocumentStream(); + uno::Reference<uno::XComponentContext> xContext(pStream->getContext()); + uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(xml::dom::DocumentBuilder::create(xContext)); + xDom = xDomBuilder->parse(xInputStream); + } + catch (uno::Exception const&) + { + TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while " + "parsing stream of Type" << nType); + return; + } + + if (xDom.is()) + { + uno::Sequence< uno::Any > glossaryTuple (5); + glossaryTuple[0] <<= xDom; + glossaryTuple[1] <<= gId; + glossaryTuple[2] <<= gType; + glossaryTuple[3] <<= gTarget; + glossaryTuple[4] <<= contentType; + aGlossaryDomList.push_back(glossaryTuple); + } + } + } + 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< uno::Any> > 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( uno::Reference<xml::sax::XFastShapeContextHandler> xContext ) +{ + if (!maShapeContexts.empty()) + maShapeContexts.top() = xContext; +} + +uno::Reference<xml::sax::XFastShapeContextHandler> OOXMLDocumentImpl::getShapeContext( ) +{ + if (!maShapeContexts.empty()) + return maShapeContexts.top(); + else + return uno::Reference<xml::sax::XFastShapeContextHandler>(); +} + +void OOXMLDocumentImpl::pushShapeContext() +{ + maShapeContexts.push(uno::Reference<xml::sax::XFastShapeContextHandler>()); +} + +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; +} + +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..b68d524f0 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx @@ -0,0 +1,142 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLDOCUMENTIMPL_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLDOCUMENTIMPL_HXX + +#include <ooxml/OOXMLDocument.hxx> + +#include <com/sun/star/xml/dom/XDocument.hpp> + +#include "OOXMLPropertySet.hxx" + +#include <vector> +#include <stack> + +namespace writerfilter { +namespace ooxml +{ + +class OOXMLDocumentImpl : public OOXMLDocument +{ + OOXMLStream::Pointer_t mpStream; + css::uno::Reference<css::task::XStatusIndicator> mxStatusIndicator; + 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::uno::Any > > mxGlossaryDomList; + /// Stack of shape contexts, 1 element for VML, 1 element / nesting level for drawingML. + std::stack< css::uno::Reference<css::xml::sax::XFastShapeContextHandler> > 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; + +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); +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 css::uno::Reference<css::xml::sax::XFastShapeContextHandler> getShapeContext( ) override; + virtual void setShapeContext( css::uno::Reference<css::xml::sax::XFastShapeContextHandler> 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::uno::Any> > 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; +}; +}} +#endif // OOXML_DOCUMENT_IMPL_HXX + +/* 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..6bc7a10e8 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFactory.cxx @@ -0,0 +1,216 @@ +/* -*- 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.get() == nullptr) + 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); + + switch (pAttr->m_nResource) + { + case ResourceType::Boolean: + { + const char *pValue = rAttribs.getAsCharByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue(OOXMLBooleanValue::Create(pValue)); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::String: + { + OUString aValue(rAttribs.getValueByIndex(nAttrIndex)); + OOXMLValue::Pointer_t xValue(new OOXMLStringValue(aValue)); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::Integer: + { + sal_Int32 nValue = rAttribs.getAsIntegerByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue = OOXMLIntegerValue::Create(nValue); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::Hex: + { + const char *pValue = rAttribs.getAsCharByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue(new OOXMLHexValue(pValue)); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::HexColor: + { + const char *pValue = rAttribs.getAsCharByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue(new OOXMLHexColorValue(pValue)); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::TwipsMeasure_asSigned: + case ResourceType::TwipsMeasure_asZero: + { + const char *pValue = rAttribs.getAsCharByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue(new OOXMLTwipsMeasureValue(pValue)); + if ( xValue->getInt() < 0 ) + { + if ( pAttr->m_nResource == ResourceType::TwipsMeasure_asZero ) + xValue = OOXMLIntegerValue::Create(0); + } + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::HpsMeasure: + { + const char *pValue = rAttribs.getAsCharByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue(new OOXMLHpsMeasureValue(pValue)); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::MeasurementOrPercent: + { + const char *pValue = rAttribs.getAsCharByIndex(nAttrIndex); + OOXMLValue::Pointer_t xValue(new OOXMLMeasurementOrPercentValue(pValue)); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + break; + case ResourceType::List: + { + sal_uInt32 nValue; + if (pFactory->getListValue(pAttr->m_nRef, rAttribs.getValueByIndex(nAttrIndex), nValue)) + { + OOXMLValue::Pointer_t xValue = OOXMLIntegerValue::Create(nValue); + pHandler->newProperty(nId, xValue); + pFactory->attributeAction(pHandler, nToken, xValue); + } + } + break; + default: + break; + } + } +} + +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.get() != nullptr) + { + pFactory->charactersAction(pHandler, rString); + } +} + +void OOXMLFactory::startAction(OOXMLFastContextHandler * pHandler) +{ + Id nDefine = pHandler->getDefine(); + OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine); + + if (pFactory.get() != nullptr) + { + pFactory->startAction(pHandler); + } +} + +void OOXMLFactory::endAction(OOXMLFastContextHandler * pHandler) +{ + Id nDefine = pHandler->getDefine(); + OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine); + + if (pFactory.get() != nullptr) + { + 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..aa3c981c6 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFactory.hxx @@ -0,0 +1,109 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFACTORY_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFACTORY_HXX + +#include <dmapper/resourcemodel.hxx> + +#include "OOXMLFastContextHandler.hxx" + +namespace writerfilter { +namespace 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 +}; + +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); +}; + +} +} + +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFACTORY_HXX + +/* 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..e425025fb --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.cxx @@ -0,0 +1,2191 @@ +/* -*- 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/FastShapeContextHandler.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 <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/PropertyIds.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/sequenceashashmap.hxx> + +static const sal_Unicode uCR = 0xd; +static const sal_Unicode uFtnEdnRef = 0x2; +static const sal_Unicode uFtnEdnSep = 0x3; +static const sal_Unicode uTab = 0x9; +static const sal_Unicode uPgNum = 0x0; +static const sal_Unicode uNoBreakHyphen = 0x2011; +static const sal_Unicode uSoftHyphen = 0xAD; + +static const sal_uInt8 cFtnEdnCont = 0x4; +static const sal_uInt8 cFieldLock = 0x8; + +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.get() == nullptr) + mpParserState = new OOXMLParserState(); + + mpParserState->incContextCount(); +} + +OOXMLFastContextHandler::OOXMLFastContextHandler(OOXMLFastContextHandler * pContext) +: cppu::WeakImplHelper<xml::sax::XFastContextHandler>(), + 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.get() == nullptr) + 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; + break; + 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 == (NMSP_officeMath | XML_oMathPara)) + { + mnMathJcVal = eMathParaJc::CENTER; + mbIsMathPara = true; + } + 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) + { + 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()) + { + if (mpParserState->isInCharacterGroup()) + endCharacterGroup(); + + if (! mpParserState->isInParagraphGroup()) + startParagraphGroup(); + + if (! mpParserState->isInCharacterGroup()) + { + mpStream->startCharacterGroup(); + mpParserState->setInCharacterGroup(true); + mpParserState->resolveCharacterProperties(*mpStream); + } + + // 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()) + { + if (mpParserState->isInParagraphGroup()) + endParagraphGroup(); + + if (! mpParserState->isInSectionGroup()) + startSectionGroup(); + + if (! mpParserState->isInParagraphGroup()) + { + mpStream->startParagraphGroup(); + mpParserState->setInParagraphGroup(true); + } + } +} + +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::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()) + { + // 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.get() != nullptr) + { + pProps->add(mId, getValue(), OOXMLProperty::SPRM); + } + } +} + +void OOXMLFastContextHandler::sendPropertiesToParent() +{ + if (mpParent != nullptr) + { + OOXMLPropertySet::Pointer_t pParentProps(mpParent->getPropertySet()); + + if (pParentProps.get() != nullptr) + { + OOXMLPropertySet::Pointer_t pProps(getPropertySet()); + + if (pProps.get() != nullptr) + { + 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(*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::setPropertySet +(const OOXMLPropertySet::Pointer_t& pPropertySet) +{ + if (pPropertySet.get() != nullptr) + 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.get() == nullptr) + { + OOXMLValue::Pointer_t pValue = OOXMLBooleanValue::Create(true); + setValue(pValue); + } +} + +void OOXMLFastContextHandlerValue::setDefaultIntegerValue() +{ + if (mpValue.get() == nullptr) + { + OOXMLValue::Pointer_t pValue = OOXMLIntegerValue::Create(0); + setValue(pValue); + } +} + +void OOXMLFastContextHandlerValue::setDefaultHexValue() +{ + if (mpValue.get() == nullptr) + { + OOXMLValue::Pointer_t pValue(new OOXMLHexValue(sal_uInt32(0))); + setValue(pValue); + } +} + +void OOXMLFastContextHandlerValue::setDefaultStringValue() +{ + if (mpValue.get() == nullptr) + { + 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 ? u"\u202B" : u"\u202A"); // RLE / LRE +} + +void OOXMLFastContextHandlerValue::popBiDiEmbedLevel() +{ + OOXMLFactory::characters(this, u"\u202C"); // PDF (POP DIRECTIONAL FORMATTING) +} + +/* + 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.get() != nullptr) + { + 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) + 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()); +} + +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()) + { + 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(); +} + +void OOXMLFastContextHandlerTextTableRow::handleGridAfter(const OOXMLValue::Pointer_t& rValue) +{ + 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(rValue); + } +} + +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.set(getDocument()->getShapeContext()); + if (!mrShapeContext.is()) + { + // Define the shape context for the whole document + mrShapeContext = css::xml::sax::FastShapeContextHandler::create(getComponentContext()); + getDocument()->setShapeContext(mrShapeContext); + } + + 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()); + + OOXMLFastContextHandler::setToken(nToken); + + if (mrShapeContext.is()) + mrShapeContext->setStartToken(nToken); +} + +void OOXMLFastContextHandlerShape::sendShape( Token_t Element ) +{ + if ( mrShapeContext.is() && !m_bShapeSent ) + { + awt::Point aPosition = mpStream->getPositionOffset(); + mrShapeContext->setPosition(aPosition); + uno::Reference<drawing::XShape> xShape(mrShapeContext->getShape()); + m_bShapeSent = true; + if (xShape.is()) + { + 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::makeAny(mbAllowInCell)); + } + // Notify the dmapper that the shape is ready to use + if ( !bIsPicture ) + { + mpStream->startShape( xShape ); + m_bShapeStarted = true; + } + } + } +} + +void OOXMLFastContextHandlerShape::lcl_endFastElement +(Token_t Element) +{ + if (isForwardEvents()) + { + + 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) +{ + uno::Reference< xml::sax::XFastContextHandler > xContextHandler; + + bool bGroupShape = Element == Token_t(NMSP_vml | XML_group); + // drawingML version also counts as a group shape. + 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); + + 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); +} + +void OOXMLFastContextHandlerWrapper::lcl_endFastElement +(Token_t Element) +{ + if (mxWrappedContext.is()) + mxWrappedContext->endFastElement(Element); +} + +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) + { + 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(1); + objArgs[0].Name = "DefaultParentBaseURL"; + objArgs[0].Value <<= 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()) + { + 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() ); + } +} + +} + +/* 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..ca6e6507e --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFastContextHandler.hxx @@ -0,0 +1,605 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTCONTEXTHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTCONTEXTHANDLER_HXX + +#include <set> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/xml/sax/XFastContextHandler.hpp> +#include <com/sun/star/xml/sax/XFastShapeContextHandler.hpp> +#include <oox/mathml/importutils.hxx> +#include <rtl/ref.hxx> +#include "OOXMLParserState.hxx" +#include "OOXMLPropertySet.hxx" + +namespace writerfilter { +namespace 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 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(); + + const css::uno::Reference< css::uno::XComponentContext >& getComponentContext() const { return m_xContext;} + + 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(); + + 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; + +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 ); + void handleGridAfter(const OOXMLValue::Pointer_t& rValue); +}; + +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; + css::uno::Reference<css::xml::sax::XFastShapeContextHandler> 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; } + +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; +}; + +}} +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTCONTEXTHANDLER_HXX + +/* 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..3fc69670b --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFastDocumentHandler.cxx @@ -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 . + */ + +#include <iostream> +#include "OOXMLFastDocumentHandler.hxx" +#include "OOXMLFastContextHandler.hxx" +#include "OOXMLFactory.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 ) + , mxContextHandler() +{ +} + +OOXMLFastDocumentHandler::~OOXMLFastDocumentHandler() {} + +// css::xml::sax::XFastContextHandler: +void SAL_CALL OOXMLFastDocumentHandler::startFastElement +(::sal_Int32 +#ifdef DBG_UTIL +Element +#endif +, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/) +{ +#ifdef DBG_UTIL + clog << this << ":start element:" + << fastTokenToId(Element) + << endl; +#endif +} + +void SAL_CALL OOXMLFastDocumentHandler::startUnknownElement +(const OUString & +#ifdef DBG_UTIL +Namespace +#endif +, const OUString & +#ifdef DBG_UTIL +Name +#endif +, + const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/) +{ +#ifdef DBG_UTIL + clog << this << ":start unknown element:" + << Namespace << ":" << Name << endl; +#endif +} + +void SAL_CALL OOXMLFastDocumentHandler::endFastElement(::sal_Int32 +#ifdef DBG_UTIL +Element +#endif +) +{ +#ifdef DBG_UTIL + clog << this << ":end element:" + << fastTokenToId(Element) + << endl; +#endif +} + +void SAL_CALL OOXMLFastDocumentHandler::endUnknownElement +(const OUString & +#ifdef DBG_UTIL +Namespace +#endif +, const OUString & +#ifdef DBG_UTIL +Name +#endif +) +{ +#ifdef DBG_UTIL + clog << this << ":end unknown element:" + << Namespace << ":" << Name + << endl; +#endif +} + +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 & +#ifdef DBG_UTIL +Namespace +#endif +, + const OUString & +#ifdef DBG_UTIL +Name +#endif +, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/) +{ +#ifdef DBG_UTIL + clog << this << ":createUnknownChildContext:" + << Namespace << ":"<< Name + << endl; +#endif + + 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..b7839178f --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFastDocumentHandler.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 . + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTDOCUMENTHANDLER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTDOCUMENTHANDLER_HXX + +#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 { +namespace 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; +}; +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTDOCUMENTHANDLER_HXX + +/* 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..fcf162f44 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLFastHelper.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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTHELPER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTHELPER_HXX + +#include "OOXMLFastContextHandler.hxx" + +namespace writerfilter { + +namespace ooxml +{ + +template <class T> +class OOXMLFastHelper +{ +public: + static OOXMLFastContextHandler* createAndSetParentAndDefine + (OOXMLFastContextHandler * pHandler, sal_uInt32 nToken, Id nId, Id nDefine); + + static void newProperty(OOXMLFastContextHandler * pHandler, + Id nId, sal_Int32 nValue); +}; + +template <class T> +OOXMLFastContextHandler* OOXMLFastHelper<T>::createAndSetParentAndDefine (OOXMLFastContextHandler * pHandler, sal_uInt32 nToken, Id nId, Id nDefine) +{ + 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); +} + +}} +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLFASTHELPER_HXX + +/* 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..576e97c8c --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLParserState.cxx @@ -0,0 +1,280 @@ +/* -*- 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) +{ +} + +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.get() != nullptr) + { + rStream.props(mpCharacterProps.get()); + mpCharacterProps = new OOXMLPropertySet; + } +} + +void OOXMLParserState::setCharacterProperties(const OOXMLPropertySet::Pointer_t& pProps) +{ + if (mpCharacterProps.get() == nullptr) + 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.get() == nullptr) + 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.get() == nullptr) + rRowProps = pProps; + else + rRowProps->add(pProps); + } +} + +void OOXMLParserState::resolveCellProperties(Stream & rStream) +{ + if (!mCellProps.empty()) + { + OOXMLPropertySet::Pointer_t & rCellProps = mCellProps.top(); + + if (rCellProps.get() != nullptr) + { + rStream.props(rCellProps.get()); + rCellProps = new OOXMLPropertySet; + } + } +} + +void OOXMLParserState::resolveRowProperties(Stream & rStream) +{ + if (!mRowProps.empty()) + { + OOXMLPropertySet::Pointer_t & rRowProps = mRowProps.top(); + + if (rRowProps.get() != nullptr) + { + rStream.props(rRowProps.get()); + rRowProps = new OOXMLPropertySet; + } + } +} + +void OOXMLParserState::resolveTableProperties(Stream & rStream) +{ + if (!mTableProps.empty()) + { + OOXMLPropertySet::Pointer_t & rTableProps = mTableProps.top(); + + if (rTableProps.get() != nullptr) + { + 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.get() == nullptr) + rTableProps = pProps; + else + rTableProps->add(pProps); + } +} + +// tdf#108714 +void OOXMLParserState::resolvePostponedBreak(Stream & rStream) +{ + for (const auto & rBreak: mvPostponedBreaks) + { + OOXMLBreakHandler aBreakHandler(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; +} + +} + +/* 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..5e9811e2a --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLParserState.hxx @@ -0,0 +1,124 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLPARSERSTATE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLPARSERSTATE_HXX + +#include <stack> +#include "OOXMLDocumentImpl.hxx" +#include "OOXMLPropertySet.hxx" + +namespace writerfilter { +namespace 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; + +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(); + +}; + +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLPARSERSTATE_HXX + +/* 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..b80710114 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLPropertySet.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 "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.get() != nullptr) + 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.get() != nullptr) + 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.get() != nullptr) + 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.get() != nullptr) + 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.get() != nullptr && 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) + { + int x = mProperties.size(); + mProperties.resize(mProperties.size() + pSet->mProperties.size()); + std::copy(pSet->mProperties.begin(), pSet->mProperties.end(), mProperties.begin() + x); + } +} + +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).get() != nullptr) + 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")) + { + 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.get() != nullptr) + pTable->entry(nPos, pProperties); + + ++nPos; + } +} + +void OOXMLTable::add(const ValuePointer_t& pPropertySet) +{ + if (pPropertySet.get() != nullptr) + 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..f31d46fce --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLPropertySet.hxx @@ -0,0 +1,402 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLPROPERTYSET_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLPROPERTYSET_HXX + +#include <vector> +#include "OOXMLBinaryObjectReference.hxx" +#include <com/sun/star/embed/XEmbeddedObject.hpp> +#include <dmapper/resourcemodel.hxx> + +namespace writerfilter { +namespace 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; } +}; + + +}} + +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLPROPERTYSET_HXX + +/* 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..73e527a55 --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx @@ -0,0 +1,443 @@ +/* -*- 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 char sDocumentType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; + static const char sStylesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"; + static const char sNumberingType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"; + static const char sFonttableType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"; + static const char sFootnotesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes"; + static const char sEndnotesType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes"; + static const char sCommentsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; + static const char sThemeType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"; + static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml"; + static const char sCustomPropsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps"; + static const char sGlossaryType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument"; + static const char sWebSettings[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings"; + static const char sSettingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"; + static const char sChartType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"; + static const char sEmbeddingsType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package"; + static const char sFooterType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"; + static const char sHeaderType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header"; + static const char sOleObjectType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject"; + // OOXML strict + static const char sDocumentTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument"; + static const char sStylesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/styles"; + static const char sNumberingTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/numbering"; + static const char sFonttableTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable"; + static const char sFootnotesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes"; + static const char sEndnotesTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes"; + static const char sCommentsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"; + static const char sThemeTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/theme"; + static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXml"; + static const char sCustomPropsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps"; + static const char sGlossaryTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument"; + static const char sWebSettingsStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings"; + static const char sSettingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/settings"; + static const char sChartTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/chart"; + static const char sEmbeddingsTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/package"; + static const char sFootersTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/footer"; + static const char sHeaderTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/header"; + static const char sOleObjectTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject"; + static const char sVBAProjectType[] = "http://schemas.microsoft.com/office/2006/relationships/vbaProject"; + static const char sVBADataType[] = "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; + 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) + { + 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())) + { + std::unique_ptr<OOXMLStreamImpl> pProject(new OOXMLStreamImpl(*pImpl, OOXMLStream::VBAPROJECT)); + pRet = new OOXMLStreamImpl(*pProject, 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..b7d5b4aaa --- /dev/null +++ b/writerfilter/source/ooxml/OOXMLStreamImpl.hxx @@ -0,0 +1,86 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLSTREAMIMPL_HXX +#define INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLSTREAMIMPL_HXX + +#include <map> + +#include <ooxml/OOXMLDocument.hxx> +#include <com/sun/star/embed/XRelationshipAccess.hpp> + +extern OUString customTarget; +extern OUString embeddingsTarget; + +namespace writerfilter { +namespace 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;} +}; +}} +#endif // INCLUDED_WRITERFILTER_SOURCE_OOXML_OOXMLSTREAMIMPL_HXX + +/* 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..4fdbfda2e --- /dev/null +++ b/writerfilter/source/ooxml/factoryimpl.py @@ -0,0 +1,215 @@ +#!/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(1); + args[0] <<= 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..db06cf1c9 --- /dev/null +++ b/writerfilter/source/ooxml/factoryimpl_ns.py @@ -0,0 +1,759 @@ +#!/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") + # Blacklist 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"): + 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") == "handleGridBefore" or actionNode.getAttribute("action") == "handleGridAfter": + ret.append(" %sif (OOXMLFastContextHandlerTextTableRow* pTextTableRow = dynamic_cast<OOXMLFastContextHandlerTextTableRow*>(pHandler))" % extra_space) + ret.append(" %s pTextTableRow->%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") == "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..380fc3f01 --- /dev/null +++ b/writerfilter/source/ooxml/model.xml @@ -0,0 +1,19197 @@ +<?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: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_SytemColor_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_String"/> + </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="Properties"> + <attribute name="val" tokenid="ooxml:CT_OnOff_val"/> + </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="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_Placeholder"> + <element name="docPart"> + <ref name="CT_String"/> + </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_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_Placeholder"/> + </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_OnOff"/> + </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> + </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> + <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> + <!-- 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_TrPrBaseGridBefore"> + <attribute name="val"> + <ref name="ST_DecimalNumber"/> + </attribute> + </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> + </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"/> + </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"/> + </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="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="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="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_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_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"/> + </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"/> + <action name="start" action="startSdt"/> + <action name="end" action="endSdt"/> + </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_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"> + <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="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_TrPrBaseGridBefore" resource="TextTableRow"> + <attribute name="val" tokenid="ooxml:CT_TrPrBase_gridBefore"/> + </resource> + <resource name="CT_TrPrBaseGridAfter" resource="TextTableRow"> + <attribute name="val" tokenid="ooxml:CT_TrPrBase_gridAfter" 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_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..69e416ce8 --- /dev/null +++ b/writerfilter/source/rtftok/rtfcharsets.cxx @@ -0,0 +1,55 @@ +/* -*- 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 <sal/macros.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 = SAL_N_ELEMENTS(aRTFEncodings); + +} // 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..42ddccce2 --- /dev/null +++ b/writerfilter/source/rtftok/rtfcharsets.hxx @@ -0,0 +1,30 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFCHARSETS_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFCHARSETS_HXX + +namespace writerfilter +{ +namespace rtftok +{ +/// RTF legacy charsets +struct RTFEncoding +{ + int charset; + int codepage; +}; +extern RTFEncoding const aRTFEncodings[]; +extern int nRTFEncodings; +} // namespace rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFCHARSETS_HXX + +/* 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..38bc9d6dd --- /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 + { "'", CONTROL_SYMBOL, RTF_HEXCHAR, 0 }, + { "-", CONTROL_SYMBOL, RTF_OPTHYPH, 0 }, + { "*", CONTROL_SYMBOL, RTF_IGNORE, 0 }, + { ":", CONTROL_SYMBOL, RTF_SUBENTRY, 0 }, + { "\\", CONTROL_SYMBOL, RTF_BACKSLASH, 0 }, + { "\n", CONTROL_SYMBOL, RTF_PAR, 0 }, + { "\r", CONTROL_SYMBOL, RTF_PAR, 0 }, + { "\r\n", CONTROL_SYMBOL, RTF_PAR, 0 }, + { "_", CONTROL_SYMBOL, RTF_NOBRKHYPH, 0 }, + { "{", CONTROL_SYMBOL, RTF_LBRACE, 0 }, + { "|", CONTROL_SYMBOL, RTF_FORMULA, 0 }, + { "}", CONTROL_SYMBOL, RTF_RBRACE, 0 }, + { "~", CONTROL_SYMBOL, RTF_NOBREAK, 0 }, + { "ab", CONTROL_TOGGLE, RTF_AB, 1 }, + { "absh", CONTROL_VALUE, RTF_ABSH, 0 }, + { "abslock", CONTROL_FLAG, RTF_ABSLOCK, 0 }, + { "absnoovrlp", CONTROL_TOGGLE, RTF_ABSNOOVRLP, 1 }, + { "absw", CONTROL_VALUE, RTF_ABSW, 0 }, + { "acaps", CONTROL_TOGGLE, RTF_ACAPS, 1 }, + { "acccircle", CONTROL_TOGGLE, RTF_ACCCIRCLE, 1 }, + { "acccomma", CONTROL_TOGGLE, RTF_ACCCOMMA, 1 }, + { "accdot", CONTROL_TOGGLE, RTF_ACCDOT, 1 }, + { "accnone", CONTROL_TOGGLE, RTF_ACCNONE, 1 }, + { "accunderdot", CONTROL_TOGGLE, RTF_ACCUNDERDOT, 1 }, + { "acf", CONTROL_VALUE, RTF_ACF, 0 }, + { "adeff", CONTROL_VALUE, RTF_ADEFF, 0 }, + { "additive", CONTROL_FLAG, RTF_ADDITIVE, 0 }, + { "adeflang", CONTROL_VALUE, RTF_ADEFLANG, 0 }, + { "adjustright", CONTROL_FLAG, RTF_ADJUSTRIGHT, 0 }, + { "adn", CONTROL_VALUE, RTF_ADN, 6 }, + { "aenddoc", CONTROL_FLAG, RTF_AENDDOC, 0 }, + { "aendnotes", CONTROL_FLAG, RTF_AENDNOTES, 0 }, + { "aexpnd", CONTROL_VALUE, RTF_AEXPND, 0 }, + { "af", CONTROL_VALUE, RTF_AF, 0 }, + { "afelev", CONTROL_FLAG, RTF_AFELEV, 0 }, + { "afs", CONTROL_VALUE, RTF_AFS, 24 }, + { "aftnbj", CONTROL_FLAG, RTF_AFTNBJ, 0 }, + { "aftncn", CONTROL_DESTINATION, RTF_AFTNCN, 0 }, + { "aftnnalc", CONTROL_FLAG, RTF_AFTNNALC, 0 }, + { "aftnnar", CONTROL_FLAG, RTF_AFTNNAR, 0 }, + { "aftnnauc", CONTROL_FLAG, RTF_AFTNNAUC, 0 }, + { "aftnnchi", CONTROL_FLAG, RTF_AFTNNCHI, 0 }, + { "aftnnchosung", CONTROL_FLAG, RTF_AFTNNCHOSUNG, 0 }, + { "aftnncnum", CONTROL_FLAG, RTF_AFTNNCNUM, 0 }, + { "aftnndbar", CONTROL_FLAG, RTF_AFTNNDBAR, 0 }, + { "aftnndbnum", CONTROL_FLAG, RTF_AFTNNDBNUM, 0 }, + { "aftnndbnumd", CONTROL_FLAG, RTF_AFTNNDBNUMD, 0 }, + { "aftnndbnumk", CONTROL_FLAG, RTF_AFTNNDBNUMK, 0 }, + { "aftnndbnumt", CONTROL_FLAG, RTF_AFTNNDBNUMT, 0 }, + { "aftnnganada", CONTROL_FLAG, RTF_AFTNNGANADA, 0 }, + { "aftnngbnum", CONTROL_FLAG, RTF_AFTNNGBNUM, 0 }, + { "aftnngbnumd", CONTROL_FLAG, RTF_AFTNNGBNUMD, 0 }, + { "aftnngbnumk", CONTROL_FLAG, RTF_AFTNNGBNUMK, 0 }, + { "aftnngbnuml", CONTROL_FLAG, RTF_AFTNNGBNUML, 0 }, + { "aftnnrlc", CONTROL_FLAG, RTF_AFTNNRLC, 0 }, + { "aftnnruc", CONTROL_FLAG, RTF_AFTNNRUC, 0 }, + { "aftnnzodiac", CONTROL_FLAG, RTF_AFTNNZODIAC, 0 }, + { "aftnnzodiacd", CONTROL_FLAG, RTF_AFTNNZODIACD, 0 }, + { "aftnnzodiacl", CONTROL_FLAG, RTF_AFTNNZODIACL, 0 }, + { "aftnrestart", CONTROL_FLAG, RTF_AFTNRESTART, 0 }, + { "aftnrstcont", CONTROL_FLAG, RTF_AFTNRSTCONT, 0 }, + { "aftnsep", CONTROL_DESTINATION, RTF_AFTNSEP, 0 }, + { "aftnsepc", CONTROL_DESTINATION, RTF_AFTNSEPC, 0 }, + { "aftnstart", CONTROL_VALUE, RTF_AFTNSTART, 1 }, + { "aftntj", CONTROL_FLAG, RTF_AFTNTJ, 0 }, + { "ai", CONTROL_TOGGLE, RTF_AI, 1 }, + { "alang", CONTROL_VALUE, RTF_ALANG, 0 }, + { "allowfieldendsel", CONTROL_FLAG, RTF_ALLOWFIELDENDSEL, 0 }, + { "allprot", CONTROL_FLAG, RTF_ALLPROT, 0 }, + { "alntblind", CONTROL_FLAG, RTF_ALNTBLIND, 0 }, + { "alt", CONTROL_FLAG, RTF_ALT, 0 }, + { "animtext", CONTROL_VALUE, RTF_ANIMTEXT, 0 }, + { "annotation", CONTROL_DESTINATION, RTF_ANNOTATION, 0 }, + { "annotprot", CONTROL_FLAG, RTF_ANNOTPROT, 0 }, + { "ansi", CONTROL_FLAG, RTF_ANSI, 0 }, + { "ansicpg", CONTROL_VALUE, RTF_ANSICPG, 0 }, + { "aoutl", CONTROL_TOGGLE, RTF_AOUTL, 1 }, + { "ApplyBrkRules", CONTROL_FLAG, RTF_APPLYBRKRULES, 0 }, + { "ascaps", CONTROL_TOGGLE, RTF_ASCAPS, 1 }, + { "ashad", CONTROL_TOGGLE, RTF_ASHAD, 1 }, + { "asianbrkrule", CONTROL_FLAG, RTF_ASIANBRKRULE, 0 }, + { "aspalpha", CONTROL_TOGGLE, RTF_ASPALPHA, 1 }, + { "aspnum", CONTROL_TOGGLE, RTF_ASPNUM, 1 }, + { "astrike", CONTROL_TOGGLE, RTF_ASTRIKE, 1 }, + { "atnauthor", CONTROL_DESTINATION, RTF_ATNAUTHOR, 0 }, + { "atndate", CONTROL_DESTINATION, RTF_ATNDATE, 0 }, + { "atnicn", CONTROL_DESTINATION, RTF_ATNICN, 0 }, + { "atnid", CONTROL_DESTINATION, RTF_ATNID, 0 }, + { "atnparent", CONTROL_DESTINATION, RTF_ATNPARENT, 0 }, + { "atnref", CONTROL_DESTINATION, RTF_ATNREF, 0 }, + { "atntime", CONTROL_DESTINATION, RTF_ATNTIME, 0 }, + { "atrfend", CONTROL_DESTINATION, RTF_ATRFEND, 0 }, + { "atrfstart", CONTROL_DESTINATION, RTF_ATRFSTART, 0 }, + { "aul", CONTROL_TOGGLE, RTF_AUL, 1 }, + { "auld", CONTROL_TOGGLE, RTF_AULD, 1 }, + { "auldb", CONTROL_TOGGLE, RTF_AULDB, 1 }, + { "aulnone", CONTROL_TOGGLE, RTF_AULNONE, 1 }, + { "aulw", CONTROL_TOGGLE, RTF_AULW, 1 }, + { "aup", CONTROL_VALUE, RTF_AUP, 6 }, + { "author", CONTROL_DESTINATION, RTF_AUTHOR, 0 }, + { "autofmtoverride", CONTROL_FLAG, RTF_AUTOFMTOVERRIDE, 0 }, + { "b", CONTROL_TOGGLE, RTF_B, 1 }, + { "background", CONTROL_DESTINATION, RTF_BACKGROUND, 0 }, + { "bdbfhdr", CONTROL_FLAG, RTF_BDBFHDR, 0 }, + { "bdrrlswsix", CONTROL_FLAG, RTF_BDRRLSWSIX, 0 }, + { "bgbdiag", CONTROL_FLAG, RTF_BGBDIAG, 0 }, + { "bgcross", CONTROL_FLAG, RTF_BGCROSS, 0 }, + { "bgdcross", CONTROL_FLAG, RTF_BGDCROSS, 0 }, + { "bgdkbdiag", CONTROL_FLAG, RTF_BGDKBDIAG, 0 }, + { "bgdkcross", CONTROL_FLAG, RTF_BGDKCROSS, 0 }, + { "bgdkdcross", CONTROL_FLAG, RTF_BGDKDCROSS, 0 }, + { "bgdkfdiag", CONTROL_FLAG, RTF_BGDKFDIAG, 0 }, + { "bgdkhoriz", CONTROL_FLAG, RTF_BGDKHORIZ, 0 }, + { "bgdkvert", CONTROL_FLAG, RTF_BGDKVERT, 0 }, + { "bgfdiag", CONTROL_FLAG, RTF_BGFDIAG, 0 }, + { "bghoriz", CONTROL_FLAG, RTF_BGHORIZ, 0 }, + { "bgvert", CONTROL_FLAG, RTF_BGVERT, 0 }, + { "bin", CONTROL_VALUE, RTF_BIN, 0 }, + { "binfsxn", CONTROL_VALUE, RTF_BINFSXN, 0 }, + { "binsxn", CONTROL_VALUE, RTF_BINSXN, 0 }, + { "bkmkcolf", CONTROL_VALUE, RTF_BKMKCOLF, 0 }, + { "bkmkcoll", CONTROL_VALUE, RTF_BKMKCOLL, 0 }, + { "bkmkend", CONTROL_DESTINATION, RTF_BKMKEND, 0 }, + { "bkmkpub", CONTROL_FLAG, RTF_BKMKPUB, 0 }, + { "bkmkstart", CONTROL_DESTINATION, RTF_BKMKSTART, 0 }, + { "bliptag", CONTROL_VALUE, RTF_BLIPTAG, 0 }, + { "blipuid", CONTROL_DESTINATION, RTF_BLIPUID, 0 }, + { "blipupi", CONTROL_VALUE, RTF_BLIPUPI, 0 }, + { "blue", CONTROL_VALUE, RTF_BLUE, 0 }, + { "bookfold", CONTROL_FLAG, RTF_BOOKFOLD, 0 }, + { "bookfoldrev", CONTROL_FLAG, RTF_BOOKFOLDREV, 0 }, + { "bookfoldsheets", CONTROL_VALUE, RTF_BOOKFOLDSHEETS, 0 }, + { "box", CONTROL_FLAG, RTF_BOX, 0 }, + { "brdrart", CONTROL_VALUE, RTF_BRDRART, 0 }, + { "brdrb", CONTROL_FLAG, RTF_BRDRB, 0 }, + { "brdrbar", CONTROL_FLAG, RTF_BRDRBAR, 0 }, + { "brdrbtw", CONTROL_FLAG, RTF_BRDRBTW, 0 }, + { "brdrcf", CONTROL_VALUE, RTF_BRDRCF, 0 }, + { "brdrdash", CONTROL_FLAG, RTF_BRDRDASH, 0 }, + { "brdrdashd", CONTROL_FLAG, RTF_BRDRDASHD, 0 }, + { "brdrdashdd", CONTROL_FLAG, RTF_BRDRDASHDD, 0 }, + { "brdrdashdotstr", CONTROL_FLAG, RTF_BRDRDASHDOTSTR, 0 }, + { "brdrdashsm", CONTROL_FLAG, RTF_BRDRDASHSM, 0 }, + { "brdrdb", CONTROL_FLAG, RTF_BRDRDB, 0 }, + { "brdrdot", CONTROL_FLAG, RTF_BRDRDOT, 0 }, + { "brdremboss", CONTROL_FLAG, RTF_BRDREMBOSS, 0 }, + { "brdrengrave", CONTROL_FLAG, RTF_BRDRENGRAVE, 0 }, + { "brdrframe", CONTROL_FLAG, RTF_BRDRFRAME, 0 }, + { "brdrhair", CONTROL_FLAG, RTF_BRDRHAIR, 0 }, + { "brdrinset", CONTROL_FLAG, RTF_BRDRINSET, 0 }, + { "brdrl", CONTROL_FLAG, RTF_BRDRL, 0 }, + { "brdrnil", CONTROL_FLAG, RTF_BRDRNIL, 0 }, + { "brdrnone", CONTROL_FLAG, RTF_BRDRNONE, 0 }, + { "brdroutset", CONTROL_FLAG, RTF_BRDROUTSET, 0 }, + { "brdrr", CONTROL_FLAG, RTF_BRDRR, 0 }, + { "brdrs", CONTROL_FLAG, RTF_BRDRS, 0 }, + { "brdrsh", CONTROL_FLAG, RTF_BRDRSH, 0 }, + { "brdrt", CONTROL_FLAG, RTF_BRDRT, 0 }, + { "brdrtbl", CONTROL_FLAG, RTF_BRDRTBL, 0 }, + { "brdrth", CONTROL_FLAG, RTF_BRDRTH, 0 }, + { "brdrthtnlg", CONTROL_FLAG, RTF_BRDRTHTNLG, 0 }, + { "brdrthtnmg", CONTROL_FLAG, RTF_BRDRTHTNMG, 0 }, + { "brdrthtnsg", CONTROL_FLAG, RTF_BRDRTHTNSG, 0 }, + { "brdrtnthlg", CONTROL_FLAG, RTF_BRDRTNTHLG, 0 }, + { "brdrtnthmg", CONTROL_FLAG, RTF_BRDRTNTHMG, 0 }, + { "brdrtnthsg", CONTROL_FLAG, RTF_BRDRTNTHSG, 0 }, + { "brdrtnthtnlg", CONTROL_FLAG, RTF_BRDRTNTHTNLG, 0 }, + { "brdrtnthtnmg", CONTROL_FLAG, RTF_BRDRTNTHTNMG, 0 }, + { "brdrtnthtnsg", CONTROL_FLAG, RTF_BRDRTNTHTNSG, 0 }, + { "brdrtriple", CONTROL_FLAG, RTF_BRDRTRIPLE, 0 }, + { "brdrw", CONTROL_VALUE, RTF_BRDRW, 0 }, + { "brdrwavy", CONTROL_FLAG, RTF_BRDRWAVY, 0 }, + { "brdrwavydb", CONTROL_FLAG, RTF_BRDRWAVYDB, 0 }, + { "brkfrm", CONTROL_FLAG, RTF_BRKFRM, 0 }, + { "brsp", CONTROL_VALUE, RTF_BRSP, 0 }, + { "bullet", CONTROL_SYMBOL, RTF_BULLET, 0 }, + { "buptim", CONTROL_DESTINATION, RTF_BUPTIM, 0 }, + { "bxe", CONTROL_FLAG, RTF_BXE, 0 }, + { "caccentfive", CONTROL_FLAG, RTF_CACCENTFIVE, 0 }, + { "caccentfour", CONTROL_FLAG, RTF_CACCENTFOUR, 0 }, + { "caccentone", CONTROL_FLAG, RTF_CACCENTONE, 0 }, + { "caccentsix", CONTROL_FLAG, RTF_CACCENTSIX, 0 }, + { "caccentthree", CONTROL_FLAG, RTF_CACCENTTHREE, 0 }, + { "caccenttwo", CONTROL_FLAG, RTF_CACCENTTWO, 0 }, + { "cachedcolbal", CONTROL_FLAG, RTF_CACHEDCOLBAL, 0 }, + { "caps", CONTROL_TOGGLE, RTF_CAPS, 1 }, + { "category", CONTROL_DESTINATION, RTF_CATEGORY, 0 }, + { "cb", CONTROL_VALUE, RTF_CB, 0 }, + { "cbackgroundone", CONTROL_FLAG, RTF_CBACKGROUNDONE, 0 }, + { "cbackgroundtwo", CONTROL_FLAG, RTF_CBACKGROUNDTWO, 0 }, + { "cbpat", CONTROL_VALUE, RTF_CBPAT, 0 }, + { "cchs", CONTROL_VALUE, RTF_CCHS, 0 }, + { "cell", CONTROL_SYMBOL, RTF_CELL, 0 }, + { "cellx", CONTROL_VALUE, RTF_CELLX, 0 }, + { "cf", CONTROL_VALUE, RTF_CF, 0 }, + { "cfollowedhyperlink", CONTROL_FLAG, RTF_CFOLLOWEDHYPERLINK, 0 }, + { "cfpat", CONTROL_VALUE, RTF_CFPAT, 0 }, + { "cgrid", CONTROL_VALUE, RTF_CGRID, 0 }, + { "charrsid", CONTROL_VALUE, RTF_CHARRSID, 0 }, + { "charscalex", CONTROL_VALUE, RTF_CHARSCALEX, 100 }, + { "chatn", CONTROL_SYMBOL, RTF_CHATN, 0 }, + { "chbgbdiag", CONTROL_FLAG, RTF_CHBGBDIAG, 0 }, + { "chbgcross", CONTROL_FLAG, RTF_CHBGCROSS, 0 }, + { "chbgdcross", CONTROL_FLAG, RTF_CHBGDCROSS, 0 }, + { "chbgdkbdiag", CONTROL_FLAG, RTF_CHBGDKBDIAG, 0 }, + { "chbgdkcross", CONTROL_FLAG, RTF_CHBGDKCROSS, 0 }, + { "chbgdkdcross", CONTROL_FLAG, RTF_CHBGDKDCROSS, 0 }, + { "chbgdkfdiag", CONTROL_FLAG, RTF_CHBGDKFDIAG, 0 }, + { "chbgdkhoriz", CONTROL_FLAG, RTF_CHBGDKHORIZ, 0 }, + { "chbgdkvert", CONTROL_FLAG, RTF_CHBGDKVERT, 0 }, + { "chbgfdiag", CONTROL_FLAG, RTF_CHBGFDIAG, 0 }, + { "chbghoriz", CONTROL_FLAG, RTF_CHBGHORIZ, 0 }, + { "chbgvert", CONTROL_FLAG, RTF_CHBGVERT, 0 }, + { "chbrdr", CONTROL_FLAG, RTF_CHBRDR, 0 }, + { "chcbpat", CONTROL_VALUE, RTF_CHCBPAT, 0 }, + { "chcfpat", CONTROL_VALUE, RTF_CHCFPAT, 0 }, + { "chdate", CONTROL_SYMBOL, RTF_CHDATE, 0 }, + { "chdpa", CONTROL_SYMBOL, RTF_CHDPA, 0 }, + { "chdpl", CONTROL_SYMBOL, RTF_CHDPL, 0 }, + { "chftn", CONTROL_SYMBOL, RTF_CHFTN, 0 }, + { "chftnsep", CONTROL_SYMBOL, RTF_CHFTNSEP, 0 }, + { "chftnsepc", CONTROL_SYMBOL, RTF_CHFTNSEPC, 0 }, + { "chpgn", CONTROL_SYMBOL, RTF_CHPGN, 0 }, + { "chhres", CONTROL_VALUE, RTF_CHHRES, 0 }, + { "chshdng", CONTROL_VALUE, RTF_CHSHDNG, 0 }, + { "chtime", CONTROL_SYMBOL, RTF_CHTIME, 0 }, + { "chyperlink", CONTROL_FLAG, RTF_CHYPERLINK, 0 }, + { "clbgbdiag", CONTROL_FLAG, RTF_CLBGBDIAG, 0 }, + { "clbgcross", CONTROL_FLAG, RTF_CLBGCROSS, 0 }, + { "clbgdcross", CONTROL_FLAG, RTF_CLBGDCROSS, 0 }, + { "clbgdkbdiag", CONTROL_FLAG, RTF_CLBGDKBDIAG, 0 }, + { "clbgdkcross", CONTROL_FLAG, RTF_CLBGDKCROSS, 0 }, + { "clbgdkdcross", CONTROL_FLAG, RTF_CLBGDKDCROSS, 0 }, + { "clbgdkfdiag", CONTROL_FLAG, RTF_CLBGDKFDIAG, 0 }, + { "clbgdkhor", CONTROL_FLAG, RTF_CLBGDKHOR, 0 }, + { "clbgdkvert", CONTROL_FLAG, RTF_CLBGDKVERT, 0 }, + { "clbgfdiag", CONTROL_FLAG, RTF_CLBGFDIAG, 0 }, + { "clbghoriz", CONTROL_FLAG, RTF_CLBGHORIZ, 0 }, + { "clbgvert", CONTROL_FLAG, RTF_CLBGVERT, 0 }, + { "clbrdrb", CONTROL_FLAG, RTF_CLBRDRB, 0 }, + { "clbrdrl", CONTROL_FLAG, RTF_CLBRDRL, 0 }, + { "clbrdrr", CONTROL_FLAG, RTF_CLBRDRR, 0 }, + { "clbrdrt", CONTROL_FLAG, RTF_CLBRDRT, 0 }, + { "clcbpat", CONTROL_VALUE, RTF_CLCBPAT, 0 }, + { "clcbpatraw", CONTROL_VALUE, RTF_CLCBPATRAW, 0 }, + { "clcfpat", CONTROL_VALUE, RTF_CLCFPAT, 0 }, + { "clcfpatraw", CONTROL_VALUE, RTF_CLCFPATRAW, 0 }, + { "cldel", CONTROL_FLAG, RTF_CLDEL, 0 }, + { "cldelauth", CONTROL_VALUE, RTF_CLDELAUTH, 0 }, + { "cldeldttm", CONTROL_VALUE, RTF_CLDELDTTM, 0 }, + { "cldgll", CONTROL_FLAG, RTF_CLDGLL, 0 }, + { "cldglu", CONTROL_FLAG, RTF_CLDGLU, 0 }, + { "clFitText", CONTROL_FLAG, RTF_CLFITTEXT, 0 }, + { "clftsWidth", CONTROL_VALUE, RTF_CLFTSWIDTH, 0 }, + { "clhidemark", CONTROL_FLAG, RTF_CLHIDEMARK, 0 }, + { "clins", CONTROL_FLAG, RTF_CLINS, 0 }, + { "clinsauth", CONTROL_VALUE, RTF_CLINSAUTH, 0 }, + { "clinsdttm", CONTROL_VALUE, RTF_CLINSDTTM, 0 }, + { "clmgf", CONTROL_FLAG, RTF_CLMGF, 0 }, + { "clmrg", CONTROL_FLAG, RTF_CLMRG, 0 }, + { "clmrgd", CONTROL_FLAG, RTF_CLMRGD, 0 }, + { "clmrgdauth", CONTROL_VALUE, RTF_CLMRGDAUTH, 0 }, + { "clmrgddttm", CONTROL_VALUE, RTF_CLMRGDDTTM, 0 }, + { "clmrgdr", CONTROL_FLAG, RTF_CLMRGDR, 0 }, + { "clNoWrap", CONTROL_FLAG, RTF_CLNOWRAP, 0 }, + { "clpadb", CONTROL_VALUE, RTF_CLPADB, 0 }, + { "clpadfb", CONTROL_VALUE, RTF_CLPADFB, 0 }, + { "clpadfl", CONTROL_VALUE, RTF_CLPADFL, 0 }, + { "clpadfr", CONTROL_VALUE, RTF_CLPADFR, 0 }, + { "clpadft", CONTROL_VALUE, RTF_CLPADFT, 0 }, + { "clpadl", CONTROL_VALUE, RTF_CLPADL, 0 }, + { "clpadr", CONTROL_VALUE, RTF_CLPADR, 0 }, + { "clpadt", CONTROL_VALUE, RTF_CLPADT, 0 }, + { "clspb", CONTROL_VALUE, RTF_CLSPB, 0 }, + { "clspfb", CONTROL_VALUE, RTF_CLSPFB, 0 }, + { "clspfl", CONTROL_VALUE, RTF_CLSPFL, 0 }, + { "clspfr", CONTROL_VALUE, RTF_CLSPFR, 0 }, + { "clspft", CONTROL_VALUE, RTF_CLSPFT, 0 }, + { "clspl", CONTROL_VALUE, RTF_CLSPL, 0 }, + { "clspr", CONTROL_VALUE, RTF_CLSPR, 0 }, + { "clspt", CONTROL_VALUE, RTF_CLSPT, 0 }, + { "clshdng", CONTROL_VALUE, RTF_CLSHDNG, 0 }, + { "clshdngraw", CONTROL_VALUE, RTF_CLSHDNGRAW, 0 }, + { "clshdrawnil", CONTROL_FLAG, RTF_CLSHDRAWNIL, 0 }, + { "clsplit", CONTROL_FLAG, RTF_CLSPLIT, 0 }, + { "clsplitr", CONTROL_FLAG, RTF_CLSPLITR, 0 }, + { "cltxbtlr", CONTROL_FLAG, RTF_CLTXBTLR, 0 }, + { "cltxlrtb", CONTROL_FLAG, RTF_CLTXLRTB, 0 }, + { "cltxlrtbv", CONTROL_FLAG, RTF_CLTXLRTBV, 0 }, + { "cltxtbrl", CONTROL_FLAG, RTF_CLTXTBRL, 0 }, + { "cltxtbrlv", CONTROL_FLAG, RTF_CLTXTBRLV, 0 }, + { "clvertalb", CONTROL_FLAG, RTF_CLVERTALB, 0 }, + { "clvertalc", CONTROL_FLAG, RTF_CLVERTALC, 0 }, + { "clvertalt", CONTROL_FLAG, RTF_CLVERTALT, 0 }, + { "clvmgf", CONTROL_FLAG, RTF_CLVMGF, 0 }, + { "clvmrg", CONTROL_FLAG, RTF_CLVMRG, 0 }, + { "clwWidth", CONTROL_VALUE, RTF_CLWWIDTH, 0 }, + { "cmaindarkone", CONTROL_FLAG, RTF_CMAINDARKONE, 0 }, + { "cmaindarktwo", CONTROL_FLAG, RTF_CMAINDARKTWO, 0 }, + { "cmainlightone", CONTROL_FLAG, RTF_CMAINLIGHTONE, 0 }, + { "cmainlighttwo", CONTROL_FLAG, RTF_CMAINLIGHTTWO, 0 }, + { "collapsed", CONTROL_FLAG, RTF_COLLAPSED, 0 }, + { "colno", CONTROL_VALUE, RTF_COLNO, 0 }, + { "colorschememapping", CONTROL_DESTINATION, RTF_COLORSCHEMEMAPPING, 0 }, + { "colortbl", CONTROL_DESTINATION, RTF_COLORTBL, 0 }, + { "cols", CONTROL_VALUE, RTF_COLS, 1 }, + { "colsr", CONTROL_VALUE, RTF_COLSR, 0 }, + { "colsx", CONTROL_VALUE, RTF_COLSX, 720 }, + { "column", CONTROL_SYMBOL, RTF_COLUMN, 0 }, + { "colw", CONTROL_VALUE, RTF_COLW, 0 }, + { "comment", CONTROL_DESTINATION, RTF_COMMENT, 0 }, + { "company", CONTROL_DESTINATION, RTF_COMPANY, 0 }, + { "contextualspace", CONTROL_FLAG, RTF_CONTEXTUALSPACE, 0 }, + { "cpg", CONTROL_VALUE, RTF_CPG, 0 }, + { "crauth", CONTROL_VALUE, RTF_CRAUTH, 0 }, + { "crdate", CONTROL_VALUE, RTF_CRDATE, 0 }, + { "creatim", CONTROL_DESTINATION, RTF_CREATIM, 0 }, + { "cs", CONTROL_VALUE, RTF_CS, 0 }, + { "cshade", CONTROL_VALUE, RTF_CSHADE, 0 }, + { "ctextone", CONTROL_FLAG, RTF_CTEXTONE, 0 }, + { "ctexttwo", CONTROL_FLAG, RTF_CTEXTTWO, 0 }, + { "ctint", CONTROL_VALUE, RTF_CTINT, 0 }, + { "ctrl", CONTROL_FLAG, RTF_CTRL, 0 }, + { "cts", CONTROL_VALUE, RTF_CTS, 0 }, + { "cufi", CONTROL_VALUE, RTF_CUFI, 0 }, + { "culi", CONTROL_VALUE, RTF_CULI, 0 }, + { "curi", CONTROL_VALUE, RTF_CURI, 0 }, + { "cvmme", CONTROL_FLAG, RTF_CVMME, 0 }, + { "datafield", CONTROL_DESTINATION, RTF_DATAFIELD, 0 }, + { "datastore", CONTROL_DESTINATION, RTF_DATASTORE, 0 }, + { "date", CONTROL_FLAG, RTF_DATE, 0 }, + { "dbch", CONTROL_FLAG, RTF_DBCH, 0 }, + { "defchp", CONTROL_DESTINATION, RTF_DEFCHP, 0 }, + { "deff", CONTROL_VALUE, RTF_DEFF, 0 }, + { "defformat", CONTROL_FLAG, RTF_DEFFORMAT, 0 }, + { "deflang", CONTROL_VALUE, RTF_DEFLANG, 0 }, + { "deflangfe", CONTROL_VALUE, RTF_DEFLANGFE, 0 }, + { "defpap", CONTROL_DESTINATION, RTF_DEFPAP, 0 }, + { "defshp", CONTROL_FLAG, RTF_DEFSHP, 0 }, + { "deftab", CONTROL_VALUE, RTF_DEFTAB, 720 }, + { "deleted", CONTROL_TOGGLE, RTF_DELETED, 1 }, + { "delrsid", CONTROL_VALUE, RTF_DELRSID, 0 }, + { "dfrauth", CONTROL_VALUE, RTF_DFRAUTH, 0 }, + { "dfrdate", CONTROL_VALUE, RTF_DFRDATE, 0 }, + { "dfrmtxtx", CONTROL_VALUE, RTF_DFRMTXTX, 0 }, + { "dfrmtxty", CONTROL_VALUE, RTF_DFRMTXTY, 0 }, + { "dfrstart", CONTROL_VALUE, RTF_DFRSTART, 0 }, + { "dfrstop", CONTROL_VALUE, RTF_DFRSTOP, 0 }, + { "dfrxst", CONTROL_VALUE, RTF_DFRXST, 0 }, + { "dghorigin", CONTROL_VALUE, RTF_DGHORIGIN, 1701 }, + { "dghshow", CONTROL_VALUE, RTF_DGHSHOW, 3 }, + { "dghspace", CONTROL_VALUE, RTF_DGHSPACE, 120 }, + { "dgmargin", CONTROL_FLAG, RTF_DGMARGIN, 0 }, + { "dgsnap", CONTROL_FLAG, RTF_DGSNAP, 0 }, + { "dgvorigin", CONTROL_VALUE, RTF_DGVORIGIN, 1984 }, + { "dgvshow", CONTROL_VALUE, RTF_DGVSHOW, 0 }, + { "dgvspace", CONTROL_VALUE, RTF_DGVSPACE, 120 }, + { "dibitmap", CONTROL_VALUE, RTF_DIBITMAP, 0 }, + { "disabled", CONTROL_TOGGLE, RTF_DISABLED, 1 }, + { "dn", CONTROL_VALUE, RTF_DN, 6 }, + { "dntblnsbdb", CONTROL_FLAG, RTF_DNTBLNSBDB, 0 }, + { "do", CONTROL_DESTINATION, RTF_DO, 0 }, + { "dobxcolumn", CONTROL_FLAG, RTF_DOBXCOLUMN, 0 }, + { "dobxmargin", CONTROL_FLAG, RTF_DOBXMARGIN, 0 }, + { "dobxpage", CONTROL_FLAG, RTF_DOBXPAGE, 0 }, + { "dobymargin", CONTROL_FLAG, RTF_DOBYMARGIN, 0 }, + { "dobypage", CONTROL_FLAG, RTF_DOBYPAGE, 0 }, + { "dobypara", CONTROL_FLAG, RTF_DOBYPARA, 0 }, + { "doccomm", CONTROL_DESTINATION, RTF_DOCCOMM, 0 }, + { "doctemp", CONTROL_FLAG, RTF_DOCTEMP, 0 }, + { "doctype", CONTROL_VALUE, RTF_DOCTYPE, 0 }, + { "docvar", CONTROL_DESTINATION, RTF_DOCVAR, 0 }, + { "dodhgt", CONTROL_VALUE, RTF_DODHGT, 0 }, + { "dolock", CONTROL_FLAG, RTF_DOLOCK, 0 }, + { "donotembedlingdata", CONTROL_VALUE, RTF_DONOTEMBEDLINGDATA, 0 }, + { "donotembedsysfont", CONTROL_VALUE, RTF_DONOTEMBEDSYSFONT, 0 }, + { "donotshowcomments", CONTROL_FLAG, RTF_DONOTSHOWCOMMENTS, 0 }, + { "donotshowinsdel", CONTROL_FLAG, RTF_DONOTSHOWINSDEL, 0 }, + { "donotshowmarkup", CONTROL_FLAG, RTF_DONOTSHOWMARKUP, 0 }, + { "donotshowprops", CONTROL_FLAG, RTF_DONOTSHOWPROPS, 0 }, + { "dpaendhol", CONTROL_FLAG, RTF_DPAENDHOL, 0 }, + { "dpaendl", CONTROL_VALUE, RTF_DPAENDL, 0 }, + { "dpaendsol", CONTROL_FLAG, RTF_DPAENDSOL, 0 }, + { "dpaendw", CONTROL_VALUE, RTF_DPAENDW, 0 }, + { "dparc", CONTROL_FLAG, RTF_DPARC, 0 }, + { "dparcflipx", CONTROL_FLAG, RTF_DPARCFLIPX, 0 }, + { "dparcflipy", CONTROL_FLAG, RTF_DPARCFLIPY, 0 }, + { "dpastarthol", CONTROL_FLAG, RTF_DPASTARTHOL, 0 }, + { "dpastartl", CONTROL_VALUE, RTF_DPASTARTL, 0 }, + { "dpastartsol", CONTROL_FLAG, RTF_DPASTARTSOL, 0 }, + { "dpastartw", CONTROL_VALUE, RTF_DPASTARTW, 0 }, + { "dpcallout", CONTROL_FLAG, RTF_DPCALLOUT, 0 }, + { "dpcoa", CONTROL_VALUE, RTF_DPCOA, 0 }, + { "dpcoaccent", CONTROL_FLAG, RTF_DPCOACCENT, 0 }, + { "dpcobestfit", CONTROL_FLAG, RTF_DPCOBESTFIT, 0 }, + { "dpcoborder", CONTROL_FLAG, RTF_DPCOBORDER, 0 }, + { "dpcodabs", CONTROL_FLAG, RTF_DPCODABS, 0 }, + { "dpcodbottom", CONTROL_FLAG, RTF_DPCODBOTTOM, 0 }, + { "dpcodcenter", CONTROL_FLAG, RTF_DPCODCENTER, 0 }, + { "dpcodescent", CONTROL_VALUE, RTF_DPCODESCENT, 0 }, + { "dpcodtop", CONTROL_FLAG, RTF_DPCODTOP, 0 }, + { "dpcolength", CONTROL_VALUE, RTF_DPCOLENGTH, 0 }, + { "dpcominusx", CONTROL_FLAG, RTF_DPCOMINUSX, 0 }, + { "dpcominusy", CONTROL_FLAG, RTF_DPCOMINUSY, 0 }, + { "dpcooffset", CONTROL_VALUE, RTF_DPCOOFFSET, 0 }, + { "dpcosmarta", CONTROL_FLAG, RTF_DPCOSMARTA, 0 }, + { "dpcotdouble", CONTROL_FLAG, RTF_DPCOTDOUBLE, 0 }, + { "dpcotright", CONTROL_FLAG, RTF_DPCOTRIGHT, 0 }, + { "dpcotsingle", CONTROL_FLAG, RTF_DPCOTSINGLE, 0 }, + { "dpcottriple", CONTROL_FLAG, RTF_DPCOTTRIPLE, 0 }, + { "dpcount", CONTROL_VALUE, RTF_DPCOUNT, 0 }, + { "dpellipse", CONTROL_FLAG, RTF_DPELLIPSE, 0 }, + { "dpendgroup", CONTROL_FLAG, RTF_DPENDGROUP, 0 }, + { "dpfillbgcb", CONTROL_VALUE, RTF_DPFILLBGCB, 0 }, + { "dpfillbgcg", CONTROL_VALUE, RTF_DPFILLBGCG, 0 }, + { "dpfillbgcr", CONTROL_VALUE, RTF_DPFILLBGCR, 0 }, + { "dpfillbggray", CONTROL_VALUE, RTF_DPFILLBGGRAY, 0 }, + { "dpfillbgpal", CONTROL_FLAG, RTF_DPFILLBGPAL, 0 }, + { "dpfillfgcb", CONTROL_VALUE, RTF_DPFILLFGCB, 0 }, + { "dpfillfgcg", CONTROL_VALUE, RTF_DPFILLFGCG, 0 }, + { "dpfillfgcr", CONTROL_VALUE, RTF_DPFILLFGCR, 0 }, + { "dpfillfggray", CONTROL_VALUE, RTF_DPFILLFGGRAY, 0 }, + { "dpfillfgpal", CONTROL_FLAG, RTF_DPFILLFGPAL, 0 }, + { "dpfillpat", CONTROL_VALUE, RTF_DPFILLPAT, 0 }, + { "dpgroup", CONTROL_FLAG, RTF_DPGROUP, 0 }, + { "dpline", CONTROL_FLAG, RTF_DPLINE, 0 }, + { "dplinecob", CONTROL_VALUE, RTF_DPLINECOB, 0 }, + { "dplinecog", CONTROL_VALUE, RTF_DPLINECOG, 0 }, + { "dplinecor", CONTROL_VALUE, RTF_DPLINECOR, 0 }, + { "dplinedado", CONTROL_FLAG, RTF_DPLINEDADO, 0 }, + { "dplinedadodo", CONTROL_FLAG, RTF_DPLINEDADODO, 0 }, + { "dplinedash", CONTROL_FLAG, RTF_DPLINEDASH, 0 }, + { "dplinedot", CONTROL_FLAG, RTF_DPLINEDOT, 0 }, + { "dplinegray", CONTROL_VALUE, RTF_DPLINEGRAY, 0 }, + { "dplinehollow", CONTROL_FLAG, RTF_DPLINEHOLLOW, 0 }, + { "dplinepal", CONTROL_FLAG, RTF_DPLINEPAL, 0 }, + { "dplinesolid", CONTROL_FLAG, RTF_DPLINESOLID, 0 }, + { "dplinew", CONTROL_VALUE, RTF_DPLINEW, 0 }, + { "dppolycount", CONTROL_VALUE, RTF_DPPOLYCOUNT, 0 }, + { "dppolygon", CONTROL_FLAG, RTF_DPPOLYGON, 0 }, + { "dppolyline", CONTROL_FLAG, RTF_DPPOLYLINE, 0 }, + { "dpptx", CONTROL_VALUE, RTF_DPPTX, 0 }, + { "dppty", CONTROL_VALUE, RTF_DPPTY, 0 }, + { "dprect", CONTROL_FLAG, RTF_DPRECT, 0 }, + { "dproundr", CONTROL_FLAG, RTF_DPROUNDR, 0 }, + { "dpshadow", CONTROL_FLAG, RTF_DPSHADOW, 0 }, + { "dpshadx", CONTROL_VALUE, RTF_DPSHADX, 0 }, + { "dpshady", CONTROL_VALUE, RTF_DPSHADY, 0 }, + { "dptxbtlr", CONTROL_FLAG, RTF_DPTXBTLR, 0 }, + { "dptxbx", CONTROL_FLAG, RTF_DPTXBX, 0 }, + { "dptxbxmar", CONTROL_VALUE, RTF_DPTXBXMAR, 0 }, + { "dptxbxtext", CONTROL_DESTINATION, RTF_DPTXBXTEXT, 0 }, + { "dptxlrtb", CONTROL_FLAG, RTF_DPTXLRTB, 0 }, + { "dptxlrtbv", CONTROL_FLAG, RTF_DPTXLRTBV, 0 }, + { "dptxtbrl", CONTROL_FLAG, RTF_DPTXTBRL, 0 }, + { "dptxtbrlv", CONTROL_FLAG, RTF_DPTXTBRLV, 0 }, + { "dpx", CONTROL_VALUE, RTF_DPX, 0 }, + { "dpxsize", CONTROL_VALUE, RTF_DPXSIZE, 0 }, + { "dpy", CONTROL_VALUE, RTF_DPY, 0 }, + { "dpysize", CONTROL_VALUE, RTF_DPYSIZE, 0 }, + { "dropcapli", CONTROL_VALUE, RTF_DROPCAPLI, 0 }, + { "dropcapt", CONTROL_VALUE, RTF_DROPCAPT, 0 }, + { "ds", CONTROL_VALUE, RTF_DS, 0 }, + { "dxfrtext", CONTROL_VALUE, RTF_DXFRTEXT, 0 }, + { "dy", CONTROL_VALUE, RTF_DY, 0 }, + { "ebcend", CONTROL_DESTINATION, RTF_EBCEND, 0 }, + { "ebcstart", CONTROL_DESTINATION, RTF_EBCSTART, 0 }, + { "edmins", CONTROL_VALUE, RTF_EDMINS, 0 }, + { "embo", CONTROL_TOGGLE, RTF_EMBO, 1 }, + { "emdash", CONTROL_SYMBOL, RTF_EMDASH, 0 }, + { "emfblip", CONTROL_FLAG, RTF_EMFBLIP, 0 }, + { "emspace", CONTROL_SYMBOL, RTF_EMSPACE, 0 }, + { "endash", CONTROL_SYMBOL, RTF_ENDASH, 0 }, + { "enddoc", CONTROL_FLAG, RTF_ENDDOC, 0 }, + { "endnhere", CONTROL_FLAG, RTF_ENDNHERE, 0 }, + { "endnotes", CONTROL_FLAG, RTF_ENDNOTES, 0 }, + { "enforceprot", CONTROL_VALUE, RTF_ENFORCEPROT, 0 }, + { "enspace", CONTROL_SYMBOL, RTF_ENSPACE, 0 }, + { "expnd", CONTROL_VALUE, RTF_EXPND, 0 }, + { "expndtw", CONTROL_VALUE, RTF_EXPNDTW, 0 }, + { "expshrtn", CONTROL_FLAG, RTF_EXPSHRTN, 0 }, + { "f", CONTROL_VALUE, RTF_F, 0 }, + { "faauto", CONTROL_FLAG, RTF_FAAUTO, 0 }, + { "facenter", CONTROL_FLAG, RTF_FACENTER, 0 }, + { "facingp", CONTROL_TOGGLE, RTF_FACINGP, 1 }, + { "factoidname", CONTROL_DESTINATION, RTF_FACTOIDNAME, 0 }, + { "fafixed", CONTROL_FLAG, RTF_FAFIXED, 0 }, + { "fahang", CONTROL_FLAG, RTF_FAHANG, 0 }, + { "falt", CONTROL_DESTINATION, RTF_FALT, 0 }, + { "faroman", CONTROL_FLAG, RTF_FAROMAN, 0 }, + { "favar", CONTROL_FLAG, RTF_FAVAR, 0 }, + { "fbias", CONTROL_VALUE, RTF_FBIAS, 0 }, + { "fbidi", CONTROL_FLAG, RTF_FBIDI, 0 }, + { "fbidis", CONTROL_FLAG, RTF_FBIDIS, 0 }, + { "fbimajor", CONTROL_FLAG, RTF_FBIMAJOR, 0 }, + { "fbiminor", CONTROL_FLAG, RTF_FBIMINOR, 0 }, + { "fchars", CONTROL_DESTINATION, RTF_FCHARS, 0 }, + { "fcharset", CONTROL_VALUE, RTF_FCHARSET, 0 }, + { "fcs", CONTROL_VALUE, RTF_FCS, 0 }, + { "fdbmajor", CONTROL_FLAG, RTF_FDBMAJOR, 0 }, + { "fdbminor", CONTROL_FLAG, RTF_FDBMINOR, 0 }, + { "fdecor", CONTROL_FLAG, RTF_FDECOR, 0 }, + { "felnbrelev", CONTROL_FLAG, RTF_FELNBRELEV, 0 }, + { "fet", CONTROL_VALUE, RTF_FET, 0 }, + { "fetch", CONTROL_FLAG, RTF_FETCH, 0 }, + { "ffdefres", CONTROL_VALUE, RTF_FFDEFRES, 0 }, + { "ffdeftext", CONTROL_DESTINATION, RTF_FFDEFTEXT, 0 }, + { "ffentrymcr", CONTROL_DESTINATION, RTF_FFENTRYMCR, 0 }, + { "ffexitmcr", CONTROL_DESTINATION, RTF_FFEXITMCR, 0 }, + { "ffformat", CONTROL_DESTINATION, RTF_FFFORMAT, 0 }, + { "ffhaslistbox", CONTROL_VALUE, RTF_FFHASLISTBOX, 0 }, + { "ffhelptext", CONTROL_DESTINATION, RTF_FFHELPTEXT, 0 }, + { "ffhps", CONTROL_VALUE, RTF_FFHPS, 0 }, + { "ffl", CONTROL_DESTINATION, RTF_FFL, 0 }, + { "ffmaxlen", CONTROL_VALUE, RTF_FFMAXLEN, 0 }, + { "ffname", CONTROL_DESTINATION, RTF_FFNAME, 0 }, + { "ffownhelp", CONTROL_VALUE, RTF_FFOWNHELP, 0 }, + { "ffownstat", CONTROL_VALUE, RTF_FFOWNSTAT, 0 }, + { "ffprot", CONTROL_VALUE, RTF_FFPROT, 0 }, + { "ffrecalc", CONTROL_VALUE, RTF_FFRECALC, 0 }, + { "ffres", CONTROL_VALUE, RTF_FFRES, 0 }, + { "ffsize", CONTROL_VALUE, RTF_FFSIZE, 0 }, + { "ffstattext", CONTROL_DESTINATION, RTF_FFSTATTEXT, 0 }, + { "fftype", CONTROL_VALUE, RTF_FFTYPE, 0 }, + { "fftypetxt", CONTROL_VALUE, RTF_FFTYPETXT, 0 }, + { "fhimajor", CONTROL_FLAG, RTF_FHIMAJOR, 0 }, + { "fhiminor", CONTROL_FLAG, RTF_FHIMINOR, 0 }, + { "fi", CONTROL_VALUE, RTF_FI, 0 }, + { "fid", CONTROL_VALUE, RTF_FID, 0 }, + { "field", CONTROL_DESTINATION, RTF_FIELD, 0 }, + { "file", CONTROL_DESTINATION, RTF_FILE, 0 }, + { "filetbl", CONTROL_DESTINATION, RTF_FILETBL, 0 }, + { "fittext", CONTROL_VALUE, RTF_FITTEXT, 0 }, + { "fjgothic", CONTROL_FLAG, RTF_FJGOTHIC, 0 }, + { "fjminchou", CONTROL_FLAG, RTF_FJMINCHOU, 0 }, + { "fldalt", CONTROL_FLAG, RTF_FLDALT, 0 }, + { "flddirty", CONTROL_FLAG, RTF_FLDDIRTY, 0 }, + { "fldedit", CONTROL_FLAG, RTF_FLDEDIT, 0 }, + { "fldinst", CONTROL_DESTINATION, RTF_FLDINST, 0 }, + { "fldlock", CONTROL_FLAG, RTF_FLDLOCK, 0 }, + { "fldpriv", CONTROL_FLAG, RTF_FLDPRIV, 0 }, + { "fldrslt", CONTROL_DESTINATION, RTF_FLDRSLT, 0 }, + { "fldtype", CONTROL_DESTINATION, RTF_FLDTYPE, 0 }, + { "flomajor", CONTROL_FLAG, RTF_FLOMAJOR, 0 }, + { "flominor", CONTROL_FLAG, RTF_FLOMINOR, 0 }, + { "fmodern", CONTROL_FLAG, RTF_FMODERN, 0 }, + { "fn", CONTROL_VALUE, RTF_FN, 0 }, + { "fname", CONTROL_DESTINATION, RTF_FNAME, 0 }, + { "fnetwork", CONTROL_FLAG, RTF_FNETWORK, 0 }, + { "fnil", CONTROL_FLAG, RTF_FNIL, 0 }, + { "fnonfilesys", CONTROL_FLAG, RTF_FNONFILESYS, 0 }, + { "fontemb", CONTROL_DESTINATION, RTF_FONTEMB, 0 }, + { "fontfile", CONTROL_DESTINATION, RTF_FONTFILE, 0 }, + { "fonttbl", CONTROL_DESTINATION, RTF_FONTTBL, 0 }, + { "footer", CONTROL_DESTINATION, RTF_FOOTER, 0 }, + { "footerf", CONTROL_DESTINATION, RTF_FOOTERF, 0 }, + { "footerl", CONTROL_DESTINATION, RTF_FOOTERL, 0 }, + { "footerr", CONTROL_DESTINATION, RTF_FOOTERR, 0 }, + { "footery", CONTROL_VALUE, RTF_FOOTERY, 720 }, + { "footnote", CONTROL_DESTINATION, RTF_FOOTNOTE, 0 }, + { "forceupgrade", CONTROL_FLAG, RTF_FORCEUPGRADE, 0 }, + { "formdisp", CONTROL_FLAG, RTF_FORMDISP, 0 }, + { "formfield", CONTROL_DESTINATION, RTF_FORMFIELD, 0 }, + { "formprot", CONTROL_FLAG, RTF_FORMPROT, 0 }, + { "formshade", CONTROL_FLAG, RTF_FORMSHADE, 0 }, + { "fosnum", CONTROL_VALUE, RTF_FOSNUM, 0 }, + { "fprq", CONTROL_VALUE, RTF_FPRQ, 0 }, + { "fracwidth", CONTROL_FLAG, RTF_FRACWIDTH, 0 }, + { "frelative", CONTROL_VALUE, RTF_FRELATIVE, 0 }, + { "frmtxbtlr", CONTROL_FLAG, RTF_FRMTXBTLR, 0 }, + { "frmtxlrtb", CONTROL_FLAG, RTF_FRMTXLRTB, 0 }, + { "frmtxlrtbv", CONTROL_FLAG, RTF_FRMTXLRTBV, 0 }, + { "frmtxtbrl", CONTROL_FLAG, RTF_FRMTXTBRL, 0 }, + { "frmtxtbrlv", CONTROL_FLAG, RTF_FRMTXTBRLV, 0 }, + { "froman", CONTROL_FLAG, RTF_FROMAN, 0 }, + { "fromhtml", CONTROL_VALUE, RTF_FROMHTML, 0 }, + { "fromtext", CONTROL_FLAG, RTF_FROMTEXT, 0 }, + { "fs", CONTROL_VALUE, RTF_FS, 24 }, + { "fscript", CONTROL_FLAG, RTF_FSCRIPT, 0 }, + { "fswiss", CONTROL_FLAG, RTF_FSWISS, 0 }, + { "ftech", CONTROL_FLAG, RTF_FTECH, 0 }, + { "ftnalt", CONTROL_FLAG, RTF_FTNALT, 0 }, + { "ftnbj", CONTROL_FLAG, RTF_FTNBJ, 0 }, + { "ftncn", CONTROL_DESTINATION, RTF_FTNCN, 0 }, + { "ftnil", CONTROL_FLAG, RTF_FTNIL, 0 }, + { "ftnlytwnine", CONTROL_FLAG, RTF_FTNLYTWNINE, 0 }, + { "ftnnalc", CONTROL_FLAG, RTF_FTNNALC, 0 }, + { "ftnnar", CONTROL_FLAG, RTF_FTNNAR, 0 }, + { "ftnnauc", CONTROL_FLAG, RTF_FTNNAUC, 0 }, + { "ftnnchi", CONTROL_FLAG, RTF_FTNNCHI, 0 }, + { "ftnnchosung", CONTROL_FLAG, RTF_FTNNCHOSUNG, 0 }, + { "ftnncnum", CONTROL_FLAG, RTF_FTNNCNUM, 0 }, + { "ftnndbar", CONTROL_FLAG, RTF_FTNNDBAR, 0 }, + { "ftnndbnum", CONTROL_FLAG, RTF_FTNNDBNUM, 0 }, + { "ftnndbnumd", CONTROL_FLAG, RTF_FTNNDBNUMD, 0 }, + { "ftnndbnumk", CONTROL_FLAG, RTF_FTNNDBNUMK, 0 }, + { "ftnndbnumt", CONTROL_FLAG, RTF_FTNNDBNUMT, 0 }, + { "ftnnganada", CONTROL_FLAG, RTF_FTNNGANADA, 0 }, + { "ftnngbnum", CONTROL_FLAG, RTF_FTNNGBNUM, 0 }, + { "ftnngbnumd", CONTROL_FLAG, RTF_FTNNGBNUMD, 0 }, + { "ftnngbnumk", CONTROL_FLAG, RTF_FTNNGBNUMK, 0 }, + { "ftnngbnuml", CONTROL_FLAG, RTF_FTNNGBNUML, 0 }, + { "ftnnrlc", CONTROL_FLAG, RTF_FTNNRLC, 0 }, + { "ftnnruc", CONTROL_FLAG, RTF_FTNNRUC, 0 }, + { "ftnnzodiac", CONTROL_FLAG, RTF_FTNNZODIAC, 0 }, + { "ftnnzodiacd", CONTROL_FLAG, RTF_FTNNZODIACD, 0 }, + { "ftnnzodiacl", CONTROL_FLAG, RTF_FTNNZODIACL, 0 }, + { "ftnrestart", CONTROL_FLAG, RTF_FTNRESTART, 0 }, + { "ftnrstcont", CONTROL_FLAG, RTF_FTNRSTCONT, 0 }, + { "ftnrstpg", CONTROL_FLAG, RTF_FTNRSTPG, 0 }, + { "ftnsep", CONTROL_DESTINATION, RTF_FTNSEP, 0 }, + { "ftnsepc", CONTROL_DESTINATION, RTF_FTNSEPC, 0 }, + { "ftnstart", CONTROL_VALUE, RTF_FTNSTART, 1 }, + { "ftntj", CONTROL_FLAG, RTF_FTNTJ, 0 }, + { "fttruetype", CONTROL_FLAG, RTF_FTTRUETYPE, 0 }, + { "fvaliddos", CONTROL_FLAG, RTF_FVALIDDOS, 0 }, + { "fvalidhpfs", CONTROL_FLAG, RTF_FVALIDHPFS, 0 }, + { "fvalidmac", CONTROL_FLAG, RTF_FVALIDMAC, 0 }, + { "fvalidntfs", CONTROL_FLAG, RTF_FVALIDNTFS, 0 }, + { "g", CONTROL_DESTINATION, RTF_G, 0 }, + { "gcw", CONTROL_VALUE, RTF_GCW, 0 }, + { "generator", CONTROL_DESTINATION, RTF_GENERATOR, 0 }, + { "green", CONTROL_VALUE, RTF_GREEN, 0 }, + { "grfdocevents", CONTROL_VALUE, RTF_GRFDOCEVENTS, 0 }, + { "gridtbl", CONTROL_DESTINATION, RTF_GRIDTBL, 0 }, + { "gutter", CONTROL_VALUE, RTF_GUTTER, 0 }, + { "gutterprl", CONTROL_FLAG, RTF_GUTTERPRL, 0 }, + { "guttersxn", CONTROL_VALUE, RTF_GUTTERSXN, 0 }, + { "header", CONTROL_DESTINATION, RTF_HEADER, 0 }, + { "headerf", CONTROL_DESTINATION, RTF_HEADERF, 0 }, + { "headerl", CONTROL_DESTINATION, RTF_HEADERL, 0 }, + { "headerr", CONTROL_DESTINATION, RTF_HEADERR, 0 }, + { "headery", CONTROL_VALUE, RTF_HEADERY, 720 }, + { "hich", CONTROL_FLAG, RTF_HICH, 0 }, + { "highlight", CONTROL_VALUE, RTF_HIGHLIGHT, 0 }, + { "hl", CONTROL_DESTINATION, RTF_HL, 0 }, + { "hlfr", CONTROL_DESTINATION, RTF_HLFR, 0 }, + { "hlinkbase", CONTROL_DESTINATION, RTF_HLINKBASE, 0 }, + { "hlloc", CONTROL_DESTINATION, RTF_HLLOC, 0 }, + { "hlsrc", CONTROL_DESTINATION, RTF_HLSRC, 0 }, + { "horzdoc", CONTROL_FLAG, RTF_HORZDOC, 0 }, + { "horzsect", CONTROL_FLAG, RTF_HORZSECT, 0 }, + { "horzvert", CONTROL_VALUE, RTF_HORZVERT, 0 }, + { "hr", CONTROL_VALUE, RTF_HR, 0 }, + { "hres", CONTROL_VALUE, RTF_HRES, 0 }, + { "hrule", CONTROL_FLAG, RTF_HRULE, 0 }, + { "hsv", CONTROL_DESTINATION, RTF_HSV, 0 }, + { "htmautsp", CONTROL_FLAG, RTF_HTMAUTSP, 0 }, + { "htmlbase", CONTROL_FLAG, RTF_HTMLBASE, 0 }, + { "htmlrtf", CONTROL_TOGGLE, RTF_HTMLRTF, 1 }, + { "htmltag", CONTROL_DESTINATION, RTF_HTMLTAG, 0 }, + { "hwelev", CONTROL_FLAG, RTF_HWELEV, 0 }, + { "hyphauto", CONTROL_TOGGLE, RTF_HYPHAUTO, 1 }, + { "hyphcaps", CONTROL_TOGGLE, RTF_HYPHCAPS, 1 }, + { "hyphconsec", CONTROL_VALUE, RTF_HYPHCONSEC, 0 }, + { "hyphhotz", CONTROL_VALUE, RTF_HYPHHOTZ, 0 }, + { "hyphpar", CONTROL_TOGGLE, RTF_HYPHPAR, 1 }, + { "i", CONTROL_TOGGLE, RTF_I, 1 }, + { "id", CONTROL_VALUE, RTF_ID, 0 }, + { "ignoremixedcontent", CONTROL_VALUE, RTF_IGNOREMIXEDCONTENT, 0 }, + { "ilfomacatclnup", CONTROL_VALUE, RTF_ILFOMACATCLNUP, 0 }, + { "ilvl", CONTROL_VALUE, RTF_ILVL, 0 }, + { "impr", CONTROL_TOGGLE, RTF_IMPR, 1 }, + { "indmirror", CONTROL_FLAG, RTF_INDMIRROR, 0 }, + { "indrlsweleven", CONTROL_FLAG, RTF_INDRLSWELEVEN, 0 }, + { "info", CONTROL_DESTINATION, RTF_INFO, 0 }, + { "insrsid", CONTROL_VALUE, RTF_INSRSID, 0 }, + { "intbl", CONTROL_FLAG, RTF_INTBL, 0 }, + { "ipgp", CONTROL_VALUE, RTF_IPGP, 0 }, + { "irowband", CONTROL_VALUE, RTF_IROWBAND, 0 }, + { "irow", CONTROL_VALUE, RTF_IROW, 0 }, + { "itap", CONTROL_VALUE, RTF_ITAP, 1 }, + { "ixe", CONTROL_FLAG, RTF_IXE, 0 }, + { "jcompress", CONTROL_FLAG, RTF_JCOMPRESS, 0 }, + { "jexpand", CONTROL_FLAG, RTF_JEXPAND, 0 }, + { "jis", CONTROL_FLAG, RTF_JIS, 0 }, + { "jpegblip", CONTROL_FLAG, RTF_JPEGBLIP, 0 }, + { "jsksu", CONTROL_FLAG, RTF_JSKSU, 0 }, + { "keep", CONTROL_FLAG, RTF_KEEP, 0 }, + { "keepn", CONTROL_FLAG, RTF_KEEPN, 0 }, + { "kerning", CONTROL_VALUE, RTF_KERNING, 0 }, + { "keycode", CONTROL_DESTINATION, RTF_KEYCODE, 0 }, + { "keywords", CONTROL_DESTINATION, RTF_KEYWORDS, 0 }, + { "krnprsnet", CONTROL_FLAG, RTF_KRNPRSNET, 0 }, + { "ksulang", CONTROL_VALUE, RTF_KSULANG, 0 }, + { "jclisttab", CONTROL_FLAG, RTF_JCLISTTAB, 0 }, + { "landscape", CONTROL_FLAG, RTF_LANDSCAPE, 0 }, + { "lang", CONTROL_VALUE, RTF_LANG, 0 }, + { "langfe", CONTROL_VALUE, RTF_LANGFE, 0 }, + { "langfenp", CONTROL_VALUE, RTF_LANGFENP, 0 }, + { "langnp", CONTROL_VALUE, RTF_LANGNP, 0 }, + { "lastrow", CONTROL_FLAG, RTF_LASTROW, 0 }, + { "latentstyles", CONTROL_DESTINATION, RTF_LATENTSTYLES, 0 }, + { "lbr", CONTROL_VALUE, RTF_LBR, 0 }, + { "lchars", CONTROL_DESTINATION, RTF_LCHARS, 0 }, + { "ldblquote", CONTROL_SYMBOL, RTF_LDBLQUOTE, 0 }, + { "level", CONTROL_VALUE, RTF_LEVEL, 0 }, + { "levelfollow", CONTROL_VALUE, RTF_LEVELFOLLOW, 0 }, + { "levelindent", CONTROL_VALUE, RTF_LEVELINDENT, 0 }, + { "leveljc", CONTROL_VALUE, RTF_LEVELJC, 0 }, + { "leveljcn", CONTROL_VALUE, RTF_LEVELJCN, 0 }, + { "levellegal", CONTROL_VALUE, RTF_LEVELLEGAL, 0 }, + { "levelnfc", CONTROL_VALUE, RTF_LEVELNFC, 0 }, + { "levelnfcn", CONTROL_VALUE, RTF_LEVELNFCN, 0 }, + { "levelnorestart", CONTROL_VALUE, RTF_LEVELNORESTART, 0 }, + { "levelnumbers", CONTROL_DESTINATION, RTF_LEVELNUMBERS, 0 }, + { "levelold", CONTROL_VALUE, RTF_LEVELOLD, 0 }, + { "levelpicture", CONTROL_VALUE, RTF_LEVELPICTURE, 0 }, + { "levelpicturenosize", CONTROL_FLAG, RTF_LEVELPICTURENOSIZE, 0 }, + { "levelprev", CONTROL_VALUE, RTF_LEVELPREV, 0 }, + { "levelprevspace", CONTROL_VALUE, RTF_LEVELPREVSPACE, 0 }, + { "levelspace", CONTROL_VALUE, RTF_LEVELSPACE, 0 }, + { "levelstartat", CONTROL_VALUE, RTF_LEVELSTARTAT, 0 }, + { "leveltemplateid", CONTROL_VALUE, RTF_LEVELTEMPLATEID, 0 }, + { "leveltext", CONTROL_DESTINATION, RTF_LEVELTEXT, 0 }, + { "lfolevel", CONTROL_DESTINATION, RTF_LFOLEVEL, 0 }, + { "li", CONTROL_VALUE, RTF_LI, 0 }, + { "line", CONTROL_SYMBOL, RTF_LINE, 0 }, + { "linebetcol", CONTROL_FLAG, RTF_LINEBETCOL, 0 }, + { "linecont", CONTROL_FLAG, RTF_LINECONT, 0 }, + { "linemod", CONTROL_VALUE, RTF_LINEMOD, 1 }, + { "lineppage", CONTROL_FLAG, RTF_LINEPPAGE, 0 }, + { "linerestart", CONTROL_FLAG, RTF_LINERESTART, 0 }, + { "linestart", CONTROL_VALUE, RTF_LINESTART, 1 }, + { "linestarts", CONTROL_VALUE, RTF_LINESTARTS, 1 }, + { "linex", CONTROL_VALUE, RTF_LINEX, 360 }, + { "linkself", CONTROL_FLAG, RTF_LINKSELF, 0 }, + { "linkstyles", CONTROL_FLAG, RTF_LINKSTYLES, 0 }, + { "linkval", CONTROL_DESTINATION, RTF_LINKVAL, 0 }, + { "lin", CONTROL_VALUE, RTF_LIN, 0 }, + { "lisa", CONTROL_VALUE, RTF_LISA, 0 }, + { "lisb", CONTROL_VALUE, RTF_LISB, 0 }, + { "list", CONTROL_DESTINATION, RTF_LIST, 0 }, + { "listhybrid", CONTROL_FLAG, RTF_LISTHYBRID, 0 }, + { "listid", CONTROL_VALUE, RTF_LISTID, 0 }, + { "listlevel", CONTROL_DESTINATION, RTF_LISTLEVEL, 0 }, + { "listname", CONTROL_DESTINATION, RTF_LISTNAME, 0 }, + { "listoverride", CONTROL_DESTINATION, RTF_LISTOVERRIDE, 0 }, + { "listoverridecount", CONTROL_VALUE, RTF_LISTOVERRIDECOUNT, 0 }, + { "listoverrideformat", CONTROL_VALUE, RTF_LISTOVERRIDEFORMAT, 0 }, + { "listoverridestartat", CONTROL_FLAG, RTF_LISTOVERRIDESTARTAT, 0 }, + { "listoverridetable", CONTROL_DESTINATION, RTF_LISTOVERRIDETABLE, 0 }, + { "listpicture", CONTROL_DESTINATION, RTF_LISTPICTURE, 0 }, + { "listrestarthdn", CONTROL_VALUE, RTF_LISTRESTARTHDN, 0 }, + { "listsimple", CONTROL_VALUE, RTF_LISTSIMPLE, 0 }, + { "liststyleid", CONTROL_VALUE, RTF_LISTSTYLEID, 0 }, + { "liststylename", CONTROL_DESTINATION, RTF_LISTSTYLENAME, 0 }, + { "listtable", CONTROL_DESTINATION, RTF_LISTTABLE, 0 }, + { "listtemplateid", CONTROL_VALUE, RTF_LISTTEMPLATEID, 0 }, + { "listtext", CONTROL_DESTINATION, RTF_LISTTEXT, 0 }, + { "lnbrkrule", CONTROL_FLAG, RTF_LNBRKRULE, 0 }, + { "lndscpsxn", CONTROL_FLAG, RTF_LNDSCPSXN, 0 }, + { "lnongrid", CONTROL_FLAG, RTF_LNONGRID, 0 }, + { "loch", CONTROL_FLAG, RTF_LOCH, 0 }, + { "lquote", CONTROL_SYMBOL, RTF_LQUOTE, 0 }, + { "ls", CONTROL_VALUE, RTF_LS, 0 }, + { "lsdlocked", CONTROL_VALUE, RTF_LSDLOCKED, 0 }, + { "lsdlockeddef", CONTROL_VALUE, RTF_LSDLOCKEDDEF, 0 }, + { "lsdlockedexcept", CONTROL_DESTINATION, RTF_LSDLOCKEDEXCEPT, 0 }, + { "lsdpriority", CONTROL_VALUE, RTF_LSDPRIORITY, 0 }, + { "lsdprioritydef", CONTROL_VALUE, RTF_LSDPRIORITYDEF, 0 }, + { "lsdqformat", CONTROL_VALUE, RTF_LSDQFORMAT, 0 }, + { "lsdqformatdef", CONTROL_VALUE, RTF_LSDQFORMATDEF, 0 }, + { "lsdsemihidden", CONTROL_VALUE, RTF_LSDSEMIHIDDEN, 0 }, + { "lsdsemihiddendef", CONTROL_VALUE, RTF_LSDSEMIHIDDENDEF, 0 }, + { "lsdstimax", CONTROL_VALUE, RTF_LSDSTIMAX, 0 }, + { "lsdunhideused", CONTROL_VALUE, RTF_LSDUNHIDEUSED, 0 }, + { "lsdunhideuseddef", CONTROL_VALUE, RTF_LSDUNHIDEUSEDDEF, 0 }, + { "ltrch", CONTROL_FLAG, RTF_LTRCH, 0 }, + { "ltrdoc", CONTROL_FLAG, RTF_LTRDOC, 0 }, + { "ltrmark", CONTROL_SYMBOL, RTF_LTRMARK, 0 }, + { "ltrpar", CONTROL_FLAG, RTF_LTRPAR, 0 }, + { "ltrrow", CONTROL_FLAG, RTF_LTRROW, 0 }, + { "ltrsect", CONTROL_FLAG, RTF_LTRSECT, 0 }, + { "lvltentative", CONTROL_FLAG, RTF_LVLTENTATIVE, 0 }, + { "lytcalctblwd", CONTROL_FLAG, RTF_LYTCALCTBLWD, 0 }, + { "lytexcttp", CONTROL_FLAG, RTF_LYTEXCTTP, 0 }, + { "lytprtmet", CONTROL_FLAG, RTF_LYTPRTMET, 0 }, + { "lyttblrtgr", CONTROL_FLAG, RTF_LYTTBLRTGR, 0 }, + { "mac", CONTROL_FLAG, RTF_MAC, 0 }, + { "macc", CONTROL_DESTINATION, RTF_MACC, 0 }, + { "maccPr", CONTROL_DESTINATION, RTF_MACCPR, 0 }, + { "macpict", CONTROL_FLAG, RTF_MACPICT, 0 }, + { "mailmerge", CONTROL_DESTINATION, RTF_MAILMERGE, 0 }, + { "makebackup", CONTROL_FLAG, RTF_MAKEBACKUP, 0 }, + { "maln", CONTROL_DESTINATION, RTF_MALN, 0 }, + { "malnScr", CONTROL_DESTINATION, RTF_MALNSCR, 0 }, + { "manager", CONTROL_DESTINATION, RTF_MANAGER, 0 }, + { "margb", CONTROL_VALUE, RTF_MARGB, 1440 }, + { "margbsxn", CONTROL_VALUE, RTF_MARGBSXN, 0 }, + { "margl", CONTROL_VALUE, RTF_MARGL, 1800 }, + { "marglsxn", CONTROL_VALUE, RTF_MARGLSXN, 0 }, + { "margmirror", CONTROL_FLAG, RTF_MARGMIRROR, 0 }, + { "margmirsxn", CONTROL_FLAG, RTF_MARGMIRSXN, 0 }, + { "margPr", CONTROL_DESTINATION, RTF_MARGPR, 0 }, + { "margr", CONTROL_VALUE, RTF_MARGR, 1800 }, + { "margrsxn", CONTROL_VALUE, RTF_MARGRSXN, 0 }, + { "margSz", CONTROL_VALUE, RTF_MARGSZ, 0 }, + { "margt", CONTROL_VALUE, RTF_MARGT, 1440 }, + { "margtsxn", CONTROL_VALUE, RTF_MARGTSXN, 0 }, + { "mbar", CONTROL_DESTINATION, RTF_MBAR, 0 }, + { "mbarPr", CONTROL_DESTINATION, RTF_MBARPR, 0 }, + { "mbaseJc", CONTROL_DESTINATION, RTF_MBASEJC, 0 }, + { "mbegChr", CONTROL_DESTINATION, RTF_MBEGCHR, 0 }, + { "mborderBox", CONTROL_DESTINATION, RTF_MBORDERBOX, 0 }, + { "mborderBoxPr", CONTROL_DESTINATION, RTF_MBORDERBOXPR, 0 }, + { "mbox", CONTROL_DESTINATION, RTF_MBOX, 0 }, + { "mboxPr", CONTROL_DESTINATION, RTF_MBOXPR, 0 }, + { "mbrk", CONTROL_VALUE, RTF_MBRK, 0 }, + { "mbrkBin", CONTROL_VALUE, RTF_MBRKBIN, 0 }, + { "mbrkBinSub", CONTROL_VALUE, RTF_MBRKBINSUB, 0 }, + { "mcGp", CONTROL_VALUE, RTF_MCGP, 0 }, + { "mcGpRule", CONTROL_VALUE, RTF_MCGPRULE, 0 }, + { "mchr", CONTROL_DESTINATION, RTF_MCHR, 0 }, + { "mcount", CONTROL_DESTINATION, RTF_MCOUNT, 0 }, + { "mcSp", CONTROL_VALUE, RTF_MCSP, 0 }, + { "mctrlPr", CONTROL_DESTINATION, RTF_MCTRLPR, 0 }, + { "md", CONTROL_DESTINATION, RTF_MD, 0 }, + { "mdefJc", CONTROL_VALUE, RTF_MDEFJC, 0 }, + { "mdeg", CONTROL_DESTINATION, RTF_MDEG, 0 }, + { "mdegHide", CONTROL_DESTINATION, RTF_MDEGHIDE, 0 }, + { "mden", CONTROL_DESTINATION, RTF_MDEN, 0 }, + { "mdiff", CONTROL_DESTINATION, RTF_MDIFF, 0 }, + { "mdiffSty", CONTROL_VALUE, RTF_MDIFFSTY, 0 }, + { "mdispdef", CONTROL_VALUE, RTF_MDISPDEF, 1 }, + { "mdPr", CONTROL_DESTINATION, RTF_MDPR, 0 }, + { "me", CONTROL_DESTINATION, RTF_ME, 0 }, + { "mendChr", CONTROL_DESTINATION, RTF_MENDCHR, 0 }, + { "meqArr", CONTROL_DESTINATION, RTF_MEQARR, 0 }, + { "meqArrPr", CONTROL_DESTINATION, RTF_MEQARRPR, 0 }, + { "mf", CONTROL_DESTINATION, RTF_MF, 0 }, + { "mfName", CONTROL_DESTINATION, RTF_MFNAME, 0 }, + { "mfPr", CONTROL_DESTINATION, RTF_MFPR, 0 }, + { "mfunc", CONTROL_DESTINATION, RTF_MFUNC, 0 }, + { "mfuncPr", CONTROL_DESTINATION, RTF_MFUNCPR, 0 }, + { "mgroupChr", CONTROL_DESTINATION, RTF_MGROUPCHR, 0 }, + { "mgroupChrPr", CONTROL_DESTINATION, RTF_MGROUPCHRPR, 0 }, + { "mgrow", CONTROL_DESTINATION, RTF_MGROW, 0 }, + { "mhideBot", CONTROL_DESTINATION, RTF_MHIDEBOT, 0 }, + { "mhideLeft", CONTROL_DESTINATION, RTF_MHIDELEFT, 0 }, + { "mhideRight", CONTROL_DESTINATION, RTF_MHIDERIGHT, 0 }, + { "mhideTop", CONTROL_DESTINATION, RTF_MHIDETOP, 0 }, + { "mhtmltag", CONTROL_DESTINATION, RTF_MHTMLTAG, 0 }, + { "min", CONTROL_VALUE, RTF_MIN, 0 }, + { "minterSp", CONTROL_VALUE, RTF_MINTERSP, 0 }, + { "mintLim", CONTROL_VALUE, RTF_MINTLIM, 0 }, + { "mintraSp", CONTROL_VALUE, RTF_MINTRASP, 0 }, + { "mjc", CONTROL_VALUE, RTF_MJC, 0 }, + { "mlim", CONTROL_DESTINATION, RTF_MLIM, 0 }, + { "mlimloc", CONTROL_DESTINATION, RTF_MLIMLOC, 0 }, + { "mlimLoc", CONTROL_DESTINATION, RTF_MLIMLOC, 0 }, + { "mlimlow", CONTROL_DESTINATION, RTF_MLIMLOW, 0 }, + { "mlimLow", CONTROL_DESTINATION, RTF_MLIMLOW, 0 }, + { "mlimlowPr", CONTROL_DESTINATION, RTF_MLIMLOWPR, 0 }, + { "mlimLowPr", CONTROL_DESTINATION, RTF_MLIMLOWPR, 0 }, + { "mlimupp", CONTROL_DESTINATION, RTF_MLIMUPP, 0 }, + { "mlimUpp", CONTROL_DESTINATION, RTF_MLIMUPP, 0 }, + { "mlimuppPr", CONTROL_DESTINATION, RTF_MLIMUPPPR, 0 }, + { "mlimUppPr", CONTROL_DESTINATION, RTF_MLIMUPPPR, 0 }, + { "mlit", CONTROL_FLAG, RTF_MLIT, 0 }, + { "mlMargin", CONTROL_VALUE, RTF_MLMARGIN, 0 }, + { "mm", CONTROL_DESTINATION, RTF_MM, 0 }, + { "mmaddfieldname", CONTROL_DESTINATION, RTF_MMADDFIELDNAME, 0 }, + { "mmath", CONTROL_DESTINATION, RTF_MMATH, 0 }, + { "mmathFont", CONTROL_VALUE, RTF_MMATHFONT, 0 }, + { "mmathPict", CONTROL_DESTINATION, RTF_MMATHPICT, 0 }, + { "mmathPr", CONTROL_DESTINATION, RTF_MMATHPR, 0 }, + { "mmattach", CONTROL_FLAG, RTF_MMATTACH, 0 }, + { "mmaxdist", CONTROL_DESTINATION, RTF_MMAXDIST, 0 }, + { "mmblanklines", CONTROL_FLAG, RTF_MMBLANKLINES, 0 }, + { "mmc", CONTROL_DESTINATION, RTF_MMC, 0 }, + { "mmcJc", CONTROL_DESTINATION, RTF_MMCJC, 0 }, + { "mmconnectstr", CONTROL_DESTINATION, RTF_MMCONNECTSTR, 0 }, + { "mmconnectstrdata", CONTROL_DESTINATION, RTF_MMCONNECTSTRDATA, 0 }, + { "mmcPr", CONTROL_DESTINATION, RTF_MMCPR, 0 }, + { "mmcs", CONTROL_DESTINATION, RTF_MMCS, 0 }, + { "mmdatasource", CONTROL_DESTINATION, RTF_MMDATASOURCE, 0 }, + { "mmdatatypeaccess", CONTROL_FLAG, RTF_MMDATATYPEACCESS, 0 }, + { "mmdatatypeexcel", CONTROL_FLAG, RTF_MMDATATYPEEXCEL, 0 }, + { "mmdatatypefile", CONTROL_FLAG, RTF_MMDATATYPEFILE, 0 }, + { "mmdatatypeodbc", CONTROL_FLAG, RTF_MMDATATYPEODBC, 0 }, + { "mmdatatypeodso", CONTROL_FLAG, RTF_MMDATATYPEODSO, 0 }, + { "mmdatatypeqt", CONTROL_FLAG, RTF_MMDATATYPEQT, 0 }, + { "mmdefaultsql", CONTROL_FLAG, RTF_MMDEFAULTSQL, 0 }, + { "mmdestemail", CONTROL_FLAG, RTF_MMDESTEMAIL, 0 }, + { "mmdestfax", CONTROL_FLAG, RTF_MMDESTFAX, 0 }, + { "mmdestnewdoc", CONTROL_FLAG, RTF_MMDESTNEWDOC, 0 }, + { "mmdestprinter", CONTROL_FLAG, RTF_MMDESTPRINTER, 0 }, + { "mmerrors", CONTROL_VALUE, RTF_MMERRORS, 0 }, + { "mmfttypeaddress", CONTROL_FLAG, RTF_MMFTTYPEADDRESS, 0 }, + { "mmfttypebarcode", CONTROL_FLAG, RTF_MMFTTYPEBARCODE, 0 }, + { "mmfttypedbcolumn", CONTROL_FLAG, RTF_MMFTTYPEDBCOLUMN, 0 }, + { "mmfttypemapped", CONTROL_FLAG, RTF_MMFTTYPEMAPPED, 0 }, + { "mmfttypenull", CONTROL_FLAG, RTF_MMFTTYPENULL, 0 }, + { "mmfttypesalutation", CONTROL_FLAG, RTF_MMFTTYPESALUTATION, 0 }, + { "mmheadersource", CONTROL_DESTINATION, RTF_MMHEADERSOURCE, 0 }, + { "mmjdsotype", CONTROL_VALUE, RTF_MMJDSOTYPE, 0 }, + { "mmlinktoquery", CONTROL_FLAG, RTF_MMLINKTOQUERY, 0 }, + { "mmmailsubject", CONTROL_DESTINATION, RTF_MMMAILSUBJECT, 0 }, + { "mmmaintypecatalog", CONTROL_FLAG, RTF_MMMAINTYPECATALOG, 0 }, + { "mmmaintypeemail", CONTROL_FLAG, RTF_MMMAINTYPEEMAIL, 0 }, + { "mmmaintypeenvelopes", CONTROL_FLAG, RTF_MMMAINTYPEENVELOPES, 0 }, + { "mmmaintypefax", CONTROL_FLAG, RTF_MMMAINTYPEFAX, 0 }, + { "mmmaintypelabels", CONTROL_FLAG, RTF_MMMAINTYPELABELS, 0 }, + { "mmmaintypeletters", CONTROL_FLAG, RTF_MMMAINTYPELETTERS, 0 }, + { "mmodso", CONTROL_DESTINATION, RTF_MMODSO, 0 }, + { "mmodsoactive", CONTROL_VALUE, RTF_MMODSOACTIVE, 0 }, + { "mmodsocoldelim", CONTROL_VALUE, RTF_MMODSOCOLDELIM, 0 }, + { "mmodsocolumn", CONTROL_VALUE, RTF_MMODSOCOLUMN, 0 }, + { "mmodsodynaddr", CONTROL_VALUE, RTF_MMODSODYNADDR, 0 }, + { "mmodsofhdr", CONTROL_VALUE, RTF_MMODSOFHDR, 0 }, + { "mmodsofilter", CONTROL_DESTINATION, RTF_MMODSOFILTER, 0 }, + { "mmodsofldmpdata", CONTROL_DESTINATION, RTF_MMODSOFLDMPDATA, 0 }, + { "mmodsofmcolumn", CONTROL_VALUE, RTF_MMODSOFMCOLUMN, 0 }, + { "mmodsohash", CONTROL_VALUE, RTF_MMODSOHASH, 0 }, + { "mmodsolid", CONTROL_VALUE, RTF_MMODSOLID, 0 }, + { "mmodsomappedname", CONTROL_DESTINATION, RTF_MMODSOMAPPEDNAME, 0 }, + { "mmodsoname", CONTROL_DESTINATION, RTF_MMODSONAME, 0 }, + { "mmodsorecipdata", CONTROL_DESTINATION, RTF_MMODSORECIPDATA, 0 }, + { "mmodsosort", CONTROL_DESTINATION, RTF_MMODSOSORT, 0 }, + { "mmodsosrc", CONTROL_DESTINATION, RTF_MMODSOSRC, 0 }, + { "mmodsotable", CONTROL_DESTINATION, RTF_MMODSOTABLE, 0 }, + { "mmodsoudl", CONTROL_DESTINATION, RTF_MMODSOUDL, 0 }, + { "mmodsoudldata", CONTROL_DESTINATION, RTF_MMODSOUDLDATA, 0 }, + { "mmodsouniquetag", CONTROL_DESTINATION, RTF_MMODSOUNIQUETAG, 0 }, + { "mmPr", CONTROL_DESTINATION, RTF_MMPR, 0 }, + { "mmquery", CONTROL_DESTINATION, RTF_MMQUERY, 0 }, + { "mmr", CONTROL_DESTINATION, RTF_MMR, 0 }, + { "mmreccur", CONTROL_VALUE, RTF_MMRECCUR, 0 }, + { "mmshowdata", CONTROL_FLAG, RTF_MMSHOWDATA, 0 }, + { "mnary", CONTROL_DESTINATION, RTF_MNARY, 0 }, + { "mnaryLim", CONTROL_VALUE, RTF_MNARYLIM, 0 }, + { "mnaryPr", CONTROL_DESTINATION, RTF_MNARYPR, 0 }, + { "mnoBreak", CONTROL_DESTINATION, RTF_MNOBREAK, 0 }, + { "mnor", CONTROL_FLAG, RTF_MNOR, 0 }, + { "mnum", CONTROL_DESTINATION, RTF_MNUM, 0 }, + { "mo", CONTROL_VALUE, RTF_MO, 0 }, + { "mobjDist", CONTROL_DESTINATION, RTF_MOBJDIST, 0 }, + { "moMath", CONTROL_DESTINATION, RTF_MOMATH, 0 }, + { "moMathPara", CONTROL_DESTINATION, RTF_MOMATHPARA, 0 }, + { "moMathParaPr", CONTROL_DESTINATION, RTF_MOMATHPARAPR, 0 }, + { "mopEmu", CONTROL_DESTINATION, RTF_MOPEMU, 0 }, + { "mphant", CONTROL_DESTINATION, RTF_MPHANT, 0 }, + { "mphantPr", CONTROL_DESTINATION, RTF_MPHANTPR, 0 }, + { "mplcHide", CONTROL_DESTINATION, RTF_MPLCHIDE, 0 }, + { "mpos", CONTROL_DESTINATION, RTF_MPOS, 0 }, + { "mpostSp", CONTROL_VALUE, RTF_MPOSTSP, 0 }, + { "mpreSp", CONTROL_VALUE, RTF_MPRESP, 0 }, + { "mr", CONTROL_DESTINATION, RTF_MR, 0 }, + { "mrad", CONTROL_DESTINATION, RTF_MRAD, 0 }, + { "mradPr", CONTROL_DESTINATION, RTF_MRADPR, 0 }, + { "mrMargin", CONTROL_VALUE, RTF_MRMARGIN, 0 }, + { "mrPr", CONTROL_DESTINATION, RTF_MRPR, 0 }, + { "mrSp", CONTROL_VALUE, RTF_MRSP, 0 }, + { "mrSpRule", CONTROL_VALUE, RTF_MRSPRULE, 0 }, + { "mscr", CONTROL_VALUE, RTF_MSCR, 0 }, + { "msepChr", CONTROL_DESTINATION, RTF_MSEPCHR, 0 }, + { "mshow", CONTROL_DESTINATION, RTF_MSHOW, 0 }, + { "mshp", CONTROL_DESTINATION, RTF_MSHP, 0 }, + { "msmallFrac", CONTROL_VALUE, RTF_MSMALLFRAC, 0 }, + { "msmcap", CONTROL_FLAG, RTF_MSMCAP, 0 }, + { "msPre", CONTROL_DESTINATION, RTF_MSPRE, 0 }, + { "msPrePr", CONTROL_DESTINATION, RTF_MSPREPR, 0 }, + { "msSub", CONTROL_DESTINATION, RTF_MSSUB, 0 }, + { "msSubPr", CONTROL_DESTINATION, RTF_MSSUBPR, 0 }, + { "msSubSup", CONTROL_DESTINATION, RTF_MSSUBSUP, 0 }, + { "msSubSupPr", CONTROL_DESTINATION, RTF_MSSUBSUPPR, 0 }, + { "msSup", CONTROL_DESTINATION, RTF_MSSUP, 0 }, + { "msSupPr", CONTROL_DESTINATION, RTF_MSSUPPR, 0 }, + { "mstrikeBLTR", CONTROL_DESTINATION, RTF_MSTRIKEBLTR, 0 }, + { "mstrikeH", CONTROL_DESTINATION, RTF_MSTRIKEH, 0 }, + { "mstrikeTLBR", CONTROL_DESTINATION, RTF_MSTRIKETLBR, 0 }, + { "mstrikeV", CONTROL_DESTINATION, RTF_MSTRIKEV, 0 }, + { "msty", CONTROL_VALUE, RTF_MSTY, 0 }, + { "msub", CONTROL_DESTINATION, RTF_MSUB, 0 }, + { "msubHide", CONTROL_DESTINATION, RTF_MSUBHIDE, 0 }, + { "msup", CONTROL_DESTINATION, RTF_MSUP, 0 }, + { "msupHide", CONTROL_DESTINATION, RTF_MSUPHIDE, 0 }, + { "mtransp", CONTROL_DESTINATION, RTF_MTRANSP, 0 }, + { "mtype", CONTROL_DESTINATION, RTF_MTYPE, 0 }, + { "muser", CONTROL_FLAG, RTF_MUSER, 0 }, + { "mvauth", CONTROL_VALUE, RTF_MVAUTH, 0 }, + { "mvdate", CONTROL_VALUE, RTF_MVDATE, 0 }, + { "mvertJc", CONTROL_DESTINATION, RTF_MVERTJC, 0 }, + { "mvf", CONTROL_FLAG, RTF_MVF, 0 }, + { "mvfmf", CONTROL_DESTINATION, RTF_MVFMF, 0 }, + { "mvfml", CONTROL_DESTINATION, RTF_MVFML, 0 }, + { "mvt", CONTROL_FLAG, RTF_MVT, 0 }, + { "mvtof", CONTROL_DESTINATION, RTF_MVTOF, 0 }, + { "mvtol", CONTROL_DESTINATION, RTF_MVTOL, 0 }, + { "mwrapIndent", CONTROL_VALUE, RTF_MWRAPINDENT, 1440 }, + { "mwrapRight", CONTROL_VALUE, RTF_MWRAPRIGHT, 0 }, + { "mzeroAsc", CONTROL_DESTINATION, RTF_MZEROASC, 0 }, + { "mzeroDesc", CONTROL_DESTINATION, RTF_MZERODESC, 0 }, + { "mzeroWid", CONTROL_DESTINATION, RTF_MZEROWID, 0 }, + { "nestcell", CONTROL_SYMBOL, RTF_NESTCELL, 0 }, + { "nestrow", CONTROL_SYMBOL, RTF_NESTROW, 0 }, + { "nesttableprops", CONTROL_DESTINATION, RTF_NESTTABLEPROPS, 0 }, + { "newtblstyruls", CONTROL_FLAG, RTF_NEWTBLSTYRULS, 0 }, + { "nextfile", CONTROL_DESTINATION, RTF_NEXTFILE, 0 }, + { "noafcnsttbl", CONTROL_FLAG, RTF_NOAFCNSTTBL, 0 }, + { "nobrkwrptbl", CONTROL_FLAG, RTF_NOBRKWRPTBL, 0 }, + { "nocolbal", CONTROL_FLAG, RTF_NOCOLBAL, 0 }, + { "nocompatoptions", CONTROL_FLAG, RTF_NOCOMPATOPTIONS, 0 }, + { "nocwrap", CONTROL_FLAG, RTF_NOCWRAP, 0 }, + { "nocxsptable", CONTROL_FLAG, RTF_NOCXSPTABLE, 0 }, + { "noextrasprl", CONTROL_FLAG, RTF_NOEXTRASPRL, 0 }, + { "nofchars", CONTROL_VALUE, RTF_NOFCHARS, 0 }, + { "nofcharsws", CONTROL_VALUE, RTF_NOFCHARSWS, 0 }, + { "nofeaturethrottle", CONTROL_FLAG, RTF_NOFEATURETHROTTLE, 0 }, + { "nofpages", CONTROL_VALUE, RTF_NOFPAGES, 0 }, + { "nofwords", CONTROL_VALUE, RTF_NOFWORDS, 0 }, + { "nogrowautofit", CONTROL_FLAG, RTF_NOGROWAUTOFIT, 0 }, + { "noindnmbrts", CONTROL_FLAG, RTF_NOINDNMBRTS, 0 }, + { "nojkernpunct", CONTROL_FLAG, RTF_NOJKERNPUNCT, 0 }, + { "nolead", CONTROL_FLAG, RTF_NOLEAD, 0 }, + { "noline", CONTROL_FLAG, RTF_NOLINE, 0 }, + { "nolnhtadjtbl", CONTROL_FLAG, RTF_NOLNHTADJTBL, 0 }, + { "nonesttables", CONTROL_DESTINATION, RTF_NONESTTABLES, 0 }, + { "nonshppict", CONTROL_FLAG, RTF_NONSHPPICT, 0 }, + { "nooverflow", CONTROL_FLAG, RTF_NOOVERFLOW, 0 }, + { "noproof", CONTROL_FLAG, RTF_NOPROOF, 0 }, + { "noqfpromote", CONTROL_FLAG, RTF_NOQFPROMOTE, 0 }, + { "nosectexpand", CONTROL_FLAG, RTF_NOSECTEXPAND, 0 }, + { "nosnaplinegrid", CONTROL_FLAG, RTF_NOSNAPLINEGRID, 0 }, + { "nospaceforul", CONTROL_FLAG, RTF_NOSPACEFORUL, 0 }, + { "nosupersub", CONTROL_FLAG, RTF_NOSUPERSUB, 0 }, + { "notabind", CONTROL_FLAG, RTF_NOTABIND, 0 }, + { "notbrkcnstfrctbl", CONTROL_FLAG, RTF_NOTBRKCNSTFRCTBL, 0 }, + { "notcvasp", CONTROL_FLAG, RTF_NOTCVASP, 0 }, + { "notvatxbx", CONTROL_FLAG, RTF_NOTVATXBX, 0 }, + { "nouicompat", CONTROL_FLAG, RTF_NOUICOMPAT, 0 }, + { "noultrlspc", CONTROL_FLAG, RTF_NOULTRLSPC, 0 }, + { "nowidctlpar", CONTROL_FLAG, RTF_NOWIDCTLPAR, 0 }, + { "nowrap", CONTROL_FLAG, RTF_NOWRAP, 0 }, + { "nowwrap", CONTROL_FLAG, RTF_NOWWRAP, 0 }, + { "noxlattoyen", CONTROL_FLAG, RTF_NOXLATTOYEN, 0 }, + { "objalias", CONTROL_DESTINATION, RTF_OBJALIAS, 0 }, + { "objalign", CONTROL_VALUE, RTF_OBJALIGN, 0 }, + { "objattph", CONTROL_FLAG, RTF_OBJATTPH, 0 }, + { "objautlink", CONTROL_FLAG, RTF_OBJAUTLINK, 0 }, + { "objclass", CONTROL_DESTINATION, RTF_OBJCLASS, 0 }, + { "objcropb", CONTROL_VALUE, RTF_OBJCROPB, 0 }, + { "objcropl", CONTROL_VALUE, RTF_OBJCROPL, 0 }, + { "objcropr", CONTROL_VALUE, RTF_OBJCROPR, 0 }, + { "objcropt", CONTROL_VALUE, RTF_OBJCROPT, 0 }, + { "objdata", CONTROL_DESTINATION, RTF_OBJDATA, 0 }, + { "object", CONTROL_DESTINATION, RTF_OBJECT, 0 }, + { "objemb", CONTROL_FLAG, RTF_OBJEMB, 0 }, + { "objh", CONTROL_VALUE, RTF_OBJH, 0 }, + { "objhtml", CONTROL_FLAG, RTF_OBJHTML, 0 }, + { "objicemb", CONTROL_FLAG, RTF_OBJICEMB, 0 }, + { "objlink", CONTROL_FLAG, RTF_OBJLINK, 0 }, + { "objlock", CONTROL_FLAG, RTF_OBJLOCK, 0 }, + { "objname", CONTROL_DESTINATION, RTF_OBJNAME, 0 }, + { "objocx", CONTROL_FLAG, RTF_OBJOCX, 0 }, + { "objpub", CONTROL_FLAG, RTF_OBJPUB, 0 }, + { "objscalex", CONTROL_VALUE, RTF_OBJSCALEX, 0 }, + { "objscaley", CONTROL_VALUE, RTF_OBJSCALEY, 0 }, + { "objsect", CONTROL_DESTINATION, RTF_OBJSECT, 0 }, + { "objsetsize", CONTROL_FLAG, RTF_OBJSETSIZE, 0 }, + { "objsub", CONTROL_FLAG, RTF_OBJSUB, 0 }, + { "objtime", CONTROL_DESTINATION, RTF_OBJTIME, 0 }, + { "objtransy", CONTROL_VALUE, RTF_OBJTRANSY, 0 }, + { "objupdate", CONTROL_FLAG, RTF_OBJUPDATE, 0 }, + { "objw", CONTROL_VALUE, RTF_OBJW, 0 }, + { "ogutter", CONTROL_VALUE, RTF_OGUTTER, 0 }, + { "oldas", CONTROL_FLAG, RTF_OLDAS, 0 }, + { "oldcprops", CONTROL_DESTINATION, RTF_OLDCPROPS, 0 }, + { "oldlinewrap", CONTROL_FLAG, RTF_OLDLINEWRAP, 0 }, + { "oldpprops", CONTROL_DESTINATION, RTF_OLDPPROPS, 0 }, + { "oldsprops", CONTROL_DESTINATION, RTF_OLDSPROPS, 0 }, + { "oldtprops", CONTROL_DESTINATION, RTF_OLDTPROPS, 0 }, + { "oleclsid", CONTROL_DESTINATION, RTF_OLECLSID, 0 }, + { "operator", CONTROL_DESTINATION, RTF_OPERATOR, 0 }, + { "otblrul", CONTROL_FLAG, RTF_OTBLRUL, 0 }, + { "outl", CONTROL_TOGGLE, RTF_OUTL, 1 }, + { "outlinelevel", CONTROL_VALUE, RTF_OUTLINELEVEL, 0 }, + { "overlay", CONTROL_FLAG, RTF_OVERLAY, 0 }, + { "page", CONTROL_SYMBOL, RTF_PAGE, 0 }, + { "pagebb", CONTROL_FLAG, RTF_PAGEBB, 0 }, + { "panose", CONTROL_DESTINATION, RTF_PANOSE, 0 }, + { "paperh", CONTROL_VALUE, RTF_PAPERH, 15840 }, + { "paperw", CONTROL_VALUE, RTF_PAPERW, 12240 }, + { "par", CONTROL_SYMBOL, RTF_PAR, 0 }, + { "pararsid", CONTROL_VALUE, RTF_PARARSID, 0 }, + { "pard", CONTROL_FLAG, RTF_PARD, 0 }, + { "password", CONTROL_DESTINATION, RTF_PASSWORD, 0 }, + { "passwordhash", CONTROL_DESTINATION, RTF_PASSWORDHASH, 0 }, + { "pc", CONTROL_FLAG, RTF_PC, 0 }, + { "pca", CONTROL_FLAG, RTF_PCA, 0 }, + { "pgbrdrb", CONTROL_FLAG, RTF_PGBRDRB, 0 }, + { "pgbrdrfoot", CONTROL_FLAG, RTF_PGBRDRFOOT, 0 }, + { "pgbrdrhead", CONTROL_FLAG, RTF_PGBRDRHEAD, 0 }, + { "pgbrdrl", CONTROL_FLAG, RTF_PGBRDRL, 0 }, + { "pgbrdropt", CONTROL_VALUE, RTF_PGBRDROPT, 0 }, + { "pgbrdrr", CONTROL_FLAG, RTF_PGBRDRR, 0 }, + { "pgbrdrsnap", CONTROL_FLAG, RTF_PGBRDRSNAP, 0 }, + { "pgbrdrt", CONTROL_FLAG, RTF_PGBRDRT, 0 }, + { "pghsxn", CONTROL_VALUE, RTF_PGHSXN, 0 }, + { "pgnbidia", CONTROL_FLAG, RTF_PGNBIDIA, 0 }, + { "pgnbidib", CONTROL_FLAG, RTF_PGNBIDIB, 0 }, + { "pgnchosung", CONTROL_FLAG, RTF_PGNCHOSUNG, 0 }, + { "pgncnum", CONTROL_FLAG, RTF_PGNCNUM, 0 }, + { "pgncont", CONTROL_FLAG, RTF_PGNCONT, 0 }, + { "pgndbnum", CONTROL_FLAG, RTF_PGNDBNUM, 0 }, + { "pgndbnumd", CONTROL_FLAG, RTF_PGNDBNUMD, 0 }, + { "pgndbnumk", CONTROL_FLAG, RTF_PGNDBNUMK, 0 }, + { "pgndbnumt", CONTROL_FLAG, RTF_PGNDBNUMT, 0 }, + { "pgndec", CONTROL_FLAG, RTF_PGNDEC, 0 }, + { "pgndecd", CONTROL_FLAG, RTF_PGNDECD, 0 }, + { "pgnganada", CONTROL_FLAG, RTF_PGNGANADA, 0 }, + { "pgngbnum", CONTROL_FLAG, RTF_PGNGBNUM, 0 }, + { "pgngbnumd", CONTROL_FLAG, RTF_PGNGBNUMD, 0 }, + { "pgngbnumk", CONTROL_FLAG, RTF_PGNGBNUMK, 0 }, + { "pgngbnuml", CONTROL_FLAG, RTF_PGNGBNUML, 0 }, + { "pgnhindia", CONTROL_FLAG, RTF_PGNHINDIA, 0 }, + { "pgnhindib", CONTROL_FLAG, RTF_PGNHINDIB, 0 }, + { "pgnhindic", CONTROL_FLAG, RTF_PGNHINDIC, 0 }, + { "pgnhindid", CONTROL_FLAG, RTF_PGNHINDID, 0 }, + { "pgnhn", CONTROL_VALUE, RTF_PGNHN, 0 }, + { "pgnhnsc", CONTROL_FLAG, RTF_PGNHNSC, 0 }, + { "pgnhnsh", CONTROL_FLAG, RTF_PGNHNSH, 0 }, + { "pgnhnsm", CONTROL_FLAG, RTF_PGNHNSM, 0 }, + { "pgnhnsn", CONTROL_FLAG, RTF_PGNHNSN, 0 }, + { "pgnhnsp", CONTROL_FLAG, RTF_PGNHNSP, 0 }, + { "pgnid", CONTROL_FLAG, RTF_PGNID, 0 }, + { "pgnlcltr", CONTROL_FLAG, RTF_PGNLCLTR, 0 }, + { "pgnlcrm", CONTROL_FLAG, RTF_PGNLCRM, 0 }, + { "pgnrestart", CONTROL_FLAG, RTF_PGNRESTART, 0 }, + { "pgnstart", CONTROL_VALUE, RTF_PGNSTART, 1 }, + { "pgnstarts", CONTROL_VALUE, RTF_PGNSTARTS, 1 }, + { "pgnthaia", CONTROL_FLAG, RTF_PGNTHAIA, 0 }, + { "pgnthaib", CONTROL_FLAG, RTF_PGNTHAIB, 0 }, + { "pgnthaic", CONTROL_FLAG, RTF_PGNTHAIC, 0 }, + { "pgnucltr", CONTROL_FLAG, RTF_PGNUCLTR, 0 }, + { "pgnucrm", CONTROL_FLAG, RTF_PGNUCRM, 0 }, + { "pgnvieta", CONTROL_FLAG, RTF_PGNVIETA, 0 }, + { "pgnx", CONTROL_VALUE, RTF_PGNX, 720 }, + { "pgny", CONTROL_VALUE, RTF_PGNY, 720 }, + { "pgnzodiac", CONTROL_FLAG, RTF_PGNZODIAC, 0 }, + { "pgnzodiacd", CONTROL_FLAG, RTF_PGNZODIACD, 0 }, + { "pgnzodiacl", CONTROL_FLAG, RTF_PGNZODIACL, 0 }, + { "pgp", CONTROL_DESTINATION, RTF_PGP, 0 }, + { "pgptbl", CONTROL_DESTINATION, RTF_PGPTBL, 0 }, + { "pgwsxn", CONTROL_VALUE, RTF_PGWSXN, 0 }, + { "phcol", CONTROL_FLAG, RTF_PHCOL, 0 }, + { "phmrg", CONTROL_FLAG, RTF_PHMRG, 0 }, + { "phpg", CONTROL_FLAG, RTF_PHPG, 0 }, + { "picbmp", CONTROL_FLAG, RTF_PICBMP, 0 }, + { "picbpp", CONTROL_VALUE, RTF_PICBPP, 0 }, + { "piccropb", CONTROL_VALUE, RTF_PICCROPB, 0 }, + { "piccropl", CONTROL_VALUE, RTF_PICCROPL, 0 }, + { "piccropr", CONTROL_VALUE, RTF_PICCROPR, 0 }, + { "piccropt", CONTROL_VALUE, RTF_PICCROPT, 0 }, + { "pich", CONTROL_VALUE, RTF_PICH, 0 }, + { "pichgoal", CONTROL_VALUE, RTF_PICHGOAL, 0 }, + { "pichGoal", CONTROL_VALUE, RTF_PICHGOAL, 0 }, + { "picprop", CONTROL_DESTINATION, RTF_PICPROP, 0 }, + { "picscaled", CONTROL_FLAG, RTF_PICSCALED, 0 }, + { "picscalex", CONTROL_VALUE, RTF_PICSCALEX, 100 }, + { "picscaley", CONTROL_VALUE, RTF_PICSCALEY, 100 }, + { "pict", CONTROL_DESTINATION, RTF_PICT, 0 }, + { "picw", CONTROL_VALUE, RTF_PICW, 0 }, + { "picwgoal", CONTROL_VALUE, RTF_PICWGOAL, 0 }, + { "picwGoal", CONTROL_VALUE, RTF_PICWGOAL, 0 }, + { "pindtabqc", CONTROL_FLAG, RTF_PINDTABQC, 0 }, + { "pindtabql", CONTROL_FLAG, RTF_PINDTABQL, 0 }, + { "pindtabqr", CONTROL_FLAG, RTF_PINDTABQR, 0 }, + { "plain", CONTROL_FLAG, RTF_PLAIN, 0 }, + { "pmartabqc", CONTROL_FLAG, RTF_PMARTABQC, 0 }, + { "pmartabql", CONTROL_FLAG, RTF_PMARTABQL, 0 }, + { "pmartabqr", CONTROL_FLAG, RTF_PMARTABQR, 0 }, + { "pmmetafile", CONTROL_VALUE, RTF_PMMETAFILE, 0 }, + { "pn", CONTROL_DESTINATION, RTF_PN, 0 }, + { "pnacross", CONTROL_FLAG, RTF_PNACROSS, 0 }, + { "pnaiu", CONTROL_FLAG, RTF_PNAIU, 0 }, + { "pnaiud", CONTROL_FLAG, RTF_PNAIUD, 0 }, + { "pnaiueo", CONTROL_FLAG, RTF_PNAIUEO, 0 }, + { "pnaiueod", CONTROL_FLAG, RTF_PNAIUEOD, 0 }, + { "pnb", CONTROL_TOGGLE, RTF_PNB, 1 }, + { "pnbidia", CONTROL_FLAG, RTF_PNBIDIA, 0 }, + { "pnbidib", CONTROL_FLAG, RTF_PNBIDIB, 0 }, + { "pncaps", CONTROL_TOGGLE, RTF_PNCAPS, 1 }, + { "pncard", CONTROL_FLAG, RTF_PNCARD, 0 }, + { "pncf", CONTROL_VALUE, RTF_PNCF, 0 }, + { "pnchosung", CONTROL_FLAG, RTF_PNCHOSUNG, 0 }, + { "pncnum", CONTROL_FLAG, RTF_PNCNUM, 0 }, + { "pndbnum", CONTROL_FLAG, RTF_PNDBNUM, 0 }, + { "pndbnumd", CONTROL_FLAG, RTF_PNDBNUMD, 0 }, + { "pndbnumk", CONTROL_FLAG, RTF_PNDBNUMK, 0 }, + { "pndbnuml", CONTROL_FLAG, RTF_PNDBNUML, 0 }, + { "pndbnumt", CONTROL_FLAG, RTF_PNDBNUMT, 0 }, + { "pndec", CONTROL_FLAG, RTF_PNDEC, 0 }, + { "pndecd", CONTROL_FLAG, RTF_PNDECD, 0 }, + { "pnf", CONTROL_VALUE, RTF_PNF, 0 }, + { "pnfs", CONTROL_VALUE, RTF_PNFS, 0 }, + { "pnganada", CONTROL_FLAG, RTF_PNGANADA, 0 }, + { "pngblip", CONTROL_FLAG, RTF_PNGBLIP, 0 }, + { "pngbnum", CONTROL_FLAG, RTF_PNGBNUM, 0 }, + { "pngbnumd", CONTROL_FLAG, RTF_PNGBNUMD, 0 }, + { "pngbnumk", CONTROL_FLAG, RTF_PNGBNUMK, 0 }, + { "pngbnuml", CONTROL_FLAG, RTF_PNGBNUML, 0 }, + { "pnhang", CONTROL_FLAG, RTF_PNHANG, 0 }, + { "pni", CONTROL_TOGGLE, RTF_PNI, 1 }, + { "pnindent", CONTROL_VALUE, RTF_PNINDENT, 0 }, + { "pniroha", CONTROL_FLAG, RTF_PNIROHA, 0 }, + { "pnirohad", CONTROL_FLAG, RTF_PNIROHAD, 0 }, + { "pnlcltr", CONTROL_FLAG, RTF_PNLCLTR, 0 }, + { "pnlcrm", CONTROL_FLAG, RTF_PNLCRM, 0 }, + { "pnlvl", CONTROL_VALUE, RTF_PNLVL, 0 }, + { "pnlvlblt", CONTROL_FLAG, RTF_PNLVLBLT, 0 }, + { "pnlvlbody", CONTROL_FLAG, RTF_PNLVLBODY, 0 }, + { "pnlvlcont", CONTROL_FLAG, RTF_PNLVLCONT, 0 }, + { "pnnumonce", CONTROL_FLAG, RTF_PNNUMONCE, 0 }, + { "pnord", CONTROL_FLAG, RTF_PNORD, 0 }, + { "pnordt", CONTROL_FLAG, RTF_PNORDT, 0 }, + { "pnprev", CONTROL_FLAG, RTF_PNPREV, 0 }, + { "pnqc", CONTROL_FLAG, RTF_PNQC, 0 }, + { "pnql", CONTROL_FLAG, RTF_PNQL, 0 }, + { "pnqr", CONTROL_FLAG, RTF_PNQR, 0 }, + { "pnrauth", CONTROL_VALUE, RTF_PNRAUTH, 0 }, + { "pnrdate", CONTROL_VALUE, RTF_PNRDATE, 0 }, + { "pnrestart", CONTROL_FLAG, RTF_PNRESTART, 0 }, + { "pnrnfc", CONTROL_VALUE, RTF_PNRNFC, 0 }, + { "pnrnot", CONTROL_FLAG, RTF_PNRNOT, 0 }, + { "pnrpnbr", CONTROL_VALUE, RTF_PNRPNBR, 0 }, + { "pnrrgb", CONTROL_VALUE, RTF_PNRRGB, 0 }, + { "pnrstart", CONTROL_VALUE, RTF_PNRSTART, 0 }, + { "pnrstop", CONTROL_VALUE, RTF_PNRSTOP, 0 }, + { "pnrxst", CONTROL_VALUE, RTF_PNRXST, 0 }, + { "pnscaps", CONTROL_TOGGLE, RTF_PNSCAPS, 1 }, + { "pnseclvl", CONTROL_DESTINATION, RTF_PNSECLVL, 0 }, + { "pnsp", CONTROL_VALUE, RTF_PNSP, 0 }, + { "pnstart", CONTROL_VALUE, RTF_PNSTART, 0 }, + { "pnstrike", CONTROL_TOGGLE, RTF_PNSTRIKE, 1 }, + { "pntext", CONTROL_DESTINATION, RTF_PNTEXT, 0 }, + { "pntxta", CONTROL_DESTINATION, RTF_PNTXTA, 0 }, + { "pntxtb", CONTROL_DESTINATION, RTF_PNTXTB, 0 }, + { "pnucltr", CONTROL_FLAG, RTF_PNUCLTR, 0 }, + { "pnucrm", CONTROL_FLAG, RTF_PNUCRM, 0 }, + { "pnul", CONTROL_TOGGLE, RTF_PNUL, 1 }, + { "pnuld", CONTROL_FLAG, RTF_PNULD, 0 }, + { "pnuldash", CONTROL_FLAG, RTF_PNULDASH, 0 }, + { "pnuldashd", CONTROL_FLAG, RTF_PNULDASHD, 0 }, + { "pnuldashdd", CONTROL_FLAG, RTF_PNULDASHDD, 0 }, + { "pnuldb", CONTROL_FLAG, RTF_PNULDB, 0 }, + { "pnulhair", CONTROL_FLAG, RTF_PNULHAIR, 0 }, + { "pnulnone", CONTROL_FLAG, RTF_PNULNONE, 0 }, + { "pnulth", CONTROL_FLAG, RTF_PNULTH, 0 }, + { "pnulw", CONTROL_FLAG, RTF_PNULW, 0 }, + { "pnulwave", CONTROL_FLAG, RTF_PNULWAVE, 0 }, + { "pnzodiac", CONTROL_FLAG, RTF_PNZODIAC, 0 }, + { "pnzodiacd", CONTROL_FLAG, RTF_PNZODIACD, 0 }, + { "pnzodiacl", CONTROL_FLAG, RTF_PNZODIACL, 0 }, + { "posnegx", CONTROL_VALUE, RTF_POSNEGX, 0 }, + { "posnegy", CONTROL_VALUE, RTF_POSNEGY, 0 }, + { "posx", CONTROL_VALUE, RTF_POSX, 0 }, + { "posxc", CONTROL_FLAG, RTF_POSXC, 0 }, + { "posxi", CONTROL_FLAG, RTF_POSXI, 0 }, + { "posxl", CONTROL_FLAG, RTF_POSXL, 0 }, + { "posxo", CONTROL_FLAG, RTF_POSXO, 0 }, + { "posxr", CONTROL_FLAG, RTF_POSXR, 0 }, + { "posy", CONTROL_VALUE, RTF_POSY, 0 }, + { "posyb", CONTROL_FLAG, RTF_POSYB, 0 }, + { "posyc", CONTROL_FLAG, RTF_POSYC, 0 }, + { "posyil", CONTROL_FLAG, RTF_POSYIL, 0 }, + { "posyin", CONTROL_FLAG, RTF_POSYIN, 0 }, + { "posyout", CONTROL_FLAG, RTF_POSYOUT, 0 }, + { "posyt", CONTROL_FLAG, RTF_POSYT, 0 }, + { "prauth", CONTROL_VALUE, RTF_PRAUTH, 0 }, + { "prcolbl", CONTROL_FLAG, RTF_PRCOLBL, 0 }, + { "prdate", CONTROL_VALUE, RTF_PRDATE, 0 }, + { "printdata", CONTROL_FLAG, RTF_PRINTDATA, 0 }, + { "printim", CONTROL_DESTINATION, RTF_PRINTIM, 0 }, + { "private", CONTROL_DESTINATION, RTF_PRIVATE, 0 }, + { "propname", CONTROL_DESTINATION, RTF_PROPNAME, 0 }, + { "proptype", CONTROL_VALUE, RTF_PROPTYPE, 0 }, + { "protect", CONTROL_TOGGLE, RTF_PROTECT, 1 }, + { "protend", CONTROL_DESTINATION, RTF_PROTEND, 0 }, + { "protlevel", CONTROL_VALUE, RTF_PROTLEVEL, 0 }, + { "protstart", CONTROL_DESTINATION, RTF_PROTSTART, 0 }, + { "protusertbl", CONTROL_DESTINATION, RTF_PROTUSERTBL, 0 }, + { "psover", CONTROL_FLAG, RTF_PSOVER, 0 }, + { "psz", CONTROL_VALUE, RTF_PSZ, 0 }, + { "ptabldot", CONTROL_FLAG, RTF_PTABLDOT, 0 }, + { "ptablmdot", CONTROL_FLAG, RTF_PTABLMDOT, 0 }, + { "ptablminus", CONTROL_FLAG, RTF_PTABLMINUS, 0 }, + { "ptablnone", CONTROL_FLAG, RTF_PTABLNONE, 0 }, + { "ptabluscore", CONTROL_FLAG, RTF_PTABLUSCORE, 0 }, + { "pubauto", CONTROL_FLAG, RTF_PUBAUTO, 0 }, + { "pvmrg", CONTROL_FLAG, RTF_PVMRG, 0 }, + { "pvpara", CONTROL_FLAG, RTF_PVPARA, 0 }, + { "pvpg", CONTROL_FLAG, RTF_PVPG, 0 }, + { "pwd", CONTROL_VALUE, RTF_PWD, 0 }, + { "pxe", CONTROL_DESTINATION, RTF_PXE, 0 }, + { "qc", CONTROL_FLAG, RTF_QC, 0 }, + { "qd", CONTROL_FLAG, RTF_QD, 0 }, + { "qj", CONTROL_FLAG, RTF_QJ, 0 }, + { "qk", CONTROL_VALUE, RTF_QK, 0 }, + { "ql", CONTROL_FLAG, RTF_QL, 0 }, + { "qmspace", CONTROL_SYMBOL, RTF_QMSPACE, 0 }, + { "qr", CONTROL_FLAG, RTF_QR, 0 }, + { "qt", CONTROL_FLAG, RTF_QT, 0 }, + { "rawclbgdkbdiag", CONTROL_FLAG, RTF_RAWCLBGDKBDIAG, 0 }, + { "rawclbgbdiag", CONTROL_FLAG, RTF_RAWCLBGBDIAG, 0 }, + { "rawclbgcross", CONTROL_FLAG, RTF_RAWCLBGCROSS, 0 }, + { "rawclbgdcross", CONTROL_FLAG, RTF_RAWCLBGDCROSS, 0 }, + { "rawclbgdkcross", CONTROL_FLAG, RTF_RAWCLBGDKCROSS, 0 }, + { "rawclbgdkdcross", CONTROL_FLAG, RTF_RAWCLBGDKDCROSS, 0 }, + { "rawclbgdkfdiag", CONTROL_FLAG, RTF_RAWCLBGDKFDIAG, 0 }, + { "rawclbgdkhor", CONTROL_FLAG, RTF_RAWCLBGDKHOR, 0 }, + { "rawclbgdkvert", CONTROL_FLAG, RTF_RAWCLBGDKVERT, 0 }, + { "rawclbgfdiag", CONTROL_FLAG, RTF_RAWCLBGFDIAG, 0 }, + { "rawclbghoriz", CONTROL_FLAG, RTF_RAWCLBGHORIZ, 0 }, + { "rawclbgvert", CONTROL_FLAG, RTF_RAWCLBGVERT, 0 }, + { "rdblquote", CONTROL_SYMBOL, RTF_RDBLQUOTE, 0 }, + { "readonlyrecommended", CONTROL_FLAG, RTF_READONLYRECOMMENDED, 0 }, + { "readprot", CONTROL_FLAG, RTF_READPROT, 0 }, + { "red", CONTROL_VALUE, RTF_RED, 0 }, + { "relyonvml", CONTROL_VALUE, RTF_RELYONVML, 0 }, + { "remdttm", CONTROL_FLAG, RTF_REMDTTM, 0 }, + { "rempersonalinfo", CONTROL_FLAG, RTF_REMPERSONALINFO, 0 }, + { "result", CONTROL_DESTINATION, RTF_RESULT, 0 }, + { "revauth", CONTROL_VALUE, RTF_REVAUTH, 0 }, + { "revauthdel", CONTROL_VALUE, RTF_REVAUTHDEL, 0 }, + { "revbar", CONTROL_VALUE, RTF_REVBAR, 3 }, + { "revdttm", CONTROL_VALUE, RTF_REVDTTM, 0 }, + { "revdttmdel", CONTROL_VALUE, RTF_REVDTTMDEL, 0 }, + { "revised", CONTROL_TOGGLE, RTF_REVISED, 1 }, + { "revisions", CONTROL_FLAG, RTF_REVISIONS, 0 }, + { "revprop", CONTROL_VALUE, RTF_REVPROP, 3 }, + { "revprot", CONTROL_FLAG, RTF_REVPROT, 0 }, + { "revtbl", CONTROL_DESTINATION, RTF_REVTBL, 0 }, + { "revtim", CONTROL_DESTINATION, RTF_REVTIM, 0 }, + { "ri", CONTROL_VALUE, RTF_RI, 0 }, + { "rin", CONTROL_VALUE, RTF_RIN, 0 }, + { "row", CONTROL_SYMBOL, RTF_ROW, 0 }, + { "rquote", CONTROL_SYMBOL, RTF_RQUOTE, 0 }, + { "rsid", CONTROL_VALUE, RTF_RSID, 0 }, + { "rsidroot", CONTROL_VALUE, RTF_RSIDROOT, 0 }, + { "rsidtbl", CONTROL_DESTINATION, RTF_RSIDTBL, 0 }, + { "rsltbmp", CONTROL_FLAG, RTF_RSLTBMP, 0 }, + { "rslthtml", CONTROL_FLAG, RTF_RSLTHTML, 0 }, + { "rsltmerge", CONTROL_FLAG, RTF_RSLTMERGE, 0 }, + { "rsltpict", CONTROL_FLAG, RTF_RSLTPICT, 0 }, + { "rsltrtf", CONTROL_FLAG, RTF_RSLTRTF, 0 }, + { "rslttxt", CONTROL_FLAG, RTF_RSLTTXT, 0 }, + { "rtf", CONTROL_DESTINATION, RTF_RTF, 0 }, + { "rtlch", CONTROL_FLAG, RTF_RTLCH, 0 }, + { "rtldoc", CONTROL_FLAG, RTF_RTLDOC, 0 }, + { "rtlgutter", CONTROL_FLAG, RTF_RTLGUTTER, 0 }, + { "rtlmark", CONTROL_SYMBOL, RTF_RTLMARK, 0 }, + { "rtlpar", CONTROL_FLAG, RTF_RTLPAR, 0 }, + { "rtlrow", CONTROL_FLAG, RTF_RTLROW, 0 }, + { "rtlsect", CONTROL_FLAG, RTF_RTLSECT, 0 }, + { "rxe", CONTROL_DESTINATION, RTF_RXE, 0 }, + { "s", CONTROL_VALUE, RTF_S, 0 }, + { "sa", CONTROL_VALUE, RTF_SA, 0 }, + { "saauto", CONTROL_TOGGLE, RTF_SAAUTO, 1 }, + { "saftnnalc", CONTROL_FLAG, RTF_SAFTNNALC, 0 }, + { "saftnnar", CONTROL_FLAG, RTF_SAFTNNAR, 0 }, + { "saftnnauc", CONTROL_FLAG, RTF_SAFTNNAUC, 0 }, + { "saftnnchi", CONTROL_FLAG, RTF_SAFTNNCHI, 0 }, + { "saftnnchosung", CONTROL_FLAG, RTF_SAFTNNCHOSUNG, 0 }, + { "saftnncnum", CONTROL_FLAG, RTF_SAFTNNCNUM, 0 }, + { "saftnndbar", CONTROL_FLAG, RTF_SAFTNNDBAR, 0 }, + { "saftnndbnum", CONTROL_FLAG, RTF_SAFTNNDBNUM, 0 }, + { "saftnndbnumd", CONTROL_FLAG, RTF_SAFTNNDBNUMD, 0 }, + { "saftnndbnumk", CONTROL_FLAG, RTF_SAFTNNDBNUMK, 0 }, + { "saftnndbnumt", CONTROL_FLAG, RTF_SAFTNNDBNUMT, 0 }, + { "saftnnganada", CONTROL_FLAG, RTF_SAFTNNGANADA, 0 }, + { "saftnngbnum", CONTROL_FLAG, RTF_SAFTNNGBNUM, 0 }, + { "saftnngbnumd", CONTROL_FLAG, RTF_SAFTNNGBNUMD, 0 }, + { "saftnngbnumk", CONTROL_FLAG, RTF_SAFTNNGBNUMK, 0 }, + { "saftnngbnuml", CONTROL_FLAG, RTF_SAFTNNGBNUML, 0 }, + { "saftnnrlc", CONTROL_FLAG, RTF_SAFTNNRLC, 0 }, + { "saftnnruc", CONTROL_FLAG, RTF_SAFTNNRUC, 0 }, + { "saftnnzodiac", CONTROL_FLAG, RTF_SAFTNNZODIAC, 0 }, + { "saftnnzodiacd", CONTROL_FLAG, RTF_SAFTNNZODIACD, 0 }, + { "saftnnzodiacl", CONTROL_FLAG, RTF_SAFTNNZODIACL, 0 }, + { "saftnrestart", CONTROL_FLAG, RTF_SAFTNRESTART, 0 }, + { "saftnrstcont", CONTROL_FLAG, RTF_SAFTNRSTCONT, 0 }, + { "saftnstart", CONTROL_VALUE, RTF_SAFTNSTART, 1 }, + { "sautoupd", CONTROL_FLAG, RTF_SAUTOUPD, 0 }, + { "saveinvalidxml", CONTROL_FLAG, RTF_SAVEINVALIDXML, 0 }, + { "saveprevpict", CONTROL_FLAG, RTF_SAVEPREVPICT, 0 }, + { "sb", CONTROL_VALUE, RTF_SB, 0 }, + { "sbasedon", CONTROL_VALUE, RTF_SBASEDON, 222 }, + { "sbauto", CONTROL_TOGGLE, RTF_SBAUTO, 1 }, + { "sbkcol", CONTROL_FLAG, RTF_SBKCOL, 0 }, + { "sbkeven", CONTROL_FLAG, RTF_SBKEVEN, 0 }, + { "sbknone", CONTROL_FLAG, RTF_SBKNONE, 0 }, + { "sbkodd", CONTROL_FLAG, RTF_SBKODD, 0 }, + { "sbkpage", CONTROL_FLAG, RTF_SBKPAGE, 0 }, + { "sbys", CONTROL_FLAG, RTF_SBYS, 0 }, + { "scaps", CONTROL_TOGGLE, RTF_SCAPS, 1 }, + { "scompose", CONTROL_FLAG, RTF_SCOMPOSE, 0 }, + { "sec", CONTROL_VALUE, RTF_SEC, 0 }, + { "sect", CONTROL_SYMBOL, RTF_SECT, 0 }, + { "sectd", CONTROL_FLAG, RTF_SECTD, 0 }, + { "sectdefaultcl", CONTROL_FLAG, RTF_SECTDEFAULTCL, 0 }, + { "sectexpand", CONTROL_VALUE, RTF_SECTEXPAND, 0 }, + { "sectlinegrid", CONTROL_VALUE, RTF_SECTLINEGRID, 0 }, + { "sectnum", CONTROL_SYMBOL, RTF_SECTNUM, 0 }, + { "sectrsid", CONTROL_VALUE, RTF_SECTRSID, 0 }, + { "sectspecifycl", CONTROL_FLAG, RTF_SECTSPECIFYCL, 0 }, + { "sectspecifygenN", CONTROL_FLAG, RTF_SECTSPECIFYGENN, 0 }, + { "sectspecifyl", CONTROL_FLAG, RTF_SECTSPECIFYL, 0 }, + { "sectunlocked", CONTROL_FLAG, RTF_SECTUNLOCKED, 0 }, + { "sftnbj", CONTROL_FLAG, RTF_SFTNBJ, 0 }, + { "sftnnalc", CONTROL_FLAG, RTF_SFTNNALC, 0 }, + { "sftnnar", CONTROL_FLAG, RTF_SFTNNAR, 0 }, + { "sftnnauc", CONTROL_FLAG, RTF_SFTNNAUC, 0 }, + { "sftnnchi", CONTROL_FLAG, RTF_SFTNNCHI, 0 }, + { "sftnnchosung", CONTROL_FLAG, RTF_SFTNNCHOSUNG, 0 }, + { "sftnncnum", CONTROL_FLAG, RTF_SFTNNCNUM, 0 }, + { "sftnndbar", CONTROL_FLAG, RTF_SFTNNDBAR, 0 }, + { "sftnndbnum", CONTROL_FLAG, RTF_SFTNNDBNUM, 0 }, + { "sftnndbnumd", CONTROL_FLAG, RTF_SFTNNDBNUMD, 0 }, + { "sftnndbnumk", CONTROL_FLAG, RTF_SFTNNDBNUMK, 0 }, + { "sftnndbnumt", CONTROL_FLAG, RTF_SFTNNDBNUMT, 0 }, + { "sftnnganada", CONTROL_FLAG, RTF_SFTNNGANADA, 0 }, + { "sftnngbnum", CONTROL_FLAG, RTF_SFTNNGBNUM, 0 }, + { "sftnngbnumd", CONTROL_FLAG, RTF_SFTNNGBNUMD, 0 }, + { "sftnngbnumk", CONTROL_FLAG, RTF_SFTNNGBNUMK, 0 }, + { "sftnngbnuml", CONTROL_FLAG, RTF_SFTNNGBNUML, 0 }, + { "sftnnrlc", CONTROL_FLAG, RTF_SFTNNRLC, 0 }, + { "sftnnruc", CONTROL_FLAG, RTF_SFTNNRUC, 0 }, + { "sftnnzodiac", CONTROL_FLAG, RTF_SFTNNZODIAC, 0 }, + { "sftnnzodiacd", CONTROL_FLAG, RTF_SFTNNZODIACD, 0 }, + { "sftnnzodiacl", CONTROL_FLAG, RTF_SFTNNZODIACL, 0 }, + { "sftnrestart", CONTROL_FLAG, RTF_SFTNRESTART, 0 }, + { "sftnrstcont", CONTROL_FLAG, RTF_SFTNRSTCONT, 0 }, + { "sftnrstpg", CONTROL_FLAG, RTF_SFTNRSTPG, 0 }, + { "sftnstart", CONTROL_VALUE, RTF_SFTNSTART, 1 }, + { "sftntj", CONTROL_FLAG, RTF_SFTNTJ, 0 }, + { "shad", CONTROL_TOGGLE, RTF_SHAD, 1 }, + { "shading", CONTROL_VALUE, RTF_SHADING, 0 }, + { "shidden", CONTROL_FLAG, RTF_SHIDDEN, 0 }, + { "shift", CONTROL_FLAG, RTF_SHIFT, 0 }, + { "showplaceholdtext", CONTROL_VALUE, RTF_SHOWPLACEHOLDTEXT, 0 }, + { "showxmlerrors", CONTROL_VALUE, RTF_SHOWXMLERRORS, 0 }, + { "shp", CONTROL_DESTINATION, RTF_SHP, 0 }, + { "shpbottom", CONTROL_VALUE, RTF_SHPBOTTOM, 0 }, + { "shpbxcolumn", CONTROL_FLAG, RTF_SHPBXCOLUMN, 0 }, + { "shpbxignore", CONTROL_FLAG, RTF_SHPBXIGNORE, 0 }, + { "shpbxmargin", CONTROL_FLAG, RTF_SHPBXMARGIN, 0 }, + { "shpbxpage", CONTROL_FLAG, RTF_SHPBXPAGE, 0 }, + { "shpbyignore", CONTROL_FLAG, RTF_SHPBYIGNORE, 0 }, + { "shpbymargin", CONTROL_FLAG, RTF_SHPBYMARGIN, 0 }, + { "shpbypage", CONTROL_FLAG, RTF_SHPBYPAGE, 0 }, + { "shpbypara", CONTROL_FLAG, RTF_SHPBYPARA, 0 }, + { "shpfblwtxt", CONTROL_VALUE, RTF_SHPFBLWTXT, 0 }, + { "shpfhdr", CONTROL_VALUE, RTF_SHPFHDR, 0 }, + { "shpgrp", CONTROL_DESTINATION, RTF_SHPGRP, 0 }, + { "shpinst", CONTROL_DESTINATION, RTF_SHPINST, 0 }, + { "shpleft", CONTROL_VALUE, RTF_SHPLEFT, 0 }, + { "shplid", CONTROL_VALUE, RTF_SHPLID, 0 }, + { "shplockanchor", CONTROL_FLAG, RTF_SHPLOCKANCHOR, 0 }, + { "shppict", CONTROL_DESTINATION, RTF_SHPPICT, 0 }, + { "shpright", CONTROL_VALUE, RTF_SHPRIGHT, 0 }, + { "shprslt", CONTROL_DESTINATION, RTF_SHPRSLT, 0 }, + { "shptop", CONTROL_VALUE, RTF_SHPTOP, 0 }, + { "shptxt", CONTROL_DESTINATION, RTF_SHPTXT, 0 }, + { "shpwrk", CONTROL_VALUE, RTF_SHPWRK, 0 }, + { "shpwr", CONTROL_VALUE, RTF_SHPWR, 0 }, + { "shpz", CONTROL_VALUE, RTF_SHPZ, 0 }, + { "sl", CONTROL_VALUE, RTF_SL, 0 }, + { "slink", CONTROL_VALUE, RTF_SLINK, 0 }, + { "slmult", CONTROL_VALUE, RTF_SLMULT, 0 }, + { "slocked", CONTROL_FLAG, RTF_SLOCKED, 0 }, + { "sn", CONTROL_DESTINATION, RTF_SN, 0 }, + { "snaptogridincell", CONTROL_FLAG, RTF_SNAPTOGRIDINCELL, 0 }, + { "snext", CONTROL_VALUE, RTF_SNEXT, 0 }, + { "softcol", CONTROL_FLAG, RTF_SOFTCOL, 0 }, + { "softlheight", CONTROL_VALUE, RTF_SOFTLHEIGHT, 0 }, + { "softline", CONTROL_FLAG, RTF_SOFTLINE, 0 }, + { "softpage", CONTROL_FLAG, RTF_SOFTPAGE, 0 }, + { "sp", CONTROL_DESTINATION, RTF_SP, 0 }, + { "spersonal", CONTROL_FLAG, RTF_SPERSONAL, 0 }, + { "spltpgpar", CONTROL_FLAG, RTF_SPLTPGPAR, 0 }, + { "splytwnine", CONTROL_FLAG, RTF_SPLYTWNINE, 0 }, + { "spriority", CONTROL_VALUE, RTF_SPRIORITY, 0 }, + { "sprsbsp", CONTROL_FLAG, RTF_SPRSBSP, 0 }, + { "sprslnsp", CONTROL_FLAG, RTF_SPRSLNSP, 0 }, + { "sprsspbf", CONTROL_FLAG, RTF_SPRSSPBF, 0 }, + { "sprstsm", CONTROL_FLAG, RTF_SPRSTSM, 0 }, + { "sprstsp", CONTROL_FLAG, RTF_SPRSTSP, 0 }, + { "spv", CONTROL_FLAG, RTF_SPV, 0 }, + { "sqformat", CONTROL_FLAG, RTF_SQFORMAT, 0 }, + { "srauth", CONTROL_VALUE, RTF_SRAUTH, 0 }, + { "srdate", CONTROL_VALUE, RTF_SRDATE, 0 }, + { "sreply", CONTROL_FLAG, RTF_SREPLY, 0 }, + { "ssemihidden", CONTROL_VALUE, RTF_SSEMIHIDDEN, 0 }, + { "staticval", CONTROL_DESTINATION, RTF_STATICVAL, 0 }, + { "stextflow", CONTROL_VALUE, RTF_STEXTFLOW, 0 }, + { "strike", CONTROL_TOGGLE, RTF_STRIKE, 1 }, + { "striked", CONTROL_TOGGLE, RTF_STRIKED, 1 }, + { "stshfbi", CONTROL_VALUE, RTF_STSHFBI, 0 }, + { "stshfdbch", CONTROL_VALUE, RTF_STSHFDBCH, 0 }, + { "stshfhich", CONTROL_VALUE, RTF_STSHFHICH, 0 }, + { "stshfloch", CONTROL_VALUE, RTF_STSHFLOCH, 0 }, + { "stylelock", CONTROL_FLAG, RTF_STYLELOCK, 0 }, + { "stylelockbackcomp", CONTROL_FLAG, RTF_STYLELOCKBACKCOMP, 0 }, + { "stylelockenforced", CONTROL_FLAG, RTF_STYLELOCKENFORCED, 0 }, + { "stylelockqfset", CONTROL_FLAG, RTF_STYLELOCKQFSET, 0 }, + { "stylelocktheme", CONTROL_FLAG, RTF_STYLELOCKTHEME, 0 }, + { "stylesheet", CONTROL_DESTINATION, RTF_STYLESHEET, 0 }, + { "stylesortmethod", CONTROL_VALUE, RTF_STYLESORTMETHOD, 1 }, + { "styrsid", CONTROL_VALUE, RTF_STYRSID, 0 }, + { "sub", CONTROL_FLAG, RTF_SUB, 0 }, + { "subdocument", CONTROL_VALUE, RTF_SUBDOCUMENT, 0 }, + { "subfontbysize", CONTROL_FLAG, RTF_SUBFONTBYSIZE, 0 }, + { "subject", CONTROL_DESTINATION, RTF_SUBJECT, 0 }, + { "sunhideused", CONTROL_VALUE, RTF_SUNHIDEUSED, 0 }, + { "super", CONTROL_FLAG, RTF_SUPER, 0 }, + { "sv", CONTROL_DESTINATION, RTF_SV, 0 }, + { "svb", CONTROL_DESTINATION, RTF_SVB, 0 }, + { "swpbdr", CONTROL_FLAG, RTF_SWPBDR, 0 }, + { "tab", CONTROL_SYMBOL, RTF_TAB, 0 }, + { "tabsnoovrlp", CONTROL_FLAG, RTF_TABSNOOVRLP, 0 }, + { "taprtl", CONTROL_FLAG, RTF_TAPRTL, 0 }, + { "tb", CONTROL_VALUE, RTF_TB, 0 }, + { "tblind", CONTROL_VALUE, RTF_TBLIND, 0 }, + { "tblindtype", CONTROL_VALUE, RTF_TBLINDTYPE, 0 }, + { "tbllkbestfit", CONTROL_FLAG, RTF_TBLLKBESTFIT, 0 }, + { "tbllkborder", CONTROL_FLAG, RTF_TBLLKBORDER, 0 }, + { "tbllkcolor", CONTROL_FLAG, RTF_TBLLKCOLOR, 0 }, + { "tbllkfont", CONTROL_FLAG, RTF_TBLLKFONT, 0 }, + { "tbllkhdrcols", CONTROL_FLAG, RTF_TBLLKHDRCOLS, 0 }, + { "tbllkhdrrows", CONTROL_FLAG, RTF_TBLLKHDRROWS, 0 }, + { "tbllklastcol", CONTROL_FLAG, RTF_TBLLKLASTCOL, 0 }, + { "tbllklastrow", CONTROL_FLAG, RTF_TBLLKLASTROW, 0 }, + { "tbllknocolband", CONTROL_FLAG, RTF_TBLLKNOCOLBAND, 0 }, + { "tbllknorowband", CONTROL_FLAG, RTF_TBLLKNOROWBAND, 0 }, + { "tbllkshading", CONTROL_FLAG, RTF_TBLLKSHADING, 0 }, + { "tblrsid", CONTROL_VALUE, RTF_TBLRSID, 0 }, + { "tc", CONTROL_DESTINATION, RTF_TC, 0 }, + { "tcelld", CONTROL_FLAG, RTF_TCELLD, 0 }, + { "tcf", CONTROL_VALUE, RTF_TCF, 67 }, + { "tcl", CONTROL_VALUE, RTF_TCL, 0 }, + { "tcn", CONTROL_FLAG, RTF_TCN, 0 }, + { "tdfrmtxtBottom", CONTROL_VALUE, RTF_TDFRMTXTBOTTOM, 0 }, + { "tdfrmtxtLeft", CONTROL_VALUE, RTF_TDFRMTXTLEFT, 0 }, + { "tdfrmtxtRight", CONTROL_VALUE, RTF_TDFRMTXTRIGHT, 0 }, + { "tdfrmtxtTop", CONTROL_VALUE, RTF_TDFRMTXTTOP, 0 }, + { "template", CONTROL_DESTINATION, RTF_TEMPLATE, 0 }, + { "themedata", CONTROL_DESTINATION, RTF_THEMEDATA, 0 }, + { "themelang", CONTROL_VALUE, RTF_THEMELANG, 0 }, + { "themelangcs", CONTROL_VALUE, RTF_THEMELANGCS, 0 }, + { "themelangfe", CONTROL_VALUE, RTF_THEMELANGFE, 0 }, + { "time", CONTROL_FLAG, RTF_TIME, 0 }, + { "title", CONTROL_DESTINATION, RTF_TITLE, 0 }, + { "titlepg", CONTROL_FLAG, RTF_TITLEPG, 0 }, + { "tldot", CONTROL_FLAG, RTF_TLDOT, 0 }, + { "tleq", CONTROL_FLAG, RTF_TLEQ, 0 }, + { "tlhyph", CONTROL_FLAG, RTF_TLHYPH, 0 }, + { "tlmdot", CONTROL_FLAG, RTF_TLMDOT, 0 }, + { "tlth", CONTROL_FLAG, RTF_TLTH, 0 }, + { "tlul", CONTROL_FLAG, RTF_TLUL, 0 }, + { "toplinepunct", CONTROL_FLAG, RTF_TOPLINEPUNCT, 0 }, + { "tphcol", CONTROL_FLAG, RTF_TPHCOL, 0 }, + { "tphmrg", CONTROL_FLAG, RTF_TPHMRG, 0 }, + { "tphpg", CONTROL_FLAG, RTF_TPHPG, 0 }, + { "tposnegx", CONTROL_VALUE, RTF_TPOSNEGX, 0 }, + { "tposnegy", CONTROL_VALUE, RTF_TPOSNEGY, 0 }, + { "tposxc", CONTROL_FLAG, RTF_TPOSXC, 0 }, + { "tposxi", CONTROL_FLAG, RTF_TPOSXI, 0 }, + { "tposxl", CONTROL_FLAG, RTF_TPOSXL, 0 }, + { "tposx", CONTROL_VALUE, RTF_TPOSX, 0 }, + { "tposxo", CONTROL_FLAG, RTF_TPOSXO, 0 }, + { "tposxr", CONTROL_FLAG, RTF_TPOSXR, 0 }, + { "tposy", CONTROL_VALUE, RTF_TPOSY, 0 }, + { "tposyb", CONTROL_FLAG, RTF_TPOSYB, 0 }, + { "tposyc", CONTROL_FLAG, RTF_TPOSYC, 0 }, + { "tposyil", CONTROL_FLAG, RTF_TPOSYIL, 0 }, + { "tposyin", CONTROL_FLAG, RTF_TPOSYIN, 0 }, + { "tposyout", CONTROL_FLAG, RTF_TPOSYOUT, 0 }, + { "tposyt", CONTROL_FLAG, RTF_TPOSYT, 0 }, + { "tpvmrg", CONTROL_FLAG, RTF_TPVMRG, 0 }, + { "tpvpara", CONTROL_FLAG, RTF_TPVPARA, 0 }, + { "tpvpg", CONTROL_FLAG, RTF_TPVPG, 0 }, + { "tqc", CONTROL_FLAG, RTF_TQC, 0 }, + { "tqdec", CONTROL_FLAG, RTF_TQDEC, 0 }, + { "tqr", CONTROL_FLAG, RTF_TQR, 0 }, + { "trackformatting", CONTROL_VALUE, RTF_TRACKFORMATTING, 0 }, + { "trackmoves", CONTROL_VALUE, RTF_TRACKMOVES, 0 }, + { "transmf", CONTROL_FLAG, RTF_TRANSMF, 0 }, + { "trauth", CONTROL_VALUE, RTF_TRAUTH, 0 }, + { "trautofit", CONTROL_TOGGLE, RTF_TRAUTOFIT, 1 }, + { "trbgbdiag", CONTROL_FLAG, RTF_TRBGBDIAG, 0 }, + { "trbgcross", CONTROL_FLAG, RTF_TRBGCROSS, 0 }, + { "trbgdcross", CONTROL_FLAG, RTF_TRBGDCROSS, 0 }, + { "trbgdkbdiag", CONTROL_FLAG, RTF_TRBGDKBDIAG, 0 }, + { "trbgdkcross", CONTROL_FLAG, RTF_TRBGDKCROSS, 0 }, + { "trbgdkdcross", CONTROL_FLAG, RTF_TRBGDKDCROSS, 0 }, + { "trbgdkfdiag", CONTROL_FLAG, RTF_TRBGDKFDIAG, 0 }, + { "trbgdkhor", CONTROL_FLAG, RTF_TRBGDKHOR, 0 }, + { "trbgdkvert", CONTROL_FLAG, RTF_TRBGDKVERT, 0 }, + { "trbgfdiag", CONTROL_FLAG, RTF_TRBGFDIAG, 0 }, + { "trbghoriz", CONTROL_FLAG, RTF_TRBGHORIZ, 0 }, + { "trbgvert", CONTROL_FLAG, RTF_TRBGVERT, 0 }, + { "trbrdrb", CONTROL_FLAG, RTF_TRBRDRB, 0 }, + { "trbrdrh", CONTROL_FLAG, RTF_TRBRDRH, 0 }, + { "trbrdrl", CONTROL_FLAG, RTF_TRBRDRL, 0 }, + { "trbrdrr", CONTROL_FLAG, RTF_TRBRDRR, 0 }, + { "trbrdrt", CONTROL_FLAG, RTF_TRBRDRT, 0 }, + { "trbrdrv", CONTROL_FLAG, RTF_TRBRDRV, 0 }, + { "trcbpat", CONTROL_VALUE, RTF_TRCBPAT, 0 }, + { "trcfpat", CONTROL_VALUE, RTF_TRCFPAT, 0 }, + { "trdate", CONTROL_VALUE, RTF_TRDATE, 0 }, + { "trftsWidthA", CONTROL_VALUE, RTF_TRFTSWIDTHA, 0 }, + { "trftsWidthB", CONTROL_VALUE, RTF_TRFTSWIDTHB, 0 }, + { "trftsWidth", CONTROL_VALUE, RTF_TRFTSWIDTH, 0 }, + { "trgaph", CONTROL_VALUE, RTF_TRGAPH, 0 }, + { "trhdr", CONTROL_FLAG, RTF_TRHDR, 0 }, + { "trkeep", CONTROL_FLAG, RTF_TRKEEP, 0 }, + { "trkeepfollow", CONTROL_FLAG, RTF_TRKEEPFOLLOW, 0 }, + { "trleft", CONTROL_VALUE, RTF_TRLEFT, 0 }, + { "trowd", CONTROL_FLAG, RTF_TROWD, 0 }, + { "trpaddb", CONTROL_VALUE, RTF_TRPADDB, 0 }, + { "trpaddfb", CONTROL_VALUE, RTF_TRPADDFB, 0 }, + { "trpaddfl", CONTROL_VALUE, RTF_TRPADDFL, 0 }, + { "trpaddfr", CONTROL_VALUE, RTF_TRPADDFR, 0 }, + { "trpaddft", CONTROL_VALUE, RTF_TRPADDFT, 0 }, + { "trpaddl", CONTROL_VALUE, RTF_TRPADDL, 0 }, + { "trpaddr", CONTROL_VALUE, RTF_TRPADDR, 0 }, + { "trpaddt", CONTROL_VALUE, RTF_TRPADDT, 0 }, + { "trpadob", CONTROL_VALUE, RTF_TRPADOB, 0 }, + { "trpadofb", CONTROL_VALUE, RTF_TRPADOFB, 0 }, + { "trpadofl", CONTROL_VALUE, RTF_TRPADOFL, 0 }, + { "trpadofr", CONTROL_VALUE, RTF_TRPADOFR, 0 }, + { "trpadoft", CONTROL_VALUE, RTF_TRPADOFT, 0 }, + { "trpadol", CONTROL_VALUE, RTF_TRPADOL, 0 }, + { "trpador", CONTROL_VALUE, RTF_TRPADOR, 0 }, + { "trpadot", CONTROL_VALUE, RTF_TRPADOT, 0 }, + { "trpat", CONTROL_VALUE, RTF_TRPAT, 0 }, + { "trqc", CONTROL_FLAG, RTF_TRQC, 0 }, + { "trql", CONTROL_FLAG, RTF_TRQL, 0 }, + { "trqr", CONTROL_FLAG, RTF_TRQR, 0 }, + { "trrh", CONTROL_VALUE, RTF_TRRH, 0 }, + { "trshdng", CONTROL_VALUE, RTF_TRSHDNG, 0 }, + { "trspdb", CONTROL_VALUE, RTF_TRSPDB, 0 }, + { "trspdfb", CONTROL_VALUE, RTF_TRSPDFB, 0 }, + { "trspdfl", CONTROL_VALUE, RTF_TRSPDFL, 0 }, + { "trspdfr", CONTROL_VALUE, RTF_TRSPDFR, 0 }, + { "trspdft", CONTROL_VALUE, RTF_TRSPDFT, 0 }, + { "trspdl", CONTROL_VALUE, RTF_TRSPDL, 0 }, + { "trspdr", CONTROL_VALUE, RTF_TRSPDR, 0 }, + { "trspdt", CONTROL_VALUE, RTF_TRSPDT, 0 }, + { "trspob", CONTROL_VALUE, RTF_TRSPOB, 0 }, + { "trspofb", CONTROL_VALUE, RTF_TRSPOFB, 0 }, + { "trspofl", CONTROL_VALUE, RTF_TRSPOFL, 0 }, + { "trspofr", CONTROL_VALUE, RTF_TRSPOFR, 0 }, + { "trspoft", CONTROL_VALUE, RTF_TRSPOFT, 0 }, + { "trspol", CONTROL_VALUE, RTF_TRSPOL, 0 }, + { "trspor", CONTROL_VALUE, RTF_TRSPOR, 0 }, + { "trspot", CONTROL_VALUE, RTF_TRSPOT, 0 }, + { "truncatefontheight", CONTROL_FLAG, RTF_TRUNCATEFONTHEIGHT, 0 }, + { "truncex", CONTROL_FLAG, RTF_TRUNCEX, 0 }, + { "trwWidthA", CONTROL_VALUE, RTF_TRWWIDTHA, 0 }, + { "trwWidthB", CONTROL_VALUE, RTF_TRWWIDTHB, 0 }, + { "trwWidth", CONTROL_VALUE, RTF_TRWWIDTH, 0 }, + { "ts", CONTROL_VALUE, RTF_TS, 0 }, + { "tsbgbdiag", CONTROL_FLAG, RTF_TSBGBDIAG, 0 }, + { "tsbgcross", CONTROL_FLAG, RTF_TSBGCROSS, 0 }, + { "tsbgdcross", CONTROL_FLAG, RTF_TSBGDCROSS, 0 }, + { "tsbgdkbdiag", CONTROL_FLAG, RTF_TSBGDKBDIAG, 0 }, + { "tsbgdkcross", CONTROL_FLAG, RTF_TSBGDKCROSS, 0 }, + { "tsbgdkdcross", CONTROL_FLAG, RTF_TSBGDKDCROSS, 0 }, + { "tsbgdkfdiag", CONTROL_FLAG, RTF_TSBGDKFDIAG, 0 }, + { "tsbgdkhor", CONTROL_FLAG, RTF_TSBGDKHOR, 0 }, + { "tsbgdkvert", CONTROL_FLAG, RTF_TSBGDKVERT, 0 }, + { "tsbgfdiag", CONTROL_FLAG, RTF_TSBGFDIAG, 0 }, + { "tsbghoriz", CONTROL_FLAG, RTF_TSBGHORIZ, 0 }, + { "tsbgvert", CONTROL_FLAG, RTF_TSBGVERT, 0 }, + { "tsbrdrb", CONTROL_FLAG, RTF_TSBRDRB, 0 }, + { "tsbrdrdgl", CONTROL_FLAG, RTF_TSBRDRDGL, 0 }, + { "tsbrdrdgr", CONTROL_FLAG, RTF_TSBRDRDGR, 0 }, + { "tsbrdrh", CONTROL_FLAG, RTF_TSBRDRH, 0 }, + { "tsbrdrl", CONTROL_FLAG, RTF_TSBRDRL, 0 }, + { "tsbrdrr", CONTROL_FLAG, RTF_TSBRDRR, 0 }, + { "tsbrdrt", CONTROL_FLAG, RTF_TSBRDRT, 0 }, + { "tsbrdrv", CONTROL_FLAG, RTF_TSBRDRV, 0 }, + { "tscbandhorzeven", CONTROL_FLAG, RTF_TSCBANDHORZEVEN, 0 }, + { "tscbandhorzodd", CONTROL_FLAG, RTF_TSCBANDHORZODD, 0 }, + { "tscbandsh", CONTROL_VALUE, RTF_TSCBANDSH, 0 }, + { "tscbandsv", CONTROL_VALUE, RTF_TSCBANDSV, 0 }, + { "tscbandverteven", CONTROL_FLAG, RTF_TSCBANDVERTEVEN, 0 }, + { "tscbandvertodd", CONTROL_FLAG, RTF_TSCBANDVERTODD, 0 }, + { "tscellcbpat", CONTROL_VALUE, RTF_TSCELLCBPAT, 0 }, + { "tscellcfpat", CONTROL_VALUE, RTF_TSCELLCFPAT, 0 }, + { "tscellpaddb", CONTROL_VALUE, RTF_TSCELLPADDB, 0 }, + { "tscellpaddfb", CONTROL_VALUE, RTF_TSCELLPADDFB, 0 }, + { "tscellpaddfl", CONTROL_VALUE, RTF_TSCELLPADDFL, 0 }, + { "tscellpaddfr", CONTROL_VALUE, RTF_TSCELLPADDFR, 0 }, + { "tscellpaddft", CONTROL_VALUE, RTF_TSCELLPADDFT, 0 }, + { "tscellpaddl", CONTROL_VALUE, RTF_TSCELLPADDL, 0 }, + { "tscellpaddr", CONTROL_VALUE, RTF_TSCELLPADDR, 0 }, + { "tscellpaddt", CONTROL_VALUE, RTF_TSCELLPADDT, 0 }, + { "tscellpct", CONTROL_VALUE, RTF_TSCELLPCT, 0 }, + { "tscellwidth", CONTROL_VALUE, RTF_TSCELLWIDTH, 0 }, + { "tscellwidthfts", CONTROL_VALUE, RTF_TSCELLWIDTHFTS, 0 }, + { "tscfirstcol", CONTROL_FLAG, RTF_TSCFIRSTCOL, 0 }, + { "tscfirstrow", CONTROL_FLAG, RTF_TSCFIRSTROW, 0 }, + { "tsclastcol", CONTROL_FLAG, RTF_TSCLASTCOL, 0 }, + { "tsclastrow", CONTROL_FLAG, RTF_TSCLASTROW, 0 }, + { "tscnecell", CONTROL_FLAG, RTF_TSCNECELL, 0 }, + { "tscnwcell", CONTROL_FLAG, RTF_TSCNWCELL, 0 }, + { "tscsecell", CONTROL_FLAG, RTF_TSCSECELL, 0 }, + { "tscswcell", CONTROL_FLAG, RTF_TSCSWCELL, 0 }, + { "tsd", CONTROL_FLAG, RTF_TSD, 0 }, + { "tsnowrap", CONTROL_FLAG, RTF_TSNOWRAP, 0 }, + { "tsrowd", CONTROL_FLAG, RTF_TSROWD, 0 }, + { "tsvertalb", CONTROL_FLAG, RTF_TSVERTALB, 0 }, + { "tsvertalc", CONTROL_FLAG, RTF_TSVERTALC, 0 }, + { "tsvertalt", CONTROL_FLAG, RTF_TSVERTALT, 0 }, + { "twoinone", CONTROL_VALUE, RTF_TWOINONE, 0 }, + { "twoonone", CONTROL_FLAG, RTF_TWOONONE, 0 }, + { "tx", CONTROL_VALUE, RTF_TX, 0 }, + { "txbxtwalways", CONTROL_FLAG, RTF_TXBXTWALWAYS, 0 }, + { "txbxtwfirst", CONTROL_FLAG, RTF_TXBXTWFIRST, 0 }, + { "txbxtwfirstlast", CONTROL_FLAG, RTF_TXBXTWFIRSTLAST, 0 }, + { "txbxtwlast", CONTROL_FLAG, RTF_TXBXTWLAST, 0 }, + { "txbxtwno", CONTROL_FLAG, RTF_TXBXTWNO, 0 }, + { "txe", CONTROL_DESTINATION, RTF_TXE, 0 }, + { "u", CONTROL_VALUE, RTF_U, 0 }, + { "uc", CONTROL_VALUE, RTF_UC, 1 }, + { "ud", CONTROL_DESTINATION, RTF_UD, 0 }, + { "ul", CONTROL_TOGGLE, RTF_UL, 1 }, + { "ulc", CONTROL_VALUE, RTF_ULC, 0 }, + { "uld", CONTROL_FLAG, RTF_ULD, 0 }, + { "uldash", CONTROL_TOGGLE, RTF_ULDASH, 1 }, + { "uldashd", CONTROL_TOGGLE, RTF_ULDASHD, 1 }, + { "uldashdd", CONTROL_TOGGLE, RTF_ULDASHDD, 1 }, + { "uldb", CONTROL_TOGGLE, RTF_ULDB, 1 }, + { "ulhair", CONTROL_TOGGLE, RTF_ULHAIR, 1 }, + { "ulhwave", CONTROL_TOGGLE, RTF_ULHWAVE, 1 }, + { "ulldash", CONTROL_TOGGLE, RTF_ULLDASH, 1 }, + { "ulnone", CONTROL_FLAG, RTF_ULNONE, 0 }, + { "ulth", CONTROL_TOGGLE, RTF_ULTH, 1 }, + { "ulthd", CONTROL_TOGGLE, RTF_ULTHD, 1 }, + { "ulthdash", CONTROL_TOGGLE, RTF_ULTHDASH, 1 }, + { "ulthdashd", CONTROL_TOGGLE, RTF_ULTHDASHD, 1 }, + { "ulthdashdd", CONTROL_TOGGLE, RTF_ULTHDASHDD, 1 }, + { "ulthldash", CONTROL_TOGGLE, RTF_ULTHLDASH, 1 }, + { "ululdbwave", CONTROL_TOGGLE, RTF_ULULDBWAVE, 1 }, + { "ulw", CONTROL_FLAG, RTF_ULW, 0 }, + { "ulwave", CONTROL_TOGGLE, RTF_ULWAVE, 1 }, + { "up", CONTROL_VALUE, RTF_UP, 6 }, + { "upr", CONTROL_DESTINATION, RTF_UPR, 0 }, + { "urtf", CONTROL_VALUE, RTF_URTF, 0 }, + { "useltbaln", CONTROL_FLAG, RTF_USELTBALN, 0 }, + { "usenormstyforlist", CONTROL_FLAG, RTF_USENORMSTYFORLIST, 0 }, + { "userprops", CONTROL_DESTINATION, RTF_USERPROPS, 0 }, + { "usexform", CONTROL_FLAG, RTF_USEXFORM, 0 }, + { "utinl", CONTROL_FLAG, RTF_UTINL, 0 }, + { "v", CONTROL_TOGGLE, RTF_V, 1 }, + { "validatexml", CONTROL_VALUE, RTF_VALIDATEXML, 0 }, + { "vern", CONTROL_VALUE, RTF_VERN, 0 }, + { "version", CONTROL_VALUE, RTF_VERSION, 0 }, + { "vertal", CONTROL_FLAG, RTF_VERTAL, 0 }, + { "vertalb", CONTROL_FLAG, RTF_VERTALB, 0 }, + { "vertalc", CONTROL_FLAG, RTF_VERTALC, 0 }, + { "vertalj", CONTROL_FLAG, RTF_VERTALJ, 0 }, + { "vertalt", CONTROL_FLAG, RTF_VERTALT, 0 }, + { "vertdoc", CONTROL_FLAG, RTF_VERTDOC, 0 }, + { "vertsect", CONTROL_FLAG, RTF_VERTSECT, 0 }, + { "viewbksp", CONTROL_VALUE, RTF_VIEWBKSP, 0 }, + { "viewkind", CONTROL_VALUE, RTF_VIEWKIND, 0 }, + { "viewnobound", CONTROL_FLAG, RTF_VIEWNOBOUND, 0 }, + { "viewscale", CONTROL_VALUE, RTF_VIEWSCALE, 100 }, + { "viewzk", CONTROL_VALUE, RTF_VIEWZK, 0 }, + { "wbitmap", CONTROL_VALUE, RTF_WBITMAP, 0 }, + { "wbmbitspixel", CONTROL_VALUE, RTF_WBMBITSPIXEL, 1 }, + { "wbmplanes", CONTROL_VALUE, RTF_WBMPLANES, 0 }, + { "wbmwidthbyte", CONTROL_VALUE, RTF_WBMWIDTHBYTE, 0 }, + { "webhidden", CONTROL_FLAG, RTF_WEBHIDDEN, 0 }, + { "wgrffmtfilter", CONTROL_DESTINATION, RTF_WGRFFMTFILTER, 0 }, + { "widctlpar", CONTROL_FLAG, RTF_WIDCTLPAR, 0 }, + { "widowctrl", CONTROL_FLAG, RTF_WIDOWCTRL, 0 }, + { "windowcaption", CONTROL_DESTINATION, RTF_WINDOWCAPTION, 0 }, + { "wmetafile", CONTROL_VALUE, RTF_WMETAFILE, 1 }, + { "wpeqn", CONTROL_FLAG, RTF_WPEQN, 0 }, + { "wpjst", CONTROL_FLAG, RTF_WPJST, 0 }, + { "wpsp", CONTROL_FLAG, RTF_WPSP, 0 }, + { "wraparound", CONTROL_FLAG, RTF_WRAPAROUND, 0 }, + { "wrapdefault", CONTROL_FLAG, RTF_WRAPDEFAULT, 0 }, + { "wrapthrough", CONTROL_FLAG, RTF_WRAPTHROUGH, 0 }, + { "wraptight", CONTROL_FLAG, RTF_WRAPTIGHT, 0 }, + { "wraptrsp", CONTROL_FLAG, RTF_WRAPTRSP, 0 }, + { "writereservation", CONTROL_DESTINATION, RTF_WRITERESERVATION, 0 }, + { "writereservhash", CONTROL_DESTINATION, RTF_WRITERESERVHASH, 0 }, + { "wrppunct", CONTROL_FLAG, RTF_WRPPUNCT, 0 }, + { "xe", CONTROL_DESTINATION, RTF_XE, 0 }, + { "xef", CONTROL_VALUE, RTF_XEF, 0 }, + { "xform", CONTROL_DESTINATION, RTF_XFORM, 0 }, + { "xmlattr", CONTROL_FLAG, RTF_XMLATTR, 0 }, + { "xmlattrname", CONTROL_DESTINATION, RTF_XMLATTRNAME, 0 }, + { "xmlattrns", CONTROL_VALUE, RTF_XMLATTRNS, 0 }, + { "xmlattrvalue", CONTROL_DESTINATION, RTF_XMLATTRVALUE, 0 }, + { "xmlclose", CONTROL_DESTINATION, RTF_XMLCLOSE, 0 }, + { "xmlname", CONTROL_DESTINATION, RTF_XMLNAME, 0 }, + { "xmlns", CONTROL_VALUE, RTF_XMLNS, 0 }, + { "xmlnstbl", CONTROL_DESTINATION, RTF_XMLNSTBL, 0 }, + { "xmlopen", CONTROL_DESTINATION, RTF_XMLOPEN, 0 }, + { "xmlsdttcell", CONTROL_FLAG, RTF_XMLSDTTCELL, 0 }, + { "xmlsdttpara", CONTROL_FLAG, RTF_XMLSDTTPARA, 0 }, + { "xmlsdttregular", CONTROL_FLAG, RTF_XMLSDTTREGULAR, 0 }, + { "xmlsdttrow", CONTROL_FLAG, RTF_XMLSDTTROW, 0 }, + { "xmlsdttunknown", CONTROL_FLAG, RTF_XMLSDTTUNKNOWN, 0 }, + { "yr", CONTROL_VALUE, RTF_YR, 0 }, + { "yts", CONTROL_VALUE, RTF_YTS, 0 }, + { "yxe", CONTROL_FLAG, RTF_YXE, 0 }, + { "zwbo", CONTROL_SYMBOL, RTF_ZWBO, 0 }, + { "zwj", CONTROL_SYMBOL, RTF_ZWJ, 0 }, + { "zwnbo", CONTROL_SYMBOL, RTF_ZWNBO, 0 }, + { "zwnj", CONTROL_SYMBOL, RTF_ZWNJ, 0 }, + { "flymaincnt", CONTROL_DESTINATION, RTF_FLYMAINCNT, 0 }, + { "flyvert", CONTROL_VALUE, RTF_FLYVERT, 0 }, + { "flyhorz", CONTROL_VALUE, RTF_FLYHORZ, 0 }, + { "flyanchor", CONTROL_VALUE, RTF_FLYANCHOR, 0 }, +}; +int nRTFControlWords = SAL_N_ELEMENTS(aRTFControlWords); + +RTFMathSymbol const aRTFMathControlWords[] = { + // eKeyword nToken eDestination + { RTF_MOMATH, M_TOKEN(oMath), Destination::MOMATH }, + { RTF_MF, M_TOKEN(f), Destination::MF }, + { RTF_MFPR, M_TOKEN(fPr), Destination::MFPR }, + { RTF_MCTRLPR, M_TOKEN(ctrlPr), Destination::MCTRLPR }, + { RTF_MNUM, M_TOKEN(num), Destination::MNUM }, + { RTF_MDEN, M_TOKEN(den), Destination::MDEN }, + { RTF_MACC, M_TOKEN(acc), Destination::MACC }, + { RTF_MACCPR, M_TOKEN(accPr), Destination::MACCPR }, + { RTF_MBAR, M_TOKEN(bar), Destination::MBAR }, + { RTF_MBARPR, M_TOKEN(barPr), Destination::MBARPR }, + { RTF_ME, M_TOKEN(e), Destination::ME }, + { RTF_MD, M_TOKEN(d), Destination::MD }, + { RTF_MDPR, M_TOKEN(dPr), Destination::MDPR }, + { RTF_MFUNC, M_TOKEN(func), Destination::MFUNC }, + { RTF_MFUNCPR, M_TOKEN(funcPr), Destination::MFUNCPR }, + { RTF_MFNAME, M_TOKEN(fName), Destination::MFNAME }, + { RTF_MLIMLOW, M_TOKEN(limLow), Destination::MLIMLOW }, + { RTF_MLIMLOWPR, M_TOKEN(limLowPr), Destination::MLIMLOWPR }, + { RTF_MLIM, M_TOKEN(lim), Destination::MLIM }, + { RTF_MM, M_TOKEN(m), Destination::MM }, + { RTF_MMPR, M_TOKEN(mPr), Destination::MMPR }, + { RTF_MMR, M_TOKEN(mr), Destination::MMR }, + { RTF_MNARY, M_TOKEN(nary), Destination::MNARY }, + { RTF_MNARYPR, M_TOKEN(naryPr), Destination::MNARYPR }, + { RTF_MSUB, M_TOKEN(sub), Destination::MSUB }, + { RTF_MSUP, M_TOKEN(sup), Destination::MSUP }, + { RTF_MLIMUPP, M_TOKEN(limUpp), Destination::MLIMUPP }, + { RTF_MLIMUPPPR, M_TOKEN(limUppPr), Destination::MLIMUPPPR }, + { RTF_MGROUPCHR, M_TOKEN(groupChr), Destination::MGROUPCHR }, + { RTF_MGROUPCHRPR, M_TOKEN(groupChrPr), Destination::MGROUPCHRPR }, + { RTF_MBORDERBOX, M_TOKEN(borderBox), Destination::MBORDERBOX }, + { RTF_MBORDERBOXPR, M_TOKEN(borderBoxPr), Destination::MBORDERBOXPR }, + { RTF_MRAD, M_TOKEN(rad), Destination::MRAD }, + { RTF_MRADPR, M_TOKEN(radPr), Destination::MRADPR }, + { RTF_MDEG, M_TOKEN(deg), Destination::MDEG }, + { RTF_MSSUB, M_TOKEN(sSub), Destination::MSSUB }, + { RTF_MSSUBPR, M_TOKEN(sSubPr), Destination::MSSUBPR }, + { RTF_MSSUP, M_TOKEN(sSup), Destination::MSSUP }, + { RTF_MSSUPPR, M_TOKEN(sSupPr), Destination::MSSUPPR }, + { RTF_MSSUBSUP, M_TOKEN(sSubSup), Destination::MSSUBSUP }, + { RTF_MSSUBSUPPR, M_TOKEN(sSubSupPr), Destination::MSSUBSUPPR }, + { RTF_MSPRE, M_TOKEN(sPre), Destination::MSPRE }, + { RTF_MSPREPR, M_TOKEN(sPrePr), Destination::MSPREPR }, + { RTF_MBOX, M_TOKEN(box), Destination::MBOX }, + { RTF_MEQARR, M_TOKEN(eqArr), Destination::MEQARR }, +}; +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..2b350e552 --- /dev/null +++ b/writerfilter/source/rtftok/rtfcontrolwords.hxx @@ -0,0 +1,2056 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFCONTROLWORDS_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFCONTROLWORDS_HXX + +namespace writerfilter +{ +namespace 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, +}; + +enum RTFKeyword +{ + RTF_invalid = -1, + RTF_HEXCHAR, + RTF_OPTHYPH, + RTF_IGNORE, + RTF_SUBENTRY, + RTF_BACKSLASH, + RTF_NOBRKHYPH, + RTF_LBRACE, + RTF_FORMULA, + RTF_RBRACE, + RTF_NOBREAK, + RTF_AB, + RTF_ABSH, + RTF_ABSLOCK, + RTF_ABSNOOVRLP, + RTF_ABSW, + RTF_ACAPS, + RTF_ACCCIRCLE, + RTF_ACCCOMMA, + RTF_ACCDOT, + RTF_ACCNONE, + RTF_ACCUNDERDOT, + RTF_ACF, + RTF_ADEFF, + RTF_ADDITIVE, + RTF_ADEFLANG, + RTF_ADJUSTRIGHT, + RTF_ADN, + RTF_AENDDOC, + RTF_AENDNOTES, + RTF_AEXPND, + RTF_AF, + RTF_AFELEV, + RTF_AFS, + RTF_AFTNBJ, + RTF_AFTNCN, + RTF_AFTNNALC, + RTF_AFTNNAR, + RTF_AFTNNAUC, + RTF_AFTNNCHI, + RTF_AFTNNCHOSUNG, + RTF_AFTNNCNUM, + RTF_AFTNNDBAR, + RTF_AFTNNDBNUM, + RTF_AFTNNDBNUMD, + RTF_AFTNNDBNUMK, + RTF_AFTNNDBNUMT, + RTF_AFTNNGANADA, + RTF_AFTNNGBNUM, + RTF_AFTNNGBNUMD, + RTF_AFTNNGBNUMK, + RTF_AFTNNGBNUML, + RTF_AFTNNRLC, + RTF_AFTNNRUC, + RTF_AFTNNZODIAC, + RTF_AFTNNZODIACD, + RTF_AFTNNZODIACL, + RTF_AFTNRESTART, + RTF_AFTNRSTCONT, + RTF_AFTNSEP, + RTF_AFTNSEPC, + RTF_AFTNSTART, + RTF_AFTNTJ, + RTF_AI, + RTF_ALANG, + RTF_ALLOWFIELDENDSEL, + RTF_ALLPROT, + RTF_ALNTBLIND, + RTF_ALT, + RTF_ANIMTEXT, + RTF_ANNOTATION, + RTF_ANNOTPROT, + RTF_ANSI, + RTF_ANSICPG, + RTF_AOUTL, + RTF_APPLYBRKRULES, + RTF_ASCAPS, + RTF_ASHAD, + RTF_ASIANBRKRULE, + RTF_ASPALPHA, + RTF_ASPNUM, + RTF_ASTRIKE, + RTF_ATNAUTHOR, + RTF_ATNDATE, + RTF_ATNICN, + RTF_ATNID, + RTF_ATNPARENT, + RTF_ATNREF, + RTF_ATNTIME, + RTF_ATRFEND, + RTF_ATRFSTART, + RTF_AUL, + RTF_AULD, + RTF_AULDB, + RTF_AULNONE, + RTF_AULW, + RTF_AUP, + RTF_AUTHOR, + RTF_AUTOFMTOVERRIDE, + RTF_B, + RTF_BACKGROUND, + RTF_BDBFHDR, + RTF_BDRRLSWSIX, + RTF_BGBDIAG, + RTF_BGCROSS, + RTF_BGDCROSS, + RTF_BGDKBDIAG, + RTF_BGDKCROSS, + RTF_BGDKDCROSS, + RTF_BGDKFDIAG, + RTF_BGDKHORIZ, + RTF_BGDKVERT, + RTF_BGFDIAG, + RTF_BGHORIZ, + RTF_BGVERT, + RTF_BIN, + RTF_BINFSXN, + RTF_BINSXN, + RTF_BKMKCOLF, + RTF_BKMKCOLL, + RTF_BKMKEND, + RTF_BKMKPUB, + RTF_BKMKSTART, + RTF_BLIPTAG, + RTF_BLIPUID, + RTF_BLIPUPI, + RTF_BLUE, + RTF_BOOKFOLD, + RTF_BOOKFOLDREV, + RTF_BOOKFOLDSHEETS, + RTF_BOX, + RTF_BRDRART, + RTF_BRDRB, + RTF_BRDRBAR, + RTF_BRDRBTW, + RTF_BRDRCF, + RTF_BRDRDASH, + RTF_BRDRDASHD, + RTF_BRDRDASHDD, + RTF_BRDRDASHDOTSTR, + RTF_BRDRDASHSM, + RTF_BRDRDB, + RTF_BRDRDOT, + RTF_BRDREMBOSS, + RTF_BRDRENGRAVE, + RTF_BRDRFRAME, + RTF_BRDRHAIR, + RTF_BRDRINSET, + RTF_BRDRL, + RTF_BRDRNIL, + RTF_BRDRNONE, + RTF_BRDROUTSET, + RTF_BRDRR, + RTF_BRDRS, + RTF_BRDRSH, + RTF_BRDRT, + RTF_BRDRTBL, + RTF_BRDRTH, + RTF_BRDRTHTNLG, + RTF_BRDRTHTNMG, + RTF_BRDRTHTNSG, + RTF_BRDRTNTHLG, + RTF_BRDRTNTHMG, + RTF_BRDRTNTHSG, + RTF_BRDRTNTHTNLG, + RTF_BRDRTNTHTNMG, + RTF_BRDRTNTHTNSG, + RTF_BRDRTRIPLE, + RTF_BRDRW, + RTF_BRDRWAVY, + RTF_BRDRWAVYDB, + RTF_BRKFRM, + RTF_BRSP, + RTF_BULLET, + RTF_BUPTIM, + RTF_BXE, + RTF_CACCENTFIVE, + RTF_CACCENTFOUR, + RTF_CACCENTONE, + RTF_CACCENTSIX, + RTF_CACCENTTHREE, + RTF_CACCENTTWO, + RTF_CACHEDCOLBAL, + RTF_CAPS, + RTF_CATEGORY, + RTF_CB, + RTF_CBACKGROUNDONE, + RTF_CBACKGROUNDTWO, + RTF_CBPAT, + RTF_CCHS, + RTF_CELL, + RTF_CELLX, + RTF_CF, + RTF_CFOLLOWEDHYPERLINK, + RTF_CFPAT, + RTF_CGRID, + RTF_CHARRSID, + RTF_CHARSCALEX, + RTF_CHATN, + RTF_CHBGBDIAG, + RTF_CHBGCROSS, + RTF_CHBGDCROSS, + RTF_CHBGDKBDIAG, + RTF_CHBGDKCROSS, + RTF_CHBGDKDCROSS, + RTF_CHBGDKFDIAG, + RTF_CHBGDKHORIZ, + RTF_CHBGDKVERT, + RTF_CHBGFDIAG, + RTF_CHBGHORIZ, + RTF_CHBGVERT, + RTF_CHBRDR, + RTF_CHCBPAT, + RTF_CHCFPAT, + RTF_CHDATE, + RTF_CHDPA, + RTF_CHDPL, + RTF_CHFTN, + RTF_CHFTNSEP, + RTF_CHFTNSEPC, + RTF_CHPGN, + RTF_CHHRES, + RTF_CHSHDNG, + RTF_CHTIME, + RTF_CHYPERLINK, + RTF_CLBGBDIAG, + RTF_CLBGCROSS, + RTF_CLBGDCROSS, + RTF_CLBGDKBDIAG, + RTF_CLBGDKCROSS, + RTF_CLBGDKDCROSS, + RTF_CLBGDKFDIAG, + RTF_CLBGDKHOR, + RTF_CLBGDKVERT, + RTF_CLBGFDIAG, + RTF_CLBGHORIZ, + RTF_CLBGVERT, + RTF_CLBRDRB, + RTF_CLBRDRL, + RTF_CLBRDRR, + RTF_CLBRDRT, + RTF_CLCBPAT, + RTF_CLCBPATRAW, + RTF_CLCFPAT, + RTF_CLCFPATRAW, + RTF_CLDEL, + RTF_CLDELAUTH, + RTF_CLDELDTTM, + RTF_CLDGLL, + RTF_CLDGLU, + RTF_CLFITTEXT, + RTF_CLFTSWIDTH, + RTF_CLHIDEMARK, + RTF_CLINS, + RTF_CLINSAUTH, + RTF_CLINSDTTM, + RTF_CLMGF, + RTF_CLMRG, + RTF_CLMRGD, + RTF_CLMRGDAUTH, + RTF_CLMRGDDTTM, + RTF_CLMRGDR, + RTF_CLNOWRAP, + RTF_CLPADB, + RTF_CLPADFB, + RTF_CLPADFL, + RTF_CLPADFR, + RTF_CLPADFT, + RTF_CLPADL, + RTF_CLPADR, + RTF_CLPADT, + RTF_CLSPB, + RTF_CLSPFB, + RTF_CLSPFL, + RTF_CLSPFR, + RTF_CLSPFT, + RTF_CLSPL, + RTF_CLSPR, + RTF_CLSPT, + RTF_CLSHDNG, + RTF_CLSHDNGRAW, + RTF_CLSHDRAWNIL, + RTF_CLSPLIT, + RTF_CLSPLITR, + RTF_CLTXBTLR, + RTF_CLTXLRTB, + RTF_CLTXLRTBV, + RTF_CLTXTBRL, + RTF_CLTXTBRLV, + RTF_CLVERTALB, + RTF_CLVERTALC, + RTF_CLVERTALT, + RTF_CLVMGF, + RTF_CLVMRG, + RTF_CLWWIDTH, + RTF_CMAINDARKONE, + RTF_CMAINDARKTWO, + RTF_CMAINLIGHTONE, + RTF_CMAINLIGHTTWO, + RTF_COLLAPSED, + RTF_COLNO, + RTF_COLORSCHEMEMAPPING, + RTF_COLORTBL, + RTF_COLS, + RTF_COLSR, + RTF_COLSX, + RTF_COLUMN, + RTF_COLW, + RTF_COMMENT, + RTF_COMPANY, + RTF_CONTEXTUALSPACE, + RTF_CPG, + RTF_CRAUTH, + RTF_CRDATE, + RTF_CREATIM, + RTF_CS, + RTF_CSHADE, + RTF_CTEXTONE, + RTF_CTEXTTWO, + RTF_CTINT, + RTF_CTRL, + RTF_CTS, + RTF_CUFI, + RTF_CULI, + RTF_CURI, + RTF_CVMME, + RTF_DATAFIELD, + RTF_DATASTORE, + RTF_DATE, + RTF_DBCH, + RTF_DEFCHP, + RTF_DEFF, + RTF_DEFFORMAT, + RTF_DEFLANG, + RTF_DEFLANGFE, + RTF_DEFPAP, + RTF_DEFSHP, + RTF_DEFTAB, + RTF_DELETED, + RTF_DELRSID, + RTF_DFRAUTH, + RTF_DFRDATE, + RTF_DFRMTXTX, + RTF_DFRMTXTY, + RTF_DFRSTART, + RTF_DFRSTOP, + RTF_DFRXST, + RTF_DGHORIGIN, + RTF_DGHSHOW, + RTF_DGHSPACE, + RTF_DGMARGIN, + RTF_DGSNAP, + RTF_DGVORIGIN, + RTF_DGVSHOW, + RTF_DGVSPACE, + RTF_DIBITMAP, + RTF_DISABLED, + RTF_DN, + RTF_DNTBLNSBDB, + RTF_DO, + RTF_DOBXCOLUMN, + RTF_DOBXMARGIN, + RTF_DOBXPAGE, + RTF_DOBYMARGIN, + RTF_DOBYPAGE, + RTF_DOBYPARA, + RTF_DOCCOMM, + RTF_DOCTEMP, + RTF_DOCTYPE, + RTF_DOCVAR, + RTF_DODHGT, + RTF_DOLOCK, + RTF_DONOTEMBEDLINGDATA, + RTF_DONOTEMBEDSYSFONT, + RTF_DONOTSHOWCOMMENTS, + RTF_DONOTSHOWINSDEL, + RTF_DONOTSHOWMARKUP, + RTF_DONOTSHOWPROPS, + RTF_DPAENDHOL, + RTF_DPAENDL, + RTF_DPAENDSOL, + RTF_DPAENDW, + RTF_DPARC, + RTF_DPARCFLIPX, + RTF_DPARCFLIPY, + RTF_DPASTARTHOL, + RTF_DPASTARTL, + RTF_DPASTARTSOL, + RTF_DPASTARTW, + RTF_DPCALLOUT, + RTF_DPCOA, + RTF_DPCOACCENT, + RTF_DPCOBESTFIT, + RTF_DPCOBORDER, + RTF_DPCODABS, + RTF_DPCODBOTTOM, + RTF_DPCODCENTER, + RTF_DPCODESCENT, + RTF_DPCODTOP, + RTF_DPCOLENGTH, + RTF_DPCOMINUSX, + RTF_DPCOMINUSY, + RTF_DPCOOFFSET, + RTF_DPCOSMARTA, + RTF_DPCOTDOUBLE, + RTF_DPCOTRIGHT, + RTF_DPCOTSINGLE, + RTF_DPCOTTRIPLE, + RTF_DPCOUNT, + RTF_DPELLIPSE, + RTF_DPENDGROUP, + RTF_DPFILLBGCB, + RTF_DPFILLBGCG, + RTF_DPFILLBGCR, + RTF_DPFILLBGGRAY, + RTF_DPFILLBGPAL, + RTF_DPFILLFGCB, + RTF_DPFILLFGCG, + RTF_DPFILLFGCR, + RTF_DPFILLFGGRAY, + RTF_DPFILLFGPAL, + RTF_DPFILLPAT, + RTF_DPGROUP, + RTF_DPLINE, + RTF_DPLINECOB, + RTF_DPLINECOG, + RTF_DPLINECOR, + RTF_DPLINEDADO, + RTF_DPLINEDADODO, + RTF_DPLINEDASH, + RTF_DPLINEDOT, + RTF_DPLINEGRAY, + RTF_DPLINEHOLLOW, + RTF_DPLINEPAL, + RTF_DPLINESOLID, + RTF_DPLINEW, + RTF_DPPOLYCOUNT, + RTF_DPPOLYGON, + RTF_DPPOLYLINE, + RTF_DPPTX, + RTF_DPPTY, + RTF_DPRECT, + RTF_DPROUNDR, + RTF_DPSHADOW, + RTF_DPSHADX, + RTF_DPSHADY, + RTF_DPTXBTLR, + RTF_DPTXBX, + RTF_DPTXBXMAR, + RTF_DPTXBXTEXT, + RTF_DPTXLRTB, + RTF_DPTXLRTBV, + RTF_DPTXTBRL, + RTF_DPTXTBRLV, + RTF_DPX, + RTF_DPXSIZE, + RTF_DPY, + RTF_DPYSIZE, + RTF_DROPCAPLI, + RTF_DROPCAPT, + RTF_DS, + RTF_DXFRTEXT, + RTF_DY, + RTF_EBCEND, + RTF_EBCSTART, + RTF_EDMINS, + RTF_EMBO, + RTF_EMDASH, + RTF_EMFBLIP, + RTF_EMSPACE, + RTF_ENDASH, + RTF_ENDDOC, + RTF_ENDNHERE, + RTF_ENDNOTES, + RTF_ENFORCEPROT, + RTF_ENSPACE, + RTF_EXPND, + RTF_EXPNDTW, + RTF_EXPSHRTN, + RTF_F, + RTF_FAAUTO, + RTF_FACENTER, + RTF_FACINGP, + RTF_FACTOIDNAME, + RTF_FAFIXED, + RTF_FAHANG, + RTF_FALT, + RTF_FAROMAN, + RTF_FAVAR, + RTF_FBIAS, + RTF_FBIDI, + RTF_FBIDIS, + RTF_FBIMAJOR, + RTF_FBIMINOR, + RTF_FCHARS, + RTF_FCHARSET, + RTF_FCS, + RTF_FDBMAJOR, + RTF_FDBMINOR, + RTF_FDECOR, + RTF_FELNBRELEV, + RTF_FET, + RTF_FETCH, + RTF_FFDEFRES, + RTF_FFDEFTEXT, + RTF_FFENTRYMCR, + RTF_FFEXITMCR, + RTF_FFFORMAT, + RTF_FFHASLISTBOX, + RTF_FFHELPTEXT, + RTF_FFHPS, + RTF_FFL, + RTF_FFMAXLEN, + RTF_FFNAME, + RTF_FFOWNHELP, + RTF_FFOWNSTAT, + RTF_FFPROT, + RTF_FFRECALC, + RTF_FFRES, + RTF_FFSIZE, + RTF_FFSTATTEXT, + RTF_FFTYPE, + RTF_FFTYPETXT, + RTF_FHIMAJOR, + RTF_FHIMINOR, + RTF_FI, + RTF_FID, + RTF_FIELD, + RTF_FILE, + RTF_FILETBL, + RTF_FITTEXT, + RTF_FJGOTHIC, + RTF_FJMINCHOU, + RTF_FLDALT, + RTF_FLDDIRTY, + RTF_FLDEDIT, + RTF_FLDINST, + RTF_FLDLOCK, + RTF_FLDPRIV, + RTF_FLDRSLT, + RTF_FLDTYPE, + RTF_FLOMAJOR, + RTF_FLOMINOR, + RTF_FMODERN, + RTF_FN, + RTF_FNAME, + RTF_FNETWORK, + RTF_FNIL, + RTF_FNONFILESYS, + RTF_FONTEMB, + RTF_FONTFILE, + RTF_FONTTBL, + RTF_FOOTER, + RTF_FOOTERF, + RTF_FOOTERL, + RTF_FOOTERR, + RTF_FOOTERY, + RTF_FOOTNOTE, + RTF_FORCEUPGRADE, + RTF_FORMDISP, + RTF_FORMFIELD, + RTF_FORMPROT, + RTF_FORMSHADE, + RTF_FOSNUM, + RTF_FPRQ, + RTF_FRACWIDTH, + RTF_FRELATIVE, + RTF_FRMTXBTLR, + RTF_FRMTXLRTB, + RTF_FRMTXLRTBV, + RTF_FRMTXTBRL, + RTF_FRMTXTBRLV, + RTF_FROMAN, + RTF_FROMHTML, + RTF_FROMTEXT, + RTF_FS, + RTF_FSCRIPT, + RTF_FSWISS, + RTF_FTECH, + RTF_FTNALT, + RTF_FTNBJ, + RTF_FTNCN, + RTF_FTNIL, + RTF_FTNLYTWNINE, + RTF_FTNNALC, + RTF_FTNNAR, + RTF_FTNNAUC, + RTF_FTNNCHI, + RTF_FTNNCHOSUNG, + RTF_FTNNCNUM, + RTF_FTNNDBAR, + RTF_FTNNDBNUM, + RTF_FTNNDBNUMD, + RTF_FTNNDBNUMK, + RTF_FTNNDBNUMT, + RTF_FTNNGANADA, + RTF_FTNNGBNUM, + RTF_FTNNGBNUMD, + RTF_FTNNGBNUMK, + RTF_FTNNGBNUML, + RTF_FTNNRLC, + RTF_FTNNRUC, + RTF_FTNNZODIAC, + RTF_FTNNZODIACD, + RTF_FTNNZODIACL, + RTF_FTNRESTART, + RTF_FTNRSTCONT, + RTF_FTNRSTPG, + RTF_FTNSEP, + RTF_FTNSEPC, + RTF_FTNSTART, + RTF_FTNTJ, + RTF_FTTRUETYPE, + RTF_FVALIDDOS, + RTF_FVALIDHPFS, + RTF_FVALIDMAC, + RTF_FVALIDNTFS, + RTF_G, + RTF_GCW, + RTF_GENERATOR, + RTF_GREEN, + RTF_GRFDOCEVENTS, + RTF_GRIDTBL, + RTF_GUTTER, + RTF_GUTTERPRL, + RTF_GUTTERSXN, + RTF_HEADER, + RTF_HEADERF, + RTF_HEADERL, + RTF_HEADERR, + RTF_HEADERY, + RTF_HICH, + RTF_HIGHLIGHT, + RTF_HL, + RTF_HLFR, + RTF_HLINKBASE, + RTF_HLLOC, + RTF_HLSRC, + RTF_HORZDOC, + RTF_HORZSECT, + RTF_HORZVERT, + RTF_HR, + RTF_HRES, + RTF_HRULE, + RTF_HSV, + RTF_HTMAUTSP, + RTF_HTMLBASE, + RTF_HTMLRTF, + RTF_HTMLTAG, + RTF_HWELEV, + RTF_HYPHAUTO, + RTF_HYPHCAPS, + RTF_HYPHCONSEC, + RTF_HYPHHOTZ, + RTF_HYPHPAR, + RTF_I, + RTF_ID, + RTF_IGNOREMIXEDCONTENT, + RTF_ILFOMACATCLNUP, + RTF_ILVL, + RTF_IMPR, + RTF_INDMIRROR, + RTF_INDRLSWELEVEN, + RTF_INFO, + RTF_INSRSID, + RTF_INTBL, + RTF_IPGP, + RTF_IROWBAND, + RTF_IROW, + RTF_ITAP, + RTF_IXE, + RTF_JCOMPRESS, + RTF_JEXPAND, + RTF_JIS, + RTF_JPEGBLIP, + RTF_JSKSU, + RTF_KEEP, + RTF_KEEPN, + RTF_KERNING, + RTF_KEYCODE, + RTF_KEYWORDS, + RTF_KRNPRSNET, + RTF_KSULANG, + RTF_JCLISTTAB, + RTF_LANDSCAPE, + RTF_LANG, + RTF_LANGFE, + RTF_LANGFENP, + RTF_LANGNP, + RTF_LASTROW, + RTF_LATENTSTYLES, + RTF_LBR, + RTF_LCHARS, + RTF_LDBLQUOTE, + RTF_LEVEL, + RTF_LEVELFOLLOW, + RTF_LEVELINDENT, + RTF_LEVELJC, + RTF_LEVELJCN, + RTF_LEVELLEGAL, + RTF_LEVELNFC, + RTF_LEVELNFCN, + RTF_LEVELNORESTART, + RTF_LEVELNUMBERS, + RTF_LEVELOLD, + RTF_LEVELPICTURE, + RTF_LEVELPICTURENOSIZE, + RTF_LEVELPREV, + RTF_LEVELPREVSPACE, + RTF_LEVELSPACE, + RTF_LEVELSTARTAT, + RTF_LEVELTEMPLATEID, + RTF_LEVELTEXT, + RTF_LFOLEVEL, + RTF_LI, + RTF_LINE, + RTF_LINEBETCOL, + RTF_LINECONT, + RTF_LINEMOD, + RTF_LINEPPAGE, + RTF_LINERESTART, + RTF_LINESTART, + RTF_LINESTARTS, + RTF_LINEX, + RTF_LINKSELF, + RTF_LINKSTYLES, + RTF_LINKVAL, + RTF_LIN, + RTF_LISA, + RTF_LISB, + RTF_LIST, + RTF_LISTHYBRID, + RTF_LISTID, + RTF_LISTLEVEL, + RTF_LISTNAME, + RTF_LISTOVERRIDE, + RTF_LISTOVERRIDECOUNT, + RTF_LISTOVERRIDEFORMAT, + RTF_LISTOVERRIDESTARTAT, + RTF_LISTOVERRIDETABLE, + RTF_LISTPICTURE, + RTF_LISTRESTARTHDN, + RTF_LISTSIMPLE, + RTF_LISTSTYLEID, + RTF_LISTSTYLENAME, + RTF_LISTTABLE, + RTF_LISTTEMPLATEID, + RTF_LISTTEXT, + RTF_LNBRKRULE, + RTF_LNDSCPSXN, + RTF_LNONGRID, + RTF_LOCH, + RTF_LQUOTE, + RTF_LS, + RTF_LSDLOCKED, + RTF_LSDLOCKEDDEF, + RTF_LSDLOCKEDEXCEPT, + RTF_LSDPRIORITY, + RTF_LSDPRIORITYDEF, + RTF_LSDQFORMAT, + RTF_LSDQFORMATDEF, + RTF_LSDSEMIHIDDEN, + RTF_LSDSEMIHIDDENDEF, + RTF_LSDSTIMAX, + RTF_LSDUNHIDEUSED, + RTF_LSDUNHIDEUSEDDEF, + RTF_LTRCH, + RTF_LTRDOC, + RTF_LTRMARK, + RTF_LTRPAR, + RTF_LTRROW, + RTF_LTRSECT, + RTF_LVLTENTATIVE, + RTF_LYTCALCTBLWD, + RTF_LYTEXCTTP, + RTF_LYTPRTMET, + RTF_LYTTBLRTGR, + RTF_MAC, + RTF_MACC, + RTF_MACCPR, + RTF_MACPICT, + RTF_MAILMERGE, + RTF_MAKEBACKUP, + RTF_MALN, + RTF_MALNSCR, + RTF_MANAGER, + RTF_MARGB, + RTF_MARGBSXN, + RTF_MARGL, + RTF_MARGLSXN, + RTF_MARGMIRROR, + RTF_MARGMIRSXN, + RTF_MARGPR, + RTF_MARGR, + RTF_MARGRSXN, + RTF_MARGSZ, + RTF_MARGT, + RTF_MARGTSXN, + RTF_MBAR, + RTF_MBARPR, + RTF_MBASEJC, + RTF_MBEGCHR, + RTF_MBORDERBOX, + RTF_MBORDERBOXPR, + RTF_MBOX, + RTF_MBOXPR, + RTF_MBRK, + RTF_MBRKBIN, + RTF_MBRKBINSUB, + RTF_MCGP, + RTF_MCGPRULE, + RTF_MCHR, + RTF_MCOUNT, + RTF_MCSP, + RTF_MCTRLPR, + RTF_MD, + RTF_MDEFJC, + RTF_MDEG, + RTF_MDEGHIDE, + RTF_MDEN, + RTF_MDIFF, + RTF_MDIFFSTY, + RTF_MDISPDEF, + RTF_MDPR, + RTF_ME, + RTF_MENDCHR, + RTF_MEQARR, + RTF_MEQARRPR, + RTF_MF, + RTF_MFNAME, + RTF_MFPR, + RTF_MFUNC, + RTF_MFUNCPR, + RTF_MGROUPCHR, + RTF_MGROUPCHRPR, + RTF_MGROW, + RTF_MHIDEBOT, + RTF_MHIDELEFT, + RTF_MHIDERIGHT, + RTF_MHIDETOP, + RTF_MHTMLTAG, + RTF_MIN, + RTF_MINTERSP, + RTF_MINTLIM, + RTF_MINTRASP, + RTF_MJC, + RTF_MLIM, + RTF_MLIMLOC, + RTF_MLIMLOW, + RTF_MLIMLOWPR, + RTF_MLIMUPP, + RTF_MLIMUPPPR, + RTF_MLIT, + RTF_MLMARGIN, + RTF_MM, + RTF_MMADDFIELDNAME, + RTF_MMATH, + RTF_MMATHFONT, + RTF_MMATHPICT, + RTF_MMATHPR, + RTF_MMATTACH, + RTF_MMAXDIST, + RTF_MMBLANKLINES, + RTF_MMC, + RTF_MMCJC, + RTF_MMCONNECTSTR, + RTF_MMCONNECTSTRDATA, + RTF_MMCPR, + RTF_MMCS, + RTF_MMDATASOURCE, + RTF_MMDATATYPEACCESS, + RTF_MMDATATYPEEXCEL, + RTF_MMDATATYPEFILE, + RTF_MMDATATYPEODBC, + RTF_MMDATATYPEODSO, + RTF_MMDATATYPEQT, + RTF_MMDEFAULTSQL, + RTF_MMDESTEMAIL, + RTF_MMDESTFAX, + RTF_MMDESTNEWDOC, + RTF_MMDESTPRINTER, + RTF_MMERRORS, + RTF_MMFTTYPEADDRESS, + RTF_MMFTTYPEBARCODE, + RTF_MMFTTYPEDBCOLUMN, + RTF_MMFTTYPEMAPPED, + RTF_MMFTTYPENULL, + RTF_MMFTTYPESALUTATION, + RTF_MMHEADERSOURCE, + RTF_MMJDSOTYPE, + RTF_MMLINKTOQUERY, + RTF_MMMAILSUBJECT, + RTF_MMMAINTYPECATALOG, + RTF_MMMAINTYPEEMAIL, + RTF_MMMAINTYPEENVELOPES, + RTF_MMMAINTYPEFAX, + RTF_MMMAINTYPELABELS, + RTF_MMMAINTYPELETTERS, + RTF_MMODSO, + RTF_MMODSOACTIVE, + RTF_MMODSOCOLDELIM, + RTF_MMODSOCOLUMN, + RTF_MMODSODYNADDR, + RTF_MMODSOFHDR, + RTF_MMODSOFILTER, + RTF_MMODSOFLDMPDATA, + RTF_MMODSOFMCOLUMN, + RTF_MMODSOHASH, + RTF_MMODSOLID, + RTF_MMODSOMAPPEDNAME, + RTF_MMODSONAME, + RTF_MMODSORECIPDATA, + RTF_MMODSOSORT, + RTF_MMODSOSRC, + RTF_MMODSOTABLE, + RTF_MMODSOUDL, + RTF_MMODSOUDLDATA, + RTF_MMODSOUNIQUETAG, + RTF_MMPR, + RTF_MMQUERY, + RTF_MMR, + RTF_MMRECCUR, + RTF_MMSHOWDATA, + RTF_MNARY, + RTF_MNARYLIM, + RTF_MNARYPR, + RTF_MNOBREAK, + RTF_MNOR, + RTF_MNUM, + RTF_MO, + RTF_MOBJDIST, + RTF_MOMATH, + RTF_MOMATHPARA, + RTF_MOMATHPARAPR, + RTF_MOPEMU, + RTF_MPHANT, + RTF_MPHANTPR, + RTF_MPLCHIDE, + RTF_MPOS, + RTF_MPOSTSP, + RTF_MPRESP, + RTF_MR, + RTF_MRAD, + RTF_MRADPR, + RTF_MRMARGIN, + RTF_MRPR, + RTF_MRSP, + RTF_MRSPRULE, + RTF_MSCR, + RTF_MSEPCHR, + RTF_MSHOW, + RTF_MSHP, + RTF_MSMALLFRAC, + RTF_MSMCAP, + RTF_MSPRE, + RTF_MSPREPR, + RTF_MSSUB, + RTF_MSSUBPR, + RTF_MSSUBSUP, + RTF_MSSUBSUPPR, + RTF_MSSUP, + RTF_MSSUPPR, + RTF_MSTRIKEBLTR, + RTF_MSTRIKEH, + RTF_MSTRIKETLBR, + RTF_MSTRIKEV, + RTF_MSTY, + RTF_MSUB, + RTF_MSUBHIDE, + RTF_MSUP, + RTF_MSUPHIDE, + RTF_MTRANSP, + RTF_MTYPE, + RTF_MUSER, + RTF_MVAUTH, + RTF_MVDATE, + RTF_MVERTJC, + RTF_MVF, + RTF_MVFMF, + RTF_MVFML, + RTF_MVT, + RTF_MVTOF, + RTF_MVTOL, + RTF_MWRAPINDENT, + RTF_MWRAPRIGHT, + RTF_MZEROASC, + RTF_MZERODESC, + RTF_MZEROWID, + RTF_NESTCELL, + RTF_NESTROW, + RTF_NESTTABLEPROPS, + RTF_NEWTBLSTYRULS, + RTF_NEXTFILE, + RTF_NOAFCNSTTBL, + RTF_NOBRKWRPTBL, + RTF_NOCOLBAL, + RTF_NOCOMPATOPTIONS, + RTF_NOCWRAP, + RTF_NOCXSPTABLE, + RTF_NOEXTRASPRL, + RTF_NOFCHARS, + RTF_NOFCHARSWS, + RTF_NOFEATURETHROTTLE, + RTF_NOFPAGES, + RTF_NOFWORDS, + RTF_NOGROWAUTOFIT, + RTF_NOINDNMBRTS, + RTF_NOJKERNPUNCT, + RTF_NOLEAD, + RTF_NOLINE, + RTF_NOLNHTADJTBL, + RTF_NONESTTABLES, + RTF_NONSHPPICT, + RTF_NOOVERFLOW, + RTF_NOPROOF, + RTF_NOQFPROMOTE, + RTF_NOSECTEXPAND, + RTF_NOSNAPLINEGRID, + RTF_NOSPACEFORUL, + RTF_NOSUPERSUB, + RTF_NOTABIND, + RTF_NOTBRKCNSTFRCTBL, + RTF_NOTCVASP, + RTF_NOTVATXBX, + RTF_NOUICOMPAT, + RTF_NOULTRLSPC, + RTF_NOWIDCTLPAR, + RTF_NOWRAP, + RTF_NOWWRAP, + RTF_NOXLATTOYEN, + RTF_OBJALIAS, + RTF_OBJALIGN, + RTF_OBJATTPH, + RTF_OBJAUTLINK, + RTF_OBJCLASS, + RTF_OBJCROPB, + RTF_OBJCROPL, + RTF_OBJCROPR, + RTF_OBJCROPT, + RTF_OBJDATA, + RTF_OBJECT, + RTF_OBJEMB, + RTF_OBJH, + RTF_OBJHTML, + RTF_OBJICEMB, + RTF_OBJLINK, + RTF_OBJLOCK, + RTF_OBJNAME, + RTF_OBJOCX, + RTF_OBJPUB, + RTF_OBJSCALEX, + RTF_OBJSCALEY, + RTF_OBJSECT, + RTF_OBJSETSIZE, + RTF_OBJSUB, + RTF_OBJTIME, + RTF_OBJTRANSY, + RTF_OBJUPDATE, + RTF_OBJW, + RTF_OGUTTER, + RTF_OLDAS, + RTF_OLDCPROPS, + RTF_OLDLINEWRAP, + RTF_OLDPPROPS, + RTF_OLDSPROPS, + RTF_OLDTPROPS, + RTF_OLECLSID, + RTF_OPERATOR, + RTF_OTBLRUL, + RTF_OUTL, + RTF_OUTLINELEVEL, + RTF_OVERLAY, + RTF_PAGE, + RTF_PAGEBB, + RTF_PANOSE, + RTF_PAPERH, + RTF_PAPERW, + RTF_PAR, + RTF_PARARSID, + RTF_PARD, + RTF_PASSWORD, + RTF_PASSWORDHASH, + RTF_PC, + RTF_PCA, + RTF_PGBRDRB, + RTF_PGBRDRFOOT, + RTF_PGBRDRHEAD, + RTF_PGBRDRL, + RTF_PGBRDROPT, + RTF_PGBRDRR, + RTF_PGBRDRSNAP, + RTF_PGBRDRT, + RTF_PGHSXN, + RTF_PGNBIDIA, + RTF_PGNBIDIB, + RTF_PGNCHOSUNG, + RTF_PGNCNUM, + RTF_PGNCONT, + RTF_PGNDBNUM, + RTF_PGNDBNUMD, + RTF_PGNDBNUMK, + RTF_PGNDBNUMT, + RTF_PGNDEC, + RTF_PGNDECD, + RTF_PGNGANADA, + RTF_PGNGBNUM, + RTF_PGNGBNUMD, + RTF_PGNGBNUMK, + RTF_PGNGBNUML, + RTF_PGNHINDIA, + RTF_PGNHINDIB, + RTF_PGNHINDIC, + RTF_PGNHINDID, + RTF_PGNHN, + RTF_PGNHNSC, + RTF_PGNHNSH, + RTF_PGNHNSM, + RTF_PGNHNSN, + RTF_PGNHNSP, + RTF_PGNID, + RTF_PGNLCLTR, + RTF_PGNLCRM, + RTF_PGNRESTART, + RTF_PGNSTART, + RTF_PGNSTARTS, + RTF_PGNTHAIA, + RTF_PGNTHAIB, + RTF_PGNTHAIC, + RTF_PGNUCLTR, + RTF_PGNUCRM, + RTF_PGNVIETA, + RTF_PGNX, + RTF_PGNY, + RTF_PGNZODIAC, + RTF_PGNZODIACD, + RTF_PGNZODIACL, + RTF_PGP, + RTF_PGPTBL, + RTF_PGWSXN, + RTF_PHCOL, + RTF_PHMRG, + RTF_PHPG, + RTF_PICBMP, + RTF_PICBPP, + RTF_PICCROPB, + RTF_PICCROPL, + RTF_PICCROPR, + RTF_PICCROPT, + RTF_PICH, + RTF_PICHGOAL, + RTF_PICPROP, + RTF_PICSCALED, + RTF_PICSCALEX, + RTF_PICSCALEY, + RTF_PICT, + RTF_PICW, + RTF_PICWGOAL, + RTF_PINDTABQC, + RTF_PINDTABQL, + RTF_PINDTABQR, + RTF_PLAIN, + RTF_PMARTABQC, + RTF_PMARTABQL, + RTF_PMARTABQR, + RTF_PMMETAFILE, + RTF_PN, + RTF_PNACROSS, + RTF_PNAIU, + RTF_PNAIUD, + RTF_PNAIUEO, + RTF_PNAIUEOD, + RTF_PNB, + RTF_PNBIDIA, + RTF_PNBIDIB, + RTF_PNCAPS, + RTF_PNCARD, + RTF_PNCF, + RTF_PNCHOSUNG, + RTF_PNCNUM, + RTF_PNDBNUM, + RTF_PNDBNUMD, + RTF_PNDBNUMK, + RTF_PNDBNUML, + RTF_PNDBNUMT, + RTF_PNDEC, + RTF_PNDECD, + RTF_PNF, + RTF_PNFS, + RTF_PNGANADA, + RTF_PNGBLIP, + RTF_PNGBNUM, + RTF_PNGBNUMD, + RTF_PNGBNUMK, + RTF_PNGBNUML, + RTF_PNHANG, + RTF_PNI, + RTF_PNINDENT, + RTF_PNIROHA, + RTF_PNIROHAD, + RTF_PNLCLTR, + RTF_PNLCRM, + RTF_PNLVL, + RTF_PNLVLBLT, + RTF_PNLVLBODY, + RTF_PNLVLCONT, + RTF_PNNUMONCE, + RTF_PNORD, + RTF_PNORDT, + RTF_PNPREV, + RTF_PNQC, + RTF_PNQL, + RTF_PNQR, + RTF_PNRAUTH, + RTF_PNRDATE, + RTF_PNRESTART, + RTF_PNRNFC, + RTF_PNRNOT, + RTF_PNRPNBR, + RTF_PNRRGB, + RTF_PNRSTART, + RTF_PNRSTOP, + RTF_PNRXST, + RTF_PNSCAPS, + RTF_PNSECLVL, + RTF_PNSP, + RTF_PNSTART, + RTF_PNSTRIKE, + RTF_PNTEXT, + RTF_PNTXTA, + RTF_PNTXTB, + RTF_PNUCLTR, + RTF_PNUCRM, + RTF_PNUL, + RTF_PNULD, + RTF_PNULDASH, + RTF_PNULDASHD, + RTF_PNULDASHDD, + RTF_PNULDB, + RTF_PNULHAIR, + RTF_PNULNONE, + RTF_PNULTH, + RTF_PNULW, + RTF_PNULWAVE, + RTF_PNZODIAC, + RTF_PNZODIACD, + RTF_PNZODIACL, + RTF_POSNEGX, + RTF_POSNEGY, + RTF_POSX, + RTF_POSXC, + RTF_POSXI, + RTF_POSXL, + RTF_POSXO, + RTF_POSXR, + RTF_POSY, + RTF_POSYB, + RTF_POSYC, + RTF_POSYIL, + RTF_POSYIN, + RTF_POSYOUT, + RTF_POSYT, + RTF_PRAUTH, + RTF_PRCOLBL, + RTF_PRDATE, + RTF_PRINTDATA, + RTF_PRINTIM, + RTF_PRIVATE, + RTF_PROPNAME, + RTF_PROPTYPE, + RTF_PROTECT, + RTF_PROTEND, + RTF_PROTLEVEL, + RTF_PROTSTART, + RTF_PROTUSERTBL, + RTF_PSOVER, + RTF_PSZ, + RTF_PTABLDOT, + RTF_PTABLMDOT, + RTF_PTABLMINUS, + RTF_PTABLNONE, + RTF_PTABLUSCORE, + RTF_PUBAUTO, + RTF_PVMRG, + RTF_PVPARA, + RTF_PVPG, + RTF_PWD, + RTF_PXE, + RTF_QC, + RTF_QD, + RTF_QJ, + RTF_QK, + RTF_QL, + RTF_QMSPACE, + RTF_QR, + RTF_QT, + RTF_RAWCLBGDKBDIAG, + RTF_RAWCLBGBDIAG, + RTF_RAWCLBGCROSS, + RTF_RAWCLBGDCROSS, + RTF_RAWCLBGDKCROSS, + RTF_RAWCLBGDKDCROSS, + RTF_RAWCLBGDKFDIAG, + RTF_RAWCLBGDKHOR, + RTF_RAWCLBGDKVERT, + RTF_RAWCLBGFDIAG, + RTF_RAWCLBGHORIZ, + RTF_RAWCLBGVERT, + RTF_RDBLQUOTE, + RTF_READONLYRECOMMENDED, + RTF_READPROT, + RTF_RED, + RTF_RELYONVML, + RTF_REMDTTM, + RTF_REMPERSONALINFO, + RTF_RESULT, + RTF_REVAUTH, + RTF_REVAUTHDEL, + RTF_REVBAR, + RTF_REVDTTM, + RTF_REVDTTMDEL, + RTF_REVISED, + RTF_REVISIONS, + RTF_REVPROP, + RTF_REVPROT, + RTF_REVTBL, + RTF_REVTIM, + RTF_RI, + RTF_RIN, + RTF_ROW, + RTF_RQUOTE, + RTF_RSID, + RTF_RSIDROOT, + RTF_RSIDTBL, + RTF_RSLTBMP, + RTF_RSLTHTML, + RTF_RSLTMERGE, + RTF_RSLTPICT, + RTF_RSLTRTF, + RTF_RSLTTXT, + RTF_RTF, + RTF_RTLCH, + RTF_RTLDOC, + RTF_RTLGUTTER, + RTF_RTLMARK, + RTF_RTLPAR, + RTF_RTLROW, + RTF_RTLSECT, + RTF_RXE, + RTF_S, + RTF_SA, + RTF_SAAUTO, + RTF_SAFTNNALC, + RTF_SAFTNNAR, + RTF_SAFTNNAUC, + RTF_SAFTNNCHI, + RTF_SAFTNNCHOSUNG, + RTF_SAFTNNCNUM, + RTF_SAFTNNDBAR, + RTF_SAFTNNDBNUM, + RTF_SAFTNNDBNUMD, + RTF_SAFTNNDBNUMK, + RTF_SAFTNNDBNUMT, + RTF_SAFTNNGANADA, + RTF_SAFTNNGBNUM, + RTF_SAFTNNGBNUMD, + RTF_SAFTNNGBNUMK, + RTF_SAFTNNGBNUML, + RTF_SAFTNNRLC, + RTF_SAFTNNRUC, + RTF_SAFTNNZODIAC, + RTF_SAFTNNZODIACD, + RTF_SAFTNNZODIACL, + RTF_SAFTNRESTART, + RTF_SAFTNRSTCONT, + RTF_SAFTNSTART, + RTF_SAUTOUPD, + RTF_SAVEINVALIDXML, + RTF_SAVEPREVPICT, + RTF_SB, + RTF_SBASEDON, + RTF_SBAUTO, + RTF_SBKCOL, + RTF_SBKEVEN, + RTF_SBKNONE, + RTF_SBKODD, + RTF_SBKPAGE, + RTF_SBYS, + RTF_SCAPS, + RTF_SCOMPOSE, + RTF_SEC, + RTF_SECT, + RTF_SECTD, + RTF_SECTDEFAULTCL, + RTF_SECTEXPAND, + RTF_SECTLINEGRID, + RTF_SECTNUM, + RTF_SECTRSID, + RTF_SECTSPECIFYCL, + RTF_SECTSPECIFYGENN, + RTF_SECTSPECIFYL, + RTF_SECTUNLOCKED, + RTF_SFTNBJ, + RTF_SFTNNALC, + RTF_SFTNNAR, + RTF_SFTNNAUC, + RTF_SFTNNCHI, + RTF_SFTNNCHOSUNG, + RTF_SFTNNCNUM, + RTF_SFTNNDBAR, + RTF_SFTNNDBNUM, + RTF_SFTNNDBNUMD, + RTF_SFTNNDBNUMK, + RTF_SFTNNDBNUMT, + RTF_SFTNNGANADA, + RTF_SFTNNGBNUM, + RTF_SFTNNGBNUMD, + RTF_SFTNNGBNUMK, + RTF_SFTNNGBNUML, + RTF_SFTNNRLC, + RTF_SFTNNRUC, + RTF_SFTNNZODIAC, + RTF_SFTNNZODIACD, + RTF_SFTNNZODIACL, + RTF_SFTNRESTART, + RTF_SFTNRSTCONT, + RTF_SFTNRSTPG, + RTF_SFTNSTART, + RTF_SFTNTJ, + RTF_SHAD, + RTF_SHADING, + RTF_SHIDDEN, + RTF_SHIFT, + RTF_SHOWPLACEHOLDTEXT, + RTF_SHOWXMLERRORS, + RTF_SHP, + RTF_SHPBOTTOM, + RTF_SHPBXCOLUMN, + RTF_SHPBXIGNORE, + RTF_SHPBXMARGIN, + RTF_SHPBXPAGE, + RTF_SHPBYIGNORE, + RTF_SHPBYMARGIN, + RTF_SHPBYPAGE, + RTF_SHPBYPARA, + RTF_SHPFBLWTXT, + RTF_SHPFHDR, + RTF_SHPGRP, + RTF_SHPINST, + RTF_SHPLEFT, + RTF_SHPLID, + RTF_SHPLOCKANCHOR, + RTF_SHPPICT, + RTF_SHPRIGHT, + RTF_SHPRSLT, + RTF_SHPTOP, + RTF_SHPTXT, + RTF_SHPWRK, + RTF_SHPWR, + RTF_SHPZ, + RTF_SL, + RTF_SLINK, + RTF_SLMULT, + RTF_SLOCKED, + RTF_SN, + RTF_SNAPTOGRIDINCELL, + RTF_SNEXT, + RTF_SOFTCOL, + RTF_SOFTLHEIGHT, + RTF_SOFTLINE, + RTF_SOFTPAGE, + RTF_SP, + RTF_SPERSONAL, + RTF_SPLTPGPAR, + RTF_SPLYTWNINE, + RTF_SPRIORITY, + RTF_SPRSBSP, + RTF_SPRSLNSP, + RTF_SPRSSPBF, + RTF_SPRSTSM, + RTF_SPRSTSP, + RTF_SPV, + RTF_SQFORMAT, + RTF_SRAUTH, + RTF_SRDATE, + RTF_SREPLY, + RTF_SSEMIHIDDEN, + RTF_STATICVAL, + RTF_STEXTFLOW, + RTF_STRIKE, + RTF_STRIKED, + RTF_STSHFBI, + RTF_STSHFDBCH, + RTF_STSHFHICH, + RTF_STSHFLOCH, + RTF_STYLELOCK, + RTF_STYLELOCKBACKCOMP, + RTF_STYLELOCKENFORCED, + RTF_STYLELOCKQFSET, + RTF_STYLELOCKTHEME, + RTF_STYLESHEET, + RTF_STYLESORTMETHOD, + RTF_STYRSID, + RTF_SUB, + RTF_SUBDOCUMENT, + RTF_SUBFONTBYSIZE, + RTF_SUBJECT, + RTF_SUNHIDEUSED, + RTF_SUPER, + RTF_SV, + RTF_SVB, + RTF_SWPBDR, + RTF_TAB, + RTF_TABSNOOVRLP, + RTF_TAPRTL, + RTF_TB, + RTF_TBLIND, + RTF_TBLINDTYPE, + RTF_TBLLKBESTFIT, + RTF_TBLLKBORDER, + RTF_TBLLKCOLOR, + RTF_TBLLKFONT, + RTF_TBLLKHDRCOLS, + RTF_TBLLKHDRROWS, + RTF_TBLLKLASTCOL, + RTF_TBLLKLASTROW, + RTF_TBLLKNOCOLBAND, + RTF_TBLLKNOROWBAND, + RTF_TBLLKSHADING, + RTF_TBLRSID, + RTF_TC, + RTF_TCELLD, + RTF_TCF, + RTF_TCL, + RTF_TCN, + RTF_TDFRMTXTBOTTOM, + RTF_TDFRMTXTLEFT, + RTF_TDFRMTXTRIGHT, + RTF_TDFRMTXTTOP, + RTF_TEMPLATE, + RTF_THEMEDATA, + RTF_THEMELANG, + RTF_THEMELANGCS, + RTF_THEMELANGFE, + RTF_TIME, + RTF_TITLE, + RTF_TITLEPG, + RTF_TLDOT, + RTF_TLEQ, + RTF_TLHYPH, + RTF_TLMDOT, + RTF_TLTH, + RTF_TLUL, + RTF_TOPLINEPUNCT, + RTF_TPHCOL, + RTF_TPHMRG, + RTF_TPHPG, + RTF_TPOSNEGX, + RTF_TPOSNEGY, + RTF_TPOSXC, + RTF_TPOSXI, + RTF_TPOSXL, + RTF_TPOSX, + RTF_TPOSXO, + RTF_TPOSXR, + RTF_TPOSY, + RTF_TPOSYB, + RTF_TPOSYC, + RTF_TPOSYIL, + RTF_TPOSYIN, + RTF_TPOSYOUT, + RTF_TPOSYT, + RTF_TPVMRG, + RTF_TPVPARA, + RTF_TPVPG, + RTF_TQC, + RTF_TQDEC, + RTF_TQR, + RTF_TRACKFORMATTING, + RTF_TRACKMOVES, + RTF_TRANSMF, + RTF_TRAUTH, + RTF_TRAUTOFIT, + RTF_TRBGBDIAG, + RTF_TRBGCROSS, + RTF_TRBGDCROSS, + RTF_TRBGDKBDIAG, + RTF_TRBGDKCROSS, + RTF_TRBGDKDCROSS, + RTF_TRBGDKFDIAG, + RTF_TRBGDKHOR, + RTF_TRBGDKVERT, + RTF_TRBGFDIAG, + RTF_TRBGHORIZ, + RTF_TRBGVERT, + RTF_TRBRDRB, + RTF_TRBRDRH, + RTF_TRBRDRL, + RTF_TRBRDRR, + RTF_TRBRDRT, + RTF_TRBRDRV, + RTF_TRCBPAT, + RTF_TRCFPAT, + RTF_TRDATE, + RTF_TRFTSWIDTHA, + RTF_TRFTSWIDTHB, + RTF_TRFTSWIDTH, + RTF_TRGAPH, + RTF_TRHDR, + RTF_TRKEEP, + RTF_TRKEEPFOLLOW, + RTF_TRLEFT, + RTF_TROWD, + RTF_TRPADDB, + RTF_TRPADDFB, + RTF_TRPADDFL, + RTF_TRPADDFR, + RTF_TRPADDFT, + RTF_TRPADDL, + RTF_TRPADDR, + RTF_TRPADDT, + RTF_TRPADOB, + RTF_TRPADOFB, + RTF_TRPADOFL, + RTF_TRPADOFR, + RTF_TRPADOFT, + RTF_TRPADOL, + RTF_TRPADOR, + RTF_TRPADOT, + RTF_TRPAT, + RTF_TRQC, + RTF_TRQL, + RTF_TRQR, + RTF_TRRH, + RTF_TRSHDNG, + RTF_TRSPDB, + RTF_TRSPDFB, + RTF_TRSPDFL, + RTF_TRSPDFR, + RTF_TRSPDFT, + RTF_TRSPDL, + RTF_TRSPDR, + RTF_TRSPDT, + RTF_TRSPOB, + RTF_TRSPOFB, + RTF_TRSPOFL, + RTF_TRSPOFR, + RTF_TRSPOFT, + RTF_TRSPOL, + RTF_TRSPOR, + RTF_TRSPOT, + RTF_TRUNCATEFONTHEIGHT, + RTF_TRUNCEX, + RTF_TRWWIDTHA, + RTF_TRWWIDTHB, + RTF_TRWWIDTH, + RTF_TS, + RTF_TSBGBDIAG, + RTF_TSBGCROSS, + RTF_TSBGDCROSS, + RTF_TSBGDKBDIAG, + RTF_TSBGDKCROSS, + RTF_TSBGDKDCROSS, + RTF_TSBGDKFDIAG, + RTF_TSBGDKHOR, + RTF_TSBGDKVERT, + RTF_TSBGFDIAG, + RTF_TSBGHORIZ, + RTF_TSBGVERT, + RTF_TSBRDRB, + RTF_TSBRDRDGL, + RTF_TSBRDRDGR, + RTF_TSBRDRH, + RTF_TSBRDRL, + RTF_TSBRDRR, + RTF_TSBRDRT, + RTF_TSBRDRV, + RTF_TSCBANDHORZEVEN, + RTF_TSCBANDHORZODD, + RTF_TSCBANDSH, + RTF_TSCBANDSV, + RTF_TSCBANDVERTEVEN, + RTF_TSCBANDVERTODD, + RTF_TSCELLCBPAT, + RTF_TSCELLCFPAT, + RTF_TSCELLPADDB, + RTF_TSCELLPADDFB, + RTF_TSCELLPADDFL, + RTF_TSCELLPADDFR, + RTF_TSCELLPADDFT, + RTF_TSCELLPADDL, + RTF_TSCELLPADDR, + RTF_TSCELLPADDT, + RTF_TSCELLPCT, + RTF_TSCELLWIDTH, + RTF_TSCELLWIDTHFTS, + RTF_TSCFIRSTCOL, + RTF_TSCFIRSTROW, + RTF_TSCLASTCOL, + RTF_TSCLASTROW, + RTF_TSCNECELL, + RTF_TSCNWCELL, + RTF_TSCSECELL, + RTF_TSCSWCELL, + RTF_TSD, + RTF_TSNOWRAP, + RTF_TSROWD, + RTF_TSVERTALB, + RTF_TSVERTALC, + RTF_TSVERTALT, + RTF_TWOINONE, + RTF_TWOONONE, + RTF_TX, + RTF_TXBXTWALWAYS, + RTF_TXBXTWFIRST, + RTF_TXBXTWFIRSTLAST, + RTF_TXBXTWLAST, + RTF_TXBXTWNO, + RTF_TXE, + RTF_U, + RTF_UC, + RTF_UD, + RTF_UL, + RTF_ULC, + RTF_ULD, + RTF_ULDASH, + RTF_ULDASHD, + RTF_ULDASHDD, + RTF_ULDB, + RTF_ULHAIR, + RTF_ULHWAVE, + RTF_ULLDASH, + RTF_ULNONE, + RTF_ULTH, + RTF_ULTHD, + RTF_ULTHDASH, + RTF_ULTHDASHD, + RTF_ULTHDASHDD, + RTF_ULTHLDASH, + RTF_ULULDBWAVE, + RTF_ULW, + RTF_ULWAVE, + RTF_UP, + RTF_UPR, + RTF_URTF, + RTF_USELTBALN, + RTF_USENORMSTYFORLIST, + RTF_USERPROPS, + RTF_USEXFORM, + RTF_UTINL, + RTF_V, + RTF_VALIDATEXML, + RTF_VERN, + RTF_VERSION, + RTF_VERTAL, + RTF_VERTALB, + RTF_VERTALC, + RTF_VERTALJ, + RTF_VERTALT, + RTF_VERTDOC, + RTF_VERTSECT, + RTF_VIEWBKSP, + RTF_VIEWKIND, + RTF_VIEWNOBOUND, + RTF_VIEWSCALE, + RTF_VIEWZK, + RTF_WBITMAP, + RTF_WBMBITSPIXEL, + RTF_WBMPLANES, + RTF_WBMWIDTHBYTE, + RTF_WEBHIDDEN, + RTF_WGRFFMTFILTER, + RTF_WIDCTLPAR, + RTF_WIDOWCTRL, + RTF_WINDOWCAPTION, + RTF_WMETAFILE, + RTF_WPEQN, + RTF_WPJST, + RTF_WPSP, + RTF_WRAPAROUND, + RTF_WRAPDEFAULT, + RTF_WRAPTHROUGH, + RTF_WRAPTIGHT, + RTF_WRAPTRSP, + RTF_WRITERESERVATION, + RTF_WRITERESERVHASH, + RTF_WRPPUNCT, + RTF_XE, + RTF_XEF, + RTF_XFORM, + RTF_XMLATTR, + RTF_XMLATTRNAME, + RTF_XMLATTRNS, + RTF_XMLATTRVALUE, + RTF_XMLCLOSE, + RTF_XMLNAME, + RTF_XMLNS, + RTF_XMLNSTBL, + RTF_XMLOPEN, + RTF_XMLSDTTCELL, + RTF_XMLSDTTPARA, + RTF_XMLSDTTREGULAR, + RTF_XMLSDTTROW, + RTF_XMLSDTTUNKNOWN, + RTF_YR, + RTF_YTS, + RTF_YXE, + RTF_ZWBO, + RTF_ZWJ, + RTF_ZWNBO, + RTF_ZWNJ, + RTF_FLYMAINCNT, + RTF_FLYVERT, + RTF_FLYHORZ, + RTF_FLYANCHOR +}; +const char* keywordToString(RTFKeyword nKeyword); + +/// Types of an RTF Control Word +enum RTFControlTypes +{ + CONTROL_FLAG, // eg \sbknone takes no parameter + CONTROL_DESTINATION, // eg \fonttbl, if ignored, the whole group should be skipped + CONTROL_SYMBOL, // eg \tab + CONTROL_TOGGLE, // eg \b (between on and off) + CONTROL_VALUE // eg \fs (requires parameter) +}; + +/// Represents an RTF Control Word +class RTFSymbol +{ + const char* m_sKeyword; + int m_nControlType; + RTFKeyword m_nIndex; + + int m_nDefValue; ///< Most of the control words default to 0. + +public: + RTFSymbol() = default; + RTFSymbol(const char* sKeyword, int nControlType = 0, RTFKeyword nIndex = RTF_invalid, + int nDefValue = 0) + : m_sKeyword(sKeyword) + , m_nControlType(nControlType) + , m_nIndex(nIndex) + , m_nDefValue(nDefValue) + { + } + + const char* GetKeyword() const { return m_sKeyword; } + + int GetControlType() const { return m_nControlType; } + + RTFKeyword GetIndex() const { return m_nIndex; } + + int GetDefValue() const { return m_nDefValue; } +}; + +extern RTFSymbol const aRTFControlWords[]; +extern 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 int nRTFMathControlWords; + +} // namespace rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFCONTROLWORDS_HXX + +/* 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..68672bde9 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchdestination.cxx @@ -0,0 +1,676 @@ +/* -*- 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/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() && RTF_UD != nKeyword) + { + m_aStates.top().setDestination(Destination::SKIP); + aSkip.setParsed(false); + } + else + switch (nKeyword) + { + case RTF_RTF: + break; + case RTF_FONTTBL: + m_aStates.top().setDestination(Destination::FONTTABLE); + break; + case RTF_COLORTBL: + m_aStates.top().setDestination(Destination::COLORTABLE); + break; + case RTF_STYLESHEET: + m_aStates.top().setDestination(Destination::STYLESHEET); + break; + case RTF_FIELD: + m_aStates.top().setDestination(Destination::FIELD); + break; + case RTF_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 (aBuf.toString() == "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.toString(), 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 RTF_FLDRSLT: + m_aStates.top().setDestination(Destination::FIELDRESULT); + break; + case RTF_LISTTABLE: + m_aStates.top().setDestination(Destination::LISTTABLE); + break; + case RTF_LISTPICTURE: + m_aStates.top().setDestination(Destination::LISTPICTURE); + m_aStates.top().setInListpicture(true); + break; + case RTF_LIST: + m_aStates.top().setDestination(Destination::LISTENTRY); + break; + case RTF_LISTNAME: + m_aStates.top().setDestination(Destination::LISTNAME); + break; + case RTF_LFOLEVEL: + m_aStates.top().setDestination(Destination::LFOLEVEL); + m_aStates.top().getTableSprms().clear(); + break; + case RTF_LISTOVERRIDETABLE: + m_aStates.top().setDestination(Destination::LISTOVERRIDETABLE); + break; + case RTF_LISTOVERRIDE: + m_aStates.top().setDestination(Destination::LISTOVERRIDEENTRY); + break; + case RTF_LISTLEVEL: + m_aStates.top().setDestination(Destination::LISTLEVEL); + ++m_nListLevel; + break; + case RTF_LEVELTEXT: + m_aStates.top().setDestination(Destination::LEVELTEXT); + break; + case RTF_LEVELNUMBERS: + m_aStates.top().setDestination(Destination::LEVELNUMBERS); + break; + case RTF_SHPPICT: + resetFrame(); + m_aStates.top().setDestination(Destination::SHPPICT); + break; + case RTF_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 RTF_PICPROP: + m_aStates.top().setDestination(Destination::PICPROP); + break; + case RTF_SP: + m_aStates.top().setDestination(Destination::SHAPEPROPERTY); + break; + case RTF_SN: + m_aStates.top().setDestination(Destination::SHAPEPROPERTYNAME); + break; + case RTF_SV: + m_aStates.top().setDestination(Destination::SHAPEPROPERTYVALUE); + break; + case RTF_SHP: + m_bNeedCrOrig = m_bNeedCr; + m_aStates.top().setDestination(Destination::SHAPE); + m_aStates.top().setInShape(true); + break; + case RTF_SHPINST: + m_aStates.top().setDestination(Destination::SHAPEINSTRUCTION); + break; + case RTF_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 RTF_HEADER: + case RTF_FOOTER: + case RTF_HEADERL: + case RTF_HEADERR: + case RTF_HEADERF: + case RTF_FOOTERL: + case RTF_FOOTERR: + case RTF_FOOTERF: + if (!m_pSuperstream) + { + Id nId = 0; + std::size_t nPos = m_nGroupStartPos - 1; + switch (nKeyword) + { + case RTF_HEADER: + if (!m_hasRHeader) + { + nId = NS_ooxml::LN_headerr; + m_hasRHeader = true; + } + break; + case RTF_FOOTER: + if (!m_hasRFooter) + { + nId = NS_ooxml::LN_footerr; + m_hasRFooter = true; + } + break; + case RTF_HEADERL: + nId = NS_ooxml::LN_headerl; + break; + case RTF_HEADERR: + nId = NS_ooxml::LN_headerr; + break; + case RTF_HEADERF: + if (!m_hasFHeader) + { + nId = NS_ooxml::LN_headerf; + m_hasFHeader = true; + } + break; + case RTF_FOOTERL: + nId = NS_ooxml::LN_footerl; + break; + case RTF_FOOTERR: + nId = NS_ooxml::LN_footerr; + break; + case RTF_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 RTF_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 RTF_BKMKSTART: + m_aStates.top().setDestination(Destination::BOOKMARKSTART); + break; + case RTF_BKMKEND: + m_aStates.top().setDestination(Destination::BOOKMARKEND); + break; + case RTF_XE: + m_aStates.top().setDestination(Destination::INDEXENTRY); + break; + case RTF_TC: + case RTF_TCN: + m_aStates.top().setDestination(Destination::TOCENTRY); + break; + case RTF_REVTBL: + m_aStates.top().setDestination(Destination::REVISIONTABLE); + break; + case RTF_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(aAttributes); + Mapper().props(pProperties); + } + } + break; + case RTF_SHPTXT: + case RTF_DPTXBXTEXT: + { + bool bPictureFrame = false; + for (const auto& rProperty : m_aStates.top().getShape().getProperties()) + { + if (rProperty.first == "shapeType" + && rProperty.second == 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(RTF_PARD); + m_bNeedPap = true; + if (nKeyword == RTF_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 RTF_FORMFIELD: + if (m_aStates.top().getDestination() == Destination::FIELDINSTRUCTION) + m_aStates.top().setDestination(Destination::FORMFIELD); + break; + case RTF_FFNAME: + m_aStates.top().setDestination(Destination::FORMFIELDNAME); + break; + case RTF_FFL: + m_aStates.top().setDestination(Destination::FORMFIELDLIST); + break; + case RTF_DATAFIELD: + m_aStates.top().setDestination(Destination::DATAFIELD); + break; + case RTF_INFO: + m_aStates.top().setDestination(Destination::INFO); + break; + case RTF_CREATIM: + m_aStates.top().setDestination(Destination::CREATIONTIME); + break; + case RTF_REVTIM: + m_aStates.top().setDestination(Destination::REVISIONTIME); + break; + case RTF_PRINTIM: + m_aStates.top().setDestination(Destination::PRINTTIME); + break; + case RTF_AUTHOR: + m_aStates.top().setDestination(Destination::AUTHOR); + break; + case RTF_KEYWORDS: + m_aStates.top().setDestination(Destination::KEYWORDS); + break; + case RTF_OPERATOR: + m_aStates.top().setDestination(Destination::OPERATOR); + break; + case RTF_COMPANY: + m_aStates.top().setDestination(Destination::COMPANY); + break; + case RTF_COMMENT: + m_aStates.top().setDestination(Destination::COMMENT); + break; + case RTF_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 (RTF_RESULT) element of the object instead, + // the result element contain picture representing the OLE Object. + m_bObject = true; + } + } + break; + case RTF_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 (RTF_RESULT) element of the object instead, + // of the \objdata. + m_aStates.top().setDestination(Destination::SKIP); + } + else + { + m_aStates.top().setDestination(Destination::OBJDATA); + } + break; + case RTF_OBJCLASS: + m_aStates.top().setDestination(Destination::OBJCLASS); + break; + case RTF_RESULT: + m_aStates.top().setDestination(Destination::RESULT); + break; + case RTF_ATNDATE: + m_aStates.top().setDestination(Destination::ANNOTATIONDATE); + break; + case RTF_ATNAUTHOR: + m_aStates.top().setDestination(Destination::ANNOTATIONAUTHOR); + break; + case RTF_ATNREF: + m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCE); + break; + case RTF_FALT: + m_aStates.top().setDestination(Destination::FALT); + break; + case RTF_FLYMAINCNT: + m_aStates.top().setDestination(Destination::FLYMAINCONTENT); + break; + case RTF_LISTTEXT: + // Should be ignored by any reader that understands Word 97 through Word 2007 numbering. + case RTF_NONESTTABLES: + // This destination should be ignored by readers that support nested tables. + m_aStates.top().setDestination(Destination::SKIP); + break; + case RTF_DO: + m_aStates.top().setDestination(Destination::DRAWINGOBJECT); + break; + case RTF_PN: + m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING); + break; + case RTF_PNTEXT: + // This destination should be ignored by readers that support paragraph numbering. + m_aStates.top().setDestination(Destination::SKIP); + break; + case RTF_PNTXTA: + m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTAFTER); + break; + case RTF_PNTXTB: + m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTBEFORE); + break; + case RTF_TITLE: + m_aStates.top().setDestination(Destination::TITLE); + break; + case RTF_SUBJECT: + m_aStates.top().setDestination(Destination::SUBJECT); + break; + case RTF_DOCCOMM: + m_aStates.top().setDestination(Destination::DOCCOMM); + break; + case RTF_ATRFSTART: + m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCESTART); + break; + case RTF_ATRFEND: + m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCEEND); + break; + case RTF_ATNID: + m_aStates.top().setDestination(Destination::ATNID); + break; + case RTF_MMATH: + case RTF_MOMATHPARA: + // Nothing to do here (just enter the destination) till RTF_MMATHPR is implemented. + break; + case RTF_MR: + m_aStates.top().setDestination(Destination::MR); + break; + case RTF_MCHR: + m_aStates.top().setDestination(Destination::MCHR); + break; + case RTF_MPOS: + m_aStates.top().setDestination(Destination::MPOS); + break; + case RTF_MVERTJC: + m_aStates.top().setDestination(Destination::MVERTJC); + break; + case RTF_MSTRIKEH: + m_aStates.top().setDestination(Destination::MSTRIKEH); + break; + case RTF_MDEGHIDE: + m_aStates.top().setDestination(Destination::MDEGHIDE); + break; + case RTF_MTYPE: + m_aStates.top().setDestination(Destination::MTYPE); + break; + case RTF_MGROW: + m_aStates.top().setDestination(Destination::MGROW); + break; + case RTF_MHIDETOP: + case RTF_MHIDEBOT: + case RTF_MHIDELEFT: + case RTF_MHIDERIGHT: + // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now. + m_aStates.top().setDestination(Destination::SKIP); + break; + case RTF_MSUBHIDE: + m_aStates.top().setDestination(Destination::MSUBHIDE); + break; + case RTF_MSUPHIDE: + m_aStates.top().setDestination(Destination::MSUPHIDE); + break; + case RTF_MBEGCHR: + m_aStates.top().setDestination(Destination::MBEGCHR); + break; + case RTF_MSEPCHR: + m_aStates.top().setDestination(Destination::MSEPCHR); + break; + case RTF_MENDCHR: + m_aStates.top().setDestination(Destination::MENDCHR); + break; + case RTF_UPR: + m_aStates.top().setDestination(Destination::UPR); + break; + case RTF_UD: + // Anything inside \ud is just normal Unicode content. + m_aStates.top().setDestination(Destination::NORMAL); + break; + case RTF_BACKGROUND: + m_aStates.top().setDestination(Destination::BACKGROUND); + m_aStates.top().setInBackground(true); + break; + case RTF_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::makeAny(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 RTF_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 RTF_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 RTF_PROPNAME: + m_aStates.top().setDestination(Destination::PROPNAME); + break; + case RTF_STATICVAL: + m_aStates.top().setDestination(Destination::STATICVAL); + break; + case RTF_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..7265d7c42 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx @@ -0,0 +1,1239 @@ +/* -*- 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/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 RTF_ULD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dotted; + break; + case RTF_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 RTF_QC: + nParam = NS_ooxml::LN_Value_ST_Jc_center; + break; + case RTF_QJ: + nParam = NS_ooxml::LN_Value_ST_Jc_both; + break; + case RTF_QL: + nParam = NS_ooxml::LN_Value_ST_Jc_left; + break; + case RTF_QR: + nParam = NS_ooxml::LN_Value_ST_Jc_right; + break; + case RTF_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 RTF_FAFIXED: + case RTF_FAAUTO: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_auto; + break; + case RTF_FAHANG: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_top; + break; + case RTF_FACENTER: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_center; + break; + case RTF_FAROMAN: + nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline; + break; + case RTF_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 RTF_TQR: + nParam = NS_ooxml::LN_Value_ST_TabJc_right; + break; + case RTF_TQC: + nParam = NS_ooxml::LN_Value_ST_TabJc_center; + break; + case RTF_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 RTF_TLDOT: + nParam = NS_ooxml::LN_Value_ST_TabTlc_dot; + break; + case RTF_TLMDOT: + nParam = NS_ooxml::LN_Value_ST_TabTlc_middleDot; + break; + case RTF_TLHYPH: + nParam = NS_ooxml::LN_Value_ST_TabTlc_hyphen; + break; + case RTF_TLUL: + case RTF_TLTH: + nParam = NS_ooxml::LN_Value_ST_TabTlc_underscore; + break; + case RTF_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 RTF_BRDRHAIR: + case RTF_BRDRS: + nParam = NS_ooxml::LN_Value_ST_Border_single; + break; + case RTF_BRDRDOT: + nParam = NS_ooxml::LN_Value_ST_Border_dotted; + break; + case RTF_BRDRDASH: + nParam = NS_ooxml::LN_Value_ST_Border_dashed; + break; + case RTF_BRDRDB: + nParam = NS_ooxml::LN_Value_ST_Border_double; + break; + case RTF_BRDRTNTHSG: + nParam = NS_ooxml::LN_Value_ST_Border_thinThickSmallGap; + break; + case RTF_BRDRTNTHMG: + nParam = NS_ooxml::LN_Value_ST_Border_thinThickMediumGap; + break; + case RTF_BRDRTNTHLG: + nParam = NS_ooxml::LN_Value_ST_Border_thinThickLargeGap; + break; + case RTF_BRDRTHTNSG: + nParam = NS_ooxml::LN_Value_ST_Border_thickThinSmallGap; + break; + case RTF_BRDRTHTNMG: + nParam = NS_ooxml::LN_Value_ST_Border_thickThinMediumGap; + break; + case RTF_BRDRTHTNLG: + nParam = NS_ooxml::LN_Value_ST_Border_thickThinLargeGap; + break; + case RTF_BRDREMBOSS: + nParam = NS_ooxml::LN_Value_ST_Border_threeDEmboss; + break; + case RTF_BRDRENGRAVE: + nParam = NS_ooxml::LN_Value_ST_Border_threeDEngrave; + break; + case RTF_BRDROUTSET: + nParam = NS_ooxml::LN_Value_ST_Border_outset; + break; + case RTF_BRDRINSET: + nParam = NS_ooxml::LN_Value_ST_Border_inset; + break; + case RTF_BRDRDASHSM: + nParam = NS_ooxml::LN_Value_ST_Border_dashSmallGap; + break; + case RTF_BRDRDASHD: + nParam = NS_ooxml::LN_Value_ST_Border_dotDash; + break; + case RTF_BRDRDASHDD: + nParam = NS_ooxml::LN_Value_ST_Border_dotDotDash; + break; + case RTF_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 RTF_SBKNONE: + nParam = NS_ooxml::LN_Value_ST_SectionMark_continuous; + break; + case RTF_SBKCOL: + nParam = NS_ooxml::LN_Value_ST_SectionMark_nextColumn; + break; + case RTF_SBKPAGE: + nParam = NS_ooxml::LN_Value_ST_SectionMark_nextPage; + break; + case RTF_SBKEVEN: + nParam = NS_ooxml::LN_Value_ST_SectionMark_evenPage; + break; + case RTF_SBKODD: + nParam = NS_ooxml::LN_Value_ST_SectionMark_oddPage; + break; + default: + break; + } + if (nParam >= 0) + { + if (m_nResetBreakOnSectBreak != RTF_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 RTF_FTNNAR: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal; + break; + case RTF_FTNNALC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter; + break; + case RTF_FTNNAUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter; + break; + case RTF_FTNNRLC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman; + break; + case RTF_FTNNRUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman; + break; + case RTF_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 RTF_FTNRSTPG: + nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachPage; + break; + case RTF_FTNRESTART: + nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachSect; + break; + case RTF_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 RTF_AFTNNAR: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal; + break; + case RTF_AFTNNALC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter; + break; + case RTF_AFTNNAUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter; + break; + case RTF_AFTNNRLC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman; + break; + case RTF_AFTNNRUC: + nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman; + break; + case RTF_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 RTF_TRQL: + nParam = NS_ooxml::LN_Value_ST_Jc_left; + break; + case RTF_TRQC: + nParam = NS_ooxml::LN_Value_ST_Jc_center; + break; + case RTF_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 RTF_CLTXLRTB: + nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTb; + break; + case RTF_CLTXTBRL: + nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRl; + break; + case RTF_CLTXBTLR: + nParam = NS_ooxml::LN_Value_ST_TextDirection_btLr; + break; + case RTF_CLTXLRTBV: + nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTbV; + break; + case RTF_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 RTF_KEEP: + if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back()) + nParam = NS_ooxml::LN_CT_PPrBase_keepLines; + break; + case RTF_KEEPN: + if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back()) + nParam = NS_ooxml::LN_CT_PPrBase_keepNext; + break; + case RTF_INTBL: + { + m_aStates.top().setCurrentBuffer(&m_aTableBufferStack.back()); + nParam = NS_ooxml::LN_inTbl; + } + break; + case RTF_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 RTF_FNIL: + case RTF_FROMAN: + case RTF_FSWISS: + case RTF_FMODERN: + case RTF_FSCRIPT: + case RTF_FDECOR: + case RTF_FTECH: + case RTF_FBIDI: + // TODO ooxml:CT_Font_family seems to be ignored by the domain mapper + break; + case RTF_ANSI: + m_aStates.top().setCurrentEncoding(RTL_TEXTENCODING_MS_1252); + break; + case RTF_MAC: + m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_APPLE_ROMAN); + m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding()); + break; + case RTF_PC: + m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_437); + m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding()); + break; + case RTF_PCA: + m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_850); + m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding()); + break; + case RTF_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 RTF_PARD: + { + if (m_bHadPicture) + dispatchSymbol(RTF_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); + } + else + { + m_aStates.top().setCurrentStyleIndex(-1); + } + } + // Need to send paragraph properties again, if there will be any. + m_bNeedPap = true; + break; + } + case RTF_SECTD: + { + m_aStates.top().getSectionSprms() = m_aDefaultState.getSectionSprms(); + m_aStates.top().getSectionAttributes() = m_aDefaultState.getSectionAttributes(); + } + break; + case RTF_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 RTF_WIDCTLPAR: + case RTF_NOWIDCTLPAR: + { + auto pValue = new RTFValue(int(nKeyword == RTF_WIDCTLPAR)); + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_widowControl, pValue); + } + break; + case RTF_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 RTF_LTRSECT: + case RTF_RTLSECT: + { + auto pValue = new RTFValue(nKeyword == RTF_LTRSECT ? 0 : 1); + m_aStates.top().setRunType(RTFParserState::RunType::NONE); + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection, + pValue); + } + break; + case RTF_LTRPAR: + case RTF_RTLPAR: + { + auto pValue = new RTFValue(nKeyword == RTF_LTRPAR ? 0 : 1); + m_aStates.top().setRunType(RTFParserState::RunType::NONE); + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_bidi, pValue); + } + break; + case RTF_LTRROW: + case RTF_RTLROW: + m_aStates.top().setRunType(RTFParserState::RunType::NONE); + m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblPrBase_bidiVisual, + new RTFValue(int(nKeyword == RTF_RTLROW))); + break; + case RTF_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 RTF_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 RTF_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 RTF_NONSHPPICT: + case RTF_MMATHPICT: // Picture group used by readers not understanding \moMath group + m_aStates.top().setDestination(Destination::SKIP); + break; + case RTF_CLBRDRT: + case RTF_CLBRDRL: + case RTF_CLBRDRB: + case RTF_CLBRDRR: + { + RTFSprms aAttributes; + RTFSprms aSprms; + auto pValue = new RTFValue(aAttributes, aSprms); + switch (nKeyword) + { + case RTF_CLBRDRT: + nParam = NS_ooxml::LN_CT_TcBorders_top; + break; + case RTF_CLBRDRL: + nParam = NS_ooxml::LN_CT_TcBorders_left; + break; + case RTF_CLBRDRB: + nParam = NS_ooxml::LN_CT_TcBorders_bottom; + break; + case RTF_CLBRDRR: + nParam = NS_ooxml::LN_CT_TcBorders_right; + break; + default: + break; + } + putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcBorders, + nParam, pValue); + m_aStates.top().setBorderState(RTFBorderState::CELL); + } + break; + case RTF_PGBRDRT: + case RTF_PGBRDRL: + case RTF_PGBRDRB: + case RTF_PGBRDRR: + { + RTFSprms aAttributes; + RTFSprms aSprms; + auto pValue = new RTFValue(aAttributes, aSprms); + switch (nKeyword) + { + case RTF_PGBRDRT: + nParam = NS_ooxml::LN_CT_PageBorders_top; + break; + case RTF_PGBRDRL: + nParam = NS_ooxml::LN_CT_PageBorders_left; + break; + case RTF_PGBRDRB: + nParam = NS_ooxml::LN_CT_PageBorders_bottom; + break; + case RTF_PGBRDRR: + nParam = NS_ooxml::LN_CT_PageBorders_right; + break; + default: + break; + } + putNestedSprm(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgBorders, nParam, pValue); + m_aStates.top().setBorderState(RTFBorderState::PAGE); + } + break; + case RTF_BRDRT: + case RTF_BRDRL: + case RTF_BRDRB: + case RTF_BRDRR: + { + RTFSprms aAttributes; + RTFSprms aSprms; + auto pValue = new RTFValue(aAttributes, aSprms); + switch (nKeyword) + { + case RTF_BRDRT: + nParam = getParagraphBorder(0); + break; + case RTF_BRDRL: + nParam = getParagraphBorder(1); + break; + case RTF_BRDRB: + nParam = getParagraphBorder(2); + break; + case RTF_BRDRR: + nParam = getParagraphBorder(3); + break; + default: + break; + } + putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nParam, + pValue); + m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH); + } + break; + case RTF_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 RTF_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 RTF_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 RTF_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 RTF_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 RTF_CLVERTALT: + case RTF_CLVERTALC: + case RTF_CLVERTALB: + { + switch (nKeyword) + { + case RTF_CLVERTALT: + nParam = NS_ooxml::LN_Value_ST_VerticalJc_top; + break; + case RTF_CLVERTALC: + nParam = NS_ooxml::LN_Value_ST_VerticalJc_center; + break; + case RTF_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 RTF_TRKEEP: + { + auto pValue = new RTFValue(1); + m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_cantSplit, pValue); + } + break; + case RTF_SECTUNLOCKED: + { + auto pValue = new RTFValue(0); + m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_formProt, pValue); + } + break; + case RTF_PGNBIDIA: + case RTF_PGNBIDIB: + // These should be mapped to NS_ooxml::LN_EG_SectPrContents_pgNumType, but dmapper has no API for that at the moment. + break; + case RTF_LOCH: + m_aStates.top().setRunType(RTFParserState::RunType::LOCH); + break; + case RTF_HICH: + m_aStates.top().setRunType(RTFParserState::RunType::HICH); + break; + case RTF_DBCH: + m_aStates.top().setRunType(RTFParserState::RunType::DBCH); + break; + case RTF_TITLEPG: + { + auto pValue = new RTFValue(1); + m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_titlePg, pValue); + } + break; + case RTF_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 RTF_SUB: + { + auto pValue = new RTFValue("subscript"); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue); + } + break; + case RTF_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 RTF_LINEPPAGE: + case RTF_LINECONT: + { + auto pValue = new RTFValue(nKeyword == RTF_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 RTF_AENDDOC: + // Noop, this is the default in Writer. + case RTF_AENDNOTES: + // Noop + case RTF_AFTNRSTCONT: + // Noop, this is the default in Writer. + case RTF_AFTNRESTART: + // Noop + case RTF_FTNBJ: + // Noop, this is the default in Writer. + break; + case RTF_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 RTF_NOLINE: + eraseNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_lnNumType, + NS_ooxml::LN_CT_LineNumber_distance); + break; + case RTF_FORMSHADE: + // Noop, this is the default in Writer. + break; + case RTF_PNGBLIP: + m_aStates.top().getPicture().eStyle = RTFBmpStyle::PNG; + break; + case RTF_JPEGBLIP: + m_aStates.top().getPicture().eStyle = RTFBmpStyle::JPEG; + break; + case RTF_POSYT: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + NS_ooxml::LN_Value_doc_ST_YAlign_top); + break; + case RTF_POSYB: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + NS_ooxml::LN_Value_doc_ST_YAlign_bottom); + break; + case RTF_POSYC: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + NS_ooxml::LN_Value_doc_ST_YAlign_center); + break; + case RTF_POSYIN: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + NS_ooxml::LN_Value_doc_ST_YAlign_inside); + break; + case RTF_POSYOUT: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + NS_ooxml::LN_Value_doc_ST_YAlign_outside); + break; + case RTF_POSYIL: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + NS_ooxml::LN_Value_doc_ST_YAlign_inline); + break; + + case RTF_PHMRG: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, + NS_ooxml::LN_Value_doc_ST_HAnchor_margin); + break; + case RTF_PVMRG: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, + NS_ooxml::LN_Value_doc_ST_VAnchor_margin); + break; + case RTF_PHPG: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, + NS_ooxml::LN_Value_doc_ST_HAnchor_page); + break; + case RTF_PVPG: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, + NS_ooxml::LN_Value_doc_ST_VAnchor_page); + break; + case RTF_PHCOL: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, + NS_ooxml::LN_Value_doc_ST_HAnchor_text); + break; + case RTF_PVPARA: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, + NS_ooxml::LN_Value_doc_ST_VAnchor_text); + break; + + case RTF_POSXC: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, + NS_ooxml::LN_Value_doc_ST_XAlign_center); + break; + case RTF_POSXI: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, + NS_ooxml::LN_Value_doc_ST_XAlign_inside); + break; + case RTF_POSXO: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, + NS_ooxml::LN_Value_doc_ST_XAlign_outside); + break; + case RTF_POSXL: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, + NS_ooxml::LN_Value_doc_ST_XAlign_left); + break; + case RTF_POSXR: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, + NS_ooxml::LN_Value_doc_ST_XAlign_right); + break; + + case RTF_DPLINE: + case RTF_DPRECT: + case RTF_DPELLIPSE: + case RTF_DPTXBX: + case RTF_DPPOLYLINE: + case RTF_DPPOLYGON: + { + sal_Int32 nType = 0; + switch (nKeyword) + { + case RTF_DPLINE: + { + uno::Reference<drawing::XShape> xShape( + getModelFactory()->createInstance("com.sun.star.drawing.LineShape"), + uno::UNO_QUERY); + m_aStates.top().getDrawingObject().setShape(xShape); + break; + } + case RTF_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 RTF_DPPOLYGON: + { + uno::Reference<drawing::XShape> xShape( + getModelFactory()->createInstance("com.sun.star.drawing.PolyPolygonShape"), + uno::UNO_QUERY); + m_aStates.top().getDrawingObject().setShape(xShape); + break; + } + case RTF_DPRECT: + { + uno::Reference<drawing::XShape> xShape( + getModelFactory()->createInstance("com.sun.star.drawing.RectangleShape"), + uno::UNO_QUERY); + m_aStates.top().getDrawingObject().setShape(xShape); + break; + } + case RTF_DPELLIPSE: + nType = ESCHER_ShpInst_Ellipse; + break; + case RTF_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 != RTF_DPTXBX) + { + // set default VertOrient before inserting + m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue( + "VertOrient", uno::makeAny(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 RTF_DOBXMARGIN: + case RTF_DOBYMARGIN: + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name + = (nKeyword == RTF_DOBXMARGIN ? OUStringLiteral("HoriOrientRelation") + : OUStringLiteral("VertOrientRelation")); + aPropertyValue.Value <<= text::RelOrientation::PAGE_PRINT_AREA; + m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue); + } + break; + case RTF_DOBXPAGE: + case RTF_DOBYPAGE: + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name + = (nKeyword == RTF_DOBXPAGE ? OUStringLiteral("HoriOrientRelation") + : OUStringLiteral("VertOrientRelation")); + aPropertyValue.Value <<= text::RelOrientation::PAGE_FRAME; + m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue); + } + break; + case RTF_DOBYPARA: + { + beans::PropertyValue aPropertyValue; + aPropertyValue.Name = "VertOrientRelation"; + aPropertyValue.Value <<= text::RelOrientation::FRAME; + m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue); + } + break; + case RTF_CONTEXTUALSPACE: + { + auto pValue = new RTFValue(1); + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_contextualSpacing, + pValue); + } + break; + case RTF_LINKSTYLES: + { + auto pValue = new RTFValue(1); + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_linkStyles, pValue); + } + break; + case RTF_PNLVLBODY: + { + auto pValue = new RTFValue(2); + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid, pValue); + } + break; + case RTF_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 RTF_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 RTF_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 RTF_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 RTF_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 RTF_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 RTF_DPLINEHOLLOW: + m_aStates.top().getDrawingObject().setFLine(0); + break; + case RTF_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::makeAny(sal_Int32(83))); + break; + case RTF_NOWRAP: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap, + NS_ooxml::LN_Value_doc_ST_Wrap_notBeside); + break; + case RTF_MNOR: + m_bMathNor = true; + break; + case RTF_REVISIONS: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_trackRevisions, new RTFValue(1)); + break; + case RTF_BRDRSH: + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_shadow, new RTFValue(1)); + break; + case RTF_NOCOLBAL: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_noColumnBalance, new RTFValue(1)); + break; + case RTF_MARGMIRROR: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_mirrorMargins, new RTFValue(1)); + break; + case RTF_SAUTOUPD: + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_autoRedefine, + new RTFValue(1)); + break; + case RTF_WIDOWCTRL: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_widowControl, new RTFValue(1)); + break; + case RTF_LINEBETCOL: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_sep, + new RTFValue(1)); + break; + case RTF_PGNRESTART: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgNumType, + NS_ooxml::LN_CT_PageNumber_start, new RTFValue(1)); + break; + case RTF_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 RTF_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 RTF_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 RTF_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 RTF_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 RTF_HTMAUTSP: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_doNotUseHTMLParagraphAutoSpacing, + new RTFValue(0)); + break; + case RTF_DNTBLNSBDB: + // tdf#128428 switch off longer space sequence + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence, + new RTFValue(0)); + 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..ff13dedcf --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx @@ -0,0 +1,432 @@ +/* -*- 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 != RTF_HEXCHAR) + checkUnicode(/*bUnicode =*/true, /*bHex =*/true); + else + checkUnicode(/*bUnicode =*/true, /*bHex =*/false); + RTFSkipDestination aSkip(*this); + + if (RTF_LINE == nKeyword) + { + // very special handling since text() will eat lone '\n' + singleChar('\n'); + return RTFError::OK; + } + // Trivial symbols + sal_uInt8 cCh = 0; + switch (nKeyword) + { + case RTF_TAB: + cCh = '\t'; + break; + case RTF_BACKSLASH: + cCh = '\\'; + break; + case RTF_LBRACE: + cCh = '{'; + break; + case RTF_RBRACE: + cCh = '}'; + break; + case RTF_EMDASH: + cCh = 151; + break; + case RTF_ENDASH: + cCh = 150; + break; + case RTF_BULLET: + cCh = 149; + break; + case RTF_LQUOTE: + cCh = 145; + break; + case RTF_RQUOTE: + cCh = 146; + break; + case RTF_LDBLQUOTE: + cCh = 147; + break; + case RTF_RDBLQUOTE: + cCh = 148; + break; + default: + break; + } + if (cCh > 0) + { + OUString aStr(OStringToOUString(OString(cCh), RTL_TEXTENCODING_MS_1252)); + text(aStr); + return RTFError::OK; + } + + switch (nKeyword) + { + case RTF_IGNORE: + { + m_bSkipUnknown = true; + aSkip.setReset(false); + return RTFError::OK; + } + break; + case RTF_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(aAttributes, 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 RTF_SECT: + { + m_bHadSect = true; + if (m_bIgnoreNextContSectBreak) + m_bIgnoreNextContSectBreak = false; + else + { + sectBreak(); + if (m_nResetBreakOnSectBreak != RTF_invalid) + { + // this should run on _second_ \sect after \page + dispatchSymbol(m_nResetBreakOnSectBreak); // lazy reset + m_nResetBreakOnSectBreak = RTF_invalid; + m_bNeedSect = false; // dispatchSymbol set it + } + } + } + break; + case RTF_NOBREAK: + { + OUString aStr(SVT_HARD_SPACE); + text(aStr); + } + break; + case RTF_NOBRKHYPH: + { + OUString aStr(SVT_HARD_HYPHEN); + text(aStr); + } + break; + case RTF_OPTHYPH: + { + OUString aStr(SVT_SOFT_HYPHEN); + text(aStr); + } + break; + case RTF_HEXCHAR: + m_aStates.top().setInternalState(RTFInternalState::HEX); + break; + case RTF_CELL: + case RTF_NESTCELL: + { + if (nKeyword == RTF_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 RTF_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 RTF_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(RTF_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 RTF_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(RTF_PAGE); + } + break; + case RTF_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 RTF_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 == RTF_SBKNONE) + && !(pTitlePg && pTitlePg->getInt())) + { + if (m_bWasInFrame) + { + dispatchSymbol(RTF_PAR); + m_bWasInFrame = false; + } + sectBreak(); + // note: this will not affect the following section break + // but the one just pushed + dispatchFlag(RTF_SBKPAGE); + if (m_bNeedPar) + dispatchSymbol(RTF_PAR); + m_bIgnoreNextContSectBreak = true; + // arrange to clean up the synthetic RTF_SBKPAGE + m_nResetBreakOnSectBreak = RTF_SBKNONE; + } + else + { + checkFirstRun(); + checkNeedPap(); + sal_uInt8 const sBreak[] = { 0xc }; + Mapper().text(sBreak, 1); + if (!m_bNeedPap) + { + parBreak(); + m_bNeedPap = true; + } + m_bNeedCr = true; + } + } + break; + case RTF_CHPGN: + { + OUString aStr("PAGE"); + singleChar(cFieldStart); + text(aStr); + singleChar(cFieldSep, true); + singleChar(cFieldEnd); + } + break; + case RTF_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..b43e85a23 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx @@ -0,0 +1,1801 @@ +/* -*- 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 RTF_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 RTF_LEVELSTARTAT: + nSprm = NS_ooxml::LN_CT_Lvl_start; + break; + case RTF_LEVELPICTURE: + nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId; + break; + case RTF_SBASEDON: + nSprm = NS_ooxml::LN_CT_Style_basedOn; + pIntValue = new RTFValue(getStyleName(nParam)); + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().getTableSprms().set(nSprm, pIntValue); + return true; + } + if (nKeyword == RTF_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 RTF_FS: + case RTF_AFS: + switch (m_aStates.top().getRunType()) + { + case RTFParserState::RunType::HICH: + case RTFParserState::RunType::RTLCH_LTRCH_1: + case RTFParserState::RunType::LTRCH_RTLCH_2: + case RTFParserState::RunType::DBCH: + 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: + default: + nSprm = NS_ooxml::LN_EG_RPrBase_sz; + break; + } + break; + case RTF_EXPNDTW: + nSprm = NS_ooxml::LN_EG_RPrBase_spacing; + break; + case RTF_KERNING: + nSprm = NS_ooxml::LN_EG_RPrBase_kern; + break; + case RTF_CHARSCALEX: + nSprm = NS_ooxml::LN_EG_RPrBase_w; + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().getCharacterSprms().set(nSprm, pIntValue); + return true; + } + + return false; +} + +bool RTFDocumentImpl::dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + + switch (nKeyword) + { + case RTF_LANG: + case RTF_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 RTF_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 == RTF_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 RTF_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 == RTF_ITAP && nParam > 0) + { + while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam)) + { + m_aTableBufferStack.emplace_back(RTFBuffer_t()); + } + // Invalid tables may omit INTBL after ITAP + dispatchFlag(RTF_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 RTF_YR: + { + m_aStates.top().setYear(nParam); + nSprm = 1; + } + break; + case RTF_MO: + { + m_aStates.top().setMonth(nParam); + nSprm = 1; + } + break; + case RTF_DY: + { + m_aStates.top().setDay(nParam); + nSprm = 1; + } + break; + case RTF_HR: + { + m_aStates.top().setHour(nParam); + nSprm = 1; + } + break; + case RTF_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 RTF_ABSW: + nId = NS_ooxml::LN_CT_FramePr_w; + break; + case RTF_ABSH: + nId = NS_ooxml::LN_CT_FramePr_h; + break; + case RTF_POSX: + { + nId = NS_ooxml::LN_CT_FramePr_x; + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0); + } + break; + case RTF_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 RTF_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(RTF_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(aAttributes, aSprms); + Mapper().props(pProperties); + } + m_nCellxMax = std::max(m_nCellxMax, nParam); + return true; + } + break; + case RTF_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 RTF_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 RTF_CLSHDNG: + { + int nValue = -1; + switch (nParam) + { + case 500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct5; + break; + case 1000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct10; + break; + case 1200: + nValue = NS_ooxml::LN_Value_ST_Shd_pct12; + break; + case 1500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct15; + break; + case 2000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct20; + break; + case 2500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct25; + break; + case 3000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct30; + break; + case 3500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct35; + break; + case 3700: + nValue = NS_ooxml::LN_Value_ST_Shd_pct37; + break; + case 4000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct40; + break; + case 4500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct45; + break; + case 5000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct50; + break; + case 5500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct55; + break; + case 6000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct60; + break; + case 6200: + nValue = NS_ooxml::LN_Value_ST_Shd_pct62; + break; + case 6500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct65; + break; + case 7000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct70; + break; + case 7500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct75; + break; + case 8000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct80; + break; + case 8500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct85; + break; + case 8700: + nValue = NS_ooxml::LN_Value_ST_Shd_pct87; + break; + case 9000: + nValue = NS_ooxml::LN_Value_ST_Shd_pct90; + break; + case 9500: + nValue = NS_ooxml::LN_Value_ST_Shd_pct95; + break; + default: + break; + } + if (nValue != -1) + putNestedAttribute(m_aStates.top().getTableCellSprms(), + NS_ooxml::LN_CT_TcPrBase_shd, NS_ooxml::LN_CT_Shd_val, + new RTFValue(nValue)); + return true; + } + break; + case RTF_CLPADB: + case RTF_CLPADL: + case RTF_CLPADR: + case RTF_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 RTF_CLPADB: + nSprm = NS_ooxml::LN_CT_TcMar_bottom; + break; + case RTF_CLPADL: + nSprm = NS_ooxml::LN_CT_TcMar_top; + break; + case RTF_CLPADR: + nSprm = NS_ooxml::LN_CT_TcMar_right; + break; + case RTF_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 RTF_TRPADDFB: + case RTF_TRPADDFL: + case RTF_TRPADDFR: + case RTF_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 RTF_TRPADDFB: + nSprm = NS_ooxml::LN_CT_TcMar_bottom; + break; + case RTF_TRPADDFL: + nSprm = NS_ooxml::LN_CT_TcMar_left; + break; + case RTF_TRPADDFR: + nSprm = NS_ooxml::LN_CT_TcMar_right; + break; + case RTF_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 RTF_TRPADDB: + case RTF_TRPADDL: + case RTF_TRPADDR: + case RTF_TRPADDT: + { + RTFSprms aAttributes; + aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); + switch (nKeyword) + { + case RTF_TRPADDB: + nSprm = NS_ooxml::LN_CT_TcMar_bottom; + break; + case RTF_TRPADDL: + nSprm = NS_ooxml::LN_CT_TcMar_left; + break; + case RTF_TRPADDR: + nSprm = NS_ooxml::LN_CT_TcMar_right; + break; + case RTF_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; + } + break; + case RTF_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; + break; + case RTF_TRFTSWIDTH: + putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW, + NS_ooxml::LN_CT_TblWidth_type, pIntValue); + return true; + break; + case RTF_TRWWIDTH: + putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW, + NS_ooxml::LN_CT_TblWidth_w, pIntValue); + return true; + break; + default: + break; + } + + return false; +} + +RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) +{ + setNeedSect(true); + checkUnicode(/*bUnicode =*/nKeyword != RTF_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 RTF_F: + case RTF_AF: + 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_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::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) + { + 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 == RTF_F) + m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex)); + } + break; + case RTF_RED: + m_aStates.top().getCurrentColor().SetRed(nParam); + break; + case RTF_GREEN: + m_aStates.top().getCurrentColor().SetGreen(nParam); + break; + case RTF_BLUE: + m_aStates.top().getCurrentColor().SetBlue(nParam); + break; + case RTF_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 RTF_ANSICPG: + case RTF_CPG: + { + rtl_TextEncoding nEncoding + = (nParam == 0) + ? utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding()) + : rtl_getTextEncodingFromWindowsCodePage(nParam); + if (nKeyword == RTF_ANSICPG) + m_aDefaultState.setCurrentEncoding(nEncoding); + else + m_nCurrentEncoding = nEncoding; + m_aStates.top().setCurrentEncoding(nEncoding); + } + break; + case RTF_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 RTF_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 RTF_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 RTF_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 RTF_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 RTF_DEFF: + m_nDefaultFontIndex = nParam; + break; + case RTF_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 RTF_DEFLANG: + case RTF_ADEFLANG: + { + LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam)))); + auto pValue = new RTFValue(aTag.getBcp47()); + putNestedAttribute(m_aStates.top().getCharacterSprms(), + (nKeyword == RTF_DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang + : NS_ooxml::LN_CT_Language_bidi), + nSprm, pValue); + } + break; + case RTF_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 RTF_CLCBPAT: + case RTF_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 RTF_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 RTF_ULC: + { + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + m_aStates.top().getCharacterSprms().set(0x6877, pValue); + } + break; + case RTF_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 RTF_UP: + case RTF_DN: + { + auto pValue = new RTFValue(nParam * (nKeyword == RTF_UP ? 1 : -1)); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue); + } + break; + case RTF_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 RTF_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 RTF_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 RTF_SL: + { + // This is similar to RTF_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 RTF_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 RTF_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 RTF_BRDRCF: + { + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue); + } + break; + case RTF_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 RTF_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 RTF_ILVL: + putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr, + NS_ooxml::LN_CT_NumPr_ilvl, pIntValue); + break; + case RTF_LISTTEMPLATEID: + // This one is not referenced anywhere, so it's pointless to store it at the moment. + break; + case RTF_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 RTF_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 RTF_UC: + if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16)) + m_aStates.top().setUc(nParam); + break; + case RTF_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 RTF_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 RTF_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 RTF_LISTOVERRIDECOUNT: + // Ignore this for now, the exporter always emits it with a zero parameter. + break; + case RTF_PICSCALEX: + m_aStates.top().getPicture().nScaleX = nParam; + break; + case RTF_PICSCALEY: + m_aStates.top().getPicture().nScaleY = nParam; + break; + case RTF_PICW: + m_aStates.top().getPicture().nWidth = nParam; + break; + case RTF_PICH: + m_aStates.top().getPicture().nHeight = nParam; + break; + case RTF_PICWGOAL: + m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam); + break; + case RTF_PICHGOAL: + m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam); + break; + case RTF_PICCROPL: + m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam); + break; + case RTF_PICCROPR: + m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam); + break; + case RTF_PICCROPT: + m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam); + break; + case RTF_PICCROPB: + m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam); + break; + case RTF_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 RTF_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 RTF_COLS: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num, + pIntValue); + break; + case RTF_COLSX: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space, + pIntValue); + break; + case RTF_COLNO: + putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols, + NS_ooxml::LN_CT_Columns_col, pIntValue); + break; + case RTF_COLW: + case RTF_COLSR: + { + RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols); + rAttributes.set( + (nKeyword == RTF_COLW ? NS_ooxml::LN_CT_Column_w : NS_ooxml::LN_CT_Column_space), + pIntValue); + } + break; + case RTF_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 RTF_PGHSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, + pIntValue); + break; + case RTF_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 RTF_PGWSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, + pIntValue); + break; + case RTF_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 RTF_MARGLSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, + pIntValue); + break; + case RTF_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 RTF_MARGRSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, + pIntValue); + break; + case RTF_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 RTF_MARGTSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, + pIntValue); + break; + case RTF_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 RTF_MARGBSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, + pIntValue); + break; + case RTF_HEADERY: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header, + pIntValue); + break; + case RTF_FOOTERY: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer, + pIntValue); + break; + case RTF_DEFTAB: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue); + break; + case RTF_LINEMOD: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_lnNumType, + NS_ooxml::LN_CT_LineNumber_countBy, pIntValue); + break; + case RTF_LINEX: + if (nParam) + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_lnNumType, + NS_ooxml::LN_CT_LineNumber_distance, pIntValue); + break; + case RTF_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 RTF_REVAUTH: + case RTF_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 RTF_REVDTTM: + case RTF_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 RTF_SHPLEFT: + m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam)); + break; + case RTF_SHPTOP: + m_aStates.top().getShape().setTop(convertTwipToMm100(nParam)); + break; + case RTF_SHPRIGHT: + m_aStates.top().getShape().setRight(convertTwipToMm100(nParam)); + break; + case RTF_SHPBOTTOM: + m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam)); + break; + case RTF_SHPZ: + m_aStates.top().getShape().setZ(nParam); + break; + case RTF_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 RTF_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 RTF_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 RTF_EDMINS: + if (m_xDocumentProperties.is()) + { + // tdf#116851 some RTF may be malformed + if (nParam < 0) + nParam = -nParam; + m_xDocumentProperties->setEditingDuration(nParam); + } + break; + case RTF_NOFPAGES: + case RTF_NOFWORDS: + case RTF_NOFCHARS: + case RTF_NOFCHARSWS: + if (m_xDocumentProperties.is()) + { + comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics(); + OUString aName; + switch (nKeyword) + { + case RTF_NOFPAGES: + aName = "PageCount"; + nParam = 99; + break; + case RTF_NOFWORDS: + aName = "WordCount"; + break; + case RTF_NOFCHARS: + aName = "CharacterCount"; + break; + case RTF_NOFCHARSWS: + aName = "NonWhitespaceCharacterCount"; + break; + default: + break; + } + if (!aName.isEmpty()) + { + aSeq[aName] <<= sal_Int32(nParam); + m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList()); + } + } + break; + case RTF_VERSION: + if (m_xDocumentProperties.is()) + m_xDocumentProperties->setEditingCycles(nParam); + break; + case RTF_VERN: + // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers. + break; + case RTF_FTNSTART: + putNestedSprm(m_aDefaultState.getParagraphSprms(), + NS_ooxml::LN_EG_SectPrContents_footnotePr, + NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue); + break; + case RTF_AFTNSTART: + putNestedSprm(m_aDefaultState.getParagraphSprms(), + NS_ooxml::LN_EG_SectPrContents_endnotePr, + NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue); + break; + case RTF_DFRMTXTX: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam); + break; + case RTF_DFRMTXTY: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam); + break; + case RTF_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 RTF_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 RTF_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 RTF_FLYANCHOR: + break; + case RTF_WMETAFILE: + m_aStates.top().getPicture().eWMetafile = nParam; + break; + case RTF_SB: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, + NS_ooxml::LN_CT_Spacing_before, pIntValue); + break; + case RTF_SA: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, + NS_ooxml::LN_CT_Spacing_after, pIntValue); + break; + case RTF_DPX: + m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam)); + break; + case RTF_DPY: + m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam)); + break; + case RTF_DPXSIZE: + m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam)); + break; + case RTF_DPYSIZE: + m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam)); + break; + case RTF_PNSTART: + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue); + break; + case RTF_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 RTF_VIEWSCALE: + m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue); + break; + case RTF_BIN: + { + m_aStates.top().setInternalState(RTFInternalState::BIN); + m_aStates.top().setBinaryToRead(nParam); + } + break; + case RTF_DPLINECOR: + m_aStates.top().getDrawingObject().setLineColorR(nParam); + m_aStates.top().getDrawingObject().setHasLineColor(true); + break; + case RTF_DPLINECOG: + m_aStates.top().getDrawingObject().setLineColorG(nParam); + m_aStates.top().getDrawingObject().setHasLineColor(true); + break; + case RTF_DPLINECOB: + m_aStates.top().getDrawingObject().setLineColorB(nParam); + m_aStates.top().getDrawingObject().setHasLineColor(true); + break; + case RTF_DPFILLBGCR: + m_aStates.top().getDrawingObject().setFillColorR(nParam); + m_aStates.top().getDrawingObject().setHasFillColor(true); + break; + case RTF_DPFILLBGCG: + m_aStates.top().getDrawingObject().setFillColorG(nParam); + m_aStates.top().getDrawingObject().setHasFillColor(true); + break; + case RTF_DPFILLBGCB: + m_aStates.top().getDrawingObject().setFillColorB(nParam); + m_aStates.top().getDrawingObject().setHasFillColor(true); + break; + case RTF_DODHGT: + m_aStates.top().getDrawingObject().setDhgt(nParam); + break; + case RTF_DPPOLYCOUNT: + if (nParam >= 0) + { + m_aStates.top().getDrawingObject().setPolyLineCount(nParam); + } + break; + case RTF_DPPTX: + { + RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject(); + + if (rDrawingObject.getPolyLinePoints().empty()) + dispatchValue(RTF_DPPOLYCOUNT, 2); + + rDrawingObject.getPolyLinePoints().emplace_back( + awt::Point(convertTwipToMm100(nParam), 0)); + } + break; + case RTF_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 RTF_SHPFBLWTXT: + // Shape is below text -> send it to the background. + m_aStates.top().getShape().setInBackground(nParam != 0); + break; + case RTF_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 RTF_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 RTF_RI: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_right, pIntValue); + break; + case RTF_LIN: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_start, pIntValue); + break; + case RTF_RIN: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_end, pIntValue); + break; + case RTF_OUTLINELEVEL: + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue); + break; + case RTF_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 RTF_DIBITMAP: + m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP; + break; + case RTF_TRWWIDTHA: + m_aStates.top().setTableRowWidthAfter(nParam); + break; + case RTF_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 RTF_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 RTF_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; + 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..f470ac552 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdocumentimpl.cxx @@ -0,0 +1,3853 @@ +/* -*- 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 <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 <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" + +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 = rString.copy(0, 4).toInt32(); + + if (nLen >= 8 && rString.match(". ", 4)) + { + aRet.Month = rString.copy(6, 2).toInt32(); + + if (nLen >= 12 && rString.match(". ", 8)) + aRet.Day = rString.copy(10, 2).toInt32(); + } + } + 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 }; + + 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); + if (pAttributes) + pAttributes->set(nId, pValue); +} + +OString DTTM22OString(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_nCurrentStyleIndex(0) + , m_bFormField(false) + , m_bMathNor(false) + , m_bIgnoreNextContSectBreak(false) + , m_nResetBreakOnSectBreak(RTF_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->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() +{ + 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(aSettingsTableEntries); + Mapper().table(NS_ooxml::LN_settings_settings, pTable); +} + +void RTFDocumentImpl::checkFirstRun() +{ + if (m_bFirstRun) + { + 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 + RTFValue::Pointer_t pFont + = getNestedAttribute(m_aDefaultState.getCharacterSprms(), + NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii); + RTFValue::Pointer_t pCurrentFont + = getNestedAttribute(m_aStates.top().getCharacterSprms(), + NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii); + if (pFont && !pCurrentFont) + putNestedAttribute(m_aStates.top().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_aStyleTableEntries.find(nStyle); + if (it != m_aStyleTableEntries.end()) + { + // cloneAndDeduplicate() wants to know about only a single "style", so + // let's merge paragraph and character style properties here. + auto itChar = m_aStyleTableEntries.end(); + if (!m_aStates.empty()) + { + int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex(); + itChar = m_aStyleTableEntries.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_aStyleTableEntries.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 const sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true, &aSprms)); + RTFSprms const attributes( + rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true)); + return new RTFReferenceProperties(attributes, sprms); + } + + if (pAbstractList) + aSprms.duplicateList(pAbstractList); + writerfilter::Reference<Properties>::Pointer_t pRet + = new RTFReferenceProperties(rAttributes, aSprms); + return pRet; +} + +void RTFDocumentImpl::checkNeedPap() +{ + if (m_bNeedPap) + { + 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(RTF_PAR); + m_bNeedPap = false; + } + Mapper().props(pParagraphProperties); + if (hasBreakBeforeFrame) + dispatchSymbol(RTF_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", + OSL_THIS_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() + == static_cast<sal_Int32>(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(RTF_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(RTF_PARD); + dispatchSymbol(RTF_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(aAttributes, 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; + 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(); + } + + // Wrap it in an XShape. + uno::Reference<drawing::XShape> xShape(rShape); + 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 RTF_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::makeAny(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<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<long>(m_aStates.top().getPicture().nScaleY) + * (nYExt + - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB))) + / 100L; + if (m_aStates.top().getInShape()) + { + // Picture in shape: it looks like pib picture, so we will stretch the picture to shape size (tdf#49893) + nXExt = m_aStates.top().getShape().getRight() - m_aStates.top().getShape().getLeft(); + nYExt = m_aStates.top().getShape().getBottom() - m_aStates.top().getShape().getTop(); + } + 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); + } + writerfilter::Reference<Properties>::Pointer_t pProperties + = new RTFReferenceProperties(aAttributes, aSprms); + checkFirstRun(); + + if (!m_aStates.top().getCurrentBuffer()) + { + 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(RTF_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(); + // Should we send run properties? + if (bRunProps) + runProps(); + Mapper().text(sValue, 1); + Mapper().endCharacterGroup(); + } + else + { + pCurrentBuffer->push_back(Buf_t(BUFFER_STARTRUN, nullptr, nullptr)); + 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::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 fonttbl there may or may not be groups; in stylesheet + // and revtbl groups are mandatory + case Destination::FONTTABLE: + case Destination::FONTENTRY: + 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::FONTTABLE: + case Destination::FONTENTRY: + { + m_aFontNames[m_nCurrentFontIndex] = aName; + 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(aName)); + + 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)); + } + break; + 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_aStyleTableEntries.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::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( + Buf_t(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. + m_aStates.top().getShape() = std::get<1>(aTuple)->getShape(); + + m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), true, RTFSdrImport::SHAPE); + 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) +{ + for (auto& rProperty : rProperties) + { + if (rProperty.Name == rName) + return true; + } + return false; +} + +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 RTF_UL: + nSprm = NS_ooxml::LN_Value_ST_Underline_single; + break; + case RTF_ULDASH: + nSprm = NS_ooxml::LN_Value_ST_Underline_dash; + break; + case RTF_ULDASHD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash; + break; + case RTF_ULDASHDD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash; + break; + case RTF_ULDB: + nSprm = NS_ooxml::LN_Value_ST_Underline_double; + break; + case RTF_ULHWAVE: + nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy; + break; + case RTF_ULLDASH: + nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong; + break; + case RTF_ULTH: + nSprm = NS_ooxml::LN_Value_ST_Underline_thick; + break; + case RTF_ULTHD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy; + break; + case RTF_ULTHDASH: + nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy; + break; + case RTF_ULTHDASHD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy; + break; + case RTF_ULTHDASHDD: + nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy; + break; + case RTF_ULTHLDASH: + nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy; + break; + case RTF_ULULDBWAVE: + nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble; + break; + case RTF_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 RTF_ACCNONE: + nSprm = NS_ooxml::LN_Value_ST_Em_none; + break; + case RTF_ACCDOT: + nSprm = NS_ooxml::LN_Value_ST_Em_dot; + break; + case RTF_ACCCOMMA: + nSprm = NS_ooxml::LN_Value_ST_Em_comma; + break; + case RTF_ACCCIRCLE: + nSprm = NS_ooxml::LN_Value_ST_Em_circle; + break; + case RTF_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 RTF_B: + case RTF_AB: + switch (m_aStates.top().getRunType()) + { + case RTFParserState::RunType::HICH: + case RTFParserState::RunType::RTLCH_LTRCH_1: + case RTFParserState::RunType::LTRCH_RTLCH_2: + case RTFParserState::RunType::DBCH: + 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: + default: + nSprm = NS_ooxml::LN_EG_RPrBase_b; + break; + } + break; + case RTF_I: + case RTF_AI: + switch (m_aStates.top().getRunType()) + { + case RTFParserState::RunType::HICH: + case RTFParserState::RunType::RTLCH_LTRCH_1: + case RTFParserState::RunType::LTRCH_RTLCH_2: + case RTFParserState::RunType::DBCH: + 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: + default: + nSprm = NS_ooxml::LN_EG_RPrBase_i; + break; + } + break; + case RTF_OUTL: + nSprm = NS_ooxml::LN_EG_RPrBase_outline; + break; + case RTF_SHAD: + nSprm = NS_ooxml::LN_EG_RPrBase_shadow; + break; + case RTF_V: + nSprm = NS_ooxml::LN_EG_RPrBase_vanish; + break; + case RTF_STRIKE: + nSprm = NS_ooxml::LN_EG_RPrBase_strike; + break; + case RTF_STRIKED: + nSprm = NS_ooxml::LN_EG_RPrBase_dstrike; + break; + case RTF_SCAPS: + nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps; + break; + case RTF_IMPR: + nSprm = NS_ooxml::LN_EG_RPrBase_imprint; + break; + case RTF_CAPS: + nSprm = NS_ooxml::LN_EG_RPrBase_caps; + break; + default: + break; + } + if (nSprm >= 0) + { + m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue); + return RTFError::OK; + } + + switch (nKeyword) + { + case RTF_ASPALPHA: + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE, + pBoolValue); + break; + case RTF_DELETED: + case RTF_REVISED: + { + auto pValue = new RTFValue(nKeyword == RTF_DELETED ? oox::XML_del : oox::XML_ins); + putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange, + NS_ooxml::LN_token, pValue); + } + break; + case RTF_SBAUTO: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, + NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue); + break; + case RTF_SAAUTO: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, + NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue); + break; + case RTF_FACINGP: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue); + break; + case RTF_HYPHAUTO: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue); + break; + case RTF_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", OSL_THIS_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_aStyleTableEntries, 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_aStyleTableEntries) + { + auto pStyle = it.second; + // 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()); + auto const itParent(m_aStyleTableEntries.find(nBasedOn)); // definition as read! + if (itParent != m_aStyleTableEntries.end()) + { + auto const pStyleType( + static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find( + NS_ooxml::LN_CT_Style_type)); + assert(pStyleType); + int const nStyleType(pStyleType->getInt()); + RTFSprms const sprms( + static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate( + static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(), + nStyleType)); + RTFSprms const attributes( + static_cast<RTFReferenceProperties&>(*pStyle) + .getAttributes() + .cloneAndDeduplicate( + static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(), + nStyleType)); + + pStyle = new RTFReferenceProperties(attributes, sprms); + } + else + { + SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn); + } + } + ret[it.first] = pStyle; + } + assert(ret.size() == m_aStyleTableEntries.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, + const OUString& 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()) + { + case 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 const pStyleTableDeduplicated(deduplicateStyleTable()); + writerfilter::Reference<Table>::Pointer_t const pTable( + new RTFReferenceTable(pStyleTableDeduplicated)); + Mapper().table(NS_ooxml::LN_STYLESHEET, pTable); + } + break; + case Destination::LISTOVERRIDETABLE: + { + RTFSprms aListTableAttributes; + writerfilter::Reference<Properties>::Pointer_t pProp + = new RTFReferenceProperties(aListTableAttributes, m_aListTableSprms); + RTFReferenceTable::Entries_t aListTableEntries; + aListTableEntries.insert(std::make_pair(0, pProp)); + writerfilter::Reference<Table>::Pointer_t const pTable( + new RTFReferenceTable(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(aFFAttributes, aFFSprms); + Mapper().props(pProperties); + } + else + { + auto pFFValue = new RTFValue(aFFAttributes, aFFSprms); + bufferProperties(*m_aStates.top().getCurrentBuffer(), pFFValue, nullptr); + } + m_aFormfieldAttributes.clear(); + m_aFormfieldSprms.clear(); + singleChar(cFieldSep); + } + break; + case Destination::FIELDRESULT: + singleChar(cFieldEnd); + + if (!m_aPicturePath.isEmpty()) + { + // Read the picture into m_aStates.top().aDestinationText. + pushState(); + dispatchDestination(RTF_PICT); + if (m_aPicturePath.endsWith(".png")) + dispatchFlag(RTF_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(OUString::number(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... + OUString const field((Destination::INDEXENTRY == rState.getDestination()) + ? OUStringLiteral("XE") + : OUStringLiteral("TC")); + str = 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()); + m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue); + } + 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 + = uno::makeAny(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 RTF_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(aObjAttributes, aObjSprms); + uno::Reference<drawing::XShape> xShape; + RTFValue::Pointer_t pShape = m_aObjectAttributes.find(NS_ooxml::LN_shape); + OSL_ASSERT(pShape.get()); + 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(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); + writerfilter::Reference<Properties>::Pointer_t pProperties + = new RTFReferenceProperties(aAttributes); + if (!m_aStates.top().getCurrentBuffer()) + { + 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(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::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + + if (bTextFrame) + { + xPropertySet->setPropertyValue("HoriOrientPosition", + uno::makeAny(rDrawing.getLeft())); + xPropertySet->setPropertyValue("VertOrientPosition", + uno::makeAny(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 = uno::makeAny(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::makeAny(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::makeAny(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(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(aListTableAttributes, aListTableSprms); + + RTFReferenceTable::Entries_t aListTableEntries; + aListTableEntries.insert(std::make_pair(0, pProp)); + writerfilter::Reference<Table>::Pointer_t const pTable( + new RTFReferenceTable(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); + putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr, + NS_ooxml::LN_CT_NumPr_numId, pIdValue); + } + } + 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::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", OSL_THIS_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(RTF_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(), 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(RTF_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 RTF_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 != RTF_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(OUString const& 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.toString(), 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_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(-1) + , 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( + Buf_t(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()), nullptr)); + rBuffer.emplace_back(Buf_t(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..64bd15d76 --- /dev/null +++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx @@ -0,0 +1,988 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFDOCUMENTIMPL_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFDOCUMENTIMPL_HXX + +#include <memory> +#include <queue> +#include <tuple> +#include <vector> +#include <optional> + +#include <com/sun/star/text/WrapTextMode.hpp> +#include <oox/mathml/importutils.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <tools/color.hxx> + +#include <rtftok/RTFDocument.hxx> +#include "rtfreferencetable.hxx" +#include "rtfsprm.hxx" +#include "rtflistener.hxx" + +class SvStream; +namespace oox +{ +class GraphicHelper; +} +namespace com +{ +namespace sun +{ +namespace star +{ +namespace beans +{ +class XPropertySet; +} +namespace document +{ +class XDocumentProperties; +} +namespace lang +{ +class XMultiServiceFactory; +} +} +} +} + +namespace writerfilter +{ +namespace 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(const OUString& 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 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; } + +private: + RTFDocumentImpl* m_pDocumentImpl; + RTFInternalState m_nInternalState; + Destination m_eDestination; + RTFFieldStatus m_eFieldStatus; + 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; +}; + +/// 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 std::out_of_range("empty rtf state stack"); + return m_Impl.back(); + } + void pop() + { + if (m_Impl.empty()) + throw std::out_of_range("empty rtf state stack"); + 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(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(OUString const& 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 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; + + RTFReferenceTable::Entries_t m_aStyleTableEntries; + 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFDOCUMENTIMPL_HXX + +/* 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..9f94720d0 --- /dev/null +++ b/writerfilter/source/rtftok/rtffly.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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFFLY_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFFLY_HXX + +#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 +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFFLY_HXX + +/* 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..e35c0cccf --- /dev/null +++ b/writerfilter/source/rtftok/rtflistener.hxx @@ -0,0 +1,75 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFLISTENER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFLISTENER_HXX + +#include "rtfcontrolwords.hxx" + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFLISTENER_HXX + +/* 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..d3a84683d --- /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 == RTF_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 == RTF_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..52a4b3b14 --- /dev/null +++ b/writerfilter/source/rtftok/rtflookahead.hxx @@ -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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFLOOKAHEAD_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFLOOKAHEAD_HXX + +#include <sal/types.h> +#include <tools/ref.hxx> +#include "rtflistener.hxx" + +class SvStream; + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFLOOKAHEAD_HXX + +/* 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..d5121b26a --- /dev/null +++ b/writerfilter/source/rtftok/rtfreferenceproperties.hxx @@ -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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFREFERENCEPROPERTIES_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFREFERENCEPROPERTIES_HXX + +#include "rtfsprm.hxx" + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFREFERENCEPROPERTIES_HXX + +/* 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..ffa9eddae --- /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 (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..8c9595493 --- /dev/null +++ b/writerfilter/source/rtftok/rtfreferencetable.hxx @@ -0,0 +1,38 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFREFERENCETABLE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFREFERENCETABLE_HXX + +#include <map> +#include <dmapper/resourcemodel.hxx> + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFREFERENCETABLE_HXX + +/* 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..ef2c92afa --- /dev/null +++ b/writerfilter/source/rtftok/rtfsdrimport.cxx @@ -0,0 +1,1151 @@ +/* -*- 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 <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/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/propertyvalue.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 <boost/logic/tribool.hpp> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <svx/unoapi.hxx> +#include <svx/svdobj.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::makeAny(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::makeAny(aBorderLine)); + } + } +} + +void RTFSdrImport::resolveFLine(uno::Reference<beans::XPropertySet> const& xPropertySet, + sal_Int32 const nFLine) +{ + if (nFLine == 0) + xPropertySet->setPropertyValue("LineStyle", uno::makeAny(drawing::LineStyle_NONE)); + else + xPropertySet->setPropertyValue("LineStyle", uno::makeAny(drawing::LineStyle_SOLID)); +} + +void RTFSdrImport::applyProperty(uno::Reference<drawing::XShape> const& xShape, + const OUString& aKey, const OUString& aValue) const +{ + uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY); + sal_Int16 nHoriOrient = 0; + sal_Int16 nVertOrient = 0; + boost::logic::tribool obFitShapeToText(boost::logic::indeterminate); + bool bFilled = true; + + if (aKey == "posh") + { + switch (aValue.toInt32()) + { + 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 == "posv") + { + switch (aValue.toInt32()) + { + 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 == "fFitShapeToText") + obFitShapeToText = aValue.toInt32() == 1; + else if (aKey == "fFilled") + bFilled = aValue.toInt32() == 1; + else if (aKey == "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 = aValue.toInt32() * 100 / RTF_MULTIPLIER; + uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY); + if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame")) + xPropertySet->setPropertyValue( + "RotateAngle", + uno::makeAny(sal_Int32(NormAngle36000(static_cast<long>(nRotation) * -1)))); + } + + if (nHoriOrient != 0 && xPropertySet.is()) + xPropertySet->setPropertyValue("HoriOrient", uno::makeAny(nHoriOrient)); + if (nVertOrient != 0 && xPropertySet.is()) + xPropertySet->setPropertyValue("VertOrient", uno::makeAny(nVertOrient)); + if (!boost::logic::indeterminate(obFitShapeToText) && xPropertySet.is()) + { + xPropertySet->setPropertyValue( + "SizeType", uno::makeAny(obFitShapeToText ? text::SizeType::MIN : text::SizeType::FIX)); + xPropertySet->setPropertyValue("FrameIsAutomaticHeight", + uno::makeAny(static_cast<bool>(obFitShapeToText))); + } + if (!bFilled && xPropertySet.is()) + { + if (m_bTextFrame) + xPropertySet->setPropertyValue("BackColorTransparency", uno::makeAny(sal_Int32(100))); + else + xPropertySet->setPropertyValue("FillStyle", uno::makeAny(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::makeAny(sal_uInt32(0xffffff))); // White in Word, kind of blue in Writer. + o_xPropSet->setPropertyValue("VertOrient", uno::makeAny(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 = uno::makeAny(COL_BLACK); + // Default line width is 0.75 pt (26 mm100) in Word, 0 in Writer. + uno::Any aLineWidth = uno::makeAny(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; + boost::logic::tribool obRelFlipV(boost::logic::indeterminate); + boost::logic::tribool obFlipH(boost::logic::indeterminate); + boost::logic::tribool obFlipV(boost::logic::indeterminate); + + OUString aShapeText = ""; + OUString aFontFamily = ""; + float nFontSize = 1.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::makeAny(rProperty.second)); + } + else if (rProperty.first == "wzDescription") + xPropertySet->setPropertyValue("Description", uno::makeAny(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( + "#" + OUString::fromUtf8(msfilter::util::ConvertColor(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("#" + + OUString::fromUtf8(msfilter::util::ConvertColor( + 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 + { + OUString aToken = rProperty.second.getToken(0, ';', nCharIndex); + if (!nSize) + nSize = aToken.toInt32(); + else if (!nCount) + nCount = aToken.toInt32(); + else if (aToken.getLength()) + { + // The coordinates are in an (x,y) form. + aToken = aToken.copy(1, aToken.getLength() - 2); + sal_Int32 nI = 0; + sal_Int32 nX = aToken.getToken(0, ',', nI).toInt32(); + sal_Int32 nY = (nI >= 0) ? aToken.getToken(0, ',', nI).toInt32() : 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 = rProperty.second.getToken(0, ';', nCharIndex).toInt32(); + 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::makeAny(rProperty.second.toInt32() / 360)); + } + else if (rProperty.first == "dyTextTop") + { + if (xPropertySet.is()) + xPropertySet->setPropertyValue("TopBorderDistance", + uno::makeAny(rProperty.second.toInt32() / 360)); + } + else if (rProperty.first == "dxTextRight") + { + if (xPropertySet.is()) + xPropertySet->setPropertyValue("RightBorderDistance", + uno::makeAny(rProperty.second.toInt32() / 360)); + } + else if (rProperty.first == "dyTextBottom") + { + if (xPropertySet.is()) + xPropertySet->setPropertyValue("BottomBorderDistance", + uno::makeAny(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::makeAny(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::makeAny(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::makeAny(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::makeAny(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("#" + + OUString::fromUtf8(msfilter::util::ConvertColor( + 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; + sal_Int16 const nVertOrient = text::VertOrientation::CENTER; + if (xPropertySet.is()) + { + xPropertySet->setPropertyValue("VertOrient", uno::makeAny(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::makeAny(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 + { + OUString aToken = rProperty.second.getToken(0, ';', nCharIndex); + if (!nSize) + nSize = aToken.toInt32(); + else if (!nCount) + nCount = aToken.toInt32(); + else if (aToken.getLength()) + { + // The coordinates are in an (x,y) form. + aToken = aToken.copy(1, aToken.getLength() - 2); + sal_Int32 nI = 0; + sal_Int32 nX = aToken.getToken(0, ',', nI).toInt32(); + sal_Int32 nY = (nI >= 0) ? aToken.getToken(0, ',', nI).toInt32() : 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 + 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::makeAny(eWritingMode)); + else + // Only Writer textframes implement text::WritingMode2. + xPropertySet->setPropertyValue("TextWritingMode", + uno::makeAny(text::WritingMode(eWritingMode))); + } + + if (!m_aParents.empty() && m_aParents.top().is() && !m_bTextFrame) + m_aParents.top()->add(xShape); + + 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 == true && xPropertySet.is()) + xPropertySet->setPropertyValue("IsMirrored", uno::makeAny(true)); + return; + } + + 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::makeAny(aFontFamily)); + xPropertySet->setPropertyValue("CharHeight", uno::makeAny(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::makeAny(true) }, + })); + aCustomShapeGeometry["TextPath"] <<= aSequence; + xPropertySet->setPropertyValue("TextAutoGrowHeight", uno::makeAny(false)); + xPropertySet->setPropertyValue("TextAutoGrowWidth", uno::makeAny(false)); + bChanged = true; + } + + if (bChanged) + { + xPropertySet->setPropertyValue( + "CustomShapeGeometry", + uno::makeAny(aCustomShapeGeometry.getAsConstPropertyValueList())); + } + } + + if (!boost::logic::indeterminate(obRelFlipV) && 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[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); + for (sal_Int32 i = 0; i < rPolygon.getLength(); ++i) + { + basegfx::B2DPoint aPoint(aPoly.getB2DPoint(i)); + rPolygon[i] + = awt::Point(static_cast<sal_Int32>(convertMm100ToTwip(aPoint.getX())), + static_cast<sal_Int32>(convertMm100ToTwip(aPoint.getY()))); + } + xPropertySet->setPropertyValue("PolyPolygon", uno::makeAny(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::makeAny(nLeft)); + xPropertySet->setPropertyValue("VertOrientPosition", uno::makeAny(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 == true || obFlipV == true) + { + 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 == true) + aCustomShapeGeometry["MirroredX"] <<= true; + if (obFlipV == true) + aCustomShapeGeometry["MirroredY"] <<= true; + xPropertySet->setPropertyValue( + "CustomShapeGeometry", + uno::makeAny(aCustomShapeGeometry.getAsConstPropertyValueList())); + } + else if (SdrObject* pObject = GetSdrObjectFromXShape(xShape)) + { + Point aRef1 = pObject->GetSnapRect().Center(); + Point aRef2(aRef1); + if (obFlipH == true) + { + // Horizontal mirror means a vertical reference line. + aRef2.AdjustY(1); + } + if (obFlipV == true) + { + // Vertical mirror means a horizontal reference line. + aRef2.AdjustX(1); + } + pObject->Mirror(aRef1, aRef2); + } + } + + if (rShape.getHoriOrientRelation() != 0) + xPropertySet->setPropertyValue("HoriOrientRelation", + uno::makeAny(rShape.getHoriOrientRelation())); + if (rShape.getVertOrientRelation() != 0) + xPropertySet->setPropertyValue("VertOrientRelation", + uno::makeAny(rShape.getVertOrientRelation())); + if (rShape.getWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE) + xPropertySet->setPropertyValue("Surround", uno::makeAny(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::makeAny(text::TextContentAnchorType_AT_CHARACTER)); + xPropertySet->setPropertyValue("Opaque", uno::makeAny(bOpaque)); + if (oRelativeWidth) + { + xPropertySet->setPropertyValue("RelativeWidth", uno::makeAny(*oRelativeWidth)); + xPropertySet->setPropertyValue("RelativeWidthRelation", + uno::makeAny(nRelativeWidthRelation)); + } + if (oRelativeHeight) + { + xPropertySet->setPropertyValue("RelativeHeight", uno::makeAny(*oRelativeHeight)); + xPropertySet->setPropertyValue("RelativeHeightRelation", + uno::makeAny(nRelativeHeightRelation)); + } + } + + 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(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(const OUString& aKey, const OUString& aValue) +{ + applyProperty(m_xShape, aKey, aValue); +} + +void RTFSdrImport::appendGroupProperty(const OUString& aKey, const OUString& 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..474966d28 --- /dev/null +++ b/writerfilter/source/rtftok/rtfsdrimport.hxx @@ -0,0 +1,115 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSDRIMPORT_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSDRIMPORT_HXX + +#include <stack> +#include <vector> + +#include <dmapper/GraphicZOrderHelper.hxx> +#include <tools/ref.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace beans +{ +class XPropertySet; +struct PropertyValue; +} +namespace drawing +{ +class XShape; +class XShapes; +} +namespace lang +{ +class XComponent; +} +} +} +} + +namespace writerfilter +{ +namespace 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(const OUString& aKey, const OUString& aValue); + /// Append property on the current parent. + void appendGroupProperty(const OUString& aKey, const OUString& 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, + const OUString& aKey, const OUString& 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSDRIMPORT_HXX + +/* 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..47ada340e --- /dev/null +++ b/writerfilter/source/rtftok/rtfskipdestination.cxx @@ -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/. + */ + +#include "rtfskipdestination.hxx" +#include <osl/diagnose.h> +#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", OSL_THIS_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..8f8c6aa9d --- /dev/null +++ b/writerfilter/source/rtftok/rtfskipdestination.hxx @@ -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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSKIPDESTINATION_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSKIPDESTINATION_HXX + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSKIPDESTINATION_HXX + +/* 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..5c2edbb1c --- /dev/null +++ b/writerfilter/source/rtftok/rtfsprm.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/. + */ + +#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 || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character) + { + switch (id) + { + case NS_ooxml::LN_EG_RPrBase_b: + return new RTFValue(0); + 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); + + default: + break; + } + } + + return RTFValue::Pointer_t(); +} + +/// Is it problematic to deduplicate this SPRM? +static bool isSPRMDeduplicateBlacklist(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 (!isSPRMDeduplicateBlacklist(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..bb4f7c790 --- /dev/null +++ b/writerfilter/source/rtftok/rtfsprm.hxx @@ -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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSPRM_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSPRM_HXX + +#include <string> +#include <utility> +#include <vector> +#include <map> + +#include <tools/ref.hxx> +#include "rtfvalue.hxx" + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFSPRM_HXX + +/* 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..5f5782cea --- /dev/null +++ b/writerfilter/source/rtftok/rtftokenizer.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/. + */ + +#include "rtftokenizer.hxx" +#include <tools/stream.hxx> +#include <svx/dialmgr.hxx> +#include <svx/strings.hrc> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.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 <osl/diagnose.h> +#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", OSL_THIS_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", OSL_THIS_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", OSL_THIS_FUNC << ": hex internal state"); + 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; + OStringBuffer aBuf(32); + bool bNeg = false; + bool bParam = false; + int nParam = 0; + + Strm().ReadChar(ch); + if (Strm().eof()) + return RTFError::UNEXPECTED_EOF; + + if (!rtl::isAsciiAlpha(static_cast<unsigned char>(ch))) + { + aBuf.append(ch); + OString aKeyword = aBuf.makeStringAndClear(); + // control symbols aren't followed by a space, so we can return here + // without doing any SeekRel() + return dispatchKeyword(aKeyword, bParam, nParam); + } + 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; + } + } + + 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; + } + 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", OSL_THIS_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", OSL_THIS_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 CONTROL_FLAG: + // flags ignore any parameter by definition + ret = m_rImport.dispatchFlag(rSymbol.GetIndex()); + if (ret != RTFError::OK) + return ret; + break; + case CONTROL_DESTINATION: + // same for destinations + ret = m_rImport.dispatchDestination(rSymbol.GetIndex()); + if (ret != RTFError::OK) + return ret; + break; + case CONTROL_SYMBOL: + // and symbols + ret = m_rImport.dispatchSymbol(rSymbol.GetIndex()); + if (ret != RTFError::OK) + return ret; + break; + case CONTROL_TOGGLE: + ret = m_rImport.dispatchToggle(rSymbol.GetIndex(), bParam, nParam); + if (ret != RTFError::OK) + return ret; + break; + case CONTROL_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() +{ + OUStringBuffer aRet; + aRet.append(m_nLineNumber + 1); + aRet.append(","); + aRet.append(sal_Int32(Strm().Tell() - m_nLineStartPos + 1)); + return aRet.makeStringAndClear(); +} + +} // 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..5c1cd1949 --- /dev/null +++ b/writerfilter/source/rtftok/rtftokenizer.hxx @@ -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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFTOKENIZER_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFTOKENIZER_HXX + +#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 +{ +namespace sun +{ +namespace star +{ +namespace task +{ +class XStatusIndicator; +} +} +} +} +class SvStream; + +namespace writerfilter +{ +namespace 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 rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFTOKENIZER_HXX + +/* 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..e4b3a5a11 --- /dev/null +++ b/writerfilter/source/rtftok/rtfvalue.cxx @@ -0,0 +1,210 @@ +/* -*- 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& rAttributes, const RTFSprms& rSprms, + uno::Reference<drawing::XShape> xShape, uno::Reference<io::XInputStream> xStream, + uno::Reference<embed::XEmbeddedObject> xObject, bool bForceString, + const RTFShape& aShape, const RTFPicture& rPicture) + : m_nValue(nValue) + , m_sValue(std::move(sValue)) + , m_pAttributes(new RTFSprms(rAttributes)) + , m_pSprms(new RTFSprms(rSprms)) + , m_xShape(std::move(xShape)) + , m_xStream(std::move(xStream)) + , m_xObject(std::move(xObject)) + , m_bForceString(bForceString) + , m_pShape(new RTFShape(aShape)) + , m_pPicture(new RTFPicture(rPicture)) +{ +} + +RTFValue::RTFValue() + : m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(int nValue) + : m_nValue(nValue) + , m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(OUString sValue, bool bForce) + : m_sValue(std::move(sValue)) + , m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_bForceString(bForce) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(const RTFSprms& rAttributes) + : m_pAttributes(new RTFSprms(rAttributes)) + , m_pSprms(new RTFSprms()) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms) + : m_pAttributes(new RTFSprms(rAttributes)) + , m_pSprms(new RTFSprms(rSprms)) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(uno::Reference<drawing::XShape> xShape) + : m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_xShape(std::move(xShape)) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(uno::Reference<io::XInputStream> xStream) + : m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_xStream(std::move(xStream)) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(uno::Reference<embed::XEmbeddedObject> xObject) + : m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_xObject(std::move(xObject)) + , m_pShape(new RTFShape()) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(const RTFShape& aShape) + : m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_pShape(new RTFShape(aShape)) + , m_pPicture(new RTFPicture) +{ +} + +RTFValue::RTFValue(const RTFPicture& rPicture) + : m_pAttributes(new RTFSprms()) + , m_pSprms(new RTFSprms()) + , m_pShape(new RTFShape()) + , 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 { return *m_pShape; } + +RTFPicture& RTFValue::getPicture() const { return *m_pPicture; } + +writerfilter::Reference<Properties>::Pointer_t RTFValue::getProperties() +{ + return new RTFReferenceProperties(*m_pAttributes, *m_pSprms); +} + +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() +{ + return new RTFValue(m_nValue, m_sValue, *m_pAttributes, *m_pSprms, m_xShape, m_xStream, + m_xObject, m_bForceString, *m_pShape, *m_pPicture); +} + +RTFValue* RTFValue::CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) +{ + return new RTFValue(m_nValue, m_sValue, rAttributes, rSprms, m_xShape, m_xStream, m_xObject, + m_bForceString, *m_pShape, *m_pPicture); +} + +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->size() != rOther.m_pAttributes->size()) + return false; + if (!m_pAttributes->equals(rOther)) + return false; + if (m_pSprms->size() != rOther.m_pSprms->size()) + return false; + if (!m_pSprms->equals(rOther)) + return false; + return true; +} + +RTFSprms& RTFValue::getAttributes() { return *m_pAttributes; } + +RTFSprms& RTFValue::getSprms() { 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..b1c22b0b9 --- /dev/null +++ b/writerfilter/source/rtftok/rtfvalue.hxx @@ -0,0 +1,96 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFVALUE_HXX +#define INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFVALUE_HXX + +#include <dmapper/resourcemodel.hxx> + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace embed +{ +class XEmbeddedObject; +} +namespace io +{ +class XInputStream; +} +} +} +} + +namespace writerfilter +{ +namespace rtftok +{ +class RTFSprms; +class RTFShape; +class RTFPicture; +/// Value of an RTF keyword +class RTFValue : public Value +{ +public: + using Pointer_t = tools::SvRef<RTFValue>; + RTFValue(int nValue, OUString sValue, const RTFSprms& rAttributes, const RTFSprms& rSprms, + 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& aShape, const RTFPicture& rPicture); + 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(); + RTFValue* CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms); + RTFSprms& getAttributes(); + RTFSprms& getSprms(); + 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; + tools::SvRef<RTFSprms> m_pAttributes; + 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; + tools::SvRef<RTFShape> m_pShape; + tools::SvRef<RTFPicture> m_pPicture; +}; +} // namespace rtftok +} // namespace writerfilter + +#endif // INCLUDED_WRITERFILTER_SOURCE_RTFTOK_RTFVALUE_HXX + +/* 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> |