summaryrefslogtreecommitdiff
path: root/sw/source
diff options
context:
space:
mode:
authorNoel Grandin <noelgrandin@gmail.com>2024-04-10 16:50:51 +0100
committerNoel Grandin <noel.grandin@collabora.co.uk>2024-04-18 09:16:12 +0200
commit828c1999e08c5bfad0a1d0e6e5ab07ee8bbc427e (patch)
tree65dfe08b2f389fd5b6d8a639fda2815815931b2e /sw/source
parent8e86df886f84fe69f13cfc367a5dd843e6ea917c (diff)
move writerfilter inside sw
writerfilter wants to convert incoming RTF and OOXML files into writer's document model. But it currently has to do so by manipulating the limited subset that we expose through the UNO API. This is both slower and less accurate than having access to the full document model. So move it inside, and then we can strip out various hacks, and optimise imports. Change-Id: Ie1114d28130ef5f9a786531bc552cb8ee7768015 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165953 Tested-by: Noel Grandin <noel.grandin@collabora.co.uk> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'sw/source')
-rw-r--r--sw/source/writerfilter/dmapper/BorderHandler.cxx243
-rw-r--r--sw/source/writerfilter/dmapper/BorderHandler.hxx86
-rw-r--r--sw/source/writerfilter/dmapper/CellColorHandler.cxx395
-rw-r--r--sw/source/writerfilter/dmapper/CellColorHandler.hxx79
-rw-r--r--sw/source/writerfilter/dmapper/CellMarginHandler.cxx177
-rw-r--r--sw/source/writerfilter/dmapper/CellMarginHandler.hxx64
-rw-r--r--sw/source/writerfilter/dmapper/ConversionHelper.cxx691
-rw-r--r--sw/source/writerfilter/dmapper/ConversionHelper.hxx60
-rw-r--r--sw/source/writerfilter/dmapper/DocumentProtection.cxx239
-rw-r--r--sw/source/writerfilter/dmapper/DocumentProtection.hxx88
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapper.cxx5049
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapper.hxx199
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapperTableHandler.cxx1778
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapperTableHandler.hxx121
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapperTableManager.cxx864
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapperTableManager.hxx172
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx9924
-rw-r--r--sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx1258
-rw-r--r--sw/source/writerfilter/dmapper/FFDataHandler.cxx190
-rw-r--r--sw/source/writerfilter/dmapper/FFDataHandler.hxx99
-rw-r--r--sw/source/writerfilter/dmapper/FieldTypes.hxx306
-rw-r--r--sw/source/writerfilter/dmapper/FontTable.cxx299
-rw-r--r--sw/source/writerfilter/dmapper/FontTable.hxx106
-rw-r--r--sw/source/writerfilter/dmapper/FormControlHelper.cxx379
-rw-r--r--sw/source/writerfilter/dmapper/FormControlHelper.hxx52
-rw-r--r--sw/source/writerfilter/dmapper/GraphicHelpers.cxx434
-rw-r--r--sw/source/writerfilter/dmapper/GraphicHelpers.hxx82
-rw-r--r--sw/source/writerfilter/dmapper/GraphicImport.cxx2118
-rw-r--r--sw/source/writerfilter/dmapper/GraphicImport.hxx140
-rw-r--r--sw/source/writerfilter/dmapper/LatentStyleHandler.cxx71
-rw-r--r--sw/source/writerfilter/dmapper/LatentStyleHandler.hxx35
-rw-r--r--sw/source/writerfilter/dmapper/LoggedResources.cxx401
-rw-r--r--sw/source/writerfilter/dmapper/LoggedResources.hxx147
-rw-r--r--sw/source/writerfilter/dmapper/MeasureHandler.cxx136
-rw-r--r--sw/source/writerfilter/dmapper/MeasureHandler.hxx60
-rw-r--r--sw/source/writerfilter/dmapper/ModelEventListener.cxx117
-rw-r--r--sw/source/writerfilter/dmapper/ModelEventListener.hxx40
-rw-r--r--sw/source/writerfilter/dmapper/NumberingManager.cxx1213
-rw-r--r--sw/source/writerfilter/dmapper/NumberingManager.hxx251
-rw-r--r--sw/source/writerfilter/dmapper/OLEHandler.cxx331
-rw-r--r--sw/source/writerfilter/dmapper/OLEHandler.hxx94
-rw-r--r--sw/source/writerfilter/dmapper/PageBordersHandler.cxx145
-rw-r--r--sw/source/writerfilter/dmapper/PageBordersHandler.hxx62
-rw-r--r--sw/source/writerfilter/dmapper/PropertyIds.cxx415
-rw-r--r--sw/source/writerfilter/dmapper/PropertyIds.hxx399
-rw-r--r--sw/source/writerfilter/dmapper/PropertyMap.cxx2170
-rw-r--r--sw/source/writerfilter/dmapper/PropertyMap.hxx651
-rw-r--r--sw/source/writerfilter/dmapper/PropertyMapHelper.cxx98
-rw-r--r--sw/source/writerfilter/dmapper/PropertyMapHelper.hxx34
-rw-r--r--sw/source/writerfilter/dmapper/SdtHelper.cxx647
-rw-r--r--sw/source/writerfilter/dmapper/SdtHelper.hxx255
-rw-r--r--sw/source/writerfilter/dmapper/SectionColumnHandler.cxx90
-rw-r--r--sw/source/writerfilter/dmapper/SectionColumnHandler.hxx62
-rw-r--r--sw/source/writerfilter/dmapper/SettingsTable.cxx800
-rw-r--r--sw/source/writerfilter/dmapper/SettingsTable.hxx113
-rw-r--r--sw/source/writerfilter/dmapper/SmartTagHandler.cxx127
-rw-r--r--sw/source/writerfilter/dmapper/SmartTagHandler.hxx60
-rw-r--r--sw/source/writerfilter/dmapper/StyleSheetTable.cxx1830
-rw-r--r--sw/source/writerfilter/dmapper/StyleSheetTable.hxx155
-rw-r--r--sw/source/writerfilter/dmapper/TDefTableHandler.cxx538
-rw-r--r--sw/source/writerfilter/dmapper/TDefTableHandler.hxx82
-rw-r--r--sw/source/writerfilter/dmapper/TableData.hxx419
-rw-r--r--sw/source/writerfilter/dmapper/TableManager.cxx686
-rw-r--r--sw/source/writerfilter/dmapper/TableManager.hxx527
-rw-r--r--sw/source/writerfilter/dmapper/TablePositionHandler.cxx160
-rw-r--r--sw/source/writerfilter/dmapper/TablePositionHandler.hxx71
-rw-r--r--sw/source/writerfilter/dmapper/TablePropertiesHandler.cxx398
-rw-r--r--sw/source/writerfilter/dmapper/TablePropertiesHandler.hxx94
-rw-r--r--sw/source/writerfilter/dmapper/TagLogger.cxx240
-rw-r--r--sw/source/writerfilter/dmapper/TagLogger.hxx70
-rw-r--r--sw/source/writerfilter/dmapper/TblStylePrHandler.cxx259
-rw-r--r--sw/source/writerfilter/dmapper/TblStylePrHandler.hxx82
-rw-r--r--sw/source/writerfilter/dmapper/TextEffectsHandler.cxx806
-rw-r--r--sw/source/writerfilter/dmapper/TextEffectsHandler.hxx69
-rw-r--r--sw/source/writerfilter/dmapper/ThemeColorHandler.hxx68
-rw-r--r--sw/source/writerfilter/dmapper/ThemeHandler.cxx423
-rw-r--r--sw/source/writerfilter/dmapper/ThemeHandler.hxx35
-rw-r--r--sw/source/writerfilter/dmapper/TrackChangesHandler.cxx88
-rw-r--r--sw/source/writerfilter/dmapper/TrackChangesHandler.hxx40
-rw-r--r--sw/source/writerfilter/dmapper/WrapPolygonHandler.cxx214
-rw-r--r--sw/source/writerfilter/dmapper/WrapPolygonHandler.hxx82
-rw-r--r--sw/source/writerfilter/dmapper/WriteProtection.cxx140
-rw-r--r--sw/source/writerfilter/dmapper/WriteProtection.hxx58
-rw-r--r--sw/source/writerfilter/dmapper/domainmapperfactory.cxx39
-rw-r--r--sw/source/writerfilter/dmapper/util.cxx70
-rw-r--r--sw/source/writerfilter/dmapper/util.hxx32
-rw-r--r--sw/source/writerfilter/filter/RtfFilter.cxx220
-rw-r--r--sw/source/writerfilter/filter/WriterFilter.cxx367
-rw-r--r--sw/source/writerfilter/inc/dmapper/CommentProperties.hxx31
-rw-r--r--sw/source/writerfilter/inc/dmapper/DomainMapperFactory.hxx48
-rw-r--r--sw/source/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx34
-rw-r--r--sw/source/writerfilter/inc/dmapper/resourcemodel.hxx420
-rw-r--r--sw/source/writerfilter/inc/ooxml/OOXMLDocument.hxx259
-rw-r--r--sw/source/writerfilter/inc/ooxml/QNameToString.hxx31
-rw-r--r--sw/source/writerfilter/inc/rtftok/RTFDocument.hxx46
-rw-r--r--sw/source/writerfilter/ooxml/Handler.cxx435
-rw-r--r--sw/source/writerfilter/ooxml/Handler.hxx179
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.cxx73
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.hxx43
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLDocumentImpl.cxx911
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLDocumentImpl.hxx171
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFactory.cxx179
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFactory.hxx109
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx2384
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx634
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.cxx71
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.hxx47
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.cxx146
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.hxx90
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLFastHelper.hxx61
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLParserState.cxx296
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLParserState.hxx130
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLPropertySet.cxx844
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLPropertySet.hxx415
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLStreamImpl.cxx449
-rw-r--r--sw/source/writerfilter/ooxml/OOXMLStreamImpl.hxx83
-rw-r--r--sw/source/writerfilter/ooxml/README13
-rw-r--r--sw/source/writerfilter/ooxml/factory_ns.py76
-rw-r--r--sw/source/writerfilter/ooxml/factoryimpl.py214
-rw-r--r--sw/source/writerfilter/ooxml/factoryimpl_ns.py755
-rw-r--r--sw/source/writerfilter/ooxml/factoryinc.py49
-rw-r--r--sw/source/writerfilter/ooxml/model.xml19426
-rw-r--r--sw/source/writerfilter/ooxml/modelpreprocess.py90
-rw-r--r--sw/source/writerfilter/ooxml/qnametostr.py64
-rw-r--r--sw/source/writerfilter/ooxml/resourceids.py60
-rw-r--r--sw/source/writerfilter/ooxml/tox.ini2
-rw-r--r--sw/source/writerfilter/rtftok/README12
-rw-r--r--sw/source/writerfilter/rtftok/rtfcharsets.cxx66
-rw-r--r--sw/source/writerfilter/rtftok/rtfcharsets.hxx37
-rw-r--r--sw/source/writerfilter/rtftok/rtfcontrolwords.cxx1900
-rw-r--r--sw/source/writerfilter/rtftok/rtfcontrolwords.hxx2049
-rw-r--r--sw/source/writerfilter/rtftok/rtfdispatchdestination.cxx684
-rw-r--r--sw/source/writerfilter/rtftok/rtfdispatchflag.cxx1381
-rw-r--r--sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx455
-rw-r--r--sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx1909
-rw-r--r--sw/source/writerfilter/rtftok/rtfdocumentfactory.cxx28
-rw-r--r--sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx4062
-rw-r--r--sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx995
-rw-r--r--sw/source/writerfilter/rtftok/rtffly.hxx138
-rw-r--r--sw/source/writerfilter/rtftok/rtflistener.hxx69
-rw-r--r--sw/source/writerfilter/rtftok/rtflookahead.cxx101
-rw-r--r--sw/source/writerfilter/rtftok/rtflookahead.hxx57
-rw-r--r--sw/source/writerfilter/rtftok/rtfreferenceproperties.cxx40
-rw-r--r--sw/source/writerfilter/rtftok/rtfreferenceproperties.hxx33
-rw-r--r--sw/source/writerfilter/rtftok/rtfreferencetable.cxx29
-rw-r--r--sw/source/writerfilter/rtftok/rtfreferencetable.hxx32
-rw-r--r--sw/source/writerfilter/rtftok/rtfsdrimport.cxx1186
-rw-r--r--sw/source/writerfilter/rtftok/rtfsdrimport.hxx104
-rw-r--r--sw/source/writerfilter/rtftok/rtfskipdestination.cxx42
-rw-r--r--sw/source/writerfilter/rtftok/rtfskipdestination.hxx33
-rw-r--r--sw/source/writerfilter/rtftok/rtfsprm.cxx487
-rw-r--r--sw/source/writerfilter/rtftok/rtfsprm.hxx101
-rw-r--r--sw/source/writerfilter/rtftok/rtftokenizer.cxx330
-rw-r--r--sw/source/writerfilter/rtftok/rtftokenizer.hxx72
-rw-r--r--sw/source/writerfilter/rtftok/rtfvalue.cxx231
-rw-r--r--sw/source/writerfilter/rtftok/rtfvalue.hxx91
156 files changed, 89200 insertions, 0 deletions
diff --git a/sw/source/writerfilter/dmapper/BorderHandler.cxx b/sw/source/writerfilter/dmapper/BorderHandler.cxx
new file mode 100644
index 000000000000..ed14194c2a01
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/BorderHandler.cxx
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "BorderHandler.hxx"
+#include "TDefTableHandler.hxx"
+#include "PropertyMap.hxx"
+#include "ConversionHelper.hxx"
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <o3tl/enumarray.hxx>
+#include <o3tl/enumrange.hxx>
+#include <ooxml/resourceids.hxx>
+#include <filter/msfilter/util.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/color.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+BorderHandler::BorderHandler( bool bOOXML ) :
+LoggedProperties("BorderHandler"),
+m_nLineWidth(15), // Word default, in twips
+m_nLineType(0),
+m_nLineColor(0),
+m_nLineDistance(0),
+m_bShadow(false),
+m_bOOXML( bOOXML )
+{
+ m_aFilledLines.fill(false);
+ m_aBorderLines.fill(table::BorderLine2());
+}
+
+BorderHandler::~BorderHandler()
+{
+}
+
+void BorderHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_Border_sz:
+ // width of a single line in 1/8 pt, max of 32 pt -> twip * 5 / 2.
+ m_nLineWidth = nIntValue * 5 / 2;
+ appendGrabBag("sz", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ m_nLineType = nIntValue;
+ appendGrabBag("val", TDefTableHandler::getBorderTypeString(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_color:
+ m_nLineColor = nIntValue;
+ appendGrabBag("color", msfilter::util::ConvertColorOU(Color(ColorTransparency, nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Border_space: // border distance in points
+ m_nLineDistance = ConversionHelper::convertTwipToMM100( nIntValue * 20 );
+ appendGrabBag("space", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ m_bShadow = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Border_frame:
+ appendGrabBag("frame", OUString::number(nIntValue, 16));
+ break;
+ case NS_ooxml::LN_CT_Border_themeTint:
+ m_nThemeTint = nIntValue;
+ appendGrabBag("themeTint", OUString::number(nIntValue, 16));
+ break;
+ case NS_ooxml::LN_CT_Border_themeShade:
+ m_nThemeShade = nIntValue;
+ appendGrabBag("themeShade", OUString::number(nIntValue, 16));
+ break;
+ case NS_ooxml::LN_CT_Border_themeColor:
+ m_eThemeColorType = TDefTableHandler::getThemeColorTypeIndex(nIntValue);
+ appendGrabBag("themeColor", TDefTableHandler::getThemeColorTypeString(nIntValue));
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+void BorderHandler::lcl_sprm(Sprm & rSprm)
+{
+ BorderPosition pos;
+ const bool rtl = false; // TODO detect
+ OUString aBorderPos;
+ switch( rSprm.getId())
+ {
+ case NS_ooxml::LN_CT_TblBorders_top:
+ pos = BorderPosition::Top;
+ aBorderPos = "top";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_start:
+ pos = rtl ? BorderPosition::Right : BorderPosition::Left;
+ aBorderPos = "start";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_left:
+ pos = BorderPosition::Left;
+ aBorderPos = "left";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_bottom:
+ pos = BorderPosition::Bottom;
+ aBorderPos = "bottom";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_end:
+ pos = rtl ? BorderPosition::Left : BorderPosition::Right;
+ aBorderPos = "end";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_right:
+ pos = BorderPosition::Right;
+ aBorderPos = "right";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_insideH:
+ pos = BorderPosition::Horizontal;
+ aBorderPos = "insideH";
+ break;
+ case NS_ooxml::LN_CT_TblBorders_insideV:
+ pos = BorderPosition::Vertical;
+ aBorderPos = "insideV";
+ break;
+ default:
+ return;
+ }
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties)
+ {
+ std::vector<beans::PropertyValue> aSavedGrabBag;
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ aSavedGrabBag = m_aInteropGrabBag;
+ m_aInteropGrabBag.clear();
+ }
+ pProperties->resolve(*this);
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ aSavedGrabBag.push_back(getInteropGrabBag(aBorderPos));
+ m_aInteropGrabBag = aSavedGrabBag;
+ }
+ }
+ ConversionHelper::MakeBorderLine( m_nLineWidth, m_nLineType, m_nLineColor,
+ m_aBorderLines[ pos ], m_bOOXML );
+ m_aFilledLines[ pos ] = true;
+}
+
+PropertyMapPtr BorderHandler::getProperties()
+{
+ static const o3tl::enumarray<BorderPosition, PropertyIds> aPropNames =
+ {
+ PROP_TOP_BORDER,
+ PROP_LEFT_BORDER,
+ PROP_BOTTOM_BORDER,
+ PROP_RIGHT_BORDER,
+ META_PROP_HORIZONTAL_BORDER,
+ META_PROP_VERTICAL_BORDER
+ };
+ PropertyMapPtr pPropertyMap(new PropertyMap);
+ // don't fill in default properties
+ if( m_bOOXML )
+ {
+ for( auto nProp: o3tl::enumrange<BorderPosition>())
+ {
+ if ( m_aFilledLines[nProp] ) {
+ pPropertyMap->Insert( aPropNames[nProp], uno::Any( m_aBorderLines[nProp] ) );
+ }
+ }
+ }
+ return pPropertyMap;
+}
+
+table::BorderLine2 BorderHandler::getBorderLine()
+{
+ table::BorderLine2 aBorderLine;
+ ConversionHelper::MakeBorderLine( m_nLineWidth, m_nLineType, m_nLineColor, aBorderLine, m_bOOXML );
+ return aBorderLine;
+}
+
+
+void BorderHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue BorderHandler::getInteropGrabBag(const OUString& aName)
+{
+ beans::PropertyValue aRet;
+ if (aName.isEmpty())
+ aRet.Name = m_aInteropGrabBagName;
+ else
+ aRet.Name = aName;
+
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+void BorderHandler::appendGrabBag(const OUString& aKey, const OUString& aValue)
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ m_aInteropGrabBag.push_back(aProperty);
+}
+
+model::ComplexColor BorderHandler::getComplexColor() const
+{
+ model::ComplexColor aComplexColor;
+ if (m_eThemeColorType == model::ThemeColorType::Unknown)
+ return aComplexColor;
+
+ aComplexColor.setThemeColor(m_eThemeColorType);
+
+ if (m_nThemeTint > 0 )
+ {
+ sal_Int16 nTint = sal_Int16((255.0 - m_nThemeTint) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Tint, nTint});
+ }
+ if (m_nThemeShade > 0)
+ {
+ sal_Int16 nShade = sal_Int16((255.0 - m_nThemeShade) * 10000 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Shade, nShade});
+ }
+
+ return aComplexColor;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/BorderHandler.hxx b/sw/source/writerfilter/dmapper/BorderHandler.hxx
new file mode 100644
index 000000000000..9a523bffc576
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/BorderHandler.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 .
+ */
+#pragma once
+
+#include <vector>
+#include "LoggedResources.hxx"
+#include "PropertyMap.hxx"
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <o3tl/enumarray.hxx>
+#include <docmodel/theme/ThemeColorType.hxx>
+#include <docmodel/color/ComplexColor.hxx>
+
+namespace writerfilter::dmapper
+{
+class PropertyMap;
+class BorderHandler : public LoggedProperties
+{
+private:
+ //todo: order is a guess
+ enum class BorderPosition
+ {
+ Top,
+ Left,
+ Bottom,
+ Right,
+ Horizontal,
+ Vertical,
+ LAST = Vertical
+ };
+
+ //values of the current border
+ sal_Int32 m_nLineWidth;
+ sal_Int32 m_nLineType;
+ sal_Int32 m_nLineColor;
+ sal_Int32 m_nLineDistance;
+ bool m_bShadow;
+ bool m_bOOXML;
+ model::ThemeColorType m_eThemeColorType = model::ThemeColorType::Unknown;
+ sal_Int32 m_nThemeShade = 0;
+ sal_Int32 m_nThemeTint = 0;
+
+ o3tl::enumarray<BorderPosition, bool> m_aFilledLines;
+ o3tl::enumarray<BorderPosition, css::table::BorderLine2> m_aBorderLines;
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+ void appendGrabBag(const OUString& aKey, const OUString& aValue);
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ explicit BorderHandler( bool bOOXML );
+ virtual ~BorderHandler() override;
+
+ PropertyMapPtr getProperties();
+ css::table::BorderLine2 getBorderLine();
+ sal_Int32 getLineDistance() const { return m_nLineDistance;}
+ sal_Int32 getLineType() const { return m_nLineType;}
+ bool getShadow() const { return m_bShadow;}
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag(const OUString& aName = OUString());
+
+ model::ComplexColor getComplexColor() const;
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/CellColorHandler.cxx b/sw/source/writerfilter/dmapper/CellColorHandler.cxx
new file mode 100644
index 000000000000..b99d40c08a12
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/CellColorHandler.cxx
@@ -0,0 +1,395 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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>
+#include <docmodel/uno/UnoComplexColor.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+CellColorHandler::CellColorHandler() :
+LoggedProperties("CellColorHandler"),
+m_nShadingPattern( drawing::ShadingPattern::CLEAR ),
+m_nColor( 0xffffffff ),
+m_nFillColor( 0xffffffff ),
+m_bAutoFillColor( true ),
+m_bFillSpecified( false ),
+ m_OutputFormat( Form )
+{
+}
+
+CellColorHandler::~CellColorHandler()
+{
+}
+
+// ST_Shd strings are converted to integers by the tokenizer, store strings in
+// the InteropGrabBag
+static uno::Any lcl_ConvertShd(sal_Int32 nIntValue)
+{
+ OUString aRet;
+ // This should be in sync with the ST_Shd list in ooxml's model.xml.
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Shd_clear: aRet = "clear"; break;
+ case NS_ooxml::LN_Value_ST_Shd_solid: aRet = "solid"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct5: aRet = "pct5"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct10: aRet = "pct10"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct20: aRet = "pct20"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct25: aRet = "pct25"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct30: aRet = "pct30"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct40: aRet = "pct40"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct50: aRet = "pct50"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct60: aRet = "pct60"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct70: aRet = "pct70"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct75: aRet = "pct75"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct80: aRet = "pct80"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct90: aRet = "pct90"; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzStripe: aRet = "horzStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_vertStripe: aRet = "vertStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_reverseDiagStripe: aRet = "reverseDiagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagStripe: aRet = "diagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzCross: aRet = "horzCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagCross: aRet = "diagCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzStripe: aRet = "thinHorzStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinVertStripe: aRet = "thinVertStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinReverseDiagStripe: aRet = "thinReverseDiagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagStripe: aRet = "thinDiagStripe"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzCross: aRet = "thinHorzCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagCross: aRet = "thinDiagCross"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct12: aRet = "pct12"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct15: aRet = "pct15"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct35: aRet = "pct35"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct37: aRet = "pct37"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct45: aRet = "pct45"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct55: aRet = "pct55"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct62: aRet = "pct62"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct65: aRet = "pct65"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct85: aRet = "pct85"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct87: aRet = "pct87"; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct95: aRet = "pct95"; break;
+ case NS_ooxml::LN_Value_ST_Shd_nil: aRet = "nil"; break;
+ }
+ return uno::Any(aRet);
+}
+
+void CellColorHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_Shd_val:
+ {
+ createGrabBag("val", lcl_ConvertShd(nIntValue));
+ m_nShadingPattern = nIntValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_Shd_fill:
+ createGrabBag("fill", uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, nIntValue))));
+ if( nIntValue == sal_Int32(COL_AUTO) )
+ nIntValue = 0xffffff; //fill color auto means white
+ else
+ m_bAutoFillColor = false;
+
+ m_nFillColor = nIntValue;
+ m_bFillSpecified = true;
+ break;
+ case NS_ooxml::LN_CT_Shd_color:
+ createGrabBag("color", uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, nIntValue))));
+ if( nIntValue == sal_Int32(COL_AUTO) )
+ nIntValue = 0; //shading color auto means black
+ //color of the shading
+ m_nColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Shd_themeFill:
+ m_eFillThemeColorType = TDefTableHandler::getThemeColorTypeIndex(nIntValue);
+ createGrabBag("themeFill", uno::Any(TDefTableHandler::getThemeColorTypeString(nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeFillShade:
+ m_nFillThemeColorShade = nIntValue;
+ createGrabBag("themeFillShade", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeFillTint:
+ m_nFillThemeColorTint = nIntValue;
+ createGrabBag("themeFillTint", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeColor:
+ m_eThemeColorType = TDefTableHandler::getThemeColorTypeIndex(nIntValue);
+ createGrabBag("themeColor", uno::Any(TDefTableHandler::getThemeColorTypeString(nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeShade:
+ m_nThemeColorShade = nIntValue;
+ createGrabBag("themeShade", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ case NS_ooxml::LN_CT_Shd_themeTint:
+ m_nThemeColorTint = nIntValue;
+ createGrabBag("themeTint", uno::Any(OUString::number(nIntValue, 16)));
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+void CellColorHandler::lcl_sprm(Sprm &) {}
+
+TablePropertyMapPtr CellColorHandler::getProperties()
+{
+ TablePropertyMapPtr pPropertyMap(new TablePropertyMap);
+
+ // Code from binary word filter (the values are out of 1000)
+ sal_Int32 nWW8BrushStyle = 0;
+ switch (m_nShadingPattern)
+ {
+ // Clear-Brush
+ case NS_ooxml::LN_Value_ST_Shd_clear: nWW8BrushStyle = 0; break;
+ // Solid-Brush
+ case NS_ooxml::LN_Value_ST_Shd_solid: nWW8BrushStyle = 1000; break;
+ // Percent values
+ case NS_ooxml::LN_Value_ST_Shd_pct5: nWW8BrushStyle = 50; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct10: nWW8BrushStyle = 100; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct20: nWW8BrushStyle = 200; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct25: nWW8BrushStyle = 250; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct30: nWW8BrushStyle = 300; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct40: nWW8BrushStyle = 400; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct50: nWW8BrushStyle = 500; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct60: nWW8BrushStyle = 600; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct70: nWW8BrushStyle = 700; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct75: nWW8BrushStyle = 750; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct80: nWW8BrushStyle = 800; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct90: nWW8BrushStyle = 900; break;
+ // Special cases
+ case NS_ooxml::LN_Value_ST_Shd_horzStripe: nWW8BrushStyle = 333; break; // Dark Horizontal
+ case NS_ooxml::LN_Value_ST_Shd_vertStripe: nWW8BrushStyle = 333; break; // Dark Vertical
+ case NS_ooxml::LN_Value_ST_Shd_reverseDiagStripe: nWW8BrushStyle = 333; break; // Dark Forward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_diagStripe: nWW8BrushStyle = 333; break; // Dark Backward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_horzCross: nWW8BrushStyle = 333; break; // Dark Cross
+ case NS_ooxml::LN_Value_ST_Shd_diagCross: nWW8BrushStyle = 333; break; // Dark Diagonal Cross
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzStripe: nWW8BrushStyle = 333; break; // Horizontal
+ case NS_ooxml::LN_Value_ST_Shd_thinVertStripe: nWW8BrushStyle = 333; break; // Vertical
+ case NS_ooxml::LN_Value_ST_Shd_thinReverseDiagStripe: nWW8BrushStyle = 333; break; // Forward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagStripe: nWW8BrushStyle = 333; break; // Backward Diagonal
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzCross: nWW8BrushStyle = 333; break; // Cross
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagCross: nWW8BrushStyle = 333; break; // 25 Diagonal Cross
+ // Different shading types
+ case NS_ooxml::LN_Value_ST_Shd_pct12: nWW8BrushStyle = 125; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct15: nWW8BrushStyle = 150; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct35: nWW8BrushStyle = 350; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct37: nWW8BrushStyle = 375; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct45: nWW8BrushStyle = 450; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct55: nWW8BrushStyle = 550; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct62: nWW8BrushStyle = 625; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct65: nWW8BrushStyle = 650; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct85: nWW8BrushStyle = 850; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct87: nWW8BrushStyle = 875; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct95: nWW8BrushStyle = 950; break;
+ }
+
+ sal_Int32 nApplyColor = 0;
+ if( !nWW8BrushStyle )
+ {
+ // Clear-Brush
+ if ( m_bFillSpecified && m_bAutoFillColor )
+ nApplyColor = sal_Int32(COL_AUTO);
+ else
+ nApplyColor = m_nFillColor;
+ }
+ else
+ {
+ sal_Int32 nFore = m_nColor;
+ sal_Int32 nBack = m_nFillColor;
+
+ sal_uInt32 nRed = ((nFore & 0xff0000)>>0x10) * nWW8BrushStyle;
+ sal_uInt32 nGreen = ((nFore & 0xff00)>>0x8) * nWW8BrushStyle;
+ sal_uInt32 nBlue = (nFore & 0xff) * nWW8BrushStyle;
+ nRed += ((nBack & 0xff0000)>>0x10) * (1000L - nWW8BrushStyle);
+ nGreen += ((nBack & 0xff00)>>0x8)* (1000L - nWW8BrushStyle);
+ nBlue += (nBack & 0xff) * (1000L - nWW8BrushStyle);
+
+ nApplyColor = ( (nRed/1000) << 0x10 ) + ((nGreen/1000) << 8) + nBlue/1000;
+ }
+
+ // Check if it is a 'Character'
+ if (m_OutputFormat == Character)
+ {
+ sal_Int32 nShadingPattern = drawing::ShadingPattern::CLEAR;
+ switch (m_nShadingPattern)
+ {
+ case NS_ooxml::LN_Value_ST_Shd_clear: nShadingPattern = drawing::ShadingPattern::CLEAR; break;
+ case NS_ooxml::LN_Value_ST_Shd_solid: nShadingPattern = drawing::ShadingPattern::SOLID; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct5: nShadingPattern = drawing::ShadingPattern::PCT5; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct10: nShadingPattern = drawing::ShadingPattern::PCT10; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct20: nShadingPattern = drawing::ShadingPattern::PCT20; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct25: nShadingPattern = drawing::ShadingPattern::PCT25; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct30: nShadingPattern = drawing::ShadingPattern::PCT30; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct40: nShadingPattern = drawing::ShadingPattern::PCT40; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct50: nShadingPattern = drawing::ShadingPattern::PCT50; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct60: nShadingPattern = drawing::ShadingPattern::PCT60; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct70: nShadingPattern = drawing::ShadingPattern::PCT70; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct75: nShadingPattern = drawing::ShadingPattern::PCT75; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct80: nShadingPattern = drawing::ShadingPattern::PCT80; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct90: nShadingPattern = drawing::ShadingPattern::PCT90; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzStripe: nShadingPattern = drawing::ShadingPattern::HORZ_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_vertStripe: nShadingPattern = drawing::ShadingPattern::VERT_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_reverseDiagStripe: nShadingPattern = drawing::ShadingPattern::REVERSE_DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagStripe: nShadingPattern = drawing::ShadingPattern::DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_horzCross: nShadingPattern = drawing::ShadingPattern::HORZ_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_diagCross: nShadingPattern = drawing::ShadingPattern::DIAG_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzStripe: nShadingPattern = drawing::ShadingPattern::THIN_HORZ_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinVertStripe: nShadingPattern = drawing::ShadingPattern::THIN_VERT_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinReverseDiagStripe: nShadingPattern = drawing::ShadingPattern::THIN_REVERSE_DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagStripe: nShadingPattern = drawing::ShadingPattern::THIN_DIAG_STRIPE; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinHorzCross: nShadingPattern = drawing::ShadingPattern::THIN_HORZ_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_thinDiagCross: nShadingPattern = drawing::ShadingPattern::THIN_DIAG_CROSS; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct12: nShadingPattern = drawing::ShadingPattern::PCT12; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct15: nShadingPattern = drawing::ShadingPattern::PCT15; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct35: nShadingPattern = drawing::ShadingPattern::PCT35; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct37: nShadingPattern = drawing::ShadingPattern::PCT37; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct45: nShadingPattern = drawing::ShadingPattern::PCT45; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct55: nShadingPattern = drawing::ShadingPattern::PCT55; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct62: nShadingPattern = drawing::ShadingPattern::PCT62; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct65: nShadingPattern = drawing::ShadingPattern::PCT65; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct85: nShadingPattern = drawing::ShadingPattern::PCT85; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct87: nShadingPattern = drawing::ShadingPattern::PCT87; break;
+ case NS_ooxml::LN_Value_ST_Shd_pct95: nShadingPattern = drawing::ShadingPattern::PCT95; break;
+ }
+
+ // Write the shading pattern property
+ pPropertyMap->Insert(PROP_CHAR_SHADING_VALUE, uno::Any( nShadingPattern ));
+ }
+
+ if (m_OutputFormat == Paragraph && m_nShadingPattern != NS_ooxml::LN_Value_ST_Shd_nil)
+ {
+ if (nWW8BrushStyle || !m_bAutoFillColor)
+ pPropertyMap->Insert(PROP_FILL_STYLE, uno::Any(drawing::FillStyle_SOLID));
+ else if (m_bFillSpecified) // m_bAutoFillColor == true
+ pPropertyMap->Insert(PROP_FILL_STYLE, uno::Any(drawing::FillStyle_NONE));
+
+ pPropertyMap->Insert(PROP_FILL_COLOR, uno::Any(nApplyColor));
+ auto xComplexColor = model::color::createXComplexColor(getFillComplexColor());
+ pPropertyMap->Insert(PROP_FILL_COMPLEX_COLOR, uno::Any(xComplexColor));
+ }
+ else if ( nWW8BrushStyle || !m_bAutoFillColor || m_bFillSpecified )
+ {
+ if (m_OutputFormat == Form)
+ {
+ pPropertyMap->Insert(PROP_BACK_COLOR, uno::Any(nApplyColor));
+ }
+ else
+ {
+ pPropertyMap->Insert(PROP_CHAR_BACK_COLOR, uno::Any(nApplyColor));
+ auto aComplexColor = getFillComplexColor();
+ if (aComplexColor.getType() != model::ColorType::Unused)
+ {
+ auto xComplexColor = model::color::createXComplexColor(aComplexColor);
+ pPropertyMap->Insert(PROP_CHAR_BACKGROUND_COMPLEX_COLOR, uno::Any(xComplexColor));
+ }
+ }
+ }
+ createGrabBag("originalColor", uno::Any(msfilter::util::ConvertColorOU(Color(ColorTransparency, nApplyColor))));
+
+ return pPropertyMap;
+}
+
+void CellColorHandler::createGrabBag(const OUString& aName, const uno::Any& rAny)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+
+ beans::PropertyValue aValue;
+ aValue.Name = aName;
+ aValue.Value = rAny;
+ m_aInteropGrabBag.push_back(aValue);
+}
+
+void CellColorHandler::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue CellColorHandler::getInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = m_aInteropGrabBagName;
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+void CellColorHandler::disableInteropGrabBag()
+{
+ m_aInteropGrabBagName.clear();
+ m_aInteropGrabBag.clear();
+}
+
+bool CellColorHandler::isInteropGrabBagEnabled() const
+{
+ return !(m_aInteropGrabBagName.isEmpty());
+}
+
+model::ComplexColor CellColorHandler::getComplexColor() const
+{
+ model::ComplexColor aComplexColor;
+ if (m_eThemeColorType != model::ThemeColorType::Unknown)
+ {
+ aComplexColor.setThemeColor(m_eThemeColorType);
+
+ if (m_nThemeColorTint > 0 )
+ {
+ sal_Int16 nTint = sal_Int16((255.0 - m_nThemeColorTint) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Tint, nTint});
+ }
+ if (m_nThemeColorShade > 0)
+ {
+ sal_Int16 nShade = sal_Int16((255.0 - m_nThemeColorShade) * 10000 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Shade, nShade});
+ }
+ }
+ return aComplexColor;
+}
+
+model::ComplexColor CellColorHandler::getFillComplexColor() const
+{
+ model::ComplexColor aComplexColor;
+ if (m_eFillThemeColorType != model::ThemeColorType::Unknown)
+ {
+ aComplexColor.setThemeColor(m_eFillThemeColorType);
+
+ if (m_nFillThemeColorTint > 0 )
+ {
+ sal_Int16 nTint = sal_Int16((255.0 - m_nFillThemeColorTint) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Tint, nTint});
+ }
+ if (m_nFillThemeColorShade > 0)
+ {
+ sal_Int16 nShade = sal_Int16((255.0 - m_nFillThemeColorShade) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Shade, nShade});
+ }
+ }
+ return aComplexColor;
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/CellColorHandler.hxx b/sw/source/writerfilter/dmapper/CellColorHandler.hxx
new file mode 100644
index 000000000000..418f8e1f93e4
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/CellColorHandler.hxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include "PropertyMap.hxx"
+#include <vector>
+#include <docmodel/theme/ThemeColorType.hxx>
+#include <docmodel/color/ComplexColor.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+class TablePropertyMap;
+class CellColorHandler : public LoggedProperties
+{
+public:
+ enum OutputFormat { Form, Paragraph, Character }; // for what part of the document
+private:
+ sal_Int32 m_nShadingPattern;
+
+ sal_Int32 m_nColor;
+ model::ThemeColorType m_eThemeColorType = model::ThemeColorType::Unknown;
+ sal_Int32 m_nThemeColorTint = 0;
+ sal_Int32 m_nThemeColorShade = 0;
+
+ sal_Int32 m_nFillColor;
+ model::ThemeColorType m_eFillThemeColorType = model::ThemeColorType::Unknown;
+ sal_Int32 m_nFillThemeColorTint = 0;
+ sal_Int32 m_nFillThemeColorShade = 0;
+
+ 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;
+
+ model::ComplexColor getComplexColor() const;
+ model::ComplexColor getFillComplexColor() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/CellMarginHandler.cxx b/sw/source/writerfilter/dmapper/CellMarginHandler.cxx
new file mode 100644
index 000000000000..e8262156e55f
--- /dev/null
+++ b/sw/source/writerfilter/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_INFO("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/sw/source/writerfilter/dmapper/CellMarginHandler.hxx b/sw/source/writerfilter/dmapper/CellMarginHandler.hxx
new file mode 100644
index 000000000000..8dcbf2dc5245
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/CellMarginHandler.hxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+class TablePropertyMap;
+class CellMarginHandler : public LoggedProperties
+{
+private:
+ sal_Int32 m_nValue; ///< Converted value.
+ sal_Int32 m_nWidth; ///< Original value.
+ sal_Int32 m_nType; ///< Unit of the value (dxa, etc).
+
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ void createGrabBag(const OUString& aName);
+
+public:
+ sal_Int32 m_nLeftMargin;
+ bool m_bLeftMarginValid;
+ sal_Int32 m_nRightMargin;
+ bool m_bRightMarginValid;
+ sal_Int32 m_nTopMargin;
+ bool m_bTopMarginValid;
+ sal_Int32 m_nBottomMargin;
+ bool m_bBottomMarginValid;
+
+public:
+ CellMarginHandler( );
+ virtual ~CellMarginHandler() override;
+
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag();
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/ConversionHelper.cxx b/sw/source/writerfilter/dmapper/ConversionHelper.cxx
new file mode 100644
index 000000000000..7f3f11544c85
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/ConversionHelper.cxx
@@ -0,0 +1,691 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "ConversionHelper.hxx"
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <editeng/borderline.hxx>
+#include <ooxml/resourceids.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/color.hxx>
+#include <tools/mapunit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper::ConversionHelper{
+
+/// Convert OOXML border style to WW8 that editeng can handle.
+static sal_Int32 lcl_convertBorderStyleFromToken(sal_Int32 nOOXMLType)
+{
+ switch (nOOXMLType)
+ {
+ case NS_ooxml::LN_Value_ST_Border_nil: return 255;
+ case NS_ooxml::LN_Value_ST_Border_none: return 0;
+ case NS_ooxml::LN_Value_ST_Border_single: return 1;
+ case NS_ooxml::LN_Value_ST_Border_thick: return 2;
+ case NS_ooxml::LN_Value_ST_Border_double: return 3;
+ case NS_ooxml::LN_Value_ST_Border_dotted: return 6;
+ case NS_ooxml::LN_Value_ST_Border_dashed: return 7;
+ case NS_ooxml::LN_Value_ST_Border_dotDash: return 8;
+ case NS_ooxml::LN_Value_ST_Border_dotDotDash: return 9;
+ case NS_ooxml::LN_Value_ST_Border_triple: return 10;
+ case NS_ooxml::LN_Value_ST_Border_thinThickSmallGap: return 11;
+ case NS_ooxml::LN_Value_ST_Border_thickThinSmallGap: return 12;
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinSmallGap: return 13;
+ case NS_ooxml::LN_Value_ST_Border_thinThickMediumGap: return 14;
+ case NS_ooxml::LN_Value_ST_Border_thickThinMediumGap: return 15;
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinMediumGap: return 16;
+ case NS_ooxml::LN_Value_ST_Border_thinThickLargeGap: return 17;
+ case NS_ooxml::LN_Value_ST_Border_thickThinLargeGap: return 18;
+ case NS_ooxml::LN_Value_ST_Border_thinThickThinLargeGap: return 19;
+ case NS_ooxml::LN_Value_ST_Border_wave: return 20;
+ case NS_ooxml::LN_Value_ST_Border_doubleWave: return 21;
+ case NS_ooxml::LN_Value_ST_Border_dashSmallGap: return 22;
+ case NS_ooxml::LN_Value_ST_Border_dashDotStroked: return 23;
+ case NS_ooxml::LN_Value_ST_Border_threeDEmboss: return 24;
+ case NS_ooxml::LN_Value_ST_Border_threeDEngrave: return 25;
+ case NS_ooxml::LN_Value_ST_Border_outset: return 26;
+ case NS_ooxml::LN_Value_ST_Border_inset: return 27;
+ case NS_ooxml::LN_Value_ST_Border_apples: return 64;
+ case NS_ooxml::LN_Value_ST_Border_archedScallops: return 65;
+ case NS_ooxml::LN_Value_ST_Border_babyPacifier: return 66;
+ case NS_ooxml::LN_Value_ST_Border_babyRattle: return 67;
+ case NS_ooxml::LN_Value_ST_Border_balloons3Colors: return 68;
+ case NS_ooxml::LN_Value_ST_Border_balloonsHotAir: return 69;
+ case NS_ooxml::LN_Value_ST_Border_basicBlackDashes: return 70;
+ case NS_ooxml::LN_Value_ST_Border_basicBlackDots: return 71;
+ case NS_ooxml::LN_Value_ST_Border_basicBlackSquares: return 72;
+ case NS_ooxml::LN_Value_ST_Border_basicThinLines: return 73;
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteDashes: return 74;
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteDots: return 75;
+ case NS_ooxml::LN_Value_ST_Border_basicWhiteSquares: return 76;
+ case NS_ooxml::LN_Value_ST_Border_basicWideInline: return 77;
+ case NS_ooxml::LN_Value_ST_Border_basicWideMidline: return 78;
+ case NS_ooxml::LN_Value_ST_Border_basicWideOutline: return 79;
+ case NS_ooxml::LN_Value_ST_Border_bats: return 80;
+ case NS_ooxml::LN_Value_ST_Border_birds: return 81;
+ case NS_ooxml::LN_Value_ST_Border_birdsFlight: return 82;
+ case NS_ooxml::LN_Value_ST_Border_cabins: return 83;
+ case NS_ooxml::LN_Value_ST_Border_cakeSlice: return 84;
+ case NS_ooxml::LN_Value_ST_Border_candyCorn: return 85;
+ case NS_ooxml::LN_Value_ST_Border_celticKnotwork: return 86;
+ case NS_ooxml::LN_Value_ST_Border_certificateBanner: return 87;
+ case NS_ooxml::LN_Value_ST_Border_chainLink: return 88;
+ case NS_ooxml::LN_Value_ST_Border_champagneBottle: return 89;
+ case NS_ooxml::LN_Value_ST_Border_checkedBarBlack: return 90;
+ case NS_ooxml::LN_Value_ST_Border_checkedBarColor: return 91;
+ case NS_ooxml::LN_Value_ST_Border_checkered: return 92;
+ case NS_ooxml::LN_Value_ST_Border_christmasTree: return 93;
+ case NS_ooxml::LN_Value_ST_Border_circlesLines: return 94;
+ case NS_ooxml::LN_Value_ST_Border_circlesRectangles: return 95;
+ case NS_ooxml::LN_Value_ST_Border_classicalWave: return 96;
+ case NS_ooxml::LN_Value_ST_Border_clocks: return 97;
+ case NS_ooxml::LN_Value_ST_Border_compass: return 98;
+ case NS_ooxml::LN_Value_ST_Border_confetti: return 99;
+ case NS_ooxml::LN_Value_ST_Border_confettiGrays: return 100;
+ case NS_ooxml::LN_Value_ST_Border_confettiOutline: return 101;
+ case NS_ooxml::LN_Value_ST_Border_confettiStreamers: return 102;
+ case NS_ooxml::LN_Value_ST_Border_confettiWhite: return 103;
+ case NS_ooxml::LN_Value_ST_Border_cornerTriangles: return 104;
+ case NS_ooxml::LN_Value_ST_Border_couponCutoutDashes: return 105;
+ case NS_ooxml::LN_Value_ST_Border_couponCutoutDots: return 106;
+ case NS_ooxml::LN_Value_ST_Border_crazyMaze: return 107;
+ case NS_ooxml::LN_Value_ST_Border_creaturesButterfly: return 108;
+ case NS_ooxml::LN_Value_ST_Border_creaturesFish: return 109;
+ case NS_ooxml::LN_Value_ST_Border_creaturesInsects: return 110;
+ case NS_ooxml::LN_Value_ST_Border_creaturesLadyBug: return 111;
+ case NS_ooxml::LN_Value_ST_Border_crossStitch: return 112;
+ case NS_ooxml::LN_Value_ST_Border_cup: return 113;
+ case NS_ooxml::LN_Value_ST_Border_decoArch: return 114;
+ case NS_ooxml::LN_Value_ST_Border_decoArchColor: return 115;
+ case NS_ooxml::LN_Value_ST_Border_decoBlocks: return 116;
+ case NS_ooxml::LN_Value_ST_Border_diamondsGray: return 117;
+ case NS_ooxml::LN_Value_ST_Border_doubleD: return 118;
+ case NS_ooxml::LN_Value_ST_Border_doubleDiamonds: return 119;
+ case NS_ooxml::LN_Value_ST_Border_earth1: return 120;
+ case NS_ooxml::LN_Value_ST_Border_earth2: return 121;
+ case NS_ooxml::LN_Value_ST_Border_eclipsingSquares1: return 122;
+ case NS_ooxml::LN_Value_ST_Border_eclipsingSquares2: return 123;
+ case NS_ooxml::LN_Value_ST_Border_eggsBlack: return 124;
+ case NS_ooxml::LN_Value_ST_Border_fans: return 125;
+ case NS_ooxml::LN_Value_ST_Border_film: return 126;
+ case NS_ooxml::LN_Value_ST_Border_firecrackers: return 127;
+ case NS_ooxml::LN_Value_ST_Border_flowersBlockPrint: return 128;
+ case NS_ooxml::LN_Value_ST_Border_flowersDaisies: return 129;
+ case NS_ooxml::LN_Value_ST_Border_flowersModern1: return 130;
+ case NS_ooxml::LN_Value_ST_Border_flowersModern2: return 131;
+ case NS_ooxml::LN_Value_ST_Border_flowersPansy: return 132;
+ case NS_ooxml::LN_Value_ST_Border_flowersRedRose: return 133;
+ case NS_ooxml::LN_Value_ST_Border_flowersRoses: return 134;
+ case NS_ooxml::LN_Value_ST_Border_flowersTeacup: return 135;
+ case NS_ooxml::LN_Value_ST_Border_flowersTiny: return 136;
+ case NS_ooxml::LN_Value_ST_Border_gems: return 137;
+ case NS_ooxml::LN_Value_ST_Border_gingerbreadMan: return 138;
+ case NS_ooxml::LN_Value_ST_Border_gradient: return 139;
+ case NS_ooxml::LN_Value_ST_Border_handmade1: return 140;
+ case NS_ooxml::LN_Value_ST_Border_handmade2: return 141;
+ case NS_ooxml::LN_Value_ST_Border_heartBalloon: return 142;
+ case NS_ooxml::LN_Value_ST_Border_heartGray: return 143;
+ case NS_ooxml::LN_Value_ST_Border_hearts: return 144;
+ case NS_ooxml::LN_Value_ST_Border_heebieJeebies: return 145;
+ case NS_ooxml::LN_Value_ST_Border_holly: return 146;
+ case NS_ooxml::LN_Value_ST_Border_houseFunky: return 147;
+ case NS_ooxml::LN_Value_ST_Border_hypnotic: return 148;
+ case NS_ooxml::LN_Value_ST_Border_iceCreamCones: return 149;
+ case NS_ooxml::LN_Value_ST_Border_lightBulb: return 150;
+ case NS_ooxml::LN_Value_ST_Border_lightning1: return 151;
+ case NS_ooxml::LN_Value_ST_Border_lightning2: return 152;
+ case NS_ooxml::LN_Value_ST_Border_mapPins: return 153;
+ case NS_ooxml::LN_Value_ST_Border_mapleLeaf: return 154;
+ case NS_ooxml::LN_Value_ST_Border_mapleMuffins: return 155;
+ case NS_ooxml::LN_Value_ST_Border_marquee: return 156;
+ case NS_ooxml::LN_Value_ST_Border_marqueeToothed: return 157;
+ case NS_ooxml::LN_Value_ST_Border_moons: return 158;
+ case NS_ooxml::LN_Value_ST_Border_mosaic: return 159;
+ case NS_ooxml::LN_Value_ST_Border_musicNotes: return 160;
+ case NS_ooxml::LN_Value_ST_Border_northwest: return 161;
+ case NS_ooxml::LN_Value_ST_Border_ovals: return 162;
+ case NS_ooxml::LN_Value_ST_Border_packages: return 163;
+ case NS_ooxml::LN_Value_ST_Border_palmsBlack: return 164;
+ case NS_ooxml::LN_Value_ST_Border_palmsColor: return 165;
+ case NS_ooxml::LN_Value_ST_Border_paperClips: return 166;
+ case NS_ooxml::LN_Value_ST_Border_papyrus: return 167;
+ case NS_ooxml::LN_Value_ST_Border_partyFavor: return 168;
+ case NS_ooxml::LN_Value_ST_Border_partyGlass: return 169;
+ case NS_ooxml::LN_Value_ST_Border_pencils: return 170;
+ case NS_ooxml::LN_Value_ST_Border_people: return 171;
+ case NS_ooxml::LN_Value_ST_Border_peopleWaving: return 172;
+ case NS_ooxml::LN_Value_ST_Border_peopleHats: return 173;
+ case NS_ooxml::LN_Value_ST_Border_poinsettias: return 174;
+ case NS_ooxml::LN_Value_ST_Border_postageStamp: return 175;
+ case NS_ooxml::LN_Value_ST_Border_pumpkin1: return 176;
+ case NS_ooxml::LN_Value_ST_Border_pushPinNote2: return 177;
+ case NS_ooxml::LN_Value_ST_Border_pushPinNote1: return 178;
+ case NS_ooxml::LN_Value_ST_Border_pyramids: return 179;
+ case NS_ooxml::LN_Value_ST_Border_pyramidsAbove: return 180;
+ case NS_ooxml::LN_Value_ST_Border_quadrants: return 181;
+ case NS_ooxml::LN_Value_ST_Border_rings: return 182;
+ case NS_ooxml::LN_Value_ST_Border_safari: return 183;
+ case NS_ooxml::LN_Value_ST_Border_sawtooth: return 184;
+ case NS_ooxml::LN_Value_ST_Border_sawtoothGray: return 185;
+ case NS_ooxml::LN_Value_ST_Border_scaredCat: return 186;
+ case NS_ooxml::LN_Value_ST_Border_seattle: return 187;
+ case NS_ooxml::LN_Value_ST_Border_shadowedSquares: return 188;
+ case NS_ooxml::LN_Value_ST_Border_sharksTeeth: return 189;
+ case NS_ooxml::LN_Value_ST_Border_shorebirdTracks: return 190;
+ case NS_ooxml::LN_Value_ST_Border_skyrocket: return 191;
+ case NS_ooxml::LN_Value_ST_Border_snowflakeFancy: return 192;
+ case NS_ooxml::LN_Value_ST_Border_snowflakes: return 193;
+ case NS_ooxml::LN_Value_ST_Border_sombrero: return 194;
+ case NS_ooxml::LN_Value_ST_Border_southwest: return 195;
+ case NS_ooxml::LN_Value_ST_Border_stars: return 196;
+ case NS_ooxml::LN_Value_ST_Border_starsTop: return 197;
+ case NS_ooxml::LN_Value_ST_Border_stars3d: return 198;
+ case NS_ooxml::LN_Value_ST_Border_starsBlack: return 199;
+ case NS_ooxml::LN_Value_ST_Border_starsShadowed: return 200;
+ case NS_ooxml::LN_Value_ST_Border_sun: return 201;
+ case NS_ooxml::LN_Value_ST_Border_swirligig: return 202;
+ case NS_ooxml::LN_Value_ST_Border_tornPaper: return 203;
+ case NS_ooxml::LN_Value_ST_Border_tornPaperBlack: return 204;
+ case NS_ooxml::LN_Value_ST_Border_trees: return 205;
+ case NS_ooxml::LN_Value_ST_Border_triangleParty: return 206;
+ case NS_ooxml::LN_Value_ST_Border_triangles: return 207;
+ case NS_ooxml::LN_Value_ST_Border_tribal1: return 208;
+ case NS_ooxml::LN_Value_ST_Border_tribal2: return 209;
+ case NS_ooxml::LN_Value_ST_Border_tribal3: return 210;
+ case NS_ooxml::LN_Value_ST_Border_tribal4: return 211;
+ case NS_ooxml::LN_Value_ST_Border_tribal5: return 212;
+ case NS_ooxml::LN_Value_ST_Border_tribal6: return 213;
+ case NS_ooxml::LN_Value_ST_Border_twistedLines1: return 214;
+ case NS_ooxml::LN_Value_ST_Border_twistedLines2: return 215;
+ case NS_ooxml::LN_Value_ST_Border_vine: return 216;
+ case NS_ooxml::LN_Value_ST_Border_waveline: return 217;
+ case NS_ooxml::LN_Value_ST_Border_weavingAngles: return 218;
+ case NS_ooxml::LN_Value_ST_Border_weavingBraid: return 219;
+ case NS_ooxml::LN_Value_ST_Border_weavingRibbon: return 220;
+ case NS_ooxml::LN_Value_ST_Border_weavingStrips: return 221;
+ case NS_ooxml::LN_Value_ST_Border_whiteFlowers: return 222;
+ case NS_ooxml::LN_Value_ST_Border_woodwork: return 223;
+ case NS_ooxml::LN_Value_ST_Border_xIllusions: return 224;
+ case NS_ooxml::LN_Value_ST_Border_zanyTriangles: return 225;
+ case NS_ooxml::LN_Value_ST_Border_zigZag: return 226;
+ case NS_ooxml::LN_Value_ST_Border_zigZagStitch: return 227;
+ default: break;
+ }
+ return 0;
+}
+
+void MakeBorderLine( sal_Int32 nLineThickness, sal_Int32 nLineToken,
+ sal_Int32 nLineColor,
+ table::BorderLine2& rToFill, bool bIsOOXML )
+{
+ static const Color aBorderDefColor[] =
+ {
+ // The first item means automatic color (COL_AUTO), but we
+ // do not use it anyway (see the next statement) .-)
+ // See also GetLineIndex in sw/source/filter/ww8/ww8par6.cxx
+ COL_AUTO, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
+ COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
+ COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
+ COL_LIGHTGRAY
+ };
+ if(!bIsOOXML && sal::static_int_cast<sal_uInt32>(nLineColor) < SAL_N_ELEMENTS(aBorderDefColor))
+ nLineColor = sal_Int32(aBorderDefColor[nLineColor]);
+ //no auto color for borders
+ if (nLineColor == sal_Int32(COL_AUTO))
+ nLineColor = sal_Int32(COL_BLACK);
+
+ sal_Int32 nLineType = lcl_convertBorderStyleFromToken(nLineToken);
+
+ // Map to our border types, we should use of one equal line
+ // thickness, or one of smaller thickness. If too small we
+ // can make the deficit up in additional white space or
+ // object size
+ SvxBorderLineStyle const nLineStyle(
+ ::editeng::ConvertBorderStyleFromWord(nLineType));
+ rToFill.LineStyle = static_cast<sal_Int16>(nLineStyle);
+ double const fConverted( (SvxBorderLineStyle::NONE == nLineStyle) ? 0.0 :
+ ::editeng::ConvertBorderWidthFromWord(nLineStyle, nLineThickness,
+ nLineType));
+ rToFill.LineWidth = convertTwipToMM100(fConverted);
+ rToFill.Color = nLineColor;
+}
+
+namespace {
+void lcl_SwapQuotesInField(OUString &rFmt)
+{
+ //Swap unescaped " and ' with ' and "
+ sal_Int32 nLen = rFmt.getLength();
+ OUStringBuffer aBuffer( rFmt );
+ const sal_Unicode* pFmt = rFmt.getStr();
+ for (sal_Int32 nI = 0; nI < nLen; ++nI)
+ {
+ if ((pFmt[nI] == '\"') && (!nI || pFmt[nI-1] != '\\'))
+ aBuffer[nI] = '\'';
+ else if ((pFmt[nI] == '\'') && (!nI || pFmt[nI-1] != '\\'))
+ aBuffer[nI] = '\"';
+ }
+ rFmt = aBuffer.makeStringAndClear();
+}
+bool lcl_IsNotAM(std::u16string_view rFmt, sal_Int32 nPos)
+{
+ return (
+ (nPos == static_cast<sal_Int32>(rFmt.size()) - 1) ||
+ (
+ (rFmt[nPos+1] != 'M') &&
+ (rFmt[nPos+1] != 'm')
+ )
+ );
+}
+bool IsPreviousAM(std::u16string_view rParams, sal_Int32 nPos)
+{
+ return nPos >= 2 && o3tl::matchIgnoreAsciiCase(rParams, u"am", nPos - 2);
+}
+bool IsNextPM(std::u16string_view rParams, sal_Int32 nPos)
+{
+ return o3tl::make_unsigned(nPos + 2) < rParams.size() && o3tl::matchIgnoreAsciiCase(rParams, u"pm", nPos + 1);
+}
+}
+
+// See also sw::ms::MSDateTimeFormatToSwFormat
+OUString ConvertMSFormatStringToSO(
+ const OUString& rFormat, lang::Locale& rLocale, bool bHijri)
+{
+ OUString sFormat(rFormat);
+ lcl_SwapQuotesInField(sFormat);
+
+ //#102782#, #102815#, #108341# & #111944# have to work at the same time :-)
+ bool bForceJapanese(false);
+ bool bForceNatNum(false);
+ const sal_Int32 nLen = sFormat.getLength();
+ sal_Int32 nI = 0;
+ sal_Int32 nAddedChars = 0;
+// const sal_Unicode* pFormat = sFormat.getStr();
+ OUStringBuffer aNewFormat( sFormat );
+ while (nI < nLen)
+ {
+ if (sFormat[nI] == '\\')
+ ++nI;
+ else if (sFormat[nI] == '\"')
+ {
+ ++nI;
+ //While not at the end and not at an unescaped end quote
+ while ((nI < nLen) && ((sFormat[nI] != '\"') && (sFormat[nI-1] != '\\')))
+ ++nI;
+ }
+ else //normal unquoted section
+ {
+ sal_Unicode nChar = sFormat[nI];
+ if (nChar == 'O')
+ {
+ aNewFormat[nI + nAddedChars] = 'M';
+ bForceNatNum = true;
+ }
+ else if (nChar == 'o')
+ {
+ aNewFormat[nI + nAddedChars] = 'm';
+ bForceNatNum = true;
+ }
+ else if ((nChar == 'A') && lcl_IsNotAM(sFormat, nI))
+ {
+ aNewFormat[nI + nAddedChars] = 'D';
+ bForceNatNum = true;
+ }
+ else if ((nChar == 'g') || (nChar == 'G'))
+ bForceJapanese = true;
+ else if ((nChar == 'a') && lcl_IsNotAM(sFormat, nI))
+ bForceJapanese = true;
+ else if (nChar == 'E')
+ {
+ if ((nI != nLen-1) && (sFormat[nI+1] == 'E'))
+ {
+ //todo: this cannot be the right way to replace a part of the string!
+ aNewFormat[nI + nAddedChars] = 'Y';
+ aNewFormat[nI + nAddedChars + 1] = 'Y';
+ aNewFormat.insert(nI + nAddedChars + 2, "YY");
+ nAddedChars += 2;
+ ++nI;
+ }
+ bForceJapanese = true;
+ }
+ else if (nChar == 'e')
+ {
+ if ((nI != nLen-1) && (sFormat[nI+1] == 'e'))
+ {
+ //todo: this cannot be the right way to replace a part of the string!
+ aNewFormat[nI + nAddedChars] = 'y';
+ aNewFormat[nI + nAddedChars + 1] = 'y';
+ aNewFormat.insert(nI + nAddedChars + 2, "yy");
+ nAddedChars += 2;
+ ++nI;
+ }
+ bForceJapanese = true;
+ }
+ else if (nChar == '/' && !(IsPreviousAM(sFormat, nI) && IsNextPM(sFormat, nI)))
+ {
+ // MM We have to escape '/' in case it's used as a char
+ //todo: this cannot be the right way to replace a part of the string!
+ aNewFormat[nI + nAddedChars] = '\\';
+ aNewFormat.insert(nI + nAddedChars + 1, "/");
+ ++nAddedChars;
+ ++nI;
+ }
+ }
+ ++nI;
+ }
+
+ if (bForceNatNum)
+ bForceJapanese = true;
+
+ if (bForceJapanese)
+ {
+ rLocale.Language = "ja";
+ rLocale.Country = "JP";
+ }
+
+ if (bForceNatNum)
+ {
+ aNewFormat.insert( 0, "[NatNum1][$-411]");
+ }
+
+ if (bHijri)
+ {
+ aNewFormat.insert( 0, "[~hijri]");
+ }
+ return aNewFormat.makeStringAndClear();
+
+}
+
+sal_Int32 convertTwipToMM100(sal_Int32 _t)
+{
+ // It appears that MSO handles large twip values specially, probably legacy 16bit handling,
+ // anything that's bigger than 32767 appears to be simply ignored.
+ if( _t >= 0x8000 )
+ return 0;
+ return ::convertTwipToMm100( _t );
+}
+
+sal_Int32 convertTwipToMM100WithoutLimit(sal_Int32 _t)
+{
+ return ::convertTwipToMm100(_t);
+}
+
+double convertTwipToMM100Double(sal_Int32 _t)
+{
+ // It appears that MSO handles large twip values specially, probably legacy 16bit handling,
+ // anything that's bigger than 32767 appears to be simply ignored.
+ if( _t >= 0x8000 )
+ return 0.0;
+ return o3tl::convert<double>(_t, o3tl::Length::twip, o3tl::Length::mm100);
+}
+
+sal_uInt32 convertTwipToMM100Unsigned(sal_Int32 _t)
+{
+ if( _t < 0 )
+ return 0;
+ return convertTwipToMM100( _t );
+}
+
+text::RubyAdjust convertRubyAlign( sal_Int32 nIntValue )
+{
+ text::RubyAdjust rubyAdjust = text::RubyAdjust_LEFT;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_RubyAlign_center:
+ case NS_ooxml::LN_Value_ST_RubyAlign_rightVertical:
+ rubyAdjust = text::RubyAdjust_CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_distributeLetter:
+ rubyAdjust = text::RubyAdjust_BLOCK;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_distributeSpace:
+ rubyAdjust = text::RubyAdjust_INDENT_BLOCK;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_left:
+ rubyAdjust = text::RubyAdjust_LEFT;
+ break;
+ case NS_ooxml::LN_Value_ST_RubyAlign_right:
+ rubyAdjust = text::RubyAdjust_RIGHT;
+ break;
+ }
+ return rubyAdjust;
+}
+
+sal_Int16 convertTableJustification( sal_Int32 nIntValue )
+{
+ sal_Int16 nOrient = text::HoriOrientation::LEFT_AND_WIDTH;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_Jc_center:
+ nOrient = text::HoriOrientation::CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_right:
+ case NS_ooxml::LN_Value_ST_Jc_end:
+ nOrient = text::HoriOrientation::RIGHT;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_left:
+ case NS_ooxml::LN_Value_ST_Jc_start:
+ //no break
+ default:;
+
+ }
+ return nOrient;
+}
+
+// Return the suggested default if the given format has no known conversion
+sal_Int16 ConvertNumberingType(const sal_Int32 nFmt, const sal_Int16 nDefault)
+{
+ sal_Int16 nRet;
+ switch(nFmt)
+ {
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimal:
+ nRet = style::NumberingType::ARABIC;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_upperRoman:
+ nRet = style::NumberingType::ROMAN_UPPER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman:
+ nRet = style::NumberingType::ROMAN_LOWER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ordinal:
+ nRet = style::NumberingType::TEXT_NUMBER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_bullet:
+ nRet = style::NumberingType::CHAR_SPECIAL;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_none:
+ nRet = style::NumberingType::NUMBER_NONE;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_upperLetter:
+ nRet = style::NumberingType::CHARS_UPPER_LETTER_N;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter:
+ nRet = style::NumberingType::CHARS_LOWER_LETTER_N;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_iroha:
+ nRet = style::NumberingType::IROHA_HALFWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth:
+ nRet = style::NumberingType::IROHA_FULLWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_aiueo:
+ nRet = style::NumberingType::AIU_HALFWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth:
+ nRet = style::NumberingType::AIU_FULLWIDTH_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_hebrew2:
+ nRet = style::NumberingType::CHARS_HEBREW;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_thaiLetters:
+ nRet = style::NumberingType::CHARS_THAI;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_russianLower:
+ nRet = style::NumberingType::CHARS_CYRILLIC_LOWER_LETTER_RU;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_russianUpper:
+ nRet = style::NumberingType::CHARS_CYRILLIC_UPPER_LETTER_RU;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese:
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircle:
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle:
+ nRet = style::NumberingType::CIRCLE_NUMBER;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional:
+ nRet = style::NumberingType::TIAN_GAN_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac:
+ nRet = style::NumberingType::DI_ZI_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ganada:
+ nRet = style::NumberingType::HANGUL_SYLLABLE_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chosung:
+ nRet = style::NumberingType::HANGUL_JAMO_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal:
+ nRet = style::NumberingType::NUMBER_LEGAL_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital:
+ nRet = style::NumberingType::NUMBER_DIGITAL_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting:
+ nRet = style::NumberingType::NUMBER_HANGUL_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2:
+ nRet = style::NumberingType::NUMBER_DIGITAL2_KO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional:
+ nRet = style::NumberingType::NUMBER_UPPER_ZH_TW;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha:
+ nRet = style::NumberingType::CHARS_ARABIC;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad:
+ nRet = style::NumberingType::CHARS_ARABIC_ABJAD;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_hindiVowels:
+ nRet = style::NumberingType::CHARS_NEPALI;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal:
+ nRet = style::NumberingType::NUMBER_TRADITIONAL_JA;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting:
+ case NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting:
+ case NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting:
+ case NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand:
+ case NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital:
+ case NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand:
+ nRet = style::NumberingType::NUMBER_LOWER_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified:
+ nRet = style::NumberingType::NUMBER_UPPER_ZH;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_hebrew1:
+ //91726
+ nRet = style::NumberingType::NUMBER_HEBREW;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth:
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2:
+ nRet = style::NumberingType::FULLWIDTH_ARABIC;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_cardinalText:
+ nRet = style::NumberingType::TEXT_CARDINAL;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_ordinalText:
+ nRet = style::NumberingType::TEXT_ORDINAL;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_chicago:
+ nRet = style::NumberingType::SYMBOL_CHICAGO;
+ break;
+ case NS_ooxml::LN_Value_ST_NumberFormat_decimalZero:
+ nRet = style::NumberingType::ARABIC_ZERO;
+ break;
+ default: nRet = nDefault;
+ }
+/* TODO: Lots of additional values are available - some are supported in the I18 framework
+ NS_ooxml::LN_Value_ST_NumberFormat_hex = 91685;
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth = 91692;
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand = 91694;
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop = 91703;
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen = 91704;
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional = 91709;
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital = 91713;
+ NS_ooxml::LN_Value_ST_NumberFormat_vietnameseCounting = 91721;
+ NS_ooxml::LN_Value_ST_NumberFormat_numberInDash = 91725;
+ NS_ooxml::LN_Value_ST_NumberFormat_hindiConsonants = 91731;
+ NS_ooxml::LN_Value_ST_NumberFormat_hindiNumbers = 91732;
+ NS_ooxml::LN_Value_ST_NumberFormat_hindiCounting = 91733;
+ NS_ooxml::LN_Value_ST_NumberFormat_thaiNumbers = 91735;
+ NS_ooxml::LN_Value_ST_NumberFormat_thaiCounting = 91736;*/
+ return nRet;
+}
+
+sal_Int16 ConvertCustomNumberFormat(std::u16string_view rFormat)
+{
+ sal_Int16 nRet = -1;
+
+ if (rFormat == u"001, 002, 003, ...")
+ {
+ nRet = style::NumberingType::ARABIC_ZERO3;
+ }
+ else if (rFormat == u"0001, 0002, 0003, ...")
+ {
+ nRet = style::NumberingType::ARABIC_ZERO4;
+ }
+ else if (rFormat == u"00001, 00002, 00003, ...")
+ {
+ nRet = style::NumberingType::ARABIC_ZERO5;
+ }
+
+ return nRet;
+}
+
+util::DateTime ConvertDateStringToDateTime( std::u16string_view rDateTime )
+{
+ util::DateTime aDateTime;
+ //xsd::DateTime in the format [-]CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] example: 2008-01-21T10:42:00Z
+ //OUString getToken( sal_Int32 token, sal_Unicode cTok, sal_Int32& index ) const
+ sal_Int32 nIndex = 0;
+ std::u16string_view sDate = o3tl::getToken(rDateTime, 0, 'T', nIndex );
+ // HACK: this is broken according to the spec, but MSOffice always treats the time as local,
+ // and writes it as Z (=UTC+0)
+ std::u16string_view sTime = o3tl::getToken(rDateTime, 0, 'Z', nIndex );
+ nIndex = 0;
+ aDateTime.Year = sal_uInt16( o3tl::toInt32(o3tl::getToken(sDate, 0, '-', nIndex )) );
+ aDateTime.Month = sal_uInt16( o3tl::toInt32(o3tl::getToken(sDate, 0, '-', nIndex )) );
+ if (nIndex != -1)
+ aDateTime.Day = sal_uInt16( o3tl::toInt32(sDate.substr( nIndex )) );
+
+ nIndex = 0;
+ aDateTime.Hours = sal_uInt16( o3tl::toInt32(o3tl::getToken(sTime, 0, ':', nIndex )) );
+ aDateTime.Minutes = sal_uInt16( o3tl::toInt32(o3tl::getToken(sTime, 0, ':', nIndex )) );
+ if (nIndex != -1)
+ aDateTime.Seconds = sal_uInt16( o3tl::toInt32(sTime.substr( nIndex )) );
+
+ return aDateTime;
+}
+
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/ConversionHelper.hxx b/sw/source/writerfilter/dmapper/ConversionHelper.hxx
new file mode 100644
index 000000000000..c14c8033ea58
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/ConversionHelper.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/RubyAdjust.hpp>
+
+namespace com::sun::star{
+ namespace lang{
+ struct Locale;
+ }
+ namespace table{
+ struct BorderLine2;
+ }
+}
+
+namespace writerfilter::dmapper::ConversionHelper{
+
+ // create a border line and return the distance value
+ void MakeBorderLine(sal_Int32 nLineThickness,
+ sal_Int32 nLineType,
+ sal_Int32 nLineColor,
+ css::table::BorderLine2& rToFill,
+ bool bIsOOXML);
+ //convert the number format string form MS format to SO format
+ OUString ConvertMSFormatStringToSO(const OUString& rFormat, css::lang::Locale& rLocale, bool bHijri);
+ // export just for test
+ SAL_DLLPUBLIC_EXPORT sal_Int32 convertTwipToMM100(sal_Int32 _t);
+ sal_Int32 convertTwipToMM100WithoutLimit(sal_Int32 _t);
+ double convertTwipToMM100Double(sal_Int32 _t);
+ SAL_DLLPUBLIC_EXPORT sal_uInt32 convertTwipToMM100Unsigned(sal_Int32 _t);
+ sal_Int16 convertTableJustification( sal_Int32 nIntValue );
+ css::text::RubyAdjust convertRubyAlign( sal_Int32 nIntValue );
+ sal_Int16 ConvertNumberingType(const sal_Int32 nFmt, const sal_Int16 nDefault = css::style::NumberingType::ARABIC);
+ sal_Int16 ConvertCustomNumberFormat(std::u16string_view rFormat);
+
+ css::util::DateTime ConvertDateStringToDateTime(std::u16string_view rDateTime);
+} // namespace writerfilter::dmapper::ConversionHelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DocumentProtection.cxx b/sw/source/writerfilter/dmapper/DocumentProtection.cxx
new file mode 100644
index 000000000000..dddf964c4022
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DocumentProtection.cxx
@@ -0,0 +1,239 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "DocumentProtection.hxx"
+#include "TagLogger.hxx"
+#include <vector>
+#include <comphelper/sequence.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+DocumentProtection::DocumentProtection()
+ : LoggedProperties("DocumentProtection")
+ , m_nEdit(
+ NS_ooxml::
+ LN_Value_doc_ST_DocProtect_none) // Specifies that no editing restrictions have been applied to the document
+ , m_bProtectForm(false)
+ , m_bRedlineProtection(false)
+ , m_bReadOnly(false)
+ , m_bEnforcement(false)
+ , m_bFormatting(false)
+ , m_nCryptProviderType(NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+ , m_sCryptAlgorithmClass("hash")
+ , m_sCryptAlgorithmType("typeAny")
+ , m_CryptSpinCount(0)
+{
+}
+
+DocumentProtection::~DocumentProtection() {}
+
+void DocumentProtection::lcl_attribute(Id nName, Value& val)
+{
+ int nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_DocProtect_edit: // 92037
+ m_nEdit = nIntValue;
+ // multiple DocProtect_edits should not exist. If they do, last one wins
+ m_bRedlineProtection = false;
+ m_bProtectForm = false;
+ m_bReadOnly = false;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges:
+ {
+ m_bRedlineProtection = true;
+ m_sRedlineProtectionKey = m_sHash;
+ break;
+ }
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_forms:
+ m_bProtectForm = true;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly:
+ m_bReadOnly = true;
+ break;
+ }
+ break;
+ case NS_ooxml::LN_CT_DocProtect_enforcement: // 92039
+ m_bEnforcement = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_DocProtect_formatting: // 92038
+ m_bFormatting = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_AG_Password_cryptProviderType: // 92025
+ m_nCryptProviderType = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmClass: // 92026
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgClass_hash) // 92023
+ m_sCryptAlgorithmClass = "hash";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmType: // 92027
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgType_typeAny) // 92024
+ m_sCryptAlgorithmType = "typeAny";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmSid: // 92028
+ m_sCryptAlgorithmSid = sStringValue;
+ break;
+ case NS_ooxml::LN_AG_Password_cryptSpinCount: // 92029
+ m_CryptSpinCount = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_hash: // 92035
+ m_sHash = sStringValue;
+ break;
+ case NS_ooxml::LN_AG_Password_salt: // 92036
+ m_sSalt = sStringValue;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void DocumentProtection::lcl_sprm(Sprm& /*rSprm*/) {}
+
+uno::Sequence<beans::PropertyValue> DocumentProtection::toSequence() const
+{
+ std::vector<beans::PropertyValue> documentProtection;
+
+ if (enabled())
+ {
+ // w:edit
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "edit";
+
+ switch (m_nEdit)
+ {
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_none:
+ aValue.Value <<= OUString("none");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly:
+ aValue.Value <<= OUString("readOnly");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_comments:
+ aValue.Value <<= OUString("comments");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges:
+ aValue.Value <<= OUString("trackedChanges");
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocProtect_forms:
+ aValue.Value <<= OUString("forms");
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+
+ documentProtection.push_back(aValue);
+ }
+
+ // w:enforcement
+ if (m_bEnforcement)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "enforcement";
+ aValue.Value <<= OUString("1");
+ documentProtection.push_back(aValue);
+ }
+
+ // w:formatting
+ if (m_bFormatting)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "formatting";
+ aValue.Value <<= OUString("1");
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptProviderType
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptProviderType";
+ if (m_nCryptProviderType == NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+ aValue.Value <<= OUString("rsaAES");
+ else if (m_nCryptProviderType == NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull)
+ aValue.Value <<= OUString("rsaFull");
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptAlgorithmClass
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptAlgorithmClass";
+ aValue.Value <<= m_sCryptAlgorithmClass;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptAlgorithmType
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptAlgorithmType";
+ aValue.Value <<= m_sCryptAlgorithmType;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptAlgorithmSid
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptAlgorithmSid";
+ aValue.Value <<= m_sCryptAlgorithmSid;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:cryptSpinCount
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "cryptSpinCount";
+ aValue.Value <<= OUString::number(m_CryptSpinCount);
+ documentProtection.push_back(aValue);
+ }
+
+ // w:hash
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "hash";
+ aValue.Value <<= m_sHash;
+ documentProtection.push_back(aValue);
+ }
+
+ // w:salt
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "salt";
+ aValue.Value <<= m_sSalt;
+ documentProtection.push_back(aValue);
+ }
+ }
+
+ return comphelper::containerToSequence(documentProtection);
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DocumentProtection.hxx b/sw/source/writerfilter/dmapper/DocumentProtection.hxx
new file mode 100644
index 000000000000..2ec0f3f21c41
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DocumentProtection.hxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper
+{
+/** Document protection restrictions
+ *
+ * This element specifies the set of document protection restrictions which have been applied to the contents of a
+ * WordprocessingML document.These restrictions should be enforced by applications editing this document
+ * when the enforcement attribute is turned on, and ignored(but persisted) otherwise.Document protection is a
+ * set of restrictions used to prevent unintentional changes to all or part of a WordprocessingML document.
+ */
+class DocumentProtection : public LoggedProperties
+{
+private:
+ /** Document Editing Restrictions
+ *
+ * Possible values:
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_none
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_readOnly
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_comments
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_trackedChanges
+ * - NS_ooxml::LN_Value_doc_ST_DocProtect_forms
+ */
+ sal_Int32 m_nEdit;
+ bool m_bProtectForm;
+ bool m_bRedlineProtection;
+ OUString m_sRedlineProtectionKey;
+ bool m_bReadOnly;
+ bool m_bEnforcement;
+ bool m_bFormatting;
+
+ /** Provider type
+ *
+ * Possible values:
+ * "rsaAES" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES
+ * "rsaFull" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull
+ */
+ sal_Int32 m_nCryptProviderType;
+ OUString m_sCryptAlgorithmClass;
+ OUString m_sCryptAlgorithmType;
+ OUString m_sCryptAlgorithmSid;
+ sal_Int32 m_CryptSpinCount;
+ OUString m_sHash;
+ OUString m_sSalt;
+
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+ bool enabled() const { return !isNone(); }
+ bool isNone() const { return m_nEdit == NS_ooxml::LN_Value_doc_ST_DocProtect_none; };
+
+public:
+ DocumentProtection();
+ virtual ~DocumentProtection() override;
+
+ css::uno::Sequence<css::beans::PropertyValue> toSequence() const;
+
+ bool getProtectForm() const { return m_bProtectForm; }
+ bool getRedlineProtection() const { return m_bRedlineProtection; }
+ bool getReadOnly() const { return m_bReadOnly; }
+ bool getEnforcement() const { return m_bEnforcement; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapper.cxx b/sw/source/writerfilter/dmapper/DomainMapper.cxx
new file mode 100644
index 000000000000..22a2a17045c0
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx
@@ -0,0 +1,5049 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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/awt/Gradient2.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <com/sun/star/drawing/FillStyle.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 <com/sun/star/util/XComplexColor.hpp>
+#include <comphelper/types.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <editeng/escapementitem.hxx>
+#include <filter/msfilter/util.hxx>
+#include <sfx2/DocumentMetadataAccess.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include "TextEffectsHandler.hxx"
+#include "ThemeColorHandler.hxx"
+#include "CellColorHandler.hxx"
+#include "SectionColumnHandler.hxx"
+#include "GraphicHelpers.hxx"
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <sal/log.hxx>
+#include <tools/UnitConversion.hxx>
+
+using namespace ::com::sun::star;
+using namespace oox;
+
+namespace writerfilter::dmapper{
+
+struct
+{
+ sal_Int32 h;
+ bool orient;
+ sal_Int32 w;
+} CT_PageSz;
+
+
+DomainMapper::DomainMapper( const uno::Reference< uno::XComponentContext >& xContext,
+ uno::Reference<io::XInputStream> const& xInputStream,
+ uno::Reference<lang::XComponent> const& xModel,
+ bool bRepairStorage,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc) :
+ LoggedProperties("DomainMapper"),
+ LoggedTable("DomainMapper"),
+ LoggedStream("DomainMapper"),
+ m_pImpl(new DomainMapper_Impl(*this, xContext, xModel, eDocumentType, rMediaDesc)),
+ mbIsSplitPara(false),
+ mbHasControls(false),
+ mbWasShapeInPara(false)
+{
+ if (m_pImpl->IsNewDoc())
+ {
+ // #i24363# tab stops relative to indent
+ m_pImpl->SetDocumentSettingsProperty(
+ getPropertyName(PROP_TABS_RELATIVE_TO_INDENT),
+ uno::Any(false));
+ m_pImpl->SetDocumentSettingsProperty(
+ getPropertyName(PROP_SURROUND_TEXT_WRAP_SMALL),
+ uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty(
+ getPropertyName(PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING),
+ uno::Any(true));
+
+ // Don't load the default style definitions to avoid weird mix
+ m_pImpl->SetDocumentSettingsProperty("StylesNoDefault", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("MsWordCompTrailingBlanks", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("HeaderSpacingBelowLastPara",
+ uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("FrameAutowidthWithMorePara", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("FootnoteInColumnToPageEnd", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty("TabAtLeftIndentForParagraphsInList", uno::Any(true));
+ m_pImpl->SetDocumentSettingsProperty(u"NoGapAfterNoteNumber"_ustr, uno::Any(true));
+
+ // Enable only for new documents, since pasting from clipboard can influence existing doc
+ m_pImpl->SetDocumentSettingsProperty("NoNumberingShowFollowBy", uno::Any(true));
+ }
+
+ // Initialize RDF metadata, to be able to add statements during the import.
+ try
+ {
+ uno::Reference<rdf::XDocumentMetadataAccess> xDocumentMetadataAccess(xModel, uno::UNO_QUERY_THROW);
+ uno::Reference<embed::XStorage> xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ OUString aBaseURL = rMediaDesc.getUnpackedValueOrDefault("URL", OUString());
+ const uno::Reference<frame::XModel> xModel_(xModel,
+ uno::UNO_QUERY_THROW);
+ const uno::Reference<rdf::XURI> xBaseURI(sfx2::createBaseURI(xContext, xModel_, aBaseURL, u""));
+ const uno::Reference<task::XInteractionHandler> xHandler;
+ xDocumentMetadataAccess->loadMetadataFromStorage(xStorage, xBaseURI, xHandler);
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "failed to initialize RDF metadata");
+ }
+
+ if (eDocumentType == SourceDocumentType::OOXML) {
+ // tdf#108350
+ // In Word since version 2007, the default document font is Calibri 11 pt.
+ // If a DOCX document doesn't contain font information, we should assume
+ // the intended font to provide best layout match.
+ try
+ {
+ uno::Reference< beans::XPropertySet > xDefProps(GetTextFactory()->createInstance("com.sun.star.text.Defaults"),
+ uno::UNO_QUERY_THROW);
+ xDefProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), css::uno::Any(OUString("Calibri")));
+ xDefProps->setPropertyValue(getPropertyName(PROP_CHAR_HEIGHT), css::uno::Any(double(11)));
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "failed to initialize default font");
+ }
+ }
+
+ //import document properties
+ try
+ {
+ m_pImpl->m_xDocumentStorage = comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
+ OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, bRepairStorage);
+
+ uno::Reference< uno::XInterface > xTemp = xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.OOXMLDocumentPropertiesImporter",
+ xContext);
+
+ uno::Reference< document::XOOXMLDocumentPropertiesImporter > xImporter( xTemp, uno::UNO_QUERY_THROW );
+ uno::Reference< document::XDocumentPropertiesSupplier > xPropSupplier( xModel, uno::UNO_QUERY_THROW);
+ xImporter->importProperties(m_pImpl->m_xDocumentStorage,
+ xPropSupplier->getDocumentProperties());
+ }
+ catch( const uno::Exception& ) {}
+}
+
+void DomainMapper::setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument)
+{
+ m_pImpl->setDocumentReference(pDocument);
+}
+
+DomainMapper::~DomainMapper()
+{
+ try
+ {
+ // Remove temporary footnotes and endnotes
+ m_pImpl->RemoveTemporaryFootOrEndnotes();
+
+ uno::Reference< text::XDocumentIndexesSupplier> xIndexesSupplier( m_pImpl->GetTextDocument(), uno::UNO_QUERY );
+ sal_Int32 nIndexes = 0;
+ if( xIndexesSupplier.is() )
+ {
+ uno::Reference< container::XIndexAccess > xIndexes = xIndexesSupplier->getDocumentIndexes();
+ nIndexes = xIndexes->getCount();
+ }
+ // If we have page references, those need updating as well, similar to the indexes.
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if(xTextFieldsSupplier.is())
+ {
+ uno::Reference<container::XEnumeration> xEnumeration = xTextFieldsSupplier->getTextFields()->createEnumeration();
+ while(xEnumeration->hasMoreElements())
+ {
+ ++nIndexes;
+ xEnumeration->nextElement();
+ }
+ }
+
+ mbHasControls |= m_pImpl->m_pSdtHelper->hasElements();
+ if ( nIndexes || mbHasControls )
+ {
+ //index update has to wait until first view is created
+ uno::Reference< document::XEventBroadcaster > xBroadcaster(xIndexesSupplier, uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addEventListener(uno::Reference< document::XEventListener >(new ModelEventListener(nIndexes, mbHasControls)));
+ }
+
+
+ // Apply the document settings for both DOCX and RTF after everything else
+ m_pImpl->GetSettingsTable()->ApplyProperties( m_pImpl->GetTextDocument( ) );
+
+ // now that importing is finished, re-enable default styles for any that were never defined/imported.
+ m_pImpl->SetDocumentSettingsProperty("StylesNoDefault", uno::Any(false));
+
+ // Grab-bag handling
+ comphelper::SequenceAsHashMap aProperties;
+
+ // Add the saved w:themeFontLang setting
+ aProperties["ThemeFontLangProps"] <<= m_pImpl->GetSettingsTable()->GetThemeFontLangProperties();
+
+ // Add the saved compat settings
+ aProperties["CompatSettings"] <<= m_pImpl->GetSettingsTable()->GetCompatSettings();
+
+ // Add the saved DocumentProtection settings
+ aProperties["DocumentProtection"] <<= m_pImpl->GetSettingsTable()->GetDocumentProtectionSettings();
+
+ // Add the saved w:doNotHyphenateCaps setting
+ aProperties["NoHyphenateCaps"] <<= m_pImpl->GetSettingsTable()->GetNoHyphenateCaps();
+
+ uno::Reference<beans::XPropertySet> xDocProps(m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if (xDocProps.is())
+ {
+ comphelper::SequenceAsHashMap aGrabBag(xDocProps->getPropertyValue("InteropGrabBag"));
+ aGrabBag.update(aProperties);
+ xDocProps->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag.getAsConstPropertyValueList()));
+ }
+
+ // tdf#138782: for docs created in MS Word 2010 and older (compatibilityMode <= 14)
+ m_pImpl->SetDocumentSettingsProperty(
+ "AddFrameOffsets",
+ uno::Any(14 >= m_pImpl->GetSettingsTable()->GetWordCompatibilityMode()));
+ }
+ catch( const uno::Exception& ) {}
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endDocument();
+#endif
+}
+
+void DomainMapper::lcl_attribute(Id nName, Value & val)
+{
+ if (m_pImpl->hasTableManager() && m_pImpl->getTableManager().attribute(nName, val))
+ return;
+
+ static const int nSingleLineSpacing = 240;
+ sal_Int32 nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ SectionPropertyMap * pSectionContext = m_pImpl->GetSectionContext();
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_Lvl_start:
+ break;
+ case NS_ooxml::LN_CT_Lvl_numFmt:
+ break;
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ break;
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_nsid:
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ break;
+ case NS_ooxml::LN_CT_Border_sz:
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ break;
+ case NS_ooxml::LN_CT_Border_space:
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ break;
+ case NS_ooxml::LN_CT_Border_frame:
+ break;
+ case NS_ooxml::LN_headerr:
+ break;
+ case NS_ooxml::LN_footerr:
+ break;
+ case NS_ooxml::LN_endnote:
+ break;
+ case NS_ooxml::LN_CT_Bookmark_name:
+ m_pImpl->SetBookmarkName( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_MarkupRangeBookmark_id:
+ // add a bookmark range -- this remembers a bookmark starting here
+ // or, if the bookmark was already started or, if the bookmark was
+ // already started before, writes out the bookmark
+ m_pImpl->StartOrEndBookmark( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_MarkupRange_displacedByCustomXml:
+ break;
+ case NS_ooxml::LN_NUMBERING:
+ break;
+ case NS_ooxml::LN_FONTTABLE:
+ break;
+ case NS_ooxml::LN_STYLESHEET:
+ break;
+
+ case NS_ooxml::LN_CT_Sym_char:
+ m_pImpl->SetSymbolChar(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Sym_font:
+ m_pImpl->SetSymbolFont(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Underline_val:
+ if (m_pImpl->GetTopContext())
+ handleUnderlineType(nIntValue, m_pImpl->GetTopContext());
+ break;
+ case NS_ooxml::LN_CT_Underline_color:
+ if (m_pImpl->GetTopContext())
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_HAS_COLOR, uno::Any( true ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_COLOR, uno::Any( nIntValue ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_Underline_themeColor:
+ case NS_ooxml::LN_CT_Underline_themeTint:
+ case NS_ooxml::LN_CT_Underline_themeShade:
+ if (m_pImpl->GetTopContext())
+ {
+ uno::Reference<util::XComplexColor> xComplexColor;
+ model::ComplexColor aComplexColor;
+
+ PropertyMapPtr pTopContext = m_pImpl->GetTopContext();
+ std::optional<PropertyMap::Property> aValue;
+ if (pTopContext && (aValue = pTopContext->getProperty(PROP_CHAR_UNDERLINE_COMPLEX_COLOR)))
+ {
+ aValue->second >>= xComplexColor;
+ if (xComplexColor.is())
+ aComplexColor = model::color::getFromXComplexColor(xComplexColor);
+ }
+
+ if (nName == NS_ooxml::LN_CT_Underline_themeColor)
+ {
+ auto eThemeColorType = TDefTableHandler::getThemeColorTypeIndex(nIntValue);
+ aComplexColor.setThemeColor(eThemeColorType);
+ }
+ else if (nName == NS_ooxml::LN_CT_Underline_themeTint)
+ {
+ if (nIntValue > 0)
+ {
+ sal_Int16 nTransformedValue = sal_Int16((255.0 - nIntValue) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Tint, sal_Int16(nTransformedValue)});
+ }
+ }
+ else if (nName == NS_ooxml::LN_CT_Underline_themeShade)
+ {
+ if (nIntValue > 0)
+ {
+ sal_Int16 nTransformedValue = sal_Int16((255.0 - nIntValue) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Shade, sal_Int16(nTransformedValue)});
+ }
+ }
+ xComplexColor = model::color::createXComplexColor(aComplexColor);
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_UNDERLINE_COMPLEX_COLOR, uno::Any(xComplexColor));
+ }
+ break;
+
+ case NS_ooxml::LN_CT_TabStop_val:
+ if (sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_TabJc_clear)
+ {
+ m_pImpl->m_aCurrentTabStop.bDeleted = true;
+ }
+ else
+ {
+ m_pImpl->m_aCurrentTabStop.bDeleted = false;
+ m_pImpl->m_aCurrentTabStop.Alignment = getTabAlignFromValue(nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_TabStop_leader:
+ m_pImpl->m_aCurrentTabStop.FillChar = getFillCharFromValue(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_TabStop_pos:
+ m_pImpl->m_aCurrentTabStop.Position = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+
+ case NS_ooxml::LN_CT_Fonts_ascii:
+ if (m_pImpl->GetTopContext())
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, uno::Any( sStringValue ));
+ }
+ break;
+ case NS_ooxml::LN_CT_Fonts_asciiTheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "asciiTheme", ThemeHandler::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ // note: overwrite Fonts_ascii with Fonts_asciiTheme *even if*
+ // theme font is empty - this is apparently what Word 2013 does
+ uno::Any aPropValue( m_pImpl->getFontNameForTheme( nIntValue ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME, aPropValue );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_ASCII, aPropValue, true, CHAR_GRAB_BAG );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_ASCII, uno::Any( ThemeHandler::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", ThemeHandler::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_H_ANSI, uno::Any( ThemeHandler::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ break;
+ case NS_ooxml::LN_CT_Fonts_eastAsia:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::Any( sStringValue ));
+ break;
+ case NS_ooxml::LN_CT_Fonts_eastAsiaTheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "eastAsiaTheme", ThemeHandler::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ uno::Any aPropValue( m_pImpl->getFontNameForTheme( nIntValue ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_ASIAN, aPropValue );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_EAST_ASIA, aPropValue, true, CHAR_GRAB_BAG );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_EAST_ASIA, uno::Any( ThemeHandler::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ }
+ break;
+ case NS_ooxml::LN_CT_Fonts_cs:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_COMPLEX, uno::Any( sStringValue ));
+ break;
+ case NS_ooxml::LN_CT_Fonts_cstheme:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "cstheme", ThemeHandler::getStringForTheme(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ uno::Any aPropValue( m_pImpl->getFontNameForTheme( nIntValue ) );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_FONT_NAME_COMPLEX, aPropValue );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_FONT_NAME_CS, aPropValue, true, CHAR_GRAB_BAG );
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_NAME_CS, uno::Any( ThemeHandler::getStringForTheme(nIntValue) ), true, CHAR_GRAB_BAG);
+ }
+ break;
+ case NS_ooxml::LN_CT_Spacing_before:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "before", OUString::number(nIntValue));
+ if (m_pImpl->GetTopContext())
+ // Don't overwrite NS_ooxml::LN_CT_Spacing_beforeAutospacing.
+ m_pImpl->GetTopContext()->Insert(
+ PROP_PARA_TOP_MARGIN,
+ uno::Any(static_cast<sal_Int32>(convertTwipToMm100(nIntValue))), false);
+ break;
+ case NS_ooxml::LN_CT_Spacing_beforeLines:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "beforeLines", OUString::number(nIntValue));
+ // We would need to make sure that this doesn't overwrite any
+ // NS_ooxml::LN_CT_Spacing_before in parent styles before style
+ // sheet support can be enabled.
+ if (m_pImpl->GetTopContext() && !IsStyleSheetImport())
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_TOP_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(nIntValue * nSingleLineSpacing / 100)), false);
+ break;
+ case NS_ooxml::LN_CT_Spacing_after:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "after", OUString::number(nIntValue));
+ if (m_pImpl->GetTopContext())
+ {
+ // Don't overwrite NS_ooxml::LN_CT_Spacing_afterAutospacing.
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any( ConversionHelper::convertTwipToMM100( nIntValue ) ), false);
+
+ uno::Any aContextualSpacingFromStyle = m_pImpl->GetPropertyFromParaStyleSheet(PROP_PARA_CONTEXT_MARGIN);
+ if (aContextualSpacingFromStyle.hasValue())
+ // Setting "after" spacing means Writer doesn't inherit
+ // contextual spacing anymore from style, but Word does.
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_CONTEXT_MARGIN, aContextualSpacingFromStyle);
+ }
+ break;
+ case NS_ooxml::LN_CT_Spacing_afterLines:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "afterLines", OUString::number(nIntValue));
+ // We would need to make sure that this doesn't overwrite any
+ // NS_ooxml::LN_CT_Spacing_after in parent styles before style
+ // sheet support can be enabled.
+ if (m_pImpl->GetTopContext() && !IsStyleSheetImport())
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(nIntValue * nSingleLineSpacing / 100)), false);
+ break;
+ case NS_ooxml::LN_CT_Spacing_line: //91434
+ case NS_ooxml::LN_CT_Spacing_lineRule: //91435
+ {
+ style::LineSpacing aSpacing;
+ PropertyMapPtr pTopContext = m_pImpl->GetTopContext();
+ std::optional<PropertyMap::Property> aLineSpacingVal;
+ if (pTopContext && (aLineSpacingVal = pTopContext->getProperty(PROP_PARA_LINE_SPACING)) )
+ {
+ aLineSpacingVal->second >>= aSpacing;
+ }
+ else
+ {
+ //default to single line spacing
+ aSpacing.Mode = style::LineSpacingMode::FIX;
+ aSpacing.Height = sal_Int16(ConversionHelper::convertTwipToMM100( nSingleLineSpacing ));
+ }
+ if( nName == NS_ooxml::LN_CT_Spacing_line )
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "line", OUString::number(nIntValue));
+ //now set the value depending on the Mode
+ if( aSpacing.Mode == style::LineSpacingMode::PROP )
+ aSpacing.Height = sal_Int16(nIntValue * 100 / nSingleLineSpacing );
+ else
+ aSpacing.Height = sal_Int16(ConversionHelper::convertTwipToMM100( nIntValue ));
+ }
+ else //NS_ooxml::LN_CT_Spacing_lineRule:
+ {
+ // exactly, atLeast, auto
+ if( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto)
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "lineRule", "auto");
+ if (aSpacing.Height >= 0)
+ {
+ aSpacing.Mode = style::LineSpacingMode::PROP;
+ //reinterpret the already set value
+ aSpacing.Height = sal_Int16( aSpacing.Height * 100 / ConversionHelper::convertTwipToMM100( nSingleLineSpacing ));
+ }
+ else
+ {
+ // Negative value still means a positive height,
+ // just the mode is "exact".
+ aSpacing.Mode = style::LineSpacingMode::FIX;
+ aSpacing.Height *= -1;
+ }
+ }
+ else if( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast)
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "lineRule", "atLeast");
+ aSpacing.Mode = style::LineSpacingMode::MINIMUM;
+ }
+ else // NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "lineRule", "exact");
+ aSpacing.Mode = style::LineSpacingMode::FIX;
+ }
+ }
+ if (pTopContext)
+ pTopContext->Insert(PROP_PARA_LINE_SPACING, uno::Any( aSpacing ));
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_start:
+ case NS_ooxml::LN_CT_Ind_left:
+ if (m_pImpl->GetTopContext())
+ {
+ // Word inherits FirstLineIndent property of the numbering, even if ParaLeftMargin is set, Writer does not.
+ // So copy it explicitly, if necessary.
+ sal_Int32 nFirstLineIndent = m_pImpl->getCurrentNumberingProperty("FirstLineIndent");
+ sal_Int32 nIndentAt = m_pImpl->getCurrentNumberingProperty("IndentAt");
+
+ sal_Int32 nParaLeftMargin = ConversionHelper::convertTwipToMM100(nIntValue);
+ if (nParaLeftMargin != 0 && nIndentAt == nParaLeftMargin)
+ // Avoid direct left margin when it's the same as from the
+ // numbering.
+ break;
+
+ if (nFirstLineIndent != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN,
+ uno::Any(nParaLeftMargin));
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_end:
+ case NS_ooxml::LN_CT_Ind_right:
+ if (m_pImpl->GetTopContext())
+ {
+ // Word inherits FirstLineIndent/ParaLeftMargin property of the numbering, even if ParaRightMargin is set, Writer does not.
+ // So copy it explicitly, if necessary.
+ sal_Int32 nFirstLineIndent = m_pImpl->getCurrentNumberingProperty("FirstLineIndent");
+ sal_Int32 nParaLeftMargin = m_pImpl->getCurrentNumberingProperty("IndentAt");
+
+ if (nFirstLineIndent != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+ if (nParaLeftMargin != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+
+ m_pImpl->GetTopContext()->Insert(
+ PROP_PARA_RIGHT_MARGIN, uno::Any( ConversionHelper::convertTwipToMM100(nIntValue ) ));
+ }
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "right", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Ind_hanging:
+ if (m_pImpl->GetTopContext())
+ {
+ sal_Int32 nValue = ConversionHelper::convertTwipToMM100( nIntValue );
+ m_pImpl->GetTopContext()->Insert(
+ PROP_PARA_FIRST_LINE_INDENT, uno::Any( - nValue ));
+
+ // See above, need to inherit left margin from list style when first is set.
+ sal_Int32 nParaLeftMargin = m_pImpl->getCurrentNumberingProperty("IndentAt");
+ if (nParaLeftMargin != 0)
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ if (m_pImpl->GetTopContext())
+ {
+ sal_Int32 nFirstLineIndent
+ = m_pImpl->getCurrentNumberingProperty("FirstLineIndent");
+ sal_Int32 nParaFirstLineIndent = ConversionHelper::convertTwipToMM100(nIntValue);
+ if (nParaFirstLineIndent != 0 && nFirstLineIndent == nParaFirstLineIndent)
+ // Avoid direct first margin when it's the same as from the
+ // numbering.
+ break;
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_FIRST_LINE_INDENT,
+ uno::Any(nParaFirstLineIndent));
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_rightChars:
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "rightChars", OUString::number(nIntValue));
+ break;
+
+ case NS_ooxml::LN_CT_EastAsianLayout_id:
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_combine:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_IS_ON, uno::Any ( nIntValue != 0 ));
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_combineBrackets:
+ if (m_pImpl->GetTopContext())
+ {
+ OUString sCombinePrefix = getBracketStringFromEnum(nIntValue);
+ OUString sCombineSuffix = getBracketStringFromEnum(nIntValue, false);
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_PREFIX, uno::Any ( sCombinePrefix ));
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMBINE_SUFFIX, uno::Any ( sCombineSuffix ));
+ }
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_vert:
+ if (m_pImpl->GetTopContext())
+ {
+ sal_Int16 nRotationAngle = (nIntValue ? 900 : 0);
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_ROTATION, uno::Any ( nRotationAngle ));
+ }
+ break;
+ case NS_ooxml::LN_CT_EastAsianLayout_vertCompress:
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_ROTATION_IS_FIT_TO_LINE, uno::Any ( nIntValue != 0 ));
+ break;
+
+ case NS_ooxml::LN_CT_PageSz_code:
+ break;
+ case NS_ooxml::LN_CT_PageSz_h:
+ {
+ sal_Int32 nHeight = ConversionHelper::convertTwipToMM100WithoutLimit(nIntValue);
+ CT_PageSz.h = PaperInfo::sloppyFitPageDimension(nHeight);
+ }
+ break;
+ case NS_ooxml::LN_CT_PageSz_orient:
+ CT_PageSz.orient = (nIntValue != NS_ooxml::LN_Value_ST_PageOrientation_portrait);
+ break;
+ case NS_ooxml::LN_CT_PageSz_w:
+ {
+ sal_Int32 nWidth = ConversionHelper::convertTwipToMM100WithoutLimit(nIntValue);
+ CT_PageSz.w = PaperInfo::sloppyFitPageDimension(nWidth);
+ }
+ break;
+
+ case NS_ooxml::LN_CT_PageMar_top:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_TOP, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_right:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_RIGHT, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_bottom:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_BOTTOM, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_left:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_LEFT, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_header:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_HEADER, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_footer:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_FOOTER, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PageMar_gutter:
+ m_pImpl->SetPageMarginTwip( PAGE_MAR_GUTTER, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_PaperSource_first:
+ m_pImpl->SetPaperSource(PAPER_SOURCE_FIRST, sStringValue.toInt32());
+ break;
+ case NS_ooxml::LN_CT_PaperSource_other:
+ m_pImpl->SetPaperSource(PAPER_SOURCE_OTHER, sStringValue.toInt32());
+ break;
+ case NS_ooxml::LN_CT_Language_val: //90314
+ case NS_ooxml::LN_CT_Language_eastAsia: //90315
+ case NS_ooxml::LN_CT_Language_bidi: //90316
+ {
+ // store decimal symbol associated to the language of the document
+ if ( m_pImpl->IsDocDefaultsImport() && ( nName == NS_ooxml::LN_CT_Language_val ) )
+ {
+ LanguageTag aLanguageTag( sStringValue );
+ LocaleDataWrapper aLocaleWrapper( std::move(aLanguageTag) );
+ if ( aLocaleWrapper.getNumDecimalSep() == "," )
+ m_pImpl->SetIsDecimalComma();
+
+ }
+ if (nName == NS_ooxml::LN_CT_Language_eastAsia)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "eastAsia", sStringValue);
+ else if (nName == NS_ooxml::LN_CT_Language_val)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "val", sStringValue);
+ else if (nName == NS_ooxml::LN_CT_Language_bidi)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "bidi", sStringValue);
+ lang::Locale aLocale;
+ if (sStringValue.getLength() <= 3 && sStringValue.getLength() >= 1)
+ {
+ // Cheesy Google Docs is known to tag language-only even for
+ // "en" or others that need some region to distinguish language
+ // variants for spell-checker and hyphenation. Obtain our known
+ // fallback to clarify and match. The original value/context is
+ // unknown anyway.
+ LanguageTag aLanguageTag( sStringValue);
+ aLanguageTag.makeFallback();
+ if (aLanguageTag.getLanguage() == sStringValue)
+ aLocale = aLanguageTag.getLocale();
+ else
+ {
+ // Do not fallback for an unknown language, which usually
+ // results in "en-US", or any other non-matching case.
+ aLocale = LanguageTag::convertToLocale( sStringValue);
+ }
+ }
+ else
+ {
+ aLocale = LanguageTag::convertToLocale( sStringValue);
+ }
+ if (m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(NS_ooxml::LN_CT_Language_val== nName ? PROP_CHAR_LOCALE :
+ NS_ooxml::LN_CT_Language_eastAsia == nName ? PROP_CHAR_LOCALE_ASIAN : PROP_CHAR_LOCALE_COMPLEX,
+ uno::Any( aLocale ) );
+ }
+ break;
+ // See SwWW8ImplReader::GetParagraphAutoSpace() on why these are 100 and 280
+ case NS_ooxml::LN_CT_Spacing_beforeAutospacing:
+ {
+ sal_Int32 default_spacing = -1;
+ if (nIntValue)
+ {
+ m_pImpl->SetParaAutoBefore(true);
+
+ default_spacing = 100;
+ if (!m_pImpl->GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing())
+ {
+ // 49 is just the old value that should be removed, once the
+ // root cause in SwTabFrm::MakeAll() is fixed.
+ if (m_pImpl->GetSettingsTable()->GetView() == NS_ooxml::LN_Value_doc_ST_View_web)
+ default_spacing = 49;
+ else
+ default_spacing = 280;
+ }
+ // required at export (here mainly for StyleSheets) to determine if the setting has changed from grab_bag
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_TOP_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(default_spacing)));
+ }
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::Any( ConversionHelper::convertTwipToMM100(default_spacing) ),true, PARA_GRAB_BAG );
+ }
+ break;
+ case NS_ooxml::LN_CT_Spacing_afterAutospacing:
+ {
+ sal_Int32 default_spacing = -1;
+ if (nIntValue)
+ {
+ default_spacing = 100;
+ if (!m_pImpl->GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing())
+ {
+ if (m_pImpl->GetSettingsTable()->GetView() == NS_ooxml::LN_Value_doc_ST_View_web)
+ default_spacing = 49;
+ else
+ default_spacing = 280;
+ }
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any(ConversionHelper::convertTwipToMM100(default_spacing)));
+ }
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, uno::Any( ConversionHelper::convertTwipToMM100(default_spacing) ),true, PARA_GRAB_BAG );
+ }
+ break;
+ case NS_ooxml::LN_CT_SmartTagRun_uri:
+ m_pImpl->getSmartTagHandler().setURI(val.getString());
+ break;
+ case NS_ooxml::LN_CT_SmartTagRun_element:
+ m_pImpl->getSmartTagHandler().setElement(val.getString());
+ break;
+ case NS_ooxml::LN_CT_Br_type:
+ // Handled in the OOXMLBreakHandler dtor.
+ break;
+ case NS_ooxml::LN_CT_Br_clear:
+ m_pImpl->HandleLineBreakClear(val.getInt());
+ break;
+ case NS_ooxml::LN_CT_Fonts_hint :
+ /* assigns script type to ambiguous characters, values can be:
+ NS_ooxml::LN_Value_ST_Hint_default
+ NS_ooxml::LN_Value_ST_Hint_eastAsia
+ NS_ooxml::LN_Value_ST_Hint_cs
+ */
+ //TODO: unsupported?
+ break;
+ case NS_ooxml::LN_CT_TblBorders_right:
+ case NS_ooxml::LN_CT_TblBorders_top:
+ case NS_ooxml::LN_CT_TblBorders_left:
+ case NS_ooxml::LN_CT_TblBorders_bottom:
+ //todo: handle cell mar
+ break;
+ case NS_ooxml::LN_blip: // contains the binary graphic
+ case NS_ooxml::LN_shape:
+ {
+ //looks a bit like a hack - and it is. The graphic import is split into the inline_inline part and
+ //afterwards the adding of the binary data.
+ m_pImpl->m_eGraphicImportType = IMPORT_AS_DETECTED_INLINE; // really ???
+ m_pImpl->GetGraphicImport()->attribute(nName, val);
+ m_pImpl->ImportGraphic(val.getProperties());
+ }
+ 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:
+ {
+ ParagraphPropertiesPropertyMap* pParaProperties = nullptr;
+ // handle frame properties at styles
+ if( m_pImpl->GetTopContextType() == CONTEXT_STYLESHEET )
+ pParaProperties = dynamic_cast< ParagraphPropertiesPropertyMap*>( m_pImpl->GetTopContextOfType( CONTEXT_STYLESHEET ).get() );
+ else
+ pParaProperties = dynamic_cast< ParagraphPropertiesPropertyMap*>( m_pImpl->GetTopContextOfType( CONTEXT_PARAGRAPH ).get() );
+
+ if( pParaProperties )
+ {
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_FramePr_dropCap:
+ pParaProperties->props().SetDropCap( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_lines:
+ pParaProperties->props().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->props().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->props().SetvAnchor( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_x:
+ pParaProperties->props().Setx(
+ ConversionHelper::convertTwipToMM100(nIntValue ));
+ pParaProperties->props().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->props().SetxAlign( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_FramePr_y:
+ pParaProperties->props().Sety(
+ ConversionHelper::convertTwipToMM100(nIntValue ));
+ pParaProperties->props().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->props().SetFrameMode(false);
+ }
+ nIntValue = text::VertOrientation::NONE;
+ break;
+ }
+ default:
+ nIntValue = text::VertOrientation::NONE;
+ break;
+ }
+ pParaProperties->props().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->props().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->props().SetWrap ( text::WrapTextMode_DYNAMIC ) ;
+ else if (sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_around)
+ pParaProperties->props().SetWrap(text::WrapTextMode_PARALLEL);
+ else if (sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_doc_ST_Wrap_none)
+ pParaProperties->props().SetWrap ( text::WrapTextMode_THROUGH ) ;
+ else
+ pParaProperties->props().SetWrap ( text::WrapTextMode_NONE ) ;
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_w:
+ pParaProperties->props().Setw(
+ ConversionHelper::convertTwipToMM100(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ pParaProperties->props().Seth(
+ ConversionHelper::convertTwipToMM100(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ pParaProperties->props().SethSpace(
+ ConversionHelper::convertTwipToMM100(nIntValue ));
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ pParaProperties->props().SetvSpace(
+ ConversionHelper::convertTwipToMM100(nIntValue ));
+ break;
+ default:;
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrackChange_author:
+ m_pImpl->SetCurrentRedlineAuthor( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_TrackChange_date:
+ m_pImpl->SetCurrentRedlineDate( sStringValue );
+ break;
+ case NS_ooxml::LN_CT_Markup_id:
+ m_pImpl->SetCurrentRedlineId( nIntValue );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart:
+ m_pImpl->AddAnnotationPosition( true, nIntValue );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd:
+ m_pImpl->AddAnnotationPosition( false, nIntValue );
+ break;
+ case NS_ooxml::LN_CT_Comment_initials:
+ m_pImpl->SetCurrentRedlineInitials(sStringValue);
+ break;
+ case NS_ooxml::LN_token:
+ m_pImpl->SetCurrentRedlineToken( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_start:
+ case NS_ooxml::LN_CT_LineNumber_distance:
+ case NS_ooxml::LN_CT_LineNumber_countBy:
+ case NS_ooxml::LN_CT_LineNumber_restart:
+ {
+ //line numbering in Writer is a global document setting
+ //in Word is a section setting
+ //if line numbering is switched on anywhere in the document it's set at the global settings
+ LineNumberSettings aSettings = m_pImpl->GetLineNumberSettings();
+ switch( nName )
+ {
+ case NS_ooxml::LN_CT_LineNumber_countBy:
+ aSettings.nInterval = nIntValue;
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetLnnMod( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_start:
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetLnnMin( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_distance:
+ aSettings.nDistance = ConversionHelper::convertTwipToMM100( nIntValue );
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetdxaLnn( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_LineNumber_restart:
+ aSettings.bRestartAtEachPage = nIntValue == NS_ooxml::LN_Value_ST_LineNumberRestart_newPage;
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ pSectionContext->SetLnc( nIntValue );
+ break;
+ default:;
+ }
+ m_pImpl->SetLineNumberSettings( aSettings );
+ }
+ break;
+ case NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows:
+ m_pImpl->StartCustomFootnote(m_pImpl->GetTopContext());
+ break;
+ case NS_ooxml::LN_CT_FtnEdnRef_id:
+ // footnote or endnote reference id - not needed
+ break;
+ case NS_ooxml::LN_CT_DocGrid_linePitch:
+ {
+ //see SwWW8ImplReader::SetDocumentGrid
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ pSectionContext->SetGridLinePitch( ConversionHelper::convertTwipToMM100( nIntValue ) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_DocGrid_charSpace:
+ {
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ pSectionContext->SetDxtCharSpace( nIntValue );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_DocGrid_type:
+ {
+ if (pSectionContext != nullptr)
+ {
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_default:
+ pSectionContext->SetGridType(text::TextGridMode::NONE);
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_lines:
+ pSectionContext->SetGridType(text::TextGridMode::LINES);
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_linesAndChars:
+ pSectionContext->SetGridType(text::TextGridMode::LINES_AND_CHARS);
+ pSectionContext->SetGridSnapToChars( false );
+ break;
+ case NS_ooxml::LN_Value_doc_ST_DocGrid_snapToChars:
+ pSectionContext->SetGridType(text::TextGridMode::LINES_AND_CHARS);
+ pSectionContext->SetGridSnapToChars( true );
+ break;
+ default :
+ OSL_FAIL("unknown SwTextGrid value");
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtBlock_sdtContent:
+ case NS_ooxml::LN_CT_SdtRun_sdtContent:
+ {
+ m_pImpl->m_pSdtHelper->SetSdtType(nName);
+
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::unknown)
+ {
+ // Still not determined content type? and it is even not unsupported? Then it is plain text field
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ }
+ if (nName == NS_ooxml::LN_CT_SdtRun_sdtContent)
+ {
+ if (m_pImpl->GetSdtStarts().empty() && m_pImpl->m_pSdtHelper->hasUnusedText())
+ {
+ // A non-inline SDT is already started, first convert that to a field and only
+ // then map the inline SDT to a content control.
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ }
+ }
+
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (pContext && m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ if (!m_pImpl->GetFootnoteContext() && !m_pImpl->IsInShape()
+ && !m_pImpl->IsInComments())
+ {
+ if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun())
+ {
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ else // IsFirstRun
+ {
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ }
+
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+ }
+ else if (pContext && m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun())
+ {
+ mbIsSplitPara = true;
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ else // IsFirstRun
+ {
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ }
+
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::richText);
+ m_pImpl->PushSdt();
+ break;
+ }
+ m_pImpl->SetSdt(true);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtBlock_sdtEndContent:
+ case NS_ooxml::LN_CT_SdtRun_sdtEndContent:
+ if (nName == NS_ooxml::LN_CT_SdtRun_sdtEndContent)
+ {
+ // Inline SDT.
+ switch (m_pImpl->m_pSdtHelper->getControlType())
+ {
+ case SdtControlType::richText:
+ case SdtControlType::plainText:
+ case SdtControlType::checkBox:
+ case SdtControlType::dropDown:
+ case SdtControlType::comboBox:
+ case SdtControlType::picture:
+ case SdtControlType::datePicker:
+ m_pImpl->PopSdt();
+ break;
+ default:
+ break;
+ }
+ }
+
+ m_pImpl->SetSdt(false);
+
+ // It's not possible to insert the relevant property to the character context here:
+ // the previous, already sent character context may be still active, so the property would be lost.
+ if (m_pImpl->m_pSdtHelper->isOutsideAParagraph())
+ m_pImpl->setParaSdtEndDeferred(true);
+ else
+ m_pImpl->setSdtEndDeferred(true);
+
+ switch (m_pImpl->m_pSdtHelper->getControlType())
+ {
+ case SdtControlType::dropDown:
+ case SdtControlType::comboBox:
+ m_pImpl->m_pSdtHelper->createDropDownControl();
+ break;
+ case SdtControlType::plainText:
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ break;
+ case SdtControlType::datePicker:
+ m_pImpl->m_pSdtHelper->createDateContentControl();
+ break;
+ case SdtControlType::unknown:
+ default:;
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtListItem_displayText:
+ m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().push_back(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtListItem_value:
+ m_pImpl->m_pSdtHelper->getDropDownItems().push_back(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtDate_fullDate:
+ m_pImpl->m_pSdtHelper->getDate().append(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Background_color:
+ if (m_pImpl->GetSettingsTable()->GetDisplayBackgroundShape())
+ m_pImpl->m_oBackgroundColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_PageNumber_start:
+ if (pSectionContext != nullptr && !m_pImpl->IsAltChunk())
+ pSectionContext->SetPageNumber(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_PageNumber_fmt:
+ if (pSectionContext)
+ {
+ sal_Int16 nNumberType = ConversionHelper::ConvertNumberingType(nIntValue, -1);
+ if (nNumberType != -1)
+ pSectionContext->SetPageNumberType(nNumberType);
+ }
+ break;
+ case NS_ooxml::LN_CT_FtnEdn_type:
+ // This is the "separator" footnote, ignore its linebreaks/text.
+ if (static_cast<sal_uInt32>(nIntValue) == NS_ooxml::LN_Value_doc_ST_FtnEdn_separator)
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::ON );
+ else
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::OFF );
+ break;
+ case NS_ooxml::LN_CT_FtnEdn_id:
+ {
+ SkipFootnoteSeparator eSkip = m_pImpl->GetSkipFootnoteState();
+ if ( eSkip == SkipFootnoteSeparator::ON )
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::SKIPPING );
+ else if ( eSkip == SkipFootnoteSeparator::SKIPPING )
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::OFF );
+ }
+ break;
+ case NS_ooxml::LN_CT_DataBinding_prefixMappings:
+ m_pImpl->m_pSdtHelper->setDataBindingPrefixMapping(sStringValue);
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_prefixMappings", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_DataBinding_xpath:
+ m_pImpl->m_pSdtHelper->setDataBindingXPath(sStringValue);
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_xpath", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_DataBinding_storeItemID:
+ m_pImpl->m_pSdtHelper->setDataBindingStoreItemID(sStringValue);
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_DataBinding_storeItemID", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtPlaceholder_docPart_val", sStringValue);
+ m_pImpl->m_pSdtHelper->SetPlaceholderDocPart(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtColor_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtColor_val", sStringValue);
+ m_pImpl->m_pSdtHelper->SetColor(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtAppearance_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtAppearance_val", sStringValue);
+ m_pImpl->m_pSdtHelper->SetAppearance(sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtText_multiLine:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtText_multiLine", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_PTab_leader:
+ case NS_ooxml::LN_CT_PTab_relativeTo:
+ break;
+ case NS_ooxml::LN_CT_PTab_alignment:
+ m_pImpl->HandlePTab(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastRowLastColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastRowLastColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastRowFirstColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastRowFirstColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstRowLastColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstRowLastColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_oddHBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "oddHBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstRowFirstColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstRowFirstColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_evenVBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "evenVBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_evenHBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "evenHBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstColumn:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstColumn", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_oddVBand:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "oddVBand", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_lastRow:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "lastRow", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_firstRow:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "firstRow", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Cnf_val:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_DocPartName_val:
+ {
+ m_sGlossaryEntryName = sStringValue;
+ break;
+ }
+ case NS_ooxml::LN_CT_DocPartGallery_val:
+ {
+ const OUString& sGlossaryEntryGallery = sStringValue;
+ if(m_pImpl->GetTopContext())
+ {
+ OUString sName = sGlossaryEntryGallery + ":" + m_sGlossaryEntryName;
+ // Add glossary entry name as a first paragraph in section
+ m_pImpl->appendTextPortion(sName, m_pImpl->GetTopContext());
+ }
+ break;
+ }
+ case NS_ooxml::LN_CT_PermStart_ed:
+ {
+ m_pImpl->setPermissionRangeEd(sStringValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_PermStart_edGrp:
+ {
+ m_pImpl->setPermissionRangeEdGrp(sStringValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_PermStart_id:
+ {
+ m_pImpl->startOrEndPermissionRange(nIntValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_PermEnd_id:
+ {
+ m_pImpl->startOrEndPermissionRange(nIntValue);
+ break;
+ }
+ case NS_ooxml::LN_CT_NumFmt_val:
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xFtnEdnSettings;
+ if (m_pImpl->IsInFootnoteProperties())
+ {
+ uno::Reference<text::XFootnotesSupplier> xFootnotesSupplier(
+ m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if (xFootnotesSupplier.is())
+ xFtnEdnSettings = xFootnotesSupplier->getFootnoteSettings();
+ }
+ else
+ {
+ uno::Reference<text::XEndnotesSupplier> xEndnotesSupplier(
+ m_pImpl->GetTextDocument(), uno::UNO_QUERY);
+ if (xEndnotesSupplier.is())
+ xFtnEdnSettings = xEndnotesSupplier->getEndnoteSettings();
+ }
+ if (xFtnEdnSettings.is())
+ {
+ sal_Int16 nNumType = ConversionHelper::ConvertNumberingType(nIntValue);
+ xFtnEdnSettings->setPropertyValue(getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any(nNumType));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_AltChunk:
+ {
+ m_pImpl->HandleAltChunk(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_AG_Parids_paraId:
+ if (ParagraphPropertyMap* pParaContext
+ = dynamic_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContext().get()))
+ {
+ pParaContext->props().SetParaId(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_OfficeArtExtension_Decorative_val:
+ m_pImpl->GetGraphicImport()->attribute(nName, val);
+ 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:
+ {
+ // if a VML background has been defined, it was imported into a shape to hold the properties
+ uno::Reference<drawing::XShape> xFill(m_pImpl->PopPendingShape());
+ if (xFill.is())
+ {
+ assert(!m_pImpl->GetTopContext());
+ assert(m_pImpl->GetIsFirstParagraphInShape());
+ assert(mbWasShapeInPara);
+ assert(m_pImpl->GetIsFirstParagraphInSection());
+ assert(m_pImpl->IsOutsideAParagraph());
+ if (m_pImpl->GetSettingsTable()->GetDisplayBackgroundShape())
+ {
+ // apply the XATTR_FILL attributes to the default page style
+ const uno::Reference<beans::XPropertySet> xFillPropertySet(xFill, uno::UNO_QUERY);
+ const uno::Reference<beans::XPropertySetInfo> xFillInfo
+ = xFillPropertySet->getPropertySetInfo();
+ uno::Reference<beans::XPropertySet> xPS(
+ m_pImpl->GetPageStyles()->getByName("Standard"), uno::UNO_QUERY_THROW);
+ for (const beans::Property& rProp : xPS->getPropertySetInfo()->getProperties())
+ {
+ if (rProp.Name == "FillComplexColor" || rProp.Name == "FillGradientName"
+ || rProp.Name == "FillGradientStepCount"
+ || rProp.Name == "FillTransparenceGradientName"
+ || rProp.Name == "FillBitmapURL" || rProp.Name == "FillColor2")
+ {
+ // silence exceptions for unsupported stuff when applying to page style
+ continue;
+ }
+ if (!rProp.Name.startsWith("Fill"))
+ continue;
+
+ if (!xFillInfo->hasPropertyByName(rProp.Name))
+ continue;
+
+ try
+ {
+ const uno::Any aFillValue = xFillPropertySet->getPropertyValue(rProp.Name);
+ xPS->setPropertyValue(rProp.Name, aFillValue);
+ }
+ catch (uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception setting page background fill");
+ }
+ }
+
+ m_pImpl->m_bCopyStandardPageStyleFill = true;
+ }
+
+ // The background was unhelpfully imported into the text body: remove it
+ uno::Reference<lang::XComponent> xComponent(xFill, uno::UNO_QUERY_THROW);
+ xComponent->dispose();
+
+ m_pImpl->SetIsFirstParagraphInShape(false);
+ mbWasShapeInPara = false;
+ }
+ return;
+ }
+ default:
+ break;
+ }
+
+ OSL_ENSURE(rContext, "PropertyMap has to be valid!");
+ if(!rContext)
+ return ;
+
+ sal_uInt32 nSprmId = rSprm.getId();
+ //needed for page properties
+ SectionPropertyMap * pSectionContext = m_pImpl->GetSectionContext();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = pValue->getInt();
+ const OUString sStringValue = pValue->getString();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_PPrBase_jc:
+ {
+ bool bExchangeLeftRight = !IsRTFImport() && !m_pImpl->IsInComments() && ExchangeLeftRight(rContext, *m_pImpl);
+ handleParaJustification(nIntValue, rContext, bExchangeLeftRight);
+ break;
+ }
+ case NS_ooxml::LN_CT_PPrBase_keepLines:
+ rContext->Insert(PROP_PARA_SPLIT, uno::Any(nIntValue == 0));
+ break;
+ case NS_ooxml::LN_CT_PPrBase_keepNext:
+ rContext->Insert(PROP_PARA_KEEP_TOGETHER, uno::Any( nIntValue != 0 ) );
+ break;
+ case NS_ooxml::LN_CT_PPrBase_pageBreakBefore:
+ rContext->Insert(PROP_BREAK_TYPE, uno::Any(nIntValue ? style::BreakType_PAGE_BEFORE : style::BreakType_NONE), /*bOverwrite=*/bool(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_NumPr_ilvl:
+ if (nIntValue < 0 || 10 <= nIntValue)
+ {
+ SAL_INFO("writerfilter",
+ "unsupported numbering level " << nIntValue);
+ break;
+ }
+ if( IsStyleSheetImport() )
+ {
+ //style sheets cannot have a numbering rule attached
+ StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() );
+ if (pStyleSheetPropertyMap)
+ pStyleSheetPropertyMap->SetListLevel( static_cast<sal_Int16>(nIntValue) );
+ }
+ // 0-8 are the 9 levels that Microsoft supports. (LO supports 10 levels).
+ // 9 indicates "no numbering", for which LO has no corresponding concept,
+ // and so it will be treated as the 10th level.
+ // finishParagraph() will convert the 9 into "no numbering" for direct formatting.
+ // (Styles only use this PROP for round-tripping and UI, but cannot trust it for import)
+ if (!IsStyleSheetImport() || nIntValue != 9)
+ rContext->Insert(PROP_NUMBERING_LEVEL, uno::Any(static_cast<sal_Int16>(nIntValue)));
+ break;
+ case NS_ooxml::LN_CT_NumPr_numId:
+ {
+ //convert the ListTable entry to a NumberingRules property and apply it
+ ListsManager::Pointer pListTable = m_pImpl->GetListTable();
+ ListDef::Pointer pList = pListTable->GetList( nIntValue );
+ if( IsStyleSheetImport() )
+ {
+ //style sheets cannot have a numbering rule attached
+ StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() );
+ if (pStyleSheetPropertyMap)
+ pStyleSheetPropertyMap->props().SetListId( nIntValue );
+ }
+ if( pList )
+ {
+ if( !IsStyleSheetImport() )
+ {
+ uno::Any aRules( pList->GetNumberingRules( ) );
+ rContext->Insert( PROP_NUMBERING_RULES, aRules );
+ rContext->Erase( PROP_NUMBERING_STYLE_NAME);
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (pContext)
+ {
+ assert(dynamic_cast<ParagraphPropertyMap*>(pContext.get()));
+ static_cast<ParagraphPropertyMap*>(pContext.get())->props().SetListId(pList->GetId());
+ }
+
+ // Indentation can came from:
+ // 1) Paragraph style's numbering's indentation: the current non-style numId has priority over it.
+ // 2) Numbering's indentation: Writer handles that natively, so it should not be set on rContext.
+ // 3) Paragraph style's indentation: ditto.
+ // 4) Direct paragraph formatting: that will came later.
+ // So no situation where keeping indentation at this point would make sense -> erase.
+ rContext->Erase(PROP_PARA_FIRST_LINE_INDENT);
+ rContext->Erase(PROP_PARA_LEFT_MARGIN);
+ rContext->Erase(PROP_PARA_RIGHT_MARGIN);
+ }
+ }
+ else
+ {
+ if( !IsStyleSheetImport() )
+ {
+ // eg. disabled numbering using non-existent numId "0"
+ rContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::Any( OUString() ) );
+ // disable inheritance of indentation of parent styles
+ rContext->Insert( PROP_PARA_LEFT_MARGIN, uno::Any( sal_Int32(0) ), /*bOverwrite=*/false);
+ rContext->Insert( PROP_PARA_FIRST_LINE_INDENT,
+ uno::Any( sal_Int32(0) ), /*bOverwrite=*/false);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_suppressLineNumbers:
+ rContext->Insert(PROP_PARA_LINE_NUMBER_COUNT, uno::Any( nIntValue == 0 ) );
+ break;
+ case NS_ooxml::LN_inTbl:
+ break;
+ case NS_ooxml::LN_tblDepth:
+ //not handled via sprm but via text( 0x07 )
+ break;
+ case NS_ooxml::LN_CT_FramePr_w:
+ break;
+ case NS_ooxml::LN_CT_FramePr_wrap:
+ break;
+
+ case NS_ooxml::LN_CT_PrBase_pBdr: //paragraph border
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_CT_PBdr_top:
+ case NS_ooxml::LN_CT_PBdr_left:
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ case NS_ooxml::LN_CT_PBdr_right:
+ case NS_ooxml::LN_CT_PBdr_between:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>( true );
+ pProperties->resolve(*pBorderHandler);
+ PropertyIds eBorderId = PropertyIds::INVALID;
+ PropertyIds eBorderComplexColorId = PropertyIds::INVALID;
+ PropertyIds eBorderDistId = PropertyIds::INVALID;
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_PBdr_top:
+ eBorderId = PROP_TOP_BORDER;
+ eBorderComplexColorId = PROP_BORDER_TOP_COMPLEX_COLOR;
+ eBorderDistId = PROP_TOP_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_left:
+ eBorderId = PROP_LEFT_BORDER;
+ eBorderComplexColorId = PROP_BORDER_LEFT_COMPLEX_COLOR;
+ eBorderDistId = PROP_LEFT_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ eBorderId = PROP_BOTTOM_BORDER;
+ eBorderComplexColorId = PROP_BORDER_BOTTOM_COMPLEX_COLOR;
+ eBorderDistId = PROP_BOTTOM_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_right:
+ eBorderId = PROP_RIGHT_BORDER;
+ eBorderComplexColorId = PROP_BORDER_RIGHT_COMPLEX_COLOR;
+ eBorderDistId = PROP_RIGHT_BORDER_DISTANCE;
+ break;
+ case NS_ooxml::LN_CT_PBdr_between:
+ if (m_pImpl->handlePreviousParagraphBorderInBetween())
+ {
+ // If previous paragraph also had border in between property
+ // then it is possible to emulate this border as top border
+ // for current paragraph
+ eBorderId = PROP_TOP_BORDER;
+ eBorderComplexColorId = PROP_BORDER_TOP_COMPLEX_COLOR;
+ eBorderDistId = PROP_TOP_BORDER_DISTANCE;
+ }
+ // Since there are borders in between, each paragraph will have own borders. No more joining
+ rContext->Insert(PROP_PARA_CONNECT_BORDERS, uno::Any(false));
+ break;
+ default:;
+ }
+
+ if (eBorderId != PropertyIds::INVALID)
+ {
+ rContext->Insert(eBorderId, uno::Any(pBorderHandler->getBorderLine()));
+ }
+ if (eBorderComplexColorId != PropertyIds::INVALID)
+ {
+ auto aComplexColor = pBorderHandler->getComplexColor();
+ auto xComplexColor = model::color::createXComplexColor(aComplexColor);
+ rContext->Insert(eBorderComplexColorId, uno::Any(xComplexColor));
+ }
+ if (eBorderDistId != PropertyIds::INVALID)
+ {
+ rContext->Insert(eBorderDistId, uno::Any(pBorderHandler->getLineDistance()));
+ }
+ if ( nSprmId == NS_ooxml::LN_CT_PBdr_right )
+ {
+ table::ShadowFormat aFormat;
+ // Word only allows shadows on visible borders
+ if ( pBorderHandler->getShadow() && pBorderHandler->getBorderLine().LineStyle != table::BorderLineStyle::NONE )
+ aFormat = writerfilter::dmapper::PropertyMap::getShadowFromBorder(pBorderHandler->getBorderLine());
+ rContext->Insert(PROP_PARA_SHADOW_FORMAT, uno::Any(aFormat));
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PBdr_bar:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens:
+ rContext->Insert(PROP_PARA_IS_HYPHENATION, uno::Any( nIntValue == 0 ));
+ break;
+ case NS_ooxml::LN_CT_FramePr_h:
+ break;
+ case NS_ooxml::LN_CT_PrBase_shd:
+ {
+ //contains fore color, back color and shadow percentage, results in a brush
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellColorHandler = std::make_shared<CellColorHandler>();
+ pCellColorHandler->setOutputFormat( CellColorHandler::Paragraph );
+ bool bEnableTempGrabBag = !pCellColorHandler->isInteropGrabBagEnabled();
+ if( bEnableTempGrabBag )
+ pCellColorHandler->enableInteropGrabBag( "TempShdPropsGrabBag" );
+
+ pProperties->resolve(*pCellColorHandler);
+ rContext->InsertProps(pCellColorHandler->getProperties().get());
+
+ rContext->Insert(PROP_CHAR_THEME_FILL, pCellColorHandler->getInteropGrabBag().Value, true, PARA_GRAB_BAG);
+ if(bEnableTempGrabBag)
+ pCellColorHandler->disableInteropGrabBag();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_FramePr_vSpace:
+ break; // sprmPDyaFromText
+ case NS_ooxml::LN_CT_FramePr_hSpace:
+ break; // sprmPDxaFromText
+ case NS_ooxml::LN_CT_FramePr_anchorLock:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_widowControl:
+ {
+ uno::Any aVal( uno::Any( sal_Int8(nIntValue ? 2 : 0 )));
+ rContext->Insert( PROP_PARA_WIDOWS, aVal );
+ rContext->Insert( PROP_PARA_ORPHANS, aVal );
+ }
+ break; // sprmPFWidowControl
+ case NS_ooxml::LN_CT_PPrBase_overflowPunct:
+ rContext->Insert(PROP_PARA_IS_HANGING_PUNCTUATION, uno::Any( nIntValue == 0 ));
+ break;
+ case NS_ooxml::LN_CT_PPrBase_topLinePunct:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_autoSpaceDE:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_autoSpaceDN:
+ break;
+ case NS_ooxml::LN_CT_PPrBase_textAlignment:
+ {
+ sal_Int16 nAlignment = 0;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_top:
+ nAlignment = 2;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_center:
+ nAlignment = 3;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline:
+ nAlignment = 1;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_bottom:
+ nAlignment = 4;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_TextAlignment_auto:
+ default:
+ break;
+ }
+ rContext->Insert( PROP_PARA_VERT_ALIGNMENT, uno::Any( nAlignment) );
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_textDirection:
+ {
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl: // ~ vert="eaVert"
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr: // ~ vert="vert270"
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::BT_LR);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
+ {
+ // East Asian character rotation is not implemented in LO, use ordinary LR_TB instead.
+ m_pImpl->SetFrameDirection(text::WritingMode2::LR_TB);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV: // ~ vert="vert"
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL90);
+ break;
+ }
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
+ // default in LO. Do not overwrite RL_TB set by bidi.
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV: // ~ vert="mongolianVert"
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_LR);
+ break;
+ }
+ default:
+ SAL_WARN("writerfilter", "DomainMapper::sprmWithProps: unhandled textDirection");
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_outlineLvl:
+ {
+ if (nIntValue < WW_OUTLINE_MIN || nIntValue > WW_OUTLINE_MAX)
+ break; // invalid value is ignored by MS Word
+
+ if( IsStyleSheetImport() )
+ {
+ StyleSheetPropertyMap* pStyleSheetPropertyMap = dynamic_cast< StyleSheetPropertyMap* >( rContext.get() );
+ if (pStyleSheetPropertyMap)
+ pStyleSheetPropertyMap->SetOutlineLevel(nIntValue);
+ }
+ else
+ {
+ // convert MS body level (9) to LO body level (0) and equivalent outline levels
+ sal_Int16 nLvl = nIntValue == WW_OUTLINE_MAX ? 0 : nIntValue + 1;
+ rContext->Insert(PROP_OUTLINE_LEVEL, uno::Any ( nLvl ));
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_bidi:
+ {
+ // Four situations to handle:
+ // 1.) bidi same as previous setting: no adjust change
+ // 2.) no previous adjust: set appropriate default for this bidi
+ // 3.) previous adjust and bidi different from previous: swap adjusts
+ // 4.) previous adjust and no previous bidi: RTL swaps adjust
+
+ const sal_Int16 nWritingMode = nIntValue ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB;
+ sal_Int16 nParentBidi = -1;
+ m_pImpl->GetPropertyFromParaStyleSheet(PROP_WRITING_MODE) >>= nParentBidi;
+ // Paragraph justification reverses its meaning in an RTL context.
+ // 1. Only make adjustments if the BiDi changes.
+ if (nParentBidi != nWritingMode && !IsRTFImport() && !m_pImpl->IsInComments())
+ {
+ style::ParagraphAdjust eAdjust = style::ParagraphAdjust(-1);
+ // 2. no adjust property exists yet
+ if ( !(m_pImpl->GetAnyProperty(PROP_PARA_ADJUST, rContext) >>= eAdjust) )
+ {
+ // RTL defaults to right adjust
+ eAdjust = nIntValue ? style::ParagraphAdjust_RIGHT : style::ParagraphAdjust_LEFT;
+ rContext->Insert(PROP_PARA_ADJUST, uno::Any( eAdjust ), /*bOverwrite=*/false);
+ }
+ // 3,4. existing adjust: if RTL, then swap. If LTR, but previous was RTL, also swap.
+ else if ( nIntValue || nParentBidi == sal_Int16(text::WritingMode2::RL_TB) )
+ {
+ if ( eAdjust == style::ParagraphAdjust_RIGHT )
+ rContext->Insert(PROP_PARA_ADJUST, uno::Any( style::ParagraphAdjust_LEFT ));
+ else if ( eAdjust == style::ParagraphAdjust_LEFT )
+ rContext->Insert(PROP_PARA_ADJUST, uno::Any( style::ParagraphAdjust_RIGHT ));
+ }
+ }
+ rContext->Insert(PROP_WRITING_MODE, uno::Any( nWritingMode ));
+ }
+
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_bidi:
+ if (pSectionContext != nullptr)
+ {
+ const sal_Int16 writingMode = (nIntValue != 0) ? sal_Int16(text::WritingMode2::RL_TB) : sal_Int16(text::WritingMode2::LR_TB);
+ pSectionContext->Insert(PROP_WRITING_MODE, uno::Any(writingMode));
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_rtlGutter:
+ if (pSectionContext != nullptr)
+ {
+ bool bRtlGutter = nIntValue != 0;
+ pSectionContext->Insert(PROP_RTL_GUTTER, uno::Any(bRtlGutter));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_highlight:
+ {
+ // MS Word completely ignores character highlighting in character styles.
+ if ( IsStyleSheetImport() )
+ {
+ const StyleSheetEntryPtr pCurrStyle = GetStyleSheetTable()->GetCurrentEntry();
+ if ( pCurrStyle && pCurrStyle->m_nStyleTypeCode == STYLE_TYPE_CHAR )
+ break;
+ }
+
+ PropertyIds ePropertyId = m_pImpl->IsInComments() ? PROP_CHAR_BACK_COLOR : PROP_CHAR_HIGHLIGHT;
+
+ // OOXML import uses an ID
+ if( IsOOXMLImport() )
+ {
+ sal_Int32 nColor = 0;
+ if( getColorFromId(nIntValue, nColor) )
+ rContext->Insert(ePropertyId, uno::Any(nColor));
+ }
+ // RTF import uses the actual color value
+ else if( IsRTFImport() )
+ {
+ rContext->Insert(ePropertyId, uno::Any(nIntValue));
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_em:
+ rContext->Insert(PROP_CHAR_EMPHASIS, uno::Any ( getEmphasisValue (nIntValue)));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_emboss:
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_bCs:
+ case NS_ooxml::LN_EG_RPrBase_i:
+ case NS_ooxml::LN_EG_RPrBase_iCs:
+ case NS_ooxml::LN_EG_RPrBase_strike:
+ case NS_ooxml::LN_EG_RPrBase_dstrike:
+ case NS_ooxml::LN_EG_RPrBase_outline:
+ case NS_ooxml::LN_EG_RPrBase_shadow:
+ case NS_ooxml::LN_EG_RPrBase_caps:
+ case NS_ooxml::LN_EG_RPrBase_smallCaps:
+ case NS_ooxml::LN_EG_RPrBase_vanish:
+ case NS_ooxml::LN_EG_RPrBase_webHidden:
+ {
+ PropertyIds ePropertyId = PROP_CHAR_WEIGHT; //initialized to prevent warning!
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_bCs:
+ ePropertyId = nSprmId != NS_ooxml::LN_EG_RPrBase_bCs ? PROP_CHAR_WEIGHT : PROP_CHAR_WEIGHT_COMPLEX;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_i:
+ case NS_ooxml::LN_EG_RPrBase_iCs:
+ ePropertyId = nSprmId == NS_ooxml::LN_EG_RPrBase_i ? PROP_CHAR_POSTURE : PROP_CHAR_POSTURE_COMPLEX;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_strike:
+ case NS_ooxml::LN_EG_RPrBase_dstrike:
+ ePropertyId = PROP_CHAR_STRIKEOUT;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_outline:
+ ePropertyId = PROP_CHAR_CONTOURED;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_shadow:
+ ePropertyId = PROP_CHAR_SHADOWED;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_caps:
+ case NS_ooxml::LN_EG_RPrBase_smallCaps:
+ ePropertyId = PROP_CHAR_CASE_MAP;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_vanish:
+ case NS_ooxml::LN_EG_RPrBase_webHidden:
+ ePropertyId = PROP_CHAR_HIDDEN;
+ break;
+ case NS_ooxml::LN_EG_RPrBase_emboss:
+ ePropertyId = PROP_CHAR_RELIEF;
+ break;
+ }
+ //expected: 0,1,128,129
+ if(nIntValue != 128) //inherited from paragraph - ignore
+ {
+ if( nIntValue == 129) //inverted style sheet value
+ {
+ //get value from style sheet and invert it
+ sal_Int16 nStyleValue = 0;
+ uno::Any aStyleVal = m_pImpl->GetPropertyFromParaStyleSheet(ePropertyId);
+ if( !aStyleVal.hasValue() )
+ {
+ nIntValue = NS_ooxml::LN_EG_RPrBase_smallCaps == nSprmId ?
+ 4 : 1;
+ }
+ else if(aStyleVal.getValueTypeClass() == uno::TypeClass_FLOAT )
+ {
+ double fDoubleValue = 0;
+ //only in case of awt::FontWeight
+ aStyleVal >>= fDoubleValue;
+ nIntValue = fDoubleValue > 100. ? 0 : 1;
+ }
+ else if((aStyleVal >>= nStyleValue) ||
+ (nStyleValue = static_cast<sal_Int16>(comphelper::getEnumAsINT32(aStyleVal))) >= 0 )
+ {
+ nIntValue = NS_ooxml::LN_EG_RPrBase_smallCaps == nSprmId ?
+ nStyleValue ? 0 : 4 :
+ nStyleValue ? 0 : 1;
+ }
+ else
+ {
+ OSL_FAIL( "what type was it");
+ }
+ }
+
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_bCs:
+ {
+ uno::Any aBold( uno::Any( nIntValue ? awt::FontWeight::BOLD : awt::FontWeight::NORMAL ) );
+
+ rContext->Insert(ePropertyId, aBold );
+ if( nSprmId != NS_ooxml::LN_EG_RPrBase_bCs )
+ rContext->Insert(PROP_CHAR_WEIGHT_ASIAN, aBold );
+
+ if (nSprmId == NS_ooxml::LN_EG_RPrBase_b)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "b", OUString::number(nIntValue));
+ else if (nSprmId == NS_ooxml::LN_EG_RPrBase_bCs)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "bCs", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_i:
+ case NS_ooxml::LN_EG_RPrBase_iCs:
+ {
+ uno::Any aPosture( uno::Any( nIntValue ? awt::FontSlant_ITALIC : awt::FontSlant_NONE ) );
+ rContext->Insert( ePropertyId, aPosture );
+ if (nSprmId != NS_ooxml::LN_EG_RPrBase_iCs)
+ rContext->Insert(PROP_CHAR_POSTURE_ASIAN, aPosture );
+ if (nSprmId == NS_ooxml::LN_EG_RPrBase_i)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "i", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_strike:
+ {
+ const auto eStrike
+ = nIntValue ? awt::FontStrikeout::SINGLE : awt::FontStrikeout::NONE;
+ const bool bOverwrite(nIntValue);
+ rContext->Insert(ePropertyId, uno::Any(eStrike), bOverwrite);
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_dstrike:
+ {
+ const auto eStrike
+ = nIntValue ? awt::FontStrikeout::DOUBLE : awt::FontStrikeout::NONE;
+ const bool bOverwrite(nIntValue);
+ rContext->Insert(ePropertyId, uno::Any(eStrike), bOverwrite);
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_outline:
+ case NS_ooxml::LN_EG_RPrBase_shadow:
+ case NS_ooxml::LN_EG_RPrBase_vanish:
+ case NS_ooxml::LN_EG_RPrBase_webHidden:
+ rContext->Insert(ePropertyId, uno::Any( nIntValue != 0 ));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_smallCaps:
+ // If smallcaps would be just disabled and another casemap is already inserted, don't do anything.
+ if (nIntValue || !rContext->isSet(ePropertyId) )
+ rContext->Insert(ePropertyId, uno::Any( nIntValue ? style::CaseMap::SMALLCAPS : style::CaseMap::NONE));
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "smallCaps", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_caps:
+ rContext->Insert(ePropertyId,
+ uno::Any( nIntValue ? style::CaseMap::UPPERCASE : style::CaseMap::NONE));
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "caps", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_emboss:
+ rContext->Insert(ePropertyId,
+ uno::Any( nIntValue ? awt::FontRelief::EMBOSSED : awt::FontRelief::NONE ));
+ break;
+
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ case NS_ooxml::LN_EG_RPrBase_szCs:
+ {
+ //multiples of half points (12pt == 24)
+ double fVal = double(nIntValue) / 2.;
+ uno::Any aVal( fVal );
+ if( NS_ooxml::LN_EG_RPrBase_szCs == nSprmId )
+ {
+ rContext->Insert( PROP_CHAR_HEIGHT_COMPLEX, aVal );
+ }
+ else
+ {
+ const RubyInfo &aInfo = m_pImpl->GetRubyInfo();
+ if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rt && aInfo.nHps > 0 )
+ {
+ fVal = double(aInfo.nHps) / 2.;
+ aVal <<= fVal;
+ }
+ else if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rubyBase && aInfo.nHpsBaseText > 0 )
+ {
+ fVal = double(aInfo.nHpsBaseText) / 2.;
+ aVal <<= fVal;
+ }
+ //Asian get the same value as Western
+ rContext->Insert( PROP_CHAR_HEIGHT, aVal );
+ rContext->Insert( PROP_CHAR_HEIGHT_ASIAN, aVal );
+ }
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, (nSprmId == NS_ooxml::LN_EG_RPrBase_sz ? OUString("sz") : OUString("szCs")), OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_position:
+ // The spec says 0 is the same as the lack of the value, so don't parse that.
+ if ( nIntValue )
+ {
+ if (!IsStyleSheetImport() && !IsNumberingImport())
+ m_pImpl->deferCharacterProperty( nSprmId, uno::Any( nIntValue ));
+ else if (!m_pImpl->IsDocDefaultsImport())
+ {
+ // For some undocumented reason, MS Word seems to ignore this in docDefaults
+
+ const StyleSheetEntryPtr pCurrStyle = GetStyleSheetTable()->GetCurrentEntry();
+ if (pCurrStyle && pCurrStyle->m_nStyleTypeCode == STYLE_TYPE_PARA && nIntValue < 0)
+ {
+ m_pImpl->deferCharacterProperty(nSprmId, uno::Any(nIntValue));
+ break;
+ }
+
+ // DON'T FIXME: Truly calculating this for Character Styles will be tricky,
+ // because it depends on the final fontsize - regardless of
+ // where it is set. So at the style level,
+ // the escapement value would need to be grabbagged.
+ // At appendText time the final fontsize needs to be determined, and then
+ // the escapement can be calculated from the grabbag'd half-point value
+ // and directly applied. Yuck.
+ // It seems best to just treat charstyle escapement like
+ // pre-commit e70df84352d3670508a4666c97df44f82c1ce934
+ // which just assigned default values and ignored the actual/given escapement.
+ sal_Int16 nEscapement = nIntValue > 0 ? DFLT_ESC_AUTO_SUPER : DFLT_ESC_AUTO_SUB;
+ sal_Int8 nProp = DFLT_ESC_PROP;
+ rContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( nEscapement ) );
+ rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::Any( nProp ) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_spacing:
+ {
+ //Kerning half point values
+ //TODO: there are two kerning values -
+ // in ww8par6.cxx NS_sprm::LN_CHpsKern is used as boolean AutoKerning
+ sal_Int16 nResult = static_cast<sal_Int16>(ConversionHelper::convertTwipToMM100(nIntValue));
+ if (m_pImpl->IsInComments())
+ {
+ nResult = static_cast<sal_Int16>(nIntValue);
+ }
+ rContext->Insert(PROP_CHAR_CHAR_KERNING, uno::Any(nResult));
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "spacing", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_kern: // auto kerning is bound to a minimum font size in Word - but not in Writer :-(
+ rContext->Insert(PROP_CHAR_AUTO_KERNING, uno::Any( nIntValue != 0 ) );
+ break;
+ case NS_ooxml::LN_EG_RPrBase_w:
+ // ST_TextScale must fall between 1% and 600% according to spec, otherwise resets to 100% according to experience
+ if ((1 <= nIntValue) && (nIntValue <= 600))
+ {
+ rContext->Insert(PROP_CHAR_SCALE_WIDTH,
+ uno::Any( sal_Int16(nIntValue) ));
+ }
+ else
+ {
+ rContext->Insert(PROP_CHAR_SCALE_WIDTH,
+ uno::Any( sal_Int16(100) ));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_imprint:
+ // FontRelief: NONE, EMBOSSED, ENGRAVED
+ rContext->Insert(PROP_CHAR_RELIEF,
+ uno::Any( nIntValue ? awt::FontRelief::ENGRAVED : awt::FontRelief::NONE ));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_effect:
+ // The file-format has many character animations. We have only
+ // one, so we use it always. Suboptimal solution though.
+ if (nIntValue != NS_ooxml::LN_Value_ST_TextEffect_none)
+ rContext->Insert(PROP_CHAR_FLASH, uno::Any( true ));
+ else
+ rContext->Insert(PROP_CHAR_FLASH, uno::Any( false ));
+ break;
+ case NS_ooxml::LN_EG_RPrBase_rtl:
+ break;
+ case NS_ooxml::LN_EG_RPrBase_shd:
+ {
+ //contains fore color, back color and shadow percentage, results in a brush
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellColorHandler = std::make_shared<CellColorHandler>();
+ pCellColorHandler->setOutputFormat( CellColorHandler::Character );
+ pProperties->resolve(*pCellColorHandler);
+ rContext->InsertProps(pCellColorHandler->getProperties().get());
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_SHADING_MARKER, uno::Any(true), true, CHAR_GRAB_BAG );
+
+ // EditEng doesn't have a corresponding property for Shading Value, so eliminate it.
+ if (m_pImpl->IsInComments())
+ rContext->Erase(PROP_CHAR_SHADING_VALUE);
+ }
+ break;
+ }
+ case NS_ooxml::LN_EG_SectPrContents_type:
+ /* break type
+ 0 - No break
+ 1 - New Column
+ 2 - New page
+ 3 - Even page
+ 4 - odd page
+ */
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ //continuous break only allowed if it is not the only section break
+ SectionPropertyMap* pLastContext = m_pImpl->GetLastSectionContext();
+ if ( nIntValue != NS_ooxml::LN_Value_ST_SectionMark_continuous || pLastContext || m_pImpl->GetParaSectpr() )
+ pSectionContext->SetBreakType( nIntValue );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_titlePg:
+ {
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ pSectionContext->SetTitlePage( nIntValue > 0 );//section has title page
+ }
+ break;
+ case 165:
+ {
+ //page height, rounded to default values, default: 0x3dc0 twip
+ sal_Int32 nHeight = ConversionHelper::convertTwipToMM100( nIntValue );
+ rContext->Insert( PROP_HEIGHT, uno::Any( PaperInfo::sloppyFitPageDimension( nHeight ) ) );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_textDirection:
+ {
+ sal_Int16 nDirection = text::WritingMode2::LR_TB;
+ switch( nIntValue )
+ {
+ // East Asian 270deg rotation in lrTbV is not implemented in LO
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
+ nDirection = text::WritingMode2::LR_TB; // =0
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ nDirection = text::WritingMode2::TB_RL; // =2
+ break;
+ // Word does not write btLr in sections, but LO would be able to use it.
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr:
+ nDirection = text::WritingMode2::BT_LR; // =5
+ break;
+ // Word maps mongolian direction to tbRlV in sections in file save, as of Aug 2022.
+ // From point of OOXML standard it would be tbLrV. Since tbRlV is currently not
+ // implemented in LO for text direction in page styles, we follow Word here.
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
+ nDirection = text::WritingMode2::TB_LR; // =3
+ break;
+ default:;
+ }
+
+ PropertyMap * pTargetContext = rContext.get();
+
+ if (pSectionContext)
+ {
+ pTargetContext = pSectionContext;
+ }
+
+ pTargetContext->Insert(PROP_WRITING_MODE, uno::Any( sal_Int16(nDirection) ) );
+ }
+ break; // sprmSTextFlow
+ // the following are not part of the official documentation
+ case NS_ooxml::LN_CT_Tabs_tab:
+ resolveSprmProps(*this, rSprm);
+ m_pImpl->IncorporateTabStop(m_pImpl->m_aCurrentTabStop);
+ m_pImpl->m_aCurrentTabStop = DeletableTabStop();
+ break;
+ case NS_ooxml::LN_CT_PPrBase_tabs:
+ {
+ // Initialize tab stop vector from style sheet
+ // fdo#81033: for RTF, a tab stop is inherited from the style if it
+ // is also applied to the paragraph directly, and cleared if it is
+ // not applied to the paragraph directly => don't InitTabStopFromStyle
+ if ( !IsRTFImport() )
+ {
+ uno::Any aValue = m_pImpl->GetPropertyFromParaStyleSheet(PROP_PARA_TAB_STOPS);
+ uno::Sequence< style::TabStop > aStyleTabStops;
+ if(aValue >>= aStyleTabStops)
+ {
+ m_pImpl->InitTabStopFromStyle( aStyleTabStops );
+ }
+ }
+ resolveSprmProps(*this, rSprm);
+ rContext->Insert(PROP_PARA_TAB_STOPS, uno::Any( m_pImpl->GetCurrentTabStopAndClear()));
+ }
+ break;
+
+ case NS_ooxml::LN_CT_DocDefaults_pPrDefault:
+ case NS_ooxml::LN_CT_DocDefaults_rPrDefault:
+ GetStyleSheetTable()->sprm( rSprm );
+ break;
+ case NS_ooxml::LN_EG_RPrBase_bdr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>( true );
+ pProperties->resolve(*pBorderHandler);
+
+ rContext->Insert( PROP_CHAR_TOP_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+ rContext->Insert( PROP_CHAR_BOTTOM_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+ rContext->Insert( PROP_CHAR_LEFT_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+ rContext->Insert( PROP_CHAR_RIGHT_BORDER, uno::Any( pBorderHandler->getBorderLine()));
+
+ rContext->Insert( PROP_CHAR_TOP_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+ rContext->Insert( PROP_CHAR_BOTTOM_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+ rContext->Insert( PROP_CHAR_LEFT_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+ rContext->Insert( PROP_CHAR_RIGHT_BORDER_DISTANCE, uno::Any( pBorderHandler->getLineDistance()));
+
+ auto xComplexColor = model::color::createXComplexColor(pBorderHandler->getComplexColor());
+
+ rContext->Insert( PROP_CHAR_BORDER_TOP_COMPLEX_COLOR, uno::Any(xComplexColor));
+ rContext->Insert( PROP_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, uno::Any(xComplexColor));
+ rContext->Insert( PROP_CHAR_BORDER_LEFT_COMPLEX_COLOR, uno::Any(xComplexColor));
+ rContext->Insert( PROP_CHAR_BORDER_RIGHT_COMPLEX_COLOR, uno::Any(xComplexColor));
+
+ table::ShadowFormat aFormat;
+ // Word only allows shadows on visible borders
+ if ( pBorderHandler->getShadow() && pBorderHandler->getBorderLine().LineStyle != table::BorderLineStyle::NONE )
+ aFormat = writerfilter::dmapper::PropertyMap::getShadowFromBorder(pBorderHandler->getBorderLine());
+ rContext->Insert(PROP_CHAR_SHADOW_FORMAT, uno::Any(aFormat));
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_color:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ auto pThemeColorHandler = std::make_shared<ThemeColorHandler>();
+ pProperties->resolve(*pThemeColorHandler);
+
+ uno::Any aThemeColorName(TDefTableHandler::getThemeColorTypeString(pThemeColorHandler->mnIndex));
+ uno::Any aThemeColorTint(OUString::number(pThemeColorHandler->mnTint, 16));
+ uno::Any aThemeColorShade(OUString::number(pThemeColorHandler->mnShade, 16));
+
+ if (m_pImpl->GetTopContext())
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COLOR, uno::Any(pThemeColorHandler->mnColor));
+
+ auto eType = TDefTableHandler::getThemeColorTypeIndex(pThemeColorHandler->mnIndex);
+ if (eType != model::ThemeColorType::Unknown)
+ {
+
+ model::ComplexColor aComplexColor;
+ aComplexColor.setThemeColor(eType);
+
+ auto eUsage = TDefTableHandler::getThemeColorUsage(pThemeColorHandler->mnIndex);
+ aComplexColor.setThemeColorUsage(eUsage);
+
+ if (pThemeColorHandler->mnTint > 0 )
+ {
+ sal_Int16 nTint = sal_Int16((255 - pThemeColorHandler->mnTint) * 10000 / 255);
+ aComplexColor.addTransformation({model::TransformationType::Tint, nTint});
+ }
+ if (pThemeColorHandler->mnShade > 0)
+ {
+ sal_Int16 nShade = sal_Int16((255 - pThemeColorHandler->mnShade) * 10000 / 255);
+ aComplexColor.addTransformation({model::TransformationType::Shade, nShade});
+ }
+
+ auto xComplexColor = model::color::createXComplexColor(aComplexColor);
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_COMPLEX_COLOR, uno::Any(xComplexColor));
+ }
+
+ uno::Any aColorAny(msfilter::util::ConvertColorOU(Color(ColorTransparency, pThemeColorHandler->mnColor)));
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_ORIGINAL_COLOR, aColorAny, true, CHAR_GRAB_BAG);
+
+ if (pThemeColorHandler->mnIndex >= 0)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_COLOR, aThemeColorName, true, CHAR_GRAB_BAG);
+
+ if (pThemeColorHandler->mnTint > 0)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_COLOR_TINT, aThemeColorTint, true, CHAR_GRAB_BAG);
+
+ if (pThemeColorHandler->mnShade > 0)
+ m_pImpl->GetTopContext()->Insert(PROP_CHAR_THEME_COLOR_SHADE, aThemeColorShade, true, CHAR_GRAB_BAG);
+ }
+ {
+ if (pThemeColorHandler->mnIndex >= 0)
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "themeColor", aThemeColorName.get<OUString>());
+ if (pThemeColorHandler->mnTint > 0)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "themeTint", aThemeColorTint.get<OUString>());
+ if (pThemeColorHandler->mnShade > 0)
+ m_pImpl->appendGrabBag(m_pImpl->m_aSubInteropGrabBag, "themeShade", aThemeColorShade.get<OUString>());
+ }
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "color", m_pImpl->m_aSubInteropGrabBag);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PPr_sectPr:
+ 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:
+ {
+ if (nSprmId == NS_ooxml::LN_CT_PPr_sectPr)
+ m_pImpl->SetParaSectpr(true);
+ 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_CT_PPrBase_ind)
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ind", m_pImpl->m_aSubInteropGrabBag);
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_wordWrap:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "wordWrap", "");
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_footnotePr:
+ case NS_ooxml::LN_EG_SectPrContents_endnotePr:
+ m_pImpl->SetInFootnoteProperties( NS_ooxml::LN_EG_SectPrContents_footnotePr == nSprmId );
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_lnNumType:
+ {
+ resolveSprmProps(*this, rSprm);
+ LineNumberSettings aSettings = m_pImpl->GetLineNumberSettings();
+ m_pImpl->SetLineNumberSettings( aSettings );
+ //apply settings at XLineNumberingProperties
+ try
+ {
+ uno::Reference< text::XLineNumberingProperties > xLineNumberingProperties( m_pImpl->GetTextDocument(), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xLineNumberingPropSet = xLineNumberingProperties->getLineNumberingProperties();
+ if( aSettings.nInterval == 0 )
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_IS_ON ), uno::Any(false) );
+ else
+ {
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_IS_ON ), uno::Any(true) );
+ if( aSettings.nInterval )
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_INTERVAL ), uno::Any(static_cast<sal_Int16>(aSettings.nInterval)) );
+ if( aSettings.nDistance != -1 )
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_DISTANCE ), uno::Any(aSettings.nDistance) );
+ else
+ {
+ // set Auto value (0.5 cm)
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_DISTANCE ), uno::Any(static_cast<sal_Int32>(500)) );
+ if( pSectionContext )
+ pSectionContext->SetdxaLnn( static_cast<sal_Int32>(283) );
+ }
+ xLineNumberingPropSet->setPropertyValue(getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::Any(aSettings.bRestartAtEachPage) );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_framePr:
+ {
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if( pContext )
+ {
+ // If there is a deferred page break applied to this framed paragraph,
+ // create a dummy paragraph without extra properties,
+ // so that the anchored frame will be on the correct page (similar to shapes).
+ if (pContext->isSet(PROP_BREAK_TYPE))
+ {
+ pContext->Erase(PROP_BREAK_TYPE);
+
+ lcl_startParagraphGroup();
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ lcl_startCharacterGroup();
+ sal_Unicode const sBreak[] = { 0x0d };
+ lcl_utext(sBreak, 1);
+ lcl_endCharacterGroup();
+ lcl_endParagraphGroup();
+ }
+
+ ParagraphPropertyMap* pParaContext = dynamic_cast< ParagraphPropertyMap* >( pContext.get() );
+ if (pParaContext)
+ pParaContext->props().SetFrameMode();
+
+ if (!IsInHeaderFooter())
+ m_pImpl->m_bIsActualParagraphFramed = true;
+ }
+ else
+ {
+ //TODO: What about style sheet import of frame properties
+ }
+ m_pImpl->NewFrameDirection();
+ resolveSprmProps(*this, rSprm);
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_pgSz:
+ {
+ PaperInfo aLetter(PAPER_LETTER);
+ CT_PageSz.w = aLetter.getWidth();
+ CT_PageSz.h = aLetter.getHeight();
+ }
+ CT_PageSz.orient = false;
+ resolveSprmProps(*this, rSprm);
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ if (!m_pImpl->IsAltChunk())
+ {
+ pSectionContext->Insert(PROP_HEIGHT, uno::Any(CT_PageSz.h));
+ }
+ pSectionContext->Insert( PROP_IS_LANDSCAPE, uno::Any( CT_PageSz.orient ));
+ if (!m_pImpl->IsAltChunk())
+ {
+ pSectionContext->Insert(PROP_WIDTH, uno::Any(CT_PageSz.w));
+ }
+ }
+ break;
+
+ case NS_ooxml::LN_EG_SectPrContents_pgMar:
+ m_pImpl->InitPageMargins();
+ resolveSprmProps(*this, rSprm);
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ const PageMar& rPageMar = m_pImpl->GetPageMargins();
+ pSectionContext->SetTopMargin( rPageMar.top );
+ pSectionContext->SetRightMargin( rPageMar.right );
+ pSectionContext->SetBottomMargin( rPageMar.bottom );
+ pSectionContext->SetLeftMargin( rPageMar.left );
+ pSectionContext->SetHeaderTop( rPageMar.header );
+ pSectionContext->SetHeaderBottom( rPageMar.footer );
+ pSectionContext->SetGutterMargin(rPageMar.gutter);
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_paperSrc:
+ m_pImpl->InitPaperSource();
+ resolveSprmProps(*this, rSprm);
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if(pSectionContext)
+ {
+ const PaperSource& rPaperSource = m_pImpl->GetPaperSource();
+ pSectionContext->SetPaperSource( rPaperSource.first, rPaperSource.other );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_cols:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+
+ tools::SvRef< SectionColumnHandler > pSectHdl( new SectionColumnHandler );
+ pProperties->resolve(*pSectHdl);
+ if(pSectionContext && !m_pImpl->isInIndexContext())
+ {
+ sal_Int16 nColumnCount = pSectHdl->GetNum() == 1 ? 0 : pSectHdl->GetNum();
+ if( pSectHdl->IsEqualWidth() )
+ {
+ pSectionContext->SetEvenlySpaced( true );
+ pSectionContext->SetColumnCount( nColumnCount );
+ pSectionContext->SetColumnDistance( pSectHdl->GetSpace() );
+ pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() );
+ }
+ else if( !pSectHdl->GetColumns().empty() )
+ {
+ pSectionContext->SetEvenlySpaced( false );
+ pSectionContext->SetColumnDistance( pSectHdl->GetSpace() );
+ nColumnCount = pSectHdl->GetColumns().size();
+ pSectionContext->SetColumnCount( nColumnCount == 1 ? 0 : nColumnCount );
+ std::vector<Column_>::const_iterator tmpIter = pSectHdl->GetColumns().begin();
+ for (; tmpIter != pSectHdl->GetColumns().end(); ++tmpIter)
+ {
+ pSectionContext->AppendColumnWidth( tmpIter->nWidth );
+ if ((tmpIter != pSectHdl->GetColumns().end() - 1) || (tmpIter->nSpace > 0))
+ pSectionContext->AppendColumnSpacing( tmpIter->nSpace );
+ }
+ pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() );
+ }
+ else if( nColumnCount )
+ {
+ pSectionContext->SetColumnCount( nColumnCount );
+ pSectionContext->SetColumnDistance( pSectHdl->GetSpace() );
+ pSectionContext->SetSeparatorLine( pSectHdl->IsSeparator() );
+ }
+ }
+
+ else if ( pSectionContext )
+ {
+ FieldContextPtr pContext = m_pImpl->GetTopFieldContext();
+ uno::Reference< beans::XPropertySet > xTOC = pContext->GetTOC();
+ if( xTOC.is() )
+ {
+ uno::Reference<text::XTextColumns> xTextColumns;
+ xTOC->getPropertyValue(getPropertyName( PROP_TEXT_COLUMNS )) >>= xTextColumns;
+ if (xTextColumns.is())
+ {
+ uno::Reference< beans::XPropertySet > xColumnPropSet( xTextColumns, uno::UNO_QUERY_THROW );
+ xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::Any( pSectHdl->GetSpace() ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TEXT_COLUMNS ), uno::Any( xTextColumns ) );
+ }
+ }
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_docGrid:
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_pgBorders:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties && pSectionContext )
+ {
+ tools::SvRef< PageBordersHandler > pHandler( new PageBordersHandler );
+ pProperties->resolve( *pHandler );
+
+ // Set the borders to the context and apply them to the styles
+ pHandler->SetBorders( pSectionContext );
+ }
+ }
+ break;
+
+ case NS_ooxml::LN_CT_PPrBase_snapToGrid:
+ if (!IsStyleSheetImport()||!m_pImpl->isInteropGrabBagEnabled())
+ {
+ rContext->Insert( PROP_SNAP_TO_GRID, uno::Any(bool(nIntValue)));
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "snapToGrid", OUString::number(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_pStyle:
+ {
+ StyleSheetTablePtr pStyleTable = m_pImpl->GetStyleSheetTable();
+ const OUString sConvertedStyleName = pStyleTable->ConvertStyleName( sStringValue, true );
+ m_pImpl->SetCurrentParaStyleName( sConvertedStyleName );
+ if (m_pImpl->GetTopContext() && m_pImpl->GetTopContextType() != CONTEXT_SECTION)
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_STYLE_NAME, uno::Any( sConvertedStyleName ));
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_rStyle:
+ {
+ OUString sConvertedName( m_pImpl->GetStyleSheetTable()->ConvertStyleName( sStringValue, true ) );
+ if (m_pImpl->CheckFootnoteStyle() && m_pImpl->GetFootnoteContext())
+ m_pImpl->SetHasFootnoteStyle(m_pImpl->GetFootnoteContext()->GetFootnoteStyle() == sConvertedName);
+
+ // First check if the style exists in the document.
+ StyleSheetEntryPtr pEntry = m_pImpl->GetStyleSheetTable( )->FindStyleSheetByConvertedStyleName( sConvertedName );
+ bool bExists = pEntry && ( pEntry->m_nStyleTypeCode == STYLE_TYPE_CHAR );
+ // Add the property if the style exists, but do not add it elements in TOC:
+ // they will receive later another style references from TOC
+ if ( bExists && m_pImpl->GetTopContext() && !m_pImpl->IsInTOC())
+ m_pImpl->GetTopContext()->Insert( PROP_CHAR_STYLE_NAME, uno::Any( sConvertedName ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar: //cell margins
+ {
+ resolveSprmProps(*this, rSprm);//contains LN_CT_TblCellMar_top, LN_CT_TblCellMar_left, LN_CT_TblCellMar_bottom, LN_CT_TblCellMar_right
+ }
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_top:
+ case NS_ooxml::LN_CT_TblCellMar_start:
+ case NS_ooxml::LN_CT_TblCellMar_left:
+ case NS_ooxml::LN_CT_TblCellMar_bottom:
+ case NS_ooxml::LN_CT_TblCellMar_end:
+ case NS_ooxml::LN_CT_TblCellMar_right:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ sal_Int32 nMeasureValue = pMeasureHandler->getMeasureValue();
+ PropertyIds eId = META_PROP_CELL_MAR_TOP;
+ bool rtl = false; // TODO
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_TblCellMar_top:
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_start:
+ eId = rtl ? META_PROP_CELL_MAR_RIGHT : META_PROP_CELL_MAR_LEFT;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_left:
+ eId = META_PROP_CELL_MAR_LEFT;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_bottom:
+ eId = META_PROP_CELL_MAR_BOTTOM;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_end:
+ eId = rtl ? META_PROP_CELL_MAR_LEFT : META_PROP_CELL_MAR_RIGHT;
+ break;
+ case NS_ooxml::LN_CT_TblCellMar_right:
+ eId = META_PROP_CELL_MAR_RIGHT;
+ break;
+ default:;
+ }
+ rContext->Insert( eId, uno::Any(nMeasureValue), false);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_noProof: // no grammar and spell checking, unsupported
+ break;
+ case NS_ooxml::LN_anchor_anchor: // at_character drawing
+ case NS_ooxml::LN_inline_inline: // as_character drawing
+ {
+ if ( m_pImpl->IsDiscardHeaderFooter() )
+ break;
+ //tdf112342: Break before images as well, if there are page break
+ if (m_pImpl->isBreakDeferred(BreakType::PAGE_BREAK)
+ && nSprmId == NS_ooxml::LN_inline_inline && !m_pImpl->IsInShape())
+ {
+ if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun())
+ {
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ else
+ {
+ m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)
+ ->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ m_pImpl->clearDeferredBreak(PAGE_BREAK);
+ }
+ }
+
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ m_pImpl->m_eGraphicImportType =
+ (NS_ooxml::LN_anchor_anchor ==
+ sal::static_int_cast<Id>(nSprmId)) ?
+ IMPORT_AS_DETECTED_ANCHOR :
+ IMPORT_AS_DETECTED_INLINE;
+ GraphicImportPtr pGraphicImport = m_pImpl->GetGraphicImport();
+ pProperties->resolve(*pGraphicImport);
+ m_pImpl->ImportGraphic(pProperties);
+ if( !pGraphicImport->IsGraphic() )
+ {
+ m_pImpl->ResetGraphicImport();
+ // todo: It's a shape, now start shape import
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_vertAlign:
+ {
+ sal_Int16 nEscapement = 0;
+ sal_Int8 nProp = DFLT_ESC_PROP;
+ if ( sStringValue == "superscript" )
+ nEscapement = DFLT_ESC_AUTO_SUPER;
+ else if ( sStringValue == "subscript" )
+ nEscapement = DFLT_ESC_AUTO_SUB;
+ else
+ nProp = 100;
+
+ rContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( nEscapement ) );
+ rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::Any( nProp ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_FtnProps_pos:
+ //footnotes in word can be at page end or beneath text - writer supports only the first
+ //endnotes in word can be at section end or document end - writer supports only the latter
+ // -> so this property can be ignored
+ break;
+ case NS_ooxml::LN_CT_FtnProps_numFmt:
+ case NS_ooxml::LN_CT_EdnProps_numFmt:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_FtnEdnNumProps_numStart:
+ case NS_ooxml::LN_EG_FtnEdnNumProps_numRestart:
+ {
+ try
+ {
+ uno::Reference< beans::XPropertySet > xFtnEdnSettings;
+ if( m_pImpl->IsInFootnoteProperties() )
+ {
+ uno::Reference< text::XFootnotesSupplier> xFootnotesSupplier( m_pImpl->GetTextDocument(), uno::UNO_QUERY );
+ if (xFootnotesSupplier.is())
+ xFtnEdnSettings = xFootnotesSupplier->getFootnoteSettings();
+ }
+ else
+ {
+ uno::Reference< text::XEndnotesSupplier> xEndnotesSupplier( m_pImpl->GetTextDocument(), uno::UNO_QUERY );
+ if (xEndnotesSupplier.is())
+ xFtnEdnSettings = xEndnotesSupplier->getEndnoteSettings();
+ }
+ if( NS_ooxml::LN_EG_FtnEdnNumProps_numStart == nSprmId && xFtnEdnSettings.is())
+ {
+ xFtnEdnSettings->setPropertyValue(
+ getPropertyName( PROP_START_AT),
+ uno::Any( sal_Int16( nIntValue - 1 )));
+ }
+ else if( NS_ooxml::LN_EG_FtnEdnNumProps_numRestart == nSprmId && xFtnEdnSettings.is())
+ {
+ sal_Int16 nFootnoteCounting = 0;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_RestartNumber_continuous: nFootnoteCounting = text::FootnoteNumbering::PER_DOCUMENT; break;
+ case NS_ooxml::LN_Value_ST_RestartNumber_eachPage: nFootnoteCounting = text::FootnoteNumbering::PER_PAGE; break;
+ case NS_ooxml::LN_Value_ST_RestartNumber_eachSect: nFootnoteCounting = text::FootnoteNumbering::PER_CHAPTER; break;
+ default: break;
+ }
+ xFtnEdnSettings->setPropertyValue(
+ getPropertyName( PROP_FOOTNOTE_COUNTING ),
+ uno::Any( nFootnoteCounting ));
+ }
+ else if (xFtnEdnSettings.is())
+ {
+ sal_Int16 nNumType = ConversionHelper::ConvertNumberingType( nIntValue );
+ xFtnEdnSettings->setPropertyValue(
+ getPropertyName( PROP_NUMBERING_TYPE),
+ uno::Any( nNumType ));
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveFromRangeStart:
+ m_pImpl->SetMoveBookmark(/*bIsFrom=*/true);
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().setMoved( getPropertyName(PROP_TABLE_ROW_DELETE) );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveToRangeStart:
+ m_pImpl->SetMoveBookmark(/*bIsFrom=*/false);
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().setMoved( getPropertyName(PROP_TABLE_ROW_INSERT) );
+ break;
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveFromRangeEnd:
+ case NS_ooxml::LN_EG_RangeMarkupElements_moveToRangeEnd:
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().setMoved( OUString() );
+ break;
+ case NS_ooxml::LN_CT_ParaRPr_moveFrom:
+ case NS_ooxml::LN_CT_ParaRPr_moveTo:
+ m_pImpl->StartParaMarkerMove( );
+ break;
+ case NS_ooxml::LN_paratrackchange:
+ m_pImpl->StartParaMarkerChange( );
+ [[fallthrough]];
+ case NS_ooxml::LN_CT_PPr_pPrChange:
+ case NS_ooxml::LN_CT_ParaRPr_rPrChange:
+ case NS_ooxml::LN_trackchange:
+ case NS_ooxml::LN_EG_RPrContent_rPrChange:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlDelRangeStart:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlDelRangeEnd:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveFromRangeStart:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveFromRangeEnd:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveToRangeStart:
+ case NS_ooxml::LN_EG_RangeMarkupElements_customXmlMoveToRangeEnd:
+ {
+ HandleRedline( rSprm );
+ }
+ break;
+ case NS_ooxml::LN_endtrackchange:
+ m_pImpl->RemoveTopRedline();
+ break;
+ case NS_ooxml::LN_CT_RPrChange_rPr:
+ {
+ // Push all the current 'Character' properties to the stack, so that we don't store them
+ // as 'tracked changes' by mistake
+ m_pImpl->PushProperties(CONTEXT_CHARACTER);
+
+ // Resolve all the properties that are under the 'rPrChange'->'rPr' XML node
+ resolveSprmProps(*this, rSprm );
+
+ // Get all the properties that were processed in the 'rPrChange'->'rPr' XML node
+ uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
+
+ // Pop back out the character properties that were on the run
+ m_pImpl->PopProperties(CONTEXT_CHARACTER);
+
+ // Store these properties in the current redline object (do it after the PopProperties() above, since
+ // otherwise it'd be stored in the content dropped there).
+ m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrChange_pPr:
+ {
+ // Push all the current 'Paragraph' properties to the stack, so that we don't store them
+ // as 'tracked changes' by mistake
+ m_pImpl->PushProperties(CONTEXT_PARAGRAPH);
+
+ // Resolve all the properties that are under the 'pPrChange'->'pPr' XML node
+ resolveSprmProps(*this, rSprm );
+
+ // Get all the properties that were processed in the 'pPrChange'->'pPr' XML node
+ uno::Sequence< beans::PropertyValue > currentRedlineRevertProperties = m_pImpl->GetTopContext()->GetPropertyValues();
+
+ // Pop back out the character properties that were on the run
+ m_pImpl->PopProperties(CONTEXT_PARAGRAPH);
+
+ // Store these properties in the current redline object (do it after the PopProperties() above, since
+ // otherwise it'd be stored in the content dropped there).
+ m_pImpl->SetCurrentRedlineRevertProperties( currentRedlineRevertProperties );
+ }
+ break;
+ case NS_ooxml::LN_object:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pOLEHandler = std::make_shared<OLEHandler>(*this);
+ pProperties->resolve(*pOLEHandler);
+ if ( pOLEHandler->isOLEObject( ) )
+ {
+ OUString sStreamName = pOLEHandler->copyOLEOStream( m_pImpl->GetTextDocument() );
+ if( !sStreamName.isEmpty() )
+ {
+ m_pImpl->appendOLE( sStreamName, pOLEHandler );
+ }
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_HdrFtrReferences_headerReference: // header reference - not needed
+ case NS_ooxml::LN_EG_HdrFtrReferences_footerReference: // footer reference - not needed
+ break;
+ case NS_ooxml::LN_EG_RPrBase_snapToGrid: // "Use document grid settings for inter-paragraph spacing"
+ break;
+ case NS_ooxml::LN_CT_PPrBase_contextualSpacing:
+ rContext->Insert(PROP_PARA_CONTEXT_MARGIN, uno::Any( nIntValue != 0 ));
+ break;
+ case NS_ooxml::LN_CT_PPrBase_mirrorIndents: // mirrorIndents
+ rContext->Insert(PROP_MIRROR_INDENTS, uno::Any( nIntValue != 0 ), true, PARA_GRAB_BAG);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_formProt: //section protection
+ {
+ if( pSectionContext )
+ pSectionContext->Insert( PROP_IS_PROTECTED, uno::Any( bool(nIntValue) ) );
+ }
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_vAlign:
+ {
+ OSL_ENSURE(pSectionContext, "SectionContext unavailable!");
+ if( pSectionContext )
+ {
+ drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_VerticalJc_center: //92367
+ nVA = drawing::TextVerticalAdjust_CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_both: //92368 - justify
+ nVA = drawing::TextVerticalAdjust_BLOCK;
+ break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_bottom: //92369
+ nVA = drawing::TextVerticalAdjust_BOTTOM;
+ break;
+ default:
+ break;
+ }
+ pSectionContext->Insert( PROP_TEXT_VERTICAL_ADJUST, uno::Any( nVA ), true, PARA_GRAB_BAG );
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_fitText:
+ break;
+ case NS_ooxml::LN_ffdata:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ FFDataHandler::Pointer_t pFFDataHandler(new FFDataHandler());
+
+ pProperties->resolve(*pFFDataHandler);
+ m_pImpl->SetFieldFFData(pFFDataHandler);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_comboBox:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::comboBox);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_dropDownList:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::dropDown);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDropDownList_listItem:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+
+ size_t nDropDownDisplayTexts = m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().size();
+ size_t nDropDownItems = m_pImpl->m_pSdtHelper->getDropDownItems().size();
+
+ if (pProperties)
+ pProperties->resolve(*this);
+
+ if (m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().size() != nDropDownDisplayTexts + 1)
+ {
+ // w:displayText="..." is optional, add empty value if it was not provided.
+ m_pImpl->m_pSdtHelper->getDropDownDisplayTexts().emplace_back();
+ }
+ if (m_pImpl->m_pSdtHelper->getDropDownItems().size() != nDropDownItems + 1)
+ {
+ // w:value="..." is optional, add empty value if it was not provided.
+ m_pImpl->m_pSdtHelper->getDropDownItems().emplace_back();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_placeholder:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ break;
+ case NS_ooxml::LN_CT_SdtPr_date:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::datePicker);
+ resolveSprmProps(*this, rSprm);
+ m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd());
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_dateFormat:
+ {
+ m_pImpl->m_pSdtHelper->getDateFormat().append(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_storeMappedDataAs:
+ {
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_calendar:
+ {
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDate_lid:
+ {
+ m_pImpl->m_pSdtHelper->getLocale().append(sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_text:
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::plainText);
+ if (m_pImpl->m_pSdtHelper->GetSdtType() == NS_ooxml::LN_CT_SdtRun_sdtContent)
+ {
+ m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ break;
+ }
+ enableInteropGrabBag("ooxml:CT_SdtPr_text");
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_dataBinding:
+ case NS_ooxml::LN_CT_SdtPr_equation:
+ case NS_ooxml::LN_CT_SdtPr_checkbox:
+ case NS_ooxml::LN_CT_SdtPr_docPartObj:
+ case NS_ooxml::LN_CT_SdtPr_docPartList:
+ case NS_ooxml::LN_CT_SdtPr_picture:
+ case NS_ooxml::LN_CT_SdtPr_citation:
+ case NS_ooxml::LN_CT_SdtPr_group:
+ case NS_ooxml::LN_CT_SdtPr_id:
+ case NS_ooxml::LN_CT_SdtPr_alias:
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart:
+ case NS_ooxml::LN_CT_SdtPr_showingPlcHdr:
+ case NS_ooxml::LN_CT_SdtPr_color:
+ case NS_ooxml::LN_CT_SdtPr_appearance:
+ case NS_ooxml::LN_CT_SdtPr_tag:
+ case NS_ooxml::LN_CT_SdtPr_tabIndex:
+ case NS_ooxml::LN_CT_SdtPr_lock:
+ {
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_showingPlcHdr)
+ {
+ if (nIntValue)
+ m_pImpl->m_pSdtHelper->SetShowingPlcHdr();
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_color)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_appearance)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_alias)
+ {
+ m_pImpl->m_pSdtHelper->SetAlias(sStringValue);
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_tag)
+ {
+ m_pImpl->m_pSdtHelper->SetTag(sStringValue);
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_id)
+ {
+ m_pImpl->m_pSdtHelper->SetId(nIntValue);
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_tabIndex)
+ {
+ m_pImpl->m_pSdtHelper->SetTabIndex(nIntValue);
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_lock)
+ {
+ m_pImpl->m_pSdtHelper->SetLock(sStringValue);
+ break;
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::checkBox);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_SdtPr_picture)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::picture);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_SdtPr_date)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::datePicker);
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ break;
+ }
+ }
+
+ // this is an unsupported SDT property, create a grab bag for it
+ OUString sName;
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_SdtPr_dataBinding: sName = "ooxml:CT_SdtPr_dataBinding"; break;
+ case NS_ooxml::LN_CT_SdtPr_equation: sName = "ooxml:CT_SdtPr_equation"; break;
+ case NS_ooxml::LN_CT_SdtPr_checkbox: sName = "ooxml:CT_SdtPr_checkbox"; break;
+ case NS_ooxml::LN_CT_SdtPr_docPartObj: sName = "ooxml:CT_SdtPr_docPartObj"; break;
+ case NS_ooxml::LN_CT_SdtPr_docPartList: sName = "ooxml:CT_SdtPr_docPartList"; break;
+ case NS_ooxml::LN_CT_SdtPr_picture: sName = "ooxml:CT_SdtPr_picture"; break;
+ case NS_ooxml::LN_CT_SdtPr_citation: sName = "ooxml:CT_SdtPr_citation"; break;
+ case NS_ooxml::LN_CT_SdtPr_group: sName = "ooxml:CT_SdtPr_group"; break;
+ case NS_ooxml::LN_CT_SdtPr_id: sName = "ooxml:CT_SdtPr_id"; break;
+ case NS_ooxml::LN_CT_SdtPr_alias: sName = "ooxml:CT_SdtPr_alias"; break;
+ case NS_ooxml::LN_CT_SdtPr_tag: sName = "ooxml:CT_SdtPr_tag"; break;
+ case NS_ooxml::LN_CT_SdtPr_tabIndex: sName = "ooxml:CT_SdtPr_tabIndex"; break;
+ case NS_ooxml::LN_CT_SdtPr_lock: sName = "ooxml:CT_SdtPr_lock"; break;
+ case NS_ooxml::LN_CT_SdtPlaceholder_docPart: sName = "ooxml:CT_SdtPlaceholder_docPart"; break;
+ case NS_ooxml::LN_CT_SdtPr_showingPlcHdr: sName = "ooxml:CT_SdtPr_showingPlcHdr"; break;
+ case NS_ooxml::LN_CT_SdtPr_color: sName = "ooxml:CT_SdtPr_color"; break;
+ case NS_ooxml::LN_CT_SdtPr_appearance: sName = "ooxml:CT_SdtPr_appearance"; break;
+ default: assert(false);
+ };
+ if (
+ nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartObj ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_docPartList ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_picture ||
+ nSprmId == NS_ooxml::LN_CT_SdtPr_citation)
+ {
+ m_pImpl->m_pSdtHelper->setControlType(SdtControlType::unsupported);
+ }
+ enableInteropGrabBag(sName);
+
+ // process subitems
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_alias || nSprmId == NS_ooxml::LN_CT_SdtPr_tag
+ || nSprmId == NS_ooxml::LN_CT_SdtPr_lock)
+ {
+ // Grabbag string values
+ beans::PropertyValue aValue;
+ aValue.Name = sName;
+ aValue.Value <<= sStringValue;
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(aValue);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_SdtPr_showingPlcHdr)
+ {
+ // Grabbag boolean values
+ beans::PropertyValue aValue;
+ aValue.Name = sName;
+ aValue.Value <<= bool(nIntValue);
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(aValue);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_SdtPr_id || nSprmId == NS_ooxml::LN_CT_SdtPr_tabIndex)
+ {
+ // Grabbag integer values
+ beans::PropertyValue aValue;
+ aValue.Name = sName;
+ aValue.Value <<= nIntValue;
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(aValue);
+ }
+ else
+ m_pImpl->m_pSdtHelper->appendToInteropGrabBag(getInteropGrabBag());
+ m_pImpl->m_pSdtHelper->setOutsideAParagraph(m_pImpl->IsOutsideAParagraph());
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtCheckbox_checked:
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ // nIntValue is not just 0 or 1, because we're in the w14 namespace's ST_OnOff.
+ if (nIntValue == NS_ooxml::LN_ST_OnOff_true || nIntValue == NS_ooxml::LN_ST_OnOff_1)
+ {
+ m_pImpl->m_pSdtHelper->SetChecked();
+ }
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtCheckbox_checked",
+ TextEffectsHandler::getOnOffString(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtCheckbox_checkedState:
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ m_pImpl->m_pSdtHelper->SetCheckedState(OUString(sal_Unicode(sStringValue.toInt32(16))));
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtCheckbox_checkedState",
+ sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtCheckbox_uncheckedState:
+ if (!m_pImpl->GetSdtStarts().empty())
+ {
+ m_pImpl->m_pSdtHelper->SetUncheckedState(
+ OUString(sal_Unicode(sStringValue.toInt32(16))));
+ }
+ else
+ {
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag,
+ "ooxml:CT_SdtCheckbox_uncheckedState", sStringValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtDocPart_docPartGallery:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtDocPart_docPartGallery", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtDocPart_docPartCategory:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtDocPart_docPartCategory", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_SdtDocPart_docPartUnique:
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "ooxml:CT_SdtDocPart_docPartUnique", sStringValue);
+ break;
+ case NS_ooxml::LN_EG_SectPrContents_pgNumType:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_tblStart:
+ {
+ /*
+ * 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_StreamStateStack.top().nTableDepth == 0
+ && m_pImpl->GetIsFirstParagraphInSection()
+ && !m_pImpl->GetIsDummyParaAddedForTableInSection() && !m_pImpl->GetIsTextFrameInserted()
+ && !m_pImpl->GetIsPreviousParagraphFramed() && !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_StreamStateStack.top().nTableDepth == 0)
+ {
+ const uno::Any aBreakType(style::BreakType_PAGE_BEFORE);
+ const PropertyMapPtr pParagraphProps = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if( pParagraphProps && pParagraphProps->isSet(PROP_PARA_STYLE_NAME) )
+ {
+ StyleSheetEntryPtr pStyle;
+ OUString sStyleName;
+ pParagraphProps->getProperty(PROP_PARA_STYLE_NAME)->second >>= sStyleName;
+ if( !sStyleName.isEmpty() && GetStyleSheetTable() )
+ pStyle = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( sStyleName );
+
+ if( pStyle && pStyle->m_pProperties
+ && pStyle->m_pProperties->isSet(PROP_BREAK_TYPE)
+ && pStyle->m_pProperties->getProperty(PROP_BREAK_TYPE)->second == aBreakType )
+ {
+ pParagraphProps->Insert(PROP_BREAK_TYPE, aBreakType);
+ }
+ }
+ }
+
+ m_pImpl->m_StreamStateStack.top().nTableDepth++;
+ }
+ break;
+ case NS_ooxml::LN_tblEnd:
+ m_pImpl->m_StreamStateStack.top().nTableDepth--;
+ break;
+ case NS_ooxml::LN_tcStart:
+ m_pImpl->m_StreamStateStack.top().nTableCellDepth++;
+ break;
+ case NS_ooxml::LN_tcEnd:
+ m_pImpl->m_StreamStateStack.top().nTableCellDepth--;
+ break;
+ case NS_ooxml::LN_glow_glow:
+ case NS_ooxml::LN_shadow_shadow:
+ case NS_ooxml::LN_reflection_reflection:
+ case NS_ooxml::LN_textOutline_textOutline:
+ case NS_ooxml::LN_textFill_textFill:
+ case NS_ooxml::LN_scene3d_scene3d:
+ case NS_ooxml::LN_props3d_props3d:
+ case NS_ooxml::LN_ligatures_ligatures:
+ case NS_ooxml::LN_numForm_numForm:
+ case NS_ooxml::LN_numSpacing_numSpacing:
+ case NS_ooxml::LN_stylisticSets_stylisticSets:
+ case NS_ooxml::LN_cntxtAlts_cntxtAlts:
+ {
+ tools::SvRef<TextEffectsHandler> pTextEffectsHandlerPtr( new TextEffectsHandler(nSprmId) );
+ std::optional<PropertyIds> aPropertyId = pTextEffectsHandlerPtr->getGrabBagPropertyId();
+ if(aPropertyId)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*pTextEffectsHandlerPtr);
+
+ beans::PropertyValue aGrabBag = pTextEffectsHandlerPtr->getInteropGrabBag();
+ rContext->Insert(*aPropertyId, uno::Any(aGrabBag), true, CHAR_GRAB_BAG);
+
+ sal_Int16 nTransparency = TextEffectsHandler::GetTextFillSolidFillAlpha(aGrabBag);
+ if (nTransparency != 0)
+ {
+ rContext->Insert(PROP_CHAR_TRANSPARENCE, uno::Any(nTransparency));
+ }
+ }
+ else if (nSprmId == NS_ooxml::LN_cntxtAlts_cntxtAlts)
+ {
+ pTextEffectsHandlerPtr->lcl_sprm(rSprm);
+ beans::PropertyValue aGrabBag = pTextEffectsHandlerPtr->getInteropGrabBag();
+ rContext->Insert(*aPropertyId, uno::Any(aGrabBag), true, CHAR_GRAB_BAG);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SdtPr_rPr:
+ {
+ // Make sure properties from a previous SDT are not merged with the current ones.
+ m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblLook:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ m_pImpl->getTableManager().finishTableLook();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_cnfStyle:
+ {
+ m_pImpl->enableInteropGrabBag("cnfStyle");
+ resolveSprmProps(*this, rSprm);
+
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_ROW_CNF_STYLE, uno::Any(comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag)), true, ROW_GRAB_BAG);
+ m_pImpl->getTableManager().insertRowProps(pPropMap);
+
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_cnfStyle:
+ {
+ m_pImpl->enableInteropGrabBag("cnfStyle");
+ resolveSprmProps(*this, rSprm);
+
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_CELL_CNF_STYLE, uno::Any(comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag)), true, CELL_GRAB_BAG);
+ m_pImpl->getTableManager().cellProps(pPropMap);
+
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_cnfStyle:
+ {
+ m_pImpl->enableInteropGrabBag("cnfStyle");
+ resolveSprmProps(*this, rSprm);
+ rContext->Insert(PROP_PARA_CNF_STYLE, uno::Any(comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag)), true, PARA_GRAB_BAG);
+ m_pImpl->disableInteropGrabBag();
+ }
+ break;
+ case NS_ooxml::LN_EG_RunInnerContent_sym:
+ {
+ resolveSprmProps(*this, rSprm);
+ SymbolData aSymbolData = m_pImpl->GetSymbolData();
+ uno::Any aVal( aSymbolData.sFont );
+ auto xFootnote = rContext->GetFootnote();
+ if (!xFootnote.is() && m_pImpl->IsInCustomFootnote())
+ xFootnote = m_pImpl->GetFootnoteContext()->GetFootnote();
+ if (xFootnote.is())
+ {
+ // DOCX can have different labels for the footnote reference and the footnote area.
+ // This skips the one from the footnote area and just uses the reference one.
+ if (!m_pImpl->IsInFootOrEndnote())
+ {
+ auto xAnchorRange = xFootnote->getAnchor();
+ auto xAnchorCursor(xAnchorRange->getText()->createTextCursorByRange(xAnchorRange));
+
+ // append a dummy character, so the following properties will be set as
+ // as SwpHints::SwTextAttr instead of the SwAttrSet of the paragraph,
+ // which would be removed by SwXText::Impl::finishOrAppendParagraph
+ xAnchorCursor->collapseToEnd();
+ uno::Reference<text::XTextRange> xHackRange(xAnchorCursor, uno::UNO_QUERY);
+ xHackRange->setString("x");
+
+ uno::Reference<beans::XPropertySet> xAnchorProps(xAnchorRange, uno::UNO_QUERY);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), aVal);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_ASIAN), aVal);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_COMPLEX), aVal);
+ xAnchorProps->setPropertyValue(getPropertyName(PROP_CHAR_FONT_CHAR_SET), uno::Any(awt::CharSet::SYMBOL));
+
+ // remove the dummy char
+ xHackRange->setString("");
+
+ OUString sLabel = xFootnote->getLabel() + OUStringChar(aSymbolData.cSymbol);
+ xFootnote->setLabel(sLabel);
+ }
+ }
+ else //it's a _real_ symbol
+ {
+ rContext->Insert(PROP_CHAR_FONT_NAME, aVal);
+ rContext->Insert(PROP_CHAR_FONT_NAME_ASIAN, aVal);
+ rContext->Insert(PROP_CHAR_FONT_NAME_COMPLEX, aVal);
+ rContext->Insert(PROP_CHAR_FONT_CHAR_SET, uno::Any(awt::CharSet::SYMBOL));
+ utext(&(aSymbolData.cSymbol), 1);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RunInnerContent_ruby:
+ {
+ RubyInfo aInfo ;
+ m_pImpl->SetRubyInfo(aInfo);
+ }
+ break;
+ case NS_ooxml::LN_CT_RubyPr:
+ case NS_ooxml::LN_CT_Ruby_rt:
+ case NS_ooxml::LN_CT_Ruby_rubyBase:
+ {
+ m_pImpl->SetRubySprmId(nSprmId);
+ if (nSprmId == NS_ooxml::LN_CT_RubyPr)
+ {
+ resolveSprmProps(*this, rSprm);
+ }
+ }
+ break;
+ case NS_ooxml::LN_EG_RubyContent_r:
+ {
+ const RubyInfo & aInfo = m_pImpl->GetRubyInfo();
+ if (aInfo.nSprmId == NS_ooxml::LN_CT_Ruby_rubyBase)
+ {
+ rContext->Insert(PROP_RUBY_TEXT, uno::Any(aInfo.sRubyText));
+ rContext->Insert(PROP_RUBY_STYLE, uno::Any(aInfo.sRubyStyle));
+ rContext->Insert(PROP_RUBY_ADJUST, uno::Any(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign))));
+ if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical )
+ rContext->Insert(PROP_RUBY_POSITION, uno::Any(css::text::RubyPosition::INTER_CHARACTER));
+
+ m_pImpl->SetRubySprmId(0);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_RubyPr_rubyAlign:
+ case NS_ooxml::LN_CT_RubyPr_hps:
+ case NS_ooxml::LN_CT_RubyPr_hpsBaseText:
+ {
+ RubyInfo aInfo = m_pImpl->GetRubyInfo();
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_RubyPr_rubyAlign:
+ aInfo.nRubyAlign = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_RubyPr_hps:
+ aInfo.nHps= nIntValue;
+ break;
+ case NS_ooxml::LN_CT_RubyPr_hpsBaseText:
+ aInfo.nHpsBaseText = nIntValue;
+ break;
+ }
+ m_pImpl->SetRubyInfo(aInfo);
+ }
+ break;
+ case NS_ooxml::LN_CT_SmartTagRun_smartTagPr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties && m_pImpl->GetTopContextType() == CONTEXT_PARAGRAPH)
+ pProperties->resolve(m_pImpl->getSmartTagHandler());
+ }
+ break;
+ case NS_ooxml::LN_CT_DocPartPr_name:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_DocPartPr_category:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_DocPartCategory_gallery:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_EG_RunInnerContent_instrText:
+ {
+ m_pImpl->SetIsTextDeleted(false);
+ }
+ break;
+ case NS_ooxml::LN_EG_RunInnerContent_delText:
+ case NS_ooxml::LN_EG_RunInnerContent_delInstrText:
+ {
+ m_pImpl->SetIsTextDeleted(true);
+ }
+ 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::ProcessDeferredStyleCharacterProperties()
+{
+ assert(m_pImpl->GetTopContextType() == CONTEXT_STYLESHEET);
+ m_pImpl->processDeferredCharacterProperties(false);
+}
+
+void DomainMapper::processDeferredCharacterProperties(
+ const std::map<sal_Int32, uno::Any>& deferredCharacterProperties, bool bCharContext)
+{
+ if (bCharContext)
+ {
+ assert(m_pImpl->GetTopContextType() == CONTEXT_CHARACTER);
+ }
+ PropertyMapPtr rContext = m_pImpl->GetTopContext();
+ for( const auto& rProp : deferredCharacterProperties )
+ {
+ sal_Int32 Id = rProp.first;
+ sal_Int32 nIntValue = 0;
+ OUString sStringValue;
+ rProp.second >>= nIntValue;
+ rProp.second >>= sStringValue;
+ switch( Id )
+ {
+ case NS_ooxml::LN_EG_RPrBase_position:
+ {
+ double nEscapement = 0;
+ sal_Int8 nProp = 0;
+ if ( nIntValue )
+ {
+ nProp = 100;
+ double fFontSize = 0;
+ m_pImpl->GetAnyProperty(PROP_CHAR_HEIGHT, rContext) >>= fFontSize;
+ if ( fFontSize )
+ // nIntValue is in half-points, fontsize is in points, escapement is a percentage.
+ nEscapement = round( nIntValue/2.0 / fFontSize * 100 );
+ else
+ nEscapement = nIntValue > 0 ? DFLT_ESC_SUPER : DFLT_ESC_SUB;
+ }
+ if ( nEscapement > MAX_ESC_POS )
+ nEscapement = MAX_ESC_POS;
+ else if ( nEscapement < -MAX_ESC_POS )
+ nEscapement = -MAX_ESC_POS;
+
+ rContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( sal_Int16(nEscapement) ) );
+ rContext->Insert(PROP_CHAR_ESCAPEMENT_HEIGHT, uno::Any( nProp ) );
+ }
+ break;
+ default:
+ SAL_WARN( "writerfilter", "Unhandled property in processDeferredCharacterProperty()" );
+ break;
+ }
+ }
+}
+
+void DomainMapper::lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref)
+{
+ ref->resolve(*this);
+}
+
+void DomainMapper::data(const sal_uInt8* /*buf*/, size_t /*len*/)
+{
+}
+
+void DomainMapper::lcl_startSectionGroup()
+{
+ if (!m_pImpl->isInIndexContext() && !m_pImpl->isInBibliographyContext())
+ {
+ m_pImpl->PushProperties(CONTEXT_SECTION);
+ }
+ m_pImpl->SetIsFirstParagraphInSection(true);
+ m_pImpl->SetIsFirstParagraphInSectionAfterRedline(true);
+}
+
+void DomainMapper::lcl_endSectionGroup()
+{
+ if (m_pImpl->isInIndexContext() || m_pImpl->isInBibliographyContext())
+ return;
+
+ m_pImpl->CheckUnregisteredFrameConversion();
+ m_pImpl->ExecuteFrameConversion();
+ // When pasting, it's fine to not have any paragraph inside the document at all.
+ if (m_pImpl->GetIsFirstParagraphInSection() && m_pImpl->IsNewDoc())
+ {
+ // This section has no paragraph at all (e.g. they are all actually in a frame).
+ // If this section has a page break, there would be nothing to apply to the page
+ // style, so force a dummy paragraph.
+ lcl_startParagraphGroup();
+ lcl_startCharacterGroup();
+ sal_Unicode const sBreak[] = { 0x0d };
+ lcl_utext(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
+ // tdf#135786: Added annotation condition
+ if (m_pImpl->GetIsDummyParaAddedForTableInSection() && (m_pImpl->GetAnnotationId() < 0))
+ 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->IsInShape() && !m_pImpl->IsInComments())
+ {
+ if (m_pImpl->GetTopContext())
+ {
+ const OUString& sDefaultParaStyle = m_pImpl->GetDefaultParaStyleName();
+ auto pContext = static_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContext().get());
+ m_pImpl->GetTopContext()->Insert( PROP_PARA_STYLE_NAME, uno::Any( sDefaultParaStyle ) );
+ m_pImpl->SetCurrentParaStyleName( sDefaultParaStyle );
+
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+
+ // With a w:br at the start of a paragraph, compat14 apparently doesn't apply.
+ // It works to insert a zero margin before importing paragraph properties because
+ // TopMargin typically imports without overwrite any existing value. Very handy.
+ pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ }
+
+ mbWasShapeInPara = false;
+ }
+ m_pImpl->clearDeferredBreaks();
+ }
+
+ if (m_pImpl->isParaSdtEndDeferred() && m_pImpl->GetTopContext())
+ m_pImpl->GetTopContext()->Insert(PROP_PARA_SDT_END_BEFORE, uno::Any(true), true, PARA_GRAB_BAG);
+ m_pImpl->setParaSdtEndDeferred(false);
+
+ m_pImpl->SetIsFirstRun(true);
+ m_pImpl->SetIsOutsideAParagraph(false);
+}
+
+void DomainMapper::lcl_endParagraphGroup()
+{
+ if (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ if (m_pImpl->GetIsLastParagraphInSection())
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+ }
+
+ m_pImpl->PopProperties(CONTEXT_PARAGRAPH);
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().endParagraphGroup();
+ //frame conversion has to be executed after table conversion
+ m_pImpl->ExecuteFrameConversion();
+ m_pImpl->SetIsOutsideAParagraph(true);
+}
+
+void DomainMapper::markLastParagraphInSection( )
+{
+ m_pImpl->SetIsLastParagraphInSection( true );
+}
+
+void DomainMapper::markLastSectionGroup( )
+{
+ m_pImpl->SetIsLastSectionGroup( true );
+}
+
+void DomainMapper::lcl_startShape(uno::Reference<drawing::XShape> const& xShape)
+{
+ assert(xShape.is());
+
+ m_pImpl->AttachTextBoxContentToShape(xShape);
+ if (m_pImpl->GetTopContext())
+ {
+ // If there is a deferred page break, handle it now, so that the
+ // started shape will be on the correct page.
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(PAGE_BREAK);
+ lcl_startCharacterGroup();
+ sal_Unicode const sBreak[] = { 0x0d };
+ lcl_utext(sBreak, 1);
+ lcl_endCharacterGroup();
+ lcl_endParagraphGroup();
+ lcl_startParagraphGroup();
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ }
+ m_pImpl->PushShapeContext( xShape );
+ lcl_startParagraphGroup();
+ }
+ else
+ {
+ // No context? Then this image should not appear directly inside the
+ // document, just save it for later usage.
+ m_pImpl->PushPendingShape(xShape);
+ }
+
+ m_pImpl->SetIsFirstParagraphInShape(true);
+ mbWasShapeInPara = true;
+}
+
+void DomainMapper::lcl_endShape( )
+{
+ if (!m_pImpl->GetTopContext())
+ return;
+
+ // End the current table, if there are any. Otherwise the unavoidable
+ // empty paragraph at the end of the shape text will cause problems: if
+ // the shape text ends with a table, the extra paragraph will be
+ // handled as an additional row of the ending table.
+ if (m_pImpl->hasTableManager())
+ m_pImpl->getTableManager().endTable();
+
+ lcl_endParagraphGroup();
+ m_pImpl->PopShapeContext( );
+ // A shape is always inside a paragraph (anchored or inline).
+ m_pImpl->SetIsOutsideAParagraph(false);
+}
+
+void DomainMapper::lcl_startTextBoxContent()
+{
+ m_pImpl->PushTextBoxContent();
+}
+
+void DomainMapper::lcl_endTextBoxContent()
+{
+ m_pImpl->PopTextBoxContent();
+}
+
+void DomainMapper::PushStyleSheetProperties( const PropertyMapPtr& pStyleProperties, bool bAffectTableMngr )
+{
+ m_pImpl->PushStyleProperties( pStyleProperties );
+ if ( bAffectTableMngr )
+ m_pImpl->getTableManager( ).SetStyleProperties( pStyleProperties );
+}
+
+void DomainMapper::PopStyleSheetProperties( bool bAffectTableMngr )
+{
+ m_pImpl->PopProperties( CONTEXT_STYLESHEET );
+ if ( bAffectTableMngr )
+ {
+ PropertyMapPtr emptyPtr;
+ m_pImpl->getTableManager( ).SetStyleProperties( emptyPtr );
+ }
+}
+
+void DomainMapper::PushListProperties( const ::tools::SvRef<PropertyMap>& pListProperties )
+{
+ m_pImpl->PushListProperties( pListProperties );
+}
+
+void DomainMapper::PopListProperties()
+{
+ m_pImpl->PopProperties( CONTEXT_LIST );
+}
+
+void DomainMapper::lcl_startCharacterGroup()
+{
+ m_pImpl->PushProperties(CONTEXT_CHARACTER);
+ if (m_pImpl->isSdtEndDeferred())
+ {
+ // Fields have an empty character group before the real one, so don't
+ // call setSdtEndDeferred(false) here, that will happen only in lcl_utext().
+ m_pImpl->GetTopContext()->Insert(PROP_SDT_END_BEFORE, uno::Any(true), true, CHAR_GRAB_BAG);
+ }
+}
+
+void DomainMapper::lcl_endCharacterGroup()
+{
+ if (m_pImpl->CheckFootnoteStyle())
+ {
+ m_pImpl->SetCheckFootnoteStyle(m_pImpl->IsInCustomFootnote());
+ m_pImpl->SetHasFootnoteStyle(false);
+ }
+ m_pImpl->PopProperties(CONTEXT_CHARACTER);
+}
+
+//copied from rtfsprm
+/// Is it problematic to deduplicate this SPRM?
+static bool isSPRMDeduplicateDenylist(PropertyIds nId, PropertyMapPtr pContext)
+{
+ switch (nId)
+ {
+ // See the NS_ooxml::LN_CT_PPrBase_tabs handler in DomainMapper,
+ // deduplication is explicitly not wanted for these tokens.
+ case PROP_PARA_TAB_STOPS:
+ case PROP_PARA_LINE_SPACING:
+ return true;
+ case PROP_TOP_BORDER:
+ case PROP_LEFT_BORDER:
+ case PROP_BOTTOM_BORDER:
+ case PROP_RIGHT_BORDER:
+ case META_PROP_HORIZONTAL_BORDER:
+ case META_PROP_VERTICAL_BORDER:
+ 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 PROP_PARA_FIRST_LINE_INDENT:
+ case PROP_PARA_LEFT_MARGIN:
+ return pContext && pContext->getProperty(PROP_NUMBERING_RULES);
+
+ default:
+ return false;
+ }
+}
+
+void DomainMapper::lcl_text(const sal_uInt8 * data_, size_t len)
+{
+ //TODO: Determine the right text encoding (FIB?)
+ OUString sText( reinterpret_cast<const char*>(data_), len, RTL_TEXTENCODING_MS_1252 );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("text");
+ TagLogger::getInstance().chars(sText);
+ TagLogger::getInstance().endElement();
+#endif
+
+ try
+ {
+ if(len == 1)
+ {
+ switch(*data_)
+ {
+ case 0x02: return; //footnote character
+ case 0x08: // Lock field if in field context
+ if (m_pImpl->IsOpenField())
+ m_pImpl->SetFieldLocked();
+ return;
+ case 0x0c: //page break
+ // page breaks aren't supported in footnotes and endnotes
+ if (!m_pImpl->IsInFootOrEndnote())
+ m_pImpl->deferBreak(PAGE_BREAK);
+ return;
+ case 0x0e: //column break
+ m_pImpl->deferBreak(COLUMN_BREAK);
+ return;
+ case 0x0a: //line break
+ if (m_pImpl->GetIsLastParagraphInSection())
+ {
+ m_pImpl->deferBreak(LINE_BREAK);
+ return;
+ }
+ break;
+ case 0x07:
+ m_pImpl->getTableManager().text(data_, len);
+ return;
+ case 0x0d:
+ {
+ assert(!"paragraph break is handled by utext() now");
+ return;
+ }
+ case cFieldStart:
+ m_pImpl->PushFieldContext();
+ return;
+ case cFieldSep:
+ // delimiter not necessarily available
+ // appears only if field contains further content
+ m_pImpl->CloseFieldCommand();
+ return;
+ case cFieldEnd:
+ m_pImpl->PopFieldContext();
+ return;
+ default:
+ break;
+ }
+ }
+
+ // GetTopContext() is changed by inserted breaks, but we want to keep the current context
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", pContext);
+ }
+
+ if (!m_pImpl->GetFootnoteContext() && !m_pImpl->IsInShape() && !m_pImpl->IsInComments())
+ {
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+
+ if (pContext && pContext->GetFootnote().is() && m_pImpl->IsInCustomFootnote())
+ {
+ pContext->GetFootnote()->setLabel(sText);
+ m_pImpl->EndCustomFootnote();
+ //otherwise ignore sText
+ }
+ else if (m_pImpl->IsOpenFieldCommand() && !m_pImpl->IsForceGenericFields())
+ {
+ m_pImpl->AppendFieldCommand(sText);
+ }
+ else if( m_pImpl->IsOpenField() && m_pImpl->IsFieldResultAsString())
+ /*depending on the success of the field insert operation this result will be
+ set at the field or directly inserted into the text*/
+ m_pImpl->AppendFieldResult(sText);
+ else
+ {
+ if (pContext == nullptr)
+ pContext = new PropertyMap();
+
+ if (sText == "\n")
+ {
+ m_pImpl->HandleLineBreak(pContext);
+ }
+ else
+ {
+ m_pImpl->appendTextPortion(sText, pContext);
+ }
+ }
+ }
+ catch( const uno::RuntimeException& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "");
+ }
+}
+
+void DomainMapper::lcl_positionOffset(const OUString& rText, bool bVertical)
+{
+ if (bVertical)
+ m_pImpl->m_aPositionOffsets.second = rText;
+ else
+ m_pImpl->m_aPositionOffsets.first = rText;
+}
+
+awt::Point DomainMapper::getPositionOffset()
+{
+ awt::Point aRet;
+ aRet.X = oox::drawingml::convertEmuToHmm(m_pImpl->m_aPositionOffsets.first.toInt32());
+ aRet.Y = oox::drawingml::convertEmuToHmm(m_pImpl->m_aPositionOffsets.second.toInt32());
+ return aRet;
+}
+
+void DomainMapper::lcl_align(const OUString& rText, bool bVertical)
+{
+ if (bVertical)
+ m_pImpl->m_aAligns.second = rText;
+ else
+ m_pImpl->m_aAligns.first = rText;
+}
+
+void DomainMapper::lcl_positivePercentage(const OUString& rText)
+{
+ m_pImpl->m_aPositivePercentages.push(rText);
+}
+
+void DomainMapper::lcl_checkId(const sal_Int32 nId)
+{
+ if (m_pImpl->IsInFootnote())
+ {
+ m_pImpl->m_aFootnoteIds.push_back(nId);
+ // keep only the first real footnote
+ if (m_pImpl->GetFootnoteCount() == -1 && m_pImpl->m_aFootnoteIds.size() == 2)
+ m_pImpl->m_aFootnoteIds.pop_front();
+ }
+ else
+ {
+ m_pImpl->m_aEndnoteIds.push_back(nId);
+ // keep only the first real endnote
+ if (m_pImpl->GetEndnoteCount() == -1 && m_pImpl->m_aEndnoteIds.size() == 2)
+ m_pImpl->m_aEndnoteIds.pop_front();
+ }
+}
+
+void DomainMapper::ResetStyleProperties()
+{
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (IsRTFImport() && pContext)
+ {
+ //reset paragraph style properties not repeated at the paragraph
+ std::optional<PropertyMap::Property> paraStyleName = pContext->getProperty(PROP_PARA_STYLE_NAME);
+ if (paraStyleName.has_value()) {
+ OUString uStyleName;
+ paraStyleName->second >>= uStyleName;
+ StyleSheetEntryPtr pStyleSheet = m_pImpl->GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(uStyleName);
+ if (pStyleSheet != nullptr)
+ {
+ std::vector< PropertyIds > stylePropertyIds = pStyleSheet->m_pProperties->GetPropertyIds();
+ std::vector< PropertyIds >::iterator stylePropertyIdsIt = stylePropertyIds.begin();
+ while (stylePropertyIdsIt != stylePropertyIds.end())
+ {
+ PropertyIds ePropertyId = *stylePropertyIdsIt;
+ std::optional< PropertyMap::Property > styleProperty = pStyleSheet->m_pProperties->getProperty(ePropertyId);
+ std::optional< PropertyMap::Property > paragraphProperty = pContext->getProperty(ePropertyId);
+ if (paragraphProperty.has_value()) {
+ if (paragraphProperty->second == styleProperty->second &&
+ !isSPRMDeduplicateDenylist(ePropertyId, pContext))
+ {
+ pContext->Erase(ePropertyId);
+ }
+ }
+ else
+ {
+ switch (ePropertyId)
+ {
+ case PROP_PARA_LEFT_MARGIN:
+ if (!pContext->getProperty(PROP_NUMBERING_RULES))
+ {
+ pContext->Insert(ePropertyId, uno::Any(0l));
+ }
+ break;
+ case PROP_PARA_RIGHT_MARGIN:
+ pContext->Insert(ePropertyId, uno::Any(0l));
+ break;
+ case PROP_PARA_LAST_LINE_ADJUST:
+ case PROP_PARA_ADJUST:
+ pContext->Insert(ePropertyId, uno::Any(style::ParagraphAdjust_LEFT));
+ break;
+ case PROP_PARA_TAB_STOPS:
+ pContext->Insert(ePropertyId, uno::Any(uno::Sequence< style::TabStop >()));
+ break;
+ case PROP_FILL_STYLE:
+ pContext->Insert(ePropertyId, uno::Any(drawing::FillStyle_NONE));
+ break;
+ case PROP_FILL_COLOR:
+ pContext->Insert(ePropertyId, uno::Any(sal_Int32(COL_TRANSPARENT)));
+ break;
+ case INVALID:
+ default:
+ break;
+ }
+ }
+ ++stylePropertyIdsIt;
+ }
+ }
+ }
+ }
+}
+
+void DomainMapper::lcl_utext(const sal_Unicode *const 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 const sText(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 (sText[0] == 0x0d)
+ {
+ ResetStyleProperties();
+ }
+
+ // preload all footnotes in separated footnotes
+ if (sText[0] == 0x5)
+ {
+ if (m_pImpl->IsInFootnote())
+ {
+ if (m_pImpl->GetFootnoteCount() > -1)
+ {
+ m_pImpl->PopFootOrEndnote();
+ m_pImpl->PushFootOrEndnote(/*bIsFootnote=*/true);
+ }
+ m_pImpl->IncrementFootnoteCount();
+ }
+ else
+ {
+ if (m_pImpl->GetEndnoteCount() > -1)
+ {
+ m_pImpl->PopFootOrEndnote();
+ m_pImpl->PushFootOrEndnote(/*bIsFootnote=*/false);
+ }
+ m_pImpl->IncrementEndnoteCount();
+ }
+ }
+
+ // If the footnote contains a Footnote Reference Mark, it can't be a custom footnote
+ // ******
+ // This code block is wrong, as it should also be in m_pImpl->IsInFootOrEndnote().
+ // The main problem is that
+ //
+ // assert(len != 1 || sText[0] != 0x2)
+ //
+ // is triggered by the unit test SwLayoutWriter::testForcepoint75, so all these pseudo
+ // value handling is broken.
+ // But this is just a symptom, as I guess it's possible to generate broken DOCX documents,
+ // which might be problematic, triggering *funny* code paths left and right.
+ // ******
+ if (sText[0] == 0x2)
+ {
+ m_pImpl->EndCustomFootnote();
+ return;
+ }
+
+ if (m_pImpl->IsInCustomFootnote())
+ {
+ if (sText[0] != 0xd && sText[0] != 0x3)
+ {
+ // DOCX can have different labels for the footnote reference and the footnote area.
+ // This skips the one from the footnote area and just uses the reference one.
+ if (!m_pImpl->IsInFootOrEndnote())
+ {
+ if (PropertyMapPtr pFootnoteContext = m_pImpl->GetFootnoteContext())
+ {
+ auto xFootnote = pFootnoteContext->GetFootnote();
+ xFootnote->setLabel(xFootnote->getLabel() + sText);
+ }
+ }
+ return;
+ }
+ else
+ m_pImpl->SetHasFootnoteStyle(true);
+ }
+ }
+
+ if (m_pImpl->isSdtEndDeferred())
+ {
+ // In case we have a field context, then save the property there, so
+ // SDT's ending right before a field start are handled as well.
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+ if (m_pImpl->IsOpenField())
+ pContext = m_pImpl->GetTopFieldContext()->getProperties();
+ pContext->Insert(PROP_SDT_END_BEFORE, uno::Any(true), true, CHAR_GRAB_BAG);
+ m_pImpl->setSdtEndDeferred(false);
+ }
+
+ bool bNewLine = len == 1 && (sText[0] == 0x0d || sText[0] == 0x07);
+ if (m_pImpl->GetSdtStarts().empty()
+ && (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::dropDown
+ || m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::comboBox))
+ {
+ // Block, cell or row SDT.
+ if (bNewLine)
+ // Dropdown control has single-line texts, so in case of newline, create the control.
+ m_pImpl->m_pSdtHelper->createDropDownControl();
+ else
+ {
+ m_pImpl->m_pSdtHelper->getSdtTexts().append(sText);
+ return;
+ }
+ }
+ else if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ {
+ if (IsInHeaderFooter() && m_pImpl->IsDiscardHeaderFooter())
+ {
+ m_pImpl->m_pSdtHelper->getDateFormat().truncate();
+ m_pImpl->m_pSdtHelper->getLocale().truncate();
+ return;
+ }
+ }
+ else if (m_pImpl->m_pSdtHelper->GetSdtType() != NS_ooxml::LN_CT_SdtRun_sdtContent && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ if (bNewLine)
+ {
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ finishParagraph();
+ return;
+ }
+ }
+ else if (!m_pImpl->m_pSdtHelper->isInteropGrabBagEmpty())
+ {
+ // there are unsupported SDT properties in the document
+ // save them in the paragraph interop grab bag
+ if (m_pImpl->IsDiscardHeaderFooter())
+ {
+ // Unless we're supposed to ignore this header/footer.
+ m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ return;
+ }
+ if((m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_checkbox") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_text") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_dataBinding") ||
+ m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_citation") ||
+ (m_pImpl->m_pSdtHelper->containedInInteropGrabBag("ooxml:CT_SdtPr_id") &&
+ m_pImpl->m_pSdtHelper->getInteropGrabBagSize() == 1)) && !m_pImpl->m_pSdtHelper->isOutsideAParagraph())
+ {
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_CHARACTER);
+
+ if (m_pImpl->IsOpenField())
+ // We have a field, insert the SDT properties to the field's grab-bag, so they won't be lost.
+ pContext = m_pImpl->GetTopFieldContext()->getProperties();
+
+ uno::Sequence<beans::PropertyValue> aGrabBag = m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ if (m_pImpl->GetSdtStarts().empty()
+ || (m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::dropDown
+ && m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::comboBox))
+ {
+ pContext->Insert(PROP_SDTPR, uno::Any(aGrabBag), true, CHAR_GRAB_BAG);
+ }
+ }
+ else
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag = m_pImpl->m_pSdtHelper->getInteropGrabBagAndClear();
+ if (m_pImpl->GetSdtStarts().empty()
+ || (m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::dropDown
+ && m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::comboBox
+ && m_pImpl->m_pSdtHelper->getControlType() != SdtControlType::richText))
+ {
+ m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)->Insert(PROP_SDTPR,
+ uno::Any(aGrabBag), true, PARA_GRAB_BAG);
+ }
+ }
+ }
+ else if (len == 1 && sText[0] == 0x03)
+ {
+ // This is the uFtnEdnSep, remember that the document has a separator.
+ m_pImpl->m_bHasFtnSep = true;
+ return;
+ }
+ else if (len == 1 && sText[0] == '\r')
+ {
+ // Clear "last" one linebreak at end of section
+ if (m_pImpl->GetIsLastParagraphInSection() && m_pImpl->isBreakDeferred(LINE_BREAK))
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ // And emit all other linebreaks
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+ }
+ else if (len == 1 && sText[0] == '\t' )
+ {
+ if (m_pImpl->m_StreamStateStack.top().bCheckFirstFootnoteTab && m_pImpl->IsInFootOrEndnote())
+ {
+ // Allow MSO to emulate LO footnote text starting at left margin - only meaningful with hanging indent
+ m_pImpl->m_StreamStateStack.top().bCheckFirstFootnoteTab = false;
+ sal_Int32 nFirstLineIndent = 0;
+ m_pImpl->GetAnyProperty(PROP_PARA_FIRST_LINE_INDENT, m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH)) >>= nFirstLineIndent;
+ if ( nFirstLineIndent < 0 )
+ {
+ return;
+ }
+ }
+ }
+ if (!m_pImpl->hasTableManager())
+ return;
+
+ SkipFootnoteSeparator eSkip = m_pImpl->GetSkipFootnoteState();
+ if ( eSkip == SkipFootnoteSeparator::ON || eSkip == SkipFootnoteSeparator::SKIPPING )
+ {
+ m_pImpl->SetSkipFootnoteState( SkipFootnoteSeparator::SKIPPING );
+ return;
+ }
+
+ try
+ {
+ while (m_pImpl->isBreakDeferred(LINE_BREAK))
+ {
+ m_pImpl->clearDeferredBreak(LINE_BREAK);
+ m_pImpl->appendTextPortion("\n", m_pImpl->GetTopContext());
+ }
+
+ m_pImpl->getTableManager().utext(data_, len);
+
+ if (bNewLine)
+ {
+ const bool bSingleParagraph = m_pImpl->GetIsFirstParagraphInSection() && m_pImpl->GetIsLastParagraphInSection();
+ const bool bSingleParagraphAfterRedline = m_pImpl->GetIsFirstParagraphInSection(/*bAfterRedline=*/true) &&
+ m_pImpl->GetIsLastParagraphInSection();
+ PropertyMapPtr pContext = m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (!m_pImpl->GetFootnoteContext() && !m_pImpl->IsInShape() && !m_pImpl->IsInComments())
+ {
+ if (m_pImpl->isBreakDeferred(PAGE_BREAK))
+ {
+ assert(pContext); // can't have deferred break without
+ if (m_pImpl->GetSettingsTable()->GetSplitPgBreakAndParaMark())
+ {
+ if ( m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() )
+ {
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ else // IsFirstRun
+ {
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ }
+
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+ }
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ assert(pContext); // can't have deferred break without
+ if ( m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() )
+ {
+ mbIsSplitPara = true;
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ else // IsFirstRun
+ {
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ }
+
+ pContext->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ m_pImpl->clearDeferredBreaks();
+ }
+ }
+
+ // If the paragraph contains only the section properties and it has
+ // no runs, we should not create a paragraph for it in Writer, unless that would remove the whole section.
+ // Also do not remove here column breaks: they are treated in a different way and place.
+ bool bIsColumnBreak = false;
+ if (pContext && pContext->isSet(PROP_BREAK_TYPE))
+ {
+ const uno::Any aBreakType = pContext->getProperty(PROP_BREAK_TYPE)->second;
+ bIsColumnBreak =
+ aBreakType == style::BreakType_COLUMN_BEFORE ||
+ aBreakType == style::BreakType_COLUMN_AFTER ||
+ aBreakType == style::BreakType_COLUMN_BOTH;
+ }
+
+ bool bRemove = (!m_pImpl->GetParaChanged() && m_pImpl->GetRemoveThisPara()) ||
+ (!m_pImpl->GetParaChanged() && m_pImpl->GetParaSectpr()
+ && !bSingleParagraphAfterRedline
+ && !bIsColumnBreak
+ && !m_pImpl->GetIsLastSectionGroup() // testContSectionPageBreak
+ && !m_pImpl->GetParaHadField()
+ && !m_pImpl->GetIsPreviousParagraphFramed()
+ && !m_pImpl->HasTopAnchoredObjects()
+ && !m_pImpl->IsParaWithInlineObject());
+
+ const bool bNoNumbering = bRemove || (!m_pImpl->GetParaChanged() && m_pImpl->GetParaSectpr() && bSingleParagraph);
+ PropertyMapPtr xContext = bNoNumbering ? m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH) : PropertyMapPtr();
+ if (xContext)
+ {
+ // tdf#97417 delete numbering of the paragraph
+ // it will be deleted anyway, and the numbering would be copied
+ // to the next paragraph in sw SplitNode and then be applied to
+ // every following paragraph
+ xContext->Erase(PROP_NUMBERING_RULES);
+ static_cast<ParagraphPropertyMap*>(xContext.get())->props().SetListId(-1);;
+ xContext->Erase(PROP_NUMBERING_LEVEL);
+ }
+ finishParagraph(bRemove, bNoNumbering);
+
+ m_pImpl->SetParaSectpr(false);
+ }
+ else
+ {
+ // GetTopContext() is changed by inserted breaks, but we want to keep the current context
+ PropertyMapPtr pContext = m_pImpl->GetTopContext();
+ if (!m_pImpl->GetFootnoteContext() && !m_pImpl->IsInShape() && !m_pImpl->IsInComments())
+ {
+ auto pPara = static_cast<ParagraphPropertyMap*>(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH).get());
+ 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();
+ }
+ else // IsFirstRun
+ {
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pPara->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)), true);
+ }
+ }
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_PAGE_BEFORE));
+ }
+ else if (m_pImpl->isBreakDeferred(COLUMN_BREAK))
+ {
+ if (m_pImpl->GetIsFirstParagraphInSection() || !m_pImpl->IsFirstRun() || mbWasShapeInPara)
+ {
+ mbIsSplitPara = true;
+ m_pImpl->m_bIsSplitPara = true;
+ finishParagraph();
+ lcl_startParagraphGroup();
+ }
+ else // IsFirstRun
+ {
+ if (GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ {
+ pPara->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ }
+ }
+ m_pImpl->GetTopContext()->Insert(PROP_BREAK_TYPE, uno::Any(style::BreakType_COLUMN_BEFORE));
+ }
+ m_pImpl->clearDeferredBreaks();
+ }
+
+ bool bInSdtBlockText
+ = m_pImpl->m_pSdtHelper->GetSdtType() == NS_ooxml::LN_CT_SdtBlock_sdtContent
+ && m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::plainText;
+ if (pContext && pContext->GetFootnote().is())
+ {
+ pContext->GetFootnote()->setLabel( sText );
+ // tdf#141548 don't lose footnote/endnote text of the run with uFtnEdnRef
+ // (i.e. when footnoteRef/endnoteRef is followed by some text in the same run)
+ m_pImpl->appendTextPortion( sText, pContext );
+ }
+ else if (m_pImpl->IsOpenFieldCommand() && !m_pImpl->IsForceGenericFields())
+ {
+ if (bInSdtBlockText)
+ {
+ if (m_pImpl->m_pSdtHelper->hasUnusedText())
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ else if (!m_pImpl->m_pSdtHelper->isFieldStartRangeSet())
+ m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd());
+ }
+ m_pImpl->AppendFieldCommand(sText);
+ }
+ else if( m_pImpl->IsOpenField() && m_pImpl->IsFieldResultAsString())
+ {
+ if (bInSdtBlockText)
+ {
+ if (m_pImpl->m_pSdtHelper->hasUnusedText())
+ m_pImpl->m_pSdtHelper->createPlainTextControl();
+ else if (!m_pImpl->m_pSdtHelper->isFieldStartRangeSet())
+ m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd());
+ }
+ /*depending on the success of the field insert operation this result will be
+ set at the field or directly inserted into the text*/
+ m_pImpl->AppendFieldResult(sText);
+ }
+ else
+ {
+ if (pContext == nullptr)
+ pContext = new PropertyMap();
+
+ if (bInSdtBlockText && !m_pImpl->m_pSdtHelper->hasUnusedText())
+ m_pImpl->m_pSdtHelper->setFieldStartRange(GetCurrentTextRange()->getEnd());
+
+ m_pImpl->appendTextPortion( sText, pContext );
+
+ if (bInSdtBlockText && !sText.isEmpty())
+ m_pImpl->m_pSdtHelper->setHasUnusedText(true);
+ }
+
+ }
+ m_pImpl->SetIsFirstRun(false);
+ }
+ catch( const uno::RuntimeException& )
+ {
+ }
+}
+
+void DomainMapper::lcl_props(const writerfilter::Reference<Properties>::Pointer_t& ref)
+{
+ ref->resolve(*this);
+}
+
+void DomainMapper::lcl_table(Id name, const writerfilter::Reference<Table>::Pointer_t& ref)
+{
+ m_pImpl->SetAnyTableImport(true);
+ switch(name)
+ {
+ case NS_ooxml::LN_FONTTABLE:
+
+ // create a font table object that listens to the attributes
+ // each entry call inserts a new font entry
+ ref->resolve( *m_pImpl->GetFontTable() );
+ break;
+ case NS_ooxml::LN_STYLESHEET:
+ //same as above to import style sheets
+ m_pImpl->SetStyleSheetImport( true );
+ ref->resolve( *m_pImpl->GetStyleSheetTable() );
+ m_pImpl->GetStyleSheetTable()->ApplyStyleSheets(m_pImpl->GetFontTable());
+ m_pImpl->SetStyleSheetImport( false );
+ break;
+ case NS_ooxml::LN_NUMBERING:
+ {
+ m_pImpl->SetNumberingImport(true);
+ //the same for list tables
+ ref->resolve( *m_pImpl->GetListTable() );
+ m_pImpl->GetListTable( )->CreateNumberingRules( );
+ m_pImpl->SetNumberingImport(false);
+ }
+ break;
+ case NS_ooxml::LN_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, const writerfilter::Reference<Stream>::Pointer_t& ref)
+{
+ m_pImpl->substream(rName, ref);
+}
+
+void DomainMapper::lcl_startGlossaryEntry()
+{
+ uno::Reference< text::XTextRange > xTextRange = GetCurrentTextRange();
+ m_pImpl->setGlossaryEntryStart(xTextRange);
+}
+
+void DomainMapper::lcl_endGlossaryEntry()
+{
+ m_pImpl->appendGlossaryEntry();
+}
+
+void DomainMapper::handleUnderlineType(const Id nId, const ::tools::SvRef<PropertyMap>& rContext)
+{
+ sal_Int16 nUnderline = awt::FontUnderline::NONE;
+
+ switch (nId)
+ {
+ case NS_ooxml::LN_Value_ST_Underline_none:
+ nUnderline = awt::FontUnderline::NONE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_words:
+ rContext->Insert(PROP_CHAR_WORD_MODE, uno::Any(true));
+ [[fallthrough]];
+ case NS_ooxml::LN_Value_ST_Underline_single:
+ nUnderline = awt::FontUnderline::SINGLE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_double:
+ nUnderline = awt::FontUnderline::DOUBLE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dotted:
+ nUnderline = awt::FontUnderline::DOTTED;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dash:
+ nUnderline = awt::FontUnderline::DASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dotDash:
+ nUnderline = awt::FontUnderline::DASHDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dotDotDash:
+ nUnderline = awt::FontUnderline::DASHDOTDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_thick:
+ nUnderline = awt::FontUnderline::BOLD;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_wave:
+ nUnderline = awt::FontUnderline::WAVE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dottedHeavy:
+ nUnderline = awt::FontUnderline::BOLDDOTTED;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashedHeavy:
+ nUnderline = awt::FontUnderline::BOLDDASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashLong:
+ nUnderline = awt::FontUnderline::LONGDASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashLongHeavy:
+ nUnderline = awt::FontUnderline::BOLDLONGDASH;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashDotHeavy:
+ nUnderline = awt::FontUnderline::BOLDDASHDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy:
+ nUnderline = awt::FontUnderline::BOLDDASHDOTDOT;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_wavyHeavy:
+ nUnderline = awt::FontUnderline::BOLDWAVE;
+ break;
+ case NS_ooxml::LN_Value_ST_Underline_wavyDouble:
+ nUnderline = awt::FontUnderline::DOUBLEWAVE;
+ break;
+ }
+ rContext->Insert(PROP_CHAR_UNDERLINE, uno::Any(nUnderline));
+}
+
+void DomainMapper::handleParaJustification(const sal_Int32 nIntValue, const ::tools::SvRef<PropertyMap>& rContext, const bool bExchangeLeftRight)
+{
+ style::ParagraphAdjust nAdjust = style::ParagraphAdjust_LEFT;
+ style::ParagraphAdjust nLastLineAdjust = style::ParagraphAdjust_LEFT;
+ OUString aStringValue = "left";
+ switch(nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Jc_center:
+ nAdjust = style::ParagraphAdjust_CENTER;
+ aStringValue = "center";
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_right:
+ case NS_ooxml::LN_Value_ST_Jc_end:
+ nAdjust = bExchangeLeftRight ? style::ParagraphAdjust_LEFT : style::ParagraphAdjust_RIGHT;
+ aStringValue = "right";
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_distribute:
+ nLastLineAdjust = style::ParagraphAdjust_BLOCK;
+ [[fallthrough]];
+ case NS_ooxml::LN_Value_ST_Jc_both:
+ nAdjust = style::ParagraphAdjust_BLOCK;
+ aStringValue = "both";
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_left:
+ case NS_ooxml::LN_Value_ST_Jc_start:
+ default:
+ nAdjust = bExchangeLeftRight ? style::ParagraphAdjust_RIGHT : style::ParagraphAdjust_LEFT;
+ break;
+ }
+ rContext->Insert( PROP_PARA_ADJUST, uno::Any( nAdjust ) );
+ rContext->Insert( PROP_PARA_LAST_LINE_ADJUST, uno::Any( nLastLineAdjust ) );
+ m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, "jc", aStringValue);
+}
+
+bool DomainMapper::getColorFromId(const Id nId, sal_Int32 &nColor)
+{
+ nColor = 0;
+ if ((nId < NS_ooxml::LN_Value_ST_HighlightColor_black) || (nId > NS_ooxml::LN_Value_ST_HighlightColor_none))
+ return false;
+
+ switch (nId)
+ {
+ case NS_ooxml::LN_Value_ST_HighlightColor_black: nColor=0x000000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_blue: nColor=0x0000ff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_cyan: nColor=0x00ffff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_green: nColor=0x00ff00; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_magenta: nColor=0xff00ff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_red: nColor=0xff0000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_yellow: nColor=0xffff00; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_white: nColor=0xffffff; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkBlue: nColor=0x000080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkCyan: nColor=0x008080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkGreen: nColor=0x008000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkMagenta: nColor=0x800080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkRed: nColor=0x800000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkYellow: nColor=0x808000; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_darkGray: nColor=0x808080; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_lightGray: nColor=0xC0C0C0; break;
+ case NS_ooxml::LN_Value_ST_HighlightColor_none: nColor=0xFFFFFFFF; break; //COL_AUTO
+ default:
+ return false;
+ }
+ return true;
+}
+
+sal_Int16 DomainMapper::getEmphasisValue(const sal_Int32 nIntValue)
+{
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Em_dot:
+ return text::FontEmphasis::DOT_ABOVE;
+ case NS_ooxml::LN_Value_ST_Em_comma:
+ return text::FontEmphasis::ACCENT_ABOVE;
+ case NS_ooxml::LN_Value_ST_Em_circle:
+ return text::FontEmphasis::CIRCLE_ABOVE;
+ case NS_ooxml::LN_Value_ST_Em_underDot:
+ return text::FontEmphasis::DOT_BELOW;
+ default:
+ return text::FontEmphasis::NONE;
+ }
+}
+
+OUString DomainMapper::getBracketStringFromEnum(const sal_Int32 nIntValue, const bool bIsPrefix)
+{
+ switch(nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_CombineBrackets_round:
+ if (bIsPrefix)
+ return "(";
+ return ")";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_square:
+ if (bIsPrefix)
+ return "[";
+ return "]";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_angle:
+ if (bIsPrefix)
+ return "<";
+ return ">";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_curly:
+ if (bIsPrefix)
+ return "{";
+ return "}";
+
+ case NS_ooxml::LN_Value_ST_CombineBrackets_none:
+ default:
+ return OUString();
+ }
+}
+
+style::TabAlign DomainMapper::getTabAlignFromValue(const sal_Int32 nIntValue)
+{
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TabJc_start:
+ case NS_ooxml::LN_Value_ST_TabJc_left:
+ case NS_ooxml::LN_Value_ST_TabJc_bar: // bar not supported
+ case NS_ooxml::LN_Value_ST_TabJc_num: // num not supported
+ return style::TabAlign_LEFT;
+ case NS_ooxml::LN_Value_ST_TabJc_center:
+ return style::TabAlign_CENTER;
+ case NS_ooxml::LN_Value_ST_TabJc_end:
+ case NS_ooxml::LN_Value_ST_TabJc_right:
+ return style::TabAlign_RIGHT;
+ case NS_ooxml::LN_Value_ST_TabJc_decimal:
+ return style::TabAlign_DECIMAL;
+ }
+ return style::TabAlign_LEFT;
+}
+
+sal_Unicode DomainMapper::getFillCharFromValue(const sal_Int32 nIntValue)
+{
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_TabTlc_dot:
+ return u'.';
+ case NS_ooxml::LN_Value_ST_TabTlc_hyphen:
+ return u'-';
+ case NS_ooxml::LN_Value_ST_TabTlc_underscore:
+ case NS_ooxml::LN_Value_ST_TabTlc_heavy: // FIXME ???
+ return u'_';
+ case NS_ooxml::LN_Value_ST_TabTlc_middleDot: // middleDot
+ return u'\x00b7';
+ case NS_ooxml::LN_Value_ST_TabTlc_none:
+ default:
+ return u' '; // blank space
+ }
+}
+
+bool DomainMapper::IsOOXMLImport() const
+{
+ return m_pImpl->IsOOXMLImport();
+}
+
+bool DomainMapper::IsRTFImport() const
+{
+ return m_pImpl->IsRTFImport();
+}
+
+uno::Reference < lang::XMultiServiceFactory > const & DomainMapper::GetTextFactory() const
+{
+ return m_pImpl->GetTextFactory();
+}
+
+uno::Reference< text::XTextRange > DomainMapper::GetCurrentTextRange()
+{
+ if (m_pImpl->HasTopText())
+ return m_pImpl->GetTopTextAppend()->getEnd();
+ return m_pImpl->m_xInsertTextRange;
+}
+
+OUString DomainMapper::getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate )
+{
+ StyleSheetTablePtr pStyleSheets = m_pImpl->GetStyleSheetTable();
+ return pStyleSheets->getOrCreateCharStyle( rCharProperties, bAlwaysCreate );
+}
+
+StyleSheetTablePtr const & DomainMapper::GetStyleSheetTable( )
+{
+ return m_pImpl->GetStyleSheetTable( );
+}
+
+SettingsTablePtr const & DomainMapper::GetSettingsTable()
+{
+ return m_pImpl->GetSettingsTable();
+}
+
+GraphicZOrderHelper& DomainMapper::graphicZOrderHelper()
+{
+ if (m_zOrderHelper == nullptr)
+ m_zOrderHelper.reset( new GraphicZOrderHelper );
+ return *m_zOrderHelper;
+}
+
+uno::Reference<drawing::XShape> DomainMapper::PopPendingShape()
+{
+ return m_pImpl->PopPendingShape();
+}
+
+bool DomainMapper::IsInHeaderFooter() const
+{
+ return m_pImpl->IsInHeaderFooter();
+}
+
+bool DomainMapper::IsInShape() const { return m_pImpl->IsInShape(); }
+
+bool DomainMapper::IsInTable() const
+{
+ return m_pImpl->hasTableManager() && m_pImpl->getTableManager().isInCell();
+}
+
+OUString DomainMapper::GetListStyleName(sal_Int32 nListId) const
+{
+ return m_pImpl->GetListStyleName( nListId );
+}
+
+void DomainMapper::ValidateListLevel(const OUString& sStyleIdentifierD)
+{
+ m_pImpl->ValidateListLevel(sStyleIdentifierD);
+}
+
+void DomainMapper::SetDocDefaultsImport(bool bSet)
+{
+ m_pImpl->SetDocDefaultsImport(bSet);
+}
+
+bool DomainMapper::IsStyleSheetImport() const
+{
+ return m_pImpl->IsStyleSheetImport();
+}
+
+bool DomainMapper::IsNumberingImport() const
+{
+ return m_pImpl->IsNumberingImport();
+}
+
+void DomainMapper::enableInteropGrabBag(const OUString& aName)
+{
+ m_pImpl->m_aInteropGrabBagName = aName;
+}
+
+beans::PropertyValue DomainMapper::getInteropGrabBag()
+{
+ beans::PropertyValue aRet;
+ aRet.Name = m_pImpl->m_aInteropGrabBagName;
+ aRet.Value <<= comphelper::containerToSequence(m_pImpl->m_aInteropGrabBag);
+
+ m_pImpl->m_aInteropGrabBag.clear();
+ m_pImpl->m_aInteropGrabBagName.clear();
+ return aRet;
+}
+
+void DomainMapper::HandleRedline( Sprm& rSprm )
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ m_pImpl->AddNewRedline( nSprmId );
+
+ if (nSprmId == NS_ooxml::LN_CT_PPr_pPrChange)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_ParagraphFormat);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TrPr_ins)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableRowInsert);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TrPr_del)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableRowDelete);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TcPrBase_cellIns)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableCellInsert);
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_TcPrBase_cellDel)
+ {
+ m_pImpl->SetCurrentRedlineToken(XML_tableCellDelete);
+ }
+
+ resolveSprmProps(*this, rSprm );
+ // now the properties author, date and id should be available
+ sal_Int32 nToken = m_pImpl->GetCurrentRedlineToken();
+ switch( nToken & 0xffff )
+ {
+ case XML_mod:
+ case XML_ins:
+ case XML_del:
+ case XML_moveTo:
+ case XML_moveFrom:
+ case XML_ParagraphFormat:
+ case XML_tableRowInsert:
+ case XML_tableRowDelete:
+ case XML_tableCellInsert:
+ case XML_tableCellDelete:
+ break;
+ default: OSL_FAIL( "redline token other than mod, ins, del, moveTo, moveFrom or table row" ); break;
+ }
+ m_pImpl->EndParaMarkerChange( );
+ m_pImpl->SetCurrentRedlineIsRead();
+}
+
+void DomainMapper::finishParagraph(const bool bRemove, const bool bNoNumbering)
+{
+ if (m_pImpl->m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ m_pImpl->m_pSdtHelper->createDateContentControl();
+ m_pImpl->finishParagraph(m_pImpl->GetTopContextOfType(CONTEXT_PARAGRAPH), bRemove, bNoNumbering);
+ if (bRemove || mbIsLastPara)
+ m_pImpl->RemoveLastParagraph();
+ mbIsLastPara = false; // handle other subdocuments
+}
+
+void DomainMapper::commentProps(const OUString& sId, const CommentProperties& rProps)
+{
+ m_pImpl->commentProps(sId, rProps);
+}
+
+css::uno::Reference<css::container::XNameContainer> const & DomainMapper::GetCharacterStyles()
+{
+ return m_pImpl->GetCharacterStyles();
+}
+
+OUString DomainMapper::GetUnusedCharacterStyleName()
+{
+ return m_pImpl->GetUnusedCharacterStyleName();
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapper.hxx b/sw/source/writerfilter/dmapper/DomainMapper.hxx
new file mode 100644
index 000000000000..9d9771e640f5
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapper.hxx
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include "LoggedResources.hxx"
+#include "PropertyMap.hxx"
+#include "SettingsTable.hxx"
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/style/TabAlign.hpp>
+
+#include <map>
+#include <vector>
+#include <memory>
+
+namespace com::sun::star{
+ namespace beans{
+ struct PropertyValue;
+ }
+ namespace io{
+ class XInputStream;
+ }
+ namespace uno{
+ class XComponentContext;
+ }
+ namespace lang{
+ class XMultiServiceFactory;
+ }
+ namespace text{
+ class XTextRange;
+ }
+}
+
+namespace utl
+{
+class MediaDescriptor;
+}
+
+typedef std::vector<css::beans::PropertyValue> PropertyValueVector_t;
+
+namespace writerfilter::dmapper
+{
+
+class PropertyMap;
+class DomainMapper_Impl;
+class ListsManager;
+class StyleSheetTable;
+class GraphicZOrderHelper;
+
+typedef tools::SvRef<StyleSheetTable> StyleSheetTablePtr;
+
+class DomainMapper : public LoggedProperties, public LoggedTable,
+ public BinaryObj, public LoggedStream
+{
+ std::unique_ptr<DomainMapper_Impl> m_pImpl;
+
+public:
+ DomainMapper(const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xModel,
+ bool bRepairStorage,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc);
+ virtual ~DomainMapper() override;
+
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) override;
+
+ // Stream
+ virtual void markLastParagraphInSection() override;
+ virtual void markLastParagraph() override { mbIsLastPara = true; }
+ virtual void markLastSectionGroup() override;
+
+ // BinaryObj
+ virtual void data(const sal_uInt8* buf, size_t len) override;
+
+ void sprmWithProps( Sprm& sprm, const PropertyMapPtr& pContext );
+
+ void PushStyleSheetProperties( const PropertyMapPtr& pStyleProperties, bool bAffectTableMngr = false );
+ void PopStyleSheetProperties( bool bAffectTableMngr = false );
+
+ void PushListProperties( const ::tools::SvRef<PropertyMap>& pListProperties );
+ void PopListProperties();
+ OUString GetListStyleName(sal_Int32 nListId) const;
+ void ValidateListLevel(const OUString& sStyleIdentifierD);
+
+ bool IsOOXMLImport() const;
+ bool IsRTFImport() const;
+ css::uno::Reference<css::lang::XMultiServiceFactory> const & GetTextFactory() const;
+ css::uno::Reference<css::text::XTextRange> GetCurrentTextRange();
+
+ OUString getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate );
+ StyleSheetTablePtr const & GetStyleSheetTable( );
+ SettingsTablePtr const & GetSettingsTable();
+ GraphicZOrderHelper& graphicZOrderHelper();
+
+ /// Return the first from the pending (not inserted to the document) shapes, if there are any.
+ css::uno::Reference<css::drawing::XShape> PopPendingShape();
+
+ bool IsInHeaderFooter() const;
+ bool IsInTable() const;
+ void SetDocDefaultsImport(bool bSet);
+ bool IsStyleSheetImport() const;
+ bool IsNumberingImport() const;
+ bool IsInShape() const;
+
+ void hasControls( const bool bSet ) { mbHasControls = bSet; }
+
+ /**
+ @see DomainMapper_Impl::processDeferredCharacterProperties()
+ */
+ void processDeferredCharacterProperties(
+ const std::map<sal_Int32, css::uno::Any>& rDeferredCharacterProperties,
+ bool bCharContext = true);
+
+ void ProcessDeferredStyleCharacterProperties();
+
+ /// Enable storing of seen tokens in a named grab bag.
+ void enableInteropGrabBag(const OUString& aName);
+ /// Get the stored tokens and clear the internal storage.
+ css::beans::PropertyValue getInteropGrabBag();
+
+ void HandleRedline( Sprm& rSprm );
+
+ virtual void commentProps(const OUString& sId, const CommentProperties& rProps) override;
+
+ css::uno::Reference<css::container::XNameContainer> const & GetCharacterStyles();
+ OUString GetUnusedCharacterStyleName();
+
+private:
+ // Stream
+ virtual void lcl_startSectionGroup() override;
+ virtual void lcl_endSectionGroup() override;
+ virtual void lcl_startParagraphGroup() override;
+ virtual void lcl_endParagraphGroup() override;
+ virtual void lcl_startCharacterGroup() override;
+ virtual void lcl_endCharacterGroup() override;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ virtual void lcl_endShape( ) override;
+ virtual void lcl_startTextBoxContent() override;
+ virtual void lcl_endTextBoxContent() override;
+ virtual void lcl_text(const sal_uInt8 * data, size_t len) override;
+ virtual void lcl_utext(const sal_Unicode * 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(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+ virtual void lcl_table(Id name,
+ const writerfilter::Reference<Table>::Pointer_t& ref) override;
+ virtual void lcl_substream(Id name,
+ const writerfilter::Reference<Stream>::Pointer_t& ref) override;
+ virtual void lcl_startGlossaryEntry() override;
+ virtual void lcl_endGlossaryEntry() override;
+ virtual void lcl_checkId(const sal_Int32 nId) override;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+
+ void ResetStyleProperties();
+ void finishParagraph(const bool bRemove = false, const bool bNoNumbering = false);
+
+ static void handleUnderlineType(const Id nId, const ::tools::SvRef<PropertyMap>& rContext);
+ void handleParaJustification(const sal_Int32 nIntValue, const ::tools::SvRef<PropertyMap>& rContext, const bool bExchangeLeftRight);
+ static bool getColorFromId(const Id, sal_Int32 &nColor);
+ static sal_Int16 getEmphasisValue(const sal_Int32 nIntValue);
+ static OUString getBracketStringFromEnum(const sal_Int32 nIntValue, const bool bIsPrefix = true);
+ static css::style::TabAlign getTabAlignFromValue(const sal_Int32 nIntValue);
+ static sal_Unicode getFillCharFromValue(const sal_Int32 nIntValue);
+ bool mbIsSplitPara;
+ bool mbHasControls;
+ bool mbWasShapeInPara;
+ bool mbIsLastPara = false;
+ std::unique_ptr< GraphicZOrderHelper > m_zOrderHelper;
+ OUString m_sGlossaryEntryName;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapperTableHandler.cxx b/sw/source/writerfilter/dmapper/DomainMapperTableHandler.cxx
new file mode 100644
index 000000000000..422d643cb7ba
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapperTableHandler.cxx
@@ -0,0 +1,1778 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "DomainMapperTableHandler.hxx"
+#include "DomainMapper_Impl.hxx"
+#include "StyleSheetTable.hxx"
+
+#include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
+#include <com/sun/star/beans/XTolerantMultiPropertySet.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/table/TableBorderDistances.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/table/BorderLineStyle.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/XTextRangeCompare.hpp>
+#include <com/sun/star/text/RelOrientation.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 <comphelper/diagnose_ex.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/style/BreakType.hpp>
+#include <officecfg/Office/Writer.hxx>
+
+#ifdef DBG_UTIL
+#include "PropertyMapHelper.hxx"
+#include <rtl/ustring.hxx>
+#include <utility>
+#endif
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+#define DEF_BORDER_DIST 190 //0,19cm
+#define CNF_FIRST_ROW 0x800
+#define CNF_LAST_ROW 0x400
+#define CNF_FIRST_COLUMN 0x200
+#define CNF_LAST_COLUMN 0x100
+#define CNF_ODD_VBAND 0x080
+#define CNF_EVEN_VBAND 0x040
+#define CNF_ODD_HBAND 0x020
+#define CNF_EVEN_HBAND 0x010
+#define CNF_FIRST_ROW_LAST_COLUMN 0x008
+#define CNF_FIRST_ROW_FIRST_COLUMN 0x004
+#define CNF_LAST_ROW_LAST_COLUMN 0x002
+#define CNF_LAST_ROW_FIRST_COLUMN 0x001
+#define CNF_ALL 0xFFF
+
+// total number of table columns
+#define MAXTABLECELLS 63
+
+DomainMapperTableHandler::DomainMapperTableHandler(
+ css::uno::Reference<css::text::XTextAppendAndConvert> xText,
+ DomainMapper_Impl& rDMapper_Impl)
+ : m_xText(std::move(xText)),
+ m_rDMapper_Impl( rDMapper_Impl )
+{
+}
+
+DomainMapperTableHandler::~DomainMapperTableHandler()
+{
+}
+
+void DomainMapperTableHandler::startTable(const TablePropertyMapPtr& pProps)
+{
+ m_aTableProperties = pProps;
+ m_aTableRanges.clear();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablehandler.table");
+
+ if (pProps)
+ pProps->dumpXml();
+#endif
+}
+
+static void lcl_mergeBorder( PropertyIds nId, const PropertyMapPtr& pOrig, const PropertyMapPtr& pDest )
+{
+ std::optional<PropertyMap::Property> pOrigVal = pOrig->getProperty(nId);
+
+ if ( pOrigVal )
+ {
+ pDest->Insert( nId, pOrigVal->second, false );
+ }
+}
+
+static void lcl_computeCellBorders( const PropertyMapPtr& pTableBorders, const PropertyMapPtr& pCellProps,
+ sal_uInt32 nCell, sal_uInt32 nFirstCell, sal_uInt32 nLastCell, sal_Int32 nRow, bool bIsEndRow, bool bMergedVertically )
+{
+ const bool bIsStartCol = nCell == nFirstCell;
+ const bool bIsEndCol = nCell == nLastCell;
+ std::optional<PropertyMap::Property> pVerticalVal = pCellProps->getProperty(META_PROP_VERTICAL_BORDER);
+ std::optional<PropertyMap::Property> pHorizontalVal = pCellProps->getProperty(META_PROP_HORIZONTAL_BORDER);
+
+ // Handle the vertical and horizontal borders
+ uno::Any aVertProp;
+ if ( !pVerticalVal)
+ {
+ pVerticalVal = pTableBorders->getProperty(META_PROP_VERTICAL_BORDER);
+ if ( pVerticalVal )
+ aVertProp = pVerticalVal->second;
+ }
+ else
+ {
+ aVertProp = pVerticalVal->second;
+ pCellProps->Erase( pVerticalVal->first );
+ }
+
+ uno::Any aHorizProp;
+ if ( !pHorizontalVal )
+ {
+ pHorizontalVal = pTableBorders->getProperty(META_PROP_HORIZONTAL_BORDER);
+ if ( pHorizontalVal )
+ aHorizProp = pHorizontalVal->second;
+ }
+ else
+ {
+ aHorizProp = pHorizontalVal->second;
+ pCellProps->Erase( pHorizontalVal->first );
+ }
+
+ if ( bIsStartCol )
+ lcl_mergeBorder( PROP_LEFT_BORDER, pTableBorders, pCellProps );
+
+ if ( bIsEndCol )
+ lcl_mergeBorder( PROP_RIGHT_BORDER, pTableBorders, pCellProps );
+
+ // <w:insideV> counts if there are multiple cells in this row.
+ if ( pVerticalVal )
+ {
+ if ( !bIsEndCol && nCell >= nFirstCell )
+ pCellProps->Insert( PROP_RIGHT_BORDER, aVertProp, false );
+ if ( !bIsStartCol && nCell <= nLastCell )
+ pCellProps->Insert( PROP_LEFT_BORDER, aVertProp, false );
+ }
+
+ if ( nRow == 0 )
+ {
+ lcl_mergeBorder( PROP_TOP_BORDER, pTableBorders, pCellProps );
+ if ( pHorizontalVal && !bMergedVertically )
+ pCellProps->Insert( PROP_BOTTOM_BORDER, aHorizProp, false );
+ }
+
+ if ( bMergedVertically )
+ lcl_mergeBorder( PROP_BOTTOM_BORDER, pTableBorders, pCellProps );
+
+ if ( bIsEndRow )
+ {
+ lcl_mergeBorder( PROP_BOTTOM_BORDER, pTableBorders, pCellProps );
+ if ( pHorizontalVal )
+ pCellProps->Insert( PROP_TOP_BORDER, aHorizProp, false );
+ }
+
+ if ( nRow > 0 && !bIsEndRow )
+ {
+ if ( pHorizontalVal )
+ {
+ pCellProps->Insert( PROP_TOP_BORDER, aHorizProp, false );
+ pCellProps->Insert( PROP_BOTTOM_BORDER, aHorizProp, false );
+ }
+ }
+}
+
+#ifdef DBG_UTIL
+
+static void lcl_debug_BorderLine(table::BorderLine const & rLine)
+{
+ TagLogger::getInstance().startElement("BorderLine");
+ TagLogger::getInstance().attribute("Color", rLine.Color);
+ TagLogger::getInstance().attribute("InnerLineWidth", rLine.InnerLineWidth);
+ TagLogger::getInstance().attribute("OuterLineWidth", rLine.OuterLineWidth);
+ TagLogger::getInstance().attribute("LineDistance", rLine.LineDistance);
+ TagLogger::getInstance().endElement();
+}
+
+static void lcl_debug_TableBorder(table::TableBorder const & rBorder)
+{
+ TagLogger::getInstance().startElement("TableBorder");
+ lcl_debug_BorderLine(rBorder.TopLine);
+ TagLogger::getInstance().attribute("IsTopLineValid", sal_uInt32(rBorder.IsTopLineValid));
+ lcl_debug_BorderLine(rBorder.BottomLine);
+ TagLogger::getInstance().attribute("IsBottomLineValid", sal_uInt32(rBorder.IsBottomLineValid));
+ lcl_debug_BorderLine(rBorder.LeftLine);
+ TagLogger::getInstance().attribute("IsLeftLineValid", sal_uInt32(rBorder.IsLeftLineValid));
+ lcl_debug_BorderLine(rBorder.RightLine);
+ TagLogger::getInstance().attribute("IsRightLineValid", sal_uInt32(rBorder.IsRightLineValid));
+ lcl_debug_BorderLine(rBorder.VerticalLine);
+ TagLogger::getInstance().attribute("IsVerticalLineValid", sal_uInt32(rBorder.IsVerticalLineValid));
+ lcl_debug_BorderLine(rBorder.HorizontalLine);
+ TagLogger::getInstance().attribute("IsHorizontalLineValid", sal_uInt32(rBorder.IsHorizontalLineValid));
+ TagLogger::getInstance().attribute("Distance", rBorder.Distance);
+ TagLogger::getInstance().attribute("IsDistanceValid", sal_uInt32(rBorder.IsDistanceValid));
+ TagLogger::getInstance().endElement();
+}
+#endif
+
+struct TableInfo
+{
+ sal_Int32 nLeftBorderDistance;
+ sal_Int32 nRightBorderDistance;
+ sal_Int32 nTopBorderDistance;
+ sal_Int32 nBottomBorderDistance;
+ sal_Int32 nTblLook;
+ sal_Int32 nNestLevel;
+ PropertyMapPtr pTableDefaults;
+ PropertyMapPtr pTableBorders;
+ TableStyleSheetEntry* pTableStyle;
+ css::beans::PropertyValues aTableProperties;
+ std::vector< PropertyIds > aTablePropertyIds;
+
+ TableInfo()
+ : nLeftBorderDistance(DEF_BORDER_DIST)
+ , nRightBorderDistance(DEF_BORDER_DIST)
+ , nTopBorderDistance(0)
+ , nBottomBorderDistance(0)
+ , nTblLook(0x4a0)
+ , nNestLevel(0)
+ , pTableDefaults(new PropertyMap)
+ , pTableBorders(new PropertyMap)
+ , pTableStyle(nullptr)
+ {
+ }
+
+};
+
+namespace
+{
+
+bool lcl_extractTableBorderProperty(const PropertyMapPtr& pTableProperties, const PropertyIds nId, TableInfo const & rInfo, table::BorderLine2& rLine)
+{
+ if (!pTableProperties)
+ return false;
+
+ const std::optional<PropertyMap::Property> aTblBorder = pTableProperties->getProperty(nId);
+ if( aTblBorder )
+ {
+ OSL_VERIFY(aTblBorder->second >>= rLine);
+
+ rInfo.pTableBorders->Insert( nId, uno::Any( rLine ) );
+ rInfo.pTableDefaults->Erase( nId );
+
+ return true;
+ }
+
+ return false;
+}
+
+void lcl_extractHoriOrient(std::vector<beans::PropertyValue>& rFrameProperties, sal_Int32& nHoriOrient)
+{
+ // Shifts the frame left by the given value.
+ for (const beans::PropertyValue & rFrameProperty : rFrameProperties)
+ {
+ if (rFrameProperty.Name == "HoriOrient")
+ {
+ sal_Int32 nValue = rFrameProperty.Value.get<sal_Int32>();
+ if (nValue != text::HoriOrientation::NONE)
+ nHoriOrient = nValue;
+ return;
+ }
+ }
+}
+
+void lcl_DecrementHoriOrientPosition(std::vector<beans::PropertyValue>& rFrameProperties, sal_Int32 nAmount)
+{
+ // Shifts the frame left by the given value.
+ for (beans::PropertyValue & rPropertyValue : rFrameProperties)
+ {
+ if (rPropertyValue.Name == "HoriOrientPosition")
+ {
+ sal_Int32 nValue = rPropertyValue.Value.get<sal_Int32>();
+ nValue -= nAmount;
+ rPropertyValue.Value <<= nValue;
+ return;
+ }
+ }
+}
+
+void lcl_adjustBorderDistance(TableInfo& rInfo, const table::BorderLine2& rLeftBorder,
+ const table::BorderLine2& rRightBorder)
+{
+ // MS Word appears to do these things to adjust the cell horizontal area:
+ //
+ // bll = left borderline width
+ // blr = right borderline width
+ // cea = cell's edit area rectangle
+ // cea_w = cea width
+ // cml = cell's left margin (padding) defined in cell settings
+ // cmr = cell's right margin (padding) defined in cell settings
+ // cw = cell width (distance between middles of left borderline and right borderline)
+ // pad_l = actual cea left padding = (its left pos relative to middle of bll)
+ // pad_r = actual cea right padding = abs (its right pos relative to middle of blr)
+ //
+ // pad_l = max(bll/2, cml) -> cea does not overlap left borderline
+ // cea_w = cw-max(pad_l+blr/2, cml+cmr) -> cea does not overlap right borderline
+ // pad_r = max(pad_l+blr/2, cml+cmr) - pad_l
+ //
+ // It means that e.g. for border widths of 6 pt (~2.12 mm), left margin 0 mm, and right margin
+ // 2 mm, actual left and right margins will (unexpectedly) coincide with inner edges of cell's
+ // borderlines - the right margin won't create spacing between right of edit rectangle and the
+ // inner edge of right borderline.
+
+ const sal_Int32 nActualL
+ = std::max<sal_Int32>(rLeftBorder.LineWidth / 2, rInfo.nLeftBorderDistance);
+ const sal_Int32 nActualR
+ = std::max<sal_Int32>(nActualL + rRightBorder.LineWidth / 2,
+ rInfo.nLeftBorderDistance + rInfo.nRightBorderDistance)
+ - nActualL;
+ rInfo.nLeftBorderDistance = nActualL;
+ rInfo.nRightBorderDistance = nActualR;
+}
+
+}
+
+TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo,
+ std::vector<beans::PropertyValue>& rFrameProperties,
+ bool bConvertToFloatingInFootnote)
+{
+ // will receive the table style if any
+ TableStyleSheetEntry* pTableStyle = nullptr;
+
+ if( m_aTableProperties )
+ {
+ //create properties from the table attributes
+ sal_Int32 nLeftMargin = 0;
+
+ comphelper::SequenceAsHashMap aGrabBag;
+
+ if (bConvertToFloatingInFootnote)
+ {
+ // define empty "TablePosition" to avoid export temporary floating
+ aGrabBag["TablePosition"] = uno::Any();
+ }
+
+ std::optional<PropertyMap::Property> aTableStyleVal = m_aTableProperties->getProperty(META_PROP_TABLE_STYLE_NAME);
+ if(aTableStyleVal)
+ {
+ // Apply table style properties recursively
+ OUString sTableStyleName;
+ aTableStyleVal->second >>= sTableStyleName;
+ StyleSheetTablePtr pStyleSheetTable = m_rDMapper_Impl.GetStyleSheetTable();
+ const StyleSheetEntryPtr pStyleSheet = pStyleSheetTable->FindStyleSheetByISTD( sTableStyleName );
+ pTableStyle = dynamic_cast<TableStyleSheetEntry*>( pStyleSheet.get( ) );
+ m_aTableProperties->Erase( aTableStyleVal->first );
+
+ aGrabBag["TableStyleName"] <<= sTableStyleName;
+
+ if( pStyleSheet )
+ {
+ // First get the style properties, then the table ones
+ PropertyMapPtr pTableProps( m_aTableProperties.get() );
+
+ m_aTableProperties = TablePropertyMapPtr(new TablePropertyMap);
+
+ PropertyMapPtr pMergedProperties = pStyleSheet->GetMergedInheritedProperties(pStyleSheetTable);
+
+ table::BorderLine2 aBorderLine;
+ TableInfo rStyleInfo;
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_TOP_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleTopBorder"] <<= aBorderLine;
+ }
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_BOTTOM_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleBottomBorder"] <<= aBorderLine;
+ }
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_LEFT_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleLeftBorder"] <<= aBorderLine;
+ }
+ if (lcl_extractTableBorderProperty(pMergedProperties, PROP_RIGHT_BORDER, rStyleInfo, aBorderLine))
+ {
+ aGrabBag["TableStyleRightBorder"] <<= aBorderLine;
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("mergedProps");
+ if (pMergedProperties)
+ pMergedProperties->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ m_aTableProperties->InsertProps(pMergedProperties);
+ m_aTableProperties->InsertProps(pTableProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TableProperties");
+ m_aTableProperties->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+ if (pTableStyle)
+ {
+ // apply tblHeader setting of the table style
+ PropertyMapPtr pHeaderStyleProps = pTableStyle->GetProperties(CNF_FIRST_ROW);
+ if ( pHeaderStyleProps->getProperty(PROP_HEADER_ROW_COUNT) )
+ m_aTableProperties->Insert(PROP_HEADER_ROW_COUNT, uno::Any( sal_Int32(1)), false);
+ }
+ }
+ }
+
+ // This is the one preserving just all the table look attributes.
+ std::optional<PropertyMap::Property> oTableLook = m_aTableProperties->getProperty(META_PROP_TABLE_LOOK);
+ if (oTableLook)
+ {
+ aGrabBag["TableStyleLook"] = oTableLook->second;
+ m_aTableProperties->Erase(oTableLook->first);
+ }
+
+ // This is just the "val" attribute's numeric value.
+ const std::optional<PropertyMap::Property> aTblLook = m_aTableProperties->getProperty(PROP_TBL_LOOK);
+ if(aTblLook)
+ {
+ aTblLook->second >>= rInfo.nTblLook;
+ m_aTableProperties->Erase( aTblLook->first );
+ }
+
+ // apply cell margin settings of the table style
+ const std::optional<PropertyMap::Property> oLeftMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_LEFT);
+ if (oLeftMargin)
+ {
+ oLeftMargin->second >>= rInfo.nLeftBorderDistance;
+ m_aTableProperties->Erase(oLeftMargin->first);
+ }
+ const std::optional<PropertyMap::Property> oRightMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_RIGHT);
+ if (oRightMargin)
+ {
+ oRightMargin->second >>= rInfo.nRightBorderDistance;
+ m_aTableProperties->Erase(oRightMargin->first);
+ }
+ const std::optional<PropertyMap::Property> oTopMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_TOP);
+ if (oTopMargin)
+ {
+ oTopMargin->second >>= rInfo.nTopBorderDistance;
+ m_aTableProperties->Erase(oTopMargin->first);
+ }
+ const std::optional<PropertyMap::Property> oBottomMargin = m_aTableProperties->getProperty(META_PROP_CELL_MAR_BOTTOM);
+ if (oBottomMargin)
+ {
+ oBottomMargin->second >>= rInfo.nBottomBorderDistance;
+ m_aTableProperties->Erase(oBottomMargin->first);
+ }
+
+ // Set the table default attributes for the cells
+ rInfo.pTableDefaults->InsertProps(m_aTableProperties.get());
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TableDefaults");
+ rInfo.pTableDefaults->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ if (!aGrabBag.empty())
+ {
+ m_aTableProperties->Insert( PROP_TABLE_INTEROP_GRAB_BAG, uno::Any( aGrabBag.getAsConstPropertyValueList() ) );
+ }
+
+ std::optional<PropertyMap::Property> oLeftMarginFromStyle = m_aTableProperties->getProperty(PROP_LEFT_MARGIN);
+ if (oLeftMarginFromStyle)
+ {
+ oLeftMarginFromStyle->second >>= nLeftMargin;
+ // don't need to erase, we will push back the adjusted value
+ // of this (or the direct formatting, if that exists) later
+ }
+ m_aTableProperties->getValue( TablePropertyMap::LEFT_MARGIN, nLeftMargin );
+
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_LEFT,
+ rInfo.nLeftBorderDistance );
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_RIGHT,
+ rInfo.nRightBorderDistance );
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_TOP,
+ rInfo.nTopBorderDistance );
+ m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_BOTTOM,
+ rInfo.nBottomBorderDistance );
+
+ table::TableBorderDistances aDistances;
+ aDistances.IsTopDistanceValid =
+ aDistances.IsBottomDistanceValid =
+ aDistances.IsLeftDistanceValid =
+ aDistances.IsRightDistanceValid = true;
+ aDistances.TopDistance = static_cast<sal_Int16>( rInfo.nTopBorderDistance );
+ aDistances.BottomDistance = static_cast<sal_Int16>( rInfo.nBottomBorderDistance );
+ aDistances.LeftDistance = static_cast<sal_Int16>( rInfo.nLeftBorderDistance );
+ aDistances.RightDistance = static_cast<sal_Int16>( rInfo.nRightBorderDistance );
+
+ m_aTableProperties->Insert( PROP_TABLE_BORDER_DISTANCES, uno::Any( aDistances ) );
+
+ sal_Int32 nMode = m_rDMapper_Impl.GetSettingsTable()->GetWordCompatibilityMode();
+ if (!rFrameProperties.empty() && nMode < 15)
+ lcl_DecrementHoriOrientPosition(rFrameProperties, rInfo.nLeftBorderDistance);
+
+ // Set table above/bottom spacing to 0.
+ m_aTableProperties->Insert( PROP_TOP_MARGIN, uno::Any( sal_Int32( 0 ) ) );
+ m_aTableProperties->Insert( PROP_BOTTOM_MARGIN, uno::Any( sal_Int32( 0 ) ) );
+
+ //table border settings
+ table::TableBorder aTableBorder;
+ table::BorderLine2 aBorderLine, aLeftBorder, aRightBorder;
+
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_TOP_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.TopLine = aBorderLine;
+ aTableBorder.IsTopLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_BOTTOM_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.BottomLine = aBorderLine;
+ aTableBorder.IsBottomLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_LEFT_BORDER, rInfo, aLeftBorder))
+ {
+ aTableBorder.LeftLine = aLeftBorder;
+ aTableBorder.IsLeftLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), PROP_RIGHT_BORDER, rInfo,
+ aRightBorder))
+ {
+ aTableBorder.RightLine = aRightBorder;
+ aTableBorder.IsRightLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), META_PROP_HORIZONTAL_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.HorizontalLine = aBorderLine;
+ aTableBorder.IsHorizontalLineValid = true;
+ }
+ if (lcl_extractTableBorderProperty(m_aTableProperties.get(), META_PROP_VERTICAL_BORDER, rInfo, aBorderLine))
+ {
+ aTableBorder.VerticalLine = aBorderLine;
+ aTableBorder.IsVerticalLineValid = true;
+ }
+
+ aTableBorder.Distance = 0;
+ aTableBorder.IsDistanceValid = false;
+
+ m_aTableProperties->Insert( PROP_TABLE_BORDER, uno::Any( aTableBorder ) );
+
+#ifdef DBG_UTIL
+ lcl_debug_TableBorder(aTableBorder);
+#endif
+
+ // Table position in Office is computed in 2 different ways :
+ // - top level tables: the goal is to have in-cell text starting at table indent pos (tblInd),
+ // so table's position depends on table's cells margin
+ // - nested tables: the goal is to have left-most border starting at table_indent pos
+
+ // Only top level table position depends on border width of Column A.
+ if ( !m_aCellProperties.empty() && !m_aCellProperties[0].empty() )
+ {
+ // aLeftBorder already contains tblBorder; overwrite if cell is different.
+ std::optional<PropertyMap::Property> aCellBorder
+ = m_aCellProperties[0][0]->getProperty(PROP_LEFT_BORDER);
+ if ( aCellBorder )
+ aCellBorder->second >>= aLeftBorder;
+ aCellBorder = m_aCellProperties[0][0]->getProperty(PROP_RIGHT_BORDER);
+ if (aCellBorder)
+ aCellBorder->second >>= aRightBorder;
+ }
+ if (rInfo.nNestLevel == 1 && aLeftBorder.LineWidth && !rFrameProperties.empty())
+ {
+ lcl_DecrementHoriOrientPosition(rFrameProperties, aLeftBorder.LineWidth * 0.5);
+ }
+ lcl_adjustBorderDistance(rInfo, aLeftBorder, aRightBorder);
+
+ // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level tables are handled the same as nested tables;
+ // the default behavior when DOCX doesn't define "compatibilityMode" option is to add the cell spacing
+
+ if (0 < nMode && nMode <= 14 && rInfo.nNestLevel == 1)
+ {
+ const sal_Int32 nAdjustedMargin = nLeftMargin - rInfo.nLeftBorderDistance;
+ m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::Any( nAdjustedMargin ) );
+ }
+ else
+ {
+ // Writer starts a table in the middle of the border.
+ // Word starts a table at the left edge of the border,
+ // so emulate that by adding the half the width. (also see docxattributeoutput)
+ if ( rInfo.nNestLevel > 1 && nLeftMargin < 0 )
+ nLeftMargin = 0;
+ const sal_Int32 nAdjustedMargin = nLeftMargin + (aLeftBorder.LineWidth / 2);
+ m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::Any( nAdjustedMargin ) );
+ }
+
+ sal_Int32 nTableWidth = 0;
+ sal_Int32 nTableWidthType = text::SizeType::FIX;
+ m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH, nTableWidth );
+ m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType );
+ if( nTableWidthType == text::SizeType::FIX )
+ {
+ if( nTableWidth > 0 )
+ m_aTableProperties->Insert( PROP_WIDTH, uno::Any( nTableWidth ));
+ else
+ {
+ // tdf#109524: If there is no width for the table, make it simply 100% by default.
+ // TODO: use cell contents to evaluate width (according to ECMA-376-1:2016 17.18.87)
+ nTableWidth = 100;
+ nTableWidthType = text::SizeType::VARIABLE;
+ }
+ }
+ if (nTableWidthType != text::SizeType::FIX)
+ {
+ m_aTableProperties->Insert( PROP_RELATIVE_WIDTH, uno::Any( sal_Int16( nTableWidth ) ) );
+ m_aTableProperties->Insert( PROP_IS_WIDTH_RELATIVE, uno::Any( true ) );
+ }
+
+ sal_Int32 nHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
+ // Fetch Horizontal Orientation in rFrameProperties if not set in m_aTableProperties
+ if ( !m_aTableProperties->getValue( TablePropertyMap::HORI_ORIENT, nHoriOrient ) )
+ lcl_extractHoriOrient( rFrameProperties, nHoriOrient );
+ m_aTableProperties->Insert( PROP_HORI_ORIENT, uno::Any( sal_Int16(nHoriOrient) ) );
+ //fill default value - if not available
+ m_aTableProperties->Insert( PROP_HEADER_ROW_COUNT, uno::Any( sal_Int32(0)), false);
+ m_aTableProperties->Insert(PROP_WRITING_MODE,
+ uno::Any(sal_Int16(text::WritingMode2::CONTEXT)),
+ /*bOverWrite=*/false);
+
+ // if table is only a single row, and row is set as don't split, set the same value for the whole table.
+ if( m_aRowProperties.size() == 1 && m_aRowProperties[0] )
+ {
+ std::optional<PropertyMap::Property> oSplitAllowed = m_aRowProperties[0]->getProperty(PROP_IS_SPLIT_ALLOWED);
+ if( oSplitAllowed )
+ {
+ bool bRowCanSplit = true;
+ oSplitAllowed->second >>= bRowCanSplit;
+ if( !bRowCanSplit )
+ m_aTableProperties->Insert( PROP_SPLIT, uno::Any(bRowCanSplit) );
+ }
+ }
+
+ rInfo.aTableProperties = m_aTableProperties->GetPropertyValues();
+ rInfo.aTablePropertyIds = m_aTableProperties->GetPropertyIds();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("debug.tableprops");
+ m_aTableProperties->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ }
+
+ return pTableStyle;
+}
+
+CellPropertyValuesSeq_t DomainMapperTableHandler::endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("getCellProperties");
+#endif
+
+ CellPropertyValuesSeq_t aCellProperties( m_aCellProperties.size() );
+
+ if ( m_aCellProperties.empty() )
+ {
+ #ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+ #endif
+ return aCellProperties;
+ }
+ // std::vector< std::vector<PropertyMapPtr> > m_aCellProperties
+ PropertyMapVector2::const_iterator aRowOfCellsIterator = m_aCellProperties.begin();
+ PropertyMapVector2::const_iterator aRowOfCellsIteratorEnd = m_aCellProperties.end();
+ PropertyMapVector2::const_iterator aLastRowIterator = m_aCellProperties.end() - 1;
+ sal_Int32 nRow = 0;
+
+ css::uno::Sequence<css::beans::PropertyValues>* pCellProperties = aCellProperties.getArray();
+ PropertyMapVector1::const_iterator aRowIter = m_aRowProperties.begin();
+ while( aRowOfCellsIterator != aRowOfCellsIteratorEnd )
+ {
+ //aRowOfCellsIterator points to a vector of PropertyMapPtr
+ PropertyMapVector1::const_iterator aCellIterator = aRowOfCellsIterator->begin();
+ PropertyMapVector1::const_iterator aCellIteratorEnd = aRowOfCellsIterator->end();
+
+ sal_Int32 nRowStyleMask = 0;
+
+ if (aRowOfCellsIterator==m_aCellProperties.begin())
+ {
+ if(rInfo.nTblLook&0x20)
+ nRowStyleMask |= CNF_FIRST_ROW; // first row style used
+ }
+ else if (aRowOfCellsIterator==aLastRowIterator)
+ {
+ if(rInfo.nTblLook&0x40)
+ nRowStyleMask |= CNF_LAST_ROW; // last row style used
+ }
+ else if (*aRowIter && (*aRowIter)->isSet(PROP_TBL_HEADER))
+ nRowStyleMask |= CNF_FIRST_ROW; // table header implies first row
+ if(!nRowStyleMask) // if no row style used yet
+ {
+ // banding used only if not first and or last row style used
+ if(!(rInfo.nTblLook&0x200))
+ { // hbanding used
+ int n = nRow + 1;
+ if(rInfo.nTblLook&0x20)
+ n++;
+ if(n & 1)
+ nRowStyleMask = CNF_ODD_HBAND;
+ else
+ nRowStyleMask = CNF_EVEN_HBAND;
+ }
+ }
+
+ // Note that this is intentionally called "cell" and not "column".
+ // Don't make the mistake that all cell x's will be in the same column.
+ // Merged cells (grid span) in a row will affect the actual column. (fake cells were added to handle gridBefore/After)
+ sal_Int32 nCell = 0;
+ pCellProperties[nRow].realloc( aRowOfCellsIterator->size() );
+ beans::PropertyValues* pSingleCellProperties = pCellProperties[nRow].getArray();
+
+ while( aCellIterator != aCellIteratorEnd )
+ {
+ PropertyMapPtr pAllCellProps( new PropertyMap );
+
+ PropertyMapVector1::const_iterator aLastCellIterator = aRowOfCellsIterator->end() - 1;
+ bool bIsEndCol = aCellIterator == aLastCellIterator;
+ bool bIsEndRow = aRowOfCellsIterator == aLastRowIterator;
+
+ //aCellIterator points to a PropertyMapPtr;
+ if( *aCellIterator )
+ {
+ // remove directly applied insideV/H borders since they are meaningless without a context (tdf#82177)
+ (*aCellIterator)->Erase(META_PROP_VERTICAL_BORDER);
+ (*aCellIterator)->Erase(META_PROP_HORIZONTAL_BORDER);
+
+ pAllCellProps->InsertProps(rInfo.pTableDefaults);
+
+ sal_Int32 nCellStyleMask = 0;
+ if (aCellIterator==aRowOfCellsIterator->begin())
+ {
+ if(rInfo.nTblLook&0x80)
+ nCellStyleMask = CNF_FIRST_COLUMN; // first col style used
+ }
+ else if (bIsEndCol)
+ {
+ if(rInfo.nTblLook&0x100)
+ nCellStyleMask = CNF_LAST_COLUMN; // last col style used
+ }
+ if(!nCellStyleMask) // if no cell style is used yet
+ {
+ if(!(rInfo.nTblLook&0x400))
+ { // vbanding used
+ int n = nCell + 1;
+ if(rInfo.nTblLook&0x80)
+ n++;
+ if(n & 1)
+ nCellStyleMask = CNF_ODD_VBAND;
+ else
+ nCellStyleMask = CNF_EVEN_VBAND;
+ }
+ }
+ sal_Int32 nCnfStyleMask = nCellStyleMask + nRowStyleMask;
+ if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_FIRST_ROW)
+ nCnfStyleMask |= CNF_FIRST_ROW_FIRST_COLUMN;
+ else if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_LAST_ROW)
+ nCnfStyleMask |= CNF_LAST_ROW_FIRST_COLUMN;
+ else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_FIRST_ROW)
+ nCnfStyleMask |= CNF_FIRST_ROW_LAST_COLUMN;
+ else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_LAST_ROW)
+ nCnfStyleMask |= CNF_LAST_ROW_LAST_COLUMN;
+
+ if ( rInfo.pTableStyle )
+ {
+ PropertyMapPtr pStyleProps = rInfo.pTableStyle->GetProperties( nCnfStyleMask );
+
+ // Check if we need to clean up some empty border definitions to match what Word does.
+ static const PropertyIds pBorders[] =
+ {
+ PROP_TOP_BORDER, PROP_LEFT_BORDER, PROP_BOTTOM_BORDER, PROP_RIGHT_BORDER
+ };
+ for (const PropertyIds& rBorder : pBorders)
+ {
+ std::optional<PropertyMap::Property> oStyleCellBorder = pStyleProps->getProperty(rBorder);
+ std::optional<PropertyMap::Property> oDirectCellBorder = (*aCellIterator)->getProperty(rBorder);
+ if (oStyleCellBorder && oDirectCellBorder)
+ {
+ // We have a cell border from the table style and as direct formatting as well.
+ table::BorderLine2 aStyleCellBorder = oStyleCellBorder->second.get<table::BorderLine2>();
+ table::BorderLine2 aDirectCellBorder = oDirectCellBorder->second.get<table::BorderLine2>();
+ if (aStyleCellBorder.LineStyle != table::BorderLineStyle::NONE && aDirectCellBorder.LineStyle == table::BorderLineStyle::NONE)
+ {
+ // The style one would be visible, but then cleared away as direct formatting.
+ // Delete both, so that table formatting can become visible.
+ pStyleProps->Erase(rBorder);
+ (*aCellIterator)->Erase(rBorder);
+ }
+ else
+ {
+ std::optional<PropertyMap::Property> oTableBorder = rInfo.pTableBorders->getProperty(rBorder);
+ if (oTableBorder)
+ {
+ table::BorderLine2 aTableBorder = oTableBorder->second.get<table::BorderLine2>();
+ // Both style and direct formatting says that the cell has no border.
+ bool bNoCellBorder = aStyleCellBorder.LineStyle == table::BorderLineStyle::NONE && aDirectCellBorder.LineStyle == table::BorderLineStyle::NONE;
+ if (aTableBorder.LineStyle != table::BorderLineStyle::NONE && bNoCellBorder)
+ {
+ // But at a table-level, there is a border, then again delete both cell properties.
+ pStyleProps->Erase(rBorder);
+ (*aCellIterator)->Erase(rBorder);
+ }
+ }
+ }
+ }
+ }
+
+ pAllCellProps->InsertProps( pStyleProps );
+ }
+
+ // Remove properties from style/row that aren't allowed in cells
+ pAllCellProps->Erase( PROP_HEADER_ROW_COUNT );
+ pAllCellProps->Erase( PROP_TBL_HEADER );
+
+ // Then add the cell properties
+ pAllCellProps->InsertProps(*aCellIterator);
+ std::swap(*(*aCellIterator), *pAllCellProps );
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("cell");
+ TagLogger::getInstance().attribute("cell", nCell);
+ TagLogger::getInstance().attribute("row", nRow);
+#endif
+
+ // Do not apply horizontal and vertical borders to a one cell table.
+ if (m_aCellProperties.size() <= 1 && aRowOfCellsIterator->size() <= 1)
+ {
+ rInfo.pTableBorders->Erase(META_PROP_HORIZONTAL_BORDER);
+ rInfo.pTableBorders->Erase(META_PROP_VERTICAL_BORDER);
+ }
+ // Do not apply vertical borders to a one column table.
+ else if (m_aCellProperties.size() > 1 && aRowOfCellsIterator->size() <= 1)
+ {
+ bool isOneCol = true;
+ for (size_t i = nRow; i < m_aCellProperties.size(); i++)
+ {
+ if (m_aCellProperties[i].size() > 1)
+ {
+ isOneCol = false;
+ break;
+ }
+ }
+ if (isOneCol)
+ rInfo.pTableBorders->Erase(META_PROP_VERTICAL_BORDER);
+ }
+ // Do not apply horizontal borders to a one row table.
+ else if (m_aCellProperties.size() == 1 && aRowOfCellsIterator->size() > 1)
+ {
+ rInfo.pTableBorders->Erase(META_PROP_HORIZONTAL_BORDER);
+ }
+
+ // tdf#129452 Checking if current cell is vertically merged with all the other cells below to the bottom.
+ // This must be done in order to apply the bottom border of the table to the first cell in a vertical merge.
+ std::optional<PropertyMap::Property> oProp = m_aCellProperties[nRow][nCell]->getProperty(PROP_VERTICAL_MERGE);
+ bool bMergedVertically = oProp && oProp->second.get<bool>(); // starting cell
+ if ( bMergedVertically )
+ {
+ const sal_uInt32 nColumn = m_rDMapper_Impl.getTableManager().findColumn(nRow, nCell);
+ sal_Int32 nLastMergedRow = 0;
+ for (size_t i = nRow + 1; bMergedVertically && i < m_aCellProperties.size(); i++)
+ {
+ const sal_uInt32 nColumnCell = m_rDMapper_Impl.getTableManager().findColumnCell(i, nColumn);
+ if ( m_aCellProperties[i].size() > sal::static_int_cast<std::size_t>(nColumnCell) )
+ {
+ oProp = m_aCellProperties[i][nColumnCell]->getProperty(PROP_VERTICAL_MERGE);
+ bMergedVertically = oProp && !oProp->second.get<bool>(); //continuing cell
+ if ( bMergedVertically )
+ nLastMergedRow = i;
+ }
+ else
+ bMergedVertically = false;
+ }
+
+ // Only consider the bottom border setting from the last merged cell.
+ // Note: in MSO, left/right apply per-unmerged-row. Can't do that in LO, so just using the top cell's borders should be fine.
+ if ( nRow < nLastMergedRow )
+ {
+ (*aCellIterator)->Erase(PROP_BOTTOM_BORDER);
+ const sal_uInt32 nColumnCell = m_rDMapper_Impl.getTableManager().findColumnCell(nLastMergedRow, nColumn);
+ lcl_mergeBorder( PROP_BOTTOM_BORDER, m_aCellProperties[nLastMergedRow][nColumnCell], *aCellIterator );
+ }
+ }
+
+ const sal_uInt32 nFirstCell = m_rDMapper_Impl.getTableManager().getGridBefore(nRow);
+ const sal_uInt32 nLastCell = m_aCellProperties[nRow].size() - m_rDMapper_Impl.getTableManager().getGridAfter(nRow) - 1;
+ lcl_computeCellBorders( rInfo.pTableBorders, *aCellIterator, nCell, nFirstCell, nLastCell, nRow, bIsEndRow, bMergedVertically );
+
+ //now set the default left+right border distance TODO: there's an sprm containing the default distance!
+ aCellIterator->get()->Insert( PROP_LEFT_BORDER_DISTANCE,
+ uno::Any(rInfo.nLeftBorderDistance ), false);
+ aCellIterator->get()->Insert( PROP_RIGHT_BORDER_DISTANCE,
+ uno::Any(rInfo.nRightBorderDistance ), false);
+ aCellIterator->get()->Insert( PROP_TOP_BORDER_DISTANCE,
+ uno::Any(rInfo.nTopBorderDistance ), false);
+ aCellIterator->get()->Insert( PROP_BOTTOM_BORDER_DISTANCE,
+ uno::Any(rInfo.nBottomBorderDistance ), false);
+
+ // Horizontal merge is not a UNO property, extract that info here to rMerges, and then remove it from the map.
+ const std::optional<PropertyMap::Property> aHorizontalMergeVal = (*aCellIterator)->getProperty(PROP_HORIZONTAL_MERGE);
+ if (aHorizontalMergeVal)
+ {
+ if (aHorizontalMergeVal->second.get<bool>())
+ {
+ // first cell in a merge
+ HorizontallyMergedCell aMerge(nRow, nCell);
+ rMerges.push_back(aMerge);
+ }
+ else if (!rMerges.empty())
+ {
+ // resuming an earlier merge
+ HorizontallyMergedCell& rMerge = rMerges.back();
+ rMerge.m_nLastRow = nRow;
+ rMerge.m_nLastCol = nCell;
+ }
+ (*aCellIterator)->Erase(PROP_HORIZONTAL_MERGE);
+ }
+ pSingleCellProperties[nCell] = (*aCellIterator)->GetPropertyValues();
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+ }
+ ++nCell;
+ ++aCellIterator;
+ }
+ ++nRow;
+ ++aRowOfCellsIterator;
+ ++aRowIter;
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+ return aCellProperties;
+}
+
+/// Do all cells in this row have a CellHideMark property?
+static bool lcl_hideMarks(PropertyMapVector1& rCellProperties)
+{
+ for (const PropertyMapPtr & p : rCellProperties)
+ {
+ // if anything is vertically merged, the row must not be set to fixed
+ // as Writer's layout doesn't handle that well
+ if (!p->isSet(PROP_CELL_HIDE_MARK) || p->isSet(PROP_VERTICAL_MERGE))
+ return false;
+ }
+ return true;
+}
+
+/// Are all cells in this row empty?
+static bool lcl_emptyRow(std::vector<RowSequence_t>& rTableRanges, sal_Int32 nRow)
+{
+ if (nRow >= static_cast<sal_Int32>(rTableRanges.size()))
+ {
+ SAL_WARN("writerfilter.dmapper", "m_aCellProperties not in sync with rTableRanges?");
+ return false;
+ }
+
+ const RowSequence_t rRowSeq = rTableRanges[nRow];
+ if (!rRowSeq.hasElements())
+ {
+ SAL_WARN("writerfilter.dmapper", "m_aCellProperties not in sync with rTableRanges?");
+ return false;
+ }
+
+ if (!rRowSeq[0][0].is())
+ {
+ // This can happen when we can't import the table, e.g. we're inside a
+ // comment.
+ SAL_WARN("writerfilter.dmapper", "rRowSeq[0][0] is an empty reference");
+ return false;
+ }
+
+ uno::Reference<text::XTextRangeCompare> xTextRangeCompare(rRowSeq[0][0]->getText(), uno::UNO_QUERY);
+ try
+ {
+ // See SwXText::Impl::ConvertCell(), we need to compare the start of
+ // the start and the end of the end. However for our text ranges, only
+ // the starts are set, so compareRegionStarts() does what we need.
+ bool bRangesAreNotEqual = std::any_of(rRowSeq.begin(), rRowSeq.end(),
+ [&xTextRangeCompare](const CellSequence_t& rCellSeq) {
+ return xTextRangeCompare->compareRegionStarts(rCellSeq[0], rCellSeq[1]) != 0; });
+ if (bRangesAreNotEqual)
+ return false;
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "compareRegionStarts() failed");
+ return false;
+ }
+ return true;
+}
+
+css::uno::Sequence<css::beans::PropertyValues> DomainMapperTableHandler::endTableGetRowProperties()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("getRowProperties");
+#endif
+
+ css::uno::Sequence<css::beans::PropertyValues> aRowProperties( m_aRowProperties.size() );
+ auto aRowPropertiesRange = asNonConstRange(aRowProperties);
+ sal_Int32 nRow = 0;
+ for( const auto& rRow : m_aRowProperties )
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("rowProps.row");
+#endif
+ if (rRow)
+ {
+ //set default to 'break across pages"
+ rRow->Insert( PROP_IS_SPLIT_ALLOWED, uno::Any(true ), false );
+ // tblHeader is only our property, remove before the property map hits UNO
+ rRow->Erase(PROP_TBL_HEADER);
+
+ if (lcl_hideMarks(m_aCellProperties[nRow]) && lcl_emptyRow(m_aTableRanges, nRow))
+ {
+ // We have CellHideMark on all cells, and also all cells are empty:
+ // Force the row height to be exactly as specified, and not just as the minimum suggestion.
+ rRow->Insert(PROP_SIZE_TYPE, uno::Any(text::SizeType::FIX));
+ }
+
+ aRowPropertiesRange[nRow] = rRow->GetPropertyValues();
+#ifdef DBG_UTIL
+ rRow->dumpXml();
+ lcl_DumpPropertyValues(aRowProperties[nRow]);
+#endif
+ }
+ ++nRow;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+ return aRowProperties;
+}
+
+static bool isAbsent(const std::vector<beans::PropertyValue>& propvals, const OUString& name)
+{
+ return std::find_if(propvals.begin(), propvals.end(),
+ [&name](const beans::PropertyValue& propval)
+ { return propval.Name == name; })
+ == propvals.end();
+}
+
+// table style has got bigger precedence than docDefault style,
+// but lower precedence than the paragraph styles and direct paragraph formatting
+void DomainMapperTableHandler::ApplyParagraphPropertiesFromTableStyle(TableParagraph rParaProp, std::vector< PropertyIds > aAllTableParaProperties, const css::beans::PropertyValues rCellProperties)
+{
+ // Setting paragraph or character properties using setPropertyValue may have unwanted
+ // side effects; e.g., setting a paragraph's font size can reset font size in a runs
+ // of the paragraph, which have own formatting, which should have highest precedence.
+ // Thus we have to collect property values, construct an autostyle, and assign it to
+ // the paragraph, to avoid such side effects.
+
+ // 1. Collect all the table-style-defined properties, that aren't overridden by the
+ // paragraph style or direct formatting
+ std::vector<beans::PropertyValue> aProps;
+ std::optional<OUString> oParagraphText;
+
+ for( auto const& eId : aAllTableParaProperties )
+ {
+ // apply paragraph and character properties of the table style on table paragraphs
+ // if there is no direct paragraph formatting
+ bool bSetDirectlyInParaLevel = rParaProp.m_pPropertyMap->isSet(eId);
+ if ( !bSetDirectlyInParaLevel || isCharacterProperty(eId) )
+ {
+ if ( (eId == PROP_PARA_LEFT_MARGIN || eId == PROP_PARA_FIRST_LINE_INDENT) &&
+ rParaProp.m_pPropertyMap->isSet(PROP_NUMBERING_RULES) )
+ {
+ // indentation of direct numbering has bigger precedence, than table style
+ continue;
+ }
+
+ OUString sPropertyName = getPropertyName(eId);
+
+ auto pCellProp = std::find_if(rCellProperties.begin(), rCellProperties.end(),
+ [&](const beans::PropertyValue& rProp) { return rProp.Name == sPropertyName; });
+ // this cell applies the table style property
+ if (pCellProp != rCellProperties.end())
+ {
+ if (bSetDirectlyInParaLevel) // it is a character property set directly in the paragraph
+ {
+ if (!oParagraphText) // do it only once
+ {
+ uno::Reference<text::XParagraphCursor> xParagraph(
+ rParaProp.m_rEndParagraph->getText()->createTextCursorByRange(rParaProp.m_rEndParagraph), uno::UNO_QUERY_THROW );
+ // select paragraph
+ xParagraph->gotoStartOfParagraph( true );
+ oParagraphText = xParagraph->getString();
+ }
+ // don't overwrite empty paragraph with table style, if it has a direct paragraph formatting
+ if (oParagraphText->isEmpty())
+ continue;
+ }
+ // handle paragraph background color defined in CellColorHandler
+ if (eId == PROP_FILL_COLOR)
+ {
+ auto pFillStyleProp = std::find_if(rCellProperties.begin(), rCellProperties.end(),
+ [](const beans::PropertyValue& rProp) { return rProp.Name == "FillStyle"; });
+ if ( pFillStyleProp == rCellProperties.end() ||
+ pFillStyleProp->Value != uno::Any(drawing::FillStyle_SOLID) )
+ {
+ // FillStyle_NONE, skip table style usage for paragraph background color
+ continue;
+ }
+ }
+ OUString sParaStyleName;
+ rParaProp.m_rPropertySet->getPropertyValue("ParaStyleName") >>= sParaStyleName;
+ bool bDocDefault;
+ uno::Any aParaStyle = m_rDMapper_Impl.GetPropertyFromStyleSheet(eId,
+ m_rDMapper_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(sParaStyleName),
+ 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()->
+ GetCompatSettingHasAndValue(u"overrideTableStyleFontSizeAndJustification").second;
+ }
+
+ // use table style when no paragraph style setting or a docDefault value is applied instead of it
+ if (!aParaStyle.hasValue() || bDocDefault || bCompatOverride) try
+ {
+ // apply style setting when the paragraph doesn't modify it
+ aProps.push_back(comphelper::makePropertyValue(sPropertyName, pCellProp->Value));
+ if (eId == PROP_FILL_COLOR)
+ {
+ // we need this for complete import of table-style based paragraph background color
+ aProps.push_back(comphelper::makePropertyValue("FillStyle", uno::Any(drawing::FillStyle_SOLID)));
+ }
+ }
+ catch ( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.dmapper", "Exception during table style correction");
+ }
+ }
+ }
+ }
+
+ if (!aProps.empty())
+ {
+ // 2. Get all properties directly defined in the paragraph
+ uno::Reference<beans::XPropertySetInfo> xPropSetInfo(
+ rParaProp.m_rPropertySet->getPropertySetInfo(), uno::UNO_SET_THROW);
+ auto props = xPropSetInfo->getProperties();
+ uno::Sequence<OUString> propNames(props.getLength());
+ std::transform(props.begin(), props.end(), propNames.getArray(),
+ [](const beans::Property& prop) { return prop.Name; });
+ uno::Reference<beans::XTolerantMultiPropertySet> xTolPara(rParaProp.m_rPropertySet,
+ uno::UNO_QUERY_THROW);
+ // getDirectPropertyValuesTolerant requires a sorted sequence.
+ // Let's hope XPropertySetInfo::getProperties returns a sorted sequence.
+ for (auto& val : xTolPara->getDirectPropertyValuesTolerant(propNames))
+ {
+ // 3. Add them to aProps, unless such properties are already there
+ // (which means, that 'val' comes from docDefault)
+ if (val.Result == beans::TolerantPropertySetResultType::SUCCESS
+ && val.State == beans::PropertyState_DIRECT_VALUE
+ && isAbsent(aProps, val.Name))
+ {
+ aProps.push_back(comphelper::makePropertyValue(val.Name, val.Value));
+ }
+ }
+
+ // 4. Create an autostyle, and assign it to the paragraph. The hidden ParaAutoStyleDef
+ // property is handled in SwXTextCursor::setPropertyValue.
+ uno::Reference<beans::XPropertySet> xCursorProps(
+ rParaProp.m_rEndParagraph->getText()->createTextCursorByRange(
+ rParaProp.m_rEndParagraph),
+ uno::UNO_QUERY_THROW);
+ xCursorProps->setPropertyValue("ParaAutoStyleDef",
+ uno::Any(comphelper::containerToSequence(aProps)));
+ }
+}
+
+// convert formula range identifier ABOVE, BELOW, LEFT and RIGHT
+static void lcl_convertFormulaRanges(const uno::Reference<text::XTextTable> & xTable)
+{
+ uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xTableRows(xTable->getRows(), uno::UNO_QUERY_THROW);
+ sal_Int32 nRows = xTableRows->getCount();
+ for (sal_Int32 nRow = 0; nRow < nRows; ++nRow)
+ {
+ for (sal_Int16 nCol = 0; nCol < MAXTABLECELLS; ++nCol)
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xCellProperties(xCellRange->getCellByPosition(nCol, nRow), uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aCellGrabBag;
+ xCellProperties->getPropertyValue("CellInteropGrabBag") >>= aCellGrabBag;
+ OUString sFormula;
+ bool bReplace = false;
+ for (const auto& rProp : aCellGrabBag)
+ {
+ if ( rProp.Name == "CellFormulaConverted" )
+ {
+ rProp.Value >>= sFormula;
+ struct RangeDirection
+ {
+ OUString m_sName;
+ sal_Int16 m_nCol;
+ sal_Int16 m_nRow;
+ };
+ static const RangeDirection pDirections[] =
+ {
+ { OUString(" LEFT "), -1, 0},
+ { OUString(" RIGHT "), 1, 0},
+ { OUString(" ABOVE "), 0, -1},
+ { OUString(" BELOW "), 0, 1 }
+ };
+ for (const RangeDirection& rRange : pDirections)
+ {
+ if ( sFormula.indexOf(rRange.m_sName) > -1 )
+ {
+ // range starts at the first cell above/below/left/right, but ends at the
+ // table border or at the first non-value cell after a value cell
+ bool bFoundFirst = false;
+ OUString sNextCell;
+ OUString sLastCell;
+ OUString sLastValueCell;
+ // walk through the cells of the range
+ try
+ {
+ sal_Int32 nCell = 0;
+ while (++nCell)
+ {
+ uno::Reference<beans::XPropertySet> xCell(
+ xCellRange->getCellByPosition(nCol + nCell * rRange.m_nCol, nRow + nCell * rRange.m_nRow),
+ uno::UNO_QUERY_THROW);
+ // empty cell or cell with text content is end of the range
+ uno::Reference<text::XText> xText(xCell, uno::UNO_QUERY_THROW);
+ sLastCell = xCell->getPropertyValue("CellName").get<OUString>();
+ if (sNextCell.isEmpty())
+ sNextCell = sLastCell;
+
+ // accept numbers with comma and percent
+ OUString sCellText = xText->getString().replace(',', '.');
+ if (sCellText.endsWith("%"))
+ sCellText = sCellText.copy(0, sCellText.getLength()-1);
+
+ rtl_math_ConversionStatus eConversionStatus;
+ sal_Int32 nParsedEnd;
+ rtl::math::stringToDouble(sCellText, '.', ',', &eConversionStatus, &nParsedEnd);
+ if ( eConversionStatus != rtl_math_ConversionStatus_Ok || nParsedEnd == 0 )
+ {
+ if ( !bFoundFirst )
+ {
+ // still search value cells
+ continue;
+ }
+ else
+ {
+ // end of range
+ break;
+ }
+ }
+ sLastValueCell = sLastCell;
+ bFoundFirst = true;
+ }
+ }
+ catch ( const lang::IndexOutOfBoundsException & )
+ {
+ }
+
+ if ( !sNextCell.isEmpty() )
+ {
+ OUString sRange = "<" + sNextCell + ":" +
+ ( sLastValueCell.isEmpty() ? sLastCell : sLastValueCell ) + ">";
+ sFormula = sFormula.replaceAll(rRange.m_sName, sRange);
+ bReplace = true;
+ }
+ }
+ }
+
+ // update formula field
+ if (bReplace)
+ {
+ uno::Reference<text::XText> xCell(xCellRange->getCellByPosition(nCol, nRow), uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCell, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParaEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ while ( xRunEnum->hasMoreElements() )
+ {
+ uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet > xRunProperties( xRun, uno::UNO_QUERY_THROW );
+ if ( xRunProperties->getPropertyValue("TextPortionType") == uno::Any(OUString("TextField")) )
+ {
+ uno::Reference<text::XTextField> const xField(xRunProperties->getPropertyValue("TextField").get<uno::Reference<text::XTextField>>());
+ uno::Reference< beans::XPropertySet > xFieldProperties( xField, uno::UNO_QUERY_THROW );
+ // cell can contain multiple text fields, but only one is handled now (~formula cell)
+ if ( rProp.Value != xFieldProperties->getPropertyValue("Content") )
+ continue;
+ xFieldProperties->setPropertyValue("Content", uno::Any(sFormula));
+ // update grab bag
+ auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aCellGrabBag);
+ beans::PropertyValue aValue;
+ aValue.Name = "CellFormulaConverted";
+ aValue.Value <<= sFormula;
+ aGrabBag.push_back(aValue);
+ xCellProperties->setPropertyValue("CellInteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+ }
+ }
+ }
+ }
+ }
+ catch ( const lang::IndexOutOfBoundsException & )
+ {
+ // jump to next table row
+ break;
+ }
+ }
+ }
+}
+
+void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablehandler.endTable");
+#endif
+
+ // If we want to make this table a floating one.
+ std::vector<beans::PropertyValue> aFrameProperties = comphelper::sequenceToContainer<std::vector<beans::PropertyValue> >
+ (m_rDMapper_Impl.getTableManager().getCurrentTablePosition());
+ TableInfo aTableInfo;
+ aTableInfo.nNestLevel = nestedTableLevel;
+
+ // non-floating tables need floating in footnotes and endnotes, because
+ // Writer core cannot handle (i.e. save in ODT, copy, edit etc.) them otherwise
+ bool bConvertToFloating = aFrameProperties.empty() &&
+ nestedTableLevel <= 1 &&
+ m_rDMapper_Impl.IsInFootOrEndnote();
+ bool bFloating = !aFrameProperties.empty() || bConvertToFloating;
+
+ aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties, bConvertToFloating);
+ // expands to uno::Sequence< Sequence< beans::PropertyValues > >
+
+ std::vector<HorizontallyMergedCell> aMerges;
+ CellPropertyValuesSeq_t aCellProperties = endTableGetCellProperties(aTableInfo, aMerges);
+
+ css::uno::Sequence<css::beans::PropertyValues> aRowProperties = endTableGetRowProperties();
+
+#ifdef DBG_UTIL
+ lcl_DumpPropertyValueSeq(aRowProperties);
+#endif
+
+ if (!m_aTableRanges.empty())
+ {
+ uno::Reference<text::XTextRange> xStart;
+ uno::Reference<text::XTextRange> xEnd;
+
+ // fill empty frame properties to create an invisible frame around the table:
+ // hide frame borders and zero inner and outer frame margins
+ if (bConvertToFloating)
+ DomainMapper_Impl::fillEmptyFrameProperties(aFrameProperties, true);
+
+ // OOXML table style may contain paragraph properties, apply these on cell paragraphs
+ if ( m_aTableRanges[0].hasElements() && m_aTableRanges[0][0].hasElements() )
+ {
+ // collect all paragraph properties used in table styles
+ PropertyMapPtr pAllTableProps( new PropertyMap );
+ pAllTableProps->InsertProps(aTableInfo.pTableDefaults);
+ if ( aTableInfo.pTableStyle )
+ pAllTableProps->InsertProps(aTableInfo.pTableStyle->GetProperties( CNF_ALL ));
+ for (const auto& eId : pAllTableProps->GetPropertyIds())
+ {
+ if ( !isParagraphProperty(eId) && !isCharacterProperty(eId) )
+ pAllTableProps->Erase(eId);
+ }
+ std::vector< PropertyIds > aAllTableParaProperties = pAllTableProps->GetPropertyIds();
+
+ if ( !aAllTableParaProperties.empty() )
+ {
+ TableParagraphVectorPtr pTableParagraphs = m_rDMapper_Impl.getTableManager().getCurrentParagraphs();
+ for (size_t nRow = 0; nRow < m_aTableRanges.size(); ++nRow)
+ {
+ // Note that this is "cell" since you must not treat it as "column".
+ for (size_t nCell = 0; nCell < m_aTableRanges[nRow].size(); ++nCell)
+ {
+ auto rStartPara = m_aTableRanges[nRow][nCell][0];
+ if (!rStartPara.is())
+ continue;
+ auto rEndPara = m_aTableRanges[nRow][nCell][1];
+ uno::Reference<text::XTextRangeCompare> xTextRangeCompare(rStartPara->getText(), uno::UNO_QUERY);
+ bool bApply = false;
+ // search paragraphs of the cell
+ std::vector<TableParagraph>::iterator aIt = pTableParagraphs->begin();
+ while ( aIt != pTableParagraphs->end() ) try
+ {
+ if (!bApply && xTextRangeCompare->compareRegionStarts(rStartPara, aIt->m_rStartParagraph) == 0)
+ bApply = true;
+ if (bApply)
+ {
+ bool bEndOfApply = (xTextRangeCompare->compareRegionEnds(rEndPara, aIt->m_rEndParagraph) == 0);
+ // tdf#153891 handle missing cell properties (exception in style handling?)
+ if ( nCell < sal::static_int_cast<std::size_t>(aCellProperties[nRow].getLength()) )
+ ApplyParagraphPropertiesFromTableStyle(*aIt, aAllTableParaProperties, aCellProperties[nRow][nCell]);
+ // erase processed paragraph from list of pending paragraphs
+ aIt = pTableParagraphs->erase(aIt);
+ if (bEndOfApply)
+ break;
+ }
+ else
+ ++aIt;
+ }
+ catch( const lang::IllegalArgumentException & )
+ {
+ // skip compareRegion with nested tables
+ ++aIt;
+ }
+ }
+ }
+ }
+ }
+
+ // Additional checks: if we can do this.
+ if (bFloating && m_aTableRanges[0].hasElements() && m_aTableRanges[0][0].hasElements())
+ {
+ xStart = m_aTableRanges[0][0][0];
+ uno::Sequence< uno::Sequence< uno::Reference<text::XTextRange> > >& rLastRow = m_aTableRanges[m_aTableRanges.size() - 1];
+ if (rLastRow.hasElements())
+ {
+ const uno::Sequence< uno::Reference<text::XTextRange> >& rLastCell = rLastRow[rLastRow.getLength() - 1];
+ xEnd = rLastCell[1];
+ }
+ }
+ uno::Reference<text::XTextTable> xTable;
+ try
+ {
+ if (m_xText.is())
+ {
+ xTable = m_xText->convertToTable(comphelper::containerToSequence(m_aTableRanges), aCellProperties, aRowProperties, aTableInfo.aTableProperties);
+
+ if (xTable.is())
+ {
+ if (!aMerges.empty())
+ {
+ static const std::vector<std::u16string_view> aBorderNames
+ = { u"TopBorder", u"LeftBorder", u"BottomBorder", u"RightBorder" };
+
+ // Perform horizontal merges in reverse order, so the fact that merging changes the position of cells won't cause a problem for us.
+ for (std::vector<HorizontallyMergedCell>::reverse_iterator it = aMerges.rbegin(); it != aMerges.rend(); ++it)
+ {
+ uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xFirstCell(
+ xCellRange->getCellByPosition(it->m_nFirstCol, it->m_nFirstRow),
+ uno::UNO_QUERY_THROW);
+ OUString aFirst
+ = xFirstCell->getPropertyValue("CellName").get<OUString>();
+ // tdf#105852: Only try to merge if m_nLastCol is set (i.e. there were some merge continuation cells)
+ if (it->m_nLastCol != -1)
+ {
+ // Save border properties of the first cell
+ // before merge.
+ table::BorderLine2 aBorderValues[4];
+ for (size_t i = 0; i < aBorderNames.size(); ++i)
+ xFirstCell->getPropertyValue(OUString(aBorderNames[i]))
+ >>= aBorderValues[i];
+
+ uno::Reference<beans::XPropertySet> xLastCell(
+ xCellRange->getCellByPosition(it->m_nLastCol, it->m_nLastRow),
+ uno::UNO_QUERY_THROW);
+ OUString aLast
+ = xLastCell->getPropertyValue("CellName").get<OUString>();
+
+ uno::Reference<text::XTextTableCursor> xCursor = xTable->createCursorByCellName(aFirst);
+ xCursor->gotoCellByName(aLast, true);
+
+ xCursor->mergeRange();
+
+ // Handle conflicting properties: mergeRange()
+ // takes the last cell, Word takes the first
+ // cell.
+ for (size_t i = 0; i < aBorderNames.size(); ++i)
+ {
+ if (aBorderValues[i].LineStyle != table::BorderLineStyle::NONE)
+ xFirstCell->setPropertyValue(
+ OUString(aBorderNames[i]), uno::Any(aBorderValues[i]));
+ }
+ }
+ }
+ }
+
+ // convert special range IDs ABOVE, BELOW, LEFT and RIGHT
+ lcl_convertFormulaRanges(xTable);
+ }
+ }
+ }
+ catch ( const lang::IllegalArgumentException & )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.dmapper", "Conversion to table error");
+#ifdef DBG_UTIL
+ TagLogger::getInstance().chars(std::string("failed to import table!"));
+#endif
+ }
+ catch ( const uno::Exception & )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.dmapper", "Exception during table creation");
+ }
+
+ // If we have a table with a start and an end position, we should make it a floating one.
+ if (xTable.is() && xStart.is() && xEnd.is())
+ {
+ uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
+ bool bIsRelative = false;
+ xTableProperties->getPropertyValue("IsWidthRelative") >>= bIsRelative;
+ if (!bIsRelative)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "Width";
+ aValue.Value = xTableProperties->getPropertyValue("Width");
+ aFrameProperties.push_back(aValue);
+ }
+ else
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "FrameWidthPercent";
+ aValue.Value = xTableProperties->getPropertyValue("RelativeWidth");
+ aFrameProperties.push_back(aValue);
+
+ // Applying the relative width to the frame, needs to have the table width to be 100% of the frame width
+ xTableProperties->setPropertyValue("RelativeWidth", uno::Any(sal_Int16(100)));
+ }
+
+ // A non-zero left margin would move the table out of the frame, move the frame itself instead.
+ xTableProperties->setPropertyValue("LeftMargin", uno::Any(sal_Int32(0)));
+
+ style::BreakType eBreakType{};
+ xTableProperties->getPropertyValue("BreakType") >>= eBreakType;
+ if (eBreakType != style::BreakType_NONE)
+ {
+ // A break before the table was requested. Reset that break here, since the table
+ // will be at the start of the fly frame, not in the body frame.
+ xTableProperties->setPropertyValue("BreakType", uno::Any(style::BreakType_NONE));
+ }
+
+ if (nestedTableLevel >= 2 || m_rDMapper_Impl.IsInHeaderFooter())
+ {
+ // Floating tables inside a table always stay inside the cell.
+ // Also extend the header/footer area if needed, so an in-header floating table
+ // typically doesn't overlap with body test.
+ bool bIsFollowingTextFlow = true;
+
+ sal_Int16 nVertOrientRelation{};
+ auto it = std::find_if(aFrameProperties.begin(), aFrameProperties.end(),
+ [](const beans::PropertyValue& rPropertyValue) -> bool
+ { return rPropertyValue.Name == "VertOrientRelation"; });
+ if (it != aFrameProperties.end())
+ {
+ it->Value >>= nVertOrientRelation;
+ if (nVertOrientRelation == text::RelOrientation::PAGE_FRAME)
+ {
+ // If vertical relation is page, follow-text-flow is not useful and causes
+ // unwanted wrap of body text around in-header floating table, so avoid it.
+ bIsFollowingTextFlow = false;
+ }
+ }
+
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue("IsFollowingTextFlow", bIsFollowingTextFlow));
+ }
+
+ // A text frame created for floating tables is always allowed to split.
+ aFrameProperties.push_back(comphelper::makePropertyValue("IsSplitAllowed", true));
+
+ 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);
+ // 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);
+ uno::Reference<beans::XPropertySet> xFrameAnchor;
+
+ // Writer layout has problems with redlines on floating table rows in footnotes, avoid
+ // them.
+ bool bInFootnote = m_rDMapper_Impl.IsInFootOrEndnote();
+ bool bRecordChanges = m_rDMapper_Impl.GetSettingsTable()->GetRecordChanges();
+ if (xTextAppendAndConvert.is() && !(bInFootnote && bRecordChanges))
+ {
+ std::deque<css::uno::Any> aFramedRedlines = m_rDMapper_Impl.m_aStoredRedlines[StoredRedlines::FRAME];
+ std::vector<sal_Int32> redPos, redLen;
+ std::vector<OUString> redCell;
+ std::vector<OUString> redTable;
+ BeforeConvertToTextFrame(aFramedRedlines, redPos, redLen, redCell, redTable);
+
+ uno::Reference<text::XTextContent> xContent = xTextAppendAndConvert->convertToTextFrame(xStart, xEnd, comphelper::containerToSequence(aFrameProperties));
+ xFrameAnchor.set(xContent->getAnchor(), uno::UNO_QUERY);
+
+ bool bConvertToFloatingInFootnote = false;
+ if (xContent.is() && xContent->getAnchor().is())
+ {
+ uno::Reference<lang::XServiceInfo> xText(xContent->getAnchor()->getText(), uno::UNO_QUERY);
+ if (xText.is())
+ {
+ bConvertToFloatingInFootnote = xText->supportsService("com.sun.star.text.Footnote");
+ }
+ }
+
+ // paragraph of the anchoring point of the floating table needs zero top and bottom
+ // margins, if the table was a not floating table in the footnote, otherwise
+ // docDefault margins could result bigger vertical spaces around the table
+ if ( bConvertToFloatingInFootnote && xContent.is() )
+ {
+ uno::Reference<beans::XPropertySet> xParagraph(
+ xContent->getAnchor(), uno::UNO_QUERY);
+ if ( xParagraph.is() )
+ {
+ xParagraph->setPropertyValue("ParaTopMargin",
+ uno::Any(static_cast<sal_Int32>(0)));
+ xParagraph->setPropertyValue("ParaBottomMargin",
+ uno::Any(static_cast<sal_Int32>(0)));
+ }
+ }
+
+ if (xContent.is())
+ {
+ // By the time the frame is created, the anchor's paragraph marker character
+ // properties are already imported. Check if we need to disable "vanish", that
+ // would lead to a hidden floating table in Writer, but it does not in Word.
+ uno::Reference<beans::XPropertySet> xParagraph(xContent->getAnchor(),
+ uno::UNO_QUERY);
+ if (xParagraph.is())
+ {
+ bool bCharHidden{};
+ xParagraph->getPropertyValue("CharHidden") >>= bCharHidden;
+ if (bCharHidden)
+ {
+ xParagraph->setPropertyValue("CharHidden", uno::Any(false));
+ }
+ }
+ }
+
+ AfterConvertToTextFrame(m_rDMapper_Impl, aFramedRedlines, redPos, redLen, redCell, redTable);
+ }
+
+ if (xFrameAnchor.is() && eBreakType != style::BreakType_NONE)
+ {
+ // A break before the table was requested. Restore that on the anchor.
+ xFrameAnchor->setPropertyValue("BreakType", uno::Any(eBreakType));
+ }
+ }
+ }
+
+ m_aTableProperties.clear();
+ m_aCellProperties.clear();
+ m_aRowProperties.clear();
+
+#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));
+}
+
+DomainMapper_Impl& DomainMapperTableHandler::getDomainMapperImpl()
+{
+ return m_rDMapper_Impl;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapperTableHandler.hxx b/sw/source/writerfilter/dmapper/DomainMapperTableHandler.hxx
new file mode 100644
index 000000000000..376a6d366688
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapperTableHandler.hxx
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "PropertyMap.hxx"
+#include <vector>
+
+#include <com/sun/star/text/XTextAppendAndConvert.hpp>
+
+namespace writerfilter::dmapper {
+
+typedef css::uno::Sequence< css::uno::Reference< css::text::XTextRange > > CellSequence_t;
+typedef css::uno::Sequence<CellSequence_t> RowSequence_t;
+
+typedef css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValues> > CellPropertyValuesSeq_t;
+
+typedef std::vector<PropertyMapPtr> PropertyMapVector1;
+typedef std::vector<PropertyMapVector1> PropertyMapVector2;
+
+class DomainMapper_Impl;
+class TableStyleSheetEntry;
+struct TableInfo;
+
+/// A horizontally merged cell is in fact a range of cells till its merge is performed.
+struct HorizontallyMergedCell
+{
+ sal_Int32 m_nFirstRow;
+ sal_Int32 m_nFirstCol;
+ sal_Int32 m_nLastRow;
+ sal_Int32 m_nLastCol;
+ HorizontallyMergedCell(sal_Int32 nFirstRow, sal_Int32 nFirstCol)
+ : m_nFirstRow(nFirstRow)
+ , m_nFirstCol(nFirstCol)
+ , m_nLastRow(nFirstRow)
+ , m_nLastCol(-1)
+ {
+ }
+};
+
+/// Class to handle events generated by TableManager::resolveCurrentTable().
+class DomainMapperTableHandler final : public virtual SvRefBase
+{
+ css::uno::Reference<css::text::XTextAppendAndConvert> m_xText;
+ DomainMapper_Impl& m_rDMapper_Impl;
+ std::vector< css::uno::Reference<css::text::XTextRange> > m_aCellRange;
+ std::vector<CellSequence_t> m_aRowRanges;
+ std::vector<RowSequence_t> m_aTableRanges;
+
+ // properties
+ PropertyMapVector2 m_aCellProperties;
+ PropertyMapVector1 m_aRowProperties;
+ TablePropertyMapPtr m_aTableProperties;
+
+ TableStyleSheetEntry * endTableGetTableStyle(TableInfo & rInfo,
+ std::vector<css::beans::PropertyValue>& rFrameProperties,
+ bool bConvertToFloating);
+ CellPropertyValuesSeq_t endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges);
+ css::uno::Sequence<css::beans::PropertyValues> endTableGetRowProperties();
+
+public:
+ typedef tools::SvRef<DomainMapperTableHandler> Pointer_t;
+
+ DomainMapperTableHandler(css::uno::Reference<css::text::XTextAppendAndConvert> xText,
+ DomainMapper_Impl& rDMapper_Impl);
+ ~DomainMapperTableHandler() override;
+
+ /**
+ Handle start of table.
+
+ @param pProps properties of the table
+ */
+ void startTable(const TablePropertyMapPtr& pProps);
+
+ void ApplyParagraphPropertiesFromTableStyle(TableParagraph rParaProp, std::vector< PropertyIds > aAllTableProperties, const css::beans::PropertyValues rCellProperties);
+
+ /// Handle end of table.
+ void endTable(unsigned int nestedTableLevel);
+ /**
+ 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);
+
+ DomainMapper_Impl& getDomainMapperImpl();
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapperTableManager.cxx b/sw/source/writerfilter/dmapper/DomainMapperTableManager.cxx
new file mode 100644
index 000000000000..2bbdfe86540e
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapperTableManager.cxx
@@ -0,0 +1,864 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <optional>
+#include "DomainMapperTableManager.hxx"
+#include "ConversionHelper.hxx"
+#include "MeasureHandler.hxx"
+#include "TagLogger.hxx"
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TableColumnSeparator.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <o3tl/numeric.hxx>
+#include <o3tl/safeint.hxx>
+#include <ooxml/resourceids.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <numeric>
+#include "TrackChangesHandler.hxx"
+#include <oox/token/tokens.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+DomainMapperTableManager::DomainMapperTableManager() :
+ m_nRow(0),
+ m_nGridSpan(1),
+ m_nHeaderRepeat(0),
+ m_nTableWidth(0),
+ m_bIsInShape(false),
+ m_bPushCurrentWidth(false),
+ m_bTableSizeTypeInserted(false),
+ m_nLayoutType(0),
+ m_pTablePropsHandler(new TablePropertiesHandler())
+{
+ m_pTablePropsHandler->SetTableManager( this );
+}
+
+
+DomainMapperTableManager::~DomainMapperTableManager()
+{
+}
+
+bool DomainMapperTableManager::attribute(Id nName, Value const & rValue)
+{
+ bool bRet = true;
+
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_TblLook_val:
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_TBL_LOOK, uno::Any(sal_Int32(rValue.getInt())));
+ insertTableProps(pPropMap);
+ m_aTableLook["val"] <<= static_cast<sal_Int32>(rValue.getInt());
+ }
+ break;
+ case NS_ooxml::LN_CT_TblLook_noVBand:
+ m_aTableLook["noVBand"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_noHBand:
+ m_aTableLook["noHBand"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_lastColumn:
+ m_aTableLook["lastColumn"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_lastRow:
+ m_aTableLook["lastRow"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_firstColumn:
+ m_aTableLook["firstColumn"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_TblLook_firstRow:
+ m_aTableLook["firstRow"] <<= static_cast<sal_Int32>(rValue.getInt());
+ break;
+ default:
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+void DomainMapperTableManager::finishTableLook()
+{
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(META_PROP_TABLE_LOOK, uno::Any(m_aTableLook.getAsConstPropertyValueList()));
+ m_aTableLook.clear();
+ insertTableProps(pPropMap);
+}
+
+bool DomainMapperTableManager::sprm(Sprm & rSprm)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.sprm");
+ std::string sSprm = rSprm.toString();
+ TagLogger::getInstance().chars(sSprm);
+ TagLogger::getInstance().endElement();
+#endif
+ bool bRet = TableManager::sprm(rSprm);
+ if( !bRet )
+ {
+ bRet = m_pTablePropsHandler->sprm( rSprm );
+ }
+
+ if ( !bRet )
+ {
+ bRet = true;
+ sal_uInt32 nSprmId = rSprm.getId();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = (pValue ? pValue->getInt() : 0);
+ switch ( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TblPrBase_tblW:
+ case NS_ooxml::LN_CT_TblPrBase_tblInd:
+ {
+ //contains unit and value
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ if (nSprmId == sal_uInt32(NS_ooxml::LN_CT_TblPrBase_tblInd))
+ {
+ pPropMap->setValue( TablePropertyMap::LEFT_MARGIN, pMeasureHandler->getMeasureValue() );
+ }
+ else
+ {
+ m_nTableWidth = pMeasureHandler->getMeasureValue();
+ if( m_nTableWidth )
+ {
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
+ m_bTableSizeTypeInserted = true;
+ }
+ else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_pct )
+ {
+ sal_Int32 nPercent = pMeasureHandler->getValue() / 50;
+ if(nPercent > 100)
+ nPercent = 100;
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, nPercent );
+ m_bTableSizeTypeInserted = true;
+ }
+ else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto )
+ {
+ /*
+ This attribute specifies the width type of table. This is used as part of the table layout
+ algorithm specified by the tblLayout element.(See 17.4.64 and 17.4.65 of the ISO/IEC 29500-1:2011.)
+ If this value is 'auto', the table layout has to use the preferred widths on the table items to generate
+ the final sizing of the table, but then must use the contents of each cell to determine final column widths.
+ (See 17.18.87 of the ISO/IEC 29500-1:2011.)
+ */
+ IntVectorPtr pCellWidths = getCurrentCellWidths();
+ // Check whether all cells have fixed widths in the given row of table.
+ bool bFixed = std::find(pCellWidths->begin(), pCellWidths->end(), -1) == pCellWidths->end();
+ if (!bFixed)
+ {
+ // Set the width type of table with 'Auto' and set the width value to 0 (as per grid values)
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, 0 );
+ m_bTableSizeTypeInserted = true;
+ }
+ else if (getTableDepth() > 1)
+ {
+ // tdf#131819 limiting the fix for nested tables temporarily
+ // TODO revert the fix for tdf#104876 and reopen it
+ m_bTableSizeTypeInserted = true;
+ }
+ }
+ }
+#ifdef DBG_UTIL
+ pPropMap->dumpXml();
+#endif
+ insertTableProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_tblHeader:
+ // if nIntValue == 1 then the row is a repeated header line
+ // to prevent later rows from increasing the repeating m_nHeaderRepeat is set to NULL when repeating stops
+ if( nIntValue > 0 && m_nHeaderRepeat == static_cast<int>(m_nRow) )
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ // FIXME: DOCX tables with more than 10 repeating header lines imported
+ // without repeating header lines to mimic an MSO workaround for its usability bug.
+ // Explanation: it's very hard to set and modify repeating header rows in Word,
+ // often resulting tables with a special workaround: setting all table rows as
+ // repeating header, because exceeding the pages by "unlimited" header rows turns off the
+ // table headers automatically in MSO. 10-row limit is a reasonable temporary limit
+ // to handle DOCX tables with "unlimited" repeating header, till the same "turn off
+ // exceeding header" feature is ready (see tdf#88496).
+#define HEADER_ROW_LIMIT_FOR_MSO_WORKAROUND 10
+ if ( m_nHeaderRepeat == HEADER_ROW_LIMIT_FOR_MSO_WORKAROUND )
+ {
+ m_nHeaderRepeat = -1;
+ pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::Any(sal_Int32(0)));
+ }
+ else
+ {
+ ++m_nHeaderRepeat;
+ pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::Any( m_nHeaderRepeat ));
+ }
+ insertTableProps(pPropMap);
+ }
+ else
+ {
+ if ( nIntValue == 0 && m_nRow == 0 )
+ {
+ // explicit tblHeader=0 in the first row must overwrite table style
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::Any(sal_Int32(0)));
+ insertTableProps(pPropMap);
+ }
+ m_nHeaderRepeat = -1;
+ }
+ if (nIntValue)
+ {
+ // Store the info that this is a header, we'll need that when we apply table styles.
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_TBL_HEADER, uno::Any(nIntValue));
+ insertRowProps(pPropMap);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblStyle: //table style name
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( META_PROP_TABLE_STYLE_NAME, uno::Any( pValue->getString() ));
+ insertTableProps(pPropMap);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblGridBase_gridCol:
+ {
+ if (nIntValue == -1)
+ getCurrentGrid()->clear();
+ else
+ getCurrentGrid()->push_back( nIntValue );
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_vMerge : //vertical merge
+ {
+ // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0
+ TablePropertyMapPtr pMergeProps( new TablePropertyMap );
+ pMergeProps->Insert( PROP_VERTICAL_MERGE, uno::Any( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart ) );
+ cellProps( pMergeProps);
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_hMerge:
+ {
+ // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0
+ TablePropertyMapPtr pMergeProps(new TablePropertyMap());
+ pMergeProps->Insert(PROP_HORIZONTAL_MERGE, uno::Any( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart ));
+ cellProps(pMergeProps);
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_gridSpan: //number of grid positions spanned by this cell
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.GridSpan");
+ TagLogger::getInstance().attribute("gridSpan", nIntValue);
+ TagLogger::getInstance().endElement();
+#endif
+ m_nGridSpan = nIntValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_textDirection:
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ bool bInsertCellProps = true;
+ switch ( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ // Binary filter takes BiDirection into account ( but I have no idea about that here )
+ // or even what it is. But... here's where to handle it if it becomes an issue
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::TB_RL ));
+ SAL_INFO( "writerfilter", "Have inserted textDirection " << nIntValue );
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr:
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::BT_LR ));
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::LR_TB ));
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
+ pPropMap->Insert( PROP_FRM_DIRECTION, uno::Any( text::WritingMode2::TB_RL ));
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
+ default:
+ // Ignore - we can't handle these
+ bInsertCellProps = false;
+ break;
+ }
+ if ( bInsertCellProps )
+ cellProps( pPropMap );
+ break;
+ }
+ case NS_ooxml::LN_CT_TcPrBase_tcW:
+ {
+ // Contains unit and value, but unit is not interesting for
+ // us, later we'll just distribute these values in a
+ // 0..10000 scale.
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler(new MeasureHandler());
+ pProperties->resolve(*pMeasureHandler);
+ if (sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto)
+ getCurrentCellWidths()->push_back(sal_Int32(-1));
+ else
+ // store the original value to limit rounding mistakes, if it's there in a recognized measure (twip)
+ getCurrentCellWidths()->push_back(pMeasureHandler->getMeasureValue() ? pMeasureHandler->getValue() : sal_Int32(0));
+ if (getTableDepthDifference())
+ m_bPushCurrentWidth = true;
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblpPr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ // Ignore <w:tblpPr> in shape text, those tables should be always non-floating ones.
+ if (!m_bIsInShape && pProperties)
+ {
+ TablePositionHandlerPtr pHandler = m_aTmpPosition.back();
+ if ( !pHandler )
+ {
+ m_aTmpPosition.pop_back();
+ pHandler = new TablePositionHandler;
+ m_aTmpPosition.push_back( pHandler );
+ }
+ pProperties->resolve(*m_aTmpPosition.back());
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblOverlap:
+ if (!m_aTmpPosition.empty() && m_aTmpPosition.back())
+ {
+ m_aTmpPosition.back()->setTableOverlap(nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_gridBefore:
+ setCurrentGridBefore( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_gridAfter:
+ setCurrentGridAfter( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCaption:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblDescription:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_tblCellSpacing:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellSpacing:
+ // To-Do: Not yet preserved
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_bidiVisual:
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_WRITING_MODE, uno::Any(sal_Int16(nIntValue ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB)));
+ insertTableProps(pPropMap);
+ break;
+ }
+ default:
+ bRet = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+ return bRet;
+}
+
+DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentGrid( )
+{
+ if (m_aTableGrid.empty())
+ throw std::out_of_range("no current grid");
+ return m_aTableGrid.back( );
+}
+
+DomainMapperTableManager::IntVectorPtr const & DomainMapperTableManager::getCurrentCellWidths( )
+{
+ return m_aCellWidths.back( );
+}
+
+uno::Sequence<beans::PropertyValue> DomainMapperTableManager::getCurrentTablePosition( )
+{
+ if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
+ return m_aTablePositions.back( )->getTablePosition();
+ else
+ return uno::Sequence< beans::PropertyValue >();
+}
+
+TablePositionHandler* DomainMapperTableManager::getCurrentTableRealPosition()
+{
+ if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
+ return m_aTablePositions.back().get();
+ else
+ return nullptr;
+}
+
+const TableParagraphVectorPtr & DomainMapperTableManager::getCurrentParagraphs( )
+{
+ return m_aParagraphsToEndTable.top( );
+}
+
+void DomainMapperTableManager::setIsInShape(bool bIsInShape)
+{
+ m_bIsInShape = bIsInShape;
+}
+
+void DomainMapperTableManager::startLevel( )
+{
+ TableManager::startLevel( );
+
+ // If requested, pop the value that was pushed too early.
+ std::optional<sal_Int32> oCurrentWidth;
+ if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
+ {
+ oCurrentWidth = m_aCellWidths.back()->back();
+ m_aCellWidths.back()->pop_back();
+ }
+ std::optional<TableParagraph> oParagraph;
+ if (getTableDepthDifference() > 0 && !m_aParagraphsToEndTable.empty() && !m_aParagraphsToEndTable.top()->empty())
+ {
+ oParagraph = m_aParagraphsToEndTable.top()->back();
+ m_aParagraphsToEndTable.top()->pop_back();
+ }
+
+ IntVectorPtr pNewGrid = std::make_shared<std::vector<sal_Int32>>();
+ IntVectorPtr pNewCellWidths = std::make_shared<std::vector<sal_Int32>>();
+ TablePositionHandlerPtr pNewPositionHandler;
+ m_aTableGrid.push_back( pNewGrid );
+ m_aCellWidths.push_back( pNewCellWidths );
+ m_aTablePositions.push_back( pNewPositionHandler );
+ // empty name will be replaced by the table style name, if it exists
+ m_aTableStyleNames.push_back( OUString() );
+ m_aMoved.push_back( OUString() );
+
+ TablePositionHandlerPtr pTmpPosition;
+ TablePropertyMapPtr pTmpProperties( new TablePropertyMap( ) );
+ m_aTmpPosition.push_back( pTmpPosition );
+ m_aTmpTableProperties.push_back( pTmpProperties );
+ m_nCell.push_back( 0 );
+ m_nTableWidth = 0;
+ m_nLayoutType = 0;
+ TableParagraphVectorPtr pNewParagraphs = std::make_shared<std::vector<TableParagraph>>();
+ m_aParagraphsToEndTable.push( pNewParagraphs );
+
+ // And push it back to the right level.
+ if (oCurrentWidth)
+ m_aCellWidths.back()->push_back(*oCurrentWidth);
+ if (oParagraph)
+ m_aParagraphsToEndTable.top()->push_back(*oParagraph);
+}
+
+void DomainMapperTableManager::endLevel( )
+{
+ if (m_aTableGrid.empty())
+ {
+ SAL_WARN("writerfilter.dmapper", "Table stack is empty");
+ return;
+ }
+
+ m_aTableGrid.pop_back( );
+
+ // Do the same trick as in startLevel(): pop the value that was pushed too early.
+ std::optional<sal_Int32> oCurrentWidth;
+ if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
+ oCurrentWidth = m_aCellWidths.back()->back();
+ m_aCellWidths.pop_back( );
+ // And push it back to the right level.
+ if (oCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
+ m_aCellWidths.back()->push_back(*oCurrentWidth);
+
+ m_nCell.pop_back( );
+ m_nTableWidth = 0;
+ m_nLayoutType = 0;
+
+ m_aTmpPosition.pop_back( );
+ m_aTmpTableProperties.pop_back( );
+
+ TableManager::endLevel( );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("dmappertablemanager.endLevel");
+ PropertyMapPtr pProps = getTableProps().get();
+ if (pProps)
+ getTableProps()->dumpXml();
+
+ TagLogger::getInstance().endElement();
+#endif
+
+ // Pop back the table position after endLevel as it's used
+ // in the endTable method called in endLevel.
+ m_aTablePositions.pop_back();
+ m_aTableStyleNames.pop_back();
+ m_aMoved.pop_back( );
+
+ std::optional<TableParagraph> oParagraph;
+ if (getTableDepthDifference() < 0 && !m_aParagraphsToEndTable.top()->empty())
+ oParagraph = m_aParagraphsToEndTable.top()->back();
+ m_aParagraphsToEndTable.pop();
+ if (oParagraph && m_aParagraphsToEndTable.size())
+ m_aParagraphsToEndTable.top()->push_back(*oParagraph);
+}
+
+void DomainMapperTableManager::endOfCellAction()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("endOFCellAction");
+#endif
+
+ if ( !isInTable() )
+ throw std::out_of_range("cell without a table");
+ if ( m_nGridSpan > 1 )
+ setCurrentGridSpan( m_nGridSpan );
+ m_nGridSpan = 1;
+ ++m_nCell.back( );
+}
+
+bool DomainMapperTableManager::shouldInsertRow(IntVectorPtr pCellWidths, IntVectorPtr pTableGrid, size_t nGrids, bool& rIsIncompleteGrid)
+{
+ if (pCellWidths->empty())
+ return false;
+ if (m_nLayoutType == NS_ooxml::LN_Value_doc_ST_TblLayout_fixed)
+ return true;
+ if (pCellWidths->size() == nGrids)
+ return true;
+ rIsIncompleteGrid = true;
+ return nGrids > pTableGrid->size();
+}
+
+void DomainMapperTableManager::endOfRowAction()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("endOfRowAction");
+#endif
+
+ // Compare the table position and style with the previous ones. We may need to split
+ // into two tables if those are different. We surely don't want to do anything
+ // if we don't have any row yet.
+ if (m_aTmpPosition.empty())
+ throw std::out_of_range("row without a position");
+ TablePositionHandlerPtr pTmpPosition = m_aTmpPosition.back();
+ TablePropertyMapPtr pTablePropMap = m_aTmpTableProperties.back( );
+ TablePositionHandlerPtr pCurrentPosition = m_aTablePositions.back();
+ bool bSamePosition = ( pTmpPosition == pCurrentPosition ) ||
+ ( pTmpPosition && pCurrentPosition && *pTmpPosition == *pCurrentPosition );
+ bool bIsSetTableStyle = pTablePropMap->isSet(META_PROP_TABLE_STYLE_NAME);
+ OUString sTableStyleName;
+ bool bSameTableStyle = ( !bIsSetTableStyle && m_aTableStyleNames.back().isEmpty()) ||
+ ( bIsSetTableStyle &&
+ (pTablePropMap->getProperty(META_PROP_TABLE_STYLE_NAME)->second >>= sTableStyleName) &&
+ sTableStyleName == m_aTableStyleNames.back() );
+ if ( (!bSamePosition || !bSameTableStyle) && m_nRow > 0 )
+ {
+ // Save the grid infos to have them survive the end/start level
+ IntVectorPtr pTmpTableGrid = m_aTableGrid.back();
+ IntVectorPtr pTmpCellWidths = m_aCellWidths.back();
+ sal_uInt32 nTmpCell = m_nCell.back();
+ TableParagraphVectorPtr pTableParagraphs = getCurrentParagraphs();
+
+ // endLevel and startLevel are taking care of the non finished row
+ // to carry it over to the next table
+ setKeepUnfinishedRow( true );
+ endLevel();
+ setKeepUnfinishedRow( false );
+ startLevel();
+
+ m_aTableGrid.pop_back();
+ m_aCellWidths.pop_back();
+ m_nCell.pop_back();
+ m_aTableGrid.push_back(pTmpTableGrid);
+ m_aCellWidths.push_back(pTmpCellWidths);
+ m_nCell.push_back(nTmpCell);
+ m_aParagraphsToEndTable.pop( );
+ m_aParagraphsToEndTable.push( pTableParagraphs );
+ }
+ // save table style in the first row for comparison
+ if ( m_nRow == 0 && pTablePropMap->isSet(META_PROP_TABLE_STYLE_NAME) )
+ {
+ pTablePropMap->getProperty(META_PROP_TABLE_STYLE_NAME)->second >>= sTableStyleName;
+ m_aTableStyleNames.pop_back();
+ m_aTableStyleNames.push_back( sTableStyleName );
+ }
+
+ // Push the tmp position now that we compared it
+ m_aTablePositions.pop_back();
+ m_aTablePositions.push_back( pTmpPosition );
+ m_aTmpPosition.back().clear( );
+
+
+ IntVectorPtr pTableGrid = getCurrentGrid( );
+ IntVectorPtr pCellWidths = getCurrentCellWidths( );
+ if(!m_nTableWidth && !pTableGrid->empty())
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tableWidth");
+#endif
+
+ for( const auto& rCell : *pTableGrid )
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("col");
+ TagLogger::getInstance().attribute("width", rCell);
+ TagLogger::getInstance().endElement();
+#endif
+
+ m_nTableWidth = o3tl::saturating_add(m_nTableWidth, rCell);
+ }
+ if (m_nTableWidth)
+ // convert sum of grid twip values to 1/100 mm with rounding up to avoid table width loss
+ m_nTableWidth = static_cast<sal_Int32>(ceil(ConversionHelper::convertTwipToMM100Double(m_nTableWidth)));
+
+ if (m_nTableWidth > 0 && !m_bTableSizeTypeInserted)
+ {
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
+ insertTableProps(pPropMap);
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+ }
+
+ std::vector<sal_uInt32> rCurrentSpans = getCurrentGridSpans();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("gridSpans");
+ {
+ for (const auto& rGridSpan : rCurrentSpans)
+ {
+ TagLogger::getInstance().startElement("gridSpan");
+ TagLogger::getInstance().attribute("span", rGridSpan);
+ TagLogger::getInstance().endElement();
+ }
+ }
+ TagLogger::getInstance().endElement();
+#endif
+
+ //calculate number of used grids - it has to match the size of m_aTableGrid
+ size_t nGrids = std::accumulate(rCurrentSpans.begin(), rCurrentSpans.end(), sal::static_int_cast<size_t>(0));
+
+ // sj: the grid is having no units... it is containing only relative values.
+ // a table with a grid of "1:2:1" looks identical as if the table is having
+ // a grid of "20:40:20" and it doesn't have to do something with the tableWidth
+ // -> so we have get the sum of each grid entry for the fullWidthRelative:
+ int nFullWidthRelative = 0;
+ for (int i : (*pTableGrid))
+ nFullWidthRelative = o3tl::saturating_add(nFullWidthRelative, i);
+
+ bool bIsIncompleteGrid = false;
+ if( pTableGrid->size() == nGrids && m_nCell.back( ) > 0 )
+ {
+ /*
+ * If table width property set earlier is smaller than the current table width,
+ * then replace the TABLE_WIDTH property, set earlier.
+ */
+ sal_Int32 nTableWidth(0);
+ sal_Int32 nTableWidthType(text::SizeType::VARIABLE);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType);
+ if ((nTableWidthType == text::SizeType::FIX) && (nTableWidth < m_nTableWidth))
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, m_nTableWidth);
+ }
+ if (nTableWidthType == text::SizeType::VARIABLE )
+ {
+ if(nTableWidth > 100 || nTableWidth <= 0)
+ {
+ if(getTableDepth() > 1 && !m_bTableSizeTypeInserted)
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, sal_Int32(100));
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE);
+ }
+ else
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, m_nTableWidth);
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX);
+ }
+ }
+ }
+ uno::Sequence< text::TableColumnSeparator > aSeparators( getCurrentGridBefore() + m_nCell.back() - 1 );
+ text::TableColumnSeparator* pSeparators = aSeparators.getArray();
+ double nLastRelPos = 0.0;
+ sal_uInt32 nBorderGridIndex = 0;
+
+ size_t nWidthsBound = getCurrentGridBefore() + m_nCell.back() - 1;
+ if (nWidthsBound)
+ {
+ ::std::vector< sal_uInt32 >::const_iterator aSpansIter = rCurrentSpans.begin();
+ for( size_t nBorder = 0; nBorder < nWidthsBound; ++nBorder )
+ {
+ double nRelPos, fGridWidth = 0.;
+ for ( sal_Int32 nGridCount = *aSpansIter; nGridCount > 0; --nGridCount )
+ fGridWidth += (*pTableGrid)[nBorderGridIndex++];
+
+ if (fGridWidth == 0.)
+ {
+ // allow nFullWidthRelative here, with a sane 0.0 result
+ nRelPos = 0.;
+ }
+ else
+ {
+ if (nFullWidthRelative == 0)
+ throw o3tl::divide_by_zero();
+
+ nRelPos = (fGridWidth * 10000) / nFullWidthRelative;
+ }
+
+ pSeparators[nBorder].Position = rtl::math::round(nRelPos + nLastRelPos);
+ pSeparators[nBorder].IsVisible = true;
+ nLastRelPos = nLastRelPos + nRelPos;
+ ++aSpansIter;
+ }
+ }
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::Any( aSeparators ) );
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("rowProperties");
+ pPropMap->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+
+ // set row insertion/deletion at tracked drag & drop of tables
+ OUString aMoved = getMoved();
+ if ( !aMoved.isEmpty() )
+ {
+ auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>(
+ aMoved == getPropertyName( PROP_TABLE_ROW_DELETE )
+ ? oox::XML_tableRowDelete
+ : oox::XML_tableRowInsert );
+ uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties();
+ pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::Any( aTableRedlineProperties ));
+ }
+
+ insertRowProps(pPropMap);
+ }
+ else if (shouldInsertRow(pCellWidths, pTableGrid, nGrids, bIsIncompleteGrid))
+ {
+ // If we're here, then the number of cells does not equal to the amount
+ // defined by the grid, even after taking care of
+ // gridSpan/gridBefore/gridAfter. Handle this by ignoring the grid and
+ // providing the separators based on the provided cell widths, as long
+ // as we have a fixed layout;
+ // On the other hand even if the layout is not fixed, but the cell widths
+ // provided equal the total number of cells, and there are no after/before cells
+ // then use the cell widths to calculate the column separators.
+ // Also handle autofit tables with incomplete grids, when rows can have
+ // different widths and last cells can be wider, than their values.
+ uno::Sequence< text::TableColumnSeparator > aSeparators(pCellWidths->size() - 1);
+ text::TableColumnSeparator* pSeparators = aSeparators.getArray();
+ sal_Int16 nSum = 0;
+ sal_uInt32 nPos = 0;
+
+ if (bIsIncompleteGrid)
+ nFullWidthRelative = 0;
+
+ // Avoid divide by zero (if there's no grid, position using cell widths).
+ if( nFullWidthRelative == 0 )
+ for (size_t i = 0; i < pCellWidths->size(); ++i)
+ nFullWidthRelative += (*pCellWidths)[i];
+
+ if (bIsIncompleteGrid)
+ {
+ /*
+ * If table width property set earlier is smaller than the current table row width,
+ * then replace the TABLE_WIDTH property, set earlier.
+ */
+ sal_Int32 nFullWidth = static_cast<sal_Int32>(ceil(ConversionHelper::convertTwipToMM100Double(nFullWidthRelative)));
+ sal_Int32 nTableWidth(0);
+ sal_Int32 nTableWidthType(text::SizeType::VARIABLE);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
+ pTablePropMap->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType);
+ if (nTableWidth < nFullWidth)
+ {
+ pTablePropMap->setValue(TablePropertyMap::TABLE_WIDTH, nFullWidth);
+ }
+ }
+
+ size_t nWidthsBound = pCellWidths->size() - 1;
+ if (nWidthsBound)
+ {
+ // At incomplete table grids, last cell width can be smaller, than its final width.
+ // Correct it based on the last but one column width and their span values.
+ if ( bIsIncompleteGrid && rCurrentSpans.size()-1 == nWidthsBound )
+ {
+ auto aSpansIter = std::next(rCurrentSpans.begin(), nWidthsBound - 1);
+ sal_Int32 nFixLastCellWidth = (*pCellWidths)[nWidthsBound-1] / *aSpansIter * *std::next(aSpansIter);
+ if (nFixLastCellWidth > (*pCellWidths)[nWidthsBound])
+ nFullWidthRelative += nFixLastCellWidth - (*pCellWidths)[nWidthsBound];
+ }
+
+ // tdf#131203 handle missing w:tblGrid
+ if (nFullWidthRelative > 0)
+ {
+ for (size_t i = 0; i < nWidthsBound; ++i)
+ {
+ nSum += (*pCellWidths)[i];
+ pSeparators[nPos].Position = (nSum * 10000) / nFullWidthRelative; // Relative position
+ pSeparators[nPos].IsVisible = true;
+ nPos++;
+ }
+ }
+ }
+
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::Any( aSeparators ) );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("rowProperties");
+ pPropMap->dumpXml();
+ TagLogger::getInstance().endElement();
+#endif
+ insertRowProps(pPropMap);
+ }
+
+ // Now that potentially opened table is closed, save the table properties
+ TableManager::insertTableProps(pTablePropMap);
+
+ m_aTmpTableProperties.pop_back();
+ TablePropertyMapPtr pEmptyTableProps( new TablePropertyMap() );
+ m_aTmpTableProperties.push_back( pEmptyTableProps );
+
+ ++m_nRow;
+ m_nCell.back( ) = 0;
+ getCurrentGrid()->clear();
+ pCellWidths->clear();
+
+ m_bTableSizeTypeInserted = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void DomainMapperTableManager::clearData()
+{
+ m_nRow = m_nHeaderRepeat = m_nTableWidth = m_nLayoutType = 0;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapperTableManager.hxx b/sw/source/writerfilter/dmapper/DomainMapperTableManager.hxx
new file mode 100644
index 000000000000..6b5cee85743f
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapperTableManager.hxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "TablePropertiesHandler.hxx"
+#include "TablePositionHandler.hxx"
+
+#include "TableManager.hxx"
+#include "PropertyMap.hxx"
+#include <vector>
+#include <memory>
+#include <comphelper/sequenceashashmap.hxx>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+
+class DomainMapperTableManager : public TableManager
+{
+ typedef std::shared_ptr< std::vector<sal_Int32> > IntVectorPtr;
+
+ sal_uInt32 m_nRow;
+ ::std::vector< sal_uInt32 > m_nCell;
+ sal_uInt32 m_nGridSpan;
+ sal_Int32 m_nHeaderRepeat; //counter of repeated headers - if == -1 then the repeating stops
+ sal_Int32 m_nTableWidth; //might be set directly or has to be calculated from the column positions
+ /// Are we in a shape (text append stack is not empty) or in the body document?
+ bool m_bIsInShape;
+ std::vector< OUString > m_aTableStyleNames;
+ /// Moved table (in moveRangeFromStart...moveRangeFromEnd or moveRangeToStart...moveRangeToEnd)
+ std::vector< OUString > m_aMoved;
+ /// Grab-bag of table look attributes for preserving.
+ comphelper::SequenceAsHashMap m_aTableLook;
+ std::vector< TablePositionHandlerPtr > m_aTablePositions;
+ std::vector< TablePositionHandlerPtr > m_aTmpPosition; ///< Temporarily stores the position to compare it later
+ std::vector< TablePropertyMapPtr > m_aTmpTableProperties; ///< Temporarily stores the table properties until end of row
+
+ ::std::vector< IntVectorPtr > m_aTableGrid;
+ /// If this is true, then we pushed a width before the next level started, and that should be carried over when starting the next level.
+ bool m_bPushCurrentWidth;
+ /// Individual table cell width values, used only in case the number of cells doesn't match the table grid.
+ ::std::vector< IntVectorPtr > m_aCellWidths;
+ /// Remember if table width was already set, when we lack a w:tblW, it should be set manually at the end.
+ bool m_bTableSizeTypeInserted;
+ /// Table layout algorithm, IOW if we should consider fixed column width or not.
+ sal_uInt32 m_nLayoutType;
+ /// Collected table paragraphs for table style handling
+ std::stack< TableParagraphVectorPtr > m_aParagraphsToEndTable;
+
+ std::unique_ptr<TablePropertiesHandler> m_pTablePropsHandler;
+ PropertyMapPtr m_pStyleProps;
+
+ bool shouldInsertRow(IntVectorPtr pCellWidths, IntVectorPtr pTableGrid, size_t nGrids, bool& rIsIncompleteGrid);
+
+ virtual void clearData() override;
+
+public:
+
+ DomainMapperTableManager();
+ virtual ~DomainMapperTableManager() override;
+
+ // use this method to avoid adding the properties for the table
+ // but in the provided properties map.
+ void SetStyleProperties(const PropertyMapPtr& pProperties) { m_pStyleProps = pProperties; };
+
+ virtual bool sprm(Sprm & rSprm) override;
+ bool attribute(Id nName, Value const & val);
+
+ virtual void startLevel( ) override;
+ virtual void endLevel( ) override;
+
+ virtual void endOfCellAction() override;
+ virtual void endOfRowAction() override;
+
+ IntVectorPtr const & getCurrentGrid( );
+ IntVectorPtr const & getCurrentCellWidths( );
+ const TableParagraphVectorPtr & getCurrentParagraphs( );
+
+ /// Turn the attributes collected so far in m_aTableLook into a property and clear the container.
+ void finishTableLook();
+ css::uno::Sequence<css::beans::PropertyValue> getCurrentTablePosition();
+ TablePositionHandler* getCurrentTableRealPosition();
+
+ virtual void cellProps(const TablePropertyMapPtr& pProps) override
+ {
+ if ( m_pStyleProps )
+ m_pStyleProps->InsertProps(pProps.get());
+ else
+ TableManager::cellProps( pProps );
+ };
+
+ virtual void insertRowProps(const TablePropertyMapPtr& pProps) override
+ {
+ if ( m_pStyleProps )
+ m_pStyleProps->InsertProps(pProps.get());
+ else
+ TableManager::insertRowProps( pProps );
+ };
+
+ virtual void insertTableProps(const TablePropertyMapPtr& pProps) override
+ {
+ if ( m_pStyleProps )
+ m_pStyleProps->InsertProps(pProps.get());
+ else
+ m_aTmpTableProperties.back()->InsertProps(pProps.get());
+ };
+
+ void SetLayoutType(sal_uInt32 nLayoutType)
+ {
+ m_nLayoutType = nLayoutType;
+ }
+
+ using TableManager::isInCell;
+
+ void setIsInShape(bool bIsInShape);
+
+ // moveFromRangeStart and moveToRangeStart are there
+ // in the first paragraph in the first cell of the
+ // table moved by drag & drop with track changes, but
+ // moveFromRangeEnd and moveToRangeEnd follow the
+ // table element w:tbl in the same level (not in paragraph).
+ // (Special indexing is related to the load of the tables:
+ // first-level tables handled by two levels during the
+ // import, to support table join etc. In the first cell,
+ // setMoved() writes the first level from these two levels
+ // i.e. second startLevel() hasn't been called, yet.)
+ // TODO: check drag & drop of only a part of the tables.
+ void setMoved(OUString sMoved)
+ {
+ if ( m_aMoved.empty() )
+ return;
+
+ if ( !sMoved.isEmpty() )
+ m_aMoved[m_aMoved.size() - 1] = sMoved;
+ else if ( m_aMoved.size() >= 2 )
+ // next table rows weren't moved
+ m_aMoved[m_aMoved.size() - 2] = "";
+ else
+ m_aMoved[m_aMoved.size() - 1] = "";
+ }
+
+ OUString getMoved() const
+ {
+ if ( m_aMoved.size() >= 2 && !m_aMoved[m_aMoved.size() - 2].isEmpty() )
+ return m_aMoved[m_aMoved.size() - 2];
+ else if ( !m_aMoved.empty() )
+ return m_aMoved[m_aMoved.size() -1 ];
+
+ return OUString();
+ }
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
new file mode 100644
index 000000000000..4fdacfb2f944
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.cxx
@@ -0,0 +1,9924 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <ooxml/resourceids.hxx>
+#include "DomainMapper_Impl.hxx"
+#include "ConversionHelper.hxx"
+#include "SdtHelper.hxx"
+#include "DomainMapperTableHandler.hxx"
+#include "TagLogger.hxx"
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/document/PrinterIndependentLayout.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/i18n/NumberFormatMapper.hpp>
+#include <com/sun/star/i18n/NumberFormatIndex.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/style/CaseMap.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/LineNumberPosition.hpp>
+#include <com/sun/star/style/LineSpacing.hpp>
+#include <com/sun/star/style/LineSpacingMode.hpp>
+#include <com/sun/star/text/ChapterFormat.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/text/SetVariableType.hpp>
+#include <com/sun/star/text/XDocumentIndex.hpp>
+#include <com/sun/star/text/XDocumentIndexesSupplier.hpp>
+#include <com/sun/star/text/XFootnote.hpp>
+#include <com/sun/star/text/XEndnotesSupplier.hpp>
+#include <com/sun/star/text/XFootnotesSupplier.hpp>
+#include <com/sun/star/text/XLineNumberingProperties.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/LabelFollow.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/XChapterNumberingSupplier.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/XTextTable.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/awt/FontRelief.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/FontStrikeout.hpp>
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <comphelper/indexedpropertyvalues.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/unotext.hxx>
+#include <o3tl/deleter.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/temporary.hxx>
+#include <oox/mathml/imexport.hxx>
+#include <utility>
+#include <xmloff/odffields.hxx>
+#include <rtl/uri.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <unotools/streamwrap.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/string.hxx>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+
+#include <oox/token/tokens.hxx>
+
+#include <cmath>
+#include <optional>
+#include <map>
+#include <tuple>
+#include <unordered_map>
+#include <regex>
+#include <algorithm>
+
+#include <officecfg/Office/Common.hxx>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/ww8fields.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+#include <com/sun/star/drawing/FillStyle.hpp>
+
+#include <unicode/errorcode.h>
+#include <unicode/regex.h>
+
+#define REFFLDFLAG_STYLE_FROM_BOTTOM 0xc100
+#define REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL 0xc200
+
+using namespace ::com::sun::star;
+using namespace oox;
+namespace writerfilter::dmapper{
+
+//line numbering for header/footer
+static void lcl_linenumberingHeaderFooter( const uno::Reference<container::XNameContainer>& xStyles, const OUString& rname, DomainMapper_Impl* dmapper )
+{
+ const StyleSheetEntryPtr pEntry = dmapper->GetStyleSheetTable()->FindStyleSheetByISTD( rname );
+ if (!pEntry)
+ return;
+ const StyleSheetPropertyMap* pStyleSheetProperties = pEntry->m_pProperties.get();
+ if ( !pStyleSheetProperties )
+ return;
+ sal_Int32 nListId = pStyleSheetProperties->props().GetListId();
+ if( xStyles.is() )
+ {
+ if( xStyles->hasByName( rname ) )
+ {
+ uno::Reference< style::XStyle > xStyle;
+ xStyles->getByName( rname ) >>= xStyle;
+ if( !xStyle.is() )
+ return;
+ uno::Reference<beans::XPropertySet> xPropertySet( xStyle, uno::UNO_QUERY );
+ xPropertySet->setPropertyValue( getPropertyName( PROP_PARA_LINE_NUMBER_COUNT ), uno::Any( nListId >= 0 ) );
+ }
+ }
+}
+
+// Populate Dropdown Field properties from FFData structure
+static void lcl_handleDropdownField( const uno::Reference< beans::XPropertySet >& rxFieldProps, const FFDataHandler::Pointer_t& pFFDataHandler )
+{
+ if ( !rxFieldProps.is() )
+ return;
+
+ if ( !pFFDataHandler->getName().isEmpty() )
+ rxFieldProps->setPropertyValue( "Name", uno::Any( pFFDataHandler->getName() ) );
+
+ const FFDataHandler::DropDownEntries_t& rEntries = pFFDataHandler->getDropDownEntries();
+ uno::Sequence< OUString > sItems( rEntries.size() );
+ ::std::copy( rEntries.begin(), rEntries.end(), sItems.getArray());
+ if ( sItems.hasElements() )
+ rxFieldProps->setPropertyValue( "Items", uno::Any( sItems ) );
+
+ sal_Int32 nResult = pFFDataHandler->getDropDownResult().toInt32();
+ if (nResult > 0 && o3tl::make_unsigned(nResult) < sItems.size())
+ rxFieldProps->setPropertyValue("SelectedItem", uno::Any(sItems[nResult]));
+ if ( !pFFDataHandler->getHelpText().isEmpty() )
+ rxFieldProps->setPropertyValue( "Help", uno::Any( pFFDataHandler->getHelpText() ) );
+}
+
+static void lcl_handleTextField( const uno::Reference< beans::XPropertySet >& rxFieldProps, const FFDataHandler::Pointer_t& pFFDataHandler )
+{
+ if ( rxFieldProps.is() && pFFDataHandler )
+ {
+ rxFieldProps->setPropertyValue
+ (getPropertyName(PROP_HINT),
+ uno::Any(pFFDataHandler->getStatusText()));
+ rxFieldProps->setPropertyValue
+ (getPropertyName(PROP_HELP),
+ uno::Any(pFFDataHandler->getHelpText()));
+ rxFieldProps->setPropertyValue
+ (getPropertyName(PROP_CONTENT),
+ uno::Any(pFFDataHandler->getTextDefault()));
+ }
+}
+
+/**
+ Very similar to DomainMapper_Impl::GetPropertyFromStyleSheet
+ It is focused on paragraph properties search in current & parent stylesheet entries.
+ But it will not take into account properties with listid: these are "list paragraph styles" and
+ not used in some cases.
+*/
+static uno::Any lcl_GetPropertyFromParaStyleSheetNoNum(PropertyIds eId, StyleSheetEntryPtr pEntry, const StyleSheetTablePtr& rStyleSheet)
+{
+ while (pEntry)
+ {
+ if (pEntry->m_pProperties)
+ {
+ std::optional<PropertyMap::Property> aProperty =
+ pEntry->m_pProperties->getProperty(eId);
+ if (aProperty)
+ {
+ if (pEntry->m_pProperties->props().GetListId())
+ // It is a paragraph style with list. Paragraph list styles are not taken into account
+ return uno::Any();
+ else
+ return aProperty->second;
+ }
+ }
+ //search until the property is set or no parent is available
+ StyleSheetEntryPtr pNewEntry;
+ if (!pEntry->m_sBaseStyleIdentifier.isEmpty())
+ pNewEntry = rStyleSheet->FindStyleSheetByISTD(pEntry->m_sBaseStyleIdentifier);
+
+ SAL_WARN_IF(pEntry == pNewEntry, "writerfilter.dmapper", "circular loop in style hierarchy?");
+
+ if (pEntry == pNewEntry) //fdo#49587
+ break;
+
+ pEntry = pNewEntry;
+ }
+ return uno::Any();
+}
+
+
+namespace {
+
+struct FieldConversion
+{
+ const char* cFieldServiceName;
+ FieldId eFieldId;
+};
+
+}
+
+typedef std::unordered_map<OUString, FieldConversion> FieldConversionMap_t;
+
+/// Gives access to the parent field context of the topmost one, if there is any.
+static FieldContextPtr GetParentFieldContext(const std::deque<FieldContextPtr>& rFieldStack)
+{
+ if (rFieldStack.size() < 2)
+ {
+ return nullptr;
+ }
+
+ return rFieldStack[rFieldStack.size() - 2];
+}
+
+/// Decides if the pInner field inside pOuter is allowed in Writer core, depending on their type.
+static bool IsFieldNestingAllowed(const FieldContextPtr& pOuter, const FieldContextPtr& pInner)
+{
+ if (!pInner->GetFieldId())
+ {
+ return true;
+ }
+
+ std::optional<FieldId> oOuterFieldId = pOuter->GetFieldId();
+ if (!oOuterFieldId)
+ {
+ OUString aCommand = pOuter->GetCommand();
+
+ // Ignore leading space before the field name, but don't accept IFF when we check for IF.
+ while (aCommand.getLength() > 3 && aCommand[0] == ' ')
+ aCommand = aCommand.subView(1);
+
+ if (aCommand.startsWith("IF "))
+ {
+ // This will be FIELD_IF once the command is closed.
+ oOuterFieldId = FIELD_IF;
+ }
+ }
+
+ if (!oOuterFieldId)
+ {
+ return true;
+ }
+
+ switch (*oOuterFieldId)
+ {
+ case FIELD_IF:
+ {
+ switch (*pInner->GetFieldId())
+ {
+ case FIELD_DOCVARIABLE:
+ case FIELD_FORMTEXT:
+ case FIELD_FORMULA:
+ case FIELD_IF:
+ case FIELD_MERGEFIELD:
+ case FIELD_REF:
+ case FIELD_PAGE:
+ case FIELD_NUMPAGES:
+ {
+ // LO does not currently know how to evaluate these as conditions or results
+ return false;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+DomainMapper_Impl::DomainMapper_Impl(
+ DomainMapper& rDMapper,
+ uno::Reference<uno::XComponentContext> xContext,
+ uno::Reference<lang::XComponent> const& xModel,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc) :
+ m_eDocumentType( eDocumentType ),
+ m_rDMapper( rDMapper ),
+ m_pOOXMLDocument(nullptr),
+ m_xTextDocument( xModel, uno::UNO_QUERY ),
+ m_xTextFactory( xModel, uno::UNO_QUERY ),
+ m_xComponentContext(std::move( xContext )),
+ m_bForceGenericFields(officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::get()),
+ m_bIsDecimalComma( false ),
+ m_bIsFirstSection( true ),
+ m_bStartTOC(false),
+ m_bStartTOCHeaderFooter(false),
+ m_bStartedTOC(false),
+ m_bStartIndex(false),
+ m_bStartBibliography(false),
+ m_nStartGenericField(0),
+ m_bTextDeleted(false),
+ m_nLastRedlineMovedID(1),
+ m_sCurrentPermId(0),
+ m_bFrameDirectionSet(false),
+ m_bInDocDefaultsImport(false),
+ m_bInStyleSheetImport( false ),
+ m_bInNumberingImport(false),
+ m_bInAnyTableImport( false ),
+ m_bDiscardHeaderFooter( false ),
+ m_eSkipFootnoteState(SkipFootnoteSeparator::OFF),
+ m_nFootnotes(-1),
+ m_nEndnotes(-1),
+ m_nFirstFootnoteIndex(-1),
+ m_nFirstEndnoteIndex(-1),
+ m_bLineNumberingSet( false ),
+ m_bIsParaMarkerChange( false ),
+ m_bIsParaMarkerMove( false ),
+ m_bRedlineImageInPreviousRun( false ),
+ m_bDummyParaAddedForTableInSection( false ),
+ m_bIsLastSectionGroup( false ),
+ m_bUsingEnhancedFields( false ),
+ m_nAnnotationId( -1 ),
+ m_aSmartTagHandler(m_xComponentContext, m_xTextDocument),
+ m_xInsertTextRange(rMediaDesc.getUnpackedValueOrDefault("TextInsertModeRange", uno::Reference<text::XTextRange>())),
+ m_xAltChunkStartingRange(rMediaDesc.getUnpackedValueOrDefault("AltChunkStartingRange", uno::Reference<text::XTextRange>())),
+ m_bIsNewDoc(!rMediaDesc.getUnpackedValueOrDefault("InsertMode", false)),
+ m_bIsAltChunk(rMediaDesc.getUnpackedValueOrDefault("AltChunkMode", false)),
+ m_bIsReadGlossaries(rMediaDesc.getUnpackedValueOrDefault("ReadGlossaries", false)),
+ m_bHasFtnSep(false),
+ m_bIsSplitPara(false),
+ m_bIsActualParagraphFramed( false ),
+ m_bSaxError(false)
+{
+ m_StreamStateStack.emplace(); // add state for document body
+ m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_DOCUMENTBASEURL, OUString());
+ if (m_aBaseUrl.isEmpty()) {
+ m_aBaseUrl = rMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_URL, OUString());
+ }
+
+ appendTableManager( );
+ GetBodyText();
+ if (!m_bIsNewDoc && !m_xBodyText)
+ {
+ throw uno::Exception("failed to find body text of the insert position", nullptr);
+ }
+
+ uno::Reference< text::XTextAppend > xBodyTextAppend( m_xBodyText, uno::UNO_QUERY );
+ m_aTextAppendStack.push(TextAppendContext(xBodyTextAppend,
+ m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : m_xBodyText->createTextCursorByRange(m_xInsertTextRange)));
+
+ //todo: does it makes sense to set the body text as static text interface?
+ uno::Reference< text::XTextAppendAndConvert > xBodyTextAppendAndConvert( m_xBodyText, uno::UNO_QUERY );
+ m_pTableHandler = new DomainMapperTableHandler(xBodyTextAppendAndConvert, *this);
+ getTableManager( ).setHandler(m_pTableHandler);
+
+ getTableManager( ).startLevel();
+ m_bUsingEnhancedFields = !comphelper::IsFuzzing() && officecfg::Office::Common::Filter::Microsoft::Import::ImportWWFieldsAsEnhancedFields::get();
+
+ m_pSdtHelper = new SdtHelper(*this, m_xComponentContext);
+
+ m_aRedlines.push(std::vector<RedlineParamsPtr>());
+
+ if (m_bIsAltChunk)
+ {
+ m_bIsFirstSection = false;
+ }
+}
+
+
+DomainMapper_Impl::~DomainMapper_Impl()
+{
+ assert(!m_StreamStateStack.empty());
+ ChainTextFrames();
+ // Don't remove last paragraph when pasting, sw expects that empty paragraph.
+ if (m_bIsNewDoc)
+ {
+ RemoveLastParagraph();
+ suppress_fun_call_w_exception(GetStyleSheetTable()->ApplyClonedTOCStyles());
+ }
+ if (hasTableManager())
+ {
+ getTableManager().endLevel();
+ popTableManager();
+ }
+}
+
+writerfilter::ooxml::OOXMLDocument* DomainMapper_Impl::getDocumentReference() const
+{
+ return m_pOOXMLDocument;
+}
+
+uno::Reference< container::XNameContainer > const & DomainMapper_Impl::GetPageStyles()
+{
+ if(!m_xPageStyles1.is())
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xSupplier( m_xTextDocument, uno::UNO_QUERY );
+ if (xSupplier.is())
+ xSupplier->getStyleFamilies()->getByName("PageStyles") >>= m_xPageStyles1;
+ }
+ return m_xPageStyles1;
+}
+
+OUString DomainMapper_Impl::GetUnusedPageStyleName()
+{
+ static const char DEFAULT_STYLE[] = "Converted";
+ if (!m_xNextUnusedPageStyleNo)
+ {
+ const uno::Sequence< OUString > aPageStyleNames = GetPageStyles()->getElementNames();
+ sal_Int32 nMaxIndex = 0;
+ // find the highest number x in each style with the name "DEFAULT_STYLE+x" and
+ // return an incremented name
+
+ for ( const auto& rStyleName : aPageStyleNames )
+ {
+ if ( rStyleName.startsWith( DEFAULT_STYLE ) )
+ {
+ sal_Int32 nIndex = o3tl::toInt32(rStyleName.subView( strlen( DEFAULT_STYLE ) ));
+ if ( nIndex > nMaxIndex )
+ nMaxIndex = nIndex;
+ }
+ }
+ m_xNextUnusedPageStyleNo = nMaxIndex + 1;
+ }
+
+ OUString sPageStyleName = DEFAULT_STYLE + OUString::number( *m_xNextUnusedPageStyleNo );
+ *m_xNextUnusedPageStyleNo = *m_xNextUnusedPageStyleNo + 1;
+ return sPageStyleName;
+}
+
+uno::Reference< container::XNameContainer > const & DomainMapper_Impl::GetCharacterStyles()
+{
+ if(!m_xCharacterStyles.is())
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xSupplier( m_xTextDocument, uno::UNO_QUERY );
+ if (xSupplier.is())
+ xSupplier->getStyleFamilies()->getByName("CharacterStyles") >>= m_xCharacterStyles;
+ }
+ return m_xCharacterStyles;
+}
+
+uno::Reference<container::XNameContainer> const& DomainMapper_Impl::GetParagraphStyles()
+{
+ if (!m_xParagraphStyles.is())
+ {
+ uno::Reference<style::XStyleFamiliesSupplier> xSupplier(m_xTextDocument, uno::UNO_QUERY);
+ if (xSupplier.is())
+ xSupplier->getStyleFamilies()->getByName("ParagraphStyles") >>= m_xParagraphStyles;
+ }
+ return m_xParagraphStyles;
+}
+
+OUString DomainMapper_Impl::GetUnusedCharacterStyleName()
+{
+ static const char cListLabel[] = "ListLabel ";
+ if (!m_xNextUnusedCharacterStyleNo)
+ {
+ //search for all character styles with the name sListLabel + <index>
+ const uno::Sequence< OUString > aCharacterStyleNames = GetCharacterStyles()->getElementNames();
+ sal_Int32 nMaxIndex = 0;
+ for ( const auto& rStyleName : aCharacterStyleNames )
+ {
+ OUString sSuffix;
+ if ( rStyleName.startsWith( cListLabel, &sSuffix ) )
+ {
+ sal_Int32 nSuffix = sSuffix.toInt32();
+ if( nSuffix > 0 && nSuffix > nMaxIndex )
+ nMaxIndex = nSuffix;
+ }
+ }
+ m_xNextUnusedCharacterStyleNo = nMaxIndex + 1;
+ }
+
+ OUString sPageStyleName = cListLabel + OUString::number( *m_xNextUnusedCharacterStyleNo );
+ *m_xNextUnusedCharacterStyleNo = *m_xNextUnusedCharacterStyleNo + 1;
+ return sPageStyleName;
+}
+
+uno::Reference< text::XText > const & DomainMapper_Impl::GetBodyText()
+{
+ if(!m_xBodyText.is())
+ {
+ if (m_xInsertTextRange.is())
+ m_xBodyText = m_xInsertTextRange->getText();
+ else if (m_xTextDocument.is())
+ m_xBodyText = m_xTextDocument->getText();
+ }
+ return m_xBodyText;
+}
+
+
+uno::Reference< beans::XPropertySet > const & DomainMapper_Impl::GetDocumentSettings()
+{
+ if( !m_xDocumentSettings.is() && m_xTextFactory.is())
+ {
+ m_xDocumentSettings.set( m_xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY );
+ }
+ return m_xDocumentSettings;
+}
+
+
+void DomainMapper_Impl::SetDocumentSettingsProperty( const OUString& rPropName, const uno::Any& rValue )
+{
+ uno::Reference< beans::XPropertySet > xSettings = GetDocumentSettings();
+ if( xSettings.is() )
+ {
+ try
+ {
+ xSettings->setPropertyValue( rPropName, rValue );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+}
+
+namespace
+{
+void CopyPageDescNameToNextParagraph(const uno::Reference<lang::XComponent>& xParagraph,
+ const uno::Reference<text::XTextCursor>& xCursor)
+{
+ // First check if xParagraph has a non-empty page style name to copy from.
+ uno::Reference<beans::XPropertySet> xParagraphProps(xParagraph, uno::UNO_QUERY);
+ if (!xParagraphProps.is())
+ {
+ return;
+ }
+
+ uno::Any aPageDescName = xParagraphProps->getPropertyValue("PageDescName");
+ OUString sPageDescName;
+ aPageDescName >>= sPageDescName;
+ if (sPageDescName.isEmpty())
+ {
+ return;
+ }
+
+ // If so, search for the next paragraph.
+ uno::Reference<text::XParagraphCursor> xParaCursor(xCursor, uno::UNO_QUERY);
+ if (!xParaCursor.is())
+ {
+ return;
+ }
+
+ // Create a range till the next paragraph and then enumerate on the range.
+ if (!xParaCursor->gotoNextParagraph(/*bExpand=*/true))
+ {
+ return;
+ }
+
+ uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xParaCursor, uno::UNO_QUERY);
+ if (!xEnumerationAccess.is())
+ {
+ return;
+ }
+
+ uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
+ if (!xEnumeration.is())
+ {
+ return;
+ }
+
+ xEnumeration->nextElement();
+ if (!xEnumeration->hasMoreElements())
+ {
+ return;
+ }
+
+ // We found a next item in the enumeration: it's usually a paragraph, but may be a table as
+ // well.
+ uno::Reference<beans::XPropertySet> xNextParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
+ if (!xNextParagraph.is())
+ {
+ return;
+ }
+
+ // See if there is page style set already: if so, don't touch it.
+ OUString sNextPageDescName;
+ xNextParagraph->getPropertyValue("PageDescName") >>= sNextPageDescName;
+ if (!sNextPageDescName.isEmpty())
+ {
+ return;
+ }
+
+ // Finally copy it over, so it's not lost.
+ xNextParagraph->setPropertyValue("PageDescName", aPageDescName);
+}
+}
+
+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);
+ // Make sure no page breaks are lost.
+ CopyPageDescNameToNextParagraph(xParagraph, xCursor);
+ xParagraph->dispose();
+ }
+}
+void DomainMapper_Impl::AddDummyParaForTableInSection()
+{
+ // Shapes and textboxes can't have sections.
+ if (IsInShape() || m_StreamStateStack.top().bIsInTextBox)
+ return;
+
+ if (!m_aTextAppendStack.empty())
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is())
+ {
+ xTextAppend->finishParagraph( uno::Sequence< beans::PropertyValue >() );
+ SetIsDummyParaAddedForTableInSection(true);
+ }
+ }
+}
+
+ static OUString lcl_FindLastBookmark(const uno::Reference<text::XTextCursor>& xCursor,
+ bool bAlreadyExpanded)
+ {
+ OUString sName;
+ if (!xCursor.is())
+ return sName;
+
+ // Select 1 previous element
+ if (!bAlreadyExpanded)
+ xCursor->goLeft(1, true);
+ comphelper::ScopeGuard unselectGuard(
+ [xCursor, bAlreadyExpanded]()
+ {
+ if (!bAlreadyExpanded)
+ xCursor->goRight(1, true);
+ });
+
+ uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xCursor, uno::UNO_QUERY);
+ if (!xParaEnumAccess.is())
+ return sName;
+
+ // Iterate through selection paragraphs
+ uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
+ if (!xParaEnum->hasMoreElements())
+ return sName;
+
+ // Iterate through first para portions
+ uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParaEnum->nextElement(),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ while (xRunEnum->hasMoreElements())
+ {
+ uno::Reference<beans::XPropertySet> xProps(xRunEnum->nextElement(), uno::UNO_QUERY_THROW);
+ uno::Any aType(xProps->getPropertyValue("TextPortionType"));
+ OUString sType;
+ aType >>= sType;
+ if (sType == "Bookmark")
+ {
+ uno::Reference<container::XNamed> xBookmark(xProps->getPropertyValue("Bookmark"),
+ uno::UNO_QUERY_THROW);
+ sName = xBookmark->getName();
+ // Do not stop the scan here. Maybe there are 2 bookmarks?
+ }
+ }
+
+ return sName;
+ }
+
+static void reanchorObjects(const uno::Reference<uno::XInterface>& xFrom,
+ const uno::Reference<text::XTextRange>& xTo,
+ const uno::Reference<drawing::XDrawPage>& xDrawPage)
+{
+ std::vector<uno::Reference<text::XTextContent>> aShapes;
+ bool bFastPathDone = false;
+ if (uno::Reference<beans::XPropertySet> xProps{ xFrom, uno::UNO_QUERY })
+ {
+ try
+ {
+ // See SwXParagraph::Impl::GetPropertyValues_Impl
+ uno::Sequence<uno::Reference<text::XTextContent>> aSeq;
+ xProps->getPropertyValue(u"OOXMLImport_AnchoredShapes"_ustr) >>= aSeq;
+ aShapes.insert(aShapes.end(), aSeq.begin(), aSeq.end());
+ bFastPathDone = true;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+
+ if (!bFastPathDone)
+ {
+ // Can this happen? Fallback to slow DrawPage iteration and range comparison
+ uno::Reference<text::XTextRange> xRange(xFrom, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRangeCompare> xCompare(xRange->getText(), uno::UNO_QUERY_THROW);
+
+ const sal_Int32 count = xDrawPage->getCount();
+ for (sal_Int32 i = 0; i < count; ++i)
+ {
+ try
+ {
+ uno::Reference<text::XTextContent> xShape(xDrawPage->getByIndex(i),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRange> xAnchor(xShape->getAnchor(), uno::UNO_SET_THROW);
+ if (xCompare->compareRegionStarts(xAnchor, xRange) <= 0
+ && xCompare->compareRegionEnds(xAnchor, xRange) >= 0)
+ {
+ aShapes.push_back(xShape);
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ // Can happen e.g. in compareRegion*, when the shape is in a header,
+ // and paragraph in body
+ }
+ }
+ }
+
+ for (const auto& xShape : aShapes)
+ xShape->attach(xTo);
+}
+
+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;
+
+ if (hasTableManager() && getTableManager().getCurrentTablePosition().getLength() != 0)
+ {
+ // If we have an open floating table, then don't remove this paragraph, since that'll be the
+ // anchor of the floating table. Otherwise we would lose the table.
+ return;
+ }
+
+ try
+ {
+ uno::Reference< text::XTextCursor > xCursor;
+ if (m_bIsNewDoc)
+ {
+ xCursor = xTextAppend->createTextCursor();
+ xCursor->gotoEnd(false);
+ }
+ else
+ xCursor.set(m_aTextAppendStack.top().xCursor, uno::UNO_SET_THROW);
+
+ // 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
+ bool const bEndOfDocument(m_aTextAppendStack.size() == 1);
+
+ uno::Reference<lang::XComponent> xParagraph;
+ if (IsInHeaderFooter() || bEndOfDocument)
+ {
+ if (uno::Reference<container::XEnumerationAccess> xEA{ xCursor, uno::UNO_QUERY })
+ {
+ xParagraph.set(xEA->createEnumeration()->nextElement(), uno::UNO_QUERY);
+ }
+ }
+
+ xCursor->goLeft(1, true);
+ // If this is a text on a shape, possibly the text has the trailing
+ // newline removed already. RTF may also not have the trailing newline.
+ 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")))
+ return;
+
+ uno::Reference<beans::XPropertySet> xDocProps(GetTextDocument(), uno::UNO_QUERY_THROW);
+ static constexpr OUString RecordChanges(u"RecordChanges"_ustr);
+
+ comphelper::ScopeGuard redlineRestore(
+ [xDocProps, aPreviousValue = xDocProps->getPropertyValue(RecordChanges)]()
+ { xDocProps->setPropertyValue(RecordChanges, aPreviousValue); });
+
+ // disable redlining, otherwise we might end up with an unwanted recorded operations
+ xDocProps->setPropertyValue(RecordChanges, uno::Any(false));
+
+ if (xParagraph)
+ {
+ // move all anchored objects to the previous paragraph
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(GetTextDocument(),
+ uno::UNO_QUERY_THROW);
+ auto xDrawPage = xDrawPageSupplier->getDrawPage();
+ if (xDrawPage && xDrawPage->hasElements())
+ {
+ // Cursor already spans two paragraphs
+ uno::Reference<container::XEnumerationAccess> xEA(xCursor,
+ uno::UNO_QUERY_THROW);
+ auto xEnumeration = xEA->createEnumeration();
+ uno::Reference<text::XTextRange> xPrevParagraph(xEnumeration->nextElement(),
+ uno::UNO_QUERY_THROW);
+ reanchorObjects(xParagraph, xPrevParagraph, xDrawPage);
+ }
+
+ xParagraph->dispose();
+ }
+ else
+ {
+ // Try to find and remember last bookmark in document: it potentially
+ // can be deleted by xCursor->setString() but not by xParagraph->dispose()
+ OUString sLastBookmarkName;
+ if (bEndOfDocument)
+ sLastBookmarkName = lcl_FindLastBookmark(xCursor, true);
+
+ // The cursor already selects across the paragraph break
+ // delete
+ xCursor->setString(OUString());
+
+ // call to xCursor->setString possibly did remove final bookmark
+ // from previous paragraph. We need to restore it, if there was any.
+ if (sLastBookmarkName.getLength())
+ {
+ OUString sBookmarkNameAfterRemoval = lcl_FindLastBookmark(xCursor, false);
+ if (sBookmarkNameAfterRemoval.isEmpty())
+ {
+ // Yes, it was removed. Restore
+ uno::Reference<text::XTextContent> xBookmark(
+ m_xTextFactory->createInstance("com.sun.star.text.Bookmark"),
+ uno::UNO_QUERY_THROW);
+
+ uno::Reference<container::XNamed> xBkmNamed(xBookmark,
+ uno::UNO_QUERY_THROW);
+ xBkmNamed->setName(sLastBookmarkName);
+ xTextAppend->insertTextContent(xCursor, xBookmark, !xCursor->isCollapsed());
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+
+void DomainMapper_Impl::SetIsLastSectionGroup( bool bIsLast )
+{
+ m_bIsLastSectionGroup = bIsLast;
+}
+
+void DomainMapper_Impl::SetIsLastParagraphInSection( bool bIsLast )
+{
+ m_StreamStateStack.top().bIsLastParaInSection = bIsLast;
+}
+
+
+void DomainMapper_Impl::SetIsFirstParagraphInSection( bool bIsFirst )
+{
+ m_StreamStateStack.top().bIsFirstParaInSection = bIsFirst;
+}
+
+void DomainMapper_Impl::SetIsFirstParagraphInSectionAfterRedline( bool bIsFirstAfterRedline )
+{
+ m_StreamStateStack.top().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_StreamStateStack.top().bIsFirstParaInSectionAfterRedline
+ : m_StreamStateStack.top().bIsFirstParaInSection)
+ && !IsInShape()
+ && !IsInComments()
+ && !IsInFootOrEndnote();
+}
+
+void DomainMapper_Impl::SetIsFirstParagraphInShape(bool bIsFirst)
+{
+ m_StreamStateStack.top().bIsFirstParaInShape = bIsFirst;
+}
+
+void DomainMapper_Impl::SetIsDummyParaAddedForTableInSection( bool bIsAdded )
+{
+ m_bDummyParaAddedForTableInSection = bIsAdded;
+}
+
+
+void DomainMapper_Impl::SetIsTextFrameInserted( bool bIsInserted )
+{
+ m_StreamStateStack.top().bTextFrameInserted = bIsInserted;
+}
+
+void DomainMapper_Impl::SetParaSectpr(bool bParaSectpr)
+{
+ m_StreamStateStack.top().bParaSectpr = bParaSectpr;
+}
+
+void DomainMapper_Impl::SetSdt(bool bSdt)
+{
+ m_StreamStateStack.top().bSdt = bSdt;
+
+ if (m_StreamStateStack.top().bSdt && !m_aTextAppendStack.empty())
+ {
+ m_StreamStateStack.top().xSdtEntryStart = GetTopTextAppend()->getEnd();
+ }
+ else
+ {
+ m_StreamStateStack.top().xSdtEntryStart.clear();
+ }
+}
+
+void DomainMapper_Impl::PushSdt()
+{
+ if (m_aTextAppendStack.empty())
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is())
+ {
+ return;
+ }
+
+ // This may delete text, so call it early, before we would set our start position, which may be
+ // invalidated by a delete.
+ MergeAtContentImageRedlineWithNext(xTextAppend);
+
+ uno::Reference<text::XText> xText = xTextAppend->getText();
+ if (!xText.is())
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextCursor> xCursor
+ = xText->createTextCursorByRange(xTextAppend->getEnd());
+ // Offset so the cursor is not adjusted as we import the SDT's content.
+ bool bStart = !xCursor->goLeft(1, /*bExpand=*/false);
+ m_xSdtStarts.push({bStart, OUString(), xCursor->getStart()});
+}
+
+const std::stack<BookmarkInsertPosition>& DomainMapper_Impl::GetSdtStarts() const
+{
+ return m_xSdtStarts;
+}
+
+void DomainMapper_Impl::PopSdt()
+{
+ if (m_xSdtStarts.empty())
+ {
+ return;
+ }
+
+ BookmarkInsertPosition aPosition = m_xSdtStarts.top();
+ m_xSdtStarts.pop();
+ uno::Reference<text::XTextRange> xStart = aPosition.m_xTextRange;
+ uno::Reference<text::XTextRange> xEnd = GetTopTextAppend()->getEnd();
+ uno::Reference<text::XText> xText = xEnd->getText();
+
+ uno::Reference<text::XTextCursor> xCursor;
+ try
+ {
+ xCursor = xText->createTextCursorByRange(xStart);
+ }
+ catch (const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "DomainMapper_Impl::DomainMapper_Impl::PopSdt: createTextCursorByRange() failed");
+ // We redline form controls and that gets us confused when
+ // we process the SDT around the placeholder. What seems to
+ // happen is we lose the text-range when we pop the SDT position.
+ // Here, we reset the text-range when we fail to create the
+ // cursor from the top SDT position.
+ if (m_aTextAppendStack.empty())
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is())
+ {
+ return;
+ }
+
+ uno::Reference<text::XText> xText2 = xTextAppend->getText();
+ if (!xText2.is())
+ {
+ return;
+ }
+
+ // Reset to the start.
+ xCursor = xText2->createTextCursorByRange(xTextAppend->getStart());
+ }
+
+ if (!xCursor)
+ {
+ SAL_WARN("writerfilter.dmapper", "DomainMapper_Impl::PopSdt: no start position");
+ return;
+ }
+
+ if (aPosition.m_bIsStartOfText)
+ {
+ // Go to the start of the end's paragraph. This helps in case
+ // DomainMapper_Impl::AddDummyParaForTableInSection() would make our range multi-paragraph,
+ // while the intention is to keep start/end inside the same paragraph for run SDTs.
+ uno::Reference<text::XParagraphCursor> xParagraphCursor(xCursor, uno::UNO_QUERY);
+ if (xParagraphCursor.is()
+ && m_pSdtHelper->GetSdtType() == NS_ooxml::LN_CT_SdtRun_sdtContent)
+ {
+ xCursor->gotoRange(xEnd, /*bExpand=*/false);
+ xParagraphCursor->gotoStartOfParagraph(/*bExpand=*/false);
+ }
+ }
+ else
+ {
+ // Undo the goLeft() in DomainMapper_Impl::PushSdt();
+ xCursor->goRight(1, /*bExpand=*/false);
+ }
+ xCursor->gotoRange(xEnd, /*bExpand=*/true);
+
+ std::optional<OUString> oData = m_pSdtHelper->getValueFromDataBinding();
+ if (oData.has_value())
+ {
+ // Data binding has a value for us, prefer that over the in-document value.
+ xCursor->setString(*oData);
+
+ // Such value is always a plain text string, remove the char style of the placeholder.
+ uno::Reference<beans::XPropertyState> xPropertyState(xCursor, uno::UNO_QUERY);
+ if (xPropertyState.is())
+ {
+ xPropertyState->setPropertyToDefault("CharStyleName");
+ }
+ }
+
+ uno::Reference<text::XTextContent> xContentControl(
+ m_xTextFactory->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ if (m_pSdtHelper->GetShowingPlcHdr())
+ {
+ xContentControlProps->setPropertyValue("ShowingPlaceHolder",
+ uno::Any(m_pSdtHelper->GetShowingPlcHdr()));
+ }
+
+ if (!m_pSdtHelper->GetPlaceholderDocPart().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("PlaceholderDocPart",
+ uno::Any(m_pSdtHelper->GetPlaceholderDocPart()));
+ }
+
+ if (!m_pSdtHelper->GetDataBindingPrefixMapping().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("DataBindingPrefixMappings",
+ uno::Any(m_pSdtHelper->GetDataBindingPrefixMapping()));
+ }
+ if (!m_pSdtHelper->GetDataBindingXPath().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("DataBindingXpath",
+ uno::Any(m_pSdtHelper->GetDataBindingXPath()));
+ }
+ if (!m_pSdtHelper->GetDataBindingStoreItemID().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("DataBindingStoreItemID",
+ uno::Any(m_pSdtHelper->GetDataBindingStoreItemID()));
+ }
+
+ if (!m_pSdtHelper->GetColor().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Color",
+ uno::Any(m_pSdtHelper->GetColor()));
+ }
+
+ if (!m_pSdtHelper->GetAppearance().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Appearance",
+ uno::Any(m_pSdtHelper->GetAppearance()));
+ }
+
+ if (!m_pSdtHelper->GetAlias().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Alias",
+ uno::Any(m_pSdtHelper->GetAlias()));
+ }
+
+ if (!m_pSdtHelper->GetTag().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Tag",
+ uno::Any(m_pSdtHelper->GetTag()));
+ }
+
+ if (m_pSdtHelper->GetId())
+ {
+ xContentControlProps->setPropertyValue("Id", uno::Any(m_pSdtHelper->GetId()));
+ }
+
+ if (m_pSdtHelper->GetTabIndex())
+ {
+ xContentControlProps->setPropertyValue("TabIndex", uno::Any(m_pSdtHelper->GetTabIndex()));
+ }
+
+ if (!m_pSdtHelper->GetLock().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Lock", uno::Any(m_pSdtHelper->GetLock()));
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::checkBox)
+ {
+ xContentControlProps->setPropertyValue("Checkbox", uno::Any(true));
+
+ xContentControlProps->setPropertyValue("Checked", uno::Any(m_pSdtHelper->GetChecked()));
+
+ xContentControlProps->setPropertyValue("CheckedState",
+ uno::Any(m_pSdtHelper->GetCheckedState()));
+
+ xContentControlProps->setPropertyValue("UncheckedState",
+ uno::Any(m_pSdtHelper->GetUncheckedState()));
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::dropDown
+ || m_pSdtHelper->getControlType() == SdtControlType::comboBox)
+ {
+ std::vector<OUString>& rDisplayTexts = m_pSdtHelper->getDropDownDisplayTexts();
+ std::vector<OUString>& rValues = m_pSdtHelper->getDropDownItems();
+ if (rDisplayTexts.size() == rValues.size())
+ {
+ uno::Sequence<beans::PropertyValues> aItems(rValues.size());
+ beans::PropertyValues* pItems = aItems.getArray();
+ for (size_t i = 0; i < rValues.size(); ++i)
+ {
+ pItems[i] = {
+ comphelper::makePropertyValue("DisplayText", rDisplayTexts[i]),
+ comphelper::makePropertyValue("Value", rValues[i])
+ };
+ }
+ xContentControlProps->setPropertyValue("ListItems", uno::Any(aItems));
+ if (m_pSdtHelper->getControlType() == SdtControlType::dropDown)
+ {
+ xContentControlProps->setPropertyValue("DropDown", uno::Any(true));
+ }
+ else
+ {
+ xContentControlProps->setPropertyValue("ComboBox", uno::Any(true));
+ }
+ }
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::picture)
+ {
+ xContentControlProps->setPropertyValue("Picture", uno::Any(true));
+ }
+
+ bool bDateFromDataBinding = false;
+ if (m_pSdtHelper->getControlType() == SdtControlType::datePicker)
+ {
+ xContentControlProps->setPropertyValue("Date", uno::Any(true));
+ OUString aDateFormat = m_pSdtHelper->getDateFormat().makeStringAndClear();
+ xContentControlProps->setPropertyValue("DateFormat",
+ uno::Any(aDateFormat.replaceAll("'", "\"")));
+ xContentControlProps->setPropertyValue("DateLanguage",
+ uno::Any(m_pSdtHelper->getLocale().makeStringAndClear()));
+ OUString aCurrentDate = m_pSdtHelper->getDate().makeStringAndClear();
+ if (oData.has_value())
+ {
+ aCurrentDate = *oData;
+ bDateFromDataBinding = true;
+ }
+ xContentControlProps->setPropertyValue("CurrentDate",
+ uno::Any(aCurrentDate));
+ }
+
+ if (m_pSdtHelper->getControlType() == SdtControlType::plainText)
+ {
+ xContentControlProps->setPropertyValue("PlainText", uno::Any(true));
+ }
+
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ if (bDateFromDataBinding)
+ {
+ OUString aDateString;
+ xContentControlProps->getPropertyValue("DateString") >>= aDateString;
+ xCursor->setString(aDateString);
+ }
+
+ m_pSdtHelper->clear();
+}
+
+void DomainMapper_Impl::PushProperties(ContextType eId)
+{
+ PropertyMapPtr pInsert(eId == CONTEXT_SECTION ?
+ (new SectionPropertyMap( m_bIsFirstSection )) :
+ eId == CONTEXT_PARAGRAPH ? new ParagraphPropertyMap : new PropertyMap);
+ if(eId == CONTEXT_SECTION)
+ {
+ if( m_bIsFirstSection )
+ m_bIsFirstSection = false;
+ // beginning with the second section group a section has to be inserted
+ // into the document
+ SectionPropertyMap* pSectionContext_ = dynamic_cast< SectionPropertyMap* >( pInsert.get() );
+ if (!m_aTextAppendStack.empty())
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is() && pSectionContext_)
+ pSectionContext_->SetStart( xTextAppend->getEnd() );
+ }
+ }
+ if(eId == CONTEXT_PARAGRAPH && m_bIsSplitPara)
+ {
+ // Some paragraph properties only apply at the beginning of the paragraph - apply only once.
+ if (!IsFirstRun())
+ {
+ auto pParaContext = static_cast<ParagraphPropertyMap*>(GetTopContextOfType(eId).get());
+ pParaContext->props().SetListId(-1);
+ pParaContext->Erase(PROP_NUMBERING_RULES); // only true with column, not page break
+ pParaContext->Erase(PROP_NUMBERING_LEVEL);
+ pParaContext->Erase(PROP_NUMBERING_TYPE);
+ pParaContext->Erase(PROP_START_WITH);
+
+ pParaContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(sal_uInt32(0)));
+ pParaContext->Erase(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING);
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(sal_uInt32(0)));
+ }
+
+ 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 = dynamic_cast< SectionPropertyMap* >( m_aPropertyStacks[eId].top().get() );
+ assert(m_pLastSectionContext);
+ }
+ }
+ 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.
+ m_StreamStateStack.top().deferredCharacterProperties.clear();
+ }
+
+ if (!IsInFootOrEndnote() && IsInCustomFootnote() && !m_aPropertyStacks[eId].empty())
+ {
+ PropertyMapPtr pRet = m_aPropertyStacks[eId].top();
+ if (pRet->GetFootnote().is() && m_pFootnoteContext.is())
+ EndCustomFootnote();
+ }
+
+ m_aPropertyStacks[eId].pop();
+ m_aContextStack.pop();
+ if(!m_aContextStack.empty() && !m_aPropertyStacks[m_aContextStack.top()].empty())
+
+ m_pTopContext = m_aPropertyStacks[m_aContextStack.top()].top();
+ else
+ {
+ // OSL_ENSURE(eId == CONTEXT_SECTION, "this should happen at a section context end");
+ m_pTopContext.clear();
+ }
+}
+
+
+PropertyMapPtr DomainMapper_Impl::GetTopContextOfType(ContextType eId)
+{
+ PropertyMapPtr pRet;
+ if(!m_aPropertyStacks[eId].empty())
+ pRet = m_aPropertyStacks[eId].top();
+ return pRet;
+}
+
+bool DomainMapper_Impl::HasTopText() const
+{
+ return !m_aTextAppendStack.empty();
+}
+
+uno::Reference< text::XTextAppend > const & DomainMapper_Impl::GetTopTextAppend()
+{
+ OSL_ENSURE(!m_aTextAppendStack.empty(), "text append stack is empty" );
+ return m_aTextAppendStack.top().xTextAppend;
+}
+
+FieldContextPtr const & DomainMapper_Impl::GetTopFieldContext()
+{
+ SAL_WARN_IF(m_aFieldStack.empty(), "writerfilter.dmapper", "Field stack is empty");
+ return m_aFieldStack.back();
+}
+
+bool DomainMapper_Impl::HasTopAnchoredObjects() const
+{
+ return !m_aTextAppendStack.empty() && !m_aTextAppendStack.top().m_aAnchoredObjects.empty();
+}
+
+void DomainMapper_Impl::InitTabStopFromStyle( const uno::Sequence< style::TabStop >& rInitTabStops )
+{
+ OSL_ENSURE(m_aCurrentTabStops.empty(), "tab stops already initialized");
+ for( const auto& rTabStop : rInitTabStops)
+ {
+ m_aCurrentTabStops.emplace_back(rTabStop);
+ }
+}
+
+void DomainMapper_Impl::IncorporateTabStop( const DeletableTabStop & rTabStop )
+{
+ sal_Int32 nConverted = rTabStop.Position;
+ auto aIt = std::find_if(m_aCurrentTabStops.begin(), m_aCurrentTabStops.end(),
+ [&nConverted](const DeletableTabStop& rCurrentTabStop) { return rCurrentTabStop.Position == nConverted; });
+ if( aIt != m_aCurrentTabStops.end() )
+ {
+ if( rTabStop.bDeleted )
+ m_aCurrentTabStops.erase( aIt );
+ else
+ *aIt = rTabStop;
+ }
+ else
+ m_aCurrentTabStops.push_back( rTabStop );
+}
+
+
+uno::Sequence< style::TabStop > DomainMapper_Impl::GetCurrentTabStopAndClear()
+{
+ std::vector<style::TabStop> aRet;
+ for (const DeletableTabStop& rStop : m_aCurrentTabStops)
+ {
+ if (!rStop.bDeleted)
+ aRet.push_back(rStop);
+ }
+ m_aCurrentTabStops.clear();
+ return comphelper::containerToSequence(aRet);
+}
+
+OUString DomainMapper_Impl::GetCurrentParaStyleName()
+{
+ OUString sName;
+ // use saved currParaStyleName as a fallback, in case no particular para style name applied.
+ // tdf#134784 except in the case of first paragraph of shapes to avoid bad fallback.
+ // TODO fix this "highly inaccurate" m_sCurrentParaStyleName
+ if ( !IsInShape() )
+ sName = m_StreamStateStack.top().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->m_sConvertedStyleName.isEmpty() )
+ {
+ if ( !m_bInStyleSheetImport )
+ m_sDefaultParaStyleName = pEntry->m_sConvertedStyleName;
+ return pEntry->m_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->m_pProperties)
+ {
+ std::optional<PropertyMap::Property> aProperty =
+ pEntry->m_pProperties->getProperty(eId);
+ if( aProperty )
+ {
+ if (pIsDocDefault)
+ *pIsDocDefault = pEntry->m_pProperties->isDocDefault(eId);
+
+ return aProperty->second;
+ }
+ }
+ //search until the property is set or no parent is available
+ StyleSheetEntryPtr pNewEntry;
+ if ( !pEntry->m_sBaseStyleIdentifier.isEmpty() )
+ pNewEntry = GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->m_sBaseStyleIdentifier);
+
+ SAL_WARN_IF( pEntry == pNewEntry, "writerfilter.dmapper", "circular loop in style hierarchy?");
+
+ if (pEntry == pNewEntry) //fdo#49587
+ break;
+
+ pEntry = pNewEntry;
+ }
+ // not found in style, try the document's DocDefault properties
+ if ( bDocDefaults && bPara )
+ {
+ const PropertyMapPtr& pDefaultParaProps = GetStyleSheetTable()->GetDefaultParaProps();
+ if ( pDefaultParaProps )
+ {
+ std::optional<PropertyMap::Property> aProperty = pDefaultParaProps->getProperty(eId);
+ if ( aProperty )
+ {
+ if (pIsDocDefault)
+ *pIsDocDefault = true;
+
+ return aProperty->second;
+ }
+ }
+ }
+ if ( bDocDefaults && isCharacterProperty(eId) )
+ {
+ const PropertyMapPtr& pDefaultCharProps = GetStyleSheetTable()->GetDefaultCharProps();
+ if ( pDefaultCharProps )
+ {
+ std::optional<PropertyMap::Property> aProperty = pDefaultCharProps->getProperty(eId);
+ if ( aProperty )
+ {
+ if (pIsDocDefault)
+ *pIsDocDefault = true;
+
+ return aProperty->second;
+ }
+ }
+ }
+
+ if (pIsDocDefault)
+ *pIsDocDefault = false;
+
+ return uno::Any();
+}
+
+uno::Any DomainMapper_Impl::GetPropertyFromParaStyleSheet(PropertyIds eId)
+{
+ StyleSheetEntryPtr pEntry;
+ if ( m_bInStyleSheetImport )
+ pEntry = GetStyleSheetTable()->GetCurrentEntry();
+ else
+ pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(GetCurrentParaStyleName());
+ return GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true);
+}
+
+uno::Any DomainMapper_Impl::GetPropertyFromCharStyleSheet(PropertyIds eId, const PropertyMapPtr& rContext)
+{
+ if ( m_bInStyleSheetImport || eId == PROP_CHAR_STYLE_NAME || !isCharacterProperty(eId) )
+ return uno::Any();
+
+ StyleSheetEntryPtr pEntry;
+ OUString sCharStyleName;
+ if ( GetAnyProperty(PROP_CHAR_STYLE_NAME, rContext) >>= sCharStyleName )
+ pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(sCharStyleName);
+ return GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/false, /*bPara=*/false);
+}
+
+uno::Any DomainMapper_Impl::GetAnyProperty(PropertyIds eId, const PropertyMapPtr& rContext)
+{
+ // first look in directly applied attributes
+ if ( rContext )
+ {
+ std::optional<PropertyMap::Property> aProperty = rContext->getProperty(eId);
+ if ( aProperty )
+ return aProperty->second;
+ }
+
+ // then look whether it was directly applied as a paragraph property
+ PropertyMapPtr pParaContext = GetTopContextOfType(CONTEXT_PARAGRAPH);
+ if (pParaContext && rContext != pParaContext)
+ {
+ std::optional<PropertyMap::Property> aProperty = pParaContext->getProperty(eId);
+ if (aProperty)
+ return aProperty->second;
+ }
+
+ // then look whether it was inherited from a directly applied character style
+ if ( eId != PROP_CHAR_STYLE_NAME && isCharacterProperty(eId) )
+ {
+ uno::Any aRet = GetPropertyFromCharStyleSheet(eId, rContext);
+ if ( aRet.hasValue() )
+ return aRet;
+ }
+
+ // then look in current paragraph style, and docDefaults
+ return GetPropertyFromParaStyleSheet(eId);
+}
+
+OUString DomainMapper_Impl::GetListStyleName(sal_Int32 nListId)
+{
+ auto const pList(GetListTable()->GetList( nListId ));
+ return pList ? pList->GetStyleName() : OUString();
+}
+
+ListsManager::Pointer const & DomainMapper_Impl::GetListTable()
+{
+ if(!m_pListTable)
+ m_pListTable =
+ new ListsManager( m_rDMapper, m_xTextFactory );
+ return m_pListTable;
+}
+
+
+void DomainMapper_Impl::deferBreak( BreakType deferredBreakType)
+{
+ assert(!m_StreamStateStack.empty());
+ switch (deferredBreakType)
+ {
+ case LINE_BREAK:
+ m_StreamStateStack.top().nLineBreaksDeferred++;
+ break;
+ case COLUMN_BREAK:
+ m_StreamStateStack.top().bIsColumnBreakDeferred = true;
+ break;
+ case PAGE_BREAK:
+ // See SwWW8ImplReader::HandlePageBreakChar(), page break should be
+ // ignored inside tables.
+ if (0 < m_StreamStateStack.top().nTableDepth)
+ return;
+
+ m_StreamStateStack.top().bIsPageBreakDeferred = true;
+ break;
+ default:
+ return;
+ }
+}
+
+bool DomainMapper_Impl::isBreakDeferred( BreakType deferredBreakType )
+{
+ assert(!m_StreamStateStack.empty());
+ switch (deferredBreakType)
+ {
+ case LINE_BREAK:
+ return 0 < m_StreamStateStack.top().nLineBreaksDeferred;
+ case COLUMN_BREAK:
+ return m_StreamStateStack.top().bIsColumnBreakDeferred;
+ case PAGE_BREAK:
+ return m_StreamStateStack.top().bIsPageBreakDeferred;
+ default:
+ return false;
+ }
+}
+
+void DomainMapper_Impl::clearDeferredBreak(BreakType deferredBreakType)
+{
+ assert(!m_StreamStateStack.empty());
+ switch (deferredBreakType)
+ {
+ case LINE_BREAK:
+ assert(0 < m_StreamStateStack.top().nLineBreaksDeferred);
+ m_StreamStateStack.top().nLineBreaksDeferred--;
+ break;
+ case COLUMN_BREAK:
+ m_StreamStateStack.top().bIsColumnBreakDeferred = false;
+ break;
+ case PAGE_BREAK:
+ m_StreamStateStack.top().bIsPageBreakDeferred = false;
+ break;
+ default:
+ break;
+ }
+}
+
+void DomainMapper_Impl::clearDeferredBreaks()
+{
+ assert(!m_StreamStateStack.empty());
+ m_StreamStateStack.top().nLineBreaksDeferred = 0;
+ m_StreamStateStack.top().bIsColumnBreakDeferred = false;
+ m_StreamStateStack.top().bIsPageBreakDeferred = false;
+}
+
+void DomainMapper_Impl::setSdtEndDeferred(bool bSdtEndDeferred)
+{
+ m_StreamStateStack.top().bSdtEndDeferred = bSdtEndDeferred;
+}
+
+bool DomainMapper_Impl::isSdtEndDeferred() const
+{
+ return m_StreamStateStack.top().bSdtEndDeferred;
+}
+
+void DomainMapper_Impl::setParaSdtEndDeferred(bool bParaSdtEndDeferred)
+{
+ m_StreamStateStack.top().bParaSdtEndDeferred = bParaSdtEndDeferred;
+}
+
+bool DomainMapper_Impl::isParaSdtEndDeferred() const
+{
+ return m_StreamStateStack.top().bParaSdtEndDeferred;
+}
+
+static void lcl_MoveBorderPropertiesToFrame(std::vector<beans::PropertyValue>& rFrameProperties,
+ uno::Reference<text::XTextRange> const& xStartTextRange,
+ uno::Reference<text::XTextRange> const& xEndTextRange,
+ bool bIsRTFImport)
+{
+ 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
+ };
+
+ // The frame width specified does not include border spacing,
+ // so the frame needs to be increased by the left/right para border spacing amount
+ sal_Int32 nWidth = 0;
+ sal_Int32 nIndexOfWidthProperty = -1;
+ sal_Int16 nType = text::SizeType::FIX;
+ for (size_t i = 0; nType == text::SizeType::FIX && i < rFrameProperties.size(); ++i)
+ {
+ if (rFrameProperties[i].Name == "WidthType")
+ rFrameProperties[i].Value >>= nType;
+ else if (rFrameProperties[i].Name == "Width")
+ nIndexOfWidthProperty = i;
+ }
+ if (nIndexOfWidthProperty > -1 && nType == text::SizeType::FIX)
+ rFrameProperties[nIndexOfWidthProperty].Value >>= nWidth;
+
+ for( size_t nProperty = 0; nProperty < SAL_N_ELEMENTS( aBorderProperties ); ++nProperty)
+ {
+ const OUString & sPropertyName = getPropertyName(aBorderProperties[nProperty]);
+ beans::PropertyValue aValue;
+ aValue.Name = sPropertyName;
+ aValue.Value = xTextRangeProperties->getPropertyValue(sPropertyName);
+ if( nProperty < 4 )
+ {
+ xTextRangeProperties->setPropertyValue( sPropertyName, uno::Any(table::BorderLine2()));
+ if (!aValue.Value.hasValue())
+ aValue.Value <<= table::BorderLine2();
+ }
+ else // border spacing
+ {
+ sal_Int32 nDistance = 0;
+ aValue.Value >>= nDistance;
+
+ // left4/right5 need to be duplicated because of INVERT_BORDER_SPACING (DOCX only)
+ // Do not duplicate the top6/bottom7 border spacing.
+ if (nProperty > 5 || bIsRTFImport)
+ aValue.Value <<= sal_Int32(0);
+
+ // frames need to be increased by the left/right para border spacing amount
+ // This is needed for RTF as well, but that requires other export/import fixes.
+ if (!bIsRTFImport && nProperty < 6 && nWidth && nDistance)
+ {
+ nWidth += nDistance;
+ rFrameProperties[nIndexOfWidthProperty].Value <<= nWidth;
+ }
+ }
+ if (aValue.Value.hasValue())
+ rFrameProperties.push_back(aValue);
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+
+static void lcl_AddRange(
+ ParagraphPropertiesPtr const & pToBeSavedProperties,
+ uno::Reference< text::XTextAppend > const& xTextAppend,
+ 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());
+}
+
+
+//define some default frame width - 0cm ATM: this allow the frame to be wrapped around the text
+constexpr sal_Int32 DEFAULT_FRAME_MIN_WIDTH = 0;
+constexpr sal_Int32 DEFAULT_FRAME_MIN_HEIGHT = 0;
+constexpr sal_Int32 DEFAULT_VALUE = 0;
+
+std::vector<css::beans::PropertyValue>
+DomainMapper_Impl::MakeFrameProperties(const ParagraphProperties& rProps)
+{
+ std::vector<beans::PropertyValue> aFrameProperties;
+
+ try
+ {
+ // A paragraph's properties come from direct formatting or somewhere in the style hierarchy
+ std::vector<const ParagraphProperties*> vProps;
+ vProps.emplace_back(&rProps);
+ sal_Int8 nSafetyLimit = 16;
+ StyleSheetEntryPtr pStyle
+ = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName(rProps.GetParaStyleName());
+ while (nSafetyLimit-- && pStyle && pStyle->m_pProperties)
+ {
+ vProps.emplace_back(&pStyle->m_pProperties->props());
+ assert(pStyle->m_sBaseStyleIdentifier != pStyle->m_sStyleName);
+ if (pStyle->m_sBaseStyleIdentifier.isEmpty())
+ break;
+ pStyle = GetStyleSheetTable()->FindStyleSheetByISTD(pStyle->m_sBaseStyleIdentifier);
+ }
+ SAL_WARN_IF(!nSafetyLimit, "writerfilter.dmapper", "Inheritance loop likely: early exit");
+
+
+ sal_Int32 nWidth = -1;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->Getw() < 0)
+ continue;
+ nWidth = pProp->Getw();
+ break;
+ }
+ 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_WIDTH_TYPE),
+ bAutoWidth ? text::SizeType::MIN : text::SizeType::FIX));
+
+ bool bValidH = false;
+ sal_Int32 nHeight = DEFAULT_FRAME_MIN_HEIGHT;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->Geth() < 0)
+ continue;
+ nHeight = pProp->Geth();
+ bValidH = true;
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_HEIGHT), nHeight));
+
+ sal_Int16 nhRule = -1;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GethRule() < 0)
+ continue;
+ nhRule = pProp->GethRule();
+ break;
+ }
+ if (nhRule < 0)
+ {
+ if (bValidH && nHeight)
+ {
+ // [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));
+
+ bool bValidX = false;
+ sal_Int32 nX = DEFAULT_VALUE;
+ for (const auto pProp : vProps)
+ {
+ bValidX = pProp->IsxValid();
+ if (!bValidX)
+ continue;
+ nX = pProp->Getx();
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_POSITION), nX));
+
+ sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GetxAlign() < 0)
+ continue;
+ nHoriOrient = pProp->GetxAlign();
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), nHoriOrient));
+
+ //Default the anchor in case FramePr_hAnchor is missing ECMA 17.3.1.11
+ sal_Int16 nHAnchor = text::RelOrientation::FRAME; // 'text'
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GethAnchor() < 0)
+ continue;
+ nHAnchor = pProp->GethAnchor();
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT_RELATION), nHAnchor));
+
+ bool bValidY = false;
+ sal_Int32 nY = DEFAULT_VALUE;
+ for (const auto pProp : vProps)
+ {
+ bValidY = pProp->IsyValid();
+ if (!bValidY)
+ continue;
+ nY = pProp->Gety();
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_POSITION), nY));
+
+ sal_Int16 nVertOrient = text::VertOrientation::NONE;
+ // Testing indicates that yAlign should be ignored if there is any specified w:y
+ if (!bValidY)
+ {
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GetyAlign() < 0)
+ continue;
+ nVertOrient = pProp->GetyAlign();
+ break;
+ }
+ }
+
+ // Default the anchor in case FramePr_vAnchor is missing.
+ // ECMA 17.3.1.11 says "page",
+ // but errata documentation MS-OE376 2.1.48 Section 2.3.1.11 says "text"
+ // while actual testing usually indicates "margin" tdf#157572 tdf#112287
+ sal_Int16 nVAnchor = text::RelOrientation::PAGE_PRINT_AREA; // 'margin'
+ if (!nY && (bValidY || nVertOrient == text::VertOrientation::NONE))
+ {
+ // special cases? "auto" position defaults to "paragraph" based on testing when w:y=0
+ nVAnchor = text::RelOrientation::FRAME; // 'text'
+ }
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GetvAnchor() < 0)
+ continue;
+ nVAnchor = pProp->GetvAnchor();
+ // vAlign is ignored if vAnchor is set to 'text'
+ if (nVAnchor == text::RelOrientation::FRAME)
+ nVertOrient = text::VertOrientation::NONE;
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT_RELATION), nVAnchor));
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), nVertOrient));
+
+ text::WrapTextMode nWrap = text::WrapTextMode_NONE;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GetWrap() == text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE)
+ continue;
+ nWrap = pProp->GetWrap();
+ break;
+ }
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_SURROUND), nWrap));
+
+ sal_Int32 nRightDist = 0;
+ sal_Int32 nLeftDist = 0;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GethSpace() < 0)
+ continue;
+ nLeftDist = nRightDist = pProp->GethSpace();
+ break;
+ }
+ 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 = 0;
+ sal_Int32 nTopDist = 0;
+ for (const auto pProp : vProps)
+ {
+ if (pProp->GetvSpace() < 0)
+ continue;
+ nTopDist = nBottomDist = pProp->GetvSpace();
+ break;
+ }
+ 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));
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ return aFrameProperties;
+}
+
+void DomainMapper_Impl::CheckUnregisteredFrameConversion(bool bPreventOverlap)
+{
+ 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;
+
+ std::vector<beans::PropertyValue> aFrameProperties
+ = MakeFrameProperties(*rAppendContext.pLastParagraphProperties);
+
+ if (const std::optional<sal_Int16> nDirection = PopFrameDirection())
+ {
+ aFrameProperties.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_FRM_DIRECTION), *nDirection));
+ }
+
+ if (bPreventOverlap)
+ aFrameProperties.push_back(comphelper::makePropertyValue("AllowOverlap", uno::Any(false)));
+
+ // 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(true) } }));
+ aFrameProperties.push_back(comphelper::makePropertyValue("FrameInteropGrabBag", aGrabBag));
+
+ lcl_MoveBorderPropertiesToFrame(aFrameProperties,
+ rAppendContext.pLastParagraphProperties->GetStartingRange(),
+ rAppendContext.pLastParagraphProperties->GetEndingRange(),
+ IsRTFImport());
+
+ //frame conversion has to be executed after table conversion, not now
+ RegisterFrameConversion(rAppendContext.pLastParagraphProperties->GetStartingRange(),
+ rAppendContext.pLastParagraphProperties->GetEndingRange(),
+ std::move(aFrameProperties));
+}
+
+/// Check if the style or its parent has a list id, recursively.
+static sal_Int32 lcl_getListId(const StyleSheetEntryPtr& rEntry, const StyleSheetTablePtr& rStyleTable, bool & rNumberingFromBaseStyle)
+{
+ const StyleSheetPropertyMap* pEntryProperties = rEntry->m_pProperties.get();
+ if (!pEntryProperties)
+ return -1;
+
+ sal_Int32 nListId = pEntryProperties->props().GetListId();
+ // The style itself has a list id.
+ if (nListId >= 0)
+ return nListId;
+
+ // The style has no parent.
+ if (rEntry->m_sBaseStyleIdentifier.isEmpty())
+ return -1;
+
+ const StyleSheetEntryPtr pParent = rStyleTable->FindStyleSheetByISTD(rEntry->m_sBaseStyleIdentifier);
+ // No such parent style or loop in the style hierarchy.
+ if (!pParent || pParent == rEntry)
+ return -1;
+
+ rNumberingFromBaseStyle = true;
+
+ return lcl_getListId(pParent, rStyleTable, rNumberingFromBaseStyle);
+}
+
+/// Return the paragraph's list level (from styles, unless pParacontext is provided).
+/// -1 indicates the level is not set anywhere. [In that case, with a numId, use 0 (level 1)]
+/// 9 indicates that numbering should be at body level (aka disabled) - rarely used by MSWord.
+/// 0-8 are the nine valid numbering levels.
+sal_Int16 DomainMapper_Impl::GetListLevel(const StyleSheetEntryPtr& pEntry,
+ const PropertyMapPtr& pParaContext)
+{
+ sal_Int16 nListLevel = -1;
+ if (pParaContext)
+ {
+ // Deliberately ignore inherited PROP_NUMBERING_LEVEL. Only trust StyleSheetEntry for that.
+ std::optional<PropertyMap::Property> aLvl = pParaContext->getProperty(PROP_NUMBERING_LEVEL);
+ if (aLvl)
+ aLvl->second >>= nListLevel;
+
+ if (nListLevel != -1)
+ return nListLevel;
+ }
+
+ if (!pEntry)
+ return -1;
+
+ const StyleSheetPropertyMap* pEntryProperties = pEntry->m_pProperties.get();
+ if (!pEntryProperties)
+ return -1;
+
+ nListLevel = pEntryProperties->GetListLevel();
+ // The style itself has a list level.
+ if (nListLevel >= 0)
+ return nListLevel;
+
+ // The style has no parent.
+ if (pEntry->m_sBaseStyleIdentifier.isEmpty())
+ return -1;
+
+ const StyleSheetEntryPtr pParent = GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->m_sBaseStyleIdentifier);
+ // No such parent style or loop in the style hierarchy.
+ if (!pParent || pParent == pEntry)
+ return -1;
+
+ return GetListLevel(pParent);
+}
+
+void DomainMapper_Impl::ValidateListLevel(const OUString& sStyleIdentifierD)
+{
+ StyleSheetEntryPtr pMyStyle = GetStyleSheetTable()->FindStyleSheetByISTD(sStyleIdentifierD);
+ if (!pMyStyle)
+ return;
+
+ sal_Int8 nListLevel = GetListLevel(pMyStyle);
+ if (nListLevel < 0 || nListLevel >= WW_OUTLINE_MAX)
+ return;
+
+ bool bDummy = false;
+ sal_Int16 nListId = lcl_getListId(pMyStyle, GetStyleSheetTable(), bDummy);
+ if (nListId < 1)
+ return;
+
+ auto const pList(GetListTable()->GetList(nListId));
+ if (!pList)
+ return;
+
+ auto pLevel = pList->GetLevel(nListLevel);
+ if (!pLevel && pList->GetAbstractDefinition())
+ pLevel = pList->GetAbstractDefinition()->GetLevel(nListLevel);
+ if (!pLevel)
+ return;
+
+ if (!pLevel->GetParaStyle())
+ {
+ // First come, first served, and it hasn't been claimed yet, so claim it now.
+ pLevel->SetParaStyle(pMyStyle);
+ }
+ else if (pLevel->GetParaStyle() != pMyStyle)
+ {
+ // This level is already used by another style, so prevent numbering via this style
+ // by setting to body level (9).
+ pMyStyle->m_pProperties->SetListLevel(WW_OUTLINE_MAX);
+ // WARNING: PROP_NUMBERING_LEVEL is now out of sync with GetListLevel()
+ }
+}
+
+void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove, const bool bNoNumbering )
+{
+ if (m_bDiscardHeaderFooter)
+ return;
+
+ if (!m_aFieldStack.empty())
+ {
+ FieldContextPtr pFieldContext = m_aFieldStack.back();
+ if (pFieldContext && !pFieldContext->IsCommandCompleted())
+ {
+ std::vector<OUString> aCommandParts = pFieldContext->GetCommandParts();
+ if (!aCommandParts.empty() && aCommandParts[0] == "IF")
+ {
+ // Conditional text field conditions don't support linebreaks in Writer.
+ return;
+ }
+ }
+
+ if (pFieldContext && pFieldContext->IsCommandCompleted())
+ {
+ if (pFieldContext->GetFieldId() == FIELD_IF)
+ {
+ // Conditional text fields can't contain newlines, finish the paragraph later.
+ FieldParagraph aFinish{pPropertyMap, bRemove};
+ pFieldContext->GetParagraphsToFinish().push_back(aFinish);
+ return;
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("finishParagraph");
+#endif
+
+ 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() );
+ SAL_WARN_IF(!pEntry, "writerfilter.dmapper", "no style sheet found");
+ const StyleSheetPropertyMap* pStyleSheetProperties = pEntry ? pEntry->m_pProperties.get() : nullptr;
+ sal_Int32 nListId = pParaContext ? pParaContext->props().GetListId() : -1;
+ bool isNumberingViaStyle(false);
+ bool isNumberingViaRule = nListId > -1;
+ if ( !bRemove && pStyleSheetProperties && pParaContext )
+ {
+ if (!pEntry || pEntry->m_nStyleTypeCode != StyleType::STYLE_TYPE_PARA) {
+ // We could not resolve paragraph style or it is not a paragraph style
+ // Remove this style reference, otherwise it will cause exceptions during further
+ // processing and not all paragraph styles will be initialized.
+ SAL_WARN("writerfilter.dmapper", "Paragraph style is incorrect. Ignored");
+ pParaContext->Erase(PROP_PARA_STYLE_NAME);
+ }
+
+ bool bNumberingFromBaseStyle = false;
+ if (!isNumberingViaRule)
+ nListId = lcl_getListId(pEntry, GetStyleSheetTable(), bNumberingFromBaseStyle);
+
+ //apply numbering level/style to paragraph if it was set at the style, but only if the paragraph itself
+ //does not specify the numbering
+ sal_Int16 nListLevel = GetListLevel(pEntry, pParaContext);
+ // Undefined listLevel with a valid numId is treated as a first level numbering.
+ if (nListLevel == -1 && nListId > (IsOOXMLImport() ? 0 : -1))
+ nListLevel = 0;
+
+ if (!bNoNumbering && nListLevel >= 0 && nListLevel < 9)
+ pParaContext->Insert( PROP_NUMBERING_LEVEL, uno::Any(nListLevel), false );
+
+ auto const pList(GetListTable()->GetList(nListId));
+ if (pList && !pParaContext->isSet(PROP_NUMBERING_STYLE_NAME))
+ {
+ // ListLevel 9 means Body Level/no numbering.
+ if (bNoNumbering || nListLevel == 9)
+ {
+ pParaContext->Insert(PROP_NUMBERING_STYLE_NAME, uno::Any(OUString()), true);
+ pParaContext->Erase(PROP_NUMBERING_LEVEL);
+ }
+ else if ( !isNumberingViaRule )
+ {
+ isNumberingViaStyle = true;
+ // Since LO7.0/tdf#131321 fixed the loss of numbering in styles, this OUGHT to be obsolete,
+ // but now other new/critical LO7.0 code expects it, and perhaps some corner cases still need it as well.
+ pParaContext->Insert(PROP_NUMBERING_STYLE_NAME, uno::Any(pList->GetStyleName()), true);
+ }
+ else
+ {
+ // we have direct numbering, as well as paragraph-style numbering.
+ // Apply the style if it uses the same list as the direct numbering,
+ // otherwise the directly-applied-to-paragraph status will be lost,
+ // and the priority of the numbering-style-indents will be lowered. tdf#133000
+ bool bDummy;
+ if (nListId == lcl_getListId(pEntry, GetStyleSheetTable(), bDummy))
+ pParaContext->Insert( PROP_NUMBERING_STYLE_NAME, uno::Any(pList->GetStyleName()), true );
+ }
+ }
+
+ if ( isNumberingViaStyle )
+ {
+ // When numbering is defined by the paragraph style, then the para-style indents have priority.
+ // But since import has just copied para-style's PROP_NUMBERING_STYLE_NAME directly onto the paragraph,
+ // the numbering indents now have the priority.
+ // So now import must also copy the para-style indents directly onto the paragraph to compensate.
+ std::optional<PropertyMap::Property> oProperty;
+ const StyleSheetEntryPtr pParent = (!pEntry->m_sBaseStyleIdentifier.isEmpty()) ? GetStyleSheetTable()->FindStyleSheetByISTD(pEntry->m_sBaseStyleIdentifier) : nullptr;
+ const StyleSheetPropertyMap* pParentProperties = pParent ? pParent->m_pProperties.get() : nullptr;
+ if (!pEntry->m_sBaseStyleIdentifier.isEmpty())
+ {
+ oProperty = pStyleSheetProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT);
+ if ( oProperty
+ // If the numbering comes from a base style, indent of the base style has also priority.
+ || (bNumberingFromBaseStyle && pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_FIRST_LINE_INDENT))) )
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, oProperty->second, /*bOverwrite=*/false);
+ }
+ oProperty = pStyleSheetProperties->getProperty(PROP_PARA_LEFT_MARGIN);
+ if ( oProperty
+ || (bNumberingFromBaseStyle && pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_LEFT_MARGIN))) )
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, oProperty->second, /*bOverwrite=*/false);
+
+ // We're inheriting properties from a numbering style. Make sure a possible right margin is inherited from the base style.
+ sal_Int32 nParaRightMargin;
+ if ( pParentProperties && (oProperty = pParentProperties->getProperty(PROP_PARA_RIGHT_MARGIN)) && (nParaRightMargin = oProperty->second.get<sal_Int32>()) != 0 )
+ {
+ // If we're setting the right margin, we should set the first / left margin as well from the numbering style.
+ const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, nListLevel, "FirstLineIndent");
+ const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, nListLevel, "IndentAt");
+ if (nFirstLineIndent != 0)
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+ if (nParaLeftMargin != 0)
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+
+ // Override right margin value with value from current style, if any
+ if (pStyleSheetProperties && pStyleSheetProperties->isSet(PROP_PARA_RIGHT_MARGIN))
+ nParaRightMargin = pStyleSheetProperties->getProperty(PROP_PARA_RIGHT_MARGIN)->second.get<sal_Int32>();
+
+ pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, uno::Any(nParaRightMargin), /*bOverwrite=*/false);
+ }
+ }
+ // Paragraph style based right paragraph indentation affects not paragraph style based lists in DOCX.
+ // Apply it as direct formatting, also left and first line indentation of numbering to keep them.
+ else if (isNumberingViaRule)
+ {
+ uno::Any aRightMargin = GetPropertyFromParaStyleSheet(PROP_PARA_RIGHT_MARGIN);
+ if ( aRightMargin != uno::Any() )
+ {
+ pParaContext->Insert(PROP_PARA_RIGHT_MARGIN, aRightMargin, /*bOverwrite=*/false);
+
+ const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, nListLevel, "FirstLineIndent");
+ const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, nListLevel, "IndentAt");
+ if (nFirstLineIndent != 0)
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(nFirstLineIndent), /*bOverwrite=*/false);
+ if (nParaLeftMargin != 0)
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(nParaLeftMargin), /*bOverwrite=*/false);
+ }
+ }
+
+ if (nListId == 0 && !pList)
+ {
+ // listid = 0 and no list definition is used in DOCX to stop numbering
+ // defined somewhere in parent styles
+ // And here we should explicitly set left margin and first-line margin.
+ // They can be taken from referred style, but not from styles with listid!
+ uno::Any aProp = lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_FIRST_LINE_INDENT, pEntry, m_pStyleSheetTable);
+ if (aProp.hasValue())
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, aProp, false);
+ else
+ pParaContext->Insert(PROP_PARA_FIRST_LINE_INDENT, uno::Any(sal_uInt32(0)), false);
+
+ aProp = lcl_GetPropertyFromParaStyleSheetNoNum(PROP_PARA_LEFT_MARGIN, pEntry, m_pStyleSheetTable);
+ if (aProp.hasValue())
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, aProp, false);
+ else
+ pParaContext->Insert(PROP_PARA_LEFT_MARGIN, uno::Any(sal_uInt32(0)), false);
+ }
+ }
+
+ // apply AutoSpacing: it has priority over all other margin settings
+ // (note that numbering with autoSpacing is handled separately later on)
+ const bool bAllowAdjustments = !GetSettingsTable()->GetDoNotUseHTMLParagraphAutoSpacing();
+ sal_Int32 nBeforeAutospacing = -1;
+ bool bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING);
+ const bool bNoTopmargin = pParaContext && !pParaContext->isSet(PROP_PARA_TOP_MARGIN);
+ // apply INHERITED autospacing only if top margin is not set
+ if ( bIsAutoSet || bNoTopmargin )
+ {
+ GetAnyProperty(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, pPropertyMap) >>= nBeforeAutospacing;
+ // tdf#137655 only w:beforeAutospacing=0 was specified, but not PARA_TOP_MARGIN
+ // (see default_spacing = -1 in processing of LN_CT_Spacing_beforeAutospacing)
+ if ( bNoTopmargin && nBeforeAutospacing == ConversionHelper::convertTwipToMM100(-1) )
+ {
+ sal_Int32 nStyleAuto = -1;
+ GetPropertyFromParaStyleSheet(PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING) >>= nStyleAuto;
+ if (nStyleAuto > 0)
+ nBeforeAutospacing = 0;
+ }
+ }
+ if ( nBeforeAutospacing > -1 && pParaContext )
+ {
+ if (bAllowAdjustments)
+ {
+ if ( GetIsFirstParagraphInShape() ||
+ (GetIsFirstParagraphInSection() && GetSectionContext() && GetSectionContext()->IsFirstSection()) ||
+ (m_StreamStateStack.top().bFirstParagraphInCell
+ && 0 < m_StreamStateStack.top().nTableDepth
+ && m_StreamStateStack.top().nTableDepth == m_StreamStateStack.top().nTableCellDepth))
+ {
+ // export requires grabbag to match top_margin, so keep them in sync
+ if (nBeforeAutospacing && bIsAutoSet)
+ pParaContext->Insert( PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, uno::Any( sal_Int32(0) ),true, PARA_GRAB_BAG );
+ nBeforeAutospacing = 0;
+ }
+ }
+ pParaContext->Insert(PROP_PARA_TOP_MARGIN, uno::Any(nBeforeAutospacing));
+ }
+
+ sal_Int32 nAfterAutospacing = -1;
+ bIsAutoSet = pParaContext && pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING);
+ const bool bNoBottomMargin = pParaContext && !pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN);
+ bool bAppliedBottomAutospacing = false;
+ if (bIsAutoSet || bNoBottomMargin)
+ {
+ GetAnyProperty(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, pPropertyMap) >>= nAfterAutospacing;
+ if (bNoBottomMargin && nAfterAutospacing == ConversionHelper::convertTwipToMM100(-1))
+ {
+ sal_Int32 nStyleAuto = -1;
+ GetPropertyFromParaStyleSheet(PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING) >>= nStyleAuto;
+ if (nStyleAuto > 0)
+ nAfterAutospacing = 0;
+ }
+ }
+ if ( nAfterAutospacing > -1 && pParaContext )
+ {
+ pParaContext->Insert(PROP_PARA_BOTTOM_MARGIN, uno::Any(nAfterAutospacing));
+ bAppliedBottomAutospacing = bAllowAdjustments;
+ }
+
+ // tell TableManager to reset the bottom margin if it determines that this is the cell's last paragraph.
+ if ( hasTableManager() && getTableManager().isInCell() )
+ getTableManager().setCellLastParaAfterAutospacing(bAppliedBottomAutospacing);
+
+ if (xTextAppend.is() && pParaContext && hasTableManager() && !getTableManager().isIgnore())
+ {
+ try
+ {
+ /*the following combinations of previous and current frame settings can occur:
+ (1) - no old frame and no current frame -> no special action
+ (2) - no old frame and current DropCap -> save DropCap for later use, don't call finishParagraph
+ remove character properties of the DropCap?
+ (3) - no old frame and current Frame -> save Frame for later use
+ (4) - old DropCap and no current frame -> add DropCap to the properties of the finished paragraph, delete previous setting
+ (5) - old DropCap and current frame -> add DropCap to the properties of the finished paragraph, save current frame settings
+ (6) - old Frame and new DropCap -> add old Frame, save DropCap for later use
+ (7) - old Frame and new same Frame -> continue
+ (8) - old Frame and new different Frame -> add old Frame, save new Frame for later use
+ (9) - old Frame and no current frame -> add old Frame, delete previous settings
+
+ old _and_ new DropCap must not occur
+ */
+
+ // The paragraph style is vital to knowing all the frame properties.
+ std::optional<PropertyMap::Property> aParaStyle
+ = pPropertyMap->getProperty(PROP_PARA_STYLE_NAME);
+ if (aParaStyle)
+ {
+ OUString sName;
+ aParaStyle->second >>= sName;
+ pParaContext->props().SetParaStyleName(sName);
+ }
+
+ bool bIsDropCap =
+ pParaContext->props().IsFrameMode() &&
+ sal::static_int_cast<Id>(pParaContext->props().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->props());
+ 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->props().IsFrameMode() )
+ pToBeSavedProperties = new ParagraphProperties(pParaContext->props());
+ }
+ else
+ {
+ const bool bIsFrameMode(pParaContext->props().IsFrameMode());
+ std::vector<beans::PropertyValue> aCurrFrameProperties;
+ std::vector<beans::PropertyValue> aPrevFrameProperties;
+ if (bIsFrameMode)
+ {
+ aCurrFrameProperties = MakeFrameProperties(pParaContext->props());
+ aPrevFrameProperties
+ = MakeFrameProperties(*rAppendContext.pLastParagraphProperties);
+ }
+
+ if (bIsFrameMode && aPrevFrameProperties == aCurrFrameProperties)
+ {
+ //handles (7)
+ rAppendContext.pLastParagraphProperties->SetEndingRange(
+ rAppendContext.xInsertPosition.is() ? rAppendContext.xInsertPosition
+ : xTextAppend->getEnd());
+ bKeepLastParagraphProperties = true;
+ }
+ else
+ {
+ // handles (8)(9) and completes (6)
+
+ // RTF has an \overlap flag (which we ignore so far)
+ // but DOCX has nothing like that for framePr
+ // Always allow overlap in the RTF case - so there can be no regression.
+
+ // In MSO UI, there is no setting for AllowOverlap for this kind of frame.
+ // Although they CAN overlap with other anchored things,
+ // they do not _easily_ overlap with other framePr's,
+ // so when one frame follows another (8), don't let the first be overlapped.
+ bool bPreventOverlap = !IsRTFImport() && bIsFrameMode && !bIsDropCap;
+
+ // Preventing overlap is emulation - so deny overlap as little as possible.
+ sal_Int16 nVertOrient = text::VertOrientation::NONE;
+ sal_Int16 nVertOrientRelation = text::RelOrientation::FRAME;
+ sal_Int32 nCurrVertPos = 0;
+ sal_Int32 nPrevVertPos = 0;
+ for (size_t i = 0; bPreventOverlap && i < aCurrFrameProperties.size(); ++i)
+ {
+ if (aCurrFrameProperties[i].Name == "VertOrientRelation")
+ {
+ aCurrFrameProperties[i].Value >>= nVertOrientRelation;
+ if (nVertOrientRelation != text::RelOrientation::FRAME)
+ bPreventOverlap = false;
+ }
+ else if (aCurrFrameProperties[i].Name == "VertOrient")
+ {
+ aCurrFrameProperties[i].Value >>= nVertOrient;
+ if (nVertOrient != text::VertOrientation::NONE)
+ bPreventOverlap = false;
+ }
+ else if (aCurrFrameProperties[i].Name == "VertOrientPosition")
+ {
+ aCurrFrameProperties[i].Value >>= nCurrVertPos;
+ // arbitrary value. Assume it must be less than 1st line height
+ if (nCurrVertPos > 20 || nCurrVertPos < -20)
+ bPreventOverlap = false;
+ }
+ }
+ for (size_t i = 0; bPreventOverlap && i < aPrevFrameProperties.size(); ++i)
+ {
+ if (aPrevFrameProperties[i].Name == "VertOrientRelation")
+ {
+ aPrevFrameProperties[i].Value >>= nVertOrientRelation;
+ if (nVertOrientRelation != text::RelOrientation::FRAME)
+ bPreventOverlap = false;
+ }
+ else if (aPrevFrameProperties[i].Name == "VertOrient")
+ {
+ aPrevFrameProperties[i].Value >>= nVertOrient;
+ if (nVertOrient != text::VertOrientation::NONE)
+ bPreventOverlap = false;
+ }
+ else if (aPrevFrameProperties[i].Name == "VertOrientPosition")
+ {
+ aPrevFrameProperties[i].Value >>= nPrevVertPos;
+ if (nPrevVertPos != nCurrVertPos)
+ bPreventOverlap = false;
+ }
+ }
+
+ CheckUnregisteredFrameConversion(bPreventOverlap);
+
+ // If different frame properties are set on this paragraph, keep them.
+ if (!bIsDropCap && bIsFrameMode)
+ {
+ pToBeSavedProperties = new ParagraphProperties(pParaContext->props());
+ lcl_AddRange(pToBeSavedProperties, xTextAppend, rAppendContext);
+ }
+ }
+ }
+ }
+ else
+ {
+ // (1) doesn't need handling
+
+ if( !bIsDropCap && pParaContext->props().IsFrameMode() )
+ {
+ pToBeSavedProperties = new ParagraphProperties(pParaContext->props());
+ lcl_AddRange(pToBeSavedProperties, xTextAppend, rAppendContext);
+ }
+ }
+ applyToggleAttributes(pPropertyMap); // for paragraph marker formatting
+ std::vector<beans::PropertyValue> aProperties;
+ if (pPropertyMap)
+ {
+ aProperties = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pPropertyMap->GetPropertyValues());
+
+ // tdf#64222 filter out the "paragraph marker" formatting and
+ // set it as a separate paragraph property, not a empty hint at
+ // end of paragraph
+ std::vector<beans::NamedValue> charProperties;
+ for (auto it = aProperties.begin(); it != aProperties.end(); )
+ {
+ // this condition isn't ideal but as it happens all
+ // RES_CHRATR_* have names that start with "Char"
+ if (it->Name.startsWith("Char"))
+ {
+ charProperties.emplace_back(it->Name, it->Value);
+ // as testN793262 demonstrates, font size in rPr must
+ // affect the paragraph size => also insert empty hint!
+// it = aProperties.erase(it);
+ }
+ ++it;
+ }
+ if (!charProperties.empty())
+ {
+ aProperties.push_back(beans::PropertyValue("ListAutoFormat",
+ 0, uno::Any(comphelper::containerToSequence(charProperties)), beans::PropertyState_DIRECT_VALUE));
+ }
+ }
+ if( !bIsDropCap )
+ {
+ if( aDrop.Lines > 1 )
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = getPropertyName(PROP_DROP_CAP_FORMAT);
+ aValue.Value <<= aDrop;
+ aProperties.push_back(aValue);
+ }
+ uno::Reference< text::XTextRange > xTextRange;
+ if (rAppendContext.xInsertPosition.is())
+ {
+ xTextRange = xTextAppend->finishParagraphInsert( comphelper::containerToSequence(aProperties), rAppendContext.xInsertPosition );
+ rAppendContext.xCursor->gotoNextParagraph(false);
+ if (rAppendContext.pLastParagraphProperties)
+ rAppendContext.pLastParagraphProperties->SetEndingRange(xTextRange->getEnd());
+ }
+ else
+ {
+ uno::Reference<text::XTextCursor> xCursor;
+ if (m_StreamStateStack.top().bParaHadField
+ && !IsInComments() && !m_xTOCMarkerCursor.is())
+ {
+ // Workaround to make sure char props of the field are not lost.
+ // Not relevant for editeng-based comments.
+ // Not relevant for fields inside a TOC field.
+ xCursor = xTextAppend->getText()->createTextCursor();
+ if (xCursor.is())
+ xCursor->gotoEnd(false);
+ PropertyMapPtr pEmpty(new PropertyMap());
+ appendTextPortion("X", pEmpty);
+ }
+
+ // Check if top / bottom margin has to be updated, now that we know the numbering status of both the previous and
+ // the current text node.
+ auto itNumberingRules = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "NumberingRules";
+ });
+
+ assert( isNumberingViaRule == (itNumberingRules != aProperties.end()) );
+ isNumberingViaRule = (itNumberingRules != aProperties.end());
+ if (m_StreamStateStack.top().xPreviousParagraph.is()
+ && (isNumberingViaRule || isNumberingViaStyle))
+ {
+ // This textnode has numbering. Look up the numbering style name of the current and previous paragraph.
+ OUString aCurrentNumberingName;
+ OUString aPreviousNumberingName;
+ if (isNumberingViaRule)
+ {
+ assert(itNumberingRules != aProperties.end() && "by definition itNumberingRules is valid if isNumberingViaRule is true");
+ uno::Reference<container::XNamed> xCurrentNumberingRules(itNumberingRules->Value, uno::UNO_QUERY);
+ if (xCurrentNumberingRules.is())
+ aCurrentNumberingName = xCurrentNumberingRules->getName();
+ try
+ {
+ uno::Reference<container::XNamed> xPreviousNumberingRules(
+ m_StreamStateStack.top().xPreviousParagraph->getPropertyValue("NumberingRules"),
+ uno::UNO_QUERY_THROW);
+ aPreviousNumberingName = xPreviousNumberingRules->getName();
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "DomainMapper_Impl::finishParagraph NumberingRules");
+ }
+ }
+ else if (m_StreamStateStack.top().xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("NumberingStyleName")
+ // don't update before tables
+ && (m_StreamStateStack.top().nTableDepth == 0
+ || !m_StreamStateStack.top().bFirstParagraphInCell))
+ {
+ aCurrentNumberingName = GetListStyleName(nListId);
+ m_StreamStateStack.top().xPreviousParagraph->getPropertyValue("NumberingStyleName") >>= aPreviousNumberingName;
+ }
+
+ // tdf#133363: remove extra auto space even for mixed list styles
+ if (!aPreviousNumberingName.isEmpty()
+ && (aCurrentNumberingName == aPreviousNumberingName
+ || !isNumberingViaRule))
+ {
+ uno::Sequence<beans::PropertyValue> aPrevPropertiesSeq;
+ m_StreamStateStack.top().xPreviousParagraph->getPropertyValue("ParaInteropGrabBag") >>= aPrevPropertiesSeq;
+ const auto & rPrevProperties = aPrevPropertiesSeq;
+ bool bParaAutoBefore = m_StreamStateStack.top().bParaAutoBefore
+ || std::any_of(rPrevProperties.begin(), rPrevProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaTopMarginBeforeAutoSpacing";
+ });
+ // if style based spacing was set to auto in the previous paragraph, style of the actual paragraph must be the same
+ if (bParaAutoBefore && !m_StreamStateStack.top().bParaAutoBefore
+ && m_StreamStateStack.top().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_StreamStateStack.top().xPreviousParagraph->getPropertyValue("ParaStyleName") == itParaStyle->Value;
+ }
+ // There was a previous textnode and it had the same numbering.
+ if (bParaAutoBefore)
+ {
+ // This before spacing is set to auto, set before space to 0.
+ auto itParaTopMargin = std::find_if(aProperties.begin(), aProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaTopMargin";
+ });
+ if (itParaTopMargin != aProperties.end())
+ itParaTopMargin->Value <<= static_cast<sal_Int32>(0);
+ else
+ aProperties.push_back(comphelper::makePropertyValue("ParaTopMargin", static_cast<sal_Int32>(0)));
+ }
+
+ bool bPrevParaAutoAfter = std::any_of(rPrevProperties.begin(), rPrevProperties.end(), [](const beans::PropertyValue& rValue)
+ {
+ return rValue.Name == "ParaBottomMarginAfterAutoSpacing";
+ });
+ if (bPrevParaAutoAfter)
+ {
+ // Previous after spacing is set to auto, set previous after space to 0.
+ m_StreamStateStack.top().xPreviousParagraph->setPropertyValue("ParaBottomMargin", uno::Any(static_cast<sal_Int32>(0)));
+ }
+ }
+ }
+
+ // apply redlines for inline images
+ if (IsParaWithInlineObject())
+ {
+ for (const auto& rAnchored : rAppendContext.m_aAnchoredObjects)
+ {
+ // process only inline objects with redlining
+ if (!rAnchored.m_xRedlineForInline)
+ continue;
+
+ // select the inline image and set its redline
+ auto xAnchorRange = rAnchored.m_xAnchoredObject->getAnchor();
+ uno::Reference< text::XTextCursor > xCursorOnImage =
+ xAnchorRange->getText()->createTextCursorByRange(xAnchorRange);
+ xCursorOnImage->goRight(1, true);
+ CreateRedline( xCursorOnImage, rAnchored.m_xRedlineForInline );
+ }
+ }
+
+ xTextRange = xTextAppend->finishParagraph( comphelper::containerToSequence(aProperties) );
+ m_StreamStateStack.top().xPreviousParagraph.set(xTextRange, uno::UNO_QUERY);
+
+ if (m_StreamStateStack.top().xPreviousParagraph.is() && // null for SvxUnoTextBase
+ (isNumberingViaStyle || isNumberingViaRule))
+ {
+ assert(pParaContext);
+ if (ListDef::Pointer const& pList = m_pListTable->GetList(nListId))
+ { // styles could refer to non-existing lists...
+ AbstractListDef::Pointer const& pAbsList =
+ pList->GetAbstractDefinition();
+ if (pAbsList &&
+ // SvxUnoTextRange doesn't have ListId
+ m_StreamStateStack.top().xPreviousParagraph->getPropertySetInfo()->hasPropertyByName("ListId"))
+ {
+ OUString paraId;
+ m_StreamStateStack.top().xPreviousParagraph->getPropertyValue("ListId") >>= paraId;
+ if (!paraId.isEmpty()) // must be on some list?
+ {
+ OUString const listId = pAbsList->MapListId(paraId);
+ if (listId != paraId)
+ {
+ m_StreamStateStack.top().xPreviousParagraph->setPropertyValue("ListId", uno::Any(listId));
+ }
+ }
+ }
+
+ sal_Int16 nCurrentLevel = GetListLevel(pEntry, pPropertyMap);
+ if (nCurrentLevel == -1)
+ nCurrentLevel = 0;
+
+ const ListLevel::Pointer pListLevel = pList->GetLevel(nCurrentLevel);
+ if (pListLevel)
+ {
+ sal_Int16 nOverrideLevel = pListLevel->GetStartOverride();
+ if (nOverrideLevel != -1 && m_aListOverrideApplied.find(nListId) == m_aListOverrideApplied.end())
+ {
+ // Apply override: we have override instruction for this level
+ // And this was not done for this list before: we can do this only once on first occurrence
+ // of list with override
+ // TODO: Not tested variant with different levels override in different lists.
+ // Probably m_aListOverrideApplied as a set of overridden listids is not sufficient
+ // and we need to register level overrides separately.
+ m_StreamStateStack.top().xPreviousParagraph->setPropertyValue("ParaIsNumberingRestart", uno::Any(true));
+ m_StreamStateStack.top().xPreviousParagraph->setPropertyValue("NumberingStartValue", uno::Any(nOverrideLevel));
+ m_aListOverrideApplied.insert(nListId);
+ }
+ }
+ }
+ }
+
+ if (!rAppendContext.m_aAnchoredObjects.empty() && !IsInHeaderFooter())
+ {
+ // Remember what objects are anchored to this paragraph.
+ // That list is only used for Word compat purposes, and
+ // it is only relevant for body text.
+ AnchoredObjectsInfo aInfo;
+ aInfo.m_xParagraph = xTextRange;
+ aInfo.m_aAnchoredObjects = rAppendContext.m_aAnchoredObjects;
+ m_aAnchoredObjectAnchors.push_back(aInfo);
+ rAppendContext.m_aAnchoredObjects.clear();
+ }
+
+ 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 (0 < m_StreamStateStack.top().nTableDepth && 0 < nMode && nMode <= 14)
+ {
+ // skip new line
+ xCur->goLeft(1, false);
+ while ( xCur->goLeft(1, true) )
+ {
+ OUString sChar = xCur->getString();
+ if ( sChar == " " || sChar == "\t" || sChar == OUStringChar(u'\x00A0') )
+ xCur->setString("");
+ else
+ break;
+ }
+
+ if (rAppendContext.xInsertPosition.is())
+ xCur->gotoRange(rAppendContext.xInsertPosition, false);
+ else
+ xCur->gotoEnd(false);
+ }
+
+ xCur->goLeft( 1 , true );
+ // Extend the redline ranges for empty paragraphs
+ if (!m_StreamStateStack.top().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 && !IsInComments()
+ && (0 < m_StreamStateStack.top().nTableDepth
+ || !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 (0 < m_StreamStateStack.top().nTableDepth)
+ {
+ TableParagraph aPending{xParaCursor, xCur, pParaContext, xParaProps};
+ getTableManager().getCurrentParagraphs()->push_back(aPending);
+ }
+
+ // hidden empty paragraph with a not hidden shape, set as not hidden
+ std::optional<PropertyMap::Property> pHidden;
+ if ( !m_aAnchoredObjectAnchors.empty() && (pHidden = pParaContext->getProperty(PROP_CHAR_HIDDEN)) )
+ {
+ bool bIsHidden = {}; // -Werror=maybe-uninitialized
+ pHidden->second >>= bIsHidden;
+ if (bIsHidden)
+ {
+ bIsHidden = false;
+ pHidden = GetTopContext()->getProperty(PROP_CHAR_HIDDEN);
+ if (pHidden)
+ pHidden->second >>= bIsHidden;
+ if (!bIsHidden)
+ {
+ uno::Reference<text::XTextCursor> xCur3 = xTextRange->getText()->createTextCursorByRange(xParaCursor);
+ xCur3->goRight(1, true);
+ if (xCur3->getString() == SAL_NEWLINE_STRING)
+ {
+ uno::Reference< beans::XPropertySet > xProp( xCur3, uno::UNO_QUERY );
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_HIDDEN), uno::Any(false));
+ }
+ }
+ }
+ }
+ }
+
+ // tdf#118521 set paragraph top or bottom margin based on the paragraph style
+ // if we already set the other margin with direct formatting
+ if (xParaProps)
+ {
+ const bool bTopSet = pParaContext->isSet(PROP_PARA_TOP_MARGIN);
+ const bool bBottomSet = pParaContext->isSet(PROP_PARA_BOTTOM_MARGIN);
+ const bool bContextSet = pParaContext->isSet(PROP_PARA_CONTEXT_MARGIN);
+ if ( bTopSet != bBottomSet || bBottomSet != bContextSet )
+ {
+
+ if ( !bTopSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_TOP_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaTopMargin", aMargin);
+ }
+ if ( !bBottomSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_BOTTOM_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaBottomMargin", aMargin);
+ }
+ if ( !bContextSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_CONTEXT_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaContextMargin", aMargin);
+ }
+ }
+ }
+
+ // Left, Right, and Hanging settings are also grouped. Ensure that all or none are set.
+ if (xParaProps)
+ {
+ const bool bLeftSet = pParaContext->isSet(PROP_PARA_LEFT_MARGIN);
+ const bool bRightSet = pParaContext->isSet(PROP_PARA_RIGHT_MARGIN);
+ const bool bFirstSet = pParaContext->isSet(PROP_PARA_FIRST_LINE_INDENT);
+ if (bLeftSet != bRightSet || bRightSet != bFirstSet)
+ {
+ if ( !bLeftSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_LEFT_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaLeftMargin", aMargin);
+ else if (isNumberingViaStyle)
+ {
+ const sal_Int32 nParaLeftMargin = getNumberingProperty(nListId, GetListLevel(pEntry, pPropertyMap), "IndentAt");
+ if (nParaLeftMargin != 0)
+ xParaProps->setPropertyValue("ParaLeftMargin", uno::Any(nParaLeftMargin));
+ }
+ }
+ if ( !bRightSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_RIGHT_MARGIN);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaRightMargin", aMargin);
+ }
+ if ( !bFirstSet )
+ {
+ uno::Any aMargin = GetPropertyFromParaStyleSheet(PROP_PARA_FIRST_LINE_INDENT);
+ if ( aMargin != uno::Any() )
+ xParaProps->setPropertyValue("ParaFirstLineIndent", aMargin);
+ else if (isNumberingViaStyle)
+ {
+ const sal_Int32 nFirstLineIndent = getNumberingProperty(nListId, GetListLevel(pEntry, pPropertyMap), "FirstLineIndent");
+ if (nFirstLineIndent != 0)
+ xParaProps->setPropertyValue("ParaFirstLineIndent", uno::Any(nFirstLineIndent));
+ }
+ }
+ }
+ }
+ }
+ if( !bKeepLastParagraphProperties )
+ rAppendContext.pLastParagraphProperties = pToBeSavedProperties;
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "DomainMapper_Impl::finishParagraph" );
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "finishParagraph()" );
+ }
+
+ }
+
+ bool bIgnoreFrameState = IsInHeaderFooter();
+ if( (!bIgnoreFrameState && pParaContext && pParaContext->props().IsFrameMode()) || (bIgnoreFrameState && GetIsPreviousParagraphFramed()) )
+ SetIsPreviousParagraphFramed(true);
+ else
+ SetIsPreviousParagraphFramed(false);
+
+ m_StreamStateStack.top().bRemoveThisParagraph = false;
+ if( !IsInHeaderFooter() && !IsInShape()
+ && (!pParaContext || !pParaContext->props().IsFrameMode()) )
+ { // If the paragraph is in a frame, shape or header/footer, it's not a paragraph of the section itself.
+ SetIsFirstParagraphInSection(false);
+ // don't count an empty deleted paragraph as first paragraph in section to avoid of
+ // the deletion of the next empty paragraph later, resulting loss of the associated page break
+ if (!m_previousRedline || m_StreamStateStack.top().bParaChanged)
+ {
+ SetIsFirstParagraphInSectionAfterRedline(false);
+ SetIsLastParagraphInSection(false);
+ }
+ }
+ m_previousRedline.clear();
+ m_StreamStateStack.top().bParaChanged = false;
+
+ if (IsInComments() && pParaContext)
+ {
+ if (const OUString sParaId = pParaContext->props().GetParaId(); !sParaId.isEmpty())
+ {
+ if (const auto& item = m_aCommentProps.find(sParaId); item != m_aCommentProps.end())
+ {
+ m_bAnnotationResolved = item->second.bDone;
+ m_sAnnotationParent = item->second.sParaIdParent;
+ }
+ m_sAnnotationImportedParaId = sParaId;
+ }
+ }
+
+ if (m_StreamStateStack.top().bIsFirstParaInShape)
+ m_StreamStateStack.top().bIsFirstParaInShape = false;
+
+ if (pParaContext)
+ {
+ // Reset the frame properties for the next paragraph
+ pParaContext->props().ResetFrameProperties();
+ }
+
+ SetIsOutsideAParagraph(true);
+ m_StreamStateStack.top().bParaHadField = false;
+
+ // don't overwrite m_bFirstParagraphInCell in table separator nodes
+ // and in text boxes anchored to the first paragraph of table cells
+ if (0 < m_StreamStateStack.top().nTableDepth
+ && m_StreamStateStack.top().nTableDepth == m_StreamStateStack.top().nTableCellDepth
+ && !IsInShape() && !IsInComments())
+ {
+ m_StreamStateStack.top().bFirstParagraphInCell = false;
+ }
+
+ m_StreamStateStack.top().bParaAutoBefore = false;
+ m_StreamStateStack.top().bParaWithInlineObject = false;
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+}
+
+// TODO this does not yet take table styles into account
+void DomainMapper_Impl::applyToggleAttributes(const PropertyMapPtr& pPropertyMap)
+{
+ std::optional<PropertyMap::Property> charStyleProperty = pPropertyMap->getProperty(PROP_CHAR_STYLE_NAME);
+ if (charStyleProperty.has_value())
+ {
+ OUString sCharStyleName;
+ charStyleProperty->second >>= sCharStyleName;
+ float fCharStyleBold = css::awt::FontWeight::NORMAL;
+ float fCharStyleBoldComplex = css::awt::FontWeight::NORMAL;
+ css::awt::FontSlant eCharStylePosture = css::awt::FontSlant_NONE;
+ css::awt::FontSlant eCharStylePostureComplex = css::awt::FontSlant_NONE;
+ sal_Int16 nCharStyleCaseMap = css::style::CaseMap::NONE;
+ sal_Int16 nCharStyleRelief = css::awt::FontRelief::NONE;
+ bool bCharStyleContoured = false;//Outline;
+ bool bCharStyleShadowed = false;
+ sal_Int16 nCharStyleStrikeThrough = awt::FontStrikeout::NONE;
+ bool bCharStyleHidden = false;
+
+ uno::Reference<beans::XPropertySet> xCharStylePropertySet = GetCharacterStyles()->getByName(sCharStyleName).get<uno::Reference<beans::XPropertySet>>();
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_WEIGHT)) >>= fCharStyleBold;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_WEIGHT_COMPLEX)) >>= fCharStyleBoldComplex;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_POSTURE)) >>= eCharStylePosture;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_POSTURE_COMPLEX)) >>= eCharStylePostureComplex;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_CASE_MAP)) >>= nCharStyleCaseMap;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_RELIEF)) >>= nCharStyleRelief;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_CONTOURED)) >>= bCharStyleContoured;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_SHADOWED)) >>= bCharStyleShadowed;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_STRIKEOUT)) >>= nCharStyleStrikeThrough;
+ xCharStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_HIDDEN)) >>= bCharStyleHidden;
+ if (fCharStyleBold > css::awt::FontWeight::NORMAL || eCharStylePosture != css::awt::FontSlant_NONE|| nCharStyleCaseMap != css::style::CaseMap::NONE ||
+ nCharStyleRelief != css::awt::FontRelief::NONE || bCharStyleContoured || bCharStyleShadowed ||
+ nCharStyleStrikeThrough == awt::FontStrikeout::SINGLE || bCharStyleHidden)
+ {
+ uno::Reference<beans::XPropertySet> const xParaStylePropertySet =
+ GetParagraphStyles()->getByName(m_StreamStateStack.top().sCurrentParaStyleName).get<uno::Reference<beans::XPropertySet>>();
+ float fParaStyleBold = css::awt::FontWeight::NORMAL;
+ float fParaStyleBoldComplex = css::awt::FontWeight::NORMAL;
+ css::awt::FontSlant eParaStylePosture = css::awt::FontSlant_NONE;
+ css::awt::FontSlant eParaStylePostureComplex = css::awt::FontSlant_NONE;
+ sal_Int16 nParaStyleCaseMap = css::style::CaseMap::NONE;
+ sal_Int16 nParaStyleRelief = css::awt::FontRelief::NONE;
+ bool bParaStyleContoured = false;
+ bool bParaStyleShadowed = false;
+ sal_Int16 nParaStyleStrikeThrough = awt::FontStrikeout::NONE;
+ bool bParaStyleHidden = false;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_WEIGHT)) >>= fParaStyleBold;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_WEIGHT_COMPLEX)) >>= fParaStyleBoldComplex;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_POSTURE)) >>= eParaStylePosture;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_POSTURE_COMPLEX)) >>= eParaStylePostureComplex;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_CASE_MAP)) >>= nParaStyleCaseMap;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_RELIEF)) >>= nParaStyleRelief;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_SHADOWED)) >>= bParaStyleShadowed;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_CONTOURED)) >>= bParaStyleContoured;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_STRIKEOUT)) >>= nParaStyleStrikeThrough;
+ xParaStylePropertySet->getPropertyValue(getPropertyName(PROP_CHAR_HIDDEN)) >>= bParaStyleHidden;
+ if (fCharStyleBold > css::awt::FontWeight::NORMAL && fParaStyleBold > css::awt::FontWeight::NORMAL)
+ {
+ std::optional<PropertyMap::Property> charBoldProperty = pPropertyMap->getProperty(PROP_CHAR_WEIGHT);
+ if (!charBoldProperty.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_WEIGHT, uno::Any(css::awt::FontWeight::NORMAL));
+ }
+ }
+ if (fCharStyleBoldComplex > css::awt::FontWeight::NORMAL && fParaStyleBoldComplex > css::awt::FontWeight::NORMAL)
+ {
+ std::optional<PropertyMap::Property> charBoldPropertyComplex = pPropertyMap->getProperty(PROP_CHAR_WEIGHT_COMPLEX);
+ if (!charBoldPropertyComplex.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_WEIGHT_COMPLEX, uno::Any(css::awt::FontWeight::NORMAL));
+ pPropertyMap->Insert(PROP_CHAR_WEIGHT_ASIAN, uno::Any(css::awt::FontWeight::NORMAL));
+ }
+ }
+ if (eCharStylePosture != css::awt::FontSlant_NONE && eParaStylePosture != css::awt::FontSlant_NONE)
+ {
+ std::optional<PropertyMap::Property> charItalicProperty = pPropertyMap->getProperty(PROP_CHAR_POSTURE);
+ if (!charItalicProperty.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_POSTURE, uno::Any(css::awt::FontSlant_NONE));
+ }
+ }
+ if (eCharStylePostureComplex != css::awt::FontSlant_NONE && eParaStylePostureComplex != css::awt::FontSlant_NONE)
+ {
+ std::optional<PropertyMap::Property> charItalicPropertyComplex = pPropertyMap->getProperty(PROP_CHAR_POSTURE_COMPLEX);
+ if (!charItalicPropertyComplex.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_POSTURE_COMPLEX, uno::Any(css::awt::FontSlant_NONE));
+ pPropertyMap->Insert(PROP_CHAR_POSTURE_ASIAN, uno::Any(css::awt::FontSlant_NONE));
+ }
+ }
+ if (nCharStyleCaseMap == nParaStyleCaseMap && nCharStyleCaseMap != css::style::CaseMap::NONE)
+ {
+ std::optional<PropertyMap::Property> charCaseMap = pPropertyMap->getProperty(PROP_CHAR_CASE_MAP);
+ if (!charCaseMap.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_CASE_MAP, uno::Any(css::style::CaseMap::NONE));
+ }
+ }
+ if (nParaStyleRelief != css::awt::FontRelief::NONE && nCharStyleRelief == nParaStyleRelief)
+ {
+ std::optional<PropertyMap::Property> charRelief = pPropertyMap->getProperty(PROP_CHAR_RELIEF);
+ if (!charRelief.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_RELIEF, uno::Any(css::awt::FontRelief::NONE));
+ }
+ }
+ if (bParaStyleContoured && bCharStyleContoured)
+ {
+ std::optional<PropertyMap::Property> charContoured = pPropertyMap->getProperty(PROP_CHAR_CONTOURED);
+ if (!charContoured.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_CONTOURED, uno::Any(false));
+ }
+ }
+ if (bParaStyleShadowed && bCharStyleShadowed)
+ {
+ std::optional<PropertyMap::Property> charShadow = pPropertyMap->getProperty(PROP_CHAR_SHADOWED);
+ if (!charShadow.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_SHADOWED, uno::Any(false));
+ }
+ }
+ if (nParaStyleStrikeThrough == css::awt::FontStrikeout::SINGLE && nParaStyleStrikeThrough == nCharStyleStrikeThrough)
+ {
+ std::optional<PropertyMap::Property> charStrikeThrough = pPropertyMap->getProperty(PROP_CHAR_STRIKEOUT);
+ if (!charStrikeThrough.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_STRIKEOUT, uno::Any(css::awt::FontStrikeout::NONE));
+ }
+ }
+ if (bParaStyleHidden && bCharStyleHidden)
+ {
+ std::optional<PropertyMap::Property> charHidden = pPropertyMap->getProperty(PROP_CHAR_HIDDEN);
+ if (!charHidden.has_value())
+ {
+ pPropertyMap->Insert(PROP_CHAR_HIDDEN, uno::Any(false));
+ }
+ }
+ }
+ }
+}
+
+void DomainMapper_Impl::MergeAtContentImageRedlineWithNext(const css::uno::Reference<css::text::XTextAppend>& xTextAppend)
+{
+ // remove workaround for change tracked images, if they are part of a redline,
+ // i.e. if the next run is a tracked change with the same type, author and date,
+ // as in the change tracking of the image.
+ if ( m_bRedlineImageInPreviousRun )
+ {
+ auto pCurrentRedline = m_aRedlines.top().size() > 0
+ ? m_aRedlines.top().back()
+ : GetTopContextOfType(CONTEXT_CHARACTER) &&
+ GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0
+ ? GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().back()
+ : nullptr;
+ if ( m_previousRedline && pCurrentRedline &&
+ // same redline
+ (m_previousRedline->m_nToken & 0xffff) == (pCurrentRedline->m_nToken & 0xffff) &&
+ m_previousRedline->m_sAuthor == pCurrentRedline->m_sAuthor &&
+ m_previousRedline->m_sDate == pCurrentRedline->m_sDate )
+ {
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->getEnd()->getText( )->createTextCursor( );
+ assert(xCursor.is());
+ xCursor->gotoEnd(false);
+ xCursor->goLeft(2, true);
+ if ( xCursor->getString() == u"​​" )
+ {
+ xCursor->goRight(1, true);
+ xCursor->setString("");
+ xCursor->gotoEnd(false);
+ xCursor->goLeft(1, true);
+ xCursor->setString("");
+ }
+ }
+
+ m_bRedlineImageInPreviousRun = false;
+ }
+}
+
+ 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
+ && !m_StreamStateStack.top().deferredCharacterProperties.empty()
+ && (GetTopContextType() == CONTEXT_CHARACTER))
+ {
+ processDeferredCharacterProperties();
+ }
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is() || !hasTableManager() || getTableManager().isIgnore())
+ return;
+
+ try
+ {
+ applyToggleAttributes(pPropertyMap);
+ // If we are in comments, then disable CharGrabBag, comment text doesn't support that.
+ uno::Sequence<beans::PropertyValue> aValues = pPropertyMap->GetPropertyValues(/*bCharGrabBag=*/!IsInComments());
+
+ if (IsInTOC() || m_bStartIndex || m_bStartBibliography)
+ for( auto& rValue : asNonConstRange(aValues) )
+ {
+ if (rValue.Name == "CharHidden")
+ rValue.Value <<= false;
+ }
+
+ MergeAtContentImageRedlineWithNext(xTextAppend);
+
+ 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 (IsInTOC() || 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);
+ }
+ if (IsInComments())
+ xTextRange = xTextAppend->finishParagraphInsert(aValues, xTOCTextCursor);
+ else
+ 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_StreamStateStack.top().bTextInserted = true;
+ xTOCTextCursor->gotoRange(xTextRange->getEnd(), true);
+ if (m_nStartGenericField == 0)
+ {
+ m_aTextAppendStack.push(TextAppendContext(xTextAppend, xTOCTextCursor));
+ }
+ }
+ }
+ else
+ {
+ if (IsOpenField() && GetTopFieldContext()->GetFieldId() == FIELD_HYPERLINK)
+ {
+ // It is content of hyperlink field. We need to create and remember
+ // character style for later applying to hyperlink
+ PropertyValueVector_t aProps = comphelper::sequenceToContainer< PropertyValueVector_t >(GetTopContext()->GetPropertyValues());
+ OUString sHyperlinkStyleName = GetStyleSheetTable()->getOrCreateCharStyle(aProps, /*bAlwaysCreate=*/false);
+ GetTopFieldContext()->SetHyperlinkStyle(sHyperlinkStyleName);
+ }
+
+#if !defined(MACOSX) // TODO: check layout differences and support all platforms, if needed
+ sal_Int32 nPos = 0;
+ OUString sFontName;
+ OUString sDoubleSpace(" ");
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_CHARACTER);
+ // tdf#123703 workaround for longer space sequences of the old or compatible RTF documents
+ if (GetSettingsTable()->GetLongerSpaceSequence() && !IsOpenFieldCommand() && (nPos = rString.indexOf(sDoubleSpace)) != -1 &&
+ // monospaced fonts have no longer space sequences, regardless of \fprq2 (not monospaced) font setting
+ // fix for the base monospaced font Courier
+ (!pContext || !pContext->isSet(PROP_CHAR_FONT_NAME) ||
+ ((pContext->getProperty(PROP_CHAR_FONT_NAME)->second >>= sFontName) && sFontName.indexOf("Courier") == -1)))
+ {
+ // an RTF space character is longer by an extra six-em-space in an old-style RTF space sequence,
+ // insert them to keep RTF document layout formatted by consecutive spaces
+ const sal_Unicode aExtraSpace[5] = { 0x2006, 0x20, 0x2006, 0x20, 0 };
+ const sal_Unicode aExtraSpace2[4] = { 0x20, 0x2006, 0x20, 0 };
+ xTextRange = xTextAppend->appendTextPortion(rString.replaceAll(sDoubleSpace, aExtraSpace, nPos)
+ .replaceAll(sDoubleSpace, aExtraSpace2, nPos), aValues);
+ }
+ else
+#endif
+ xTextRange = xTextAppend->appendTextPortion(rString, aValues);
+ }
+ }
+
+ // reset moveFrom/moveTo data of non-terminating runs of the paragraph
+ if ( m_pParaMarkerRedlineMove )
+ {
+ m_pParaMarkerRedlineMove.clear();
+ }
+ CheckRedline( xTextRange );
+ m_StreamStateStack.top().bParaChanged = true;
+
+ //getTableManager( ).handle(xTextRange);
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "DomainMapper_Impl::appendTextPortion" );
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "DomainMapper_Impl::appendTextPortion" );
+ }
+}
+
+void DomainMapper_Impl::appendTextContent(
+ const uno::Reference< text::XTextContent >& xContent,
+ const uno::Sequence< beans::PropertyValue >& xPropertyValues
+ )
+{
+ SAL_WARN_IF(m_aTextAppendStack.empty(), "writerfilter.dmapper", "no text append stack");
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( m_aTextAppendStack.top().xTextAppend, uno::UNO_QUERY );
+ OSL_ENSURE( xTextAppendAndConvert.is(), "trying to append a text content without XTextAppendAndConvert" );
+ if (!xTextAppendAndConvert.is() || !hasTableManager() || getTableManager().isIgnore())
+ return;
+
+ try
+ {
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ xTextAppendAndConvert->insertTextContentWithProperties( xContent, xPropertyValues, m_aTextAppendStack.top().xInsertPosition );
+ else
+ xTextAppendAndConvert->appendTextContent( xContent, xPropertyValues );
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ }
+ catch(const uno::Exception&)
+ {
+ }
+}
+
+void DomainMapper_Impl::appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOLEHandler )
+{
+ try
+ {
+ uno::Reference< text::XTextContent > xOLE( m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xOLEProperties(xOLE, uno::UNO_QUERY_THROW);
+
+ OUString aCLSID = pOLEHandler->getCLSID();
+ if (aCLSID.isEmpty())
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_STREAM_NAME ),
+ uno::Any( rStreamName ));
+ else
+ xOLEProperties->setPropertyValue("CLSID", uno::Any(aCLSID));
+
+ OUString aDrawAspect = pOLEHandler->GetDrawAspect();
+ if(!aDrawAspect.isEmpty())
+ xOLEProperties->setPropertyValue("DrawAspect", uno::Any(aDrawAspect));
+
+ awt::Size aSize = pOLEHandler->getSize();
+ if( !aSize.Width )
+ aSize.Width = 1000;
+ if( !aSize.Height )
+ aSize.Height = 1000;
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_WIDTH ),
+ uno::Any(aSize.Width));
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ),
+ uno::Any(aSize.Height));
+
+ OUString aVisAreaWidth = pOLEHandler->GetVisAreaWidth();
+ if(!aVisAreaWidth.isEmpty())
+ xOLEProperties->setPropertyValue("VisibleAreaWidth", uno::Any(aVisAreaWidth));
+
+ OUString aVisAreaHeight = pOLEHandler->GetVisAreaHeight();
+ if(!aVisAreaHeight.isEmpty())
+ xOLEProperties->setPropertyValue("VisibleAreaHeight", uno::Any(aVisAreaHeight));
+
+ uno::Reference< graphic::XGraphic > xGraphic = pOLEHandler->getReplacement();
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC ),
+ uno::Any(xGraphic));
+ uno::Reference<beans::XPropertySet> xReplacementProperties(pOLEHandler->getShape(), uno::UNO_QUERY);
+ if (xReplacementProperties.is())
+ {
+ table::BorderLine2 aBorderProps;
+ xReplacementProperties->getPropertyValue("LineColor") >>= aBorderProps.Color;
+ xReplacementProperties->getPropertyValue("LineWidth") >>= aBorderProps.LineWidth;
+ xReplacementProperties->getPropertyValue("LineStyle") >>= aBorderProps.LineStyle;
+
+ if (aBorderProps.LineStyle) // Set line props only if LineStyle is set
+ {
+ xOLEProperties->setPropertyValue("RightBorder", uno::Any(aBorderProps));
+ xOLEProperties->setPropertyValue("TopBorder", uno::Any(aBorderProps));
+ xOLEProperties->setPropertyValue("LeftBorder", uno::Any(aBorderProps));
+ xOLEProperties->setPropertyValue("BottomBorder", uno::Any(aBorderProps));
+ }
+ OUString pProperties[] = {
+ "AnchorType",
+ "Surround",
+ "SurroundContour",
+ "HoriOrient",
+ "HoriOrientPosition",
+ "VertOrient",
+ "VertOrientPosition",
+ "VertOrientRelation",
+ "HoriOrientRelation",
+ "LeftMargin",
+ "RightMargin",
+ "TopMargin",
+ "BottomMargin"
+ };
+ for (const OUString& s : pProperties)
+ {
+ const uno::Any aVal = xReplacementProperties->getPropertyValue(s);
+ xOLEProperties->setPropertyValue(s, aVal);
+ }
+
+ if (xReplacementProperties->getPropertyValue("FillStyle").get<css::drawing::FillStyle>()
+ != css::drawing::FillStyle::FillStyle_NONE) // Apply fill props if style is set
+ {
+ xOLEProperties->setPropertyValue(
+ "FillStyle", xReplacementProperties->getPropertyValue("FillStyle"));
+ xOLEProperties->setPropertyValue(
+ "FillColor", xReplacementProperties->getPropertyValue("FillColor"));
+ xOLEProperties->setPropertyValue(
+ "FillColor2", xReplacementProperties->getPropertyValue("FillColor2"));
+ }
+ }
+ else
+ // mimic the treatment of graphics here... it seems anchoring as character
+ // gives a better ( visually ) result
+ xOLEProperties->setPropertyValue(getPropertyName( PROP_ANCHOR_TYPE ), uno::Any( text::TextContentAnchorType_AS_CHARACTER ) );
+ // remove ( if valid ) associated shape ( used for graphic replacement )
+ SAL_WARN_IF(m_aAnchoredStack.empty(), "writerfilter.dmapper", "no anchor stack");
+ if (!m_aAnchoredStack.empty())
+ m_aAnchoredStack.top( ).bToRemove = true;
+ RemoveLastParagraph();
+ SAL_WARN_IF(m_aTextAppendStack.empty(), "writerfilter.dmapper", "no text stack");
+ if (!m_aTextAppendStack.empty())
+ m_aTextAppendStack.pop();
+
+ appendTextContent( xOLE, uno::Sequence< beans::PropertyValue >() );
+
+ if (!aCLSID.isEmpty())
+ pOLEHandler->importStream(m_xComponentContext, GetTextDocument(), xOLE);
+
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "in creation of OLE object" );
+ }
+
+}
+
+void DomainMapper_Impl::appendStarMath( const Value& val )
+{
+ uno::Reference< embed::XEmbeddedObject > formula;
+ val.getAny() >>= formula;
+ if( !formula.is() )
+ return;
+
+ try
+ {
+ uno::Reference< text::XTextContent > xStarMath( m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xStarMathProperties(xStarMath, uno::UNO_QUERY_THROW);
+
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_EMBEDDED_OBJECT ),
+ val.getAny());
+ // tdf#66405: set zero margins for embedded object
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
+ uno::Any(sal_Int32(0)));
+
+ uno::Reference< uno::XInterface > xInterface( formula->getComponent(), uno::UNO_QUERY );
+ // set zero margins for object's component
+ uno::Reference< beans::XPropertySet > xComponentProperties( xInterface, uno::UNO_QUERY_THROW );
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ xComponentProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ),
+ uno::Any(sal_Int32(0)));
+ Size size( 1000, 1000 );
+ if( oox::FormulaImExportBase* formulaimport = dynamic_cast< oox::FormulaImExportBase* >( xInterface.get()))
+ size = formulaimport->getFormulaSize();
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_WIDTH ),
+ uno::Any( sal_Int32(size.Width())));
+ xStarMathProperties->setPropertyValue(getPropertyName( PROP_HEIGHT ),
+ uno::Any( sal_Int32(size.Height())));
+ xStarMathProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE),
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+ // mimic the treatment of graphics here... it seems anchoring as character
+ // gives a better ( visually ) result
+ appendTextContent(xStarMath, uno::Sequence<beans::PropertyValue>());
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "in creation of StarMath object" );
+ }
+}
+
+void DomainMapper_Impl::adjustLastPara(sal_Int8 nAlign)
+{
+ PropertyMapPtr pLastPara = GetTopContextOfType(dmapper::CONTEXT_PARAGRAPH);
+ pLastPara->Insert(PROP_PARA_ADJUST, uno::Any(nAlign), true);
+}
+
+static void checkAndAddPropVal(const OUString& prop, const css::uno::Any& val,
+ std::vector<OUString>& props, std::vector<css::uno::Any>& values)
+{
+ // Avoid well-known reasons for exceptions when setting property values
+ if (!val.hasValue())
+ return;
+ if (prop == "CharStyleName" || prop == "DropCapCharStyleName")
+ if (OUString val_string; (val >>= val_string) && val_string.isEmpty())
+ return;
+
+ props.push_back(prop);
+ values.push_back(val);
+}
+
+static uno::Reference<lang::XComponent>
+getParagraphOfRange(const css::uno::Reference<css::text::XTextRange>& xRange)
+{
+ uno::Reference<container::XEnumerationAccess> xEA{ xRange, uno::UNO_QUERY_THROW };
+ return { xEA->createEnumeration()->nextElement(), uno::UNO_QUERY_THROW };
+}
+
+static void copyAllProps(const css::uno::Reference<css::uno::XInterface>& from,
+ const css::uno::Reference<css::uno::XInterface>& to)
+{
+ css::uno::Reference<css::beans::XPropertySet> xFromProps(from, css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::beans::XPropertySetInfo> xFromInfo(xFromProps->getPropertySetInfo(),
+ css::uno::UNO_SET_THROW);
+ css::uno::Sequence<css::beans::Property> rawProps(xFromInfo->getProperties());
+ std::vector<OUString> props;
+ props.reserve(rawProps.getLength());
+ for (const auto& prop : rawProps)
+ if ((prop.Attributes & css::beans::PropertyAttribute::READONLY) == 0)
+ props.push_back(prop.Name);
+
+ if (css::uno::Reference<css::beans::XPropertyState> xFromState{ from, css::uno::UNO_QUERY })
+ {
+ const auto propsSeq = comphelper::containerToSequence(props);
+ const auto statesSeq = xFromState->getPropertyStates(propsSeq);
+ assert(propsSeq.getLength() == statesSeq.getLength());
+ for (sal_Int32 i = 0; i < propsSeq.getLength(); ++i)
+ if (statesSeq[i] != css::beans::PropertyState_DIRECT_VALUE)
+ std::erase(props, propsSeq[i]);
+ }
+
+ std::vector<css::uno::Any> values;
+ values.reserve(props.size());
+ if (css::uno::Reference<css::beans::XMultiPropertySet> xFromMulti{ xFromProps,
+ css::uno::UNO_QUERY })
+ {
+ const auto propsSeq = comphelper::containerToSequence(props);
+ const auto valuesSeq = xFromMulti->getPropertyValues(propsSeq);
+ assert(propsSeq.getLength() == valuesSeq.getLength());
+ props.clear();
+ for (size_t i = 0; i < propsSeq.size(); ++i)
+ checkAndAddPropVal(propsSeq[i], valuesSeq[i], props, values);
+ }
+ else
+ {
+ std::vector<OUString> filtered_props;
+ filtered_props.reserve(props.size());
+ for (const auto& prop : props)
+ checkAndAddPropVal(prop, xFromProps->getPropertyValue(prop), filtered_props, values);
+ filtered_props.swap(props);
+ }
+ assert(props.size() == values.size());
+
+ css::uno::Reference<css::beans::XPropertySet> xToProps(to, css::uno::UNO_QUERY_THROW);
+ if (css::uno::Reference<css::beans::XMultiPropertySet> xToMulti{ xToProps,
+ css::uno::UNO_QUERY })
+ {
+ try
+ {
+ xToMulti->setPropertyValues(comphelper::containerToSequence(props),
+ comphelper::containerToSequence(values));
+ return;
+ }
+ catch (css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+ // Fallback to property-by-property iteration
+ }
+
+ for (size_t i = 0; i < props.size(); ++i)
+ {
+ try
+ {
+ xToProps->setPropertyValue(props[i], values[i]);
+ }
+ catch (css::uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+ }
+}
+
+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. The previous node may be a
+ // table; then trying to go left would skip the whole table. Split the trailing
+ // paragraph; let the section span over the first of the two resulting paragraphs;
+ // destroy the last section's paragraph afterwards.
+ xTextAppend->insertControlCharacter(
+ xCursor->getEnd(), css::text::ControlCharacter::PARAGRAPH_BREAK, false);
+ auto xNewPara = getParagraphOfRange(xCursor->getEnd());
+ xCursor->gotoPreviousParagraph(true);
+ auto xEndPara = getParagraphOfRange(xCursor->getEnd());
+ // xEndPara may already have properties (like page break); make sure to apply them
+ // to the newly appended paragraph, which will be kept in the end.
+ copyAllProps(xEndPara, xNewPara);
+
+ uno::Reference< text::XTextContent > xSection( m_xTextFactory->createInstance("com.sun.star.text.TextSection"), uno::UNO_QUERY_THROW );
+ xSection->attach(xCursor);
+
+ // Remove the extra paragraph (last inside the section)
+ xEndPara->dispose();
+
+ xRet.set(xSection, uno::UNO_QUERY );
+ }
+ catch(const uno::Exception&)
+ {
+ }
+
+ }
+
+ return xRet;
+}
+
+void DomainMapper_Impl::appendGlossaryEntry()
+{
+ appendTextSectionAfter(m_xGlossaryEntryStart);
+}
+
+void DomainMapper_Impl::fillEmptyFrameProperties(std::vector<beans::PropertyValue>& rFrameProperties, bool bSetAnchorToChar)
+{
+ if (bSetAnchorToChar)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_ANCHOR_TYPE), text::TextContentAnchorType_AS_CHARACTER));
+
+ uno::Any aEmptyBorder{table::BorderLine2()};
+ static const std::vector<PropertyIds> aBorderIds
+ = { PROP_BOTTOM_BORDER, PROP_LEFT_BORDER, PROP_RIGHT_BORDER, PROP_TOP_BORDER };
+ for (size_t i = 0; i < aBorderIds.size(); ++i)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(aBorderIds[i]), aEmptyBorder));
+
+ static const std::vector<PropertyIds> aMarginIds
+ = { PROP_BOTTOM_MARGIN, PROP_BOTTOM_BORDER_DISTANCE,
+ PROP_LEFT_MARGIN, PROP_LEFT_BORDER_DISTANCE,
+ PROP_RIGHT_MARGIN, PROP_RIGHT_BORDER_DISTANCE,
+ PROP_TOP_MARGIN, PROP_TOP_BORDER_DISTANCE };
+ for (size_t i = 0; i < aMarginIds.size(); ++i)
+ rFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(aMarginIds[i]), static_cast<sal_Int32>(0)));
+}
+
+bool DomainMapper_Impl::IsInTOC() const
+{
+ if (IsInHeaderFooter())
+ return m_bStartTOCHeaderFooter;
+ else
+ return m_bStartTOC;
+}
+
+void DomainMapper_Impl::ConvertHeaderFooterToTextFrame(bool bDynamicHeightTop, bool bDynamicHeightBottom)
+{
+ while (!m_aHeaderFooterTextAppendStack.empty())
+ {
+ auto& [aTextAppendContext, ePagePartType] = m_aHeaderFooterTextAppendStack.top();
+ if ((ePagePartType == PagePartType::Header && !bDynamicHeightTop) || (ePagePartType == PagePartType::Footer && !bDynamicHeightBottom))
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = aTextAppendContext.xTextAppend;
+ uno::Reference< text::XTextCursor > xCursor = xTextAppend->createTextCursor();
+ uno::Reference< text::XTextRange > xRangeStart, xRangeEnd;
+
+ xRangeStart = xCursor->getStart();
+ xCursor->gotoEnd(false);
+ xRangeEnd = xCursor->getStart();
+
+ std::vector<beans::PropertyValue> aFrameProperties
+ {
+ comphelper::makePropertyValue("TextWrap", css::text::WrapTextMode_THROUGH),
+ comphelper::makePropertyValue(getPropertyName(PROP_HORI_ORIENT), text::HoriOrientation::LEFT),
+ comphelper::makePropertyValue(getPropertyName(PROP_OPAQUE), false),
+ comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), text::SizeType::MIN),
+ comphelper::makePropertyValue(getPropertyName(PROP_SIZE_TYPE), text::SizeType::MIN),
+ // tdf#143384 If the header/footer started with a table, convertToTextFrame could not
+ // convert the table, because it used createTextCursor() -which ignore tables-
+ // to set the conversion range.
+ // This dummy property is set to make convertToTextFrame to use another CreateTextCursor
+ // method that can be parameterized to not ignore tables.
+ comphelper::makePropertyValue(getPropertyName(PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF), true)
+ };
+
+ fillEmptyFrameProperties(aFrameProperties, false);
+
+ // If it is a footer, then orient the frame to the bottom
+ if (ePagePartType == PagePartType::Footer)
+ {
+ aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_VERT_ORIENT), text::VertOrientation::BOTTOM));
+ }
+ uno::Reference<text::XTextAppendAndConvert> xBodyText(xRangeStart->getText(), uno::UNO_QUERY);
+ xBodyText->convertToTextFrame(xTextAppend, xRangeEnd, comphelper::containerToSequence(aFrameProperties));
+ }
+ m_aHeaderFooterTextAppendStack.pop();
+ }
+}
+
+namespace
+{
+// Determines if the XText content is empty (no text, no shapes, no tables)
+bool isContentEmpty(uno::Reference<text::XText> const& xText)
+{
+ if (!xText.is())
+ return true; // no XText means it's empty
+
+ uno::Reference<css::lang::XServiceInfo> xTextServiceInfo(xText, uno::UNO_QUERY);
+ if (xTextServiceInfo && xTextServiceInfo->getImplementationName() == "SwXHeadFootText")
+ return false;
+
+ uno::Reference<container::XEnumerationAccess> xEnumAccess(xText->getText(), uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xEnum = xEnumAccess->createEnumeration();
+ while (xEnum->hasMoreElements())
+ {
+ auto xObject = xEnum->nextElement();
+ uno::Reference<text::XTextTable> const xTextTable(xObject, uno::UNO_QUERY);
+ if (xTextTable.is())
+ return false;
+
+ uno::Reference<text::XTextRange> const xParagraph(xObject, uno::UNO_QUERY);
+ if (xParagraph.is() && !xParagraph->getString().isEmpty())
+ return false;
+ }
+ return true;
+}
+
+} // end anonymous namespace
+
+void DomainMapper_Impl::PushPageHeaderFooter(PagePartType ePagePartType, PageType eType)
+{
+ bool bHeader = ePagePartType == PagePartType::Header;
+
+ 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 ePropTextFirst = bHeader ? PROP_HEADER_TEXT_FIRST: PROP_FOOTER_TEXT_FIRST;
+ const PropertyIds ePropTextRight = bHeader ? PROP_HEADER_TEXT: PROP_FOOTER_TEXT;
+
+ m_bDiscardHeaderFooter = true;
+ m_StreamStateStack.top().eSubstreamType = bHeader ? SubstreamType::Header : SubstreamType::Footer;
+
+ //get the section context
+ SectionPropertyMap* pSectionContext = GetSectionContext();;
+ if (!pSectionContext)
+ return;
+
+ if (!m_bIsNewDoc)
+ return; // TODO sw cannot Undo insert header/footer without crashing
+
+ uno::Reference<beans::XPropertySet> xPageStyle = pSectionContext->GetPageStyle(*this);
+ if (!xPageStyle.is())
+ return;
+
+ bool bEvenAndOdd = GetSettingsTable()->GetEvenAndOddHeaders();
+
+ try
+ {
+ // Turn on the headers
+ xPageStyle->setPropertyValue(getPropertyName(ePropIsOn), uno::Any(true));
+
+ // Set both sharing left and first to off so we can import the content regardless of what value
+ // the "titlePage" or "evenAndOdd" flags are set (which decide what the sharing is set to in the document).
+ xPageStyle->setPropertyValue(getPropertyName(ePropShared), uno::Any(false));
+ xPageStyle->setPropertyValue(getPropertyName(PROP_FIRST_IS_SHARED), uno::Any(false));
+
+ if (eType == PageType::LEFT)
+ {
+ if (bHeader)
+ {
+ pSectionContext->m_bLeftHeader = true;
+ pSectionContext->m_bHadLeftHeader = true;
+ }
+ else
+ pSectionContext->m_bLeftFooter = true;
+
+ prepareHeaderFooterContent(xPageStyle, ePagePartType, ePropTextLeft, bEvenAndOdd);
+ }
+ else if (eType == PageType::FIRST)
+ {
+ if (bHeader)
+ {
+ pSectionContext->m_bFirstHeader = true;
+ pSectionContext->m_bHadFirstHeader = true;
+ }
+ else
+ pSectionContext->m_bFirstFooter = true;
+
+ prepareHeaderFooterContent(xPageStyle, ePagePartType, ePropTextFirst, true);
+ }
+ else
+ {
+ if (bHeader)
+ {
+ pSectionContext->m_bRightHeader = true;
+ pSectionContext->m_bHadRightHeader = true;
+ }
+ else
+ pSectionContext->m_bRightFooter = true;
+
+ prepareHeaderFooterContent(xPageStyle, ePagePartType, ePropTextRight, true);
+ }
+
+ m_bDiscardHeaderFooter = false; // set only on success!
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+}
+
+/** Prepares the header/footer text content by first removing the existing
+ * content and adding it to the text append stack. */
+void DomainMapper_Impl::prepareHeaderFooterContent(uno::Reference<beans::XPropertySet> const& xPageStyle,
+ PagePartType ePagePartType, PropertyIds ePropertyID,
+ bool bAppendToHeaderAndFooterTextStack)
+{
+ uno::Reference<text::XText> xText;
+ xPageStyle->getPropertyValue(getPropertyName(ePropertyID)) >>= xText;
+
+ //remove the existing content first
+ SectionPropertyMap::removeXTextContent(xText);
+
+ auto xTextCursor = m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : xText->createTextCursorByRange(xText->getStart());
+ uno::Reference<text::XTextAppend> xTextAppend(xText, uno::UNO_QUERY_THROW);
+ m_aTextAppendStack.push(TextAppendContext(xTextAppend, xTextCursor));
+ if (bAppendToHeaderAndFooterTextStack)
+ m_aHeaderFooterTextAppendStack.push(std::make_pair(TextAppendContext(xTextAppend, xTextCursor), ePagePartType));
+}
+
+bool DomainMapper_Impl::SeenHeaderFooter(PagePartType const partType, PageType const pageType) const
+{
+ return m_HeaderFooterSeen.find({partType, pageType}) != m_HeaderFooterSeen.end();
+}
+
+/** Checks if the header and footer content on the text appended stack is empty.
+ */
+void DomainMapper_Impl::checkIfHeaderFooterIsEmpty(PagePartType ePagePartType, PageType eType)
+{
+ if (m_bDiscardHeaderFooter)
+ return;
+
+ if (m_aTextAppendStack.empty())
+ return;
+
+ SectionPropertyMap* pSectionContext = GetSectionContext();
+ if (!pSectionContext)
+ return;
+
+ bool bHeader = ePagePartType == PagePartType::Header;
+
+ uno::Reference<beans::XPropertySet> xPageStyle(pSectionContext->GetPageStyle(*this));
+
+ if (!xPageStyle.is())
+ return;
+
+ bool bEmpty = isContentEmpty(m_aTextAppendStack.top().xTextAppend);
+
+ if (eType == PageType::FIRST && bEmpty)
+ {
+ if (bHeader)
+ pSectionContext->m_bFirstHeader = false;
+ else
+ pSectionContext->m_bFirstFooter = false;
+ }
+ else if (eType == PageType::LEFT && bEmpty)
+ {
+ if (bHeader)
+ pSectionContext->m_bLeftHeader = false;
+ else
+ pSectionContext->m_bLeftFooter = false;
+ }
+ else if (eType == PageType::RIGHT && bEmpty)
+ {
+ if (bHeader)
+ pSectionContext->m_bRightHeader = false;
+ else
+ pSectionContext->m_bRightFooter = false;
+ }
+}
+
+void DomainMapper_Impl::PopPageHeaderFooter(PagePartType ePagePartType, PageType eType)
+{
+ //header and footer always have an empty paragraph at the end
+ //this has to be removed
+ RemoveLastParagraph();
+
+ checkIfHeaderFooterIsEmpty(ePagePartType, eType);
+
+ // clear the "Link To Previous" flag so that the header/footer
+ // content is not copied from the previous section
+ SectionPropertyMap* pSectionContext = GetSectionContext();
+ if (pSectionContext)
+ {
+ pSectionContext->clearHeaderFooterLinkToPrevious(ePagePartType, eType);
+ m_HeaderFooterSeen.emplace(ePagePartType, eType);
+ }
+
+ if (!m_aTextAppendStack.empty())
+ {
+ if (!m_bDiscardHeaderFooter)
+ {
+ m_aTextAppendStack.pop();
+ }
+ m_bDiscardHeaderFooter = false;
+ }
+}
+
+void DomainMapper_Impl::PushFootOrEndnote( bool bIsFootnote )
+{
+ SAL_WARN_IF(m_StreamStateStack.top().eSubstreamType != SubstreamType::Body, "writerfilter.dmapper", "PushFootOrEndnote() is called from another foot or endnote");
+ m_StreamStateStack.top().eSubstreamType = bIsFootnote ? SubstreamType::Footnote : SubstreamType::Endnote;
+ m_StreamStateStack.top().bCheckFirstFootnoteTab = true;
+ try
+ {
+ // Redlines outside the footnote should not affect footnote content
+ m_aRedlines.push(std::vector< RedlineParamsPtr >());
+
+ // IMHO character styles from footnote labels should be ignored in the edit view of Writer.
+ // This adds a hack on top of the following hack to save the style name in the context.
+ PropertyMapPtr pTopContext = GetTopContext();
+ OUString sFootnoteCharStyleName;
+ std::optional< PropertyMap::Property > aProp = pTopContext->getProperty(PROP_CHAR_STYLE_NAME);
+ if (aProp)
+ aProp->second >>= sFootnoteCharStyleName;
+
+ // Remove style reference, if any. This reference did appear here as a side effect of tdf#43017
+ // Seems it is not required by LO, but causes side effects during editing. So remove it
+ // for footnotes/endnotes to restore original LO behavior here.
+ pTopContext->Erase(PROP_CHAR_STYLE_NAME);
+
+ uno::Reference< text::XText > xFootnoteText;
+ if (GetTextFactory().is())
+ xFootnoteText.set( GetTextFactory()->createInstance(
+ bIsFootnote ?
+ OUString( "com.sun.star.text.Footnote" ) : OUString( "com.sun.star.text.Endnote" )),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< text::XFootnote > xFootnote( xFootnoteText, uno::UNO_QUERY_THROW );
+ pTopContext->SetFootnote(xFootnote, sFootnoteCharStyleName);
+ uno::Sequence< beans::PropertyValue > aFontProperties;
+ if (GetTopContextOfType(CONTEXT_CHARACTER))
+ aFontProperties = GetTopContextOfType(CONTEXT_CHARACTER)->GetPropertyValues();
+ appendTextContent( uno::Reference< text::XTextContent >( xFootnoteText, uno::UNO_QUERY_THROW ), aFontProperties );
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xFootnoteText, uno::UNO_QUERY_THROW ),
+ xFootnoteText->createTextCursorByRange(xFootnoteText->getStart())));
+
+ // Redlines for the footnote anchor in the main text content
+ std::vector< RedlineParamsPtr > aFootnoteRedline = std::move(m_aRedlines.top());
+ m_aRedlines.pop();
+ CheckRedline( xFootnote->getAnchor( ) );
+ m_aRedlines.push( aFootnoteRedline );
+
+ // Try scanning for custom footnote labels
+ if (!sFootnoteCharStyleName.isEmpty())
+ StartCustomFootnote(pTopContext);
+ else
+ EndCustomFootnote();
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "PushFootOrEndnote");
+ }
+}
+
+void DomainMapper_Impl::CreateRedline(uno::Reference<text::XTextRange> const& xRange,
+ const RedlineParamsPtr& pRedline)
+{
+ if ( !pRedline )
+ return;
+
+ bool bRedlineMoved = false;
+ try
+ {
+ OUString sType;
+ switch ( pRedline->m_nToken & 0xffff )
+ {
+ case XML_mod:
+ sType = getPropertyName( PROP_FORMAT );
+ break;
+ case XML_moveTo:
+ bRedlineMoved = true;
+ m_pParaMarkerRedlineMove = pRedline.get();
+ [[fallthrough]];
+ case XML_ins:
+ sType = getPropertyName( PROP_INSERT );
+ break;
+ case XML_moveFrom:
+ bRedlineMoved = true;
+ m_pParaMarkerRedlineMove = pRedline.get();
+ [[fallthrough]];
+ case XML_del:
+ sType = getPropertyName( PROP_DELETE );
+ break;
+ case XML_ParagraphFormat:
+ sType = getPropertyName( PROP_PARAGRAPH_FORMAT );
+ break;
+ default:
+ throw lang::IllegalArgumentException("illegal redline token type", nullptr, 0);
+ }
+ beans::PropertyValues aRedlineProperties( 4 );
+ beans::PropertyValue * pRedlineProperties = aRedlineProperties.getArray( );
+ pRedlineProperties[0].Name = getPropertyName( PROP_REDLINE_AUTHOR );
+ pRedlineProperties[0].Value <<= pRedline->m_sAuthor;
+ pRedlineProperties[1].Name = getPropertyName( PROP_REDLINE_DATE_TIME );
+ util::DateTime aDateTime = ConversionHelper::ConvertDateStringToDateTime( pRedline->m_sDate );
+ // tdf#146171 import not specified w:date (or specified as zero date "0-00-00")
+ // as Epoch time to avoid of losing change tracking data during ODF roundtrip
+ if ( aDateTime.Year == 0 && aDateTime.Month == 0 && aDateTime.Day == 0 )
+ {
+ aDateTime.Year = 1970;
+ aDateTime.Month = 1;
+ aDateTime.Day = 1;
+ }
+ pRedlineProperties[1].Value <<= aDateTime;
+ pRedlineProperties[2].Name = getPropertyName( PROP_REDLINE_REVERT_PROPERTIES );
+ pRedlineProperties[2].Value <<= pRedline->m_aRevertProperties;
+
+ sal_uInt32 nRedlineMovedID = 0;
+ if (bRedlineMoved)
+ {
+ if (!m_sCurrentBkmkId.isEmpty())
+ {
+ nRedlineMovedID = 1;
+ BookmarkMap_t::iterator aBookmarkIter = m_aBookmarkMap.find(m_sCurrentBkmkId);
+ if (aBookmarkIter != m_aBookmarkMap.end())
+ {
+ OUString sMoveID = aBookmarkIter->second.m_sBookmarkName;
+ auto aIter = m_aRedlineMoveIDs.end();
+
+ if (sMoveID.indexOf("__RefMoveFrom__") >= 0)
+ {
+ aIter = std::find(m_aRedlineMoveIDs.begin(), m_aRedlineMoveIDs.end(),
+ sMoveID.subView(15));
+ }
+ else if (sMoveID.indexOf("__RefMoveTo__") >= 0)
+ {
+ aIter = std::find(m_aRedlineMoveIDs.begin(), m_aRedlineMoveIDs.end(),
+ sMoveID.subView(13));
+ };
+
+ if (aIter != m_aRedlineMoveIDs.end())
+ {
+ nRedlineMovedID = aIter - m_aRedlineMoveIDs.begin() + 2;
+ m_nLastRedlineMovedID = nRedlineMovedID;
+ }
+ }
+ }
+ else
+ nRedlineMovedID = m_nLastRedlineMovedID;
+ }
+ pRedlineProperties[3].Name = "RedlineMoved";
+ pRedlineProperties[3].Value <<= nRedlineMovedID;
+
+ if (!m_bIsActualParagraphFramed)
+ {
+ uno::Reference < text::XRedline > xRedline( xRange, uno::UNO_QUERY_THROW );
+ xRedline->makeRedline( sType, aRedlineProperties );
+ }
+ // store frame and (possible floating) table redline data for restoring them after frame conversion
+ enum StoredRedlines eType;
+ if (m_bIsActualParagraphFramed || 0 < m_StreamStateStack.top().nTableDepth)
+ eType = StoredRedlines::FRAME;
+ else if (IsInFootOrEndnote())
+ eType = IsInFootnote() ? StoredRedlines::FOOTNOTE : StoredRedlines::ENDNOTE;
+ else
+ eType = StoredRedlines::NONE;
+
+ if (eType != StoredRedlines::NONE)
+ {
+ m_aStoredRedlines[eType].emplace_back(xRange);
+ m_aStoredRedlines[eType].emplace_back(sType);
+ m_aStoredRedlines[eType].emplace_back(aRedlineProperties);
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "in makeRedline" );
+ }
+}
+
+void DomainMapper_Impl::CheckParaMarkerRedline( uno::Reference< text::XTextRange > const& xRange )
+{
+ if ( m_pParaMarkerRedline )
+ {
+ CreateRedline( xRange, m_pParaMarkerRedline );
+ if ( m_pParaMarkerRedline )
+ {
+ m_pParaMarkerRedline.clear();
+ m_currentRedline.clear();
+ }
+ }
+ else if ( m_pParaMarkerRedlineMove && m_bIsParaMarkerMove )
+ {
+ // terminating moveFrom/moveTo redline removes also the paragraph mark
+ CreateRedline( xRange, m_pParaMarkerRedlineMove );
+ }
+ if ( m_pParaMarkerRedlineMove )
+ {
+ m_pParaMarkerRedlineMove.clear();
+ EndParaMarkerMove();
+ }
+}
+
+void DomainMapper_Impl::CheckRedline( uno::Reference< text::XTextRange > const& xRange )
+{
+ // Writer core "officially" does not like overlapping redlines, and its UNO interface is stupid enough
+ // to not prevent that. However, in practice in fact everything appears to work fine (except for the debug warnings
+ // about redline table corruption, which may possibly be harmless in reality). So leave this as it is, since this
+ // is a better representation of how the changes happened. If this will ever become a problem, overlapping redlines
+ // will need to be merged into one, just like doing the changes in the UI does, which will lose some information
+ // (and so if that happens, it may be better to fix Writer).
+ // Create the redlines here from lowest (formats) to highest (inserts/removals) priority, since the last one is
+ // what Writer presents graphically, so this will show deletes as deleted text and not as just formatted text being there.
+ bool bUsedRange = m_aRedlines.top().size() > 0 || (GetTopContextOfType(CONTEXT_CHARACTER) &&
+ GetTopContextOfType(CONTEXT_CHARACTER)->Redlines().size() > 0);
+
+ // only export ParagraphFormat, when there is no other redline in the same text portion to avoid missing redline compression,
+ // but always export the first ParagraphFormat redline in a paragraph to keep the paragraph style change data for rejection
+ if ((!bUsedRange || !m_StreamStateStack.top().bParaChanged)
+ && GetTopContextOfType(CONTEXT_PARAGRAPH))
+ {
+ std::vector<RedlineParamsPtr>& avRedLines = GetTopContextOfType(CONTEXT_PARAGRAPH)->Redlines();
+ for( const auto& rRedline : avRedLines )
+ CreateRedline( xRange, rRedline );
+ }
+ if( GetTopContextOfType(CONTEXT_CHARACTER) )
+ {
+ std::vector<RedlineParamsPtr>& avRedLines = GetTopContextOfType(CONTEXT_CHARACTER)->Redlines();
+ for( const auto& rRedline : avRedLines )
+ CreateRedline( xRange, rRedline );
+ }
+ for (const auto& rRedline : m_aRedlines.top() )
+ CreateRedline( xRange, rRedline );
+}
+
+void DomainMapper_Impl::StartParaMarkerChange( )
+{
+ m_bIsParaMarkerChange = true;
+}
+
+void DomainMapper_Impl::EndParaMarkerChange( )
+{
+ m_bIsParaMarkerChange = false;
+ m_previousRedline = m_currentRedline;
+ m_currentRedline.clear();
+}
+
+void DomainMapper_Impl::StartParaMarkerMove( )
+{
+ m_bIsParaMarkerMove = true;
+}
+
+void DomainMapper_Impl::EndParaMarkerMove( )
+{
+ m_bIsParaMarkerMove = false;
+}
+
+void DomainMapper_Impl::StartCustomFootnote(const PropertyMapPtr pContext)
+{
+ if (pContext == m_pFootnoteContext)
+ return;
+
+ assert(pContext->GetFootnote().is());
+ m_StreamStateStack.top().bHasFootnoteStyle = true;
+ m_StreamStateStack.top().bCheckFootnoteStyle = !pContext->GetFootnoteStyle().isEmpty();
+ m_pFootnoteContext = pContext;
+}
+
+void DomainMapper_Impl::EndCustomFootnote()
+{
+ m_StreamStateStack.top().bHasFootnoteStyle = false;
+ m_StreamStateStack.top().bCheckFootnoteStyle = false;
+}
+
+void DomainMapper_Impl::PushAnnotation()
+{
+ try
+ {
+ m_StreamStateStack.top().eSubstreamType = SubstreamType::Annotation;
+ if (!GetTextFactory().is())
+ return;
+ m_xAnnotationField.set( GetTextFactory()->createInstance( "com.sun.star.text.TextField.Annotation" ),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< text::XText > xAnnotationText;
+ m_xAnnotationField->getPropertyValue("TextRange") >>= xAnnotationText;
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference< text::XTextAppend >( xAnnotationText, uno::UNO_QUERY_THROW ),
+ m_bIsNewDoc ? uno::Reference<text::XTextCursor>() : xAnnotationText->createTextCursorByRange(xAnnotationText->getStart())));
+ }
+ catch( const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+}
+
+static void lcl_CopyRedlines(
+ uno::Reference< text::XText > const& xSrc,
+ std::deque<css::uno::Any>& rRedlines,
+ std::vector<sal_Int32>& redPos,
+ std::vector<sal_Int32>& redLen,
+ sal_Int32& redIdx)
+{
+ redIdx = -1;
+ for( size_t i = 0; i < rRedlines.size(); i+=3)
+ {
+ uno::Reference< text::XTextRange > xRange;
+ rRedlines[i] >>= xRange;
+
+ // is this a redline of the temporary footnote?
+ uno::Reference<text::XTextCursor> xRangeCursor;
+ try
+ {
+ xRangeCursor = xSrc->createTextCursorByRange( xRange );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ if (xRangeCursor.is())
+ {
+ redIdx = i;
+ sal_Int32 nLen = xRange->getString().getLength();
+ redLen.push_back(nLen);
+ xRangeCursor->gotoRange(xSrc->getStart(), true);
+ redPos.push_back(xRangeCursor->getString().getLength() - nLen);
+ }
+ else
+ {
+ // we have already found all redlines of the footnote,
+ // skip checking the redlines of the other footnotes
+ if (redIdx > -1)
+ break;
+ // failed createTextCursorByRange(), for example, table inside the frame
+ redLen.push_back(-1);
+ redPos.push_back(-1);
+ }
+ }
+}
+
+static void lcl_PasteRedlines(
+ uno::Reference< text::XText > const& xDest,
+ std::deque<css::uno::Any>& rRedlines,
+ std::vector<sal_Int32>& redPos,
+ std::vector<sal_Int32>& redLen,
+ sal_Int32 redIdx)
+{
+ // create redlines in the copied footnote
+ for( size_t i = 0; redIdx > -1 && i <= sal::static_int_cast<size_t>(redIdx); i+=3)
+ {
+ OUString sType;
+ beans::PropertyValues aRedlineProperties( 3 );
+ // skip failed createTextCursorByRange()
+ if (redPos[i/3] == -1)
+ continue;
+ rRedlines[i+1] >>= sType;
+ rRedlines[i+2] >>= aRedlineProperties;
+ uno::Reference< text::XTextCursor > xCrsr = xDest->getText()->createTextCursor();
+ xCrsr->goRight(redPos[i/3], false);
+ xCrsr->goRight(redLen[i/3], true);
+ uno::Reference < text::XRedline > xRedline( xCrsr, uno::UNO_QUERY_THROW );
+ try {
+ xRedline->makeRedline( sType, aRedlineProperties );
+ }
+ catch(const uno::Exception&)
+ {
+ // ignore (footnotes of tracked deletions)
+ }
+ }
+}
+
+bool DomainMapper_Impl::CopyTemporaryNotes(
+ uno::Reference< text::XFootnote > xNoteSrc,
+ uno::Reference< text::XFootnote > xNoteDest )
+{
+ if (!m_bSaxError && xNoteSrc != xNoteDest)
+ {
+ uno::Reference< text::XText > xSrc( xNoteSrc, uno::UNO_QUERY_THROW );
+ uno::Reference< text::XText > xDest( xNoteDest, uno::UNO_QUERY_THROW );
+ uno::Reference< text::XTextCopy > xTxt, xTxt2;
+ xTxt.set( xSrc, uno::UNO_QUERY_THROW );
+ xTxt2.set( xDest, uno::UNO_QUERY_THROW );
+ xTxt2->copyText( xTxt );
+
+ // copy its redlines
+ std::vector<sal_Int32> redPos, redLen;
+ sal_Int32 redIdx;
+ enum StoredRedlines eType = IsInFootnote() ? StoredRedlines::FOOTNOTE : StoredRedlines::ENDNOTE;
+ lcl_CopyRedlines(xSrc, m_aStoredRedlines[eType], redPos, redLen, redIdx);
+ lcl_PasteRedlines(xDest, m_aStoredRedlines[eType], redPos, redLen, redIdx);
+
+ // remove processed redlines
+ for( size_t i = 0; redIdx > -1 && i <= sal::static_int_cast<size_t>(redIdx) + 2; i++)
+ m_aStoredRedlines[eType].pop_front();
+
+ return true;
+ }
+
+ return false;
+}
+
+void DomainMapper_Impl::RemoveTemporaryFootOrEndnotes()
+{
+ uno::Reference< text::XFootnotesSupplier> xFootnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< text::XEndnotesSupplier> xEndnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< text::XFootnote > xNote;
+ if (GetFootnoteCount() > 0)
+ {
+ auto xFootnotes = xFootnotesSupplier->getFootnotes();
+ if ( m_nFirstFootnoteIndex > 0 )
+ {
+ uno::Reference< text::XFootnote > xFirstNote;
+ xFootnotes->getByIndex(0) >>= xFirstNote;
+ uno::Reference< text::XText > xText( xFirstNote, uno::UNO_QUERY_THROW );
+ xText->setString("");
+ xFootnotes->getByIndex(m_nFirstFootnoteIndex) >>= xNote;
+ CopyTemporaryNotes(xNote, xFirstNote);
+ }
+ for (sal_Int32 i = GetFootnoteCount(); i > 0; --i)
+ {
+ xFootnotes->getByIndex(i) >>= xNote;
+ xNote->getAnchor()->setString("");
+ }
+ }
+ if (GetEndnoteCount() > 0)
+ {
+ auto xEndnotes = xEndnotesSupplier->getEndnotes();
+ if ( m_nFirstEndnoteIndex > 0 )
+ {
+ uno::Reference< text::XFootnote > xFirstNote;
+ xEndnotes->getByIndex(0) >>= xFirstNote;
+ uno::Reference< text::XText > xText( xFirstNote, uno::UNO_QUERY_THROW );
+ xText->setString("");
+ xEndnotes->getByIndex(m_nFirstEndnoteIndex) >>= xNote;
+ CopyTemporaryNotes(xNote, xFirstNote);
+ }
+ for (sal_Int32 i = GetEndnoteCount(); i > 0; --i)
+ {
+ xEndnotes->getByIndex(i) >>= xNote;
+ xNote->getAnchor()->setString("");
+ }
+ }
+}
+
+static void lcl_convertToNoteIndices(std::deque<sal_Int32>& rNoteIds, sal_Int32& rFirstNoteIndex)
+{
+ // rNoteIds contains XML footnote identifiers in the loaded order of the footnotes
+ // (the same order as in footnotes.xml), i.e. it maps temporary footnote positions to the
+ // identifiers. For example: Ids[0] = 100; Ids[1] = -1, Ids[2] = 5.
+ // To copy the footnotes in their final place, create an array, which map the (normalized)
+ // footnote identifiers to the temporary footnote positions. Using the previous example,
+ // Pos[0] = 1; Pos[1] = 2; Pos[2] = 0 (where [0], [1], [2] are the normalized
+ // -1, 5 and 100 identifiers).
+ std::deque<sal_Int32> aSortedIds = rNoteIds;
+ std::sort(aSortedIds.begin(), aSortedIds.end());
+ std::map<sal_Int32, size_t> aMapIds;
+ // normalize footnote identifiers to 0, 1, 2 ...
+ for (size_t i = 0; i < aSortedIds.size(); ++i)
+ aMapIds[aSortedIds[i]] = i;
+ // reusing rNoteIds, create the Pos array to map normalized identifiers to the loaded positions
+ std::deque<sal_Int32> aOrigNoteIds = rNoteIds;
+ for (size_t i = 0; i < rNoteIds.size(); ++i)
+ rNoteIds[aMapIds[aOrigNoteIds[i]]] = i;
+ rFirstNoteIndex = rNoteIds.front();
+ rNoteIds.pop_front();
+}
+
+void DomainMapper_Impl::PopFootOrEndnote()
+{
+ // content of the footnotes were inserted after the first footnote in temporary footnotes,
+ // restore the content of the actual footnote by copying its content from the first
+ // (remaining) temporary footnote and remove the temporary footnote.
+ uno::Reference< text::XFootnotesSupplier> xFootnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ uno::Reference< text::XEndnotesSupplier> xEndnotesSupplier( GetTextDocument(), uno::UNO_QUERY );
+ bool bCopied = false;
+ if ( IsInFootOrEndnote() && ( ( IsInFootnote() && GetFootnoteCount() > -1 && xFootnotesSupplier.is() ) ||
+ ( !IsInFootnote() && GetEndnoteCount() > -1 && xEndnotesSupplier.is() ) ) )
+ {
+ uno::Reference< text::XFootnote > xNoteFirst, xNoteLast;
+ auto xFootnotes = xFootnotesSupplier->getFootnotes();
+ auto xEndnotes = xEndnotesSupplier->getEndnotes();
+ if ( ( ( IsInFootnote() && xFootnotes->getCount() > 1 &&
+ ( xFootnotes->getByIndex(xFootnotes->getCount()-1) >>= xNoteLast ) ) ||
+ ( !IsInFootnote() && xEndnotes->getCount() > 1 &&
+ ( xEndnotes->getByIndex(xEndnotes->getCount()-1) >>= xNoteLast ) )
+ ) && xNoteLast->getLabel().isEmpty() )
+ {
+ // copy content of the next temporary footnote
+ try
+ {
+ if ( IsInFootnote() && !m_aFootnoteIds.empty() )
+ {
+ if ( m_nFirstFootnoteIndex == -1 )
+ lcl_convertToNoteIndices(m_aFootnoteIds, m_nFirstFootnoteIndex);
+ if (m_aFootnoteIds.empty()) // lcl_convertToNoteIndices pops m_aFootnoteIds
+ m_bSaxError = true;
+ else
+ {
+ xFootnotes->getByIndex(m_aFootnoteIds.front()) >>= xNoteFirst;
+ m_aFootnoteIds.pop_front();
+ }
+ }
+ else if ( !IsInFootnote() && !m_aEndnoteIds.empty() )
+ {
+ if ( m_nFirstEndnoteIndex == -1 )
+ lcl_convertToNoteIndices(m_aEndnoteIds, m_nFirstEndnoteIndex);
+ if (m_aEndnoteIds.empty()) // lcl_convertToNoteIndices pops m_aEndnoteIds
+ m_bSaxError = true;
+ else
+ {
+ xEndnotes->getByIndex(m_aEndnoteIds.front()) >>= xNoteFirst;
+ m_aEndnoteIds.pop_front();
+ }
+ }
+ else
+ m_bSaxError = true;
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "Cannot insert footnote/endnote");
+ m_bSaxError = true;
+ }
+
+ bCopied = CopyTemporaryNotes(xNoteFirst, xNoteLast);
+ }
+ }
+
+ if (!IsRTFImport() && !bCopied)
+ RemoveLastParagraph();
+
+ 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_pFootnoteContext = nullptr;
+}
+
+void DomainMapper_Impl::PopAnnotation()
+{
+ RemoveLastParagraph();
+
+ m_aTextAppendStack.pop();
+
+ try
+ {
+ if (m_bAnnotationResolved)
+ m_xAnnotationField->setPropertyValue("Resolved", uno::Any(true));
+
+ m_xAnnotationField->setPropertyValue("ParaIdParent", uno::Any(m_sAnnotationParent));
+ m_xAnnotationField->setPropertyValue("ParaId", uno::Any(m_sAnnotationImportedParaId));
+
+ // 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_sAnnotationParent.clear();
+ m_sAnnotationImportedParaId.clear();
+ m_nAnnotationId = -1;
+ m_bAnnotationResolved = false;
+}
+
+void DomainMapper_Impl::PushPendingShape( const uno::Reference< drawing::XShape > & xShape )
+{
+ m_aPendingShapes.push_back(xShape);
+}
+
+uno::Reference<drawing::XShape> DomainMapper_Impl::PopPendingShape()
+{
+ uno::Reference<drawing::XShape> xRet;
+ if (!m_aPendingShapes.empty())
+ {
+ xRet = m_aPendingShapes.front();
+ m_aPendingShapes.pop_front();
+ }
+ return xRet;
+}
+
+void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape > & xShape )
+{
+ // Append these early, so the context and the table manager stack will be
+ // in sync, even if the text append stack is empty.
+ appendTableManager();
+ appendTableHandler();
+ getTableManager().startLevel();
+
+ if (m_aTextAppendStack.empty())
+ return;
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+
+ try
+ {
+ uno::Reference< lang::XServiceInfo > xSInfo( xShape, uno::UNO_QUERY_THROW );
+ if (xSInfo->supportsService("com.sun.star.drawing.GroupShape"))
+ {
+ // Textboxes in shapes do not support styles, so check saved style information and apply properties directly to the child shapes.
+ const uno::Reference<drawing::XShapes> xShapes(xShape, uno::UNO_QUERY);
+ const sal_uInt32 nShapeCount = xShapes.is() ? xShapes->getCount() : 0;
+ for ( sal_uInt32 i = 0; i < nShapeCount; ++i )
+ {
+ try
+ {
+ uno::Reference<text::XTextRange> xFrame(xShapes->getByIndex(i), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xFramePropertySet;
+ if (xFrame)
+ xFramePropertySet.set(xFrame, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShapes->getByIndex(i), uno::UNO_QUERY_THROW);
+
+ comphelper::SequenceAsHashMap aGrabBag( xShapePropertySet->getPropertyValue("CharInteropGrabBag") );
+
+ // only VML import has checked for style. Don't apply default parastyle properties to other imported shapes
+ // - except for fontsize - to maintain compatibility with previous versions of LibreOffice.
+ const bool bOnlyApplyCharHeight = !aGrabBag["mso-pStyle"].hasValue();
+
+ OUString sStyleName;
+ aGrabBag["mso-pStyle"] >>= sStyleName;
+ StyleSheetEntryPtr pEntry = GetStyleSheetTable()->FindStyleSheetByISTD( sStyleName );
+ if ( !pEntry )
+ {
+ // Use default style even in ambiguous cases (where multiple styles were defined) since MOST styles inherit
+ // MOST of their properties from the default style. In the ambiguous case, we have to accept some kind of compromise
+ // and the default paragraph style ought to be the safest one... (compared to DocDefaults or program defaults)
+ pEntry = GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( GetDefaultParaStyleName() );
+ }
+ if ( pEntry )
+ {
+ // The Ids here come from oox/source/vml/vmltextbox.cxx.
+ // It probably could safely expand to all Ids that shapes support.
+ const PropertyIds eIds[] = {
+ PROP_CHAR_HEIGHT,
+ PROP_CHAR_FONT_NAME,
+ PROP_CHAR_WEIGHT,
+ PROP_CHAR_CHAR_KERNING,
+ PROP_CHAR_COLOR,
+ PROP_PARA_ADJUST
+ };
+ const uno::Reference<beans::XPropertyState> xShapePropertyState(xShapePropertySet, uno::UNO_QUERY_THROW);
+ for ( const auto& eId : eIds )
+ {
+ try
+ {
+ if ( bOnlyApplyCharHeight && eId != PROP_CHAR_HEIGHT )
+ continue;
+
+ const OUString & sPropName = getPropertyName(eId);
+ if ( beans::PropertyState_DEFAULT_VALUE == xShapePropertyState->getPropertyState(sPropName) )
+ {
+ const uno::Any aProp = GetPropertyFromStyleSheet(eId, pEntry, /*bDocDefaults=*/true, /*bPara=*/true);
+ if (aProp.hasValue())
+ {
+ if (xFrame)
+ xFramePropertySet->setPropertyValue(sPropName, aProp);
+ else
+ xShapePropertySet->setPropertyValue(sPropName, aProp);
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "PushShapeContext() text stylesheet property exception" );
+ }
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "PushShapeContext()" );
+ }
+ }
+
+ // A GroupShape doesn't implement text::XTextRange, but appending
+ // an empty reference to the stacks still makes sense, because this
+ // way bToRemove can be set, and we won't end up with duplicated
+ // shapes for OLE objects.
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xShape, uno::UNO_QUERY), uno::Reference<text::XTextCursor>()));
+ uno::Reference<text::XTextContent> xTxtContent(xShape, uno::UNO_QUERY);
+ m_aAnchoredStack.push(AnchoredContext(xTxtContent));
+ }
+ else if (xSInfo->supportsService("com.sun.star.drawing.OLE2Shape"))
+ {
+ // OLE2Shape from oox should be converted to a TextEmbeddedObject for sw.
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xShape, uno::UNO_QUERY), uno::Reference<text::XTextCursor>()));
+ uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY);
+ m_aAnchoredStack.push(AnchoredContext(xTextContent));
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+
+ m_StreamStateStack.top().xEmbedded.set(m_xTextFactory->createInstance("com.sun.star.text.TextEmbeddedObject"), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xEmbeddedProperties(m_StreamStateStack.top().xEmbedded, uno::UNO_QUERY_THROW);
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_EMBEDDED_OBJECT), xShapePropertySet->getPropertyValue(getPropertyName(PROP_EMBEDDED_OBJECT)));
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE), uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+ // So that the original bitmap-only shape will be replaced by the embedded object.
+ m_aAnchoredStack.top().bToRemove = true;
+ m_aTextAppendStack.pop();
+ appendTextContent(m_StreamStateStack.top().xEmbedded, uno::Sequence<beans::PropertyValue>());
+ }
+ else
+ {
+ uno::Reference<text::XTextRange> xShapeTextRange(xShape, uno::UNO_QUERY_THROW);
+ // Add the shape to the text append stack
+ uno::Reference<text::XTextAppend> xShapeTextAppend(xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextCursor> xTextCursor;
+ if (!m_bIsNewDoc)
+ {
+ xTextCursor = xShapeTextRange->getText()->createTextCursorByRange(
+ xShapeTextRange->getStart());
+ }
+ TextAppendContext aContext(xShapeTextAppend, xTextCursor);
+ m_aTextAppendStack.push(aContext);
+
+ // Add the shape to the anchored objects stack
+ uno::Reference< text::XTextContent > xTxtContent( xShape, uno::UNO_QUERY_THROW );
+ m_aAnchoredStack.push( AnchoredContext(xTxtContent) );
+
+ uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
+#ifdef DBG_UTIL
+ TagLogger::getInstance().unoPropertySet(xProps);
+#endif
+ text::TextContentAnchorType nAnchorType(text::TextContentAnchorType_AT_PARAGRAPH);
+ xProps->getPropertyValue(getPropertyName( PROP_ANCHOR_TYPE )) >>= nAnchorType;
+ bool checkZOrderStatus = false;
+ if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
+ {
+ SetIsTextFrameInserted(true);
+ // Extract the special "btLr text frame" mode, requested by oox, if needed.
+ // Extract vml ZOrder from FrameInteropGrabBag
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ xShapePropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
+
+ for (const auto& rProp : aGrabBag)
+ {
+ if (rProp.Name == "VML-Z-ORDER")
+ {
+ GraphicZOrderHelper& rZOrderHelper = m_rDMapper.graphicZOrderHelper();
+ sal_Int64 zOrder(0);
+ rProp.Value >>= zOrder;
+ GraphicZOrderHelper::adjustRelativeHeight(zOrder, /*IsZIndex=*/true,
+ zOrder < 0, IsInHeaderFooter());
+ xShapePropertySet->setPropertyValue("ZOrder",
+ uno::Any(rZOrderHelper.findZOrder(zOrder, /*LastDuplicateWins*/true)));
+ rZOrderHelper.addItem(xShapePropertySet, zOrder);
+ xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any( zOrder >= 0 ) );
+ checkZOrderStatus = true;
+ }
+ else if ( rProp.Name == "TxbxHasLink" )
+ {
+ //Chaining of textboxes will happen in ~DomainMapper_Impl
+ //i.e when all the textboxes are read and all its attributes
+ //have been set ( basically the Name/LinkedDisplayName )
+ //which is set in Graphic Import.
+ m_vTextFramesForChaining.push_back(xShape);
+ }
+ }
+
+ uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRange> xTextRange(xTextAppend->createTextCursorByRange(xTextAppend->getEnd()), uno::UNO_QUERY_THROW);
+ xTextAppend->insertTextContent(xTextRange, xTextContent, false);
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+ // we need to re-set this value to xTextContent, then only values are preserved.
+ xPropertySet->setPropertyValue("FrameInteropGrabBag",uno::Any(aGrabBag));
+ }
+ else if (nAnchorType == text::TextContentAnchorType_AS_CHARACTER)
+ {
+ // Fix spacing for as-character objects. If the paragraph has CT_Spacing_after set,
+ // it needs to be set on the object too, as that's what object placement code uses.
+ PropertyMapPtr paragraphContext = GetTopContextOfType( CONTEXT_PARAGRAPH );
+ std::optional<PropertyMap::Property> aPropMargin = paragraphContext->getProperty(PROP_PARA_BOTTOM_MARGIN);
+ if(aPropMargin)
+ xProps->setPropertyValue( getPropertyName( PROP_BOTTOM_MARGIN ), aPropMargin->second );
+ }
+ else
+ {
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ xShapePropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ for (const auto& rProp : aGrabBag)
+ {
+ if (rProp.Name == "VML-Z-ORDER")
+ {
+ GraphicZOrderHelper& rZOrderHelper = m_rDMapper.graphicZOrderHelper();
+ sal_Int64 zOrder(0);
+ rProp.Value >>= zOrder;
+ GraphicZOrderHelper::adjustRelativeHeight(zOrder, /*IsZIndex=*/true,
+ zOrder < 0, IsInHeaderFooter());
+ xShapePropertySet->setPropertyValue("ZOrder",
+ uno::Any(rZOrderHelper.findZOrder(zOrder, /*LastDuplicateWins*/true)));
+ rZOrderHelper.addItem(xShapePropertySet, zOrder);
+ xShapePropertySet->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any( zOrder >= 0 ) );
+ checkZOrderStatus = true;
+ }
+ else if ( rProp.Name == "TxbxHasLink" )
+ {
+ //Chaining of textboxes will happen in ~DomainMapper_Impl
+ //i.e when all the textboxes are read and all its attributes
+ //have been set ( basically the Name/LinkedDisplayName )
+ //which is set in Graphic Import.
+ m_vTextFramesForChaining.push_back(xShape);
+ }
+ }
+
+ if(IsSdtEndBefore())
+ {
+ uno::Reference< beans::XPropertySetInfo > xPropSetInfo;
+ if(xShapePropertySet.is())
+ {
+ xPropSetInfo = xShapePropertySet->getPropertySetInfo();
+ if (xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("InteropGrabBag"))
+ {
+ uno::Sequence<beans::PropertyValue> aShapeGrabBag( comphelper::InitPropertySequence({
+ { "SdtEndBefore", uno::Any(true) }
+ }));
+ xShapePropertySet->setPropertyValue("InteropGrabBag",uno::Any(aShapeGrabBag));
+ }
+ }
+ }
+ }
+ if (!IsInHeaderFooter() && !checkZOrderStatus)
+ xProps->setPropertyValue(
+ getPropertyName( PROP_OPAQUE ),
+ uno::Any( true ) );
+ }
+ m_StreamStateStack.top().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> const xEmbeddedProperties(m_StreamStateStack.top().xEmbedded, uno::UNO_QUERY_THROW);
+ awt::Size aSize = xShape->getSize( );
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_WIDTH), uno::Any(sal_Int32(aSize.Width)));
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_HEIGHT), uno::Any(sal_Int32(aSize.Height)));
+ uno::Reference<beans::XPropertySet> const xShapeProps(xShape, uno::UNO_QUERY);
+ // tdf#130782 copy a11y related properties
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_DESCRIPTION),
+ xShapeProps->getPropertyValue(getPropertyName(PROP_DESCRIPTION)));
+ xEmbeddedProperties->setPropertyValue(getPropertyName(PROP_TITLE),
+ xShapeProps->getPropertyValue(getPropertyName(PROP_TITLE)));
+ uno::Reference<container::XNamed> const xEmbedName(m_StreamStateStack.top().xEmbedded, uno::UNO_QUERY);
+ uno::Reference<container::XNamed> const xShapeName(xShape, uno::UNO_QUERY);
+ OUString const name(xShapeName->getName());
+ if (!name.isEmpty()) // setting empty name will throw
+ {
+ try
+ {
+ xEmbedName->setName(name);
+ }
+ catch (uno::RuntimeException const&)
+ {
+ // ignore - document may contain duplicates (testchartoleobjectembeddings.docx)
+ }
+ }
+}
+
+void DomainMapper_Impl::PopShapeContext()
+{
+ if (hasTableManager())
+ {
+ getTableManager().endLevel();
+ popTableManager();
+ }
+ if ( m_aAnchoredStack.empty() )
+ return;
+
+ // For OLE object replacement shape, the text append context was already removed
+ // or the OLE object couldn't be inserted.
+ if ( !m_aAnchoredStack.top().bToRemove )
+ {
+ RemoveLastParagraph();
+ if (!m_aTextAppendStack.empty())
+ m_aTextAppendStack.pop();
+ }
+
+ uno::Reference< text::XTextContent > xObj = m_aAnchoredStack.top( ).xTextContent;
+ try
+ {
+ appendTextContent( xObj, uno::Sequence< beans::PropertyValue >() );
+ }
+ catch ( const uno::RuntimeException& )
+ {
+ // this is normal: the shape is already attached
+ }
+
+ const uno::Reference<drawing::XShape> xShape( xObj, uno::UNO_QUERY_THROW );
+ // Remove the shape if required (most likely replacement shape for OLE object)
+ // or anchored to a discarded header or footer
+ if ( m_aAnchoredStack.top().bToRemove || m_bDiscardHeaderFooter )
+ {
+ try
+ {
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ if ( xDrawPage.is() )
+ xDrawPage->remove( xShape );
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+
+ // Relative width calculations deferred until section's margins are defined.
+ // Being cautious: only deferring undefined/minimum-width shapes in order to avoid causing potential regressions
+ css::awt::Size aShapeSize;
+ try
+ {
+ aShapeSize = xShape->getSize();
+ }
+ catch (const css::uno::RuntimeException& e)
+ {
+ // May happen e.g. when text frame has no frame format
+ // See sw/qa/extras/ooxmlimport/data/n779627.docx
+ SAL_WARN("writerfilter.dmapper", "getSize failed. " << e.Message);
+ }
+ if( aShapeSize.Width <= 2 )
+ {
+ const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
+ SectionPropertyMap* pSectionContext = GetSectionContext();
+ if ( pSectionContext && (!hasTableManager() || !getTableManager().isInTable()) &&
+ xShapePropertySet->getPropertySetInfo()->hasPropertyByName(getPropertyName(PROP_RELATIVE_WIDTH)) )
+ {
+ pSectionContext->addRelativeWidthShape(xShape);
+ }
+ }
+
+ m_aAnchoredStack.pop();
+}
+
+bool DomainMapper_Impl::IsSdtEndBefore()
+{
+ bool bIsSdtEndBefore = false;
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_CHARACTER);
+ if(pContext)
+ {
+ const uno::Sequence< beans::PropertyValue > currentCharProps = pContext->GetPropertyValues();
+ for (const auto& rCurrentCharProp : currentCharProps)
+ {
+ if (rCurrentCharProp.Name == "CharInteropGrabBag")
+ {
+ uno::Sequence<beans::PropertyValue> aCharGrabBag;
+ rCurrentCharProp.Value >>= aCharGrabBag;
+ for (const auto& rProp : 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_StreamStateStack.top().nTableDepth == (m_StreamStateStack.top().nTableCellDepth + 1))
+ && m_StreamStateStack.top().xPreviousParagraph.is()
+ && hasTableManager() && getTableManager().isCellLastParaAfterAutospacing())
+ {
+ uno::Reference<container::XNamed> xPreviousNumberingRules(m_StreamStateStack.top().xPreviousParagraph->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+ if ( !xPreviousNumberingRules.is() || xPreviousNumberingRules->getName().isEmpty() )
+ m_StreamStateStack.top().xPreviousParagraph->setPropertyValue("ParaBottomMargin", uno::Any(static_cast<sal_Int32>(0)));
+ }
+
+ m_StreamStateStack.top().xPreviousParagraph.clear();
+
+ // next table paragraph will be first paragraph in a cell
+ m_StreamStateStack.top().bFirstParagraphInCell = true;
+}
+
+void DomainMapper_Impl::HandleAltChunk(const OUString& rStreamName)
+{
+ try
+ {
+ // Create the import filter.
+ uno::Reference<lang::XMultiServiceFactory> xMultiServiceFactory(
+ comphelper::getProcessServiceFactory());
+ uno::Reference<uno::XInterface> xDocxFilter
+ = xMultiServiceFactory->createInstance("com.sun.star.comp.Writer.WriterFilter");
+
+ // Set the target document.
+ uno::Reference<document::XImporter> xImporter(xDocxFilter, uno::UNO_QUERY);
+ xImporter->setTargetDocument(m_xTextDocument);
+
+ // Set the import parameters.
+ uno::Reference<embed::XHierarchicalStorageAccess> xStorageAccess(m_xDocumentStorage,
+ uno::UNO_QUERY);
+ if (!xStorageAccess.is())
+ {
+ return;
+ }
+ // Turn the ZIP stream into a seekable one, as the importer only works with such streams.
+ uno::Reference<io::XStream> xStream = xStorageAccess->openStreamElementByHierarchicalName(
+ rStreamName, embed::ElementModes::READ);
+ std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(xStream, true);
+ SvMemoryStream aMemory;
+ aMemory.WriteStream(*pStream);
+ uno::Reference<io::XStream> xInputStream = new utl::OStreamWrapper(aMemory);
+ // Not handling AltChunk during paste for now.
+ uno::Reference<text::XTextRange> xInsertTextRange = GetCurrentXText()->getEnd();
+ uno::Reference<text::XTextRange> xSectionStartingRange;
+ SectionPropertyMap* pSectionContext = GetSectionContext();
+ if (pSectionContext)
+ {
+ xSectionStartingRange = pSectionContext->GetStartingRange();
+ }
+ uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
+ { "InputStream", uno::Any(xInputStream) },
+ { "InsertMode", uno::Any(true) },
+ { "TextInsertModeRange", uno::Any(xInsertTextRange) },
+ { "AltChunkMode", uno::Any(true) },
+ { "AltChunkStartingRange", uno::Any(xSectionStartingRange) },
+ }));
+
+ // Do the actual import.
+ uno::Reference<document::XFilter> xFilter(xDocxFilter, uno::UNO_QUERY);
+ xFilter->filter(aDescriptor);
+ }
+ catch (const uno::Exception& rException)
+ {
+ SAL_WARN("writerfilter", "DomainMapper_Impl::HandleAltChunk: failed to handle alt chunk: "
+ << rException.Message);
+ }
+}
+
+void DomainMapper_Impl::HandlePTab(sal_Int32 nAlignment)
+{
+ // We only handle the case when the line already has content, so the left-aligned ptab is
+ // equivalent to a line break.
+ if (nAlignment != NS_ooxml::LN_Value_ST_PTabAlignment_left)
+ {
+ return;
+ }
+
+ if (m_aTextAppendStack.empty())
+ {
+ return;
+ }
+
+ uno::Reference<text::XTextAppend> xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (!xTextAppend.is())
+ {
+ return;
+ }
+
+ uno::Reference<css::text::XTextRange> xInsertPosition
+ = m_aTextAppendStack.top().xInsertPosition;
+ if (!xInsertPosition.is())
+ {
+ xInsertPosition = xTextAppend->getEnd();
+ }
+ uno::Reference<text::XTextCursor> xCursor
+ = xTextAppend->createTextCursorByRange(xInsertPosition);
+
+ // Assume that we just inserted a tab character.
+ xCursor->goLeft(1, true);
+ if (xCursor->getString() != "\t")
+ {
+ return;
+ }
+
+ // Assume that there is some content before the tab character.
+ uno::Reference<text::XParagraphCursor> xParagraphCursor(xCursor, uno::UNO_QUERY);
+ if (!xParagraphCursor.is())
+ {
+ return;
+ }
+
+ xCursor->collapseToStart();
+ xParagraphCursor->gotoStartOfParagraph(true);
+ if (xCursor->isCollapsed())
+ {
+ return;
+ }
+
+ // Then select the tab again and replace with a line break.
+ xCursor->collapseToEnd();
+ xCursor->goRight(1, true);
+ xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::LINE_BREAK, true);
+}
+
+void DomainMapper_Impl::HandleLineBreakClear(sal_Int32 nClear)
+{
+ switch (nClear)
+ {
+ case NS_ooxml::LN_Value_ST_BrClear_left:
+ // SwLineBreakClear::LEFT
+ m_StreamStateStack.top().oLineBreakClear = 1;
+ break;
+ case NS_ooxml::LN_Value_ST_BrClear_right:
+ // SwLineBreakClear::RIGHT
+ m_StreamStateStack.top().oLineBreakClear = 2;
+ break;
+ case NS_ooxml::LN_Value_ST_BrClear_all:
+ // SwLineBreakClear::ALL
+ m_StreamStateStack.top().oLineBreakClear = 3;
+ break;
+ }
+}
+
+void DomainMapper_Impl::HandleLineBreak(const PropertyMapPtr& pPropertyMap)
+{
+ if (!m_StreamStateStack.top().oLineBreakClear.has_value())
+ {
+ appendTextPortion("\n", pPropertyMap);
+ return;
+ }
+
+ if (GetTextFactory().is())
+ {
+ uno::Reference<text::XTextContent> xLineBreak(
+ GetTextFactory()->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
+ xLineBreakProps->setPropertyValue("Clear", uno::Any(*m_StreamStateStack.top().oLineBreakClear));
+ appendTextContent(xLineBreak, pPropertyMap->GetPropertyValues());
+ }
+ m_StreamStateStack.top().oLineBreakClear.reset();
+}
+
+static sal_Int16 lcl_ParseNumberingType( std::u16string_view rCommand )
+{
+ sal_Int16 nRet = style::NumberingType::PAGE_DESCRIPTOR;
+
+ // The command looks like: " PAGE \* Arabic "
+ // tdf#132185: but may as well be "PAGE \* Arabic"
+ OUString sNumber;
+ constexpr OUString rSeparator(u"\\* "_ustr);
+ if (size_t nStartIndex = rCommand.find(rSeparator); nStartIndex != std::u16string_view::npos)
+ {
+ sal_Int32 nStartIndex2 = nStartIndex + rSeparator.getLength();
+ sNumber = o3tl::getToken(rCommand, 0, ' ', nStartIndex2);
+ }
+
+ if( !sNumber.isEmpty() )
+ {
+ //todo: might make sense to hash this list, too
+ struct NumberingPairs
+ {
+ const char* cWordName;
+ sal_Int16 nType;
+ };
+ static const NumberingPairs aNumberingPairs[] =
+ {
+ {"Arabic", style::NumberingType::ARABIC}
+ ,{"ROMAN", style::NumberingType::ROMAN_UPPER}
+ ,{"roman", style::NumberingType::ROMAN_LOWER}
+ ,{"ALPHABETIC", style::NumberingType::CHARS_UPPER_LETTER}
+ ,{"alphabetic", style::NumberingType::CHARS_LOWER_LETTER}
+ ,{"CircleNum", style::NumberingType::CIRCLE_NUMBER}
+ ,{"ThaiArabic", style::NumberingType::CHARS_THAI}
+ ,{"ThaiCardText", style::NumberingType::CHARS_THAI}
+ ,{"ThaiLetter", style::NumberingType::CHARS_THAI}
+// ,{"SBCHAR", style::NumberingType::}
+// ,{"DBCHAR", style::NumberingType::}
+// ,{"DBNUM1", style::NumberingType::}
+// ,{"DBNUM2", style::NumberingType::}
+// ,{"DBNUM3", style::NumberingType::}
+// ,{"DBNUM4", style::NumberingType::}
+ ,{"Aiueo", style::NumberingType::AIU_FULLWIDTH_JA}
+ ,{"Iroha", style::NumberingType::IROHA_FULLWIDTH_JA}
+// ,{"ZODIAC1", style::NumberingType::}
+// ,{"ZODIAC2", style::NumberingType::}
+// ,{"ZODIAC3", style::NumberingType::}
+// ,{"CHINESENUM1", style::NumberingType::}
+// ,{"CHINESENUM2", style::NumberingType::}
+// ,{"CHINESENUM3", style::NumberingType::}
+ ,{"ArabicAlpha", style::NumberingType::CHARS_ARABIC}
+ ,{"ArabicAbjad", style::NumberingType::FULLWIDTH_ARABIC}
+ ,{"Ganada", style::NumberingType::HANGUL_JAMO_KO}
+ ,{"Chosung", style::NumberingType::HANGUL_SYLLABLE_KO}
+ ,{"KoreanCounting", style::NumberingType::NUMBER_HANGUL_KO}
+ ,{"KoreanLegal", style::NumberingType::NUMBER_LEGAL_KO}
+ ,{"KoreanDigital", style::NumberingType::NUMBER_DIGITAL_KO}
+ ,{"KoreanDigital2", style::NumberingType::NUMBER_DIGITAL2_KO}
+/* possible values:
+style::NumberingType::
+
+ CHARS_UPPER_LETTER_N
+ CHARS_LOWER_LETTER_N
+ TRANSLITERATION
+ NATIVE_NUMBERING
+ CIRCLE_NUMBER
+ NUMBER_LOWER_ZH
+ NUMBER_UPPER_ZH
+ NUMBER_UPPER_ZH_TW
+ TIAN_GAN_ZH
+ DI_ZI_ZH
+ NUMBER_TRADITIONAL_JA
+ AIU_HALFWIDTH_JA
+ IROHA_HALFWIDTH_JA
+ NUMBER_UPPER_KO
+ NUMBER_HANGUL_KO
+ HANGUL_JAMO_KO
+ HANGUL_SYLLABLE_KO
+ HANGUL_CIRCLED_JAMO_KO
+ HANGUL_CIRCLED_SYLLABLE_KO
+ CHARS_HEBREW
+ CHARS_NEPALI
+ CHARS_KHMER
+ CHARS_LAO
+ CHARS_TIBETAN
+ CHARS_CYRILLIC_UPPER_LETTER_BG
+ CHARS_CYRILLIC_LOWER_LETTER_BG
+ CHARS_CYRILLIC_UPPER_LETTER_N_BG
+ CHARS_CYRILLIC_LOWER_LETTER_N_BG
+ CHARS_CYRILLIC_UPPER_LETTER_RU
+ CHARS_CYRILLIC_LOWER_LETTER_RU
+ CHARS_CYRILLIC_UPPER_LETTER_N_RU
+ CHARS_CYRILLIC_LOWER_LETTER_N_RU
+ CHARS_CYRILLIC_UPPER_LETTER_SR
+ CHARS_CYRILLIC_LOWER_LETTER_SR
+ CHARS_CYRILLIC_UPPER_LETTER_N_SR
+ CHARS_CYRILLIC_LOWER_LETTER_N_SR
+ CHARS_CYRILLIC_UPPER_LETTER_UK
+ CHARS_CYRILLIC_LOWER_LETTER_UK
+ CHARS_CYRILLIC_UPPER_LETTER_N_UK
+ CHARS_CYRILLIC_LOWER_LETTER_N_UK*/
+
+ };
+ for(const NumberingPairs& rNumberingPair : aNumberingPairs)
+ {
+ if( /*sCommand*/sNumber.equalsAscii(rNumberingPair.cWordName ))
+ {
+ nRet = rNumberingPair.nType;
+ break;
+ }
+ }
+
+ }
+ return nRet;
+}
+
+
+static OUString lcl_ParseFormat( const OUString& rCommand )
+{
+ // The command looks like: " DATE \@"dd MMMM yyyy" or "09/02/2014"
+ OUString command;
+ sal_Int32 delimPos = rCommand.indexOf("\\@");
+ if (delimPos != -1)
+ {
+ // Remove whitespace permitted by standard between \@ and "
+ const sal_Int32 nQuoteIndex = rCommand.indexOf('\"');
+ if (nQuoteIndex != -1)
+ {
+ sal_Int32 wsChars = nQuoteIndex - delimPos - 2;
+ command = rCommand.replaceAt(delimPos+2, wsChars, u"");
+ }
+ else
+ {
+ // turn date \@ MM into date \@"MM"
+ command = OUString::Concat(rCommand.subView(0, delimPos + 2)) + "\"" + o3tl::trim(rCommand.subView(delimPos + 2)) + "\"";
+ }
+ return OUString(msfilter::util::findQuotedText(command, u"\\@\"", '\"'));
+ }
+
+ return OUString();
+}
+/*-------------------------------------------------------------------------
+extract a parameter (with or without quotes) between the command and the following backslash
+ -----------------------------------------------------------------------*/
+static OUString lcl_ExtractToken(std::u16string_view rCommand,
+ size_t & rIndex, bool & rHaveToken, bool & rIsSwitch)
+{
+ rHaveToken = false;
+ rIsSwitch = false;
+
+ OUStringBuffer token;
+ bool bQuoted(false);
+ for (; rIndex < rCommand.size(); ++rIndex)
+ {
+ sal_Unicode const currentChar(rCommand[rIndex]);
+ switch (currentChar)
+ {
+ case '\\':
+ {
+ if (rIndex == rCommand.size() - 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 OUString(rCommand.substr(rIndex - 2, 2)).toAsciiUpperCase();
+ }
+ else
+ { // leave rIndex, read it again next time
+ return token.makeStringAndClear();
+ }
+ }
+ }
+ break;
+ case '\"':
+ if (bQuoted || !token.isEmpty())
+ {
+ rHaveToken = true;
+ if (bQuoted)
+ {
+ ++rIndex;
+ }
+ return token.makeStringAndClear();
+ }
+ else
+ {
+ bQuoted = true;
+ }
+ break;
+ case ' ':
+ if (bQuoted)
+ {
+ token.append(' ');
+ }
+ else
+ {
+ if (!token.isEmpty())
+ {
+ rHaveToken = true;
+ ++rIndex;
+ return token.makeStringAndClear();
+ }
+ }
+ break;
+ case '=':
+ if (token.isEmpty())
+ {
+ rHaveToken = true;
+ ++rIndex;
+ return "FORMULA";
+ }
+ else
+ token.append('=');
+ break;
+ default:
+ token.append(currentChar);
+ break;
+ }
+ }
+ assert(rIndex == rCommand.size());
+ 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(std::u16string_view rCommand)
+{
+ OUString sType;
+ std::vector<OUString> arguments;
+ std::vector<OUString> switches;
+ size_t 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.size() >= 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.size());
+ 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.size());
+
+ return std::make_tuple(sType, arguments, switches);
+}
+
+static OUString lcl_ExtractVariableAndHint( std::u16string_view rCommand, OUString& rHint )
+{
+ // the first word after "ASK " is the variable
+ // the text after the variable and before a '\' is the hint
+ // if no hint is set the variable is used as hint
+ // the quotes of the hint have to be removed
+ size_t nIndex = rCommand.find( ' ', 2); //find last space after 'ASK'
+ if (nIndex == std::u16string_view::npos)
+ return OUString();
+ while (nIndex < rCommand.size() && rCommand[nIndex] == ' ')
+ ++nIndex;
+ std::u16string_view sShortCommand( rCommand.substr( nIndex ) ); //cut off the " ASK "
+
+ sShortCommand = o3tl::getToken(sShortCommand, 0, '\\');
+ sal_Int32 nIndex2 = 0;
+ std::u16string_view sRet = o3tl::getToken(sShortCommand, 0, ' ', nIndex2);
+ if( nIndex2 > 0)
+ rHint = sShortCommand.substr( nIndex2 );
+ if( rHint.isEmpty() )
+ rHint = sRet;
+ return OUString(sRet);
+}
+
+static size_t nextCode(std::u16string_view rCommand, size_t pos)
+{
+ bool inQuotes = false;
+ for (; pos < rCommand.size(); ++pos)
+ {
+ switch (rCommand[pos])
+ {
+ case '"':
+ inQuotes = !inQuotes;
+ break;
+ case '\\':
+ ++pos;
+ if (!inQuotes)
+ return pos;
+ break;
+ }
+ }
+ return std::u16string_view::npos;
+}
+
+// Returns the position of the field code
+static size_t findCode(std::u16string_view rCommand, sal_Unicode cSwitch)
+{
+ for (size_t i = nextCode(rCommand, 0); i < rCommand.size(); i = nextCode(rCommand, i))
+ if (rCommand[i] == cSwitch)
+ return i;
+
+ return std::u16string_view::npos;
+}
+
+static bool lcl_FindInCommand(
+ std::u16string_view rCommand,
+ sal_Unicode cSwitch,
+ OUString& rValue )
+{
+ if (size_t i = findCode(rCommand, cSwitch); i < rCommand.size())
+ {
+ ++i;
+ size_t next = nextCode(rCommand, i);
+ if (next < rCommand.size())
+ --next; // get back before the next '\\'
+ rValue = o3tl::trim(rCommand.substr(i, next - i));
+ return true;
+ }
+
+ return false;
+}
+
+static OUString lcl_trim(std::u16string_view sValue)
+{
+ // it seems, all kind of quotation marks are allowed around index type identifiers
+ // TODO apply this on bookmarks, too, if needed
+ return OUString(o3tl::trim(sValue)).replaceAll("\"","").replaceAll(u"“", "").replaceAll(u"”", "");
+}
+
+/*-------------------------------------------------------------------------
+ extract the number format from the command and apply the resulting number
+ format to the XPropertySet
+ -----------------------------------------------------------------------*/
+void DomainMapper_Impl::SetNumberFormat( const OUString& rCommand,
+ uno::Reference< beans::XPropertySet > const& xPropertySet,
+ bool const bDetectFormat)
+{
+ OUString sFormatString = lcl_ParseFormat( rCommand );
+ // find \h - hijri/luna calendar todo: what about saka/era calendar?
+ bool bHijri = 0 < rCommand.indexOf("\\h ");
+ lang::Locale aUSLocale;
+ aUSLocale.Language = "en";
+ aUSLocale.Country = "US";
+
+ lang::Locale aCurrentLocale;
+ GetAnyProperty(PROP_CHAR_LOCALE, GetTopContext()) >>= aCurrentLocale;
+
+ if (sFormatString.isEmpty())
+ {
+ // No format specified. MS Word uses different formats depending on w:lang,
+ // "M/d/yyyy h:mm:ss AM/PM" for en-US, and "dd/MM/yyyy hh:mm:ss AM/PM" for en-GB.
+ // ALSO SEE: ww8par5's GetWordDefaultDateStringAsUS.
+ sal_Int32 nPos = rCommand.indexOf(" \\");
+ OUString sCommand = nPos == -1 ? rCommand.trim()
+ : OUString(o3tl::trim(rCommand.subView(0, nPos)));
+ if (sCommand == "CREATEDATE" || sCommand == "PRINTDATE" || sCommand == "SAVEDATE")
+ {
+ try
+ {
+ css::uno::Reference<css::i18n::XNumberFormatCode> const& xNumberFormatCode =
+ i18n::NumberFormatMapper::create(m_xComponentContext);
+ sFormatString = xNumberFormatCode->getFormatCode(
+ css::i18n::NumberFormatIndex::DATE_SYSTEM_SHORT, aCurrentLocale).Code;
+ nPos = sFormatString.indexOf("YYYY");
+ if (nPos == -1)
+ sFormatString = sFormatString.replaceFirst("YY", "YYYY");
+ if (aCurrentLocale == aUSLocale)
+ sFormatString += " h:mm:ss AM/PM";
+ else
+ sFormatString += " hh:mm:ss AM/PM";
+ }
+ catch(const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+ }
+ }
+ OUString sFormat = ConversionHelper::ConvertMSFormatStringToSO( sFormatString, aCurrentLocale, bHijri);
+ //get the number formatter and convert the string to a format value
+ try
+ {
+ sal_Int32 nKey = 0;
+ uno::Reference< util::XNumberFormatsSupplier > xNumberSupplier( m_xTextDocument, uno::UNO_QUERY_THROW );
+ if( bDetectFormat )
+ {
+ uno::Reference< util::XNumberFormatter> xFormatter(util::NumberFormatter::create(m_xComponentContext), uno::UNO_QUERY_THROW);
+ xFormatter->attachNumberFormatsSupplier( xNumberSupplier );
+ nKey = xFormatter->detectNumberFormat( 0, rCommand );
+ }
+ else
+ {
+ nKey = xNumberSupplier->getNumberFormats()->addNewConverted( sFormat, aUSLocale, aCurrentLocale );
+ }
+ xPropertySet->setPropertyValue(
+ getPropertyName(PROP_NUMBER_FORMAT),
+ uno::Any( nKey ));
+ }
+ catch(const uno::Exception&)
+ {
+ }
+}
+
+static uno::Any lcl_getGrabBagValue( const uno::Sequence<beans::PropertyValue>& grabBag, OUString const & name )
+{
+ auto pProp = std::find_if(grabBag.begin(), grabBag.end(),
+ [&name](const beans::PropertyValue& rProp) { return rProp.Name == name; });
+ if (pProp != grabBag.end())
+ return pProp->Value;
+ return uno::Any();
+}
+
+//Link the text frames.
+void DomainMapper_Impl::ChainTextFrames()
+{
+ //can't link textboxes if there are not even two of them...
+ if( 2 > m_vTextFramesForChaining.size() )
+ return ;
+
+ struct TextFramesForChaining {
+ css::uno::Reference< css::drawing::XShape > xShape;
+ sal_Int32 nId;
+ sal_Int32 nSeq;
+ OUString s_mso_next_textbox;
+ OUString shapeName;
+ TextFramesForChaining() : nId(0), nSeq(0) {}
+ } ;
+ typedef std::map <OUString, TextFramesForChaining> ChainMap;
+
+ try
+ {
+ ChainMap aTextFramesForChainingHelper;
+ ::std::vector<TextFramesForChaining> chainingWPS;
+ OUString sChainNextName("ChainNextName");
+
+ //learn about ALL of the textboxes and their chaining values first - because frames are processed in no specific order.
+ for( const auto& rTextFrame : m_vTextFramesForChaining )
+ {
+ uno::Reference<text::XTextContent> xTextContent(rTextFrame, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo;
+ if( xPropertySet.is() )
+ xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xPropertySet, uno::UNO_QUERY);
+
+ TextFramesForChaining aChainStruct;
+ OUString sShapeName;
+ OUString sLinkChainName;
+
+ //The chaining name and the shape name CAN be different in .docx.
+ //MUST use LinkDisplayName/ChainName as the shape name for establishing links.
+ if ( xServiceInfo->supportsService("com.sun.star.text.TextFrame") )
+ {
+ xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
+ xPropertySet->getPropertyValue("LinkDisplayName") >>= sShapeName;
+ }
+ else
+ {
+ xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ xPropertySet->getPropertyValue("ChainName") >>= sShapeName;
+ }
+
+ lcl_getGrabBagValue( aGrabBag, "Txbx-Id") >>= aChainStruct.nId;
+ lcl_getGrabBagValue( aGrabBag, "Txbx-Seq") >>= aChainStruct.nSeq;
+ lcl_getGrabBagValue( aGrabBag, "LinkChainName") >>= sLinkChainName;
+ lcl_getGrabBagValue( aGrabBag, "mso-next-textbox") >>= aChainStruct.s_mso_next_textbox;
+
+ //Sometimes the shape names have not been imported. If not, we may have a fallback name.
+ //Set name later, only if required for linking.
+ aChainStruct.shapeName = sShapeName;
+
+ if (!sLinkChainName.isEmpty())
+ {
+ aChainStruct.xShape = rTextFrame;
+ aTextFramesForChainingHelper[sLinkChainName] = aChainStruct;
+ }
+ if (aChainStruct.s_mso_next_textbox.isEmpty())
+ { // no VML chaining => try to chain DrawingML via IDs
+ aChainStruct.xShape = rTextFrame;
+ if (!sLinkChainName.isEmpty())
+ { // for member of group shapes, TestTdf73499
+ aChainStruct.shapeName = sLinkChainName;
+ }
+ chainingWPS.emplace_back(aChainStruct);
+ }
+ }
+
+ //if mso-next-textbox tags are provided, create those vml-style links first. Afterwards we will make dml-style id/seq links.
+ for (auto& msoItem : aTextFramesForChainingHelper)
+ {
+ //if no mso-next-textbox, we are done.
+ //if it points to itself, we are done.
+ if( !msoItem.second.s_mso_next_textbox.isEmpty()
+ && msoItem.second.s_mso_next_textbox != msoItem.first )
+ {
+ ChainMap::iterator nextFinder=aTextFramesForChainingHelper.find(msoItem.second.s_mso_next_textbox);
+ if( nextFinder != aTextFramesForChainingHelper.end() )
+ {
+ //if the frames have no name yet, then set them. LinkDisplayName / ChainName are read-only.
+ if (msoItem.second.shapeName.isEmpty())
+ {
+ uno::Reference< container::XNamed > xNamed( msoItem.second.xShape, uno::UNO_QUERY );
+ if ( xNamed.is() )
+ {
+ xNamed->setName( msoItem.first );
+ msoItem.second.shapeName = msoItem.first;
+ }
+ }
+ if (nextFinder->second.shapeName.isEmpty())
+ {
+ uno::Reference< container::XNamed > xNamed( nextFinder->second.xShape, uno::UNO_QUERY );
+ if ( xNamed.is() )
+ {
+ xNamed->setName( nextFinder->first );
+ nextFinder->second.shapeName = msoItem.first;
+ }
+ }
+
+ uno::Reference<text::XTextContent> xTextContent(msoItem.second.xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+
+ //The reverse chaining happens automatically, so only one direction needs to be set
+ xPropertySet->setPropertyValue(sChainNextName, uno::Any(nextFinder->second.shapeName));
+
+ //the last item in an mso-next-textbox chain is indistinguishable from id/seq items. Now that it is handled, remove it.
+ if( nextFinder->second.s_mso_next_textbox.isEmpty() )
+ aTextFramesForChainingHelper.erase(nextFinder->first);
+ }
+ }
+ }
+
+ //TODO: Perhaps allow reverse sequences when mso-layout-flow-alt = "bottom-to-top"
+ const sal_Int32 nDirection = 1;
+
+ //Finally - go through and attach the chains based on matching ID and incremented sequence number (dml-style).
+ for (const auto& rOuter : chainingWPS)
+ {
+ for (const auto& rInner : chainingWPS)
+ {
+ if (rInner.nId == rOuter.nId)
+ {
+ if (rInner.nSeq == (rOuter.nSeq + nDirection))
+ {
+ uno::Reference<text::XTextContent> const xTextContent(rOuter.xShape, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+
+ //The reverse chaining happens automatically, so only one direction needs to be set
+ xPropertySet->setPropertyValue(sChainNextName, uno::Any(rInner.shapeName));
+ break ; //there cannot be more than one next frame
+ }
+ }
+ }
+ }
+ m_vTextFramesForChaining.clear(); //clear the vector
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper");
+ }
+}
+
+void DomainMapper_Impl::PushTextBoxContent()
+{
+ if (m_StreamStateStack.top().bIsInTextBox)
+ return;
+
+ try
+ {
+ uno::Reference<text::XTextFrame> xTBoxFrame(
+ m_xTextFactory->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XNamed>(xTBoxFrame, uno::UNO_QUERY_THROW)
+ ->setName("textbox" + OUString::number(m_xPendingTextBoxFrames.size() + 1));
+ uno::Reference<text::XTextAppendAndConvert>(m_aTextAppendStack.top().xTextAppend,
+ uno::UNO_QUERY_THROW)
+ ->appendTextContent(xTBoxFrame, beans::PropertyValues());
+ m_xPendingTextBoxFrames.push(xTBoxFrame);
+
+ m_aTextAppendStack.push(TextAppendContext(uno::Reference<text::XTextAppend>(xTBoxFrame, uno::UNO_QUERY_THROW), {}));
+ m_StreamStateStack.top().bIsInTextBox = true;
+
+ appendTableManager();
+ appendTableHandler();
+ getTableManager().startLevel();
+ }
+ catch (uno::Exception& e)
+ {
+ SAL_WARN("writerfilter.dmapper", "Exception during creating textbox (" + e.Message + ")!");
+ }
+}
+
+void DomainMapper_Impl::PopTextBoxContent()
+{
+ if (!m_StreamStateStack.top().bIsInTextBox || m_xPendingTextBoxFrames.empty())
+ return;
+
+ if (uno::Reference<text::XTextFrame>(m_aTextAppendStack.top().xTextAppend, uno::UNO_QUERY).is())
+ {
+ if (hasTableManager())
+ {
+ getTableManager().endLevel();
+ popTableManager();
+ }
+ RemoveLastParagraph();
+
+ m_aTextAppendStack.pop();
+ m_StreamStateStack.top().bIsInTextBox = false;
+ }
+}
+
+void DomainMapper_Impl::AttachTextBoxContentToShape(css::uno::Reference<css::drawing::XShape> xShape)
+{
+ // Without textbox or shape pointless to continue
+ if (m_xPendingTextBoxFrames.empty() || !xShape)
+ return;
+
+ uno::Reference< drawing::XShapes >xGroup(xShape, uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet >xProps(xShape, uno::UNO_QUERY);
+
+ // If this is a group go inside
+ if (xGroup)
+ for (sal_Int32 i = 0; i < xGroup->getCount(); ++i)
+ AttachTextBoxContentToShape(
+ uno::Reference<drawing::XShape>(xGroup->getByIndex(i), uno::UNO_QUERY));
+
+ // if this shape has to be a textbox, attach the frame
+ if (!xProps->getPropertyValue("TextBox").get<bool>())
+ return;
+
+ // if this is a textbox there must be a waiting frame
+ auto xTextBox = m_xPendingTextBoxFrames.front();
+ if (!xTextBox)
+ return;
+
+ // Pop the pending frames
+ m_xPendingTextBoxFrames.pop();
+
+ // Attach the textbox to the shape
+ try
+ {
+ xProps->setPropertyValue("TextBoxContent", uno::Any(xTextBox));
+ }
+ catch (...)
+ {
+ SAL_WARN("writerfilter.dmapper", "Exception while trying to attach textboxes!");
+ return;
+ }
+
+ // If attaching is successful, then do the linking
+ try
+ {
+ // Get the name of the textbox
+ OUString sTextBoxName;
+ uno::Reference<container::XNamed> xName(xTextBox, uno::UNO_QUERY);
+ if (xName && !xName->getName().isEmpty())
+ sTextBoxName = xName->getName();
+
+ // Try to get the grabbag
+ uno::Sequence<beans::PropertyValue> aOldGrabBagSeq;
+ if (xProps->getPropertySetInfo()->hasPropertyByName("InteropGrabBag"))
+ xProps->getPropertyValue("InteropGrabBag") >>= aOldGrabBagSeq;
+
+ // If the grabbag successfully get...
+ if (!aOldGrabBagSeq.hasElements())
+ return;
+
+ // Check for the existing linking information
+ bool bSuccess = false;
+ beans::PropertyValues aNewGrabBagSeq;
+ const auto& aHasLink = lcl_getGrabBagValue(aOldGrabBagSeq, "TxbxHasLink");
+
+ // If there must be a link, do it
+ if (aHasLink.hasValue() && aHasLink.get<bool>())
+ {
+ auto aLinkProp = comphelper::makePropertyValue("LinkChainName", sTextBoxName);
+ for (sal_uInt32 i = 0; i < aOldGrabBagSeq.size(); ++i)
+ {
+ aNewGrabBagSeq.realloc(i + 1);
+ // If this is the link name replace it
+ if (!aOldGrabBagSeq[i].Name.isEmpty() && !aLinkProp.Name.isEmpty()
+ && (aOldGrabBagSeq[i].Name == aLinkProp.Name))
+ {
+ aNewGrabBagSeq.getArray()[i] = aLinkProp;
+ bSuccess = true;
+ }
+ // else copy
+ else
+ aNewGrabBagSeq.getArray()[i] = aOldGrabBagSeq[i];
+ }
+
+ // If there was no replacement, append the linking data
+ if (!bSuccess)
+ {
+ aNewGrabBagSeq.realloc(aNewGrabBagSeq.size() + 1);
+ aNewGrabBagSeq.getArray()[aNewGrabBagSeq.size() - 1] = aLinkProp;
+ bSuccess = true;
+ }
+ }
+
+ // If the linking changed the grabbag, apply the modifications
+ if (aNewGrabBagSeq.hasElements() && bSuccess)
+ {
+ xProps->setPropertyValue("InteropGrabBag", uno::Any(aNewGrabBagSeq));
+ m_vTextFramesForChaining.push_back(xShape);
+ }
+ }
+ catch (...)
+ {
+ SAL_WARN("writerfilter.dmapper", "Exception while trying to link textboxes!");
+ }
+}
+
+uno::Reference<beans::XPropertySet> DomainMapper_Impl::FindOrCreateFieldMaster(const char* pFieldMasterService, const OUString& rFieldMasterName)
+{
+ // query master, create if not available
+ uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier( GetTextDocument(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
+ uno::Reference< beans::XPropertySet > xMaster;
+ OUString sFieldMasterService( OUString::createFromAscii(pFieldMasterService) );
+ OUStringBuffer aFieldMasterName;
+ OUString sDatabaseDataSourceName = GetSettingsTable()->GetCurrentDatabaseDataSource();
+ bool bIsMergeField = sFieldMasterService.endsWith("Database");
+ aFieldMasterName.appendAscii( pFieldMasterService );
+ aFieldMasterName.append('.');
+ if ( bIsMergeField && !sDatabaseDataSourceName.isEmpty() )
+ {
+ aFieldMasterName.append(sDatabaseDataSourceName + ".");
+ }
+ aFieldMasterName.append(rFieldMasterName);
+ OUString sFieldMasterName = aFieldMasterName.makeStringAndClear();
+ if(xFieldMasterAccess->hasByName(sFieldMasterName))
+ {
+ //get the master
+ xMaster.set(xFieldMasterAccess->getByName(sFieldMasterName), uno::UNO_QUERY_THROW);
+ }
+ else if( m_xTextFactory.is() )
+ {
+ //create the master
+ xMaster.set( m_xTextFactory->createInstance(sFieldMasterService), uno::UNO_QUERY_THROW);
+ if ( !bIsMergeField || sDatabaseDataSourceName.isEmpty() )
+ {
+ //set the master's name
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_NAME),
+ uno::Any(rFieldMasterName));
+ } else {
+ // set database data, based on the "databasename.tablename" of sDatabaseDataSourceName
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_DATABASE_NAME),
+ uno::Any(sDatabaseDataSourceName.copy(0, sDatabaseDataSourceName.indexOf('.'))));
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_COMMAND_TYPE),
+ uno::Any(sal_Int32(0)));
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_DATATABLE_NAME),
+ uno::Any(sDatabaseDataSourceName.copy(sDatabaseDataSourceName.indexOf('.') + 1)));
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_DATACOLUMN_NAME),
+ uno::Any(rFieldMasterName));
+ }
+ }
+ return xMaster;
+}
+
+void DomainMapper_Impl::PushFieldContext()
+{
+ m_StreamStateStack.top().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();
+}
+
+
+FieldContext::FieldContext(uno::Reference< text::XTextRange > xStart)
+ : m_bFieldCommandCompleted(false)
+ , m_xStartRange(std::move( xStart ))
+ , m_bFieldLocked( false )
+ , m_bCommandType(false)
+{
+ m_pProperties = new PropertyMap();
+}
+
+
+FieldContext::~FieldContext()
+{
+}
+
+void FieldContext::SetTextField(uno::Reference<text::XTextField> const& xTextField)
+{
+#ifndef NDEBUG
+ if (xTextField.is())
+ {
+ uno::Reference<lang::XServiceInfo> const xServiceInfo(xTextField, uno::UNO_QUERY);
+ assert(xServiceInfo.is());
+ // those must be set by SetFormField()
+ assert(!xServiceInfo->supportsService("com.sun.star.text.Fieldmark")
+ && !xServiceInfo->supportsService("com.sun.star.text.FormFieldmark"));
+ }
+#endif
+ m_xTextField = xTextField;
+}
+
+void FieldContext::CacheVariableValue(const uno::Any& rAny)
+{
+ rAny >>= m_sVariableValue;
+}
+
+void FieldContext::AppendCommand(std::u16string_view rPart)
+{
+ m_sCommand[m_bCommandType] += rPart;
+}
+
+::std::vector<OUString> FieldContext::GetCommandParts() const
+{
+ ::std::vector<OUString> aResult;
+ sal_Int32 nIndex = 0;
+ bool bInString = false;
+ OUString sPart;
+ while (nIndex != -1)
+ {
+ OUString sToken = GetCommand().getToken(0, ' ', nIndex);
+ bool bInStringNext = bInString;
+
+ if (sToken.isEmpty())
+ continue;
+
+ if (sToken[0] == '"')
+ {
+ bInStringNext = true;
+ sToken = sToken.copy(1);
+ }
+ if (sToken.endsWith("\""))
+ {
+ bInStringNext = false;
+ sToken = sToken.copy(0, sToken.getLength() - 1);
+ }
+
+ if (bInString)
+ {
+ sPart += " " + sToken;
+ if (!bInStringNext)
+ {
+ aResult.push_back(sPart);
+ }
+ }
+ else
+ {
+ if (bInStringNext)
+ {
+ sPart = sToken;
+ }
+ else
+ {
+ aResult.push_back(sToken);
+ }
+ }
+
+ bInString = bInStringNext;
+ }
+
+ return aResult;
+}
+
+/*-------------------------------------------------------------------------
+//collect the pieces of the command
+ -----------------------------------------------------------------------*/
+void DomainMapper_Impl::AppendFieldCommand(OUString const & rPartOfCommand)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("appendFieldCommand");
+ TagLogger::getInstance().chars(rPartOfCommand);
+ TagLogger::getInstance().endElement();
+#endif
+
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( pContext )
+ {
+ // Set command line type: normal or deleted
+ pContext->SetCommandType(m_bTextDeleted);
+ pContext->AppendCommand( rPartOfCommand );
+ }
+}
+
+
+typedef std::multimap < sal_Int32, OUString > TOCStyleMap;
+
+
+static ww::eField GetWW8FieldId(OUString const& rType)
+{
+ std::unordered_map<OUString, ww::eField> mapID
+ {
+ {"ADDRESSBLOCK", ww::eADDRESSBLOCK},
+ {"ADVANCE", ww::eADVANCE},
+ {"ASK", ww::eASK},
+ {"AUTONUM", ww::eAUTONUM},
+ {"AUTONUMLGL", ww::eAUTONUMLGL},
+ {"AUTONUMOUT", ww::eAUTONUMOUT},
+ {"AUTOTEXT", ww::eAUTOTEXT},
+ {"AUTOTEXTLIST", ww::eAUTOTEXTLIST},
+ {"AUTHOR", ww::eAUTHOR},
+ {"BARCODE", ww::eBARCODE},
+ {"BIDIOUTLINE", ww::eBIDIOUTLINE},
+ {"DATE", ww::eDATE},
+ {"COMMENTS", ww::eCOMMENTS},
+ {"COMPARE", ww::eCOMPARE},
+ {"CONTROL", ww::eCONTROL},
+ {"CREATEDATE", ww::eCREATEDATE},
+ {"DATABASE", ww::eDATABASE},
+ {"DDEAUTOREF", ww::eDDEAUTOREF},
+ {"DDEREF", ww::eDDEREF},
+ {"DOCPROPERTY", ww::eDOCPROPERTY},
+ {"DOCVARIABLE", ww::eDOCVARIABLE},
+ {"EDITTIME", ww::eEDITTIME},
+ {"EMBED", ww::eEMBED},
+ {"EQ", ww::eEQ},
+ {"FILLIN", ww::eFILLIN},
+ {"FILENAME", ww::eFILENAME},
+ {"FILESIZE", ww::eFILESIZE},
+ {"FOOTREF", ww::eFOOTREF},
+// {"FORMULA", ww::},
+ {"FORMCHECKBOX", ww::eFORMCHECKBOX},
+ {"FORMDROPDOWN", ww::eFORMDROPDOWN},
+ {"FORMTEXT", ww::eFORMTEXT},
+ {"GLOSSREF", ww::eGLOSSREF},
+ {"GOTOBUTTON", ww::eGOTOBUTTON},
+ {"GREETINGLINE", ww::eGREETINGLINE},
+ {"HTMLCONTROL", ww::eHTMLCONTROL},
+ {"HYPERLINK", ww::eHYPERLINK},
+ {"IF", ww::eIF},
+ {"INFO", ww::eINFO},
+ {"INCLUDEPICTURE", ww::eINCLUDEPICTURE},
+ {"INCLUDETEXT", ww::eINCLUDETEXT},
+ {"INCLUDETIFF", ww::eINCLUDETIFF},
+ {"KEYWORDS", ww::eKEYWORDS},
+ {"LASTSAVEDBY", ww::eLASTSAVEDBY},
+ {"LINK", ww::eLINK},
+ {"LISTNUM", ww::eLISTNUM},
+ {"MACRO", ww::eMACRO},
+ {"MACROBUTTON", ww::eMACROBUTTON},
+ {"MERGEDATA", ww::eMERGEDATA},
+ {"MERGEFIELD", ww::eMERGEFIELD},
+ {"MERGEINC", ww::eMERGEINC},
+ {"MERGEREC", ww::eMERGEREC},
+ {"MERGESEQ", ww::eMERGESEQ},
+ {"NEXT", ww::eNEXT},
+ {"NEXTIF", ww::eNEXTIF},
+ {"NOTEREF", ww::eNOTEREF},
+ {"PAGE", ww::ePAGE},
+ {"PAGEREF", ww::ePAGEREF},
+ {"PLUGIN", ww::ePLUGIN},
+ {"PRINT", ww::ePRINT},
+ {"PRINTDATE", ww::ePRINTDATE},
+ {"PRIVATE", ww::ePRIVATE},
+ {"QUOTE", ww::eQUOTE},
+ {"RD", ww::eRD},
+ {"REF", ww::eREF},
+ {"REVNUM", ww::eREVNUM},
+ {"SAVEDATE", ww::eSAVEDATE},
+ {"SECTION", ww::eSECTION},
+ {"SECTIONPAGES", ww::eSECTIONPAGES},
+ {"SEQ", ww::eSEQ},
+ {"SET", ww::eSET},
+ {"SKIPIF", ww::eSKIPIF},
+ {"STYLEREF", ww::eSTYLEREF},
+ {"SUBSCRIBER", ww::eSUBSCRIBER},
+ {"SUBJECT", ww::eSUBJECT},
+ {"SYMBOL", ww::eSYMBOL},
+ {"TA", ww::eTA},
+ {"TEMPLATE", ww::eTEMPLATE},
+ {"TIME", ww::eTIME},
+ {"TITLE", ww::eTITLE},
+ {"TOA", ww::eTOA},
+ {"USERINITIALS", ww::eUSERINITIALS},
+ {"USERADDRESS", ww::eUSERADDRESS},
+ {"USERNAME", ww::eUSERNAME},
+
+ {"TOC", ww::eTOC},
+ {"TC", ww::eTC},
+ {"NUMCHARS", ww::eNUMCHARS},
+ {"NUMWORDS", ww::eNUMWORDS},
+ {"NUMPAGES", ww::eNUMPAGES},
+ {"INDEX", ww::eINDEX},
+ {"XE", ww::eXE},
+ {"BIBLIOGRAPHY", ww::eBIBLIOGRAPHY},
+ {"CITATION", ww::eCITATION},
+ };
+ auto const it = mapID.find(rType);
+ return (it == mapID.end()) ? ww::eNONE : it->second;
+}
+
+static const FieldConversionMap_t & lcl_GetFieldConversion()
+{
+ static const FieldConversionMap_t aFieldConversionMap
+ {
+// {"ADDRESSBLOCK", {"", FIELD_ADDRESSBLOCK }},
+// {"ADVANCE", {"", FIELD_ADVANCE }},
+ {"ASK", {"SetExpression", FIELD_ASK }},
+ {"AUTONUM", {"SetExpression", FIELD_AUTONUM }},
+ {"AUTONUMLGL", {"SetExpression", FIELD_AUTONUMLGL }},
+ {"AUTONUMOUT", {"SetExpression", FIELD_AUTONUMOUT }},
+ {"AUTHOR", {"DocInfo.CreateAuthor", FIELD_AUTHOR }},
+ {"DATE", {"DateTime", FIELD_DATE }},
+ {"COMMENTS", {"DocInfo.Description", FIELD_COMMENTS }},
+ {"CREATEDATE", {"DocInfo.CreateDateTime", FIELD_CREATEDATE }},
+ {"DOCPROPERTY", {"", FIELD_DOCPROPERTY }},
+ {"DOCVARIABLE", {"User", FIELD_DOCVARIABLE }},
+ {"EDITTIME", {"DocInfo.EditTime", FIELD_EDITTIME }},
+ {"EQ", {"", FIELD_EQ }},
+ {"FILLIN", {"Input", FIELD_FILLIN }},
+ {"FILENAME", {"FileName", FIELD_FILENAME }},
+// {"FILESIZE", {"", FIELD_FILESIZE }},
+ {"FORMULA", {"TableFormula", FIELD_FORMULA }},
+ {"FORMCHECKBOX", {"", FIELD_FORMCHECKBOX }},
+ {"FORMDROPDOWN", {"DropDown", FIELD_FORMDROPDOWN }},
+ {"FORMTEXT", {"Input", FIELD_FORMTEXT }},
+ {"GOTOBUTTON", {"", FIELD_GOTOBUTTON }},
+ {"HYPERLINK", {"", FIELD_HYPERLINK }},
+ {"IF", {"ConditionalText", FIELD_IF }},
+// {"INFO", {"", FIELD_INFO }},
+ {"INCLUDEPICTURE", {"", FIELD_INCLUDEPICTURE}},
+ {"KEYWORDS", {"DocInfo.KeyWords", FIELD_KEYWORDS }},
+ {"LASTSAVEDBY", {"DocInfo.ChangeAuthor", FIELD_LASTSAVEDBY }},
+ {"MACROBUTTON", {"Macro", FIELD_MACROBUTTON }},
+ {"MERGEFIELD", {"Database", FIELD_MERGEFIELD }},
+ {"MERGEREC", {"DatabaseNumberOfSet", FIELD_MERGEREC }},
+// {"MERGESEQ", {"", FIELD_MERGESEQ }},
+ {"NEXT", {"DatabaseNextSet", FIELD_NEXT }},
+ {"NEXTIF", {"DatabaseNextSet", FIELD_NEXTIF }},
+ {"PAGE", {"PageNumber", FIELD_PAGE }},
+ {"PAGEREF", {"GetReference", FIELD_PAGEREF }},
+ {"PRINTDATE", {"DocInfo.PrintDateTime", FIELD_PRINTDATE }},
+ {"REF", {"GetReference", FIELD_REF }},
+ {"REVNUM", {"DocInfo.Revision", FIELD_REVNUM }},
+ {"SAVEDATE", {"DocInfo.ChangeDateTime", FIELD_SAVEDATE }},
+// {"SECTION", {"", FIELD_SECTION }},
+// {"SECTIONPAGES", {"", FIELD_SECTIONPAGES }},
+ {"SEQ", {"SetExpression", FIELD_SEQ }},
+ {"SET", {"SetExpression", FIELD_SET }},
+// {"SKIPIF", {"", FIELD_SKIPIF }},
+ {"STYLEREF", {"GetReference", FIELD_STYLEREF }},
+ {"SUBJECT", {"DocInfo.Subject", FIELD_SUBJECT }},
+ {"SYMBOL", {"", FIELD_SYMBOL }},
+ {"TEMPLATE", {"TemplateName", FIELD_TEMPLATE }},
+ {"TIME", {"DateTime", FIELD_TIME }},
+ {"TITLE", {"DocInfo.Title", FIELD_TITLE }},
+ {"USERINITIALS", {"Author", FIELD_USERINITIALS }},
+// {"USERADDRESS", {"", FIELD_USERADDRESS }},
+ {"USERNAME", {"Author", FIELD_USERNAME }},
+
+
+ {"TOC", {"com.sun.star.text.ContentIndex", FIELD_TOC }},
+ {"TC", {"com.sun.star.text.ContentIndexMark", FIELD_TC }},
+ {"NUMCHARS", {"CharacterCount", FIELD_NUMCHARS }},
+ {"NUMWORDS", {"WordCount", FIELD_NUMWORDS }},
+ {"NUMPAGES", {"PageCount", FIELD_NUMPAGES }},
+ {"INDEX", {"com.sun.star.text.DocumentIndex", FIELD_INDEX }},
+ {"XE", {"com.sun.star.text.DocumentIndexMark", FIELD_XE }},
+ {"BIBLIOGRAPHY",{"com.sun.star.text.Bibliography", FIELD_BIBLIOGRAPHY }},
+ {"CITATION", {"com.sun.star.text.TextField.Bibliography",FIELD_CITATION }},
+ };
+
+ return aFieldConversionMap;
+}
+
+static const FieldConversionMap_t & lcl_GetEnhancedFieldConversion()
+{
+ static const FieldConversionMap_t aEnhancedFieldConversionMap =
+ {
+ {"FORMCHECKBOX", {"FormFieldmark", FIELD_FORMCHECKBOX}},
+ {"FORMDROPDOWN", {"FormFieldmark", FIELD_FORMDROPDOWN}},
+ {"FORMTEXT", {"Fieldmark", FIELD_FORMTEXT}},
+ };
+
+ return aEnhancedFieldConversionMap;
+}
+
+void DomainMapper_Impl::handleFieldSet
+ (const FieldContextPtr& pContext,
+ uno::Reference< uno::XInterface > const & xFieldInterface,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ OUString sVariable, sHint;
+
+ sVariable = lcl_ExtractVariableAndHint(pContext->GetCommand(), sHint);
+
+ // remove surrounding "" if exists
+ if(sHint.getLength() >= 2)
+ {
+ std::u16string_view sTmp = o3tl::trim(sHint);
+ if (o3tl::starts_with(sTmp, u"\"") && o3tl::ends_with(sTmp, u"\""))
+ {
+ sHint = sTmp.substr(1, sTmp.size() - 2);
+ }
+ }
+
+ // determine field master name
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster
+ ("com.sun.star.text.FieldMaster.SetExpression", sVariable);
+
+ // a set field is a string
+ xMaster->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField
+ ( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+
+ uno::Any aAnyHint(sHint);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_HINT), aAnyHint);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), aAnyHint);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+
+ // Mimic MS Word behavior (hide the SET)
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::Any(false));
+}
+
+void DomainMapper_Impl::handleFieldAsk
+ (const FieldContextPtr& pContext,
+ uno::Reference< uno::XInterface > & xFieldInterface,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ //doesn the command contain a variable name?
+ OUString sVariable, sHint;
+
+ sVariable = lcl_ExtractVariableAndHint( pContext->GetCommand(),
+ sHint );
+ if(!sVariable.isEmpty())
+ {
+ // determine field master name
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster
+ ("com.sun.star.text.FieldMaster.SetExpression", sVariable );
+ // An ASK field is always a string of characters
+ xMaster->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField
+ ( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+
+ // set input flag at the field
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_INPUT), uno::Any( true ));
+ // set the prompt
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_HINT),
+ uno::Any( sHint ));
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+ // The ASK has no field value to display
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_IS_VISIBLE), uno::Any(false));
+ }
+ else
+ {
+ //don't insert the field
+ //todo: maybe import a 'normal' input field here?
+ xFieldInterface = nullptr;
+ }
+}
+
+/**
+ * Converts a Microsoft Word field formula into LibreOffice syntax
+ * @param input The Microsoft Word field formula, with no leading '=' sign
+ * @return An equivalent LibreOffice field formula
+ */
+OUString DomainMapper_Impl::convertFieldFormula(const OUString& input) {
+
+ if (!m_pSettingsTable)
+ {
+ return input;
+ }
+
+ OUString listSeparator = m_pSettingsTable->GetListSeparator();
+
+ /* Replace logical condition functions with LO equivalent operators */
+ OUString changed = input.replaceAll(" <> ", " NEQ ");
+ changed = changed.replaceAll(" <= ", " LEQ ");
+ changed = changed.replaceAll(" >= ", " GEQ ");
+ changed = changed.replaceAll(" = " , " EQ ");
+ changed = changed.replaceAll(" < " , " L ");
+ changed = changed.replaceAll(" > " , " G ");
+
+ changed = changed.replaceAll("<>", " NEQ ");
+ changed = changed.replaceAll("<=", " LEQ ");
+ changed = changed.replaceAll(">=", " GEQ ");
+ changed = changed.replaceAll("=" , " EQ ");
+ changed = changed.replaceAll("<" , " L ");
+ changed = changed.replaceAll(">" , " G ");
+
+ /* Replace function calls with infix keywords for AND(), OR(), and ROUND(). Nothing needs to be
+ * done for NOT(). This simple regex will work properly with most common cases. However, it may
+ * not work correctly when the arguments are nested subcalls to other functions, like
+ * ROUND(MIN(1,2),MAX(3,4)). See TDF#134765. */
+ icu::ErrorCode status;
+ icu::UnicodeString usInput(changed.getStr());
+ const uint32_t rMatcherFlags = UREGEX_CASE_INSENSITIVE;
+ OUString regex = "\\b(AND|OR|ROUND)\\s*\\(\\s*([^" + listSeparator + "]+)\\s*" + listSeparator + "\\s*([^)]+)\\s*\\)";
+ icu::UnicodeString usRegex(regex.getStr());
+ icu::RegexMatcher rmatch1(usRegex, usInput, rMatcherFlags, status);
+ usInput = rmatch1.replaceAll(icu::UnicodeString("(($2) $1 ($3))"), status);
+
+ /* Assumes any remaining list separators separate arguments to functions that accept lists
+ * (SUM, MIN, MAX, MEAN, etc.) */
+ usInput.findAndReplace(icu::UnicodeString(listSeparator.getStr()), "|");
+
+ /* Surround single cell references with angle brackets.
+ * If there is ever added a function name that ends with a digit, this regex will need to be revisited. */
+ icu::RegexMatcher rmatch2("\\b([A-Z]{1,3}[0-9]+)\\b(?![(])", usInput, rMatcherFlags, status);
+ usInput = rmatch2.replaceAll(icu::UnicodeString("<$1>"), status);
+
+ /* Cell references must be upper case
+ * TODO: convert reference to other tables, e.g. SUM(Table1 A1:B2), where "Table1" is a bookmark of the table,
+ * TODO: also column range A:A */
+ icu::RegexMatcher rmatch3("(<[a-z]{1,3}[0-9]+>|\\b(above|below|left|right)\\b)", usInput, rMatcherFlags, status);
+ icu::UnicodeString replacedCellRefs;
+ while (rmatch3.find(status) && status.isSuccess()) {
+ rmatch3.appendReplacement(replacedCellRefs, rmatch3.group(status).toUpper(), status);
+ }
+ rmatch3.appendTail(replacedCellRefs);
+
+ /* Fix up cell ranges */
+ icu::RegexMatcher rmatch4("<([A-Z]{1,3}[0-9]+)>:<([A-Z]{1,3}[0-9]+)>", replacedCellRefs, rMatcherFlags, status);
+ usInput = rmatch4.replaceAll(icu::UnicodeString("<$1:$2>"), status);
+
+ /* Fix up user defined names */
+ icu::RegexMatcher rmatch5("\\bDEFINED\\s*\\(<([A-Z]+[0-9]+)>\\)", usInput, rMatcherFlags, status);
+ usInput = rmatch5.replaceAll(icu::UnicodeString("DEFINED($1)"), status);
+
+ /* Prepare replace of ABOVE/BELOW/LEFT/RIGHT by adding spaces around them */
+ icu::RegexMatcher rmatch6("\\b(ABOVE|BELOW|LEFT|RIGHT)\\b", usInput, rMatcherFlags, status);
+ usInput = rmatch6.replaceAll(icu::UnicodeString(" $1 "), status);
+
+ /* DOCX allows to set decimal symbol independently from the locale of the document, so if
+ * needed, convert decimal comma to get working formula in a document language (locale),
+ * which doesn't use decimal comma */
+ if ( m_pSettingsTable->GetDecimalSymbol() == "," && !m_bIsDecimalComma )
+ {
+ icu::RegexMatcher rmatch7("\\b([0-9]+),([0-9]+([eE][-]?[0-9]+)?)\\b", usInput, rMatcherFlags, status);
+ usInput = rmatch7.replaceAll(icu::UnicodeString("$1.$2"), status);
+ }
+
+ return OUString(usInput.getTerminatedBuffer());
+}
+
+void DomainMapper_Impl::handleFieldFormula
+ (const FieldContextPtr& pContext,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ OUString command = pContext->GetCommand().trim();
+
+ // Remove number formatting from \# to end of command
+ // TODO: handle custom number formatting
+ sal_Int32 delimPos = command.indexOf("\\#");
+ if (delimPos != -1)
+ {
+ command = command.replaceAt(delimPos, command.getLength() - delimPos, u"").trim();
+ }
+
+ // command must contains = and at least another char
+ if (command.getLength() < 2)
+ return;
+
+ // we don't copy the = symbol from the command
+ OUString formula = convertFieldFormula(command.copy(1));
+
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::Any(formula));
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_NUMBER_FORMAT), uno::Any(sal_Int32(0)));
+ xFieldProperties->setPropertyValue("IsShowFormula", uno::Any(false));
+
+ // grab-bag the original and converted formula
+ if (hasTableManager())
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_CELL_FORMULA, uno::Any(command.copy(1)), true, CELL_GRAB_BAG);
+ pPropMap->Insert(PROP_CELL_FORMULA_CONVERTED, uno::Any(formula), true, CELL_GRAB_BAG);
+ getTableManager().cellProps(pPropMap);
+ }
+}
+
+void DomainMapper_Impl::handleRubyEQField( const FieldContextPtr& pContext)
+{
+ const OUString & rCommand(pContext->GetCommand());
+ sal_Int32 nIndex = 0, nEnd = 0;
+ RubyInfo aInfo ;
+ nIndex = rCommand.indexOf("\\* jc" );
+ if (nIndex != -1)
+ {
+ nIndex += 5;
+ sal_uInt32 nJc = o3tl::toInt32(o3tl::getToken(rCommand, 0, ' ',nIndex));
+ const sal_Int32 aRubyAlignValues[] =
+ {
+ NS_ooxml::LN_Value_ST_RubyAlign_center,
+ NS_ooxml::LN_Value_ST_RubyAlign_distributeLetter,
+ NS_ooxml::LN_Value_ST_RubyAlign_distributeSpace,
+ NS_ooxml::LN_Value_ST_RubyAlign_left,
+ NS_ooxml::LN_Value_ST_RubyAlign_right,
+ NS_ooxml::LN_Value_ST_RubyAlign_rightVertical,
+ };
+ aInfo.nRubyAlign = aRubyAlignValues[(nJc<SAL_N_ELEMENTS(aRubyAlignValues))?nJc:0];
+ }
+
+ // we don't parse or use the font field in rCommand
+
+ nIndex = rCommand.indexOf("\\* hps" );
+ if (nIndex != -1)
+ {
+ nIndex += 6;
+ aInfo.nHps = o3tl::toInt32(o3tl::getToken(rCommand, 0, ' ',nIndex));
+ }
+
+ nIndex = rCommand.indexOf("\\o");
+ if (nIndex == -1)
+ return;
+ nIndex = rCommand.indexOf('(', nIndex);
+ if (nIndex == -1)
+ return;
+ nEnd = rCommand.lastIndexOf(')');
+ if (nEnd == -1)
+ return;
+ if (nEnd <= nIndex)
+ return;
+
+ std::u16string_view sRubyParts = rCommand.subView(nIndex+1,nEnd-nIndex-1);
+ nIndex = 0;
+ std::u16string_view sPart1 = o3tl::getToken(sRubyParts, 0, ',', nIndex);
+ std::u16string_view sPart2 = o3tl::getToken(sRubyParts, 0, ',', nIndex);
+ size_t nIndex2 = 0;
+ size_t nEnd2 = 0;
+ if ((nIndex2 = sPart1.find('(')) != std::u16string_view::npos && (nEnd2 = sPart1.rfind(')')) != std::u16string_view::npos && nEnd2 > nIndex2)
+ {
+ aInfo.sRubyText = sPart1.substr(nIndex2+1,nEnd2-nIndex2-1);
+ }
+
+ PropertyMapPtr pRubyContext(new PropertyMap());
+ pRubyContext->InsertProps(GetTopContext());
+ if (aInfo.nHps > 0)
+ {
+ double fVal = double(aInfo.nHps) / 2.;
+ uno::Any aVal( fVal );
+
+ pRubyContext->Insert(PROP_CHAR_HEIGHT, aVal);
+ pRubyContext->Insert(PROP_CHAR_HEIGHT_ASIAN, aVal);
+ }
+ PropertyValueVector_t aProps = comphelper::sequenceToContainer< PropertyValueVector_t >(pRubyContext->GetPropertyValues());
+ aInfo.sRubyStyle = m_rDMapper.getOrCreateCharStyle(aProps, /*bAlwaysCreate=*/false);
+ PropertyMapPtr pCharContext(new PropertyMap());
+ if (m_pLastCharacterContext)
+ pCharContext->InsertProps(m_pLastCharacterContext);
+ pCharContext->InsertProps(pContext->getProperties());
+ pCharContext->Insert(PROP_RUBY_TEXT, uno::Any( aInfo.sRubyText ) );
+ pCharContext->Insert(PROP_RUBY_ADJUST, uno::Any(static_cast<sal_Int16>(ConversionHelper::convertRubyAlign(aInfo.nRubyAlign))));
+ if ( aInfo.nRubyAlign == NS_ooxml::LN_Value_ST_RubyAlign_rightVertical )
+ pCharContext->Insert(PROP_RUBY_POSITION, uno::Any(css::text::RubyPosition::INTER_CHARACTER));
+ pCharContext->Insert(PROP_RUBY_STYLE, uno::Any(aInfo.sRubyStyle));
+ appendTextPortion(OUString(sPart2), pCharContext);
+
+}
+
+void DomainMapper_Impl::handleAutoNum
+ (const FieldContextPtr& pContext,
+ uno::Reference< uno::XInterface > const & xFieldInterface,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties)
+{
+ //create a sequence field master "AutoNr"
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster
+ ("com.sun.star.text.FieldMaster.SetExpression",
+ "AutoNr");
+
+ xMaster->setPropertyValue( getPropertyName(PROP_SUB_TYPE),
+ uno::Any(text::SetVariableType::SEQUENCE));
+
+ //apply the numbering type
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField
+ ( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+}
+
+void DomainMapper_Impl::handleAuthor
+ (std::u16string_view,
+ uno::Reference< beans::XPropertySet > const& xFieldProperties,
+ FieldId eFieldId )
+{
+ if (eFieldId == FIELD_USERNAME)
+ xFieldProperties->setPropertyValue
+ ( getPropertyName(PROP_FULL_NAME), uno::Any( true ));
+
+ // Always set as FIXED b/c MS Word only updates these fields via user intervention (F9)
+ // AUTHOR of course never changes and USERNAME is easily mis-used as an original author field.
+ // Additionally, this was forced as fixed if any special case-formatting was provided.
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ),
+ uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+}
+
+ void DomainMapper_Impl::handleDocProperty
+ (const FieldContextPtr& pContext,
+ OUString const& rFirstParam,
+ uno::Reference< uno::XInterface > & xFieldInterface)
+{
+ //some docproperties should be imported as document statistic fields, some as DocInfo fields
+ //others should be user fields
+ if (rFirstParam.isEmpty())
+ return;
+
+ constexpr sal_uInt8 SET_ARABIC = 0x01;
+ constexpr sal_uInt8 SET_DATE = 0x04;
+ struct DocPropertyMap
+ {
+ const char* pDocPropertyName;
+ const char* pServiceName;
+ sal_uInt8 nFlags;
+ };
+ static const DocPropertyMap aDocProperties[] =
+ {
+ {"CreateTime", "DocInfo.CreateDateTime", SET_DATE},
+ {"Characters", "CharacterCount", SET_ARABIC},
+ {"Comments", "DocInfo.Description", 0},
+ {"Keywords", "DocInfo.KeyWords", 0},
+ {"LastPrinted", "DocInfo.PrintDateTime", 0},
+ {"LastSavedBy", "DocInfo.ChangeAuthor", 0},
+ {"LastSavedTime", "DocInfo.ChangeDateTime", SET_DATE},
+ {"Paragraphs", "ParagraphCount", SET_ARABIC},
+ {"RevisionNumber", "DocInfo.Revision", 0},
+ {"Subject", "DocInfo.Subject", 0},
+ {"Template", "TemplateName", 0},
+ {"Title", "DocInfo.Title", 0},
+ {"TotalEditingTime", "DocInfo.EditTime", 0},
+ {"Words", "WordCount", SET_ARABIC}
+
+ //other available DocProperties:
+ //Bytes, Category, CharactersWithSpaces, Company
+ //HyperlinkBase,
+ //Lines, Manager, NameofApplication, ODMADocId, Pages,
+ //Security,
+ };
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(m_xTextDocument, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+ uno::Reference<beans::XPropertySet> xUserDefinedProps(xDocumentProperties->getUserDefinedProperties(), uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xUserDefinedProps->getPropertySetInfo();
+ //search for a field mapping
+ OUString sFieldServiceName;
+ size_t nMap = 0;
+ if (!xPropertySetInfo->hasPropertyByName(rFirstParam))
+ {
+ for( ; nMap < SAL_N_ELEMENTS(aDocProperties); ++nMap )
+ {
+ if (rFirstParam.equalsAscii(aDocProperties[nMap].pDocPropertyName))
+ {
+ sFieldServiceName = OUString::createFromAscii(aDocProperties[nMap].pServiceName);
+ break;
+ }
+ }
+ }
+ else
+ pContext->CacheVariableValue(xUserDefinedProps->getPropertyValue(rFirstParam));
+
+ OUString sServiceName("com.sun.star.text.TextField.");
+ bool bIsCustomField = false;
+ if(sFieldServiceName.isEmpty())
+ {
+ //create a custom property field
+ sServiceName += "DocInfo.Custom";
+ bIsCustomField = true;
+ }
+ else
+ {
+ sServiceName += sFieldServiceName;
+ }
+ if (m_xTextFactory.is())
+ xFieldInterface = m_xTextFactory->createInstance(sServiceName);
+ uno::Reference<beans::XPropertySet> xFieldProperties( xFieldInterface, uno::UNO_QUERY_THROW);
+ if( bIsCustomField )
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NAME), uno::Any(rFirstParam));
+ pContext->SetCustomField( xFieldProperties );
+ }
+ else
+ {
+ if(0 != (aDocProperties[nMap].nFlags & SET_ARABIC))
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( style::NumberingType::ARABIC ));
+ else if(0 != (aDocProperties[nMap].nFlags & SET_DATE))
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_DATE),
+ uno::Any( true ));
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ }
+}
+
+static uno::Sequence< beans::PropertyValues > lcl_createTOXLevelHyperlinks( bool bHyperlinks, const OUString& sChapterNoSeparator,
+ const uno::Sequence< beans::PropertyValues >& aLevel, const std::optional<style::TabStop> numtab)
+{
+ //create a copy of the level and add new entries
+
+ std::vector<css::beans::PropertyValues> aNewLevel;
+ aNewLevel.reserve(aLevel.getLength() + 5); // at most 5 added items
+
+ static constexpr OUString tokType(u"TokenType"_ustr);
+ static constexpr OUString tokHStart(u"TokenHyperlinkStart"_ustr);
+ static constexpr OUString tokHEnd(u"TokenHyperlinkEnd"_ustr);
+ static constexpr OUStringLiteral tokPNum(u"TokenPageNumber");
+ static constexpr OUStringLiteral tokENum(u"TokenEntryNumber");
+
+ if (bHyperlinks)
+ aNewLevel.push_back({ comphelper::makePropertyValue(tokType, tokHStart) });
+
+ for (const auto& item : aLevel)
+ {
+ OUString tokenType;
+ if (auto it = std::find_if(item.begin(), item.end(),
+ [](const auto& p) { return p.Name == tokType; });
+ it != item.end())
+ it->Value >>= tokenType;
+
+ if (bHyperlinks && (tokenType == tokHStart || tokenType == tokHEnd))
+ continue; // We add hyperlink ourselves, so just skip existing hyperlink start / end
+
+ if (!sChapterNoSeparator.isEmpty() && tokenType == tokPNum)
+ {
+ // This is an existing page number token; insert the chapter and separator before it
+ aNewLevel.push_back(
+ { comphelper::makePropertyValue(tokType, OUString("TokenChapterInfo")),
+ comphelper::makePropertyValue("ChapterFormat", text::ChapterFormat::NUMBER) });
+ aNewLevel.push_back({ comphelper::makePropertyValue(tokType, OUString("TokenText")),
+ comphelper::makePropertyValue("Text", sChapterNoSeparator) });
+ }
+
+ aNewLevel.push_back(item);
+
+ if (numtab && tokenType == tokENum)
+ {
+ // There is a fixed tab stop position needed in the level after the numbering
+ aNewLevel.push_back(
+ { comphelper::makePropertyValue(tokType, OUString("TokenTabStop")),
+ comphelper::makePropertyValue("TabStopPosition", numtab->Position) });
+ }
+ }
+
+ if (bHyperlinks)
+ aNewLevel.push_back({ comphelper::makePropertyValue(tokType, tokHEnd) });
+
+ return comphelper::containerToSequence(aNewLevel);
+}
+
+/// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
+OUString DomainMapper_Impl::extractTocTitle()
+{
+ if (!m_StreamStateStack.top().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> const xCursor(
+ xTextAppend->createTextCursorByRange(m_StreamStateStack.top().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_StreamStateStack.top().bParaChanged)
+ {
+ finishParagraph(GetTopContextOfType(CONTEXT_PARAGRAPH), false); // resets 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 bParaChanged)
+ m_StreamStateStack.top().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;
+}
+
+/**
+ This is a heuristic to find Word's w:styleId value from localised style name.
+ It's not clear how exactly it works, but apparently Word stores into
+ w:styleId some filtered representation of the localised style name.
+ Tragically there are references to the localised style name itself in TOC
+ fields.
+ Hopefully this works and a complete map of >100 built-in style names
+ localised to all languages isn't needed.
+*/
+static auto FilterChars(std::u16string_view const& rStyleName) -> OUString
+{
+ return msfilter::util::CreateDOCXStyleId(rStyleName);
+}
+
+static OUString UnquoteFieldText(std::u16string_view s)
+{
+ OUStringBuffer result(s.size());
+ for (size_t i = 0; i < s.size(); ++i)
+ {
+ switch (s[i])
+ {
+ case '"':
+ continue;
+ case '\\':
+ if (i < s.size() - 1)
+ ++i;
+ [[fallthrough]];
+ default:
+ result.append(s[i]);
+ }
+ }
+ return result.makeStringAndClear();
+}
+
+OUString DomainMapper_Impl::ConvertTOCStyleName(OUString const& rTOCStyleName)
+{
+ assert(!rTOCStyleName.isEmpty());
+ if (auto const pStyle = GetStyleSheetTable()->FindStyleSheetByISTD(rTOCStyleName))
+ { // theoretical case: what OOXML says
+ return pStyle->m_sStyleName;
+ }
+ auto const pStyle = GetStyleSheetTable()->FindStyleSheetByISTD(FilterChars(rTOCStyleName));
+ if (pStyle && m_bIsNewDoc)
+ { // practical case: Word wrote i18n name to TOC field, but it doesn't
+ // exist in styles.xml; tdf#153083 clone it for best roundtrip
+ SAL_INFO("writerfilter.dmapper", "cloning TOC paragraph style (presumed built-in) " << rTOCStyleName << " from " << pStyle->m_sStyleName);
+ return GetStyleSheetTable()->CloneTOCStyle(GetFontTable(), pStyle, rTOCStyleName);
+ }
+ else
+ {
+ return GetStyleSheetTable()->ConvertStyleName(rTOCStyleName);
+ }
+}
+
+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;
+ 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 = UnquoteFieldText(sValue);
+ }
+// \f Builds a table of contents using TC entries instead of outline levels
+ if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
+ {
+ //todo: sValue can contain a TOC entry identifier - use unclear
+ bFromEntries = true;
+ }
+// \h Hyperlinks the entries and page numbers within the table of contents
+ if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue ))
+ {
+ //todo: make all entries to hyperlinks
+ bHyperlinks = true;
+ }
+// \l Defines the TC entries field level used to build a table of contents
+// if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
+// {
+ //todo: entries can only be included completely
+// }
+// \n Builds a table of contents or a range of entries, such as 1-9 in a table of contents without page numbers
+// if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
+// {
+ //todo: what does the description mean?
+// }
+// \o Builds a table of contents by using outline levels instead of TC entries
+ if( lcl_FindInCommand( pContext->GetCommand(), 'o', sValue ))
+ {
+ bFromOutline = true;
+ if (sValue.isEmpty())
+ nMaxLevel = WW_OUTLINE_MAX;
+ else
+ {
+ sal_Int32 nIndex = 0;
+ o3tl::getToken(sValue, 0, '-', nIndex );
+ nMaxLevel = static_cast<sal_Int16>(nIndex != -1 ? o3tl::toInt32(sValue.subView(nIndex)) : 0);
+ }
+ }
+// \p Defines the separator between the table entry and its page number
+// \s Builds a table of contents by using a sequence type
+// \t Builds a table of contents by using style names other than the standard outline styles
+ if( lcl_FindInCommand( pContext->GetCommand(), 't', sValue ))
+ {
+ OUString sToken = sValue.getToken(1, '"');
+ sTemplate = sToken.isEmpty() ? sValue : sToken;
+ }
+// \u Builds a table of contents by using the applied paragraph outline level
+ if( lcl_FindInCommand( pContext->GetCommand(), 'u', sValue ))
+ {
+ bFromOutline = true;
+ bParagraphOutlineLevel = true;
+ //todo: what doesn 'the applied paragraph outline level' refer to?
+ }
+// \w Preserve tab characters within table entries
+ if( lcl_FindInCommand( pContext->GetCommand(), 'w', sValue ))
+ {
+ bIsTabEntry = true ;
+ }
+// \x Preserve newline characters within table entries
+ if( lcl_FindInCommand( pContext->GetCommand(), 'x', sValue ))
+ {
+ bNewLine = true ;
+ }
+// \z Hides page numbers within the table of contents when shown in Web Layout View
+ if( lcl_FindInCommand( pContext->GetCommand(), 'z', sValue ))
+ {
+ bHideTabLeaderPageNumbers = true ;
+ }
+
+ //if there's no option then it should be created from outline
+ if( !bFromOutline && !bFromEntries && sTemplate.isEmpty() )
+ bFromOutline = true;
+
+ const OUString aTocTitle = extractTocTitle();
+
+ uno::Reference<beans::XPropertySet> xTOC;
+
+ if (m_xTextFactory.is() && ! m_aTextAppendStack.empty())
+ {
+ const auto& xTextAppend = GetTopTextAppend();
+ if (aTocTitle.isEmpty() || bTableOfFigures)
+ {
+ // reset marker of the TOC title
+ m_StreamStateStack.top().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);
+ m_xTOCMarkerCursor = xTextCursor;
+ }
+ else
+ {
+ // create TOC section
+ css::uno::Reference<css::text::XTextRange> xTextRangeEndOfTocHeader = GetTopTextAppend()->getEnd();
+ xTOC = createSectionForRange(m_StreamStateStack.top().xSdtEntryStart, xTextRangeEndOfTocHeader, sTOCServiceName, false);
+
+ // init [xTOCMarkerCursor]
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ m_xTOCMarkerCursor = xText->createTextCursor();
+
+ // create header of the TOC with the TOC title inside
+ createSectionForRange(m_StreamStateStack.top().xSdtEntryStart, xTextRangeEndOfTocHeader, "com.sun.star.text.IndexHeaderSection", true);
+ }
+ }
+
+ m_bStartTOC = true;
+ pContext->SetTOC(xTOC);
+ m_StreamStateStack.top().bParaHadField = false;
+
+ if (!xTOC)
+ return;
+
+ xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::Any(aTocTitle));
+
+ if (!aBookmarkName.isEmpty())
+ xTOC->setPropertyValue(getPropertyName(PROP_TOC_BOOKMARK), uno::Any(aBookmarkName));
+ if (!bTableOfFigures)
+ {
+ xTOC->setPropertyValue( getPropertyName( PROP_LEVEL ), uno::Any( nMaxLevel ) );
+ xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_OUTLINE ), uno::Any( bFromOutline ));
+ xTOC->setPropertyValue( getPropertyName( PROP_CREATE_FROM_MARKS ), uno::Any( bFromEntries ));
+ xTOC->setPropertyValue( getPropertyName( PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS ), uno::Any( bHideTabLeaderPageNumbers ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TAB_IN_TOC ), uno::Any( bIsTabEntry ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TOC_NEW_LINE ), uno::Any( bNewLine ));
+ xTOC->setPropertyValue( getPropertyName( PROP_TOC_PARAGRAPH_OUTLINE_LEVEL ), uno::Any( bParagraphOutlineLevel ));
+ if( !sTemplate.isEmpty() )
+ {
+ //the string contains comma separated the names and related levels
+ //like: "Heading 1,1,Heading 2,2"
+ TOCStyleMap aMap;
+ sal_Int32 nLevel;
+ sal_Int32 nPosition = 0;
+ auto const tsep(sTemplate.indexOf(',') != -1 ? ',' : ';');
+ while( nPosition >= 0)
+ {
+ OUString sStyleName = sTemplate.getToken(0, tsep, nPosition);
+ //empty tokens should be skipped
+ while( sStyleName.isEmpty() && nPosition > 0 )
+ sStyleName = sTemplate.getToken(0, tsep, nPosition);
+ nLevel = o3tl::toInt32(o3tl::getToken(sTemplate, 0, tsep, nPosition ));
+ if( !nLevel )
+ nLevel = 1;
+ if( !sStyleName.isEmpty() )
+ aMap.emplace(nLevel, sStyleName);
+ }
+ uno::Reference< container::XIndexReplace> xParaStyles;
+ xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_PARAGRAPH_STYLES)) >>= xParaStyles;
+ for( nLevel = 1; nLevel < 10; ++nLevel)
+ {
+ sal_Int32 nLevelCount = aMap.count( nLevel );
+ if( nLevelCount )
+ {
+ TOCStyleMap::iterator aTOCStyleIter = aMap.find( nLevel );
+
+ uno::Sequence< OUString> aStyles( nLevelCount );
+ for ( auto& rStyle : asNonConstRange(aStyles) )
+ {
+ // tdf#153083 must map w:styleId to w:name
+ rStyle = ConvertTOCStyleName(aTOCStyleIter->second);
+ ++aTOCStyleIter;
+ }
+ xParaStyles->replaceByIndex(nLevel - 1, uno::Any(aStyles));
+ }
+ }
+ xTOC->setPropertyValue(getPropertyName(PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES), uno::Any( true ));
+
+ }
+
+ uno::Reference<container::XIndexAccess> xChapterNumberingRules;
+ if (auto xSupplier = GetTextDocument().query<text::XChapterNumberingSupplier>())
+ xChapterNumberingRules = xSupplier->getChapterNumberingRules();
+ uno::Reference<container::XNameContainer> xStyles;
+ if (auto xStylesSupplier = GetTextDocument().query<style::XStyleFamiliesSupplier>())
+ {
+ auto xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES)) >>= xStyles;
+ }
+
+ 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;
+
+ // Get the tab stops coming from the styles; store to the level definitions
+ std::optional<style::TabStop> numTab;
+ if (xChapterNumberingRules && xStyles)
+ {
+ // This relies on the chapter numbering rules already defined
+ // (see ListDef::CreateNumberingRules)
+ uno::Sequence<beans::PropertyValue> props;
+ xChapterNumberingRules->getByIndex(nLevel - 1) >>= props;
+ bool bHasNumbering = false;
+ bool bUseTabStop = false;
+ for (const auto& propval : props)
+ {
+ // We rely on PositionAndSpaceMode being always equal to LABEL_ALIGNMENT,
+ // because ListDef::CreateNumberingRules doesn't create legacy lists
+ if (propval.Name == "NumberingType")
+ bHasNumbering = propval.Value != style::NumberingType::NUMBER_NONE;
+ else if (propval.Name == "LabelFollowedBy")
+ bUseTabStop = propval.Value == text::LabelFollow::LISTTAB;
+ // Do not use FirstLineIndent property from the rules, because it is unreliable
+ }
+ if (bHasNumbering && bUseTabStop)
+ {
+ OUString style;
+ xTOC->getPropertyValue("ParaStyleLevel" + OUString::number(nLevel)) >>= style;
+ uno::Reference<beans::XPropertySet> xStyle;
+ if (xStyles->getByName(style) >>= xStyle)
+ {
+ if (uno::Reference<beans::XPropertyState> xPropState{ xStyle,
+ uno::UNO_QUERY })
+ {
+ if (xPropState->getPropertyState("ParaTabStops")
+ == beans::PropertyState_DIRECT_VALUE)
+ {
+ if (uno::Sequence<style::TabStop> tabStops;
+ xStyle->getPropertyValue("ParaTabStops") >>= tabStops)
+ {
+ // If the style only has one tab stop, Word uses it for
+ // page number, and generates the other from defaults
+ if (tabStops.getLength() > 1)
+ numTab = tabStops[0];
+ }
+ }
+ }
+ }
+ if (!numTab)
+ {
+ // Generate the default position.
+ // Word uses multiples of 440 twips for default chapter number tab stops
+ numTab.emplace();
+ numTab->Position
+ = o3tl::convert(440 * nLevel, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+ }
+ }
+
+ uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks(
+ bHyperlinks, sChapterNoSeparator,
+ aLevel, numTab);
+ xLevelFormats->replaceByIndex( nLevel, uno::Any( aNewLevel ) );
+ }
+ }
+ else // if (bTableOfFigures)
+ {
+ if (!sFigureSequence.isEmpty())
+ xTOC->setPropertyValue(getPropertyName(PROP_LABEL_CATEGORY),
+ uno::Any(sFigureSequence));
+
+ if (!sTemplate.isEmpty())
+ {
+ OUString const sConvertedStyleName(ConvertTOCStyleName(sTemplate));
+ xTOC->setPropertyValue("CreateFromParagraphStyle", uno::Any(sConvertedStyleName));
+ }
+
+ if ( bHyperlinks )
+ {
+ uno::Reference< container::XIndexReplace> xLevelFormats;
+ xTOC->getPropertyValue(getPropertyName(PROP_LEVEL_FORMAT)) >>= xLevelFormats;
+ uno::Sequence< beans::PropertyValues > aLevel;
+ xLevelFormats->getByIndex( 1 ) >>= aLevel;
+
+ uno::Sequence< beans::PropertyValues > aNewLevel = lcl_createTOXLevelHyperlinks(
+ bHyperlinks, sChapterNoSeparator,
+ aLevel, {});
+ xLevelFormats->replaceByIndex( 1, uno::Any( aNewLevel ) );
+ }
+ }
+}
+
+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 );
+ try
+ {
+ xSection->attach( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW) );
+ }
+ catch(const uno::Exception&)
+ {
+ }
+ xRet.set(xSection, uno::UNO_QUERY );
+ }
+ catch(const uno::Exception&)
+ {
+ }
+ }
+
+ return xRet;
+}
+
+void DomainMapper_Impl::handleBibliography
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName)
+{
+ if (m_aTextAppendStack.empty())
+ {
+ // tdf#130214: a workaround to avoid crash on import errors
+ SAL_WARN("writerfilter.dmapper", "no text append stack");
+ return;
+ }
+ // Create section before setting m_bStartTOC and m_bStartBibliography: finishing paragraph
+ // inside StartIndexSectionChecked could do the wrong thing otherwise
+ const auto xTOC = StartIndexSectionChecked(sTOCServiceName);
+ m_bStartTOC = true;
+ m_bStartBibliography = true;
+
+ if (xTOC.is())
+ xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::Any(OUString()));
+
+ pContext->SetTOC( xTOC );
+ m_StreamStateStack.top().bParaHadField = false;
+
+ uno::Reference< text::XTextContent > xToInsert( xTOC, uno::UNO_QUERY );
+ appendTextContent(xToInsert, uno::Sequence< beans::PropertyValue >() );
+}
+
+void DomainMapper_Impl::handleIndex
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName)
+{
+ // only UserIndex can handle user index defined by \f
+ // e.g. INDEX \f "user-index-id"
+ OUString sUserIndex;
+ if ( lcl_FindInCommand( pContext->GetCommand(), 'f', sUserIndex ) )
+ sUserIndex = lcl_trim(sUserIndex);
+
+ // Create section before setting m_bStartTOC and m_bStartIndex: finishing paragraph
+ // inside StartIndexSectionChecked could do the wrong thing otherwise
+ const auto xTOC = StartIndexSectionChecked( sUserIndex.isEmpty()
+ ? sTOCServiceName
+ : "com.sun.star.text.UserIndex");
+
+ m_bStartTOC = true;
+ m_bStartIndex = true;
+ OUString sValue;
+ if (xTOC.is())
+ {
+ xTOC->setPropertyValue(getPropertyName( PROP_TITLE ), uno::Any(OUString()));
+
+ if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
+ {
+ xTOC->setPropertyValue("IsCommaSeparated", uno::Any(true));
+ }
+ if( lcl_FindInCommand( pContext->GetCommand(), 'h', sValue ))
+ {
+ xTOC->setPropertyValue("UseAlphabeticalSeparators", uno::Any(true));
+ }
+ if( !sUserIndex.isEmpty() )
+ {
+ xTOC->setPropertyValue("UserIndexName", uno::Any(sUserIndex));
+ }
+ }
+ pContext->SetTOC( xTOC );
+ m_StreamStateStack.top().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;
+ if (xTOC.is())
+ {
+ xTOC->getPropertyValue(getPropertyName( PROP_TEXT_COLUMNS )) >>= xTextColumns;
+ }
+ if (xTextColumns.is())
+ {
+ xTextColumns->setColumnCount( sValue.toInt32() );
+ xTOC->setPropertyValue( getPropertyName( PROP_TEXT_COLUMNS ), uno::Any( xTextColumns ) );
+ }
+ }
+}
+
+static auto InsertFieldmark(std::stack<TextAppendContext> & rTextAppendStack,
+ uno::Reference<text::XFormField> const& xFormField,
+ uno::Reference<text::XTextRange> const& xStartRange,
+ std::optional<FieldId> const oFieldId) -> void
+{
+ uno::Reference<text::XTextContent> const xTextContent(xFormField, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextAppend> const& xTextAppend(rTextAppendStack.top().xTextAppend);
+ uno::Reference<text::XTextCursor> const xCursor =
+ xTextAppend->createTextCursorByRange(xStartRange);
+ if (rTextAppendStack.top().xInsertPosition.is())
+ {
+ uno::Reference<text::XTextRangeCompare> const xCompare(
+ rTextAppendStack.top().xTextAppend,
+ uno::UNO_QUERY);
+ if (xCompare->compareRegionStarts(xStartRange, rTextAppendStack.top().xInsertPosition) < 0)
+ {
+ SAL_WARN("writerfilter.dmapper", "invalid field mark positions");
+ assert(false);
+ }
+ xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, true);
+ }
+ else
+ {
+ xCursor->gotoEnd(true);
+ }
+ xTextAppend->insertTextContent(xCursor, xTextContent, true);
+ if (oFieldId
+ && (oFieldId == FIELD_FORMCHECKBOX || oFieldId == FIELD_FORMDROPDOWN))
+ {
+ return; // only a single CH_TXT_ATR_FORMELEMENT!
+ }
+ // problem: the fieldmark must be inserted in CloseFieldCommand(), because
+ // attach() takes 2 positions, not 3!
+ // FAIL: AppendTextNode() ignores the content index!
+ // plan B: insert a spurious paragraph break now and join
+ // it in PopFieldContext()!
+ xCursor->gotoRange(xTextContent->getAnchor()->getEnd(), false);
+ xCursor->goLeft(1, false); // skip CH_TXT_ATR_FIELDEND
+ xTextAppend->insertControlCharacter(xCursor, text::ControlCharacter::PARAGRAPH_BREAK, false);
+ xCursor->goLeft(1, false); // back to previous paragraph
+ rTextAppendStack.push(TextAppendContext(xTextAppend, xCursor));
+}
+
+static auto PopFieldmark(std::stack<TextAppendContext> & rTextAppendStack,
+ uno::Reference<text::XTextCursor> const& xCursor,
+ std::optional<FieldId> const oFieldId) -> void
+{
+ if (oFieldId
+ && (oFieldId == FIELD_FORMCHECKBOX || oFieldId == FIELD_FORMDROPDOWN))
+ {
+ return; // only a single CH_TXT_ATR_FORMELEMENT!
+ }
+ xCursor->gotoRange(rTextAppendStack.top().xInsertPosition, false);
+ xCursor->goRight(1, true);
+ xCursor->setString(OUString()); // undo SplitNode from CloseFieldCommand()
+ // note: paragraph properties will be overwritten
+ // by finishParagraph() anyway so ignore here
+ rTextAppendStack.pop();
+}
+
+void DomainMapper_Impl::CloseFieldCommand()
+{
+ if(m_bDiscardHeaderFooter)
+ return;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("closeFieldCommand");
+#endif
+
+ FieldContextPtr pContext;
+ if(!m_aFieldStack.empty())
+ pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( !pContext )
+ return;
+
+ pContext->m_bSetUserFieldContent = false;
+ pContext->m_bSetCitation = false;
+ pContext->m_bSetDateValue = false;
+ // tdf#124472: If the normal command line is not empty, use it,
+ // otherwise, the last active row is evaluated.
+ if (!pContext->GetCommandIsEmpty(false))
+ pContext->SetCommandType(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 character properties to the form control
+ if (!m_aTextAppendStack.empty() && m_pLastCharacterContext)
+ {
+ 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 );
+ for (auto& rPropValue : m_pLastCharacterContext->GetPropertyValues(false))
+ {
+ try
+ {
+ xProp->setPropertyValue(rPropValue.Name, rPropValue.Value);
+ }
+ catch(uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "Unknown Field PropVal");
+ }
+ }
+ }
+ }
+ }
+
+ 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 (IsInTOC() && (aIt->second.eFieldId == FIELD_PAGEREF))
+ {
+ bCreateField = false;
+ }
+
+ if( bCreateField || bCreateEnhancedField )
+ {
+ //add the service prefix
+ OUString sServiceName("com.sun.star.text.");
+ if ( bCreateEnhancedField )
+ {
+ const FieldConversionMap_t& aEnhancedFieldConversionMap = lcl_GetEnhancedFieldConversion();
+ FieldConversionMap_t::const_iterator aEnhancedIt =
+ aEnhancedFieldConversionMap.find(sType);
+ if ( aEnhancedIt != aEnhancedFieldConversionMap.end())
+ sServiceName += OUString::createFromAscii(aEnhancedIt->second.cFieldServiceName );
+ }
+ else
+ {
+ sServiceName += "TextField." + OUString::createFromAscii(aIt->second.cFieldServiceName );
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("fieldService");
+ TagLogger::getInstance().chars(sServiceName);
+ TagLogger::getInstance().endElement();
+#endif
+
+ if (m_xTextFactory.is())
+ {
+ xFieldInterface = m_xTextFactory->createInstance(sServiceName);
+ xFieldProperties.set( xFieldInterface, uno::UNO_QUERY_THROW);
+ }
+ }
+ switch( aIt->second.eFieldId )
+ {
+ case FIELD_ADDRESSBLOCK: break;
+ case FIELD_ADVANCE : break;
+ case FIELD_ASK :
+ handleFieldAsk(pContext, xFieldInterface, xFieldProperties);
+ break;
+ case FIELD_AUTONUM :
+ case FIELD_AUTONUMLGL :
+ case FIELD_AUTONUMOUT :
+ handleAutoNum(pContext, xFieldInterface, xFieldProperties);
+ break;
+ case FIELD_AUTHOR :
+ case FIELD_USERNAME :
+ case FIELD_USERINITIALS :
+ handleAuthor(sFirstParam,
+ xFieldProperties,
+ aIt->second.eFieldId);
+ break;
+ case FIELD_DATE:
+ if (xFieldProperties.is())
+ {
+ // Get field fixed property from the context handler
+ if (pContext->IsFieldLocked())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED),
+ uno::Any( true ));
+ pContext->m_bSetDateValue = true;
+ }
+ else
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED),
+ uno::Any( false ));
+
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_DATE),
+ uno::Any( true ));
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ break;
+ case FIELD_COMMENTS :
+ {
+ // OUString sParam = lcl_ExtractParameter(pContext->GetCommand(), sizeof(" COMMENTS") );
+ // A parameter with COMMENTS shouldn't set fixed
+ // ( or at least the binary filter doesn't )
+ // If we set fixed then we won't export a field cmd.
+ // Additionally the para in COMMENTS is more like an
+ // instruction to set the document property comments
+ // with the param ( e.g. each COMMENT with a param will
+ // overwrite the Comments document property
+ // #TODO implement the above too
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( false ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ break;
+ case FIELD_CREATEDATE :
+ case FIELD_PRINTDATE:
+ case FIELD_SAVEDATE:
+ {
+ if (pContext->IsFieldLocked())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED), uno::Any( true ));
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_DATE ), uno::Any( true ));
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ break;
+ case FIELD_DOCPROPERTY :
+ handleDocProperty(pContext, sFirstParam,
+ xFieldInterface);
+ break;
+ case FIELD_DOCVARIABLE :
+ {
+ if (bCreateField)
+ {
+ //create a user field and type
+ uno::Reference<beans::XPropertySet> xMaster = FindOrCreateFieldMaster(
+ "com.sun.star.text.FieldMaster.User", sFirstParam);
+ uno::Reference<text::XDependentTextField> xDependentField(
+ xFieldInterface, uno::UNO_QUERY_THROW);
+ xDependentField->attachTextFieldMaster(xMaster);
+ pContext->m_bSetUserFieldContent = true;
+ }
+ }
+ break;
+ case FIELD_EDITTIME :
+ //it's a numbering type, no number format! SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ break;
+ case FIELD_EQ:
+ {
+ OUString aCommand = pContext->GetCommand().trim();
+
+ msfilter::util::EquationResult aResult(msfilter::util::ParseCombinedChars(aCommand));
+ if (!aResult.sType.isEmpty() && m_xTextFactory.is())
+ {
+ xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField." + aResult.sType);
+ xFieldProperties =
+ uno::Reference< beans::XPropertySet >( xFieldInterface,
+ uno::UNO_QUERY_THROW);
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_CONTENT), uno::Any(aResult.sResult));
+ }
+ else
+ {
+ //merge Read_SubF_Ruby into filter/.../util.cxx and reuse that ?
+ sal_Int32 nSpaceIndex = aCommand.indexOf(' ');
+ if(nSpaceIndex > 0)
+ aCommand = o3tl::trim(aCommand.subView(nSpaceIndex));
+ if (aCommand.startsWith("\\s"))
+ {
+ aCommand = aCommand.copy(2);
+ if (aCommand.startsWith("\\do"))
+ {
+ aCommand = aCommand.copy(3);
+ sal_Int32 nStartIndex = aCommand.indexOf('(');
+ sal_Int32 nEndIndex = aCommand.indexOf(')');
+ if (nStartIndex > 0 && nEndIndex > 0)
+ {
+ // nDown is the requested "lower by" value in points.
+ sal_Int32 nDown = o3tl::toInt32(aCommand.subView(0, nStartIndex));
+ OUString aContent = aCommand.copy(nStartIndex + 1, nEndIndex - nStartIndex - 1);
+ PropertyMapPtr pCharContext = GetTopContext();
+ // dHeight is the font size of the current style.
+ double dHeight = 0;
+ if ((GetPropertyFromParaStyleSheet(PROP_CHAR_HEIGHT) >>= dHeight) && dHeight != 0)
+ // Character escapement should be given in negative percents for subscripts.
+ pCharContext->Insert(PROP_CHAR_ESCAPEMENT, uno::Any( sal_Int16(- 100 * nDown / dHeight) ) );
+ appendTextPortion(aContent, pCharContext);
+ }
+ }
+ }
+ else if (aCommand.startsWith("\\* jc"))
+ {
+ handleRubyEQField(pContext);
+ }
+ }
+ }
+ break;
+ case FIELD_FILLIN :
+ if (xFieldProperties.is())
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_HINT), uno::Any( pContext->GetCommand().getToken(1, '\"')));
+ break;
+ case FIELD_FILENAME:
+ {
+ sal_Int32 nNumberingTypeIndex = pContext->GetCommand().indexOf("\\p");
+ if (xFieldProperties.is())
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_FILE_FORMAT),
+ uno::Any( nNumberingTypeIndex > 0 ? text::FilenameDisplayFormat::FULL : text::FilenameDisplayFormat::NAME_AND_EXT ));
+ }
+ break;
+ case FIELD_FILESIZE : break;
+ case FIELD_FORMULA :
+ if (bCreateField)
+ {
+ handleFieldFormula(pContext, xFieldProperties);
+ }
+ break;
+ case FIELD_FORMCHECKBOX :
+ case FIELD_FORMDROPDOWN :
+ case FIELD_FORMTEXT :
+ {
+ if (bCreateEnhancedField)
+ {
+ FFDataHandler::Pointer_t
+ pFFDataHandler(pContext->getFFDataHandler());
+ FormControlHelper::Pointer_t
+ pFormControlHelper(new FormControlHelper
+ (m_bUsingEnhancedFields ? aIt->second.eFieldId : FIELD_FORMCHECKBOX,
+
+ m_xTextDocument, pFFDataHandler));
+ pContext->setFormControlHelper(pFormControlHelper);
+ uno::Reference< text::XFormField > xFormField( xFieldInterface, uno::UNO_QUERY );
+ uno::Reference< container::XNamed > xNamed( xFormField, uno::UNO_QUERY );
+ if ( xNamed.is() )
+ {
+ if ( pFFDataHandler && !pFFDataHandler->getName().isEmpty() )
+ xNamed->setName( pFFDataHandler->getName() );
+ pContext->SetFormField( xFormField );
+ }
+ InsertFieldmark(m_aTextAppendStack,
+ xFormField, pContext->GetStartRange(),
+ pContext->GetFieldId());
+ }
+ else
+ {
+ if ( aIt->second.eFieldId == FIELD_FORMDROPDOWN )
+ lcl_handleDropdownField( xFieldProperties, pContext->getFFDataHandler() );
+ else
+ lcl_handleTextField( xFieldProperties, pContext->getFFDataHandler() );
+ }
+ }
+ break;
+ case FIELD_GOTOBUTTON : break;
+ case FIELD_HYPERLINK:
+ {
+ ::std::vector<OUString> aParts = pContext->GetCommandParts();
+
+ // Syntax is either:
+ // HYPERLINK "" \l "link"
+ // or
+ // HYPERLINK \l "link"
+ // Make sure "HYPERLINK" doesn't end up as part of link in the second case.
+ if (!aParts.empty() && aParts[0] == "HYPERLINK")
+ aParts.erase(aParts.begin());
+
+ ::std::vector<OUString>::const_iterator aItEnd = aParts.end();
+ ::std::vector<OUString>::const_iterator aPartIt = aParts.begin();
+
+ OUString sURL;
+ OUString sTarget;
+
+ while (aPartIt != aItEnd)
+ {
+ if ( *aPartIt == "\\l" )
+ {
+ ++aPartIt;
+
+ if (aPartIt == aItEnd)
+ break;
+
+ sURL += "#" + *aPartIt;
+ }
+ else if (*aPartIt == "\\m" || *aPartIt == "\\n" || *aPartIt == "\\h")
+ {
+ }
+ else if ( *aPartIt == "\\o" || *aPartIt == "\\t" )
+ {
+ ++aPartIt;
+
+ if (aPartIt == aItEnd)
+ break;
+
+ sTarget = *aPartIt;
+ }
+ else
+ {
+ sURL = *aPartIt;
+ }
+
+ ++aPartIt;
+ }
+
+ if (!sURL.isEmpty())
+ {
+ if (sURL.startsWith("file:///"))
+ {
+ // file:///absolute\\path\\to\\file => invalid file URI (Writer cannot open)
+ // convert all double backslashes to slashes:
+ sURL = sURL.replaceAll("\\\\", "/");
+
+ // file:///absolute\path\to\file => invalid file URI (Writer cannot open)
+ // convert all backslashes to slashes:
+ sURL = sURL.replace('\\', '/');
+ }
+ // Try to make absolute any relative URLs, except
+ // for relative same-document URLs that only contain
+ // a fragment part:
+ else if (!sURL.startsWith("#")) {
+ try {
+ sURL = rtl::Uri::convertRelToAbs(
+ m_aBaseUrl, sURL);
+ } catch (rtl::MalformedUriException & e) {
+ SAL_WARN(
+ "writerfilter.dmapper",
+ "MalformedUriException "
+ << e.getMessage());
+ }
+ }
+ pContext->SetHyperlinkURL(sURL);
+ }
+
+ if (!sTarget.isEmpty())
+ pContext->SetHyperlinkTarget(sTarget);
+ }
+ break;
+ case FIELD_IF:
+ {
+ if (vArguments.size() < 3)
+ {
+ SAL_WARN("writerfilter.dmapper", "IF field requires at least 3 parameters!");
+ break;
+ }
+
+ if (xFieldProperties.is())
+ {
+ // Following code assumes that last argument in field is false value
+ // before it - true value and everything before them is a condition
+ OUString sCondition;
+ size_t i = 0;
+ while (i < vArguments.size() - 2) {
+ if (!sCondition.isEmpty())
+ sCondition += " ";
+ sCondition += vArguments[i++];
+ }
+
+ xFieldProperties->setPropertyValue(
+ "TrueContent", uno::Any(vArguments[vArguments.size() - 2]));
+ xFieldProperties->setPropertyValue(
+ "FalseContent", uno::Any(vArguments[vArguments.size() - 1]));
+ xFieldProperties->setPropertyValue(
+ "Condition", uno::Any(sCondition));
+ }
+ }
+ break;
+ case FIELD_INFO : break;
+ case FIELD_INCLUDEPICTURE: break;
+ case FIELD_KEYWORDS :
+ {
+ if (!sFirstParam.isEmpty())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ }
+ break;
+ case FIELD_LASTSAVEDBY :
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED), uno::Any(true));
+ break;
+ case FIELD_MACROBUTTON:
+ {
+ if (xFieldProperties.is())
+ {
+ sal_Int32 nIndex = sizeof(" MACROBUTTON ");
+ OUString sCommand = pContext->GetCommand();
+
+ //extract macro name
+ if (sCommand.getLength() >= nIndex)
+ {
+ OUString sMacro = sCommand.getToken(0, ' ', nIndex);
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_MACRO_NAME), uno::Any( sMacro ));
+ }
+
+ //extract quick help text
+ if (sCommand.getLength() > nIndex + 1)
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_HINT),
+ uno::Any( sCommand.copy( nIndex )));
+ }
+ }
+ }
+ break;
+ case FIELD_MERGEFIELD :
+ {
+ //todo: create a database field and fieldmaster pointing to a column, only
+ //create a user field and type
+ uno::Reference< beans::XPropertySet > xMaster =
+ FindOrCreateFieldMaster("com.sun.star.text.FieldMaster.Database", sFirstParam);
+
+// xFieldProperties->setPropertyValue(
+// "FieldCode",
+// uno::makeAny( pContext->GetCommand().copy( nIndex + 1 )));
+ uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+ }
+ break;
+ case FIELD_MERGEREC : break;
+ case FIELD_MERGESEQ : break;
+ case FIELD_NEXT : break;
+ case FIELD_NEXTIF : break;
+ case FIELD_PAGE :
+ if (xFieldProperties.is())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_SUB_TYPE),
+ uno::Any( text::PageNumberType_CURRENT ));
+ }
+
+ break;
+ case FIELD_PAGEREF:
+ case FIELD_REF:
+ case FIELD_STYLEREF:
+ if (xFieldProperties.is() && !IsInTOC())
+ {
+ bool bPageRef = aIt->second.eFieldId == FIELD_PAGEREF;
+ bool bStyleRef = aIt->second.eFieldId == FIELD_STYLEREF;
+
+ // 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))
+ {
+ if (bStyleRef)
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
+ uno::Any(sal_Int16(text::ReferenceFieldSource::STYLE)));
+
+ OUString sStyleSheetName
+ = GetStyleSheetTable()->ConvertStyleName(sFirstParam, true);
+
+ uno::Any aStyleDisplayName;
+
+ uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(
+ GetTextDocument(), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyles;
+ xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES))
+ >>= xStyles;
+ uno::Reference<css::beans::XPropertySet> xStyle;
+
+ try
+ {
+ xStyles->getByName(sStyleSheetName) >>= xStyle;
+ aStyleDisplayName = xStyle->getPropertyValue("DisplayName");
+ }
+ catch (css::container::NoSuchElementException)
+ {
+ aStyleDisplayName <<= sStyleSheetName;
+ }
+
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_SOURCE_NAME), aStyleDisplayName);
+
+ sal_uInt16 nFlags = 0;
+ OUString sValue;
+ if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
+ {
+ //search-below-first
+ nFlags |= REFFLDFLAG_STYLE_FROM_BOTTOM;
+ }
+ if( lcl_FindInCommand( pContext->GetCommand(), 't', sValue ))
+ {
+ //suppress-nondelimiter
+ nFlags |= REFFLDFLAG_STYLE_HIDE_NON_NUMERICAL;
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_REFERENCE_FIELD_FLAGS ), uno::Any(nFlags) );
+ }
+ else
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_REFERENCE_FIELD_SOURCE),
+ uno::Any( sal_Int16(text::ReferenceFieldSource::BOOKMARK)) );
+
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_SOURCE_NAME),
+ uno::Any(sFirstParam));
+ }
+
+ sal_Int16 nFieldPart = (bPageRef ? text::ReferenceFieldPart::PAGE : text::ReferenceFieldPart::TEXT);
+ OUString sValue;
+ if( lcl_FindInCommand( pContext->GetCommand(), 'p', sValue ))
+ {
+ //above-below
+ nFieldPart = text::ReferenceFieldPart::UP_DOWN;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
+ {
+ //number
+ nFieldPart = text::ReferenceFieldPart::NUMBER;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
+ {
+ //number-no-context
+ nFieldPart = text::ReferenceFieldPart::NUMBER_NO_CONTEXT;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'w', sValue ))
+ {
+ //number-full-context
+ nFieldPart = text::ReferenceFieldPart::NUMBER_FULL_CONTEXT;
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_REFERENCE_FIELD_PART ), uno::Any( nFieldPart ));
+ }
+ else if( m_xTextFactory.is() )
+ {
+ xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.TextField.GetExpression");
+ xFieldProperties.set(xFieldInterface, uno::UNO_QUERY);
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_CONTENT),
+ uno::Any(sFirstParam));
+ xFieldProperties->setPropertyValue(getPropertyName(PROP_SUB_TYPE), uno::Any(text::SetVariableType::STRING));
+ }
+ }
+ break;
+ case FIELD_REVNUM : break;
+ case FIELD_SECTION : break;
+ case FIELD_SECTIONPAGES : break;
+ case FIELD_SEQ :
+ {
+ // command looks like: " SEQ Table \* ARABIC "
+ OUString sCmd(pContext->GetCommand());
+ // find the sequence name, e.g. "SEQ"
+ std::u16string_view sSeqName = msfilter::util::findQuotedText(sCmd, u"SEQ ", '\\');
+ sSeqName = o3tl::trim(sSeqName);
+
+ // create a sequence field master using the sequence name
+ uno::Reference< beans::XPropertySet > xMaster = FindOrCreateFieldMaster(
+ "com.sun.star.text.FieldMaster.SetExpression",
+ OUString(sSeqName));
+
+ xMaster->setPropertyValue(
+ getPropertyName(PROP_SUB_TYPE),
+ uno::Any(text::SetVariableType::SEQUENCE));
+
+ // apply the numbering type
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+
+ // attach the master to the field
+ uno::Reference< text::XDependentTextField > xDependentField( xFieldInterface, uno::UNO_QUERY_THROW );
+ xDependentField->attachTextFieldMaster( xMaster );
+
+ OUString sFormula = OUString::Concat(sSeqName) + "+1";
+ OUString sValue;
+ if( lcl_FindInCommand( pContext->GetCommand(), 'c', sValue ))
+ {
+ sFormula = sSeqName;
+ }
+ else if( lcl_FindInCommand( pContext->GetCommand(), 'r', sValue ))
+ {
+ sFormula = sValue;
+ }
+ // TODO \s isn't handled, but the spec isn't easy to understand without
+ // an example for this one.
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_CONTENT),
+ uno::Any(sFormula));
+
+ // Take care of the numeric formatting definition, default is Arabic
+ sal_Int16 nNumberingType = lcl_ParseNumberingType(pContext->GetCommand());
+ if (nNumberingType == style::NumberingType::PAGE_DESCRIPTOR)
+ nNumberingType = style::NumberingType::ARABIC;
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any(nNumberingType));
+ }
+ break;
+ case FIELD_SET :
+ handleFieldSet(pContext, xFieldInterface, xFieldProperties);
+ break;
+ case FIELD_SKIPIF : break;
+ case FIELD_SUBJECT :
+ {
+ if (!sFirstParam.isEmpty())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ }
+ break;
+ case FIELD_SYMBOL:
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ OUString sSymbol( sal_Unicode( sFirstParam.startsWithIgnoreAsciiCase("0x") ? o3tl::toUInt32(sFirstParam.subView(2),16) : sFirstParam.toUInt32() ) );
+ OUString sFont;
+ bool bHasFont = lcl_FindInCommand( pContext->GetCommand(), 'f', sFont);
+ if ( bHasFont )
+ {
+ sFont = sFont.trim();
+ if (sFont.startsWith("\""))
+ sFont = sFont.copy(1);
+ if (sFont.endsWith("\""))
+ sFont = sFont.copy(0,sFont.getLength()-1);
+ }
+
+
+
+ if (xTextAppend.is())
+ {
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ if (xCrsr.is())
+ {
+ xCrsr->gotoEnd(false);
+ xText->insertString(xCrsr, sSymbol, true);
+ uno::Reference< beans::XPropertySet > xProp( xCrsr, uno::UNO_QUERY );
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_CHAR_SET), uno::Any(awt::CharSet::SYMBOL));
+ if(bHasFont)
+ {
+ uno::Any aVal( sFont );
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME), aVal);
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_ASIAN), aVal);
+ xProp->setPropertyValue(getPropertyName(PROP_CHAR_FONT_NAME_COMPLEX), aVal);
+
+ }
+ }
+ }
+ }
+ break;
+ case FIELD_TEMPLATE: break;
+ case FIELD_TIME :
+ {
+ if (pContext->IsFieldLocked())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_IS_FIXED),
+ uno::Any( true ));
+ pContext->m_bSetDateValue = true;
+ }
+ SetNumberFormat( pContext->GetCommand(), xFieldProperties );
+ }
+ break;
+ case FIELD_TITLE :
+ {
+ if (!sFirstParam.isEmpty())
+ {
+ xFieldProperties->setPropertyValue(
+ getPropertyName( PROP_IS_FIXED ), uno::Any( true ));
+ //PROP_CURRENT_PRESENTATION is set later anyway
+ }
+ }
+ break;
+ case FIELD_USERADDRESS : //todo: user address collects street, city ...
+ break;
+ case FIELD_INDEX:
+ handleIndex(pContext,
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ break;
+ case FIELD_BIBLIOGRAPHY:
+ handleBibliography(pContext,
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ break;
+ case FIELD_TOC:
+ handleToc(pContext,
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ break;
+ case FIELD_XE:
+ {
+ if( !m_xTextFactory.is() )
+ break;
+
+ // only UserIndexMark can handle user index types defined by \f
+ // e.g. XE "text" \f "user-index-id"
+ OUString sUserIndex;
+ OUString sFieldServiceName =
+ lcl_FindInCommand( pContext->GetCommand(), 'f', sUserIndex )
+ ? "com.sun.star.text.UserIndexMark"
+ : OUString::createFromAscii(aIt->second.cFieldServiceName);
+ uno::Reference< beans::XPropertySet > xTC(
+ m_xTextFactory->createInstance(sFieldServiceName),
+ uno::UNO_QUERY_THROW);
+
+ if (!sFirstParam.isEmpty())
+ {
+ xTC->setPropertyValue(sUserIndex.isEmpty()
+ ? OUString("PrimaryKey")
+ : OUString("AlternativeText"),
+ uno::Any(sFirstParam));
+ }
+
+ sUserIndex = lcl_trim(sUserIndex);
+ if (!sUserIndex.isEmpty())
+ {
+ xTC->setPropertyValue("UserIndexName",
+ uno::Any(sUserIndex));
+ }
+ uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY );
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if (xTextAppend.is())
+ {
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ if (xCrsr.is())
+ {
+ xCrsr->gotoEnd(false);
+ xText->insertTextContent(uno::Reference< text::XTextRange >( xCrsr, uno::UNO_QUERY_THROW ), xToInsert, false);
+ }
+ }
+ }
+ break;
+ case FIELD_CITATION:
+ {
+ if( !m_xTextFactory.is() )
+ break;
+
+ xFieldInterface = m_xTextFactory->createInstance(
+ OUString::createFromAscii(aIt->second.cFieldServiceName));
+ uno::Reference< beans::XPropertySet > xTC(xFieldInterface,
+ uno::UNO_QUERY_THROW);
+ OUString sCmd(pContext->GetCommand());//sCmd is the entire instrText including the index e.g. CITATION Kra06 \l 1033
+ if( !sCmd.isEmpty()){
+ uno::Sequence<beans::PropertyValue> aValues( comphelper::InitPropertySequence({
+ { "Identifier", uno::Any(sCmd) }
+ }));
+ xTC->setPropertyValue("Fields", uno::Any(aValues));
+ }
+ uno::Reference< text::XTextContent > xToInsert( xTC, uno::UNO_QUERY );
+
+ uno::Sequence<beans::PropertyValue> aValues
+ = m_aFieldStack.back()->getProperties()->GetPropertyValues();
+ appendTextContent(xToInsert, aValues);
+ pContext->m_bSetCitation = true;
+ }
+ break;
+
+ case FIELD_TC :
+ {
+ if( !m_xTextFactory.is() )
+ break;
+
+ uno::Reference< beans::XPropertySet > xTC(
+ m_xTextFactory->createInstance(
+ OUString::createFromAscii(aIt->second.cFieldServiceName)),
+ uno::UNO_QUERY_THROW);
+ if (!sFirstParam.isEmpty())
+ {
+ xTC->setPropertyValue(getPropertyName(PROP_ALTERNATIVE_TEXT),
+ uno::Any(sFirstParam));
+ }
+ OUString sValue;
+ // \f TC entry in doc with multiple tables
+// if( lcl_FindInCommand( pContext->GetCommand(), 'f', sValue ))
+// {
+ // todo: unsupported
+// }
+ if( lcl_FindInCommand( pContext->GetCommand(), 'l', sValue ))
+ // \l Outline Level
+ {
+ sal_Int32 nLevel = sValue.toInt32();
+ if( !sValue.isEmpty() && nLevel >= 0 && nLevel <= 10 )
+ xTC->setPropertyValue(getPropertyName(PROP_LEVEL), uno::Any( static_cast<sal_Int16>(nLevel) ));
+ }
+// if( lcl_FindInCommand( pContext->GetCommand(), 'n', sValue ))
+// \n Suppress page numbers
+// {
+ //todo: unsupported feature
+// }
+ pContext->SetTC( xTC );
+ }
+ break;
+ case FIELD_NUMCHARS:
+ case FIELD_NUMWORDS:
+ case FIELD_NUMPAGES:
+ if (xFieldProperties.is())
+ xFieldProperties->setPropertyValue(
+ getPropertyName(PROP_NUMBERING_TYPE),
+ uno::Any( lcl_ParseNumberingType(pContext->GetCommand()) ));
+ break;
+ }
+
+ if (!bCreateEnhancedField)
+ {
+ pContext->SetTextField( uno::Reference<text::XTextField>(xFieldInterface, uno::UNO_QUERY) );
+ }
+ }
+ else
+ {
+ /* Unsupported fields will be handled here for docx file.
+ * To handle unsupported fields used fieldmark API.
+ */
+ OUString aCode( pContext->GetCommand().trim() );
+ // Don't waste resources on wrapping shapes inside a fieldmark.
+ if (sType != "SHAPE" && m_xTextFactory.is() && !m_aTextAppendStack.empty())
+ {
+ xFieldInterface = m_xTextFactory->createInstance("com.sun.star.text.Fieldmark");
+
+ uno::Reference<text::XFormField> const xFormField(xFieldInterface, uno::UNO_QUERY);
+ InsertFieldmark(m_aTextAppendStack, xFormField, pContext->GetStartRange(),
+ pContext->GetFieldId());
+ xFormField->setFieldType(ODF_UNHANDLED);
+ ++m_nStartGenericField;
+ pContext->SetFormField( xFormField );
+ uno::Reference<container::XNameContainer> const xNameCont(xFormField->getParameters());
+ // note: setting the code to empty string is *required* in
+ // m_bForceGenericFields mode, or the export will write
+ // the ODF_UNHANDLED string!
+ assert(!m_bForceGenericFields || aCode.isEmpty());
+ xNameCont->insertByName(ODF_CODE_PARAM, uno::Any(aCode));
+ ww::eField const id(GetWW8FieldId(sType));
+ if (id != ww::eNONE)
+ { // tdf#129247 tdf#134264 set WW8 id for WW8 export
+ xNameCont->insertByName(ODF_ID_PARAM, uno::Any(OUString::number(id)));
+ }
+ }
+ else
+ m_StreamStateStack.top().bParaHadField = false;
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter.dmapper", "Exception in CloseFieldCommand()" );
+ }
+ pContext->SetCommandCompleted();
+}
+/*-------------------------------------------------------------------------
+//the _current_ fields require a string type result while TOCs accept richt results
+ -----------------------------------------------------------------------*/
+bool DomainMapper_Impl::IsFieldResultAsString()
+{
+ bool bRet = false;
+ OSL_ENSURE( !m_aFieldStack.empty(), "field stack empty?");
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( pContext )
+ {
+ bRet = pContext->GetTextField().is()
+ || pContext->GetFieldId() == FIELD_FORMDROPDOWN
+ || pContext->GetFieldId() == FIELD_FILLIN;
+ }
+
+ if (!bRet)
+ {
+ FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
+ if (pOuter)
+ {
+ if (!IsFieldNestingAllowed(pOuter, m_aFieldStack.back()))
+ {
+ // If nesting is not allowed, then the result can only be a string.
+ bRet = true;
+ }
+ }
+ }
+ return bRet;
+}
+
+void DomainMapper_Impl::AppendFieldResult(std::u16string_view rString)
+{
+ assert(!m_aFieldStack.empty());
+ FieldContextPtr pContext = m_aFieldStack.back();
+ SAL_WARN_IF(!pContext, "writerfilter.dmapper", "no field context");
+ if (!pContext)
+ return;
+
+ FieldContextPtr pOuter = GetParentFieldContext(m_aFieldStack);
+ if (pOuter)
+ {
+ if (!IsFieldNestingAllowed(pOuter, pContext))
+ {
+ if (pOuter->IsCommandCompleted())
+ {
+ // Child can't host the field result, forward to parent's result.
+ pOuter->AppendResult(rString);
+ }
+ return;
+ }
+ }
+
+ pContext->AppendResult(rString);
+}
+
+// Calculates css::DateTime based on ddddd.sssss since 1899-12-30
+static util::DateTime lcl_dateTimeFromSerial(const double& dSerial)
+{
+ DateTime d(Date(30, 12, 1899));
+ d.AddTime(dSerial);
+ return d.GetUNODateTime();
+}
+
+void DomainMapper_Impl::SetFieldResult(OUString const& rResult)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("setFieldResult");
+ TagLogger::getInstance().chars(rResult);
+#endif
+
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+
+ if (m_aFieldStack.size() > 1)
+ {
+ // This is a nested field. See if the parent supports nesting on the Writer side.
+ FieldContextPtr pParentContext = m_aFieldStack[m_aFieldStack.size() - 2];
+ if (pParentContext)
+ {
+ std::vector<OUString> aParentParts = pParentContext->GetCommandParts();
+ // Conditional text fields don't support nesting in Writer.
+ if (!aParentParts.empty() && aParentParts[0] == "IF")
+ {
+ return;
+ }
+ }
+ }
+
+ if( !pContext )
+ return;
+
+ uno::Reference<text::XTextField> xTextField = pContext->GetTextField();
+ try
+ {
+ OSL_ENSURE( xTextField.is()
+ //||m_xTOC.is() ||m_xTC.is()
+ //||m_sHyperlinkURL.getLength()
+ , "DomainMapper_Impl::SetFieldResult: field not created" );
+ if(xTextField.is())
+ {
+ try
+ {
+ if (pContext->m_bSetUserFieldContent)
+ {
+ // user field content has to be set at the field master
+ uno::Reference< text::XDependentTextField > xDependentField( xTextField, uno::UNO_QUERY_THROW );
+ xDependentField->getTextFieldMaster()->setPropertyValue(
+ getPropertyName(PROP_CONTENT),
+ uno::Any( rResult ));
+ }
+ else if (pContext->m_bSetCitation)
+ {
+
+ uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
+ // In case of SetExpression, the field result contains the content of the variable.
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY);
+
+ bool bIsSetbiblio = xServiceInfo->supportsService("com.sun.star.text.TextField.Bibliography");
+ if( bIsSetbiblio )
+ {
+ uno::Any aProperty = xFieldProperties->getPropertyValue("Fields");
+ uno::Sequence<beans::PropertyValue> aValues ;
+ aProperty >>= aValues;
+ beans::PropertyValue propertyVal;
+ sal_Int32 nTitleFoundIndex = -1;
+ for (sal_Int32 i = 0; i < aValues.getLength(); ++i)
+ {
+ propertyVal = aValues[i];
+ if (propertyVal.Name == "Title")
+ {
+ nTitleFoundIndex = i;
+ break;
+ }
+ }
+ if (nTitleFoundIndex != -1)
+ {
+ OUString titleStr;
+ uno::Any aValue(propertyVal.Value);
+ aValue >>= titleStr;
+ titleStr += rResult;
+ propertyVal.Value <<= titleStr;
+ aValues.getArray()[nTitleFoundIndex] = propertyVal;
+ }
+ else
+ {
+ aValues.realloc(aValues.getLength() + 1);
+ propertyVal.Name = "Title";
+ propertyVal.Value <<= rResult;
+ aValues.getArray()[aValues.getLength() - 1] = propertyVal;
+ }
+ xFieldProperties->setPropertyValue("Fields",
+ uno::Any(aValues));
+ }
+ }
+ else if (pContext->m_bSetDateValue)
+ {
+ uno::Reference< util::XNumberFormatsSupplier > xNumberSupplier( m_xTextDocument, uno::UNO_QUERY_THROW );
+
+ uno::Reference<util::XNumberFormatter> xFormatter(util::NumberFormatter::create(m_xComponentContext), uno::UNO_QUERY_THROW);
+ xFormatter->attachNumberFormatsSupplier( xNumberSupplier );
+ sal_Int32 nKey = 0;
+
+ uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
+
+ xFieldProperties->getPropertyValue( "NumberFormat" ) >>= nKey;
+ xFieldProperties->setPropertyValue(
+ "DateTimeValue",
+ uno::Any( lcl_dateTimeFromSerial( xFormatter->convertStringToNumber( nKey, rResult ) ) ) );
+ }
+ else
+ {
+ uno::Reference< beans::XPropertySet > xFieldProperties( xTextField, uno::UNO_QUERY_THROW);
+ // In case of SetExpression, and Input fields the field result contains the content of the variable.
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xTextField, uno::UNO_QUERY);
+ // there are fields with a content property, which aren't working correctly with
+ // a generalized try catch of the content, property, so just restrict content
+ // handling to these explicit services.
+ const bool bHasContent = xServiceInfo->supportsService("com.sun.star.text.TextField.SetExpression") ||
+ xServiceInfo->supportsService("com.sun.star.text.TextField.Input");
+ // If we already have content set, then use the current presentation
+ OUString sValue;
+ if (bHasContent)
+ {
+ // this will throw for field types without Content
+ uno::Any aValue(xFieldProperties->getPropertyValue(
+ getPropertyName(PROP_CONTENT)));
+ aValue >>= sValue;
+ }
+ xFieldProperties->setPropertyValue(
+ getPropertyName(bHasContent && sValue.isEmpty()? PROP_CONTENT : PROP_CURRENT_PRESENTATION),
+ uno::Any( rResult ));
+
+ // LO always automatically updates a DocInfo field from the File-Properties-Custom Prop
+ // while MS Word requires the user to manually refresh the field (with F9).
+ // In other words, Word lets the field to be out of sync with the controlling variable.
+ // Marking as FIXEDFLD solves the automatic replacement problem, but of course prevents
+ // Writer from making any changes, even on an F9 refresh.
+ OUString sVariable = pContext->GetVariableValue();
+ if (rResult.getLength() != sVariable.getLength())
+ {
+ sal_Int32 nLen = sVariable.indexOf('\x0');
+ if (nLen >= 0)
+ sVariable = sVariable.copy(0, nLen);
+ }
+ bool bCustomFixedField = rResult != sVariable &&
+ xServiceInfo->supportsService("com.sun.star.text.TextField.DocInfo.Custom");
+
+ if (bCustomFixedField || xServiceInfo->supportsService(
+ "com.sun.star.text.TextField.DocInfo.CreateDateTime"))
+ {
+ // Creation time is const, don't try to update it.
+ xFieldProperties->setPropertyValue("IsFixed", uno::Any(true));
+ }
+ }
+ }
+ catch( const beans::UnknownPropertyException& )
+ {
+ //some fields don't have a CurrentPresentation (DateTime)
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper", "DomainMapper_Impl::SetFieldResult");
+ }
+}
+
+void DomainMapper_Impl::SetFieldFFData(const FFDataHandler::Pointer_t& pFFDataHandler)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("setFieldFFData");
+#endif
+
+ if (!m_aFieldStack.empty())
+ {
+ FieldContextPtr pContext = m_aFieldStack.back();
+ if (pContext)
+ {
+ pContext->setFFDataHandler(pFFDataHandler);
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void DomainMapper_Impl::PopFieldContext()
+{
+ if(m_bDiscardHeaderFooter)
+ return;
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("popFieldContext");
+#endif
+
+ if (m_aFieldStack.empty())
+ return;
+
+ FieldContextPtr pContext = m_aFieldStack.back();
+ OSL_ENSURE( pContext, "no field context available");
+ if( pContext )
+ {
+ if( !pContext->IsCommandCompleted() )
+ CloseFieldCommand();
+
+ if (!pContext->GetResult().isEmpty())
+ {
+ uno::Reference< beans::XPropertySet > xFieldProperties = pContext->GetCustomField();
+ if(xFieldProperties.is())
+ SetNumberFormat( pContext->GetResult(), xFieldProperties, true );
+ SetFieldResult( pContext->GetResult() );
+ }
+
+ //insert the field, TC or TOC
+ uno::Reference< text::XTextAppend > xTextAppend;
+ if (!m_aTextAppendStack.empty())
+ xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(xTextAppend.is())
+ {
+ try
+ {
+ uno::Reference< text::XTextContent > xToInsert( pContext->GetTOC(), uno::UNO_QUERY );
+ if( xToInsert.is() )
+ {
+ if (m_bStartedTOC || m_bStartIndex || m_bStartBibliography)
+ {
+ // inside SDT, last empty paragraph is also part of index
+ if (!m_StreamStateStack.top().bParaChanged && !m_StreamStateStack.top().xSdtEntryStart)
+ {
+ // End of index is the first item on a new paragraph - this paragraph
+ // should not be part of index
+ auto xCursor
+ = xTextAppend->createTextCursorByRange(
+ m_aTextAppendStack.top().xInsertPosition.is()
+ ? m_aTextAppendStack.top().xInsertPosition
+ : xTextAppend->getEnd());
+ xCursor->goLeft(1, true);
+ // delete
+ xCursor->setString(OUString());
+ // But a new paragraph should be started after the index instead
+ if (m_bIsNewDoc) // this check - see testTdf129402
+ { // where finishParagraph inserts between 2 EndNode
+ xTextAppend->finishParagraph(css::beans::PropertyValues());
+ }
+ else
+ {
+ xTextAppend->finishParagraphInsert(css::beans::PropertyValues(),
+ m_aTextAppendStack.top().xInsertPosition);
+ }
+ }
+ m_bStartedTOC = false;
+ m_aTextAppendStack.pop();
+ m_StreamStateStack.top().bTextInserted = false;
+ m_StreamStateStack.top().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() && !IsInTOC() && !m_bStartIndex && !m_bStartBibliography)
+ xToInsert = pContext->GetTextField();
+ if (xToInsert.is() && !IsInTOC() && !m_bStartIndex && !m_bStartBibliography)
+ {
+ PropertyMap aMap;
+ // Character properties of the field show up here the
+ // last (always empty) run. Inherit character
+ // properties from there.
+ // Also merge in the properties from the field context,
+ // e.g. SdtEndBefore.
+ if (m_pLastCharacterContext)
+ aMap.InsertProps(m_pLastCharacterContext);
+ aMap.InsertProps(m_aFieldStack.back()->getProperties());
+ appendTextContent(xToInsert, aMap.GetPropertyValues());
+ CheckRedline( xToInsert->getAnchor( ) );
+ }
+ else
+ {
+ uno::Reference< text::XTextCursor > xCrsr = xTextAppend->createTextCursorByRange(pContext->GetStartRange());
+ FormControlHelper::Pointer_t pFormControlHelper(pContext->getFormControlHelper());
+ if (pFormControlHelper)
+ {
+ // xCrsr may be empty e.g. when pContext->GetStartRange() is outside of
+ // xTextAppend, like when a field started in a parent paragraph is being
+ // closed inside an anchored text box. It could be possible to throw an
+ // exception here, and abort import, but Word tolerates such invalid
+ // input, so it makes sense to do the same (tdf#152200)
+ if (xCrsr.is())
+ {
+ uno::Reference< text::XFormField > xFormField(pContext->GetFormField());
+ if (pFormControlHelper->hasFFDataHandler())
+ {
+ xToInsert.set(xFormField, uno::UNO_QUERY);
+ if (xFormField.is() && xToInsert.is())
+ {
+ PopFieldmark(m_aTextAppendStack, xCrsr,
+ pContext->GetFieldId());
+ pFormControlHelper->processField(xFormField);
+ }
+ else
+ {
+ pFormControlHelper->insertControl(xCrsr);
+ }
+ }
+ else
+ {
+ PopFieldmark(m_aTextAppendStack, xCrsr,
+ pContext->GetFieldId());
+ uno::Reference<lang::XComponent>(xFormField, uno::UNO_QUERY_THROW)->dispose(); // presumably invalid?
+ }
+ }
+ }
+ else if (!pContext->GetHyperlinkURL().isEmpty() && xCrsr.is())
+ {
+ if (m_aTextAppendStack.top().xInsertPosition.is())
+ {
+ xCrsr->gotoRange(m_aTextAppendStack.top().xInsertPosition, true);
+ }
+ else
+ {
+ xCrsr->gotoEnd(true);
+ }
+
+ // Draw components (like comments) need hyperlinks set differently
+ SvxUnoTextRangeBase* pDrawText = dynamic_cast<SvxUnoTextRangeBase*>(xCrsr.get());
+ if ( pDrawText )
+ pDrawText->attachField( std::make_unique<SvxURLField>(pContext->GetHyperlinkURL(), xCrsr->getString(), SvxURLFormat::AppDefault) );
+ else
+ {
+ uno::Reference< beans::XPropertySet > xCrsrProperties( xCrsr, uno::UNO_QUERY_THROW );
+ xCrsrProperties->setPropertyValue(getPropertyName(PROP_HYPER_LINK_U_R_L), uno::
+ Any(pContext->GetHyperlinkURL()));
+
+ if (!pContext->GetHyperlinkTarget().isEmpty())
+ xCrsrProperties->setPropertyValue("HyperLinkTarget", uno::Any(pContext->GetHyperlinkTarget()));
+
+ if (IsInTOC())
+ {
+ OUString sDisplayName("Index Link");
+ xCrsrProperties->setPropertyValue("VisitedCharStyleName",uno::Any(sDisplayName));
+ xCrsrProperties->setPropertyValue("UnvisitedCharStyleName",uno::Any(sDisplayName));
+ }
+ else if (!pContext->GetHyperlinkStyle().isEmpty())
+ {
+ uno::Any aAny = xCrsrProperties->getPropertyValue("CharStyleName");
+ OUString charStyle;
+ if (css::uno::fromAny(aAny, &charStyle))
+ {
+ if (!charStyle.isEmpty() && charStyle.equalsIgnoreAsciiCase("Internet Link"))
+ {
+ xCrsrProperties->setPropertyValue("CharStyleName", uno::Any(OUString("Default Style")));
+ }
+ else
+ {
+ xCrsrProperties->setPropertyValue("VisitedCharStyleName", uno::Any(pContext->GetHyperlinkStyle()));
+ xCrsrProperties->setPropertyValue("UnvisitedCharStyleName", uno::Any(pContext->GetHyperlinkStyle()));
+
+ }
+ }
+ }
+ }
+ }
+ else if (m_nStartGenericField != 0)
+ {
+ --m_nStartGenericField;
+ PopFieldmark(m_aTextAppendStack, xCrsr, pContext->GetFieldId());
+ if (m_StreamStateStack.top().bTextInserted)
+ {
+ m_StreamStateStack.top().bTextInserted = false;
+ }
+ }
+ }
+ }
+ }
+ catch(const lang::IllegalArgumentException&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "PopFieldContext()" );
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "PopFieldContext()" );
+ }
+ }
+
+ //TOCs have to include all the imported content
+ }
+
+ std::vector<FieldParagraph> aParagraphsToFinish;
+ if (pContext)
+ {
+ aParagraphsToFinish = pContext->GetParagraphsToFinish();
+ }
+
+ //remove the field context
+ m_aFieldStack.pop_back();
+
+ // Finish the paragraph(s) now that the field is closed.
+ for (const auto& rFinish : aParagraphsToFinish)
+ {
+ finishParagraph(rFinish.m_pPropertyMap, rFinish.m_bRemove);
+ }
+}
+
+
+void DomainMapper_Impl::SetBookmarkName( const OUString& rBookmarkName )
+{
+ BookmarkMap_t::iterator aBookmarkIter = m_aBookmarkMap.find( m_sCurrentBkmkId );
+ if( aBookmarkIter != m_aBookmarkMap.end() )
+ {
+ // fields are internal bookmarks: consume redundant "normal" bookmark
+ if ( IsOpenField() )
+ {
+ FFDataHandler::Pointer_t pFFDataHandler(GetTopFieldContext()->getFFDataHandler());
+ if (pFFDataHandler && pFFDataHandler->getName() == rBookmarkName)
+ {
+ // HACK: At the END marker, StartOrEndBookmark will START
+ // a bookmark which will eventually be abandoned, not created.
+ m_aBookmarkMap.erase(aBookmarkIter);
+ return;
+ }
+ }
+
+ if ((m_sCurrentBkmkPrefix == "__RefMoveFrom__"
+ || m_sCurrentBkmkPrefix == "__RefMoveTo__")
+ && std::find(m_aRedlineMoveIDs.begin(), m_aRedlineMoveIDs.end(), rBookmarkName)
+ == m_aRedlineMoveIDs.end())
+ {
+ m_aRedlineMoveIDs.push_back(rBookmarkName);
+ }
+
+ aBookmarkIter->second.m_sBookmarkName = m_sCurrentBkmkPrefix + rBookmarkName;
+ m_sCurrentBkmkPrefix.clear();
+ }
+ else
+ {
+ m_sCurrentBkmkName = rBookmarkName;
+ m_sCurrentBkmkPrefix.clear();
+ }
+}
+
+// This method was used as-is for DomainMapper_Impl::startOrEndPermissionRange() implementation.
+void DomainMapper_Impl::StartOrEndBookmark( const OUString& rId )
+{
+ /*
+ * Add the dummy paragraph to handle section properties
+ * iff the first element in the section is a table. If the dummy para is not added yet, then add it;
+ * So bookmark is not attached to the wrong paragraph.
+ */
+ if (hasTableManager() && getTableManager().isInCell()
+ && m_StreamStateStack.top().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 );
+ }
+ if (!aBookmarkIter->second.m_bIsStartOfText)
+ {
+ xCursor->goRight( 1, false );
+ }
+
+ xCursor->gotoRange( xTextAppend->getEnd(), true );
+ // A Paragraph was recently finished, and a new Paragraph has not been started as yet
+ // then move the bookmark-End to the earlier paragraph
+ if (IsOutsideAParagraph())
+ {
+ // keep bookmark range, if it doesn't exceed cell boundary
+ uno::Reference< text::XTextRange > xStart = xCursor->getStart();
+ xCursor->goLeft( 1, false );
+ if (m_StreamStateStack.top().nTableDepth == 0
+ || !m_StreamStateStack.top().bFirstParagraphInCell)
+ {
+ xCursor->gotoRange(xStart, true );
+ }
+ }
+ uno::Reference< container::XNamed > xBkmNamed( xBookmark, uno::UNO_QUERY_THROW );
+ SAL_WARN_IF(aBookmarkIter->second.m_sBookmarkName.isEmpty(), "writerfilter.dmapper", "anonymous bookmark");
+ //todo: make sure the name is not used already!
+ xBkmNamed->setName( aBookmarkIter->second.m_sBookmarkName );
+ xTextAppend->insertTextContent( uno::Reference< text::XTextRange >( xCursor, uno::UNO_QUERY_THROW), xBookmark, !xCursor->isCollapsed() );
+ }
+ m_aBookmarkMap.erase( aBookmarkIter );
+ m_sCurrentBkmkId.clear();
+ }
+ else
+ {
+ //otherwise insert a text range as marker
+ bool bIsStart = true;
+ uno::Reference< text::XTextRange > xCurrent;
+ if (xTextAppend.is())
+ {
+ uno::Reference<text::XTextCursor> const xCursor =
+ xTextAppend->createTextCursorByRange(
+ m_aTextAppendStack.top().xInsertPosition.is()
+ ? m_aTextAppendStack.top().xInsertPosition
+ : xTextAppend->getEnd() );
+
+ if (!xCursor)
+ return;
+
+ if (!bIsAfterDummyPara)
+ bIsStart = !xCursor->goLeft(1, false);
+ xCurrent = xCursor->getStart();
+ }
+ m_sCurrentBkmkId = rId;
+ m_aBookmarkMap.emplace( rId, BookmarkInsertPosition( bIsStart, m_sCurrentBkmkName, xCurrent ) );
+ m_sCurrentBkmkName.clear();
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ //TODO: What happens to bookmarks where start and end are at different XText objects?
+ }
+}
+
+void DomainMapper_Impl::SetMoveBookmark( bool bIsFrom )
+{
+ static constexpr OUStringLiteral MoveFrom_Bookmark_NamePrefix = u"__RefMoveFrom__";
+ static constexpr OUStringLiteral MoveTo_Bookmark_NamePrefix = u"__RefMoveTo__";
+ if ( bIsFrom )
+ m_sCurrentBkmkPrefix = MoveFrom_Bookmark_NamePrefix;
+ else
+ m_sCurrentBkmkPrefix = MoveTo_Bookmark_NamePrefix;
+}
+
+void DomainMapper_Impl::setPermissionRangeEd(const OUString& user)
+{
+ PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
+ if (aPremIter != m_aPermMap.end())
+ aPremIter->second.m_Ed = user;
+ else
+ m_sCurrentPermEd = user;
+}
+
+void DomainMapper_Impl::setPermissionRangeEdGrp(const OUString& group)
+{
+ PermMap_t::iterator aPremIter = m_aPermMap.find(m_sCurrentPermId);
+ if (aPremIter != m_aPermMap.end())
+ aPremIter->second.m_EdGrp = group;
+ else
+ m_sCurrentPermEdGrp = group;
+}
+
+// This method is based on implementation from DomainMapper_Impl::StartOrEndBookmark()
+void DomainMapper_Impl::startOrEndPermissionRange(sal_Int32 permissinId)
+{
+ /*
+ * Add the dummy paragraph to handle section properties
+ * if the first element in the section is a table. If the dummy para is not added yet, then add it;
+ * So permission is not attached to the wrong paragraph.
+ */
+ if (getTableManager().isInCell()
+ && m_StreamStateStack.top().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);
+ }
+ if (!aPermIter->second.m_bIsStartOfText)
+ {
+ 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()
+{
+ if(!m_pGraphicImport)
+ {
+ m_pGraphicImport = new GraphicImport(m_xComponentContext, m_xTextFactory, m_rDMapper, m_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)
+{
+ GetGraphicImport();
+ if (m_eGraphicImportType != IMPORT_AS_DETECTED_INLINE && m_eGraphicImportType != IMPORT_AS_DETECTED_ANCHOR)
+ { // this appears impossible?
+ //create the graphic
+ ref->resolve( *m_pGraphicImport );
+ }
+
+ //insert it into the document at the current cursor position
+
+ uno::Reference<text::XTextContent> xTextContent
+ (m_pGraphicImport->GetGraphicObject());
+
+ // In case the SDT starts with the text portion of the graphic, then set the SDT properties here.
+ bool bHasGrabBag = false;
+ uno::Reference<beans::XPropertySet> xPropertySet(xTextContent, uno::UNO_QUERY);
+ if (xPropertySet.is())
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ bHasGrabBag = xPropertySetInfo->hasPropertyByName("FrameInteropGrabBag");
+ // In case we're outside a paragraph, then the SDT properties are stored in the paragraph grab-bag, not the frame one.
+ if (!m_pSdtHelper->isInteropGrabBagEmpty() && bHasGrabBag && !m_pSdtHelper->isOutsideAParagraph())
+ {
+ comphelper::SequenceAsHashMap aFrameGrabBag(xPropertySet->getPropertyValue("FrameInteropGrabBag"));
+ aFrameGrabBag["SdtPr"] <<= m_pSdtHelper->getInteropGrabBagAndClear();
+ xPropertySet->setPropertyValue("FrameInteropGrabBag", uno::Any(aFrameGrabBag.getAsConstPropertyValueList()));
+ }
+ }
+
+ /* Set "SdtEndBefore" property on Drawing.
+ * It is required in a case when Drawing appears immediately after first run i.e.
+ * there is no text/space/tab in between two runs.
+ * In this case "SdtEndBefore" property needs to be set on Drawing.
+ */
+ if(IsSdtEndBefore())
+ {
+ if(xPropertySet.is() && bHasGrabBag)
+ {
+ uno::Sequence<beans::PropertyValue> aFrameGrabBag( comphelper::InitPropertySequence({
+ { "SdtEndBefore", uno::Any(true) }
+ }));
+ xPropertySet->setPropertyValue("FrameInteropGrabBag",uno::Any(aFrameGrabBag));
+ }
+ }
+
+
+ // Update the shape properties if it is embedded object.
+ if (m_StreamStateStack.top().xEmbedded.is())
+ {
+ if (m_pGraphicImport->GetXShapeObject())
+ m_pGraphicImport->GetXShapeObject()->setPosition(
+ m_pGraphicImport->GetGraphicObjectPosition());
+
+ uno::Reference<drawing::XShape> xShape = m_pGraphicImport->GetXShapeObject();
+ UpdateEmbeddedShapeProps(xShape);
+ if (m_eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ uno::Reference<beans::XPropertySet> const xEmbeddedProps(m_StreamStateStack.top().xEmbedded, uno::UNO_QUERY);
+ xEmbeddedProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ xEmbeddedProps->setPropertyValue("IsFollowingTextFlow", uno::Any(m_pGraphicImport->GetLayoutInCell()));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xEmbeddedProps->setPropertyValue("HoriOrient", xShapeProps->getPropertyValue("HoriOrient"));
+ xEmbeddedProps->setPropertyValue("HoriOrientPosition", xShapeProps->getPropertyValue("HoriOrientPosition"));
+ xEmbeddedProps->setPropertyValue("HoriOrientRelation", xShapeProps->getPropertyValue("HoriOrientRelation"));
+ xEmbeddedProps->setPropertyValue("VertOrient", xShapeProps->getPropertyValue("VertOrient"));
+ xEmbeddedProps->setPropertyValue("VertOrientPosition", xShapeProps->getPropertyValue("VertOrientPosition"));
+ xEmbeddedProps->setPropertyValue("VertOrientRelation", xShapeProps->getPropertyValue("VertOrientRelation"));
+ //tdf123873 fix missing textwrap import
+ xEmbeddedProps->setPropertyValue("TextWrap", xShapeProps->getPropertyValue("TextWrap"));
+
+ // GraphicZOrderHelper::findZOrder() was called already, so can just copy it over.
+ xEmbeddedProps->setPropertyValue("ZOrder", xShapeProps->getPropertyValue("ZOrder"));
+ }
+ }
+ //insert it into the document at the current cursor position
+ OSL_ENSURE( xTextContent.is(), "DomainMapper_Impl::ImportGraphic");
+ if( xTextContent.is())
+ {
+ bool bAppend = true;
+ // workaround for images anchored to characters: add ZWSPs around the anchoring point
+ if (m_eGraphicImportType != IMPORT_AS_DETECTED_INLINE && !m_aRedlines.top().empty())
+ {
+ uno::Reference< text::XTextAppend > xTextAppend = m_aTextAppendStack.top().xTextAppend;
+ if(xTextAppend.is())
+ {
+ try
+ {
+ uno::Reference< text::XText > xText = xTextAppend->getText();
+ uno::Reference< text::XTextCursor > xCrsr = xText->createTextCursor();
+ xCrsr->gotoEnd(false);
+ PropertyMapPtr pEmpty(new PropertyMap());
+ appendTextPortion(u"​"_ustr, pEmpty);
+ appendTextContent( xTextContent, uno::Sequence< beans::PropertyValue >() );
+ bAppend = false;
+ xCrsr->gotoEnd(false);
+ appendTextPortion(u"​"_ustr, pEmpty);
+
+ m_bRedlineImageInPreviousRun = true;
+ m_previousRedline = m_currentRedline;
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if ( bAppend )
+ appendTextContent( xTextContent, uno::Sequence< beans::PropertyValue >() );
+
+ if (m_eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR && !m_aTextAppendStack.empty())
+ {
+ // Remember this object is anchored to the current paragraph.
+ AnchoredObjectInfo aInfo;
+ aInfo.m_xAnchoredObject = xTextContent;
+ if (m_pGraphicImport)
+ {
+ // We still have the graphic import around, remember the original margin, so later
+ // SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing() can use it.
+ aInfo.m_nLeftMargin = m_pGraphicImport->GetLeftMarginOrig();
+ }
+ m_aTextAppendStack.top().m_aAnchoredObjects.push_back(aInfo);
+ }
+ else if (m_eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
+ {
+ m_StreamStateStack.top().bParaWithInlineObject = true;
+
+ // store inline images with track changes, because the anchor point
+ // to set redlining is not available yet
+ if (!m_aTextAppendStack.empty() && !m_aRedlines.top().empty() )
+ {
+ // Remember this object is anchored to the current paragraph.
+ AnchoredObjectInfo aInfo;
+ aInfo.m_xAnchoredObject = xTextContent;
+ aInfo.m_xRedlineForInline = m_aRedlines.top().back();
+ m_aTextAppendStack.top().m_aAnchoredObjects.push_back(aInfo);
+ }
+
+ }
+ }
+
+ // Clear the reference, so in case the embedded object is inside a
+ // TextFrame, we won't try to resize it (to match the size of the
+ // TextFrame) here.
+ m_StreamStateStack.top().xEmbedded.clear();
+ m_pGraphicImport.clear();
+}
+
+
+void DomainMapper_Impl::SetLineNumbering( sal_Int32 nLnnMod, sal_uInt32 nLnc, sal_Int32 ndxaLnn )
+{
+ if( !m_bLineNumberingSet )
+ {
+ try
+ {
+ uno::Reference< text::XLineNumberingProperties > xLineProperties( m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xProperties = xLineProperties->getLineNumberingProperties();
+ uno::Any aTrue( uno::Any( true ));
+ xProperties->setPropertyValue( getPropertyName( PROP_IS_ON ), aTrue);
+ xProperties->setPropertyValue( getPropertyName( PROP_COUNT_EMPTY_LINES ), aTrue );
+ xProperties->setPropertyValue( getPropertyName( PROP_COUNT_LINES_IN_FRAMES ), uno::Any( false ) );
+ xProperties->setPropertyValue( getPropertyName( PROP_INTERVAL ), uno::Any( static_cast< sal_Int16 >( nLnnMod )));
+ xProperties->setPropertyValue( getPropertyName( PROP_DISTANCE ), uno::Any( ConversionHelper::convertTwipToMM100(ndxaLnn) ));
+ xProperties->setPropertyValue( getPropertyName( PROP_NUMBER_POSITION ), uno::Any( style::LineNumberPosition::LEFT));
+ xProperties->setPropertyValue( getPropertyName( PROP_NUMBERING_TYPE ), uno::Any( style::NumberingType::ARABIC));
+ xProperties->setPropertyValue( getPropertyName( PROP_RESTART_AT_EACH_PAGE ), uno::Any( nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newPage ));
+ }
+ catch( const uno::Exception& )
+ {}
+ }
+ m_bLineNumberingSet = true;
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( GetTextDocument(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xStyles;
+ xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xStyles;
+ lcl_linenumberingHeaderFooter( xStyles, "Header", this );
+ lcl_linenumberingHeaderFooter( xStyles, "Footer", this );
+}
+
+
+void DomainMapper_Impl::SetPageMarginTwip( PageMarElement eElement, sal_Int32 nValue )
+{
+ nValue = ConversionHelper::convertTwipToMM100(nValue);
+ switch(eElement)
+ {
+ case PAGE_MAR_TOP : m_aPageMargins.top = nValue; break;
+ case PAGE_MAR_RIGHT : m_aPageMargins.right = nValue; break;
+ case PAGE_MAR_BOTTOM : m_aPageMargins.bottom = nValue; break;
+ case PAGE_MAR_LEFT : m_aPageMargins.left = nValue; break;
+ case PAGE_MAR_HEADER : m_aPageMargins.header = nValue; break;
+ case PAGE_MAR_FOOTER : m_aPageMargins.footer = nValue; break;
+ case PAGE_MAR_GUTTER:
+ m_aPageMargins.gutter = nValue;
+ break;
+ }
+}
+
+void DomainMapper_Impl::SetPaperSource(PaperSourceElement eElement, sal_Int32 nValue)
+{
+ if(eElement == PAPER_SOURCE_FIRST)
+ m_aPaperSource.first = nValue;
+ else
+ m_aPaperSource.other = nValue;
+}
+
+
+PageMar::PageMar()
+ : top(ConversionHelper::convertTwipToMM100( sal_Int32(1440)))
+ // This is strange, the RTF spec says it's 1800, but it's clearly 1440 in Word
+ // OOXML seems not to specify a default value
+ , right(ConversionHelper::convertTwipToMM100( sal_Int32(1440)))
+ , bottom(top)
+ , left(right)
+ , header(ConversionHelper::convertTwipToMM100(sal_Int32(720)))
+ , footer(header)
+ , gutter(0)
+{
+}
+
+
+void DomainMapper_Impl::RegisterFrameConversion(
+ uno::Reference< text::XTextRange > const& xFrameStartRange,
+ uno::Reference< text::XTextRange > const& xFrameEndRange,
+ std::vector<beans::PropertyValue>&& rFrameProperties
+ )
+{
+ OSL_ENSURE(
+ m_aFrameProperties.empty() && !m_xFrameStartRange.is() && !m_xFrameEndRange.is(),
+ "frame properties not removed");
+ m_aFrameProperties = std::move(rFrameProperties);
+ m_xFrameStartRange = xFrameStartRange;
+ m_xFrameEndRange = xFrameEndRange;
+}
+
+
+void DomainMapper_Impl::ExecuteFrameConversion()
+{
+ if( m_xFrameStartRange.is() && m_xFrameEndRange.is() && !m_bDiscardHeaderFooter )
+ {
+ std::vector<sal_Int32> redPos, redLen;
+ try
+ {
+ uno::Reference< text::XTextAppendAndConvert > xTextAppendAndConvert( GetTopTextAppend(), uno::UNO_QUERY_THROW );
+ // convert redline ranges to cursor movement and character length
+ sal_Int32 redIdx;
+ lcl_CopyRedlines(GetTopTextAppend(), m_aStoredRedlines[StoredRedlines::FRAME], redPos, redLen, redIdx);
+
+ const uno::Reference< text::XTextContent >& xTextContent = xTextAppendAndConvert->convertToTextFrame(
+ m_xFrameStartRange,
+ m_xFrameEndRange,
+ comphelper::containerToSequence(m_aFrameProperties) );
+
+ uno::Reference< text::XText > xDest( xTextContent, uno::UNO_QUERY_THROW );
+ lcl_PasteRedlines(xDest, m_aStoredRedlines[StoredRedlines::FRAME], redPos, redLen, redIdx);
+ }
+ catch( const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION( "writerfilter.dmapper", "Exception caught when converting to frame");
+ }
+
+ m_bIsActualParagraphFramed = false;
+
+ if (redPos.size() == m_aStoredRedlines[StoredRedlines::FRAME].size()/3)
+ {
+ for( sal_Int32 i = m_aStoredRedlines[StoredRedlines::FRAME].size() - 1; i >= 0; --i)
+ {
+ // keep redlines of floating tables to process them in CloseSectionGroup()
+ if ( redPos[i/3] != -1 )
+ {
+ m_aStoredRedlines[StoredRedlines::FRAME].erase(m_aStoredRedlines[StoredRedlines::FRAME].begin() + i);
+ }
+ }
+ }
+ else
+ m_aStoredRedlines[StoredRedlines::FRAME].clear();
+ }
+ m_xFrameStartRange = nullptr;
+ m_xFrameEndRange = nullptr;
+ m_aFrameProperties.clear();
+}
+
+void DomainMapper_Impl::AddNewRedline( sal_uInt32 sprmId )
+{
+ RedlineParamsPtr pNew( new RedlineParams );
+ pNew->m_nToken = XML_mod;
+ if ( !m_bIsParaMarkerChange )
+ {
+ // <w:rPrChange> applies to the whole <w:r>, <w:pPrChange> applies to the whole <w:p>,
+ // so keep those two in CONTEXT_CHARACTERS and CONTEXT_PARAGRAPH, which will take
+ // care of their scope (i.e. when they should be used and discarded).
+ // Let's keep the rest the same way they used to be handled (explicitly dropped
+ // from a global stack by endtrackchange), but quite possibly they should not be handled
+ // that way either (I don't know).
+ if( sprmId == NS_ooxml::LN_EG_RPrContent_rPrChange )
+ GetTopContextOfType( CONTEXT_CHARACTER )->Redlines().push_back( pNew );
+ else if( sprmId == NS_ooxml::LN_CT_PPr_pPrChange )
+ GetTopContextOfType( CONTEXT_PARAGRAPH )->Redlines().push_back( pNew );
+ else if( sprmId != NS_ooxml::LN_CT_ParaRPr_rPrChange )
+ m_aRedlines.top().push_back( pNew );
+ }
+ else
+ {
+ m_pParaMarkerRedline = pNew;
+ }
+ // Newly read data will go into this redline.
+ m_currentRedline = pNew;
+}
+
+void DomainMapper_Impl::SetCurrentRedlineIsRead()
+{
+ m_currentRedline.clear();
+}
+
+sal_Int32 DomainMapper_Impl::GetCurrentRedlineToken( ) const
+{
+ assert(m_currentRedline);
+ return m_currentRedline->m_nToken;
+}
+
+void DomainMapper_Impl::SetCurrentRedlineAuthor( const OUString& sAuthor )
+{
+ if (!m_xAnnotationField.is())
+ {
+ if (m_currentRedline)
+ m_currentRedline->m_sAuthor = sAuthor;
+ else
+ SAL_INFO("writerfilter.dmapper", "numberingChange not implemented");
+ }
+ else
+ m_xAnnotationField->setPropertyValue("Author", uno::Any(sAuthor));
+}
+
+void DomainMapper_Impl::SetCurrentRedlineInitials( const OUString& sInitials )
+{
+ if (m_xAnnotationField.is())
+ m_xAnnotationField->setPropertyValue("Initials", uno::Any(sInitials));
+}
+
+void DomainMapper_Impl::SetCurrentRedlineDate( const OUString& sDate )
+{
+ if (!m_xAnnotationField.is())
+ {
+ if (m_currentRedline)
+ m_currentRedline->m_sDate = sDate;
+ else
+ SAL_INFO("writerfilter.dmapper", "numberingChange not implemented");
+ }
+ else
+ m_xAnnotationField->setPropertyValue("DateTimeValue", uno::Any(ConversionHelper::ConvertDateStringToDateTime(sDate)));
+}
+
+void DomainMapper_Impl::SetCurrentRedlineId( sal_Int32 sId )
+{
+ if (m_xAnnotationField.is())
+ {
+ m_nAnnotationId = sId;
+ }
+ else
+ {
+ // This should be an assert, but somebody had the smart idea to reuse this function also for comments and whatnot,
+ // and in some cases the id is actually not handled, which may be in fact a bug.
+ if( !m_currentRedline)
+ SAL_INFO("writerfilter.dmapper", "no current redline");
+ }
+}
+
+void DomainMapper_Impl::SetCurrentRedlineToken( sal_Int32 nToken )
+{
+ assert(m_currentRedline);
+ m_currentRedline->m_nToken = nToken;
+}
+
+void DomainMapper_Impl::SetCurrentRedlineRevertProperties( const uno::Sequence<beans::PropertyValue>& aProperties )
+{
+ assert(m_currentRedline);
+ m_currentRedline->m_aRevertProperties = aProperties;
+}
+
+
+// This removes only the last redline stored here, those stored in contexts are automatically removed when
+// the context is destroyed.
+void DomainMapper_Impl::RemoveTopRedline( )
+{
+ if (m_aRedlines.top().empty())
+ {
+ if (GetFootnoteCount() > -1 || GetEndnoteCount() > -1)
+ return;
+ SAL_WARN("writerfilter.dmapper", "RemoveTopRedline called with empty stack");
+ throw uno::Exception("RemoveTopRedline failed", nullptr);
+ }
+ m_aRedlines.top().pop_back( );
+ m_currentRedline.clear();
+}
+
+void DomainMapper_Impl::ApplySettingsTable()
+{
+ if (!(m_pSettingsTable && m_xTextFactory.is()))
+ return;
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xTextDefaults(m_xTextFactory->createInstance("com.sun.star.text.Defaults"), uno::UNO_QUERY_THROW );
+ sal_Int32 nDefTab = m_pSettingsTable->GetDefaultTabStop();
+ xTextDefaults->setPropertyValue( getPropertyName( PROP_TAB_STOP_DISTANCE ), uno::Any(nDefTab) );
+ if (m_pSettingsTable->GetLinkStyles())
+ {
+ // If linked styles are enabled, set paragraph defaults from Word's default template
+ xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_BOTTOM_MARGIN), uno::Any(ConversionHelper::convertTwipToMM100(200)));
+ style::LineSpacing aSpacing;
+ aSpacing.Mode = style::LineSpacingMode::PROP;
+ aSpacing.Height = sal_Int16(115);
+ xTextDefaults->setPropertyValue(getPropertyName(PROP_PARA_LINE_SPACING), uno::Any(aSpacing));
+ }
+
+ if (m_pSettingsTable->GetZoomFactor() || m_pSettingsTable->GetView())
+ {
+ std::vector<beans::PropertyValue> aViewProps;
+ if (m_pSettingsTable->GetZoomFactor())
+ {
+ aViewProps.emplace_back("ZoomFactor", -1, uno::Any(m_pSettingsTable->GetZoomFactor()), beans::PropertyState_DIRECT_VALUE);
+ aViewProps.emplace_back("VisibleBottom", -1, uno::Any(sal_Int32(0)), beans::PropertyState_DIRECT_VALUE);
+ aViewProps.emplace_back("ZoomType", -1,
+ uno::Any(m_pSettingsTable->GetZoomType()),
+ beans::PropertyState_DIRECT_VALUE);
+ }
+ rtl::Reference< comphelper::IndexedPropertyValuesContainer > xBox = new comphelper::IndexedPropertyValuesContainer();
+ xBox->insertByIndex(sal_Int32(0), uno::Any(comphelper::containerToSequence(aViewProps)));
+ uno::Reference<document::XViewDataSupplier> xViewDataSupplier(m_xTextDocument, uno::UNO_QUERY);
+ xViewDataSupplier->setViewData(xBox);
+ }
+
+ uno::Reference< beans::XPropertySet > xSettings(m_xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+
+ if (m_pSettingsTable->GetDoNotExpandShiftReturn())
+ xSettings->setPropertyValue( "DoNotJustifyLinesWithManualBreak", uno::Any(true) );
+ // new paragraph justification has been introduced in version 15,
+ // breaking text layout interoperability: new line shrinking needs less space
+ // i.e. it typesets the same text with less lines and pages.
+ if (m_pSettingsTable->GetWordCompatibilityMode() >= 15)
+ xSettings->setPropertyValue("JustifyLinesWithShrinking", uno::Any( true ));
+ if (m_pSettingsTable->GetUsePrinterMetrics())
+ xSettings->setPropertyValue("PrinterIndependentLayout", uno::Any(document::PrinterIndependentLayout::DISABLED));
+ if( m_pSettingsTable->GetEmbedTrueTypeFonts())
+ xSettings->setPropertyValue( getPropertyName( PROP_EMBED_FONTS ), uno::Any(true) );
+ if( m_pSettingsTable->GetEmbedSystemFonts())
+ xSettings->setPropertyValue( getPropertyName( PROP_EMBED_SYSTEM_FONTS ), uno::Any(true) );
+ xSettings->setPropertyValue("AddParaTableSpacing", uno::Any(m_pSettingsTable->GetDoNotUseHTMLParagraphAutoSpacing()));
+ if (m_pSettingsTable->GetNoLeading())
+ {
+ xSettings->setPropertyValue("AddExternalLeading", uno::Any(!m_pSettingsTable->GetNoLeading()));
+ }
+ if( m_pSettingsTable->GetProtectForm() )
+ xSettings->setPropertyValue("ProtectForm", uno::Any( true ));
+ if( m_pSettingsTable->GetReadOnly() )
+ xSettings->setPropertyValue("LoadReadonly", uno::Any( true ));
+ if (m_pSettingsTable->GetGutterAtTop())
+ {
+ xSettings->setPropertyValue("GutterAtTop", uno::Any(true));
+ }
+ uno::Sequence<beans::PropertyValue> aWriteProtection
+ = m_pSettingsTable->GetWriteProtectionSettings();
+ if (aWriteProtection.hasElements())
+ xSettings->setPropertyValue("ModifyPasswordInfo", uno::Any(aWriteProtection));
+ }
+ catch(const uno::Exception&)
+ {
+ }
+}
+
+SectionPropertyMap * DomainMapper_Impl::GetSectionContext()
+{
+ SectionPropertyMap* pSectionContext = nullptr;
+ //the section context is not available before the first call of startSectionGroup()
+ if( !IsAnyTableImport() )
+ {
+ PropertyMapPtr pContext = GetTopContextOfType(CONTEXT_SECTION);
+ pSectionContext = dynamic_cast< SectionPropertyMap* >( pContext.get() );
+ }
+
+ return pSectionContext;
+}
+
+void DomainMapper_Impl::deferCharacterProperty(sal_Int32 id, const css::uno::Any& value)
+{
+ m_StreamStateStack.top().deferredCharacterProperties[ id ] = value;
+}
+
+void DomainMapper_Impl::processDeferredCharacterProperties(bool bCharContext)
+{
+ // Actually process in DomainMapper, so that it's the same source file like normal processing.
+ if (!m_StreamStateStack.top().deferredCharacterProperties.empty())
+ {
+ m_rDMapper.processDeferredCharacterProperties(m_StreamStateStack.top().deferredCharacterProperties, bCharContext);
+ m_StreamStateStack.top().deferredCharacterProperties.clear();
+ }
+}
+
+sal_Int32 DomainMapper_Impl::getNumberingProperty(const sal_Int32 nListId, sal_Int32 nNumberingLevel, const OUString& aProp)
+{
+ sal_Int32 nRet = 0;
+ if ( nListId < 0 )
+ return nRet;
+
+ try
+ {
+ if (nNumberingLevel < 0) // It seems it's valid to omit numbering level, and in that case it means zero.
+ nNumberingLevel = 0;
+
+ auto const pList(GetListTable()->GetList(nListId));
+ assert(pList);
+ const OUString aListName = pList->GetStyleName();
+ const uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(GetTextDocument(), uno::UNO_QUERY_THROW);
+ const uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xNumberingStyles;
+ xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles;
+ const uno::Reference<beans::XPropertySet> xStyle(xNumberingStyles->getByName(aListName), uno::UNO_QUERY);
+ const uno::Reference<container::XIndexAccess> xNumberingRules(xStyle->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
+ if (xNumberingRules.is())
+ {
+ uno::Sequence<beans::PropertyValue> aProps;
+ xNumberingRules->getByIndex(nNumberingLevel) >>= aProps;
+ auto pProp = std::find_if(std::cbegin(aProps), std::cend(aProps),
+ [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; });
+ if (pProp != std::cend(aProps))
+ pProp->Value >>= nRet;
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ // This can happen when the doc contains some hand-crafted invalid list level.
+ }
+
+ return nRet;
+}
+
+sal_Int32 DomainMapper_Impl::getCurrentNumberingProperty(const OUString& aProp)
+{
+ sal_Int32 nRet = 0;
+
+ std::optional<PropertyMap::Property> pProp = m_pTopContext->getProperty(PROP_NUMBERING_RULES);
+ uno::Reference<container::XIndexAccess> xNumberingRules;
+ if (pProp)
+ xNumberingRules.set(pProp->second, uno::UNO_QUERY);
+ pProp = m_pTopContext->getProperty(PROP_NUMBERING_LEVEL);
+ // Default numbering level is the first one.
+ sal_Int32 nNumberingLevel = 0;
+ if (pProp)
+ pProp->second >>= nNumberingLevel;
+ if (xNumberingRules.is())
+ {
+ uno::Sequence<beans::PropertyValue> aProps;
+ xNumberingRules->getByIndex(nNumberingLevel) >>= aProps;
+ auto pPropVal = std::find_if(std::cbegin(aProps), std::cend(aProps),
+ [&aProp](const beans::PropertyValue& rProp) { return rProp.Name == aProp; });
+ if (pPropVal != std::cend(aProps))
+ pPropVal->Value >>= nRet;
+ }
+
+ return nRet;
+}
+
+
+void DomainMapper_Impl::enableInteropGrabBag(const OUString& aName)
+{
+ m_aInteropGrabBagName = aName;
+}
+
+void DomainMapper_Impl::disableInteropGrabBag()
+{
+ m_aInteropGrabBagName.clear();
+ m_aInteropGrabBag.clear();
+ m_aSubInteropGrabBag.clear();
+}
+
+bool DomainMapper_Impl::isInteropGrabBagEnabled() const
+{
+ return !(m_aInteropGrabBagName.isEmpty());
+}
+
+void DomainMapper_Impl::appendGrabBag(std::vector<beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, const OUString& aValue)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ rInteropGrabBag.push_back(aProperty);
+}
+
+void DomainMapper_Impl::appendGrabBag(std::vector<beans::PropertyValue>& rInteropGrabBag, const OUString& aKey, std::vector<beans::PropertyValue>& rValue)
+{
+ if (m_aInteropGrabBagName.isEmpty())
+ return;
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= comphelper::containerToSequence(rValue);
+ rValue.clear();
+ rInteropGrabBag.push_back(aProperty);
+}
+
+void DomainMapper_Impl::substream(Id rName,
+ ::writerfilter::Reference<Stream>::Pointer_t const& ref)
+{
+#ifndef NDEBUG
+ size_t contextSize(m_aContextStack.size());
+ size_t propSize[NUMBER_OF_CONTEXTS];
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; ++i) {
+ propSize[i] = m_aPropertyStacks[i].size();
+ }
+#endif
+
+ //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();
+
+ // Save "has footnote" state, which is specific to a section in the body
+ // text, so state from substreams is not relevant.
+ m_StreamStateStack.emplace();
+
+ //import of page header/footer
+ //Ensure that only one header/footer per section is pushed
+
+ switch( rName )
+ {
+ case NS_ooxml::LN_headerl:
+ PushPageHeaderFooter(PagePartType::Header, PageType::LEFT);
+ break;
+ case NS_ooxml::LN_headerr:
+ PushPageHeaderFooter(PagePartType::Header, PageType::RIGHT);
+ break;
+ case NS_ooxml::LN_headerf:
+ PushPageHeaderFooter(PagePartType::Header, PageType::FIRST);
+ break;
+ case NS_ooxml::LN_footerl:
+ PushPageHeaderFooter(PagePartType::Footer, PageType::LEFT);
+ break;
+ case NS_ooxml::LN_footerr:
+ PushPageHeaderFooter(PagePartType::Footer, PageType::RIGHT);
+ break;
+ case NS_ooxml::LN_footerf:
+ PushPageHeaderFooter(PagePartType::Footer, PageType::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;
+ default:
+ assert(false); // unexpected?
+ }
+
+ assert(m_StreamStateStack.top().eSubstreamType != SubstreamType::Body);
+
+ try
+ {
+ ref->resolve(m_rDMapper);
+ }
+ catch (xml::sax::SAXException const&)
+ {
+ m_bSaxError = true;
+ throw;
+ }
+
+ switch( rName )
+ {
+ case NS_ooxml::LN_headerl:
+ PopPageHeaderFooter(PagePartType::Header, PageType::LEFT);
+ break;
+ case NS_ooxml::LN_footerl:
+ PopPageHeaderFooter(PagePartType::Footer, PageType::LEFT);
+ break;
+ case NS_ooxml::LN_headerr:
+ PopPageHeaderFooter(PagePartType::Header, PageType::RIGHT);
+ break;
+ case NS_ooxml::LN_footerr:
+ PopPageHeaderFooter(PagePartType::Footer, PageType::RIGHT);
+ break;
+ case NS_ooxml::LN_headerf:
+ PopPageHeaderFooter(PagePartType::Header, PageType::FIRST);
+ break;
+ case NS_ooxml::LN_footerf:
+ PopPageHeaderFooter(PagePartType::Footer, PageType::FIRST);
+ break;
+ case NS_ooxml::LN_footnote:
+ case NS_ooxml::LN_endnote:
+ PopFootOrEndnote();
+ break;
+ case NS_ooxml::LN_annotation :
+ PopAnnotation();
+ break;
+ }
+
+ m_StreamStateStack.pop();
+ assert(!m_StreamStateStack.empty());
+
+ getTableManager().endLevel();
+ popTableManager();
+
+ switch(rName)
+ {
+ case NS_ooxml::LN_footnote:
+ case NS_ooxml::LN_endnote:
+ m_StreamStateStack.top().bHasFtn = true;
+ break;
+ }
+
+ // check that stacks are the same as before substream
+ assert(m_aContextStack.size() == contextSize);
+ for (int i = 0; i < NUMBER_OF_CONTEXTS; ++i) {
+ assert(m_aPropertyStacks[i].size() == propSize[i]);
+ }
+}
+
+void DomainMapper_Impl::commentProps(const OUString& sId, const CommentProperties& rProps)
+{
+ m_aCommentProps[sId] = rProps;
+}
+
+
+bool DomainMapper_Impl::handlePreviousParagraphBorderInBetween() const
+{
+ if (!m_StreamStateStack.top().xPreviousParagraph.is())
+ return false;
+
+ // Connected borders ("ParaIsConnectBorder") are always on by default
+ // and never changed by DomainMapper. Except one case when border in
+ // between is used. So this is not the best, but easiest way to check
+ // is previous paragraph has border in between.
+ bool bConnectBorders = true;
+ m_StreamStateStack.top().xPreviousParagraph->getPropertyValue(getPropertyName(PROP_PARA_CONNECT_BORDERS)) >>= bConnectBorders;
+
+ if (bConnectBorders)
+ return false;
+
+ // Previous paragraph has border in between. Current one also has (since this
+ // method is called). So current paragraph will get border above, but
+ // also need to ensure, that no unexpected bottom border are remaining in previous
+ // paragraph: since ParaIsConnectBorder=false it will be displayed in unexpected way.
+ m_StreamStateStack.top().xPreviousParagraph->setPropertyValue(getPropertyName(PROP_BOTTOM_BORDER), uno::Any(table::BorderLine2()));
+
+ return true;
+}
+
+OUString DomainMapper_Impl::getFontNameForTheme(const Id id)
+{
+ auto const& pHandler = getThemeHandler();
+ if (pHandler)
+ return pHandler->getFontNameForTheme(id);
+ return OUString();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
new file mode 100644
index 000000000000..94ab42de3f98
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/DomainMapper_Impl.hxx
@@ -0,0 +1,1258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/text/XParagraphCursor.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/XTextAppend.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
+#include <com/sun/star/style/TabStop.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <queue>
+#include <stack>
+#include <string_view>
+#include <o3tl/sorted_vector.hxx>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <ooxml/OOXMLDocument.hxx>
+
+#include <dmapper/CommentProperties.hxx>
+
+#include "DomainMapper.hxx"
+#include "DomainMapperTableManager.hxx"
+#include "DomainMapperTableHandler.hxx"
+#include "PropertyMap.hxx"
+#include "FontTable.hxx"
+#include "NumberingManager.hxx"
+#include "StyleSheetTable.hxx"
+#include "SettingsTable.hxx"
+#include "ThemeHandler.hxx"
+#include "GraphicImport.hxx"
+#include "OLEHandler.hxx"
+#include "FFDataHandler.hxx"
+#include "SmartTagHandler.hxx"
+#include "FormControlHelper.hxx"
+#include <map>
+
+namespace com::sun::star{
+ namespace awt{
+ struct Size;
+ }
+ namespace lang{
+ class XMultiServiceFactory;
+ struct Locale;
+ }
+ namespace text
+ {
+ class XTextField;
+ class XTextFrame;
+ class XFormField;
+ }
+ namespace beans{ class XPropertySet;}
+}
+
+namespace writerfilter::ooxml {
+ class OOXMLDocument;
+}
+
+namespace writerfilter::dmapper {
+
+class SdtHelper;
+
+struct PageMar
+{
+ sal_Int32 top;
+ sal_Int32 right;
+ sal_Int32 bottom;
+ sal_Int32 left;
+ sal_Int32 header;
+ sal_Int32 footer;
+ sal_Int32 gutter;
+ public:
+ PageMar();
+};
+enum PageMarElement
+{
+ PAGE_MAR_TOP,
+ PAGE_MAR_RIGHT,
+ PAGE_MAR_BOTTOM,
+ PAGE_MAR_LEFT,
+ PAGE_MAR_HEADER,
+ PAGE_MAR_FOOTER,
+ PAGE_MAR_GUTTER
+};
+
+struct PaperSource
+{
+ sal_Int32 first;
+ sal_Int32 other;
+ public:
+ PaperSource() :
+ first(0),
+ other(0)
+ {}
+};
+
+enum PaperSourceElement
+{
+ PAPER_SOURCE_FIRST,
+ PAPER_SOURCE_OTHER,
+};
+
+/// property stack element
+enum ContextType
+{
+ CONTEXT_SECTION,
+ CONTEXT_PARAGRAPH,
+ CONTEXT_CHARACTER,
+ CONTEXT_STYLESHEET,
+ CONTEXT_LIST
+};
+enum { NUMBER_OF_CONTEXTS = CONTEXT_LIST + 1 };
+
+enum BreakType
+{
+ PAGE_BREAK,
+ COLUMN_BREAK,
+ LINE_BREAK
+};
+
+/**
+ * Two special footnotes are a separator line, and a continuation line.
+ * In MSOffice, these can contain text as well, but LO doesn't implement this
+ * rarely used feature, so the separator text needs to be skipped. (tdf#123262)
+ * Three-way logic is needed because there is no guaranteed on-off event.
+ * OFF == not in footnote separator
+ * ON == in footnote separator
+ * SKIPPING == ON status has been recognized.
+ */
+enum class SkipFootnoteSeparator
+{
+ OFF,
+ ON,
+ SKIPPING
+};
+
+// type of stored redlines
+enum StoredRedlines
+{
+ FRAME = 0,
+ FOOTNOTE,
+ ENDNOTE,
+ NONE
+};
+
+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)
+ {
+ }
+};
+
+enum class SubstreamType
+{
+ Body,
+ Header,
+ Footer,
+ Footnote,
+ Endnote,
+ Annotation,
+};
+
+/**
+ * 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.
+ *
+ * note: presumably more state should be moved here.
+ */
+struct SubstreamContext
+{
+ SubstreamType eSubstreamType = SubstreamType::Body;
+ bool bTextInserted = false;
+ /**
+ * This contains the raw table depth. 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 nTableDepth = 0;
+ // deferred breaks need to be saved for RTF, also for DOCX annotations
+ bool bIsColumnBreakDeferred = false;
+ bool bIsPageBreakDeferred = false;
+ sal_Int32 nLineBreaksDeferred = 0;
+ /// Current paragraph had at least one field in it.
+ bool bParaHadField = false;
+ /// Current paragraph in a table is first paragraph of a cell
+ bool bFirstParagraphInCell = true;
+ /// If the current paragraph has any runs.
+ bool bParaChanged = false;
+ bool bIsFirstParaInSectionAfterRedline = true;
+ bool bIsFirstParaInSection = true;
+ bool bIsLastParaInSection = false;
+ /// If the current paragraph contains section property definitions.
+ bool bParaSectpr = false;
+ bool bIsPreviousParagraphFramed = false;
+ /// Current paragraph had at least one inline object in it.
+ bool bParaWithInlineObject = false;
+ /// This is a continuation of already finished paragraph - e.g., first in an index section
+ bool bRemoveThisParagraph = false;
+ bool bIsFirstParaInShape = false;
+ /// If the current section has footnotes.
+ bool bHasFtn = false;
+ css::uno::Reference<css::beans::XPropertySet> xPreviousParagraph;
+ /// Current paragraph has automatic before spacing.
+ bool bParaAutoBefore = false;
+ /// Raw table cell depth.
+ sal_Int32 nTableCellDepth = 0;
+ /// If the next tab should be ignored, used for footnotes.
+ bool bCheckFirstFootnoteTab = false;
+ std::optional<sal_Int16> oLineBreakClear;
+ bool bIsInTextBox = false;
+ css::uno::Reference<css::text::XTextContent> xEmbedded;
+ /// If we want to set "sdt end" on the next character context.
+ bool bSdtEndDeferred = false;
+ /// If we want to set "paragraph sdt end" on the next paragraph context.
+ bool bParaSdtEndDeferred = false;
+ /// If the current paragraph is inside a structured document element.
+ bool bSdt = false;
+ css::uno::Reference<css::text::XTextRange> xSdtEntryStart;
+ OUString sCurrentParaStyleName; ///< highly inaccurate. Overwritten by "overlapping" paragraphs like flys.
+ bool bHasFootnoteStyle = false;
+ bool bCheckFootnoteStyle = false;
+ bool bIsInFootnoteProperties = false;
+ RubyInfo aRubyInfo;
+ bool bTextFrameInserted = false;
+ bool bIsFirstRun = false;
+ bool bIsOutsideAParagraph = true;
+ std::map<sal_Int32, css::uno::Any> deferredCharacterProperties;
+};
+
+/// 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;
+
+ // Two command string:
+ // 0: Normal, inserted command line
+ // 1: Deleted command line
+ OUString m_sCommand[2];
+ OUString m_sResult;
+ OUString m_sVariableValue;
+ std::optional<FieldId> m_eFieldId;
+ bool m_bFieldLocked;
+ // Current command line type: normal or deleted
+ bool m_bCommandType;
+public:
+ bool m_bSetUserFieldContent = false;
+ bool m_bSetCitation = false;
+ bool m_bSetDateValue = false;
+private:
+
+ 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;
+ OUString m_sHyperlinkStyle;
+
+ 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> xStart);
+ ~FieldContext() override;
+
+ const css::uno::Reference<css::text::XTextRange>& GetStartRange() const { return m_xStartRange; }
+
+ void AppendCommand(std::u16string_view rPart);
+ const OUString& GetCommand() const {return m_sCommand[m_bCommandType]; }
+ bool GetCommandIsEmpty(bool bType) const { return m_sCommand[bType].isEmpty(); }
+ void SetCommandType(bool cType) { m_bCommandType = cType; }
+
+ void SetFieldId(FieldId eFieldId ) { m_eFieldId = eFieldId; }
+ std::optional<FieldId> const & GetFieldId() const { return m_eFieldId; }
+
+ void AppendResult(std::u16string_view rResult) { m_sResult += rResult; }
+ const OUString& GetResult() const { return m_sResult; }
+
+ void CacheVariableValue(const css::uno::Any& rAny);
+ const OUString& GetVariableValue() { return m_sVariableValue; }
+
+ void SetCommandCompleted() { m_bFieldCommandCompleted = true; }
+ bool IsCommandCompleted() const { return m_bFieldCommandCompleted; }
+
+ void SetFieldLocked() { m_bFieldLocked = true; }
+ bool IsFieldLocked() const { return m_bFieldLocked; }
+
+ const css::uno::Reference<css::beans::XPropertySet>& GetCustomField() const { return m_xCustomField; }
+ void SetCustomField(css::uno::Reference<css::beans::XPropertySet> const& xCustomField) { m_xCustomField = xCustomField; }
+ const css::uno::Reference<css::text::XTextField>& GetTextField() const { return m_xTextField;}
+ void SetTextField(css::uno::Reference<css::text::XTextField> const& xTextField);
+ const css::uno::Reference<css::text::XFormField>& GetFormField() const { return m_xFormField;}
+ void SetFormField(css::uno::Reference<css::text::XFormField> const& xFormField) { m_xFormField = xFormField;}
+
+ void SetTOC(css::uno::Reference<css::beans::XPropertySet> const& xTOC) { m_xTOC = xTOC; }
+ const css::uno::Reference<css::beans::XPropertySet>& GetTOC() const { return m_xTOC; }
+
+ void SetTC(css::uno::Reference<css::beans::XPropertySet> const& xTC) { m_xTC = xTC; }
+ const css::uno::Reference<css::beans::XPropertySet>& GetTC() const { return m_xTC; }
+
+ void SetHyperlinkURL( const OUString& rURL ) { m_sHyperlinkURL = rURL; }
+ const OUString& GetHyperlinkURL() const { return m_sHyperlinkURL; }
+ void SetHyperlinkTarget(const OUString& rTarget) { m_sHyperlinkTarget = rTarget; }
+ const OUString& GetHyperlinkTarget() const { return m_sHyperlinkTarget; }
+ void SetHyperlinkStyle(const OUString& rStyle) { m_sHyperlinkStyle = rStyle; }
+ const OUString& GetHyperlinkStyle() const { return m_sHyperlinkStyle; }
+
+ void setFFDataHandler(const FFDataHandler::Pointer_t& pFFDataHandler) { m_pFFDataHandler = pFFDataHandler; }
+ const FFDataHandler::Pointer_t& getFFDataHandler() const { return m_pFFDataHandler; }
+
+ void setFormControlHelper(const 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 AnchoredContext
+{
+ css::uno::Reference<css::text::XTextContent> xTextContent;
+ bool bToRemove;
+
+ explicit AnchoredContext(css::uno::Reference<css::text::XTextContent> xContent)
+ : xTextContent(std::move(xContent)), bToRemove(false)
+ {
+ }
+};
+
+typedef tools::SvRef<FieldContext> FieldContextPtr;
+
+/*-------------------------------------------------------------------------
+ extended tab stop struct
+ -----------------------------------------------------------------------*/
+struct DeletableTabStop : public css::style::TabStop
+{
+ bool bDeleted;
+ explicit DeletableTabStop()
+ : bDeleted(false)
+ {
+ FillChar = ' '; // same default as SvxXMLTabStopContext_Impl
+ }
+ DeletableTabStop(const css::style::TabStop& rTabStop)
+ : TabStop(rTabStop),
+ bDeleted(false)
+ {
+ }
+};
+/// helper to remember bookmark start position
+struct BookmarkInsertPosition
+{
+ bool m_bIsStartOfText;
+ OUString m_sBookmarkName;
+ css::uno::Reference<css::text::XTextRange> m_xTextRange;
+ BookmarkInsertPosition(bool bIsStartOfText, OUString rName, css::uno::Reference<css::text::XTextRange> xTextRange):
+ m_bIsStartOfText( bIsStartOfText ),
+ m_sBookmarkName(std::move( rName )),
+ m_xTextRange(std::move( 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, OUString ed, OUString edGrp, css::uno::Reference<css::text::XTextRange> xTextRange)
+ : m_bIsStartOfText(bIsStartOfText)
+ , m_Id(id)
+ , m_Ed(std::move(ed))
+ , m_EdGrp(std::move(edGrp))
+ , m_xTextRange(std::move(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 LineNumberSettings
+{
+ sal_Int32 nDistance;
+ sal_Int32 nInterval;
+ bool bRestartAtEachPage;
+ LineNumberSettings() :
+ nDistance(-1)
+ ,nInterval(0)
+ ,bRestartAtEachPage(true)
+ {}
+
+};
+
+/// Stores original/in-file-format info about a single anchored object.
+struct AnchoredObjectInfo
+{
+ css::uno::Reference<css::text::XTextContent> m_xAnchoredObject;
+ sal_Int32 m_nLeftMargin = 0;
+ RedlineParamsPtr m_xRedlineForInline;
+};
+
+/// Stores info about objects anchored to a given paragraph.
+struct AnchoredObjectsInfo
+{
+ css::uno::Reference<css::text::XTextRange> m_xParagraph;
+ std::vector<AnchoredObjectInfo> m_aAnchoredObjects;
+};
+
+struct TextAppendContext
+{
+ css::uno::Reference<css::text::XTextAppend> xTextAppend;
+ css::uno::Reference<css::text::XParagraphCursor> xCursor;
+ css::uno::Reference<css::text::XTextRange> xInsertPosition;
+ ParagraphPropertiesPtr pLastParagraphProperties;
+
+ /**
+ * Objects anchored to the current paragraph, may affect the paragraph
+ * spacing.
+ */
+ std::vector<AnchoredObjectInfo> m_aAnchoredObjects;
+
+ TextAppendContext(css::uno::Reference<css::text::XTextAppend> const& i_xAppend,
+ css::uno::Reference<css::text::XTextCursor> const& i_xCursor)
+ : xTextAppend(i_xAppend)
+ , xCursor(i_xCursor, css::uno::UNO_QUERY)
+ , xInsertPosition(xCursor)
+ {}
+};
+
+struct SymbolData
+{
+ sal_Unicode cSymbol;
+ OUString sFont;
+ SymbolData():
+ cSymbol(),
+ sFont()
+ { }
+};
+
+class DomainMapper;
+class DomainMapper_Impl final
+{
+public:
+ typedef std::map < OUString, BookmarkInsertPosition > BookmarkMap_t;
+ typedef std::map < sal_Int32, PermInsertPosition > PermMap_t;
+
+private:
+ SourceDocumentType m_eDocumentType;
+ DomainMapper& m_rDMapper;
+ writerfilter::ooxml::OOXMLDocument* m_pOOXMLDocument;
+ OUString m_aBaseUrl;
+ css::uno::Reference<css::text::XTextDocument> m_xTextDocument;
+ css::uno::Reference<css::beans::XPropertySet> m_xDocumentSettings;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xTextFactory;
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+ css::uno::Reference<css::container::XNameContainer> m_xPageStyles1;
+ // cache next available number, expensive to repeatedly compute
+ std::optional<int> m_xNextUnusedPageStyleNo;
+ css::uno::Reference<css::container::XNameContainer> m_xCharacterStyles;
+ css::uno::Reference<css::container::XNameContainer> m_xParagraphStyles;
+
+ // cache next available number, expensive to repeatedly compute
+ std::optional<int> m_xNextUnusedCharacterStyleNo;
+ css::uno::Reference<css::text::XText> m_xBodyText;
+
+ std::stack<TextAppendContext> m_aTextAppendStack;
+ std::stack<AnchoredContext> m_aAnchoredStack;
+public: // DomainMapper needs it
+ std::stack<SubstreamContext> m_StreamStateStack;
+private:
+ std::stack<std::pair<TextAppendContext, PagePartType>> m_aHeaderFooterTextAppendStack;
+
+ std::deque<FieldContextPtr> m_aFieldStack;
+ bool m_bForceGenericFields;
+ /// Type of decimal symbol associated to the document language in Writer locale definition
+ bool m_bIsDecimalComma;
+ bool m_bIsFirstSection;
+ 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_bTextDeleted;
+ LineNumberSettings m_aLineNumberSettings;
+
+ std::vector<OUString> m_aRedlineMoveIDs;
+ // Remember the last used redline MoveID. To avoid regression, because of wrong docx export
+ sal_uInt32 m_nLastRedlineMovedID;
+
+ BookmarkMap_t m_aBookmarkMap;
+ OUString m_sCurrentBkmkId;
+ OUString m_sCurrentBkmkName;
+ OUString m_sCurrentBkmkPrefix;
+
+ PermMap_t m_aPermMap;
+ sal_Int32 m_sCurrentPermId;
+ OUString m_sCurrentPermEd;
+ OUString m_sCurrentPermEdGrp;
+
+ PageMar m_aPageMargins;
+ PaperSource m_aPaperSource;
+ SymbolData m_aSymbolData;
+
+ // TableManagers are stacked: one for each stream to avoid any confusion
+ std::stack< tools::SvRef< DomainMapperTableManager > > m_aTableManagers;
+ tools::SvRef<DomainMapperTableHandler> m_pTableHandler;
+ // List of document lists overrides. They are applied only once on first occurrence in document
+ o3tl::sorted_vector<sal_Int32> m_aListOverrideApplied;
+
+ //each context needs a stack of currently used attributes
+ std::stack<PropertyMapPtr> m_aPropertyStacks[NUMBER_OF_CONTEXTS];
+ std::stack<ContextType> m_aContextStack;
+ std::queue<std::optional<sal_Int16>> m_aFrameDirectionQueue;
+ bool m_bFrameDirectionSet;
+ FontTablePtr m_pFontTable;
+ ListsManager::Pointer m_pListTable;
+ std::deque< css::uno::Reference<css::drawing::XShape> > m_aPendingShapes;
+ StyleSheetTablePtr m_pStyleSheetTable;
+ SettingsTablePtr m_pSettingsTable;
+ GraphicImportPtr m_pGraphicImport;
+
+ std::unique_ptr<ThemeHandler> m_pThemeHandler;
+
+ PropertyMapPtr m_pTopContext;
+ tools::SvRef<SectionPropertyMap> m_pLastSectionContext;
+ PropertyMapPtr m_pLastCharacterContext;
+
+ ::std::vector<DeletableTabStop> m_aCurrentTabStops;
+ OUString m_sDefaultParaStyleName; //caches the ConvertedStyleName of the default paragraph style
+ bool m_bInDocDefaultsImport;
+ bool m_bInStyleSheetImport; //in import of fonts, styles, lists or lfos
+ bool m_bInNumberingImport; //in import of numbering (i.e. numbering.xml)
+ bool m_bInAnyTableImport; //in import of fonts, styles, lists or lfos
+ bool m_bDiscardHeaderFooter;
+ PropertyMapPtr m_pFootnoteContext;
+ /// Skip paragraphs from the <w:separator/> footnote
+ SkipFootnoteSeparator m_eSkipFootnoteState;
+ /// preload footnotes and endnotes
+ sal_Int32 m_nFootnotes; // footnote count
+ sal_Int32 m_nEndnotes; // endnote count
+ // these are the real first notes, use their content in the first notes
+ sal_Int32 m_nFirstFootnoteIndex;
+ sal_Int32 m_nFirstEndnoteIndex;
+
+ bool m_bLineNumberingSet;
+
+ //registered frame properties
+ std::vector<css::beans::PropertyValue> m_aFrameProperties;
+ css::uno::Reference<css::text::XTextRange> m_xFrameStartRange;
+ css::uno::Reference<css::text::XTextRange> m_xFrameEndRange;
+
+ // Redline stack
+ std::stack< std::vector< RedlineParamsPtr > > m_aRedlines;
+ // The redline currently read, may be also stored by a context instead of m_aRedlines.
+ RedlineParamsPtr m_currentRedline;
+ RedlineParamsPtr m_previousRedline;
+ RedlineParamsPtr m_pParaMarkerRedline;
+ bool m_bIsParaMarkerChange;
+ bool m_bIsParaMarkerMove;
+ // redline data of the terminating run, if it's a moveFrom deletion or a moveTo insertion
+ RedlineParamsPtr m_pParaMarkerRedlineMove;
+ // This is for removing workaround (double ZWSPs around the anchoring point) for track
+ // changed images anchored *to* character, if it's followed by a redline text run immediately.
+ // (In that case, the image is part of a tracked text range, no need for the dummy
+ // text ZWSPs to keep the change tracking of the image in Writer.)
+ bool m_bRedlineImageInPreviousRun;
+
+ bool m_bDummyParaAddedForTableInSection;
+ bool m_bIsLastSectionGroup;
+ bool m_bUsingEnhancedFields;
+
+ css::uno::Reference< css::text::XTextCursor > m_xTOCMarkerCursor;
+
+ ::std::set<::std::pair<PagePartType, PageType>> m_HeaderFooterSeen;
+
+ //annotation import
+ css::uno::Reference< css::beans::XPropertySet > m_xAnnotationField;
+ sal_Int32 m_nAnnotationId;
+ bool m_bAnnotationResolved = false;
+ OUString m_sAnnotationParent;
+ OUString m_sAnnotationImportedParaId;
+ std::unordered_map< sal_Int32, AnnotationPosition > m_aAnnotationPositions;
+
+ void SetNumberFormat(const OUString& rCommand, css::uno::Reference<css::beans::XPropertySet> const& xPropertySet, bool bDetectFormat = false);
+ /// @throws css::uno::Exception
+ css::uno::Reference<css::beans::XPropertySet> FindOrCreateFieldMaster(const char* pFieldMasterService, const OUString& rFieldMasterName);
+ css::uno::Reference<css::beans::XPropertySet> const & GetDocumentSettings();
+
+ SmartTagHandler m_aSmartTagHandler;
+
+ css::uno::Reference<css::text::XTextRange> m_xGlossaryEntryStart;
+ std::stack<BookmarkInsertPosition> m_xSdtStarts;
+
+ std::queue< css::uno::Reference< css::text::XTextFrame > > m_xPendingTextBoxFrames;
+
+public:
+ css::uno::Reference<css::text::XTextRange> m_xInsertTextRange;
+ css::uno::Reference<css::text::XTextRange> m_xAltChunkStartingRange;
+ std::deque<sal_Int32> m_aFootnoteIds;
+ std::deque<sal_Int32> m_aEndnoteIds;
+
+private:
+ bool m_bIsNewDoc;
+ bool m_bIsAltChunk = false;
+ bool m_bIsReadGlossaries;
+
+public:
+ DomainMapper_Impl(
+ DomainMapper& rDMapper,
+ css::uno::Reference < css::uno::XComponentContext > xContext,
+ css::uno::Reference< css::lang::XComponent > const& xModel,
+ SourceDocumentType eDocumentType,
+ utl::MediaDescriptor const & rMediaDesc);
+ ~DomainMapper_Impl();
+
+ void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) { if (!m_pOOXMLDocument) m_pOOXMLDocument = pDocument; };
+ writerfilter::ooxml::OOXMLDocument* getDocumentReference() const;
+
+ SectionPropertyMap* GetLastSectionContext( )
+ {
+ return m_pLastSectionContext.get( );
+ }
+
+ css::uno::Reference<css::container::XNameContainer> const & GetPageStyles();
+ OUString GetUnusedPageStyleName();
+ css::uno::Reference<css::container::XNameContainer> const & GetCharacterStyles();
+ css::uno::Reference<css::container::XNameContainer> const& GetParagraphStyles();
+ OUString GetUnusedCharacterStyleName();
+ css::uno::Reference<css::text::XText> const & GetBodyText();
+ const css::uno::Reference<css::lang::XMultiServiceFactory>& GetTextFactory() const
+ {
+ return m_xTextFactory;
+ }
+ const css::uno::Reference<css::text::XTextDocument>& GetTextDocument() const
+ {
+ return m_xTextDocument;
+ }
+ void SetDocumentSettingsProperty( const OUString& rPropName, const css::uno::Any& rValue );
+
+ void CreateRedline(css::uno::Reference<css::text::XTextRange> const& xRange, const RedlineParamsPtr& pRedline);
+
+ void CheckParaMarkerRedline(css::uno::Reference<css::text::XTextRange> const& xRange);
+
+ void CheckRedline(css::uno::Reference<css::text::XTextRange> const& xRange);
+
+ void StartParaMarkerChange( );
+ void EndParaMarkerChange( );
+ void StartParaMarkerMove( );
+ void EndParaMarkerMove( );
+ void ChainTextFrames();
+
+ void PushTextBoxContent();
+ void PopTextBoxContent();
+ void AttachTextBoxContentToShape(css::uno::Reference<css::drawing::XShape> xShape);
+
+ void RemoveDummyParaForTableInSection();
+ void AddDummyParaForTableInSection();
+ void RemoveLastParagraph();
+
+ void checkIfHeaderFooterIsEmpty(PagePartType ePagePartType, PageType eType);
+ void prepareHeaderFooterContent(css::uno::Reference<css::beans::XPropertySet> const& xPageStyle,
+ PagePartType ePagePartType, PropertyIds eID,
+ bool bAppendToHeaderAndFooterTextStack);
+
+ void SetIsDecimalComma() { m_bIsDecimalComma = true; };
+ void SetIsLastParagraphInSection( bool bIsLast );
+ bool GetIsLastParagraphInSection() const { return m_StreamStateStack.top().bIsLastParaInSection; }
+ void SetRubySprmId(sal_uInt32 const nSprmId) { m_StreamStateStack.top().aRubyInfo.nSprmId = nSprmId; }
+ void SetRubyText( OUString const &sText, OUString const &sStyle) {
+ m_StreamStateStack.top().aRubyInfo.sRubyText = sText;
+ m_StreamStateStack.top().aRubyInfo.sRubyStyle = sStyle;
+ }
+ const RubyInfo & GetRubyInfo() const { return m_StreamStateStack.top().aRubyInfo; }
+ void SetRubyInfo(const RubyInfo & rInfo) { m_StreamStateStack.top().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_StreamStateStack.top().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_StreamStateStack.top().bTextFrameInserted; }
+ void SetIsTextDeleted(bool bIsTextDeleted) { m_bTextDeleted = bIsTextDeleted; }
+
+ void SetIsPreviousParagraphFramed(bool const bIsFramed)
+ { m_StreamStateStack.top().bIsPreviousParagraphFramed = bIsFramed; }
+ bool GetIsPreviousParagraphFramed() const { return m_StreamStateStack.top().bIsPreviousParagraphFramed; }
+ void SetParaSectpr(bool bParaSectpr);
+ bool GetParaSectpr() const { return m_StreamStateStack.top().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;}
+
+ void SetSdt(bool bSdt);
+
+ void PushSdt();
+ void PopSdt();
+ /// Gives access to the currently open run/inline SDTs.
+ const std::stack<BookmarkInsertPosition>& GetSdtStarts() const;
+
+
+ bool GetParaChanged() const { return m_StreamStateStack.top().bParaChanged; }
+ bool GetParaHadField() const { return m_StreamStateStack.top().bParaHadField; }
+ bool GetRemoveThisPara() const { return m_StreamStateStack.top().bRemoveThisParagraph; }
+
+ void deferBreak( BreakType deferredBreakType );
+ bool isBreakDeferred( BreakType deferredBreakType );
+ void clearDeferredBreaks();
+ void clearDeferredBreak(BreakType deferredBreakType);
+
+ void setSdtEndDeferred(bool bSdtEndDeferred);
+ bool isSdtEndDeferred() const;
+ void setParaSdtEndDeferred(bool bParaSdtEndDeferred);
+ bool isParaSdtEndDeferred() const;
+
+ void finishParagraph( const PropertyMapPtr& pPropertyMap, const bool bRemove = false, const bool bNoNumbering = false);
+ void applyToggleAttributes( const PropertyMapPtr& pPropertyMap );
+ void MergeAtContentImageRedlineWithNext(const css::uno::Reference<css::text::XTextAppend>& xTextAppend);
+ void appendTextPortion( const OUString& rString, const PropertyMapPtr& pPropertyMap );
+ void appendTextContent(const css::uno::Reference<css::text::XTextContent>&, const css::uno::Sequence<css::beans::PropertyValue>&);
+ void appendOLE( const OUString& rStreamName, const std::shared_ptr<OLEHandler>& pOleHandler );
+ void appendStarMath( const Value& v);
+ void adjustLastPara(sal_Int8 nAlign);
+ css::uno::Reference<css::beans::XPropertySet> appendTextSectionAfter(css::uno::Reference<css::text::XTextRange> const & xBefore);
+
+ /// AutoText import: each entry is placed in the separate section
+ void appendGlossaryEntry();
+ /// Remember where entry was started
+ void setGlossaryEntryStart( css::uno::Reference<css::text::XTextRange> const & xStart )
+ {
+ m_xGlossaryEntryStart = xStart;
+ }
+
+ // push the new properties onto the stack and make it the 'current' property map
+ void PushProperties(ContextType eId);
+ void PushStyleProperties(const PropertyMapPtr& pStyleProperties);
+ void PushListProperties(const PropertyMapPtr& pListProperties);
+ void PopProperties(ContextType eId);
+
+ ContextType GetTopContextType() const { return m_aContextStack.top(); }
+ const PropertyMapPtr& GetTopContext() const
+ {
+ return m_pTopContext;
+ }
+ PropertyMapPtr GetTopContextOfType(ContextType eId);
+
+ bool HasTopText() const;
+ css::uno::Reference<css::text::XTextAppend> const & GetTopTextAppend();
+ FieldContextPtr const & GetTopFieldContext();
+
+ bool HasTopAnchoredObjects() const;
+
+ FontTablePtr const & GetFontTable()
+ {
+ if(!m_pFontTable)
+ m_pFontTable = new FontTable();
+ return m_pFontTable;
+ }
+ StyleSheetTablePtr const & GetStyleSheetTable()
+ {
+ if(!m_pStyleSheetTable)
+ m_pStyleSheetTable = new StyleSheetTable( m_rDMapper, m_xTextDocument, m_bIsNewDoc );
+ return m_pStyleSheetTable;
+ }
+ OUString GetListStyleName(sal_Int32 nListId);
+ ListsManager::Pointer const & GetListTable();
+
+ std::unique_ptr<ThemeHandler> const& getThemeHandler()
+ {
+ if (!m_pThemeHandler && m_pOOXMLDocument && m_pOOXMLDocument->getTheme())
+ {
+ m_pThemeHandler = std::make_unique<ThemeHandler>(m_pOOXMLDocument->getTheme(), GetSettingsTable()->GetThemeFontLangProperties());
+ }
+ return m_pThemeHandler;
+ }
+
+ SettingsTablePtr const & GetSettingsTable()
+ {
+ if( !m_pSettingsTable )
+ m_pSettingsTable = new SettingsTable(m_rDMapper);
+ return m_pSettingsTable;
+ }
+
+ GraphicImportPtr const & GetGraphicImport();
+ void ResetGraphicImport();
+ // this method deletes the current m_pGraphicImport after import
+ void ImportGraphic(const writerfilter::Reference<Properties>::Pointer_t&);
+
+ 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& rString) { m_StreamStateStack.top().sCurrentParaStyleName = rString; }
+ OUString GetCurrentParaStyleName();
+ OUString GetDefaultParaStyleName();
+
+ // specified style - including inherited properties. Indicate whether paragraph defaults should be checked.
+ css::uno::Any GetPropertyFromStyleSheet(PropertyIds eId, StyleSheetEntryPtr pEntry, const bool bDocDefaults, const bool bPara, bool* bIsDocDefault = nullptr);
+ // current paragraph style - including inherited properties
+ css::uno::Any GetPropertyFromParaStyleSheet(PropertyIds eId);
+ // context's character style - including inherited properties
+ css::uno::Any GetPropertyFromCharStyleSheet(PropertyIds eId, const PropertyMapPtr& rContext);
+ // get property first from the given context, or secondly via inheritance from styles/docDefaults
+ css::uno::Any GetAnyProperty(PropertyIds eId, const PropertyMapPtr& rContext);
+ void SetDocDefaultsImport( bool bSet ) { m_bInDocDefaultsImport = bSet;}
+ bool IsDocDefaultsImport()const { return m_bInDocDefaultsImport;}
+ void SetStyleSheetImport( bool bSet ) { m_bInStyleSheetImport = bSet;}
+ bool IsStyleSheetImport()const { return m_bInStyleSheetImport;}
+ void SetNumberingImport( bool bSet ) { m_bInNumberingImport = bSet;}
+ bool IsNumberingImport() const { return m_bInNumberingImport;}
+ void SetAnyTableImport( bool bSet ) { m_bInAnyTableImport = bSet;}
+ bool IsAnyTableImport()const { return m_bInAnyTableImport;}
+ bool IsInShape()const { return m_aAnchoredStack.size() > 0;}
+
+ void PushShapeContext(const css::uno::Reference<css::drawing::XShape>& xShape);
+ void PopShapeContext();
+ void UpdateEmbeddedShapeProps(const css::uno::Reference<css::drawing::XShape>& xShape);
+ /// Add a pending shape: it's currently inserted into the document, but it should be removed before the import finishes.
+ void PushPendingShape(const css::uno::Reference<css::drawing::XShape>& xShape);
+ /// Get the first pending shape, if there are any.
+ css::uno::Reference<css::drawing::XShape> PopPendingShape();
+
+ void PopPageHeaderFooter(PagePartType ePagePartType, PageType eType);
+ bool IsInHeaderFooter() const { auto const type(m_StreamStateStack.top().eSubstreamType); return type == SubstreamType::Header || type == SubstreamType::Footer; }
+ void ConvertHeaderFooterToTextFrame(bool, bool);
+ static void fillEmptyFrameProperties(std::vector<css::beans::PropertyValue>& rFrameProperties, bool bSetAnchorToChar);
+
+ bool IsInTOC() const;
+
+ void PushFootOrEndnote( bool bIsFootnote );
+ void PopFootOrEndnote();
+ bool IsInFootOrEndnote() const { auto const type(m_StreamStateStack.top().eSubstreamType); return type == SubstreamType::Footnote || type == SubstreamType::Endnote; }
+ bool IsInFootnote() const { return m_StreamStateStack.top().eSubstreamType == SubstreamType::Footnote; }
+
+ void StartCustomFootnote(const PropertyMapPtr pContext);
+ void EndCustomFootnote();
+ bool IsInCustomFootnote() const { return m_StreamStateStack.top().bHasFootnoteStyle; }
+ bool CheckFootnoteStyle() const { return m_StreamStateStack.top().bCheckFootnoteStyle; }
+ void SetHasFootnoteStyle(bool const bVal) { m_StreamStateStack.top().bHasFootnoteStyle = bVal; }
+ void SetCheckFootnoteStyle(bool const bVal) { m_StreamStateStack.top().bCheckFootnoteStyle = bVal; }
+
+ const PropertyMapPtr& GetFootnoteContext() const { return m_pFootnoteContext; }
+
+ SkipFootnoteSeparator GetSkipFootnoteState() const { return m_eSkipFootnoteState; }
+ void SetSkipFootnoteState(SkipFootnoteSeparator eId) { m_eSkipFootnoteState = eId; }
+ sal_Int32 GetFootnoteCount() const { return m_nFootnotes; }
+ void IncrementFootnoteCount() { ++m_nFootnotes; }
+ sal_Int32 GetEndnoteCount() const { return m_nEndnotes; }
+ void IncrementEndnoteCount() { ++m_nEndnotes; }
+ bool CopyTemporaryNotes(
+ css::uno::Reference< css::text::XFootnote > xNoteSrc,
+ css::uno::Reference< css::text::XFootnote > xNoteDest );
+ void RemoveTemporaryFootOrEndnotes();
+
+ void PushAnnotation();
+ void PopAnnotation();
+ sal_Int32 GetAnnotationId() { return m_nAnnotationId; }
+
+ /// A field context starts with a cFieldStart.
+ void PushFieldContext();
+ //the current field context waits for the completion of the command
+ bool IsOpenFieldCommand() const;
+ bool IsOpenField() const;
+ //mark field in current context as locked (fixed)
+ void SetFieldLocked();
+ //collect the pieces of the command
+ void AppendFieldCommand(OUString const & rPartOfCommand);
+ void handleRubyEQField( const FieldContextPtr& pContext);
+ void handleFieldSet
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::uno::XInterface > const & xFieldInterface,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ void handleFieldAsk
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::uno::XInterface > & xFieldInterface,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ OUString convertFieldFormula(const OUString& input);
+ void handleFieldFormula
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ void handleAutoNum
+ (const FieldContextPtr& pContext,
+ css::uno::Reference< css::uno::XInterface > const & xFieldInterface,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties);
+ static void handleAuthor
+ (std::u16string_view rFirstParam,
+ css::uno::Reference< css::beans::XPropertySet > const& xFieldProperties,
+ FieldId eFieldId);
+ void handleDocProperty
+ (const FieldContextPtr& pContext,
+ OUString const& rFirstParam,
+ css::uno::Reference< css::uno::XInterface > & xFieldInterface);
+ void handleToc
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName);
+ void handleIndex
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName);
+
+ void handleBibliography
+ (const FieldContextPtr& pContext,
+ const OUString & sTOCServiceName);
+ /// The field command has to be closed (cFieldSep appeared).
+ void CloseFieldCommand();
+ //the _current_ fields require a string type result while TOCs accept richt results
+ bool IsFieldResultAsString();
+ void AppendFieldResult(std::u16string_view rResult);
+ //apply the result text to the related field
+ void SetFieldResult(OUString const& rResult);
+ // set FFData of top field context
+ void SetFieldFFData( const FFDataHandler::Pointer_t& pFFDataHandler );
+ /// The end of field is reached (cFieldEnd appeared) - the command might still be open.
+ void PopFieldContext();
+
+ /// Returns title of the TOC placed in paragraph(s) before TOC field inside STD-frame
+ OUString extractTocTitle();
+ css::uno::Reference<css::beans::XPropertySet> createSectionForRange(css::uno::Reference< css::text::XTextRange > xStart, css::uno::Reference< css::text::XTextRange > xEnd, const OUString & sObjectType, bool stepLeft);
+
+ void SetBookmarkName( const OUString& rBookmarkName );
+ void StartOrEndBookmark( const OUString& rId );
+
+ void SetMoveBookmark( bool IsFrom );
+
+ void setPermissionRangeEd(const OUString& user);
+ void setPermissionRangeEdGrp(const OUString& group);
+ void startOrEndPermissionRange(sal_Int32 permissinId);
+
+ void AddAnnotationPosition(
+ const bool bStart,
+ const sal_Int32 nAnnotationId );
+
+ bool hasTableManager() const
+ {
+ return !m_aTableManagers.empty();
+ }
+
+ DomainMapperTableManager& getTableManager()
+ {
+ return *m_aTableManagers.top();
+ }
+
+ void appendTableManager( )
+ {
+ tools::SvRef<DomainMapperTableManager> pMngr(new DomainMapperTableManager());
+ m_aTableManagers.push( pMngr );
+ }
+
+ void appendTableHandler( )
+ {
+ if (m_pTableHandler)
+ m_aTableManagers.top()->setHandler(m_pTableHandler);
+ }
+
+ void popTableManager( )
+ {
+ if (hasTableManager())
+ m_aTableManagers.pop();
+ }
+
+ void SetLineNumbering( sal_Int32 nLnnMod, sal_uInt32 nLnc, sal_Int32 ndxaLnn );
+ bool IsLineNumberingSet() const {return m_bLineNumberingSet;}
+
+ DeletableTabStop m_aCurrentTabStop;
+
+ 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;}
+
+ void InitPaperSource() { m_aPaperSource = PaperSource(); }
+ void SetPaperSource( PaperSourceElement eElement, sal_Int32 nValue );
+ const PaperSource& GetPaperSource() {return m_aPaperSource;}
+
+ const LineNumberSettings& GetLineNumberSettings() const { return m_aLineNumberSettings;}
+ void SetLineNumberSettings(const LineNumberSettings& rSet) { m_aLineNumberSettings = rSet;}
+
+ void SetInFootnoteProperties(bool const bSet) { m_StreamStateStack.top().bIsInFootnoteProperties = bSet; }
+ bool IsInFootnoteProperties() const { return m_StreamStateStack.top().bIsInFootnoteProperties; }
+
+ bool IsInComments() const { return m_StreamStateStack.top().eSubstreamType == SubstreamType::Annotation; };
+
+ std::vector<css::beans::PropertyValue> MakeFrameProperties(const ParagraphProperties& rProps);
+ void CheckUnregisteredFrameConversion(bool bPreventOverlap = false);
+
+ void RegisterFrameConversion(css::uno::Reference<css::text::XTextRange> const& xFrameStartRange,
+ css::uno::Reference<css::text::XTextRange> const& xFrameEndRange,
+ std::vector<css::beans::PropertyValue>&& aFrameProperties);
+ void ExecuteFrameConversion();
+
+ void AddNewRedline( sal_uInt32 sprmId );
+
+ sal_Int32 GetCurrentRedlineToken( ) const;
+ void SetCurrentRedlineAuthor( const OUString& sAuthor );
+ void SetCurrentRedlineDate( const OUString& sDate );
+ void SetCurrentRedlineId( sal_Int32 nId );
+ void SetCurrentRedlineToken( sal_Int32 nToken );
+ void SetCurrentRedlineRevertProperties( const css::uno::Sequence<css::beans::PropertyValue>& aProperties );
+ void SetCurrentRedlineIsRead();
+ void RemoveTopRedline( );
+ void SetCurrentRedlineInitials( const OUString& sInitials );
+ bool IsFirstRun() const { return m_StreamStateStack.top().bIsFirstRun; }
+ void SetIsFirstRun(bool const bval) { m_StreamStateStack.top().bIsFirstRun = bval; }
+ bool IsOutsideAParagraph() const { return m_StreamStateStack.top().bIsOutsideAParagraph; }
+ void SetIsOutsideAParagraph(bool const bval) { m_StreamStateStack.top().bIsOutsideAParagraph = bval; }
+
+ void ApplySettingsTable();
+
+ css::uno::Reference<css::text::XTextAppend> GetCurrentXText() {
+ return m_aTextAppendStack.empty() ? nullptr : m_aTextAppendStack.top().xTextAppend;
+ }
+
+ void NewFrameDirection() {
+ m_aFrameDirectionQueue.push(std::nullopt);
+ m_bFrameDirectionSet = false;
+ }
+ void SetFrameDirection(sal_Int16 nDirection) {
+ if (!m_bFrameDirectionSet && !m_aFrameDirectionQueue.empty()) {
+ m_aFrameDirectionQueue.back() = nDirection;
+ m_bFrameDirectionSet = true;
+ }
+ }
+ std::optional<sal_Int16> PopFrameDirection() {
+ if (m_aFrameDirectionQueue.empty())
+ return {};
+ const std::optional<sal_Int16> nDirection = m_aFrameDirectionQueue.front();
+ m_aFrameDirectionQueue.pop();
+ return nDirection;
+ }
+
+ SectionPropertyMap * GetSectionContext();
+
+ sal_Int16 GetListLevel(const StyleSheetEntryPtr& pEntry, const PropertyMapPtr& pParaContext = nullptr);
+ void ValidateListLevel(const OUString& sStyleIdentifierD);
+
+ /**
+ Used for attributes/sprms which cannot be evaluated immediately (e.g. they depend
+ on another one that comes in the same CONTEXT_CHARACTER). The property will be processed
+ again in DomainMapper::processDeferredCharacterProperties().
+ */
+ void deferCharacterProperty(sal_Int32 id, const css::uno::Any& value);
+ /**
+ Processes properties deferred using deferCharacterProperty(). To be called whenever the top
+ CONTEXT_CHARACTER is going to be used (e.g. by appendText()).
+ */
+ void processDeferredCharacterProperties(bool bCharContext = true);
+
+ sal_Int32 getNumberingProperty(const sal_Int32 nListId, sal_Int32 nListLevel, const OUString& aProp);
+ /// Get a property of the current numbering style's current level.
+ sal_Int32 getCurrentNumberingProperty(const OUString& aProp);
+
+ /// If we're importing into a new document, or just pasting to an existing one.
+ bool IsNewDoc() const { return m_bIsNewDoc;}
+
+ bool IsAltChunk() const { return m_bIsAltChunk;}
+
+ /// If we're importing autotext.
+ bool IsReadGlossaries() const { return m_bIsReadGlossaries;}
+
+ tools::SvRef<SdtHelper> m_pSdtHelper;
+
+ /// Document background color, applied to every page style.
+ std::optional<sal_Int32> m_oBackgroundColor;
+ bool m_bCopyStandardPageStyleFill = false;
+
+ /// If the current section has a footnote separator.
+ bool m_bHasFtnSep;
+
+ /// 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;
+ enum GraphicImportType m_eGraphicImportType = {};
+ 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 const bParaAutoBefore) { m_StreamStateStack.top().bParaAutoBefore = bParaAutoBefore; }
+
+ /// Forget about the previous paragraph, as it's not inside the same
+ /// start/end node.
+ void ClearPreviousParagraph();
+
+ /// Check if previous paragraph has borders in between and do the border magic to it if so
+ bool handlePreviousParagraphBorderInBetween() const;
+
+ /// Handle redline text portions in a frame, footnotes and redlines:
+ /// store their data, and create them after frame creation or footnote/endnote copying
+ bool m_bIsActualParagraphFramed;
+ std::deque<css::uno::Any> m_aStoredRedlines[StoredRedlines::NONE];
+
+ bool IsParaWithInlineObject() const { return m_StreamStateStack.top().bParaWithInlineObject; }
+
+ bool SeenHeaderFooter(PagePartType, PageType) const;
+
+ css::uno::Reference< css::embed::XStorage > m_xDocumentStorage;
+
+ /// Handles <w:altChunk>.
+ void HandleAltChunk(const OUString& rStreamName);
+
+ /// Handles <w:ptab>.
+ void HandlePTab(sal_Int32 nAlignment);
+
+ /// Handles <w:br w:clear="...">.
+ void HandleLineBreakClear(sal_Int32 nClear);
+
+ /// Handles <w:br>.
+ void HandleLineBreak(const PropertyMapPtr& pPropertyMap);
+
+ void commentProps(const OUString& sId, const CommentProperties& rProps);
+
+ OUString ConvertTOCStyleName(OUString const&);
+
+ OUString getFontNameForTheme(const Id id);
+
+private:
+ void PushPageHeaderFooter(PagePartType ePagePartType, 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 ;
+ /// SAXException was seen so document will be abandoned
+ bool m_bSaxError;
+
+ std::unordered_map<OUString, CommentProperties> m_aCommentProps;
+};
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/FFDataHandler.cxx b/sw/source/writerfilter/dmapper/FFDataHandler.cxx
new file mode 100644
index 000000000000..507327cf8333
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/dmapper/FFDataHandler.hxx b/sw/source/writerfilter/dmapper/FFDataHandler.hxx
new file mode 100644
index 000000000000..f8a88f5c9d6b
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/FFDataHandler.hxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include "LoggedResources.hxx"
+#include <rtl/ustring.hxx>
+#include <vector>
+namespace writerfilter::dmapper
+{
+class FFDataHandler : public LoggedProperties
+{
+public:
+ // typedefs
+ typedef ::tools::SvRef<FFDataHandler> Pointer_t;
+ typedef ::std::vector<OUString> DropDownEntries_t;
+
+ // constructor
+ FFDataHandler();
+ // destructor
+ virtual ~FFDataHandler() override;
+
+ // member: name
+ const OUString& getName() const { return m_sName; }
+
+ // member: helpText
+ const OUString& getHelpText() const { return m_sHelpText; }
+
+ // member: statusText
+ const OUString& getStatusText() const { return m_sStatusText; }
+
+ const OUString& getEntryMacro() const { return m_sEntryMacro; }
+ const OUString& getExitMacro() const { return m_sExitMacro; }
+
+ // member: checkboxHeight
+ sal_uInt32 getCheckboxHeight() const { return m_nCheckboxHeight; }
+
+ // member: checkboxAutoHeight
+ bool getCheckboxAutoHeight() const { return m_bCheckboxAutoHeight; }
+
+ // member: checkboxChecked or checkboxDefault (if the previous is not set)
+ bool getCheckboxChecked() const;
+
+ // member: dropDownResult
+ const OUString& getDropDownResult() const { return m_sDropDownResult; }
+
+ // member: dropDownEntries
+ const DropDownEntries_t& getDropDownEntries() const { return m_DropDownEntries; }
+
+ // member: textDefault
+ const OUString& getTextDefault() const { return m_sTextDefault; }
+
+ const OUString& getTextType() const { return m_sTextType; }
+ const OUString& getTextFormat() const { return m_sTextFormat; }
+ sal_uInt16 getTextMaxLength() const { return m_nTextMaxLength; }
+
+ // sprm
+ void resolveSprm(Sprm& r_sprm);
+
+private:
+ OUString m_sName;
+ OUString m_sHelpText;
+ OUString m_sStatusText;
+ OUString m_sEntryMacro;
+ OUString m_sExitMacro;
+ sal_uInt32 m_nCheckboxHeight;
+ bool m_bCheckboxAutoHeight;
+ int m_nCheckboxChecked;
+ int m_nCheckboxDefault;
+ OUString m_sDropDownResult;
+ DropDownEntries_t m_DropDownEntries;
+ OUString m_sTextDefault;
+ OUString m_sTextType;
+ OUString m_sTextFormat;
+ sal_uInt16 m_nTextMaxLength;
+
+ // sprm
+ void lcl_sprm(Sprm& r_sprm) override;
+
+ // attribute
+ void lcl_attribute(Id name, Value& val) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/FieldTypes.hxx b/sw/source/writerfilter/dmapper/FieldTypes.hxx
new file mode 100644
index 000000000000..144d1efe1370
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/FieldTypes.hxx
@@ -0,0 +1,306 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+namespace writerfilter::dmapper {
+
+enum FieldId
+{
+ /* ADDRESSBLOCK \d \* MERGEFORMAT -> Addressblock completely unsupported*/
+ FIELD_ADDRESSBLOCK
+ /* ADVANCE \d downvalue \l leftvalue \r rightvalue \u upvalue \x xvalue \y yvalue -> unsupported*/
+ ,FIELD_ADVANCE
+ /* ASK bookmarkname "hint" \d defaultanswer \o \* MERGEFORMAT ->
+ the hint is not always quoted, inputfield with default answer, prompt before merge (\o)
+ */
+ ,FIELD_ASK
+ /* AUTONUM \* Numberingswitch ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTONUM
+ /* AUTONUMLGL \* Numberingswitch ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTONUMLGL
+ /* AUTONUMOUT \* Numberingswitch ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTONUMOUT
+ /* AUTHOR NewAuthor \* defaultswitch \* MERGEFORMAT ->
+ mapped to sequence field "AutoNr"
+ */
+ ,FIELD_AUTHOR
+ /* COMMENTS "comment" \* MERGEFORMAT ->
+ Docinfo-Comments
+ */
+ ,FIELD_COMMENTS
+ /* CREATEDATE \h \* MERGEFORMAT ->
+ docinfo-created-date
+ */
+ ,FIELD_CREATEDATE
+ /* DATE \@ "number format" \s \* MERGEFORMAT ->
+ ww8filterimprovement: multiple languages now supported
+ */
+ ,FIELD_DATE
+ /* DOCPROPERTY propertyname \* MERGEFORMAT ->
+ ww8filterimprovement: some fields imported as functionally equivalent fields if possible,
+ the others imported as UserField
+ */
+ ,FIELD_DOCPROPERTY
+ /* DOCVARIABLE Name \* MERGEFORMAT ->
+ ww8filterimprovement: now imported as user fields
+ */
+ ,FIELD_DOCVARIABLE
+ /* EDITTIME \# "displayformat" \* Numberingswitch \* MERGEFORMAT ->
+ DocInfo-Modified-Date
+ ww8filterimprovement: multiple languages now supported
+ */
+ ,FIELD_EDITTIME
+ ,FIELD_EQ
+ /* FILLIN "text to fill in" \d defaultanswer \o \* MERGEFORMAT ->
+ Function-InputField
+ */
+ ,FIELD_FILLIN
+ /* FILENAME \p \* * MERGEFORMAT ->
+ file name (\p with path)
+ */
+ ,FIELD_FILENAME
+ /* FILESIZE \* NumberingType \* MERGEFORMAT ->
+ not imported in old ww8 filter, see lcl_ParseNumberingType
+ todo find alternative field
+ */
+ ,FIELD_FILESIZE
+ /* =formula \# "number format"
+ todo find alternative field
+ */
+ ,FIELD_FORMULA
+ /* FORMCHECKBOX */
+ ,FIELD_FORMCHECKBOX
+ /* FORMDROPDOWN */
+ ,FIELD_FORMDROPDOWN
+ /* FORMTEXT */
+ ,FIELD_FORMTEXT
+ /* GOTOBUTTON text \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo find alternative field
+ */
+ ,FIELD_GOTOBUTTON
+ /* HYPERLINK "link" \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ ww8filterimprovement: now imported as hyperlink
+ */
+ ,FIELD_HYPERLINK
+ /* IF condition "then text" "else text" ->
+ not imported in old ww8 filter
+ ww8filterimprovement: now imported
+ todo: condition, if text, else text still missing
+ */
+ ,FIELD_IF
+ /* INFO NameOfInfo \* MERGEFORMAT -> old
+ todo: filter imports wrong?
+ */
+ ,FIELD_INFO
+ /* INCLUDEPICTURE path \* MERGEFORMAT->
+ old filter imports an embedded picture
+ */
+ ,FIELD_INCLUDEPICTURE
+ /* KEYWORDS keyword \* defaultswitch \* Numberingswitch \* MERGEFORMAT ->
+ DocInfo Keywords
+ */
+ ,FIELD_KEYWORDS
+ /* LASTSAVEDBY \* MERGEFORMAT ->
+ DocInfo-Modified-Author
+ */
+ ,FIELD_LASTSAVEDBY
+ /* MACROBUTTON MacroName quick help text ->
+ Macro field
+ */
+ ,FIELD_MACROBUTTON
+ /* MERGEFIELD ColumName \b prefix \f suffix \* MERGEFORMAT ->
+ ww8filterimprovement: column-only API now supported
+ */
+ ,FIELD_MERGEFIELD
+ /* MERGEREC \* MERGEFORMAT ->
+ RecordNumber field, maybe without db name
+ todo: currently unchecked
+ */
+ ,FIELD_MERGEREC
+ /* MERGESEQ \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ ww8filterimprovement: now imported
+ todo: currently unchecked
+ */
+ ,FIELD_MERGESEQ
+ /* NEXT text ->
+ Next record
+ todo: currently unchecked
+ */
+ ,FIELD_NEXT
+ /* NEXTIF condition
+ todo: condition not imported
+ */
+ ,FIELD_NEXTIF
+ /* PAGE \* Numberingswitch \* MERGEFORMAT ->
+ see lcl_ParseNumberingType
+ */
+ ,FIELD_PAGE
+ ,FIELD_PAGEREF
+ ,FIELD_PRINTDATE
+ /* REF targetbkm \f \* MERGEFORMAT ->
+ imports a ShowVariable (bookmarkname)?
+ \h hyperlink to paragraph
+ \p relative to para above/below
+ \f reference number
+ \d separator number separator
+ \n paragraph number
+ \r paragraph number in relative context
+ \t suppress non delimiters
+ \w paragraph number in full context
+ \* Upper/Lower...
+ */
+ ,FIELD_REF
+ /* REVNUM \* Numberingswitch \* MERGEFORMAT ->
+ DocInfo-revision number
+ */
+ ,FIELD_REVNUM
+ /* SAVEDATE \@ "NumberFormat"\* MERGEFORMAT ->
+ DocInfo-modified-date
+ */
+ ,FIELD_SAVEDATE
+ /* SECTION \* NumberFormat \* MERGEFORMAT ->
+ not imported in old ww8 filter see lcl_ParseNumberingType
+ todo: find alternative
+ */
+ ,FIELD_SECTION
+ /* SECTIONPAGES \* NumberFormat \* MERGEFORMAT ->
+ not imported in old ww8 filter see lcl_ParseNumberingType
+ todo: find alternative
+ */
+ ,FIELD_SECTIONPAGES
+ /* SEQ sequencename \h \c \n \r \s \* MERGEFORMAT ->
+ number range name:sequencename value:sequencename+1
+ todo: only partially implemented, switches unsupported
+ */
+ ,FIELD_SEQ
+ /* SET bookmarkname newtext \* MERGEFORMAT ->
+ SetVariable bookmarkname = newtext
+ todo: not implemented yet
+ */
+ ,FIELD_SET
+ /* SKIPIF condition \* MERGEFORMAT ->
+ ??
+ todo: not implemented yet
+ */
+ ,FIELD_SKIPIF
+ /* STYLEREF stylename \* MERGEFORMAT ->
+ implemented using GetReference, but some switches are not implemented yet
+ \l isn't implemented
+ \t isn't implemented
+ */
+ ,FIELD_STYLEREF
+ /* SUBJECT subject \* Defaultswitch \* MERGEFORMAT ->
+ DocInfo - subject
+ */
+ ,FIELD_SUBJECT
+ /* SYMBOL symbolnumber \* MERGEFORMAT ->
+ inserts a special char (symbolnumber)
+ todo: find alternative
+ */
+ ,FIELD_SYMBOL
+ /* TEMPLATE \* Defaultswitch \* MERGEFORMAT
+ TemplateName field
+ */
+ ,FIELD_TEMPLATE
+ /* TIME \@ "number format" \* MERGEFORMAT
+ ww8filterimprovement: multiple languages now supported
+ */
+ ,FIELD_TIME
+ /* TITLE \* Defaultswitch \* MERGEFORMAT ->
+ DocInfo-title
+ */
+ ,FIELD_TITLE
+ /* USERINITIALS newinitials \* MERGEFORMAT ->
+ ExtendedUser field (SHORTCUT)
+ */
+ ,FIELD_USERINITIALS
+ /* USERADDRESS \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo: find alternative
+ */
+ ,FIELD_USERADDRESS
+ /* USERNAME newusername \* MERGEFORMAT ->
+ not imported in old ww8 filter
+ todo: import as extended user field(s)
+ */
+ ,FIELD_USERNAME
+ /*
+ TOC options:
+ \a Builds a table of figures but does not include the captions's label and number
+ \b Uses a bookmark to specify area of document from which to build table of contents
+ \c Builds a table of figures of the given label
+ \d Defines the separator between sequence and page numbers
+ \f Builds a table of contents using TC entries instead of outline levels
+ \h Hyperlinks the entries and page numbers within the table of contents
+ \l Defines the TC entries field level used to build a table of contents
+ \n Builds a table of contents or a range of entries, such as 1-9, in a table of contents without page numbers
+ \o Builds a table of contents by using outline levels instead of TC entries
+ \p Defines the separator between the table entry and its page number
+ \s Builds a table of contents by using a sequence type
+ \t Builds a table of contents by using style names other than the standard outline styles
+ \u Builds a table of contents by using the applied paragraph outline level
+ \w Preserve tab characters within table entries
+ \x Preserve newline characters within table entries
+ \z Hides page numbers within the table of contents when shown in Web Layout View
+ */
+ ,FIELD_TOC
+ /*
+ TOC entry: text
+ \f TC entry in doc with multiple tables
+ \l Outline Level
+ \n Suppress page numbers
+ example: TOC "EntryText \f \l 2 \n
+ */
+ ,FIELD_TC
+ /* document statistic - number of characters
+ */
+ ,FIELD_NUMCHARS
+ /* document statistic - number of words
+ */
+ ,FIELD_NUMWORDS
+ /* document statistic - number of pages
+ */
+ ,FIELD_NUMPAGES
+ /* Document alphabetical index
+ */
+ ,FIELD_INDEX
+ /* Document alphabetical index marks
+ */
+ ,FIELD_XE
+ /**
+ * Bibliography
+ */
+ ,FIELD_BIBLIOGRAPHY
+ /* Citation
+ */
+ ,FIELD_CITATION
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/FontTable.cxx b/sw/source/writerfilter/dmapper/FontTable.cxx
new file mode 100644
index 000000000000..c64276585a5d
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/FontTable.cxx
@@ -0,0 +1,299 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "FontTable.hxx"
+#include <o3tl/deleter.hxx>
+#include <ooxml/resourceids.hxx>
+#include <utility>
+#include <vector>
+#include <sal/log.hxx>
+#include <rtl/tencinfo.h>
+#include <vcl/embeddedfontshelper.hxx>
+#include <unotools/fontdefs.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+
+struct FontTable_Impl
+{
+ std::unique_ptr<EmbeddedFontsHelper, o3tl::default_delete<EmbeddedFontsHelper>> xEmbeddedFontHelper;
+ std::vector< FontEntry::Pointer_t > aFontEntries;
+ FontEntry::Pointer_t pCurrentEntry;
+ FontTable_Impl() {}
+};
+
+FontTable::FontTable()
+: LoggedProperties("FontTable")
+, LoggedTable("FontTable")
+, LoggedStream("FontTable")
+, m_pImpl( new FontTable_Impl )
+{
+}
+
+FontTable::~FontTable()
+{
+}
+
+void FontTable::lcl_attribute(Id Name, Value & val)
+{
+ SAL_WARN_IF( !m_pImpl->pCurrentEntry, "writerfilter.dmapper", "current entry has to be set here" );
+ if(!m_pImpl->pCurrentEntry)
+ return ;
+ int nIntValue = val.getInt();
+ OUString sValue = val.getString();
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_Pitch_val:
+ if (static_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Pitch_fixed)
+ ;
+ else if (static_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Pitch_variable)
+ ;
+ else if (static_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Pitch_default)
+ ;
+ else
+ SAL_WARN("writerfilter.dmapper", "FontTable::lcl_attribute: unhandled NS_ooxml::CT_Pitch_val: " << nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Font_name:
+ m_pImpl->pCurrentEntry->sFontName = sValue;
+ break;
+ case NS_ooxml::LN_CT_Charset_val:
+ // w:characterSet has higher priority, set only if that one is not set
+ if( m_pImpl->pCurrentEntry->nTextEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ m_pImpl->pCurrentEntry->nTextEncoding = rtl_getTextEncodingFromWindowsCharset( nIntValue );
+ if( IsOpenSymbol( 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( IsOpenSymbol( 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 ? u""
+ : nSprmId == NS_ooxml::LN_CT_Font_embedBold ? u"b"
+ : nSprmId == NS_ooxml::LN_CT_Font_embedItalic ? u"i"
+ : /*NS_ooxml::LN_CT_Font_embedBoldItalic*/ u"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(const 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_Unicode*, size_t)
+{
+}
+
+void FontTable::lcl_props(const writerfilter::Reference<Properties>::Pointer_t&)
+{
+}
+
+void FontTable::lcl_table(Id, const writerfilter::Reference<Table>::Pointer_t&)
+{
+}
+
+void FontTable::lcl_substream(Id, const writerfilter::Reference<Stream>::Pointer_t&)
+{
+}
+
+void FontTable::lcl_startShape(uno::Reference<drawing::XShape> const&)
+{
+}
+
+void FontTable::lcl_endShape( )
+{
+}
+
+FontEntry::Pointer_t FontTable::getFontEntry(sal_uInt32 nIndex)
+{
+ return (m_pImpl->aFontEntries.size() > nIndex)
+ ? m_pImpl->aFontEntries[nIndex]
+ : FontEntry::Pointer_t();
+}
+
+sal_uInt32 FontTable::size()
+{
+ return m_pImpl->aFontEntries.size();
+}
+
+void FontTable::addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream,
+ const OUString& fontName, std::u16string_view extra,
+ std::vector<unsigned char> const & key)
+{
+ if (!m_pImpl->xEmbeddedFontHelper)
+ m_pImpl->xEmbeddedFontHelper.reset(new EmbeddedFontsHelper);
+ m_pImpl->xEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key);
+}
+
+EmbeddedFontHandler::EmbeddedFontHandler(FontTable& rFontTable, OUString _fontName, std::u16string_view style )
+: LoggedProperties("EmbeddedFontHandler")
+, m_fontTable( rFontTable )
+, m_fontName(std::move( _fontName ))
+, m_style( style )
+{
+}
+
+EmbeddedFontHandler::~EmbeddedFontHandler()
+{
+ if( !m_inputStream.is())
+ return;
+ std::vector< unsigned char > key( 32 );
+ if( !m_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 = m_fontKey[ pos[ i ]];
+ int v2 = m_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;
+ }
+ }
+ m_fontTable.addEmbeddedFont( m_inputStream, m_fontName, m_style, key );
+ m_inputStream->closeInput();
+}
+
+void EmbeddedFontHandler::lcl_attribute( Id name, Value& val )
+{
+ switch( name )
+ {
+ case NS_ooxml::LN_CT_FontRel_fontKey:
+ m_fontKey = val.getString();
+ 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() >>= m_inputStream;
+ break;
+ default:
+ break;
+ }
+}
+
+void EmbeddedFontHandler::lcl_sprm( Sprm& )
+{
+}
+
+
+}//namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/FontTable.hxx b/sw/source/writerfilter/dmapper/FontTable.hxx
new file mode 100644
index 000000000000..092affebe871
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/FontTable.hxx
@@ -0,0 +1,106 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include "LoggedResources.hxx"
+#include <com/sun/star/io/XInputStream.hpp>
+
+namespace writerfilter::dmapper
+{
+
+struct FontTable_Impl;
+struct FontEntry : public virtual SvRefBase
+{
+ typedef tools::SvRef<FontEntry> Pointer_t;
+
+ OUString sFontName;
+ sal_Int32 nTextEncoding;
+ FontEntry() :
+ nTextEncoding( RTL_TEXTENCODING_DONTKNOW )
+ {}
+};
+
+class FontTable : public LoggedProperties, public LoggedTable
+ /*,public BinaryObj*/, public LoggedStream
+{
+ std::unique_ptr<FontTable_Impl> m_pImpl;
+
+ public:
+ FontTable();
+ virtual ~FontTable() override;
+
+ sal_uInt32 size();
+ FontEntry::Pointer_t getFontEntry(sal_uInt32 nIndex);
+
+ void addEmbeddedFont(const css::uno::Reference<css::io::XInputStream>& stream,
+ const OUString& fontName, std::u16string_view extra,
+ std::vector<unsigned char> const & key);
+
+ private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+ void resolveSprm(Sprm & r_sprm);
+
+ // Table
+ virtual void lcl_entry(const 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_Unicode * data, size_t len) override;
+ virtual void lcl_props(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+ virtual void lcl_table(Id name,
+ const writerfilter::Reference<Table>::Pointer_t& ref) override;
+ virtual void lcl_substream(Id name,
+ const writerfilter::Reference<Stream>::Pointer_t& ref) override;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ virtual void lcl_endShape( ) override;
+ virtual void lcl_startTextBoxContent() override {};
+ virtual void lcl_endTextBoxContent() override {};
+};
+typedef tools::SvRef< FontTable > FontTablePtr;
+
+class EmbeddedFontHandler : public LoggedProperties
+{
+public:
+ EmbeddedFontHandler(FontTable& rFontTable, OUString fontName, std::u16string_view style);
+ virtual ~EmbeddedFontHandler() override;
+private:
+ virtual void lcl_attribute( Id name, Value& val ) override;
+ virtual void lcl_sprm( Sprm& rSprm ) override;
+ FontTable& m_fontTable;
+ OUString m_fontName;
+ std::u16string_view m_style;
+ OUString m_fontKey;
+ css::uno::Reference<css::io::XInputStream> m_inputStream;
+};
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/FormControlHelper.cxx b/sw/source/writerfilter/dmapper/FormControlHelper.cxx
new file mode 100644
index 000000000000..40f5d703815e
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/FormControlHelper.cxx
@@ -0,0 +1,379 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <math.h>
+
+#include <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/uno/Any.hxx>
+
+#include <o3tl/safeint.hxx>
+
+#include "FormControlHelper.hxx"
+#include <utility>
+#include <xmloff/odffields.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+struct FormControlHelper::FormControlHelper_Impl : public virtual SvRefBase
+{
+ FieldId m_eFieldId;
+ awt::Size aSize;
+ uno::Reference<drawing::XDrawPage> rDrawPage;
+ uno::Reference<form::XForm> rForm;
+ uno::Reference<form::XFormComponent> rFormComponent;
+ uno::Reference<lang::XMultiServiceFactory> rServiceFactory;
+ uno::Reference<text::XTextDocument> rTextDocument;
+
+ uno::Reference<drawing::XDrawPage> const & getDrawPage();
+ uno::Reference<lang::XMultiServiceFactory> const & getServiceFactory();
+ uno::Reference<form::XForm> const & getForm();
+ uno::Reference<container::XIndexContainer> getFormComps();
+};
+
+uno::Reference<drawing::XDrawPage> const & FormControlHelper::FormControlHelper_Impl::getDrawPage()
+{
+ if (! rDrawPage.is())
+ {
+ uno::Reference<drawing::XDrawPageSupplier>
+ xDrawPageSupplier(rTextDocument, uno::UNO_QUERY);
+ if (xDrawPageSupplier.is())
+ rDrawPage = xDrawPageSupplier->getDrawPage();
+ }
+
+ return rDrawPage;
+}
+
+uno::Reference<lang::XMultiServiceFactory> const & FormControlHelper::FormControlHelper_Impl::getServiceFactory()
+{
+ if (! rServiceFactory.is())
+ rServiceFactory.set(rTextDocument, uno::UNO_QUERY);
+
+ return rServiceFactory;
+}
+
+uno::Reference<form::XForm> const & FormControlHelper::FormControlHelper_Impl::getForm()
+{
+ if (! rForm.is())
+ {
+ uno::Reference<form::XFormsSupplier> xFormsSupplier(getDrawPage(), uno::UNO_QUERY);
+
+ if (xFormsSupplier.is())
+ {
+ uno::Reference<container::XNameContainer> xFormsNamedContainer(xFormsSupplier->getForms());
+ static constexpr OUString sDOCXForm = u"DOCX-Standard"_ustr;
+
+ 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 pFFData)
+ : m_pFFData(std::move(pFFData)), m_pImpl(new FormControlHelper_Impl)
+{
+ m_pImpl->m_eFieldId = eFieldId;
+ m_pImpl->rTextDocument = xTextDocument;
+}
+
+FormControlHelper::~FormControlHelper()
+{
+}
+
+bool FormControlHelper::createCheckbox(uno::Reference<text::XTextRange> const& xTextRange,
+ const OUString & rControlName)
+{
+ if ( !m_pFFData )
+ return false;
+ uno::Reference<lang::XMultiServiceFactory>
+ xServiceFactory(m_pImpl->getServiceFactory());
+
+ if (! xServiceFactory.is())
+ return false;
+
+ uno::Reference<uno::XInterface> xInterface = xServiceFactory->createInstance("com.sun.star.form.component.CheckBox");
+
+ if (!xInterface.is())
+ return false;
+
+ m_pImpl->rFormComponent.set(xInterface, uno::UNO_QUERY);
+ if (!m_pImpl->rFormComponent.is())
+ return false;
+
+ uno::Reference<beans::XPropertySet> xPropSet(xInterface, uno::UNO_QUERY);
+
+ sal_uInt32 nCheckBoxHeight = 16 * m_pFFData->getCheckboxHeight();
+
+ if (m_pFFData->getCheckboxAutoHeight())
+ {
+ uno::Reference<beans::XPropertySet> xTextRangeProps(xTextRange, uno::UNO_QUERY);
+
+ try
+ {
+ float fCheckBoxHeight = 0.0;
+ xTextRangeProps->getPropertyValue("CharHeight") >>= fCheckBoxHeight;
+ nCheckBoxHeight = static_cast<sal_uInt32>(floor(fCheckBoxHeight * 35.3));
+ }
+ catch (beans::UnknownPropertyException &)
+ {
+ }
+ }
+
+ m_pImpl->aSize.Width = nCheckBoxHeight;
+ m_pImpl->aSize.Height = m_pImpl->aSize.Width;
+
+ if (!m_pFFData->getStatusText().isEmpty())
+ {
+ xPropSet->setPropertyValue("HelpText", uno::Any(m_pFFData->getStatusText()));
+ }
+
+ xPropSet->setPropertyValue("DefaultState", uno::Any(m_pFFData->getCheckboxChecked()));
+
+ if (!m_pFFData->getHelpText().isEmpty())
+ {
+ xPropSet->setPropertyValue("HelpF1Text", uno::Any(m_pFFData->getHelpText()));
+ }
+
+ xPropSet->setPropertyValue("Name", uno::Any(rControlName));
+
+ return true;
+}
+
+void FormControlHelper::processField(uno::Reference<text::XFormField> const& xFormField)
+{
+ // Set field type first before adding parameters.
+ if (m_pImpl->m_eFieldId == FIELD_FORMTEXT )
+ {
+ xFormField->setFieldType(ODF_FORMTEXT);
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMCHECKBOX )
+ {
+ xFormField->setFieldType(ODF_FORMCHECKBOX);
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMDROPDOWN )
+ {
+ xFormField->setFieldType(ODF_FORMDROPDOWN);
+ }
+
+ uno::Reference<container::XNameContainer> xNameCont = xFormField->getParameters();
+ uno::Reference<container::XNamed> xNamed( xFormField, uno::UNO_QUERY );
+ if ( !(m_pFFData && xNamed.is() && xNameCont.is()) )
+ return;
+
+ OUString sTmp = m_pFFData->getEntryMacro();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "EntryMacro", uno::Any(sTmp) );
+ sTmp = m_pFFData->getExitMacro();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "ExitMacro", uno::Any(sTmp) );
+
+ sTmp = m_pFFData->getHelpText();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Help", uno::Any(sTmp) );
+
+ sTmp = m_pFFData->getStatusText();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Hint", uno::Any(sTmp) );
+
+ if (m_pImpl->m_eFieldId == FIELD_FORMTEXT )
+ {
+ sTmp = m_pFFData->getName();
+ try
+ {
+ if ( !sTmp.isEmpty() )
+ xNamed->setName( sTmp );
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter", "Set Formfield name failed");
+ }
+
+ sTmp = m_pFFData->getTextType();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Type", uno::Any(sTmp) );
+
+ const sal_uInt16 nMaxLength = m_pFFData->getTextMaxLength();
+ if ( nMaxLength )
+ {
+ xNameCont->insertByName( "MaxLength", uno::Any(nMaxLength) );
+ }
+
+ sTmp = m_pFFData->getTextDefault();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Content", uno::Any(sTmp) );
+
+ sTmp = m_pFFData->getTextFormat();
+ if ( !sTmp.isEmpty() )
+ xNameCont->insertByName( "Format", uno::Any(sTmp) );
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMCHECKBOX )
+ {
+ uno::Reference<beans::XPropertySet> xPropSet(xFormField, uno::UNO_QUERY);
+ uno::Any aAny;
+ aAny <<= m_pFFData->getCheckboxChecked();
+ if ( xPropSet.is() )
+ xPropSet->setPropertyValue("Checked", aAny);
+ }
+ else if (m_pImpl->m_eFieldId == FIELD_FORMDROPDOWN )
+ {
+ const FFDataHandler::DropDownEntries_t& rEntries = m_pFFData->getDropDownEntries();
+ if (!rEntries.empty())
+ {
+ if ( xNameCont->hasByName(ODF_FORMDROPDOWN_LISTENTRY) )
+ xNameCont->replaceByName(ODF_FORMDROPDOWN_LISTENTRY, uno::Any(comphelper::containerToSequence(rEntries)));
+ else
+ xNameCont->insertByName(ODF_FORMDROPDOWN_LISTENTRY, uno::Any(comphelper::containerToSequence(rEntries)));
+
+ sal_Int32 nResult = m_pFFData->getDropDownResult().toInt32();
+ // 0 is valid, but also how toInt32 reports parse error, but it's a sensible default...
+ if (0 <= nResult && o3tl::make_unsigned(nResult) < rEntries.size())
+ {
+ if ( xNameCont->hasByName(ODF_FORMDROPDOWN_RESULT) )
+ xNameCont->replaceByName(ODF_FORMDROPDOWN_RESULT, uno::Any( nResult ) );
+ else
+ xNameCont->insertByName(ODF_FORMDROPDOWN_RESULT, uno::Any( nResult ) );
+ }
+ }
+ }
+}
+
+void FormControlHelper::insertControl(uno::Reference<text::XTextRange> const& xTextRange)
+{
+ bool bCreated = false;
+ if ( !m_pFFData )
+ return;
+ uno::Reference<container::XNameContainer> xFormCompsByName(m_pImpl->getForm(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexContainer> xFormComps(m_pImpl->getFormComps());
+ if (! xFormComps.is())
+ return;
+
+ sal_Int32 nControl = 0;
+ bool bDone = false;
+ OUString sControlName;
+
+ do
+ {
+ OUString sTmp = "Control" + OUString::number(nControl);
+
+ nControl++;
+ if (! xFormCompsByName->hasByName(sTmp))
+ {
+ sControlName = sTmp;
+ bDone = true;
+ }
+ }
+ while (! bDone);
+
+ switch (m_pImpl->m_eFieldId)
+ {
+ case FIELD_FORMCHECKBOX:
+ bCreated = createCheckbox(xTextRange, sControlName);
+ break;
+ default:
+ break;
+ }
+
+ if (!bCreated)
+ return;
+
+ uno::Any aAny(m_pImpl->rFormComponent);
+ xFormComps->insertByIndex(xFormComps->getCount(), aAny);
+
+ if (! m_pImpl->getServiceFactory().is())
+ return;
+
+ uno::Reference<uno::XInterface> xInterface = m_pImpl->getServiceFactory()->createInstance("com.sun.star.drawing.ControlShape");
+
+ if (! xInterface.is())
+ return;
+
+ uno::Reference<drawing::XShape> xShape(xInterface, uno::UNO_QUERY);
+
+ if (! xShape.is())
+ return;
+
+ xShape->setSize(m_pImpl->aSize);
+
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+
+ sal_uInt16 nTmp = sal_uInt16(text::TextContentAnchorType_AS_CHARACTER);
+ xShapeProps->setPropertyValue("AnchorType", uno::Any(sal_uInt16(nTmp)));
+
+ nTmp = text::VertOrientation::CENTER;
+ xShapeProps->setPropertyValue("VertOrient", uno::Any(sal_uInt16(nTmp)));
+
+ xShapeProps->setPropertyValue("TextRange", uno::Any(xTextRange));
+
+ uno::Reference<drawing::XControlShape> xControlShape(xShape, uno::UNO_QUERY);
+ uno::Reference<awt::XControlModel> xControlModel(m_pImpl->rFormComponent, uno::UNO_QUERY);
+ xControlShape->setControl(xControlModel);
+
+ m_pImpl->getDrawPage()->add(xShape);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/FormControlHelper.hxx b/sw/source/writerfilter/dmapper/FormControlHelper.hxx
new file mode 100644
index 000000000000..326637f85f78
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/FormControlHelper.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "FFDataHandler.hxx"
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XFormField.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include "FieldTypes.hxx"
+
+namespace writerfilter::dmapper
+{
+class FormControlHelper : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<FormControlHelper> Pointer_t;
+ FormControlHelper(FieldId eFieldId,
+ css::uno::Reference<css::text::XTextDocument> const& rTextDocument,
+ FFDataHandler::Pointer_t pFFData);
+ ~FormControlHelper() override;
+
+ void insertControl(css::uno::Reference<css::text::XTextRange> const& xTextRange);
+ void processField(css::uno::Reference<css::text::XFormField> const& xFormField);
+ bool hasFFDataHandler() const { return (m_pFFData != nullptr); }
+
+private:
+ FFDataHandler::Pointer_t m_pFFData;
+ struct FormControlHelper_Impl;
+ tools::SvRef<FormControlHelper_Impl> m_pImpl;
+
+ bool createCheckbox(css::uno::Reference<css::text::XTextRange> const& xTextRange,
+ const OUString& rControlName);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/GraphicHelpers.cxx b/sw/source/writerfilter/dmapper/GraphicHelpers.cxx
new file mode 100644
index 000000000000..32e13b04bec8
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/GraphicHelpers.cxx
@@ -0,0 +1,434 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <comphelper/diagnose_ex.hxx>
+
+#include <iostream>
+
+namespace writerfilter::dmapper {
+
+using namespace com::sun::star;
+
+PositionHandler::PositionHandler( std::pair<OUString, OUString>& rPositionOffsets, std::pair<OUString, OUString>& rAligns ) :
+LoggedProperties("PositionHandler"),
+m_nOrient(text::VertOrientation::NONE),
+m_nRelation(text::RelOrientation::FRAME),
+m_nPosition(0),
+m_rPositionOffsets(rPositionOffsets),
+m_rAligns(rAligns)
+{
+}
+
+PositionHandler::~PositionHandler( )
+{
+}
+
+void PositionHandler::lcl_attribute( Id aName, Value& rVal )
+{
+ sal_Int32 nIntValue = rVal.getInt( );
+ switch ( aName )
+ {
+ case NS_ooxml::LN_CT_PosV_relativeFrom:
+ {
+ switch ( nIntValue )
+ {
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_margin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page:
+ m_nRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_topMargin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA_TOP;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_bottomMargin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA_BOTTOM;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_paragraph:
+ m_nRelation = text::RelOrientation::FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_line:
+ m_nRelation = text::RelOrientation::TEXT_LINE;
+ break;
+
+ // TODO There are some other unhandled values
+ default:
+ SAL_WARN("writerfilter", "unhandled case (" << nIntValue << ") in NS_ooxml::LN_CT_PosV_relativeFrom");
+ }
+ }
+ break;
+
+ case NS_ooxml::LN_CT_PosH_relativeFrom:
+ {
+ switch ( nIntValue )
+ {
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_margin:
+ m_nRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page:
+ m_nRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_insideMargin:
+ m_nRelation = text::RelOrientation::PAGE_FRAME;
+ m_bPageToggle = true;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_column:
+ m_nRelation = text::RelOrientation::FRAME;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_character:
+ m_nRelation = text::RelOrientation::CHAR;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_leftMargin:
+ m_nRelation = text::RelOrientation::PAGE_LEFT;
+ break;
+
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_rightMargin:
+ m_nRelation = text::RelOrientation::PAGE_RIGHT;
+ break;
+
+ // TODO There are some other unhandled values
+ default:
+ SAL_WARN("writerfilter", "unhandled case (" << nIntValue << ") in NS_ooxml::LN_CT_PosH_relativeFrom");
+ }
+ }
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+void PositionHandler::lcl_sprm(Sprm& rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_PosH_posOffset:
+ m_nPosition = oox::drawingml::convertEmuToHmm(m_rPositionOffsets.first.toInt32());
+ m_rPositionOffsets.first.clear();
+ break;
+ case NS_ooxml::LN_CT_PosV_posOffset:
+ m_nPosition = oox::drawingml::convertEmuToHmm(m_rPositionOffsets.second.toInt32());
+ m_rPositionOffsets.second.clear();
+ break;
+ case NS_ooxml::LN_CT_PosH_align:
+ {
+ OUString& rAlign = m_rAligns.first;
+ if (rAlign == "left")
+ m_nOrient = text::HoriOrientation::LEFT;
+ else if (rAlign == "right")
+ m_nOrient = text::HoriOrientation::RIGHT;
+ else if (rAlign == "center")
+ m_nOrient = text::HoriOrientation::CENTER;
+ else if (rAlign == "inside")
+ m_nOrient = text::HoriOrientation::INSIDE;
+ else if (rAlign == "outside")
+ m_nOrient = text::HoriOrientation::OUTSIDE;
+ rAlign.clear();
+ break;
+ }
+ case NS_ooxml::LN_CT_PosV_align:
+ {
+ OUString& rAlign = m_rAligns.second;
+ if (rAlign == "top")
+ m_nOrient = text::VertOrientation::TOP;
+ else if (rAlign == "bottom")
+ m_nOrient = text::VertOrientation::BOTTOM;
+ else if (rAlign == "center")
+ m_nOrient = text::VertOrientation::CENTER;
+ else if (rAlign == "inside" && m_nRelation == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
+ m_nOrient = text::VertOrientation::TOP;
+ else if (rAlign == "outside" && m_nRelation == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
+ m_nOrient = text::VertOrientation::BOTTOM;
+ rAlign.clear();
+ break;
+ }
+ }
+}
+
+sal_Int16 PositionHandler::orientation() const
+{
+ if( m_nRelation == text::RelOrientation::TEXT_LINE )
+ { // It appears that to 'line of text' alignment is backwards to other alignments,
+ // 'top' meaning putting on top of the line instead of having top at the line.
+ if( m_nOrient == text::VertOrientation::TOP )
+ return text::VertOrientation::BOTTOM;
+ else if( m_nOrient == text::VertOrientation::BOTTOM )
+ return text::VertOrientation::TOP;
+ }
+ return m_nOrient;
+}
+
+WrapHandler::WrapHandler( ) :
+LoggedProperties("WrapHandler"),
+ m_nType( 0 ),
+ m_nSide( 0 )
+{
+}
+
+WrapHandler::~WrapHandler( )
+{
+}
+
+void WrapHandler::lcl_attribute( Id aName, Value& rVal )
+{
+ switch ( aName )
+ {
+ case NS_ooxml::LN_CT_Wrap_type:
+ m_nType = sal_Int32( rVal.getInt( ) );
+ break;
+ case NS_ooxml::LN_CT_Wrap_side:
+ m_nSide = sal_Int32( rVal.getInt( ) );
+ break;
+ default:;
+ }
+}
+
+void WrapHandler::lcl_sprm( Sprm& )
+{
+}
+
+text::WrapTextMode WrapHandler::getWrapMode( ) const
+{
+ // The wrap values do not map directly to our wrap mode,
+ // e.g. none in .docx actually means through in LO.
+ text::WrapTextMode nMode = text::WrapTextMode_THROUGH;
+
+ switch ( m_nType )
+ {
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_square:
+ // through and tight are somewhat complicated, approximate
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_tight:
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_through:
+ {
+ switch ( m_nSide )
+ {
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapSide_left:
+ nMode = text::WrapTextMode_LEFT;
+ break;
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapSide_right:
+ nMode = text::WrapTextMode_RIGHT;
+ break;
+ default:
+ nMode = text::WrapTextMode_PARALLEL;
+ }
+ }
+ break;
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_topAndBottom:
+ nMode = text::WrapTextMode_NONE;
+ break;
+ case NS_ooxml::LN_Value_vml_wordprocessingDrawing_ST_WrapType_none:
+ default:
+ nMode = text::WrapTextMode_THROUGH;
+ }
+
+ return nMode;
+}
+
+
+void GraphicZOrderHelper::addItem(uno::Reference<beans::XPropertySet> const& props,
+ sal_Int64 const relativeHeight)
+{
+ m_items[ relativeHeight ] = props;
+}
+
+void GraphicZOrderHelper::adjustRelativeHeight(sal_Int64& rRelativeHeight, bool bIsZIndex,
+ bool bIsBehindText, bool bIsInHeader)
+{
+ // zOrder can be defined either by z-index (VML) or by relativeHeight (DML).
+ // z-index indicates background with a negative value,
+ // while relativeHeight indicates background with behindDoc = true.
+ //
+ // In general, all z-index-defined shapes appear on top of relativeHeight graphics
+ // regardless of the value.
+
+ // priority order
+ // above text: positive sal_Int32 z-index (opaque/in front of text)
+ // relativeHeight (represented here as a negative sal_Int32, but still opaque)
+ // behind body: negative sal_Int32 z-index (!opaque/in the background)
+ // behindText relativeHeight
+ // (in header) positive z-index
+ // (in header) relativeHeight
+ // (in header) negative z-index
+ // (in header) behindText
+
+ const sal_Int64 nMaxUnsignedInt32 = SAL_MAX_UINT32;
+ if (!bIsInHeader)
+ {
+ if (bIsZIndex)
+ {
+ // this number is already fine
+ // positive values are the only positive values coming into zOrder,
+ // and negative values will be !opaque (below text)
+ }
+ else if (!bIsBehindText)
+ {
+ assert (rRelativeHeight < 0);
+ // this number is already fine - will be above text, but relativeHeight is negative
+ }
+ else
+ {
+ // reduce to negative level 1 to force below a negative z-index
+ rRelativeHeight -= nMaxUnsignedInt32;
+ }
+ }
+ else // bIsInHeader
+ {
+ if (bIsZIndex && !bIsBehindText)
+ rRelativeHeight -= nMaxUnsignedInt32 * 2; // reduce to negative level 2
+ else if (!bIsBehindText)
+ rRelativeHeight -= nMaxUnsignedInt32 * 3; // reduce to negative level 3
+ else if (bIsZIndex)
+ rRelativeHeight -= nMaxUnsignedInt32 * 4; // reduce to negative level 4
+ else
+ rRelativeHeight -= nMaxUnsignedInt32 * 5; // reduce to negative level 5
+ }
+}
+
+// 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.
+
+// The key to this function is that later on, when setPropertyValue("ZOrder", <returned sal_Int32>),
+// SW also automatically increments ALL zOrders >= the one returned for this fly.
+// Thus, getProperty PROP_Z_ORDER for relativeHeight "x" can return different values for itemZOrder.
+sal_Int32 GraphicZOrderHelper::findZOrder(sal_Int64 relativeHeight, bool bOldStyle)
+{
+ // std::map is iterated sorted by key
+ auto it = std::find_if(m_items.cbegin(), m_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 == m_items.end()) // we're topmost
+ {
+ if( m_items.empty())
+ return 0; // the lowest
+ --it;
+ itemZOrderOffset = 1; // after the topmost
+
+ // Check if this shape has a textbox. If so, the textbox will have its own ZOrder, so
+ // suggest a larger offset.
+ bool bTextBox = false;
+ uno::Reference<beans::XPropertySet> xShape = it->second;
+ uno::Reference<beans::XPropertySetInfo> xInfo = xShape->getPropertySetInfo();
+ if (xInfo->hasPropertyByName("TextBox"))
+ {
+ xShape->getPropertyValue("TextBox") >>= bTextBox;
+ }
+ if (bTextBox)
+ {
+ ++itemZOrderOffset;
+ }
+ }
+ // SwXFrame::getPropertyValue throws uno::RuntimeException
+ // when its GetFrameFormat() returns nullptr
+ try {
+ sal_Int32 itemZOrder(0);
+ if( it->second->getPropertyValue(getPropertyName( PROP_Z_ORDER )) >>= itemZOrder )
+ return itemZOrder + itemZOrderOffset;
+ }
+ catch (const uno::RuntimeException&) {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Exception when getting item z-order");
+ }
+ SAL_WARN( "writerfilter", "findZOrder() didn't find item z-order" );
+ return 0; // this should not(?) happen
+}
+
+ExtentHandler::ExtentHandler()
+{
+}
+
+ExtentHandler::~ExtentHandler()
+{
+}
+
+void ExtentHandler::attribute(Id nName, Value & rValue)
+{
+ sal_Int32 nIntValue = rValue.getInt();
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_PositiveSize2D_cx:
+ {
+ m_Extent.Width = nIntValue;
+ }
+ break;
+ case NS_ooxml::LN_CT_PositiveSize2D_cy:
+ {
+ m_Extent.Height = nIntValue;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ExtentHandler::sprm(Sprm & rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_Inline_extent:
+ case NS_ooxml::LN_CT_Anchor_extent:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/GraphicHelpers.hxx b/sw/source/writerfilter/dmapper/GraphicHelpers.hxx
new file mode 100644
index 000000000000..21eb65f88402
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/GraphicHelpers.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/text/WrapTextMode.hpp>
+
+#include <utility>
+
+namespace writerfilter::dmapper
+{
+class PositionHandler : public LoggedProperties
+{
+public:
+ PositionHandler(std::pair<OUString, OUString>& rPositionOffsets,
+ std::pair<OUString, OUString>& rAligns);
+ virtual ~PositionHandler() override;
+ sal_Int16 orientation() const;
+ sal_Int16 relation() const { return m_nRelation; }
+ sal_Int32 position() const { return m_nPosition; }
+ bool GetPageToggle() const { return m_bPageToggle; }
+
+private:
+ virtual void lcl_attribute(Id aName, Value& rVal) override;
+ virtual void lcl_sprm(Sprm& rSprm) override;
+ sal_Int16 m_nOrient;
+ sal_Int16 m_nRelation;
+ sal_Int32 m_nPosition;
+ std::pair<OUString, OUString>& m_rPositionOffsets;
+ std::pair<OUString, OUString>& m_rAligns;
+ bool m_bPageToggle = false;
+};
+
+class WrapHandler : public LoggedProperties
+{
+public:
+ WrapHandler();
+ virtual ~WrapHandler() override;
+
+ css::text::WrapTextMode getWrapMode() const;
+
+private:
+ virtual void lcl_attribute(Id aName, Value& rVal) override;
+ virtual void lcl_sprm(Sprm& rSprm) override;
+
+ sal_Int32 m_nType;
+ sal_Int32 m_nSide;
+};
+
+class ExtentHandler : public Properties
+{
+ css::awt::Size m_Extent; // width and height in EMU
+
+public:
+ typedef ::tools::SvRef<ExtentHandler> Pointer_t;
+ explicit ExtentHandler();
+ virtual ~ExtentHandler() override;
+
+ virtual void attribute(Id nName, Value& rValue) override;
+ virtual void sprm(Sprm& rSprm) override;
+ css::awt::Size getExtent() const { return m_Extent; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/GraphicImport.cxx b/sw/source/writerfilter/dmapper/GraphicImport.cxx
new file mode 100644
index 000000000000..2df2569530a1
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/GraphicImport.cxx
@@ -0,0 +1,2118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/XGraphicProvider.hpp>
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/XTextContent.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdtrans.hxx>
+#include <svx/unoapi.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <rtl/math.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/sequence.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+
+#include "DomainMapper.hxx"
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <ooxml/resourceids.hxx>
+
+#include "ConversionHelper.hxx"
+#include "GraphicHelpers.hxx"
+#include "GraphicImport.hxx"
+#include "PropertyMap.hxx"
+#include "TagLogger.hxx"
+#include "WrapPolygonHandler.hxx"
+#include "util.hxx"
+
+#include <comphelper/propertysequence.hxx>
+#include <algorithm>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <oox/export/drawingml.hxx>
+#include <utility>
+
+using namespace css;
+
+namespace
+{
+bool isTopGroupObj(const uno::Reference<drawing::XShape>& xShape)
+{
+ SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape);
+ if (!pObject)
+ return false;
+
+ if (pObject->getParentSdrObjectFromSdrObject())
+ return false;
+
+ return pObject->IsGroupObject();
+}
+}
+
+namespace writerfilter::dmapper
+{
+
+namespace {
+
+class XInputStreamHelper : public cppu::WeakImplHelper<io::XInputStream>
+{
+ const sal_uInt8* m_pBuffer;
+ const sal_Int32 m_nLength;
+ sal_Int32 m_nPosition;
+public:
+ XInputStreamHelper(const sal_uInt8* buf, size_t len);
+
+ virtual ::sal_Int32 SAL_CALL readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) override;
+ virtual ::sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) override;
+ virtual ::sal_Int32 SAL_CALL available( ) override;
+ virtual void SAL_CALL closeInput( ) override;
+};
+
+}
+
+XInputStreamHelper::XInputStreamHelper(const sal_uInt8* buf, size_t len) :
+ m_pBuffer( buf ),
+ m_nLength( len ),
+ m_nPosition( 0 )
+{
+}
+
+sal_Int32 XInputStreamHelper::readBytes( uno::Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead )
+{
+ return readSomeBytes( aData, nBytesToRead );
+}
+
+sal_Int32 XInputStreamHelper::readSomeBytes( uno::Sequence<sal_Int8>& aData, sal_Int32 nMaxBytesToRead )
+{
+ sal_Int32 nRet = 0;
+ if( nMaxBytesToRead > 0 )
+ {
+ if( nMaxBytesToRead > m_nLength - m_nPosition )
+ nRet = m_nLength - m_nPosition;
+ else
+ nRet = nMaxBytesToRead;
+ aData.realloc( nRet );
+ sal_Int8* pData = aData.getArray();
+ if( nRet )
+ {
+ memcpy( pData, m_pBuffer + m_nPosition, nRet );
+ m_nPosition += nRet;
+ }
+ }
+ return nRet;
+}
+
+
+void XInputStreamHelper::skipBytes( sal_Int32 nBytesToSkip )
+{
+ if( nBytesToSkip < 0 || m_nPosition + nBytesToSkip > m_nLength)
+ throw io::BufferSizeExceededException();
+ m_nPosition += nBytesToSkip;
+}
+
+
+sal_Int32 XInputStreamHelper::available( )
+{
+ return m_nLength - m_nPosition;
+}
+
+
+void XInputStreamHelper::closeInput( )
+{
+}
+
+namespace {
+
+struct GraphicBorderLine
+{
+ sal_Int32 nLineWidth;
+ bool bHasShadow;
+
+ GraphicBorderLine() :
+ nLineWidth(0)
+ ,bHasShadow(false)
+ {}
+
+ bool isEmpty() const
+ {
+ return nLineWidth == 0 && !bHasShadow;
+ }
+
+};
+
+}
+
+class GraphicImport_Impl
+{
+private:
+ sal_Int32 m_nXSize;
+ bool m_bXSizeValid;
+ sal_Int32 m_nYSize;
+ bool m_bYSizeValid;
+
+public:
+ GraphicImportType & m_rGraphicImportType;
+ DomainMapper& m_rDomainMapper;
+
+ sal_Int32 m_nLeftPosition;
+ sal_Int32 m_nTopPosition;
+
+ bool m_bUseSimplePos;
+ std::optional<sal_Int64> m_oZOrder;
+
+ sal_Int16 m_nHoriOrient;
+ sal_Int16 m_nHoriRelation;
+ bool m_bPageToggle = false;
+ sal_Int16 m_nVertOrient;
+ sal_Int16 m_nVertRelation;
+ text::WrapTextMode m_nWrap;
+ bool m_bLayoutInCell;
+ bool m_bCompatForcedLayoutInCell;
+ bool m_bAllowOverlap = true;
+
+ // Opaque means not in the background (but instead, the graphic will be over top of the text)
+ // This flag holds where LO will ACTUALLY put the graphic
+ bool m_bOpaque;
+ // BehindDoc means in the background. This flag says the graphic REQUESTED to be behind the text
+ bool m_bBehindDoc;
+
+ bool m_bContour;
+ bool m_bContourOutside;
+ WrapPolygon::Pointer_t mpWrapPolygon;
+
+ sal_Int32 m_nLeftMargin;
+ sal_Int32 m_nLeftMarginOrig = 0;
+ sal_Int32 m_nRightMargin;
+ sal_Int32 m_nTopMargin;
+ sal_Int32 m_nBottomMargin;
+
+ bool m_bShadow;
+ sal_Int32 m_nShadowXDistance;
+ sal_Int32 m_nShadowYDistance;
+ sal_Int32 m_nShadowColor;
+ sal_Int32 m_nShadowTransparence;
+
+ sal_Int32 m_nContrast;
+ sal_Int32 m_nBrightness;
+
+ static constexpr sal_Int32 nFillColor = 0xffffffff;
+
+ drawing::ColorMode m_eColorMode;
+
+ GraphicBorderLine m_aBorders[4];
+
+ bool m_bIsGraphic;
+
+ bool m_bSizeProtected;
+ bool m_bPositionProtected;
+ bool m_bHidden;
+ bool m_bDecorative = false;
+
+ sal_Int32 m_nShapeOptionType;
+
+ OUString m_sName;
+ OUString m_sAlternativeText;
+ OUString m_title;
+ OUString m_sHyperlinkURL;
+ std::pair<OUString, OUString>& m_rPositionOffsets;
+ std::pair<OUString, OUString>& m_rAligns;
+ std::queue<OUString>& m_rPositivePercentages;
+ OUString m_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;
+ std::optional<text::GraphicCrop> m_oCrop;
+
+ GraphicImport_Impl(GraphicImportType & rImportType, DomainMapper& rDMapper,
+ std::pair<OUString, OUString>& rPositionOffsets,
+ std::pair<OUString, OUString>& rAligns,
+ std::queue<OUString>& rPositivePercentages)
+ : m_nXSize(0)
+ ,m_bXSizeValid(false)
+ ,m_nYSize(0)
+ ,m_bYSizeValid(false)
+ ,m_rGraphicImportType(rImportType)
+ ,m_rDomainMapper( rDMapper )
+ ,m_nLeftPosition(0)
+ ,m_nTopPosition(0)
+ ,m_bUseSimplePos(false)
+ ,m_nHoriOrient( text::HoriOrientation::NONE )
+ ,m_nHoriRelation( text::RelOrientation::FRAME )
+ ,m_nVertOrient( text::VertOrientation::NONE )
+ ,m_nVertRelation( text::RelOrientation::FRAME )
+ ,m_nWrap(text::WrapTextMode_NONE)
+ ,m_bLayoutInCell(true)
+ ,m_bCompatForcedLayoutInCell(false)
+ ,m_bOpaque( !rDMapper.IsInHeaderFooter() )
+ ,m_bBehindDoc(false)
+ ,m_bContour(false)
+ ,m_bContourOutside(true)
+ ,m_nLeftMargin(319)
+ ,m_nRightMargin(319)
+ ,m_nTopMargin(0)
+ ,m_nBottomMargin(0)
+ ,m_bShadow(false)
+ ,m_nShadowXDistance(0)
+ ,m_nShadowYDistance(0)
+ ,m_nShadowColor(0)
+ ,m_nShadowTransparence(0)
+ ,m_nContrast(0)
+ ,m_nBrightness(0)
+ ,m_eColorMode( drawing::ColorMode_STANDARD )
+ ,m_bIsGraphic(false)
+ ,m_bSizeProtected(false)
+ ,m_bPositionProtected(false)
+ ,m_bHidden(false)
+ ,m_nShapeOptionType(0)
+ ,m_rPositionOffsets(rPositionOffsets)
+ ,m_rAligns(rAligns)
+ ,m_rPositivePercentages(rPositivePercentages)
+ {
+ }
+
+ void setXSize(sal_Int32 _nXSize)
+ {
+ m_nXSize = _nXSize;
+ m_bXSizeValid = true;
+ }
+
+ sal_uInt32 getXSize() const
+ {
+ return m_nXSize;
+ }
+
+ bool isXSizeValid() const
+ {
+ return m_bXSizeValid;
+ }
+
+ void setYSize(sal_Int32 _nYSize)
+ {
+ m_nYSize = _nYSize;
+ m_bYSizeValid = true;
+ }
+
+ sal_uInt32 getYSize() const
+ {
+ return m_nYSize;
+ }
+
+ bool isYSizeValid() const
+ {
+ return m_bYSizeValid;
+ }
+
+ void applyMargins(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ), uno::Any(m_nLeftMargin));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ), uno::Any(m_nRightMargin));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ), uno::Any(m_nTopMargin));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ), uno::Any(m_nBottomMargin));
+ }
+
+ void applyPosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT ),
+ uno::Any(m_nHoriOrient));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT ),
+ uno::Any(m_nVertOrient));
+ }
+
+ void applyRelativePosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties, bool bRelativeOnly = false) const
+ {
+ if (!bRelativeOnly)
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_POSITION),
+ uno::Any(m_nLeftPosition));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_RELATION ),
+ uno::Any(m_nHoriRelation));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_PAGE_TOGGLE),
+ uno::Any(m_bPageToggle));
+ if (!bRelativeOnly)
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_POSITION),
+ uno::Any(m_nTopPosition));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_RELATION ),
+ uno::Any(m_nVertRelation));
+ }
+
+ void applyZOrder(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const
+ {
+ std::optional<sal_Int64> oZOrder = m_oZOrder;
+ if (m_rGraphicImportType == GraphicImportType::IMPORT_AS_DETECTED_INLINE
+ && !m_rDomainMapper.IsInShape())
+ {
+ oZOrder = SAL_MIN_INT64;
+ }
+ else if (!oZOrder)
+ return;
+ else
+ {
+ const bool bBehindText = m_bBehindDoc && !m_bOpaque;
+ GraphicZOrderHelper::adjustRelativeHeight(*oZOrder, /*IsZIndex=*/false, bBehindText,
+ m_rDomainMapper.IsInHeaderFooter());
+ }
+
+ // TODO: it is possible that RTF has been wrong all along as well. Always true here?
+ const bool bLastDuplicateWins(!m_rDomainMapper.IsRTFImport()
+ || m_rGraphicImportType == GraphicImportType::IMPORT_AS_DETECTED_INLINE);
+
+ GraphicZOrderHelper& rZOrderHelper = m_rDomainMapper.graphicZOrderHelper();
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_Z_ORDER),
+ uno::Any(rZOrderHelper.findZOrder(*oZOrder, bLastDuplicateWins)));
+ rZOrderHelper.addItem(xGraphicObjectProperties, *oZOrder);
+ }
+
+ void applyName(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const
+ {
+ try
+ {
+ if (!m_sName.isEmpty())
+ {
+ uno::Reference<container::XNamed> const xNamed(xGraphicObjectProperties, uno::UNO_QUERY_THROW);
+ xNamed->setName(m_sName);
+ }
+ // else: name is automatically generated by SwDoc::MakeFlySection_()
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_DESCRIPTION ),
+ uno::Any( m_sAlternativeText ));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TITLE ),
+ uno::Any( m_title ));
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "failed");
+ }
+ }
+
+ void applyHyperlink(uno::Reference<beans::XPropertySet> const & xShapeProps, bool bIsShape)
+ {
+ // Graphic objects have a different hyperlink prop than shapes
+ auto aHyperlinkProp = bIsShape ? PROP_HYPERLINK : PROP_HYPER_LINK_U_R_L;
+ if (!m_sHyperlinkURL.isEmpty())
+ {
+ xShapeProps->setPropertyValue(
+ getPropertyName(aHyperlinkProp), uno::Any(m_sHyperlinkURL));
+ }
+ }
+
+ /// Getter for m_aInteropGrabBag, but also merges in the values from other members if they are set.
+ comphelper::SequenceAsHashMap const & getInteropGrabBag()
+ {
+ comphelper::SequenceAsHashMap aEffectExtent;
+ if (m_oEffectExtentLeft)
+ aEffectExtent["l"] <<= *m_oEffectExtentLeft;
+ if (m_oEffectExtentTop)
+ aEffectExtent["t"] <<= *m_oEffectExtentTop;
+ if (m_oEffectExtentRight)
+ aEffectExtent["r"] <<= *m_oEffectExtentRight;
+ if (m_oEffectExtentBottom)
+ aEffectExtent["b"] <<= *m_oEffectExtentBottom;
+ if (!aEffectExtent.empty())
+ m_aInteropGrabBag["CT_EffectExtent"] <<= aEffectExtent.getAsConstPropertyValueList();
+ return m_aInteropGrabBag;
+ }
+};
+
+GraphicImport::GraphicImport(uno::Reference<uno::XComponentContext> xComponentContext,
+ uno::Reference<lang::XMultiServiceFactory> xTextFactory,
+ DomainMapper& rDMapper,
+ GraphicImportType & rImportType,
+ 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(rImportType, rDMapper, rPositionOffsets, rAligns, rPositivePercentages))
+, m_xComponentContext(std::move(xComponentContext))
+, m_xTextFactory(std::move(xTextFactory))
+{
+}
+
+GraphicImport::~GraphicImport()
+{
+}
+
+com::sun::star::awt::Point GraphicImport::GetGraphicObjectPosition() const
+{
+ return (com::sun::star::awt::Point(m_pImpl->m_nLeftPosition, m_pImpl->m_nTopPosition));
+}
+
+bool GraphicImport::GetLayoutInCell() const
+{
+ return m_pImpl->m_bLayoutInCell;
+}
+
+void GraphicImport::handleWrapTextValue(sal_uInt32 nVal)
+{
+ switch (nVal)
+ {
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides:
+ m_pImpl->m_nWrap = text::WrapTextMode_PARALLEL;
+ break;
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left:
+ m_pImpl->m_nWrap = text::WrapTextMode_LEFT;
+ break;
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right:
+ m_pImpl->m_nWrap = text::WrapTextMode_RIGHT;
+ break;
+ case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest:
+ m_pImpl->m_nWrap = text::WrapTextMode_DYNAMIC;
+ break;
+ default:;
+ }
+}
+
+void GraphicImport::putPropertyToFrameGrabBag( const OUString& sPropertyName, const uno::Any& aPropertyValue )
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = sPropertyName;
+ aProperty.Value = aPropertyValue;
+
+ if (!m_xShape.is())
+ return;
+
+ uno::Reference< beans::XPropertySet > xSet(m_xShape, uno::UNO_QUERY_THROW);
+
+ uno::Reference< beans::XPropertySetInfo > xSetInfo(xSet->getPropertySetInfo());
+ if (!xSetInfo.is())
+ return;
+
+ OUString aGrabBagPropName;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
+ if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ aGrabBagPropName = "FrameInteropGrabBag";
+ else
+ aGrabBagPropName = "InteropGrabBag";
+
+ if (xSetInfo->hasPropertyByName(aGrabBagPropName))
+ {
+ //Add pProperty to the end of the Sequence for aGrabBagPropName
+ uno::Sequence<beans::PropertyValue> aTmp;
+ xSet->getPropertyValue(aGrabBagPropName) >>= aTmp;
+ std::vector<beans::PropertyValue> aGrabBag(comphelper::sequenceToContainer<std::vector<beans::PropertyValue> >(aTmp));
+ aGrabBag.push_back(aProperty);
+
+ xSet->setPropertyValue(aGrabBagPropName, uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+}
+
+static bool lcl_bHasGroupSlantedChild(const SdrObject* pObj)
+{
+ // Returns true, if a child object differs more than 0.02deg from horizontal or vertical.
+ // Because lines sometimes are imported as customshapes, a horizontal or vertical line
+ // might not have exactly 0, 90, 180, or 270 degree as rotate angle.
+ if (!pObj)
+ return false;
+ if (!pObj->IsGroupObject())
+ return false;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if (!pSubList)
+ return false;
+ SdrObjListIter aIterator(pSubList, SdrIterMode::DeepNoGroups);
+ while (aIterator.IsMore())
+ {
+ const SdrObject* pSubObj = aIterator.Next();
+ const Degree100 nRotateAngle = NormAngle36000(pSubObj->GetRotateAngle());
+ const sal_uInt16 nRot = nRotateAngle.get();
+ if ((3 < nRot && nRot < 8997) || (9003 < nRot && nRot < 17997)
+ || (18003 < nRot && nRot < 26997) || (27003 < nRot && nRot < 35997))
+ return true;
+ }
+ return false;
+}
+
+void GraphicImport::lcl_correctWord2007EffectExtent(const sal_Int32 nMSOAngle)
+{
+ // Word versions older than 14 do not swap width and height (see lcl_doMSOWidthHeightSwap)
+ // and therefore generate different effectExtent. We correct them here.
+ sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
+ if (nAngleDeg < 45 || nAngleDeg >= 135)
+ return;
+
+ sal_Int32 nDiff = o3tl::convert(
+ (double(m_pImpl->getXSize()) - double(m_pImpl->getYSize())) / 2.0,
+ o3tl::Length::mm100, o3tl::Length::emu);
+ if (m_pImpl->m_oEffectExtentLeft)
+ *m_pImpl->m_oEffectExtentLeft += nDiff;
+ if (m_pImpl->m_oEffectExtentRight)
+ *m_pImpl->m_oEffectExtentRight += nDiff;
+ if (m_pImpl->m_oEffectExtentTop)
+ *m_pImpl->m_oEffectExtentTop -= nDiff;
+ if (m_pImpl->m_oEffectExtentBottom)
+ *m_pImpl->m_oEffectExtentBottom -= nDiff;
+}
+
+static void lcl_doMSOWidthHeightSwap(awt::Point& rLeftTop, awt::Size& rSize,
+ const sal_Int32 nMSOAngle)
+{
+ if (nMSOAngle == 0)
+ return;
+ // convert nMSOAngle to degree in [0°,180°[
+ sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
+ if (nAngleDeg >= 45 && nAngleDeg < 135)
+ {
+ // keep center of rectangle given in rLeftTop and rSize
+ sal_Int32 aTemp = rSize.Width - rSize.Height;
+ rLeftTop.X += aTemp / 2;
+ rLeftTop.Y -= aTemp / 2;
+ std::swap(rSize.Width, rSize.Height);
+ }
+ return;
+}
+
+void GraphicImport::lcl_expandRectangleByEffectExtent(awt::Point& rLeftTop, awt::Size& rSize)
+{
+ sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
+ : 0;
+ rLeftTop.X -= nEffectExtent;
+ rSize.Width += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentRight)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight)
+ : 0;
+ rSize.Width += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentTop)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop)
+ : 0;
+ rLeftTop.Y -= nEffectExtent;
+ rSize.Height += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom)
+ : 0;
+ rSize.Height += nEffectExtent;
+}
+
+void GraphicImport::lcl_attribute(Id nName, Value& rValue)
+{
+ sal_Int32 nIntValue = rValue.getInt();
+ switch( nName )
+ {
+ case NS_ooxml::LN_OfficeArtExtension_Decorative_val:
+ m_pImpl->m_bDecorative = true;
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_URL:
+ m_pImpl->m_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->m_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->m_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:
+ //id of the object - ignored
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_name:
+ //name of the object
+ m_pImpl->m_sName = rValue.getString();
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_descr:
+ //alternative text
+ m_pImpl->m_sAlternativeText = rValue.getString();
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_title:
+ //alternative text
+ m_pImpl->m_title = rValue.getString();
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_hidden:
+ m_pImpl->m_bHidden = (nIntValue == 1);
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noChangeAspect:
+ //disallow aspect ratio change - ignored
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noMove:
+ m_pImpl->m_bPositionProtected = true;
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noResize:
+ m_pImpl->m_bSizeProtected = true;
+ break;
+ case NS_ooxml::LN_CT_Anchor_distT:
+ case NS_ooxml::LN_CT_Anchor_distB:
+ case NS_ooxml::LN_CT_Anchor_distL:
+ case NS_ooxml::LN_CT_Anchor_distR:
+ {
+ m_pImpl->m_nShapeOptionType = nName;
+ ProcessShapeOptions(rValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_simplePos_attr:
+ m_pImpl->m_bUseSimplePos = nIntValue > 0;
+ break;
+ case NS_ooxml::LN_CT_Anchor_relativeHeight: // unsigned content
+ {
+ // undocumented - based on testing: both 0 and 1 are equivalent to the maximum 503316479
+ const sal_Int32 nMaxAllowed = 0x1DFFFFFF;
+ if (nIntValue < 2 || nIntValue > nMaxAllowed)
+ m_pImpl->m_oZOrder = nMaxAllowed;
+ else
+ m_pImpl->m_oZOrder = nIntValue;
+
+ // all relativeHeight objects (i.e. DOCX graphics that use GraphicImport),
+ // no matter how high their value, are below the lowest z-index shape (in same layer)
+ // so emulate that by pretending that they are below text (in the hell-layer).
+ // Please be assured that this does not actually place it in the hell-layer.
+ m_pImpl->m_oZOrder = *m_pImpl->m_oZOrder - (nMaxAllowed + 1);
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_behindDoc:
+ if (nIntValue > 0)
+ {
+ m_pImpl->m_bOpaque = false;
+ m_pImpl->m_bBehindDoc = true;
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_locked:
+ break;
+ case NS_ooxml::LN_CT_Anchor_layoutInCell:
+ // Starting in MSO 2013, anchors are ALWAYS considered to be laid out in table cell.
+ m_pImpl->m_bCompatForcedLayoutInCell = !nIntValue
+ && m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14
+ && m_pImpl->m_rDomainMapper.IsInTable();
+ m_pImpl->m_bLayoutInCell = m_pImpl->m_bCompatForcedLayoutInCell || nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Anchor_hidden:
+ break;
+ case NS_ooxml::LN_CT_Anchor_allowOverlap:
+ m_pImpl->m_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->m_sAnchorId = aString.makeStringAndClear().toAsciiUpperCase();
+ }
+ break;
+ case NS_ooxml::LN_CT_Point2D_x:
+ m_pImpl->m_nLeftPosition = ConversionHelper::convertTwipToMM100(nIntValue);
+ m_pImpl->m_nHoriRelation = text::RelOrientation::PAGE_FRAME;
+ m_pImpl->m_nHoriOrient = text::HoriOrientation::NONE;
+ break;
+ case NS_ooxml::LN_CT_Point2D_y:
+ m_pImpl->m_nTopPosition = ConversionHelper::convertTwipToMM100(nIntValue);
+ m_pImpl->m_nVertRelation = text::RelOrientation::PAGE_FRAME;
+ m_pImpl->m_nVertOrient = text::VertOrientation::NONE;
+ break;
+ case NS_ooxml::LN_CT_WrapTight_wrapText:
+ m_pImpl->m_bContour = true;
+ m_pImpl->m_bContourOutside = true;
+
+ handleWrapTextValue(rValue.getInt());
+
+ break;
+ case NS_ooxml::LN_CT_WrapThrough_wrapText:
+ m_pImpl->m_bContour = true;
+ m_pImpl->m_bContourOutside = false;
+
+ handleWrapTextValue(rValue.getInt());
+
+ break;
+ case NS_ooxml::LN_CT_WrapSquare_wrapText:
+ handleWrapTextValue(rValue.getInt());
+ break;
+ case NS_ooxml::LN_CT_BlipFillProperties_srcRect:
+ m_pImpl->m_oCrop.emplace(rValue.getAny().get<text::GraphicCrop>());
+ break;
+ case NS_ooxml::LN_shape:
+ {
+ uno::Reference< drawing::XShape> xShape;
+ rValue.getAny( ) >>= xShape;
+ if ( xShape.is( ) )
+ {
+ // Is it a graphic image
+ bool bUseShape = true;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps
+ ( xShape, uno::UNO_QUERY_THROW );
+
+ uno::Reference<graphic::XGraphic> xGraphic;
+ xShapeProps->getPropertyValue("Graphic") >>= xGraphic;
+
+ sal_Int32 nRotation = 0;
+ xShapeProps->getPropertyValue("RotateAngle") >>= nRotation;
+
+ css::beans::PropertyValues aGrabBag;
+ xShapeProps->getPropertyValue("InteropGrabBag") >>= aGrabBag;
+ // if the shape contains effects in the grab bag, we should not transform it
+ // in a XTextContent so those effects can be preserved
+ bool bContainsEffects = std::any_of(std::cbegin(aGrabBag), std::cend(aGrabBag), [](const auto& rProp) {
+ return rProp.Name == "EffectProperties"
+ || rProp.Name == "3DEffectProperties"
+ || rProp.Name == "ArtisticEffectProperties";
+ });
+
+ xShapeProps->getPropertyValue("Shadow") >>= m_pImpl->m_bShadow;
+ if (m_pImpl->m_bShadow)
+ {
+ xShapeProps->getPropertyValue("ShadowXDistance") >>= m_pImpl->m_nShadowXDistance;
+ xShapeProps->getPropertyValue("ShadowYDistance") >>= m_pImpl->m_nShadowYDistance;
+ xShapeProps->getPropertyValue("ShadowColor") >>= m_pImpl->m_nShadowColor;
+ xShapeProps->getPropertyValue("ShadowTransparence") >>= m_pImpl->m_nShadowTransparence;
+ }
+
+ xShapeProps->getPropertyValue("GraphicColorMode") >>= m_pImpl->m_eColorMode;
+ xShapeProps->getPropertyValue("AdjustLuminance") >>= m_pImpl->m_nBrightness;
+ xShapeProps->getPropertyValue("AdjustContrast") >>= m_pImpl->m_nContrast;
+
+ // fdo#70457: transform XShape into a SwXTextGraphicObject only if there's no rotation
+ if ( nRotation == 0 && !bContainsEffects )
+ m_xGraphicObject = createGraphicObject( xGraphic, xShapeProps );
+
+ bUseShape = !m_xGraphicObject.is( );
+
+ if ( !bUseShape )
+ {
+ // Define the object size
+ uno::Reference< beans::XPropertySet > xGraphProps( m_xGraphicObject,
+ uno::UNO_QUERY );
+ awt::Size aSize = xShape->getSize( );
+ xGraphProps->setPropertyValue("Height",
+ uno::Any( aSize.Height ) );
+ xGraphProps->setPropertyValue("Width",
+ uno::Any( aSize.Width ) );
+
+ text::GraphicCrop aGraphicCrop( 0, 0, 0, 0 );
+ uno::Reference< beans::XPropertySet > xSourceGraphProps( xShape, uno::UNO_QUERY );
+ uno::Any aAny = xSourceGraphProps->getPropertyValue("GraphicCrop");
+ if (m_pImpl->m_oCrop)
+ { // RTF: RTFValue from resolvePict()
+ xGraphProps->setPropertyValue("GraphicCrop",
+ uno::Any(*m_pImpl->m_oCrop));
+ }
+ else if (aAny >>= aGraphicCrop)
+ { // DOCX: imported in oox BlipFillContext
+ xGraphProps->setPropertyValue("GraphicCrop",
+ uno::Any( aGraphicCrop ) );
+ }
+
+ // We need to drop the shape here somehow
+ uno::Reference< lang::XComponent > xShapeComponent( xShape, uno::UNO_QUERY );
+ xShapeComponent->dispose( );
+ }
+ }
+ catch( const beans::UnknownPropertyException & )
+ {
+ // It isn't a graphic image
+ }
+
+ if ( bUseShape )
+ m_xShape = xShape;
+
+ if ( m_xShape.is( ) )
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps
+ (m_xShape, uno::UNO_QUERY_THROW);
+
+
+ xShapeProps->setPropertyValue
+ (getPropertyName(PROP_ANCHOR_TYPE),
+ uno::Any
+ (text::TextContentAnchorType_AS_CHARACTER));
+
+ // In Word, if a shape is anchored inline, that
+ // excludes being in the background.
+ xShapeProps->setPropertyValue("Opaque", uno::Any(true));
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
+
+ // TextFrames can't be rotated. But for anything else,
+ // make sure that setting size doesn't affect rotation,
+ // that would not match Word's definition of rotation.
+ bool bKeepRotation = false;
+ if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ {
+ bKeepRotation = true;
+ xShapeProps->setPropertyValue
+ (getPropertyName(PROP_TEXT_RANGE),
+ uno::Any
+ (m_pImpl->m_rDomainMapper.GetCurrentTextRange()));
+ }
+
+ awt::Size aSize(m_xShape->getSize());
+
+ // One purpose of the next part is, to set the logic rectangle of the SdrObject
+ // to nXSize and nYSize from import. That doesn't work for groups or lines,
+ // because they do not have a logic rectangle and m_xShape->getSize and
+ // m_xShape->setSize would work on the snap rectangle. In case a shape is
+ // rotated, non-uniform scaling the snap rectangle will introduce shearing on
+ // the shape. In case group or line is rotated, nXSize and nYSize contain the
+ // unrotated size from oox. The rotation is already incorporated into group
+ // children and line points. We must not scale them to unrotated size. Exclude
+ // those shapes here.
+
+ // Get MSO rotation angle. GetRotateAngle from SdrObject is not suitable
+ // here, because it returns the rotate angle of the first child for groups
+ // and slope angle for lines, even if line or group had not been rotated.
+ // Import in oox has put the rotation from oox file into InteropGrabBag.
+ comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
+ sal_Int32 nOOXAngle(0);
+ aInteropGrabBag.getValue("mso-rotation-angle") >>= nOOXAngle; // 1/60000 deg
+ // tdf#143455: A diagram is imported as group, but has no valid object list
+ // and contour wrap is different to Word. As workaround diagrams are excluded
+ // here in various places.
+ const SdrObject* pDiagramCandidate(SdrObject::getSdrObjectFromXShape(m_xShape));
+ const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram());
+ // tdf#143476: A lockedCanvas (Word2007) is imported as group, but has not
+ // got size and position. Values from m_Impl has to be used.
+ bool bIsLockedCanvas(false);
+ aInteropGrabBag.getValue("LockedCanvas") >>= bIsLockedCanvas;
+ bool bIsWordprocessingCanvas(false);
+ aInteropGrabBag.getValue("WordprocessingCanvas") >>= bIsWordprocessingCanvas;
+ const bool bIsGroupOrLine = (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape")
+ && !bIsDiagram && !bIsLockedCanvas && !bIsWordprocessingCanvas)
+ || xServiceInfo->supportsService("com.sun.star.drawing.LineShape");
+ SdrObject* pShape = SdrObject::getSdrObjectFromXShape(m_xShape);
+ if (!bIsGroupOrLine || (!nOOXAngle && !lcl_bHasGroupSlantedChild(pShape)))
+ {
+ if (m_pImpl->isXSizeValid())
+ aSize.Width = m_pImpl->getXSize();
+ if (m_pImpl->isYSizeValid())
+ aSize.Height = m_pImpl->getYSize();
+ }
+
+ Degree100 nRotation;
+ if (bKeepRotation)
+ {
+ // Use internal API, getPropertyValue("RotateAngle")
+ // would use GetObjectRotation(), which is not what
+ // we want.
+ if (pShape)
+ nRotation = pShape->GetRotateAngle();
+ }
+
+ // tdf#157960: SdrEdgeObj::NbcResize would reset the adjustment values of
+ // connectors to default zero. Thus we do not resize in case of a group that
+ // represents a Word drawing canvas.
+ if (!bIsWordprocessingCanvas)
+ m_xShape->setSize(aSize);
+
+ if (bKeepRotation)
+ {
+ xShapeProps->setPropertyValue("RotateAngle", uno::Any(nRotation.get()));
+ }
+
+ m_pImpl->m_bIsGraphic = true;
+
+ if (!m_pImpl->m_sAnchorId.isEmpty())
+ {
+ putPropertyToFrameGrabBag("AnchorId", uno::Any(m_pImpl->m_sAnchorId));
+ }
+
+ // Calculate mso unrotated rectangle and its center, needed below
+ awt::Size aImportSize(m_xShape->getSize()); // here only fallback
+ if (m_pImpl->isXSizeValid())
+ aImportSize.Width = m_pImpl->getXSize(); // Hmm
+ if (m_pImpl->isYSizeValid())
+ aImportSize.Height = m_pImpl->getYSize(); // Hmm
+ const awt::Point aImportPosition(GetGraphicObjectPosition()); // Hmm
+ double fCentrumX = aImportPosition.X + aImportSize.Width / 2.0;
+ double fCentrumY = aImportPosition.Y + aImportSize.Height / 2.0;
+
+ // In case of group and lines, transformations are incorporated in the child
+ // shapes or points respectively in LO. MSO has rotation as separate property.
+ // The position refers to the unrotated rectangle of MSO. We need to adapt it
+ // to the left-top of the transformed shape.
+ awt::Size aLOSize(m_xShape->getSize()); // LO snap rectangle size in Hmm
+ if (bIsGroupOrLine && !(m_pImpl->mpWrapPolygon))
+ {
+ // Set LO position. MSO rotation is done on shape center.
+ if(pShape && pShape->IsGroupObject())
+ {
+ tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twips
+ m_pImpl->m_nLeftPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
+ m_pImpl->m_nTopPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
+ aLOSize.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenWidth());
+ aLOSize.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenHeight());
+ }
+ else
+ {
+ m_pImpl->m_nLeftPosition = fCentrumX - aLOSize.Width / 2.0;
+ m_pImpl->m_nTopPosition = fCentrumY - aLOSize.Height / 2.0;
+ }
+ m_xShape->setPosition(GetGraphicObjectPosition());
+ }
+ // ToDo: Rotated shapes with position type "Alignment" (UI of Word) have
+ // wrong position. Word aligns the unrotated logic rectangle, LO the rotated
+ // snap rectangle.
+
+ // Margin correction
+
+ // tdf#143475: Word 2007 (vers 12) calculates effectExtent for rotated images
+ // based on the unrotated image without width-height-swap. We correct this to
+ // those values, which would be calculated if width-height-swap was used.
+ if (m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() < 14
+ && xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")
+ && nOOXAngle != 0)
+ {
+ lcl_correctWord2007EffectExtent(nOOXAngle);
+ }
+
+ if (m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_INLINE)
+ {
+ if (nOOXAngle == 0)
+ {
+ // EffectExtent contains all needed additional space, including fat
+ // stroke and shadow. Simple add it to the margins.
+ sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
+ : 0;
+ m_pImpl->m_nLeftMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentRight)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight) : 0;
+ m_pImpl->m_nRightMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentTop)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop) : 0;
+ m_pImpl->m_nTopMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom) : 0;
+ m_pImpl->m_nBottomMargin += nEffectExtent;
+ }
+ else
+ {
+ // As of June 2021 LibreOffice uses an area, which is large enough to
+ // contain the rotated snap rectangle. MSO uses a smaller area, so
+ // that the rotated snap rectangle covers text.
+ awt::Point aMSOBaseLeftTop = aImportPosition;
+ awt::Size aMSOBaseSize = aImportSize;
+ lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
+ lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
+
+ // Get LO SnapRect from SdrObject if possible
+ awt::Rectangle aLOSnapRect;
+ // For case we have no SdrObject, initialize with values from m_pImpl
+ aLOSnapRect.X = m_pImpl->m_nLeftPosition;
+ aLOSnapRect.Y = m_pImpl->m_nTopPosition;
+ aLOSnapRect.Width = aLOSize.Width;
+ aLOSnapRect.Height = aLOSize.Height;
+ if (pShape)
+ {
+ tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twip
+ aLOSnapRect.X = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
+ aLOSnapRect.Y = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
+ aLOSnapRect.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenWidth());
+ aLOSnapRect.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenHeight());
+ }
+
+ m_pImpl->m_nLeftMargin += aLOSnapRect.X - aMSOBaseLeftTop.X;
+ m_pImpl->m_nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
+ - (aLOSnapRect.X + aLOSnapRect.Width);
+ m_pImpl->m_nTopMargin += aLOSnapRect.Y - aMSOBaseLeftTop.Y;
+ m_pImpl->m_nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
+ - (aLOSnapRect.Y + aLOSnapRect.Height);
+ // tdf#141880 LibreOffice cannot handle negative vertical margins.
+ // Those cases are caught below at common place.
+ }
+ } // end IMPORT_AS_DETECTED_INLINE
+ else if ((m_pImpl->m_nWrap == text::WrapTextMode_PARALLEL
+ || m_pImpl->m_nWrap == text::WrapTextMode_DYNAMIC
+ || m_pImpl->m_nWrap == text::WrapTextMode_LEFT
+ || m_pImpl->m_nWrap == text::WrapTextMode_RIGHT
+ || m_pImpl->m_nWrap == text::WrapTextMode_NONE)
+ && !(m_pImpl->mpWrapPolygon) && !bIsDiagram && !bIsWordprocessingCanvas)
+ {
+ // For wrap "Square" an area is defined around which the text wraps. MSO
+ // describes the area by a base rectangle and effectExtent. LO uses the
+ // shape bounding box and margins. We adapt the margins to get the same
+ // area as MSO.
+ awt::Point aMSOBaseLeftTop = aImportPosition;
+ awt::Size aMSOBaseSize = aImportSize;
+ lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
+ lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
+
+ // Get LO bound rectangle from SdrObject if possible
+ awt::Rectangle aLOBoundRect;
+ // For case we have no SdrObject, initialize with values from m_pImpl
+ aLOBoundRect.X = m_pImpl->m_nLeftPosition;
+ aLOBoundRect.Y = m_pImpl->m_nTopPosition;
+ aLOBoundRect.Width = aLOSize.Width;
+ aLOBoundRect.Height = aLOSize.Height;
+ if (pShape)
+ {
+ tools::Rectangle aBoundRect = pShape->GetCurrentBoundRect(); // Twip
+ aLOBoundRect.X = ConversionHelper::convertTwipToMM100(aBoundRect.Left());
+ aLOBoundRect.Y = ConversionHelper::convertTwipToMM100(aBoundRect.Top());
+ aLOBoundRect.Width = ConversionHelper::convertTwipToMM100(aBoundRect.getOpenWidth());
+ aLOBoundRect.Height = ConversionHelper::convertTwipToMM100(aBoundRect.getOpenHeight());
+ }
+
+ m_pImpl->m_nLeftMargin += aLOBoundRect.X - aMSOBaseLeftTop.X;
+ m_pImpl->m_nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
+ - (aLOBoundRect.X + aLOBoundRect.Width);
+ m_pImpl->m_nTopMargin += aLOBoundRect.Y - aMSOBaseLeftTop.Y;
+ m_pImpl->m_nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
+ - (aLOBoundRect.Y + aLOBoundRect.Height);
+ }
+ else if (m_pImpl->mpWrapPolygon && !bIsDiagram && !bIsWordprocessingCanvas)
+ {
+ // Word uses a wrap polygon, LibreOffice has no explicit wrap polygon
+ // but creates the wrap contour based on the shape geometry, without
+ // stroke width and shadow, but with rotation and flip. The concepts
+ // are not compatible. We approximate Word's rendering by setting
+ // wrap margins.
+
+ // Build a range from the wrap polygon from Word.
+ const drawing::PointSequenceSequence aWrapPolygon
+ = m_pImpl->mpWrapPolygon->getPointSequenceSequence();
+ basegfx::B2DPolyPolygon aB2DWrapPolyPolygon
+ = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
+ aWrapPolygon);
+ // Wrap polygon values are relative to 0..21600|0..21600.
+ // Scale to shape size (in Hmm).
+ basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleB2DHomMatrix(
+ aImportSize.Width / 21600.0, aImportSize.Height / 21600.0);
+ aB2DWrapPolyPolygon.transform(aMatrix);
+
+ // Shape geometry will be rotated, rotate wrap polygon too.
+ if (nOOXAngle != 0)
+ {
+ aMatrix = basegfx::utils::createRotateAroundPoint(
+ aImportSize.Width / 2.0, aImportSize.Height / 2.0,
+ basegfx::deg2rad<60000>(nOOXAngle));
+ aB2DWrapPolyPolygon.transform(aMatrix);
+ }
+ basegfx::B2DRange aB2DWrapRange = aB2DWrapPolyPolygon.getB2DRange();
+
+ // Build a range from shape geometry
+ basegfx::B2DRange aShapeRange;
+ if (pShape)
+ {
+ basegfx::B2DPolyPolygon aShapePolygon = pShape->TakeXorPoly(); // Twips
+ aMatrix = basegfx::utils::createScaleB2DHomMatrix(
+ o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100),
+ o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100));
+ aShapePolygon.transform(aMatrix);
+ // Wrap polygon treats left/top of shape as origin, shift shape polygon accordingly
+ aMatrix = basegfx::utils::createTranslateB2DHomMatrix(
+ -aImportPosition.X, -aImportPosition.Y);
+ aShapePolygon.transform(aMatrix);
+ aShapeRange = aShapePolygon.getB2DRange();
+ }
+ else // can this happen?
+ {
+ aShapeRange
+ = basegfx::B2DRange(0, 0, aImportSize.Width, aImportSize.Height);
+ if (nOOXAngle != 0)
+ {
+ aMatrix = basegfx::utils::createRotateB2DHomMatrix(
+ basegfx::deg2rad<60000>(nOOXAngle));
+ aShapeRange.transform(aMatrix);
+ }
+ }
+
+ // Add difference between shape and wrap range to margin and remember
+ // difference in Twips for export.
+ comphelper::SequenceAsHashMap aAnchorDistDiff;
+
+ const double fTopDiff = aShapeRange.getMinY() - aB2DWrapRange.getMinY();
+ m_pImpl->m_nTopMargin += basegfx::fround(fTopDiff);
+ aAnchorDistDiff["distTDiff"] <<= basegfx::fround(
+ o3tl::convert(fTopDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ const double fBottomDiff = aB2DWrapRange.getMaxY() - aShapeRange.getMaxY();
+ m_pImpl->m_nBottomMargin += basegfx::fround(fBottomDiff);
+ aAnchorDistDiff["distBDiff"] <<= basegfx::fround(
+ o3tl::convert(fBottomDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ const double fLeftDiff = aShapeRange.getMinX() - aB2DWrapRange.getMinX();
+ m_pImpl->m_nLeftMargin += basegfx::fround(fLeftDiff);
+ aAnchorDistDiff["distLDiff"] <<= basegfx::fround(
+ o3tl::convert(fLeftDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ const double fRightDiff = aB2DWrapRange.getMaxX() - aShapeRange.getMaxX();
+ m_pImpl->m_nRightMargin += basegfx::fround(fRightDiff);
+ aAnchorDistDiff["distRDiff"] <<= basegfx::fround(
+ o3tl::convert(fRightDiff, o3tl::Length::mm100, o3tl::Length::twip));
+
+ m_pImpl->m_aInteropGrabBag["AnchorDistDiff"]
+ <<= aAnchorDistDiff.getAsConstPropertyValueList();
+
+ // FixMe: tdf#141880. LibreOffice cannot handle negative horizontal margin in contour wrap
+ if (m_pImpl->m_nLeftMargin < 0)
+ m_pImpl->m_nLeftMargin = 0;
+ if (m_pImpl->m_nRightMargin < 0)
+ m_pImpl->m_nRightMargin = 0;
+ }
+ else if (!bIsDiagram && !bIsWordprocessingCanvas) // text::WrapTextMode_THROUGH
+ {
+ // Word writes and evaluates the effectExtent in case of position
+ // type 'Alignment' (UI). We move these values to margin to approximate
+ // Word's rendering.
+ if (m_pImpl->m_oEffectExtentLeft)
+ {
+ m_pImpl->m_nLeftMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft);
+ }
+ if (m_pImpl->m_oEffectExtentTop)
+ {
+ m_pImpl->m_nTopMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop);
+ }
+ if (m_pImpl->m_oEffectExtentRight)
+ {
+ m_pImpl->m_nRightMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight);
+ }
+ if (m_pImpl->m_oEffectExtentBottom)
+ {
+ m_pImpl->m_nBottomMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom);
+ }
+ }
+
+ // FixMe: tdf#141880 LibreOffice cannot handle negative vertical margins
+ // although they are allowed in ODF.
+ if (m_pImpl->m_nTopMargin < 0)
+ m_pImpl->m_nTopMargin = 0;
+ if (m_pImpl->m_nBottomMargin < 0)
+ m_pImpl->m_nBottomMargin = 0;
+ }
+
+ if (bUseShape && m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ // If we are here, this is a drawingML shape. For those, only dmapper (and not oox) knows the anchoring infos (just like for Writer pictures).
+ // But they aren't Writer pictures, either (which are already handled above).
+ uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
+
+ if (m_pImpl->m_nWrap == text::WrapTextMode_THROUGH && m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME)
+ {
+ if (m_pImpl->m_bLayoutInCell && m_pImpl->m_rDomainMapper.IsInTable()
+ && (m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_FRAME
+ || m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA))
+ {
+ // Impossible to be page-oriented when layout in cell.
+ // Since we are turning LayoutInCell off (to simplify layout),
+ // we need to set the orientation to the paragraph,
+ // as MSO effectively does when it forces layoutInCell.
+ // Probably also needs to happen with TEXT_LINE,
+ // but MSO is really weird with vertical relation to "line"
+ m_pImpl->m_nVertRelation = text::RelOrientation::FRAME;
+ }
+
+ // text::RelOrientation::FRAME is OOXML's "column", which behaves as if
+ // layout-in-cell would be always off.
+ m_pImpl->m_bLayoutInCell = false;
+ }
+
+ if (m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME
+ && m_pImpl->m_nHoriOrient > text::HoriOrientation::NONE
+ && m_pImpl->m_nHoriOrient != text::HoriOrientation::CENTER
+ && m_pImpl->m_nHoriOrient < text::HoriOrientation::FULL)
+ {
+ // before compat15, relative left/right/inside/outside honored margins.
+ if (m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() < 15)
+ m_pImpl->m_nHoriRelation = text::RelOrientation::PRINT_AREA;
+ }
+
+ // Anchored: Word only supports at-char in that case.
+ text::TextContentAnchorType eAnchorType = text::TextContentAnchorType_AT_CHARACTER;
+
+ if (m_pImpl->m_bHidden)
+ {
+ xShapeProps->setPropertyValue("Visible", uno::Any(false));
+ xShapeProps->setPropertyValue("Printable", uno::Any(false));
+ }
+
+ // Avoid setting AnchorType for TextBoxes till SwTextBoxHelper::syncProperty() doesn't handle transition.
+ bool bTextBox = false;
+ xShapeProps->getPropertyValue("TextBox") >>= bTextBox;
+
+ // The positioning change caused by LayoutInCell doesn't sync well
+ // in the text / frame duo. So the compatibility fix only correctly
+ // positions the frame and not the text currently.
+ // tdf#135943: Instead of half-fixing and making a complete mess,
+ // just avoid until layout's repositioning is sync'd to the text frame.
+ if (m_pImpl->m_bLayoutInCell && bTextBox)
+ m_pImpl->m_bLayoutInCell = !m_pImpl->m_bCompatForcedLayoutInCell;
+
+ xShapeProps->setPropertyValue("AnchorType", uno::Any(eAnchorType));
+
+ if (m_pImpl->m_nVertRelation == text::RelOrientation::TEXT_LINE)
+ {
+ // Word's "line" is "below the bottom of the line", our TEXT_LINE is
+ // "towards top, from the bottom of the line", so invert the vertical
+ // position.
+ awt::Point aPoint = xShape->getPosition();
+ aPoint.Y *= -1;
+ xShape->setPosition(aPoint);
+ }
+
+ if (m_pImpl->m_bLayoutInCell && bTextBox && m_pImpl->m_rDomainMapper.IsInTable()
+ && m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_FRAME)
+ m_pImpl->m_nHoriRelation = text::RelOrientation::FRAME;
+ if(m_pImpl->m_rDomainMapper.IsInTable())
+ xShapeProps->setPropertyValue(getPropertyName(PROP_FOLLOW_TEXT_FLOW),
+ uno::Any(m_pImpl->m_bLayoutInCell));
+ //only the position orientation is handled in applyPosition()
+ m_pImpl->applyPosition(xShapeProps);
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
+ if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape") ||
+ xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ // You would expect that position and rotation are
+ // independent, but they are not. Till we are not
+ // there yet to handle all scaling, translation and
+ // rotation with a single transformation matrix,
+ // make sure there is no graphic rotation set when we set
+ // the position.
+ sal_Int32 nRotation = 0;
+ if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ xShapeProps->getPropertyValue("RotateAngle") >>= nRotation;
+ }
+ if (nRotation)
+ xShapeProps->setPropertyValue("RotateAngle", uno::Any(sal_Int32(0)));
+
+ // Position of the groupshape should be set after children have been added.
+ // Long-term we should get rid of positioning group
+ // shapes, though. Do it for top-level ones with
+ // absolute page position as a start.
+ // fdo#80555: also set position for graphic shapes here
+ if (!isTopGroupObj(m_xShape)
+ || m_pImpl->m_nHoriRelation != text::RelOrientation::PAGE_FRAME
+ || m_pImpl->m_nVertRelation != text::RelOrientation::PAGE_FRAME)
+ m_xShape->setPosition(
+ awt::Point(m_pImpl->m_nLeftPosition, m_pImpl->m_nTopPosition));
+
+ if (nRotation)
+ xShapeProps->setPropertyValue("RotateAngle", uno::Any(nRotation));
+ }
+
+
+ m_pImpl->applyRelativePosition(xShapeProps, /*bRelativeOnly=*/true);
+
+ xShapeProps->setPropertyValue("SurroundContour", uno::Any(m_pImpl->m_bContour));
+ xShapeProps->setPropertyValue("ContourOutside", uno::Any(m_pImpl->m_bContourOutside));
+ m_pImpl->applyMargins(xShapeProps);
+ xShapeProps->setPropertyValue("Opaque", uno::Any(m_pImpl->m_bOpaque));
+ xShapeProps->setPropertyValue("Surround", uno::Any(static_cast<sal_Int32>(m_pImpl->m_nWrap)));
+ m_pImpl->applyZOrder(xShapeProps);
+ m_pImpl->applyName(xShapeProps);
+ m_pImpl->applyHyperlink(xShapeProps, bUseShape);
+ xShapeProps->setPropertyValue("AllowOverlap",
+ uno::Any(m_pImpl->m_bAllowOverlap));
+
+ // Get the grab-bag set by oox, merge with our one and then put it back.
+ comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
+ aInteropGrabBag.update(m_pImpl->getInteropGrabBag());
+ xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag.getAsConstPropertyValueList()));
+ }
+ else if (bUseShape && m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_INLINE)
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
+ m_pImpl->applyMargins(xShapeProps);
+ m_pImpl->applyZOrder(xShapeProps);
+ m_pImpl->applyName(xShapeProps);
+ comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
+ aInteropGrabBag.update(m_pImpl->getInteropGrabBag());
+ xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag.getAsConstPropertyValueList()));
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Inline_distT:
+ m_pImpl->m_nTopMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_Inline_distB:
+ m_pImpl->m_nBottomMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_Inline_distL:
+ m_pImpl->m_nLeftMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_Inline_distR:
+ m_pImpl->m_nRightMargin = 0;
+ break;
+ case NS_ooxml::LN_CT_GraphicalObjectData_uri:
+ rValue.getString();
+ //TODO: does it need to be handled?
+ break;
+ case NS_ooxml::LN_CT_SizeRelH_relativeFrom:
+ {
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_ST_SizeRelFromH_margin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::FRAME));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromH_leftMargin:
+ case NS_ooxml::LN_ST_SizeRelFromH_outsideMargin:
+ if (m_xShape.is())
+ {
+ // Here we handle the relative size of the width of some shape.
+ // The size of the shape's width is going to be relative to the size of the left margin.
+ // E.g.: (left margin = 8 && relative size = 150%) -> width of some shape = 12.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_LEFT));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromH_rightMargin:
+ case NS_ooxml::LN_ST_SizeRelFromH_insideMargin:
+ if (m_xShape.is())
+ {
+ // Same as the left margin above.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_RIGHT));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromH_page:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_FRAME));
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "GraphicImport::lcl_attribute: unhandled NS_ooxml::LN_CT_SizeRelH_relativeFrom value: " << nIntValue);
+ break;
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SizeRelV_relativeFrom:
+ {
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_ST_SizeRelFromV_margin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::FRAME));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromV_page:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_FRAME));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromV_topMargin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_PRINT_AREA));
+ }
+ break;
+ case NS_ooxml::LN_ST_SizeRelFromV_bottomMargin:
+ if (m_xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_PRINT_AREA_BOTTOM));
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "GraphicImport::lcl_attribute: unhandled NS_ooxml::LN_CT_SizeRelV_relativeFrom value: " << nIntValue);
+ break;
+ }
+ }
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+uno::Reference<text::XTextContent> GraphicImport::GetGraphicObject()
+{
+ uno::Reference<text::XTextContent> xResult;
+
+ if (m_xGraphicObject.is())
+ xResult = m_xGraphicObject;
+ else if (m_xShape.is())
+ {
+ xResult.set(m_xShape, uno::UNO_QUERY_THROW);
+ }
+
+ return xResult;
+}
+
+
+void GraphicImport::ProcessShapeOptions(Value const & rValue)
+{
+ sal_Int32 nIntValue = rValue.getInt();
+ switch( m_pImpl->m_nShapeOptionType )
+ {
+ case NS_ooxml::LN_CT_Anchor_distL:
+ m_pImpl->m_nLeftMargin = nIntValue / 360;
+ m_pImpl->m_nLeftMarginOrig = m_pImpl->m_nLeftMargin;
+ break;
+ case NS_ooxml::LN_CT_Anchor_distT:
+ //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustULWrapForWordMargins()
+ m_pImpl->m_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->m_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->m_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:
+ case NS_ooxml::LN_CT_Inline_effectExtent:
+ case NS_ooxml::LN_CT_Inline_docPr:
+ case NS_ooxml::LN_CT_Inline_cNvGraphicFramePr:
+ case NS_ooxml::LN_CT_NonVisualGraphicFrameProperties_graphicFrameLocks:
+ case NS_ooxml::LN_CT_Inline_a_graphic:
+ case NS_ooxml::LN_CT_Anchor_simplePos_elem:
+ case NS_ooxml::LN_CT_Anchor_extent:
+ case NS_ooxml::LN_CT_Anchor_effectExtent:
+ case NS_ooxml::LN_EG_WrapType_wrapSquare:
+ case NS_ooxml::LN_EG_WrapType_wrapTight:
+ case NS_ooxml::LN_EG_WrapType_wrapThrough:
+ case NS_ooxml::LN_CT_Anchor_docPr:
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_extLst:
+ case NS_ooxml::LN_CT_Anchor_cNvGraphicFramePr:
+ case NS_ooxml::LN_CT_Anchor_a_graphic:
+ case NS_ooxml::LN_CT_WrapPath_start:
+ case NS_ooxml::LN_CT_WrapPath_lineTo:
+ 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:
+ case NS_ooxml::LN_wpc_wpc:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+
+ // We'll map these to PARALLEL, save the original wrap type.
+ if (nSprmId == NS_ooxml::LN_EG_WrapType_wrapTight)
+ m_pImpl->m_aInteropGrabBag["EG_WrapType"] <<= OUString("wrapTight");
+ else if (nSprmId == NS_ooxml::LN_EG_WrapType_wrapThrough)
+ m_pImpl->m_aInteropGrabBag["EG_WrapType"] <<= OUString("wrapThrough");
+
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_EG_WrapType_wrapSquare:
+ case NS_ooxml::LN_EG_WrapType_wrapThrough:
+ case NS_ooxml::LN_EG_WrapType_wrapTight:
+ {
+ // tdf#137850: Word >= 2013 seems to ignore bBehindDoc except for wrapNone, but older versions honour it.
+ if (m_pImpl->m_bBehindDoc && m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ m_pImpl->m_bOpaque = !m_pImpl->m_rDomainMapper.IsInHeaderFooter();
+ }
+ break;
+ }
+
+ }
+ break;
+ case NS_ooxml::LN_CT_WrapTight_wrapPolygon:
+ case NS_ooxml::LN_CT_WrapThrough_wrapPolygon:
+ {
+ WrapPolygonHandler aHandler;
+
+ resolveSprmProps(aHandler, rSprm);
+
+ m_pImpl->mpWrapPolygon = aHandler.getPolygon();
+
+ // Save the wrap path in case we can't handle it natively: drawinglayer shapes, TextFrames.
+ m_pImpl->m_aInteropGrabBag["CT_WrapPath"] <<= m_pImpl->mpWrapPolygon->getPointSequenceSequence();
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_positionH:
+ {
+ // 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->m_bUseSimplePos )
+ {
+ m_pImpl->m_nHoriRelation = pHandler->relation();
+ m_pImpl->m_bPageToggle = pHandler->GetPageToggle();
+ m_pImpl->m_nHoriOrient = pHandler->orientation();
+ m_pImpl->m_nLeftPosition = pHandler->position();
+
+ // Left adjustments: if horizontally aligned to left of margin, then remove the
+ // left wrapping.
+ if (m_pImpl->m_nHoriOrient == text::HoriOrientation::LEFT)
+ {
+ if (m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA)
+ {
+ m_pImpl->m_nLeftMargin = 0;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Anchor_positionV:
+ {
+ // 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->m_bUseSimplePos )
+ {
+ m_pImpl->m_nVertRelation = pHandler->relation();
+ m_pImpl->m_nVertOrient = pHandler->orientation();
+ m_pImpl->m_nTopPosition = pHandler->position();
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_SizeRelH_pctWidth:
+ case NS_ooxml::LN_CT_SizeRelV_pctHeight:
+ if (m_pImpl->m_rPositivePercentages.empty())
+ break;
+
+ if (m_xShape.is())
+ {
+ sal_Int16 nPositivePercentage = rtl::math::round(m_pImpl->m_rPositivePercentages.front().toDouble() / oox::drawingml::PER_PERCENT);
+
+ if (nPositivePercentage)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
+ OUString aProperty = nSprmId == NS_ooxml::LN_CT_SizeRelH_pctWidth ? OUString("RelativeWidth") : OUString("RelativeHeight");
+
+ sal_Int32 nTextPreRotateAngle = 0;
+ uno::Any aAny;
+ if (xPropertySet->getPropertySetInfo()->hasPropertyByName(
+ "CustomShapeGeometry"))
+ {
+ aAny = xPropertySet->getPropertyValue("CustomShapeGeometry");
+ }
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(aAny);
+ auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
+ if (it != aCustomShapeGeometry.end())
+ {
+ nTextPreRotateAngle = it->second.get<sal_Int32>();
+ }
+ if (nTextPreRotateAngle == 0)
+ {
+ xPropertySet->setPropertyValue(aProperty,
+ uno::Any(nPositivePercentage));
+ }
+ }
+ }
+
+ // Make sure the token is consumed even if xShape is an empty
+ // reference.
+ m_pImpl->m_rPositivePercentages.pop();
+ break;
+ case NS_ooxml::LN_EG_WrapType_wrapNone:
+ //depending on the behindDoc attribute text wraps through behind or in front of the object
+ m_pImpl->m_nWrap = text::WrapTextMode_THROUGH;
+
+ // Wrap though means the margins defined earlier should not be
+ // respected.
+ m_pImpl->m_nLeftMargin = 0;
+ m_pImpl->m_nTopMargin = 0;
+ m_pImpl->m_nRightMargin = 0;
+ m_pImpl->m_nBottomMargin = 0;
+ break;
+ case NS_ooxml::LN_EG_WrapType_wrapTopAndBottom:
+ // tdf#137850: Word >= 2013 seems to ignore bBehindDoc except for wrapNone, but older versions honour it.
+ if (m_pImpl->m_bBehindDoc && m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14)
+ m_pImpl->m_bOpaque = !m_pImpl->m_rDomainMapper.IsInHeaderFooter();
+ m_pImpl->m_nWrap = text::WrapTextMode_NONE;
+ break;
+ case NS_ooxml::LN_CT_GraphicalObject_graphicData:
+ {
+ m_pImpl->m_bIsGraphic = true;
+
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_NonVisualDrawingProps_a_hlinkClick:
+ {
+ 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(const writerfilter::Reference<Properties>::Pointer_t& /*ref*/)
+{
+}
+
+uno::Reference<text::XTextContent> GraphicImport::createGraphicObject(uno::Reference<graphic::XGraphic> const & rxGraphic,
+ uno::Reference<beans::XPropertySet> const & xShapeProps)
+{
+ uno::Reference<text::XTextContent> xGraphicObject;
+ try
+ {
+ if (rxGraphic.is())
+ {
+ uno::Reference< beans::XPropertySet > xGraphicObjectProperties(
+ m_xTextFactory->createInstance("com.sun.star.text.TextGraphicObject"),
+ uno::UNO_QUERY_THROW);
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_GRAPHIC), uno::Any(rxGraphic));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE),
+ uno::Any( m_pImpl->m_rGraphicImportType == 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->m_aBorders[0];
+ if (rBorderLine.isEmpty() && xShapeProps.is() && xShapeProps->getPropertyValue("LineStyle").get<drawing::LineStyle>() != drawing::LineStyle_NONE)
+ {
+ // In case we got no border tokens and we have the
+ // original shape, then use its line properties as the
+ // border.
+ aBorderLine.Color = xShapeProps->getPropertyValue("LineColor").get<sal_Int32>();
+ aBorderLine.LineWidth = xShapeProps->getPropertyValue("LineWidth").get<sal_Int32>();
+ }
+ else
+ {
+ aBorderLine.Color = 0;
+ aBorderLine.InnerLineWidth = 0;
+ aBorderLine.OuterLineWidth = static_cast<sal_Int16>(rBorderLine.nLineWidth);
+ aBorderLine.LineDistance = 0;
+ }
+ PropertyIds const aBorderProps[] =
+ {
+ PROP_LEFT_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_TOP_BORDER,
+ PROP_BOTTOM_BORDER
+ };
+
+ for(PropertyIds const & rBorderProp : aBorderProps)
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(rBorderProp), uno::Any(aBorderLine));
+
+ // setting graphic object shadow properties
+ if (m_pImpl->m_bShadow)
+ {
+ // Shadow width is approximated by average of X and Y
+ table::ShadowFormat aShadow;
+ sal_uInt32 nShadowColor = m_pImpl->m_nShadowColor & 0x00FFFFFF; // The shadow color we get is RGB only.
+ sal_Int32 nShadowWidth = (abs(m_pImpl->m_nShadowXDistance)
+ + abs(m_pImpl->m_nShadowYDistance)) / 2;
+
+ aShadow.ShadowWidth = nShadowWidth;
+ sal_uInt8 nShadowTransparence = float(m_pImpl->m_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->m_nShadowXDistance > 0)
+ {
+ if (m_pImpl->m_nShadowYDistance > 0)
+ aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT;
+ else
+ aShadow.Location = table::ShadowLocation_TOP_RIGHT;
+ }
+ else
+ {
+ if (m_pImpl->m_nShadowYDistance > 0)
+ aShadow.Location = table::ShadowLocation_BOTTOM_LEFT;
+ else
+ aShadow.Location = table::ShadowLocation_TOP_LEFT;
+ }
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_SHADOW_FORMAT), uno::Any(aShadow));
+ }
+
+ // setting properties for all types
+ if( m_pImpl->m_bPositionProtected )
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_POSITION_PROTECTED ),
+ uno::Any(true));
+ if( m_pImpl->m_bSizeProtected )
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SIZE_PROTECTED ),
+ uno::Any(true));
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_DECORATIVE), uno::Any(m_pImpl->m_bDecorative));
+ sal_Int32 nWidth = - m_pImpl->m_nLeftPosition;
+ if (m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ if (m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME
+ && (m_pImpl->m_nHoriOrient == text::HoriOrientation::LEFT
+ || m_pImpl->m_nHoriOrient == text::HoriOrientation::RIGHT
+ || m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE
+ || m_pImpl->m_nHoriOrient == text::HoriOrientation::OUTSIDE))
+ {
+ // before compat15, relative left/right/inside/outside honored margins.
+ if (m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() < 15)
+ m_pImpl->m_nHoriRelation = text::RelOrientation::PRINT_AREA;
+ }
+
+ //adjust margins
+ if( (m_pImpl->m_nHoriOrient == text::HoriOrientation::LEFT &&
+ (m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME) ) ||
+ (m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE &&
+ m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ))
+ m_pImpl->m_nLeftMargin = 0;
+ if((m_pImpl->m_nHoriOrient == text::HoriOrientation::RIGHT &&
+ (m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME) ) ||
+ (m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE &&
+ m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ))
+ m_pImpl->m_nRightMargin = 0;
+ // adjust top/bottom margins
+ if( m_pImpl->m_nVertOrient == text::VertOrientation::TOP &&
+ ( m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_FRAME))
+ m_pImpl->m_nTopMargin = 0;
+ if( m_pImpl->m_nVertOrient == text::VertOrientation::BOTTOM &&
+ ( m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA ||
+ m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_FRAME))
+ m_pImpl->m_nBottomMargin = 0;
+ if( m_pImpl->m_nVertOrient == text::VertOrientation::BOTTOM &&
+ m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA )
+ m_pImpl->m_nBottomMargin = 0;
+ //adjust alignment
+ if( m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE &&
+ m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_FRAME )
+ {
+ // convert 'left to page' to 'from left -<width> to page text area'
+ m_pImpl->m_nHoriOrient = text::HoriOrientation::NONE;
+ m_pImpl->m_nHoriRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ m_pImpl->m_nLeftPosition = - nWidth;
+ }
+ else if( m_pImpl->m_nHoriOrient == text::HoriOrientation::OUTSIDE &&
+ m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_FRAME )
+ {
+ // convert 'right to page' to 'from left 0 to right page border'
+ m_pImpl->m_nHoriOrient = text::HoriOrientation::NONE;
+ m_pImpl->m_nHoriRelation = text::RelOrientation::PAGE_RIGHT;
+ m_pImpl->m_nLeftPosition = 0;
+ }
+
+ if (m_pImpl->m_nVertRelation == text::RelOrientation::TEXT_LINE)
+ {
+ // Word's "line" is "below the bottom of the line", our TEXT_LINE is
+ // "towards top, from the bottom of the line", so invert the vertical position.
+ m_pImpl->m_nTopPosition *= -1;
+ }
+
+ m_pImpl->applyPosition(xGraphicObjectProperties);
+ m_pImpl->applyRelativePosition(xGraphicObjectProperties);
+ if( !m_pImpl->m_bOpaque )
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any(m_pImpl->m_bOpaque));
+ }
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND ),
+ uno::Any(static_cast<sal_Int32>(m_pImpl->m_nWrap)));
+ if( m_pImpl->m_rDomainMapper.IsInTable())
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_FOLLOW_TEXT_FLOW ),
+ uno::Any(m_pImpl->m_bLayoutInCell));
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_ALLOW_OVERLAP),
+ uno::Any(m_pImpl->m_bAllowOverlap));
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND_CONTOUR ),
+ uno::Any(m_pImpl->m_bContour));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_CONTOUR_OUTSIDE ),
+ uno::Any(m_pImpl->m_bContourOutside));
+ m_pImpl->applyMargins(xGraphicObjectProperties);
+ }
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_CONTRAST ),
+ uno::Any(static_cast<sal_Int16>(m_pImpl->m_nContrast)));
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_LUMINANCE ),
+ uno::Any(static_cast<sal_Int16>(m_pImpl->m_nBrightness)));
+ if(m_pImpl->m_eColorMode != drawing::ColorMode_STANDARD)
+ {
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC_COLOR_MODE ),
+ uno::Any(m_pImpl->m_eColorMode));
+ }
+
+ xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BACK_COLOR ),
+ uno::Any( GraphicImport_Impl::nFillColor ));
+ m_pImpl->applyZOrder(xGraphicObjectProperties);
+
+ //there seems to be no way to detect the original size via _real_ API
+ uno::Reference< beans::XPropertySet > xGraphicProperties(rxGraphic, uno::UNO_QUERY_THROW);
+
+ if (m_pImpl->mpWrapPolygon)
+ {
+ uno::Any aContourPolyPolygon;
+ awt::Size aGraphicSize;
+ WrapPolygon::Pointer_t pCorrected;
+ xGraphicProperties->getPropertyValue(getPropertyName(PROP_SIZE100th_M_M)) >>= aGraphicSize;
+ if (aGraphicSize.Width && aGraphicSize.Height)
+ {
+ pCorrected = m_pImpl->mpWrapPolygon->correctWordWrapPolygon(aGraphicSize);
+ }
+ else
+ {
+ xGraphicProperties->getPropertyValue(getPropertyName(PROP_SIZE_PIXEL)) >>= aGraphicSize;
+ if (aGraphicSize.Width && aGraphicSize.Height)
+ {
+ pCorrected = m_pImpl->mpWrapPolygon->correctWordWrapPolygonPixel(aGraphicSize);
+ }
+ }
+
+ text::GraphicCrop aGraphicCrop;
+ xShapeProps->getPropertyValue("GraphicCrop") >>= aGraphicCrop;
+ if (aGraphicCrop.Top != 0 || aGraphicCrop.Bottom != 0 || aGraphicCrop.Left != 0
+ || aGraphicCrop.Right != 0)
+ {
+ // Word's wrap polygon deals with a canvas which has the size of the already
+ // cropped graphic, correct our polygon to have the same render result.
+ pCorrected = pCorrected->correctCrop(aGraphicSize, aGraphicCrop);
+ }
+
+ if (pCorrected)
+ {
+ aContourPolyPolygon <<= pCorrected->getPointSequenceSequence();
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_CONTOUR_POLY_POLYGON),
+ aContourPolyPolygon);
+ // We should bring it to front, even if wp:anchor's behindDoc="1",
+ // because otherwise paragraph background (if set) overlaps the graphic
+ // TODO: if paragraph's background becomes bottommost, then remove this hack
+ xGraphicObjectProperties->setPropertyValue("Opaque", uno::Any(true));
+ }
+ }
+
+
+ if (m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_INLINE
+ || m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
+ {
+ if( m_pImpl->getXSize() && m_pImpl->getYSize() )
+ xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_SIZE),
+ uno::Any( awt::Size( m_pImpl->getXSize(), m_pImpl->getYSize() )));
+ m_pImpl->applyMargins(xGraphicObjectProperties);
+ m_pImpl->applyName(xGraphicObjectProperties);
+ m_pImpl->applyHyperlink(xGraphicObjectProperties, false);
+ }
+
+ // Handle horizontal flip.
+ bool bMirrored = false;
+ xShapeProps->getPropertyValue("IsMirrored") >>= bMirrored;
+ if (bMirrored)
+ {
+ xGraphicObjectProperties->setPropertyValue("HoriMirroredOnEvenPages",
+ uno::Any(true));
+ xGraphicObjectProperties->setPropertyValue("HoriMirroredOnOddPages",
+ uno::Any(true));
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "");
+ }
+ return xGraphicObject;
+}
+
+
+void GraphicImport::data(const sal_uInt8* buf, size_t len)
+{
+ uno::Reference< io::XInputStream > xIStream = new XInputStreamHelper( buf, len );
+ beans::PropertyValues aMediaProperties{ comphelper::makePropertyValue(
+ getPropertyName(PROP_INPUT_STREAM), xIStream) };
+
+ uno::Reference<beans::XPropertySet> xPropertySet;
+ uno::Reference<graphic::XGraphicProvider> xGraphicProvider(graphic::GraphicProvider::create(m_xComponentContext));
+ uno::Reference<graphic::XGraphic> xGraphic = xGraphicProvider->queryGraphic(aMediaProperties);
+ m_xGraphicObject = createGraphicObject(xGraphic, xPropertySet);
+}
+
+
+void GraphicImport::lcl_startSectionGroup()
+{
+}
+
+
+void GraphicImport::lcl_endSectionGroup()
+{
+}
+
+
+void GraphicImport::lcl_startParagraphGroup()
+{
+}
+
+
+void GraphicImport::lcl_endParagraphGroup()
+{
+}
+
+void GraphicImport::lcl_startCharacterGroup()
+{
+}
+
+void GraphicImport::lcl_endCharacterGroup()
+{
+}
+
+void GraphicImport::lcl_text(const sal_uInt8 * /*_data*/, size_t /*len*/)
+{
+}
+
+void GraphicImport::lcl_utext(const sal_Unicode * /*_data*/, size_t /*len*/)
+{
+}
+
+void GraphicImport::lcl_props(const writerfilter::Reference<Properties>::Pointer_t& /*ref*/)
+{
+}
+
+void GraphicImport::lcl_table(Id /*name*/, const writerfilter::Reference<Table>::Pointer_t& /*ref*/)
+{
+}
+
+void GraphicImport::lcl_substream(Id /*name*/, const 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->m_bIsGraphic;
+}
+
+sal_Int32 GraphicImport::GetLeftMarginOrig() const
+{
+ return m_pImpl->m_nLeftMarginOrig;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/GraphicImport.hxx b/sw/source/writerfilter/dmapper/GraphicImport.hxx
new file mode 100644
index 000000000000..dae19ce85c03
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/GraphicImport.hxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <queue>
+#include <memory>
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+
+namespace com::sun::star {
+ namespace uno
+ {
+ class XComponentContext;
+ }
+ namespace lang
+ {
+ class XMultiServiceFactory;
+ }
+ namespace text
+ {
+ class XTextContent;
+ }
+ namespace drawing
+ {
+ class XShape;
+ }
+ namespace beans
+ {
+ struct PropertyValue;
+ }
+}
+
+namespace writerfilter::dmapper
+{
+class GraphicImport_Impl;
+class DomainMapper;
+
+enum GraphicImportType
+{
+ IMPORT_AS_DETECTED_INLINE,
+ IMPORT_AS_DETECTED_ANCHOR
+};
+
+class GraphicImport : public LoggedProperties, public LoggedTable
+ ,public BinaryObj, public LoggedStream
+{
+ std::unique_ptr<GraphicImport_Impl> m_pImpl;
+
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xTextFactory;
+
+ css::uno::Reference<css::text::XTextContent> m_xGraphicObject;
+
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ void ProcessShapeOptions(Value const & val);
+
+ css::uno::Reference<css::text::XTextContent>
+ createGraphicObject(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
+ css::uno::Reference<css::beans::XPropertySet> const & xShapeProps);
+
+ void putPropertyToFrameGrabBag( const OUString& sPropertyName, const css::uno::Any& aPropertyValue );
+
+public:
+ explicit GraphicImport( css::uno::Reference<css::uno::XComponentContext> xComponentContext,
+ css::uno::Reference<css::lang::XMultiServiceFactory> xTextFactory,
+ DomainMapper& rDomainMapper,
+ GraphicImportType & rGraphicImportType,
+ std::pair<OUString, OUString>& rPositionOffsets,
+ std::pair<OUString, OUString>& rAligns,
+ std::queue<OUString>& rPositivePercentages);
+ virtual ~GraphicImport() override;
+
+ // BinaryObj
+ virtual void data(const sal_uInt8* buffer, size_t len) override;
+
+ css::uno::Reference<css::text::XTextContent> GetGraphicObject();
+ const css::uno::Reference<css::drawing::XShape>& GetXShapeObject() const { return m_xShape;}
+ bool IsGraphic() const;
+ sal_Int32 GetLeftMarginOrig() const;
+
+ com::sun::star::awt::Point GetGraphicObjectPosition() const;
+
+ bool GetLayoutInCell() const;
+
+ private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(const 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_Unicode * data, size_t len) override;
+ virtual void lcl_props(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+ virtual void lcl_table(Id name,
+ const writerfilter::Reference<Table>::Pointer_t& ref) override;
+ virtual void lcl_substream(Id name, const writerfilter::Reference<Stream>::Pointer_t& ref) override;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ virtual void lcl_startTextBoxContent() override {};
+ virtual void lcl_endTextBoxContent() override {};
+ virtual void lcl_endShape() override;
+
+ void handleWrapTextValue(sal_uInt32 nVal);
+ void lcl_expandRectangleByEffectExtent(css::awt::Point& rLeftTop, css::awt::Size& rSize);
+ void lcl_correctWord2007EffectExtent(const sal_Int32 nMSOAngle);
+};
+
+typedef tools::SvRef<GraphicImport> GraphicImportPtr;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/LatentStyleHandler.cxx b/sw/source/writerfilter/dmapper/LatentStyleHandler.cxx
new file mode 100644
index 000000000000..bc381d21fe3e
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/dmapper/LatentStyleHandler.hxx b/sw/source/writerfilter/dmapper/LatentStyleHandler.hxx
new file mode 100644
index 000000000000..52a4d9e7c318
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/LatentStyleHandler.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+/// Handler for a latent style (w:lsdException element)
+class LatentStyleHandler : public LoggedProperties
+{
+ std::vector<css::beans::PropertyValue> m_aAttributes;
+
+ // Properties
+ void lcl_attribute(Id nId, Value& rVal) override;
+ void lcl_sprm(Sprm& sprm) override;
+
+public:
+ LatentStyleHandler();
+ ~LatentStyleHandler() override;
+
+ const std::vector<css::beans::PropertyValue>& getAttributes() const;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/LoggedResources.cxx b/sw/source/writerfilter/dmapper/LoggedResources.cxx
new file mode 100644
index 000000000000..05ebcd057532
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/LoggedResources.cxx
@@ -0,0 +1,401 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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>
+#include <utility>
+
+using namespace ::com::sun::star;
+
+namespace writerfilter
+{
+#ifdef DBG_UTIL
+
+LoggedResourcesHelper::LoggedResourcesHelper(std::string sPrefix)
+ : msPrefix(std::move(sPrefix))
+{
+}
+
+LoggedResourcesHelper::~LoggedResourcesHelper() {}
+
+void LoggedResourcesHelper::startElement(const std::string& sElement)
+{
+ TagLogger::getInstance().startElement(msPrefix + "." + sElement);
+}
+
+void LoggedResourcesHelper::endElement() { TagLogger::getInstance().endElement(); }
+
+void LoggedResourcesHelper::chars(std::u16string_view rChars)
+{
+ TagLogger::getInstance().chars(rChars);
+}
+
+void LoggedResourcesHelper::chars(const std::string& rChars)
+{
+ TagLogger::getInstance().chars(rChars);
+}
+
+void LoggedResourcesHelper::attribute(const std::string& rName, const std::string& rValue)
+{
+ TagLogger::getInstance().attribute(rName, rValue);
+}
+
+void LoggedResourcesHelper::attribute(const std::string& rName, sal_uInt32 nValue)
+{
+ TagLogger::getInstance().attribute(rName, nValue);
+}
+
+#endif
+
+LoggedStream::LoggedStream(
+#ifdef DBG_UTIL
+ const std::string& sPrefix)
+ : mHelper(sPrefix)
+#else
+ const std::string&)
+#endif
+{
+}
+
+LoggedStream::~LoggedStream() {}
+
+void LoggedStream::startSectionGroup()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("section");
+#endif
+
+ lcl_startSectionGroup();
+}
+
+void LoggedStream::endSectionGroup()
+{
+ lcl_endSectionGroup();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startParagraphGroup()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("paragraph");
+#endif
+
+ lcl_startParagraphGroup();
+}
+
+void LoggedStream::endParagraphGroup()
+{
+ lcl_endParagraphGroup();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startCharacterGroup()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("charactergroup");
+#endif
+
+ lcl_startCharacterGroup();
+}
+
+void LoggedStream::endCharacterGroup()
+{
+ lcl_endCharacterGroup();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startShape(uno::Reference<drawing::XShape> const& xShape)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("shape");
+#endif
+
+ lcl_startShape(xShape);
+}
+
+void LoggedStream::endShape()
+{
+ lcl_endShape();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startTextBoxContent() { lcl_startTextBoxContent(); }
+
+void LoggedStream::endTextBoxContent() { lcl_endTextBoxContent(); }
+
+void LoggedStream::text(const sal_uInt8* data, size_t len)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("text");
+
+ OUString sText(reinterpret_cast<const char*>(data), len, RTL_TEXTENCODING_MS_1252);
+
+ mHelper.startElement("data");
+ LoggedResourcesHelper::chars(sText);
+ LoggedResourcesHelper::endElement();
+#endif
+
+ lcl_text(data, len);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::utext(const sal_Unicode* const data, size_t const len)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("utext");
+ mHelper.startElement("data");
+
+ OUString const sText(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(const 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, const 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, const writerfilter::Reference<Stream>::Pointer_t& ref)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("substream");
+ LoggedResourcesHelper::attribute("name", QNameToString(name));
+#endif
+
+ lcl_substream(name, ref);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::info(const std::string& _info)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("info");
+ LoggedResourcesHelper::attribute("text", _info);
+#else
+ (void)_info;
+#endif
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::startGlossaryEntry()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("startGlossaryEntry");
+#endif
+
+ lcl_startGlossaryEntry();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::endGlossaryEntry()
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("endGlossaryEntry");
+#endif
+
+ lcl_endGlossaryEntry();
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+void LoggedStream::checkId(const sal_Int32 nId)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("checkId");
+ LoggedResourcesHelper::chars(OUString::number(nId));
+#endif
+
+ lcl_checkId(nId);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+LoggedProperties::LoggedProperties(
+#ifdef DBG_UTIL
+ const std::string& sPrefix)
+ : mHelper(sPrefix)
+#else
+ const std::string&)
+#endif
+{
+}
+
+LoggedProperties::~LoggedProperties() {}
+
+void LoggedProperties::attribute(Id name, Value& val)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("attribute");
+ LoggedResourcesHelper::attribute("name", QNameToString(name));
+ LoggedResourcesHelper::attribute("value", val.toString());
+ LoggedResourcesHelper::endElement();
+#endif
+
+ lcl_attribute(name, val);
+}
+
+void LoggedProperties::sprm(Sprm& rSprm)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("sprm");
+ LoggedResourcesHelper::attribute("name", QNameToString(rSprm.getId()));
+ LoggedResourcesHelper::chars(rSprm.toString());
+#endif
+
+ lcl_sprm(rSprm);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+
+LoggedTable::LoggedTable(
+#ifdef DBG_UTIL
+ const std::string& sPrefix)
+ : mHelper(sPrefix)
+#else
+ const std::string&)
+#endif
+{
+}
+
+LoggedTable::~LoggedTable() {}
+
+void LoggedTable::entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref)
+{
+#ifdef DBG_UTIL
+ mHelper.startElement("entry");
+ LoggedResourcesHelper::attribute("pos", pos);
+#else
+ (void)pos;
+#endif
+
+ lcl_entry(ref);
+
+#ifdef DBG_UTIL
+ LoggedResourcesHelper::endElement();
+#endif
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/LoggedResources.hxx b/sw/source/writerfilter/dmapper/LoggedResources.hxx
new file mode 100644
index 000000000000..c0927c9130c4
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/LoggedResources.hxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter
+{
+#ifdef DBG_UTIL
+class LoggedResourcesHelper final
+{
+public:
+ explicit LoggedResourcesHelper(std::string sPrefix);
+ ~LoggedResourcesHelper();
+
+ void startElement(const std::string& sElement);
+ static void endElement();
+ static void chars(std::u16string_view rChars);
+ static void chars(const std::string& rChars);
+ static void attribute(const std::string& rName, const std::string& rValue);
+ static void attribute(const std::string& rName, sal_uInt32 nValue);
+
+private:
+ std::string msPrefix;
+};
+#endif
+
+class LoggedStream : public Stream
+{
+public:
+ explicit LoggedStream(const std::string& sPrefix);
+ virtual ~LoggedStream() override;
+
+ void startSectionGroup() override;
+ void endSectionGroup() override;
+ void startParagraphGroup() override;
+ void endParagraphGroup() override;
+ void startCharacterGroup() override;
+ void endCharacterGroup() override;
+ void startShape(css::uno::Reference<css::drawing::XShape> const& xShape) override;
+ void endShape() override;
+ void startTextBoxContent() override;
+ void endTextBoxContent() override;
+ void text(const sal_uInt8* data, size_t len) override;
+ void utext(const sal_Unicode* 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(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+ void table(Id name, const writerfilter::Reference<Table>::Pointer_t& ref) override;
+ void substream(Id name, const writerfilter::Reference<Stream>::Pointer_t& ref) override;
+ void info(const std::string& info) override;
+ void startGlossaryEntry() override;
+ void endGlossaryEntry() override;
+ void checkId(const sal_Int32 nId) override;
+
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* /*pDocument*/) override{};
+
+protected:
+ virtual void lcl_startSectionGroup() = 0;
+ virtual void lcl_endSectionGroup() = 0;
+ virtual void lcl_startParagraphGroup() = 0;
+ virtual void lcl_endParagraphGroup() = 0;
+ virtual void lcl_startCharacterGroup() = 0;
+ virtual void lcl_endCharacterGroup() = 0;
+ virtual void lcl_startShape(css::uno::Reference<css::drawing::XShape> const& xShape) = 0;
+ virtual void lcl_endShape() = 0;
+ virtual void lcl_startTextBoxContent() = 0;
+ virtual void lcl_endTextBoxContent() = 0;
+ virtual void lcl_text(const sal_uInt8* data, size_t len) = 0;
+ virtual void lcl_utext(const sal_Unicode* 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(const writerfilter::Reference<Properties>::Pointer_t& ref) = 0;
+ virtual void lcl_table(Id name, const writerfilter::Reference<Table>::Pointer_t& ref) = 0;
+ virtual void lcl_substream(Id name, const writerfilter::Reference<Stream>::Pointer_t& ref) = 0;
+ virtual void lcl_startGlossaryEntry() {}
+ virtual void lcl_endGlossaryEntry() {}
+ virtual void lcl_checkId(const sal_Int32) {}
+
+private:
+#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;
+
+private:
+#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(const writerfilter::Reference<Properties>::Pointer_t& ref) = 0;
+
+private:
+#ifdef DBG_UTIL
+ LoggedResourcesHelper mHelper;
+#endif
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/MeasureHandler.cxx b/sw/source/writerfilter/dmapper/MeasureHandler.cxx
new file mode 100644
index 000000000000..5eea9a5c613b
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/dmapper/MeasureHandler.hxx b/sw/source/writerfilter/dmapper/MeasureHandler.hxx
new file mode 100644
index 000000000000..8a6f9639eec5
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/MeasureHandler.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+/** Handler for sprms that contain a measure and a unit
+ - Left indent of tables
+ - Preferred width of tables
+ */
+class MeasureHandler : public LoggedProperties
+{
+ sal_Int32 m_nMeasureValue;
+ sal_Int32 m_nUnit;
+ sal_Int16 m_nRowHeightSizeType; //table row height type
+
+ OUString m_aInteropGrabBagName;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+public:
+ MeasureHandler();
+ virtual ~MeasureHandler() override;
+
+ sal_Int32 getMeasureValue() const;
+
+ sal_Int32 getValue() const { return m_nMeasureValue; }
+ sal_Int32 getUnit() const { return m_nUnit; }
+
+ sal_Int16 GetRowHeightSizeType() const { return m_nRowHeightSizeType; }
+ void enableInteropGrabBag(const OUString& aName);
+ css::beans::PropertyValue getInteropGrabBag();
+};
+typedef tools::SvRef<MeasureHandler> MeasureHandlerPtr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/ModelEventListener.cxx b/sw/source/writerfilter/dmapper/ModelEventListener.cxx
new file mode 100644
index 000000000000..4df26105a37c
--- /dev/null
+++ b/sw/source/writerfilter/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 <comphelper/diagnose_ex.hxx>
+
+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/sw/source/writerfilter/dmapper/ModelEventListener.hxx b/sw/source/writerfilter/dmapper/ModelEventListener.hxx
new file mode 100644
index 000000000000..47cd94b80a82
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/ModelEventListener.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/document/XEventListener.hpp>
+#include <cppuhelper/implbase.hxx>
+
+namespace writerfilter::dmapper
+{
+class ModelEventListener : public cppu::WeakImplHelper<css::document::XEventListener>
+{
+ bool m_bIndexes;
+ bool m_bControls;
+
+public:
+ ModelEventListener(bool bIndexes, bool bControls);
+ virtual ~ModelEventListener() override;
+
+ virtual void SAL_CALL notifyEvent(const css::document::EventObject& Event) override;
+ virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+};
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/NumberingManager.cxx b/sw/source/writerfilter/dmapper/NumberingManager.cxx
new file mode 100644
index 000000000000..ec8e1be07c7f
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/NumberingManager.cxx
@@ -0,0 +1,1213 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <comphelper/diagnose_ex.hxx>
+#include <tools/UnitConversion.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <regex>
+#include <utility>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper {
+
+//--------------------------------------------------- Utility functions
+template <typename T>
+static beans::PropertyValue lcl_makePropVal(PropertyIds nNameID, T const & aValue)
+{
+ return comphelper::makePropertyValue(getPropertyName(nNameID), aValue);
+}
+
+static sal_Int32 lcl_findProperty( const uno::Sequence< beans::PropertyValue >& aProps, std::u16string_view sName )
+{
+ sal_Int32 i = 0;
+ sal_Int32 nLen = aProps.getLength( );
+ sal_Int32 nPos = -1;
+
+ while ( nPos == -1 && i < nLen )
+ {
+ if ( aProps[i].Name == sName )
+ nPos = i;
+ else
+ i++;
+ }
+
+ return nPos;
+}
+
+static void lcl_mergeProperties( const uno::Sequence< beans::PropertyValue >& aSrc,
+ uno::Sequence< beans::PropertyValue >& aDst )
+{
+ for ( const auto& rProp : aSrc )
+ {
+ // Look for the same property in aDst
+ sal_Int32 nPos = lcl_findProperty( aDst, rProp.Name );
+ if ( nPos >= 0 )
+ {
+ // Replace the property value by the one in aSrc
+ aDst.getArray()[nPos] = rProp;
+ }
+ else
+ {
+ // Simply add the new value
+ aDst.realloc( aDst.getLength( ) + 1 );
+ aDst.getArray()[ aDst.getLength( ) - 1 ] = rProp;
+ }
+ }
+}
+
+//-------------------------------------------- ListLevel implementation
+void ListLevel::SetValue( Id nId, sal_Int32 nValue )
+{
+ switch( nId )
+ {
+ case NS_ooxml::LN_CT_Lvl_start:
+ m_nIStartAt = nValue;
+ break;
+ case NS_ooxml::LN_CT_NumLvl_startOverride:
+ m_nStartOverride = nValue;
+ break;
+ case NS_ooxml::LN_CT_NumFmt_val:
+ m_nNFC = nValue;
+ break;
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ m_bIsLegal = true;
+ break;
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ break;
+ case NS_ooxml::LN_CT_Lvl_suff:
+ m_nXChFollow = nValue;
+ break;
+ case NS_ooxml::LN_CT_TabStop_pos:
+ if (nValue < 0)
+ {
+ SAL_INFO("writerfilter",
+ "unsupported list tab stop position " << nValue);
+ }
+ else
+ m_nTabstop = nValue;
+ break;
+ default:
+ OSL_FAIL( "this line should never be reached");
+ }
+ m_bHasValues = true;
+}
+
+void ListLevel::SetCustomNumberFormat(const OUString& rValue) { m_aCustomNumberFormat = rValue; }
+
+sal_Int16 ListLevel::GetNumberingType(sal_Int16 nDefault) const
+{
+ return ConversionHelper::ConvertNumberingType(m_nNFC, nDefault);
+}
+
+bool ListLevel::HasValues() const
+{
+ return m_bHasValues;
+}
+
+void ListLevel::SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle )
+{
+ if (!pStyle)
+ return;
+ m_pParaStyle = pStyle;
+}
+
+uno::Sequence<beans::PropertyValue> ListLevel::GetProperties(bool bDefaults)
+{
+ uno::Sequence<beans::PropertyValue> aLevelProps = GetLevelProperties(bDefaults);
+ if (m_pParaStyle)
+ AddParaProperties( &aLevelProps );
+ return aLevelProps;
+}
+
+static bool IgnoreForCharStyle(std::u16string_view aStr, const bool bIsSymbol)
+{
+ //Names found in PropertyIds.cxx, Lines 56-396
+ return (aStr==u"Adjust" || aStr==u"IndentAt" || aStr==u"FirstLineIndent"
+ || aStr==u"FirstLineOffset" || aStr==u"LeftMargin"
+ // We need font names when they are different for the bullet and for the text.
+ // But leave symbols alone, we only want to keep the font style for letters and numbers.
+ || (bIsSymbol && aStr==u"CharFontName")
+ );
+}
+uno::Sequence< beans::PropertyValue > ListLevel::GetCharStyleProperties( )
+{
+ PropertyValueVector_t rProperties;
+
+ const uno::Sequence< beans::PropertyValue > vPropVals = PropertyMap::GetPropertyValues();
+ const bool bIsSymbol(GetBulletChar().getLength() <= 1);
+ for( const auto& rPropNal : vPropVals )
+ if (! IgnoreForCharStyle(rPropNal.Name, bIsSymbol))
+ rProperties.emplace_back(rPropNal.Name, 0, rPropNal.Value, beans::PropertyState_DIRECT_VALUE);
+
+ return comphelper::containerToSequence(rProperties);
+}
+
+uno::Sequence<beans::PropertyValue> ListLevel::GetLevelProperties(bool bDefaults)
+{
+ std::vector<beans::PropertyValue> aNumberingProperties;
+
+ if (m_nIStartAt >= 0)
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_START_WITH, m_nIStartAt) );
+ else if (bDefaults)
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_START_WITH, 0));
+
+ sal_Int16 nNumberFormat = -1;
+ if (m_nNFC == NS_ooxml::LN_Value_ST_NumberFormat_custom)
+ {
+ nNumberFormat = ConversionHelper::ConvertCustomNumberFormat(m_aCustomNumberFormat);
+ }
+ else
+ {
+ nNumberFormat = ConversionHelper::ConvertNumberingType(m_nNFC);
+ }
+ if( m_nNFC >= 0)
+ {
+ if (m_xGraphicBitmap.is())
+ nNumberFormat = style::NumberingType::BITMAP;
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_NUMBERING_TYPE, nNumberFormat));
+ }
+
+ // todo: this is not the bullet char
+ if( nNumberFormat == style::NumberingType::CHAR_SPECIAL )
+ {
+ if (!GetBulletChar().isEmpty())
+ {
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_BULLET_CHAR, m_sBulletChar->copy(0, 1)));
+ }
+ else
+ {
+ // If w:lvlText's value is null - set bullet char to zero.
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Unicode>(PROP_BULLET_CHAR, 0));
+ }
+ }
+ if (m_xGraphicBitmap.is())
+ {
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_GRAPHIC_BITMAP, m_xGraphicBitmap));
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_GRAPHIC_SIZE, m_aGraphicSize));
+ }
+
+ if (m_nTabstop.has_value())
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_LISTTAB_STOP_POSITION, *m_nTabstop));
+ else if (bDefaults)
+ aNumberingProperties.push_back(lcl_makePropVal<sal_Int16>(PROP_LISTTAB_STOP_POSITION, 0));
+
+ //TODO: handling of nFLegal?
+ //TODO: nFNoRestart lower levels do not restart when higher levels are incremented, like:
+ //1.
+ //1.1
+ //2.2
+ //2.3
+ //3.4
+
+// TODO: sRGBXchNums; array of inherited numbers
+
+// nXChFollow; following character 0 - tab, 1 - space, 2 - nothing
+ if (bDefaults || m_nXChFollow != SvxNumberFormat::LISTTAB)
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_LEVEL_FOLLOW, m_nXChFollow));
+
+ PropertyIds const aReadIds[] =
+ {
+ PROP_ADJUST, PROP_INDENT_AT, PROP_FIRST_LINE_INDENT,
+ PROP_FIRST_LINE_OFFSET, PROP_LEFT_MARGIN
+ };
+ for(PropertyIds const & rReadId : aReadIds) {
+ std::optional<PropertyMap::Property> aProp = getProperty(rReadId);
+ if (aProp)
+ aNumberingProperties.emplace_back( getPropertyName(aProp->first), 0, aProp->second, beans::PropertyState_DIRECT_VALUE );
+ else if (rReadId == PROP_FIRST_LINE_INDENT && bDefaults)
+ // Writer default is -360 twips, Word default seems to be 0.
+ aNumberingProperties.emplace_back("FirstLineIndent", 0, uno::Any(static_cast<sal_Int32>(0)), beans::PropertyState_DIRECT_VALUE);
+ else if (rReadId == PROP_INDENT_AT && bDefaults)
+ // Writer default is 720 twips, Word default seems to be 0.
+ aNumberingProperties.emplace_back("IndentAt", 0,
+ uno::Any(static_cast<sal_Int32>(0)),
+ beans::PropertyState_DIRECT_VALUE);
+ }
+
+ std::optional<PropertyMap::Property> aPropFont = getProperty(PROP_CHAR_FONT_NAME);
+ if (aPropFont)
+ aNumberingProperties.emplace_back( getPropertyName(PROP_BULLET_FONT_NAME), 0, aPropFont->second, beans::PropertyState_DIRECT_VALUE );
+
+ if (m_bIsLegal)
+ aNumberingProperties.push_back(lcl_makePropVal(PROP_LEVEL_IS_LEGAL, true));
+
+ 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;
+
+ const OUString & sFirstLineIndent = getPropertyName(
+ PROP_FIRST_LINE_INDENT );
+ const 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->m_pProperties->GetPropertyValues( );
+
+ // ParaFirstLineIndent -> FirstLineIndent
+ // ParaLeftMargin -> IndentAt
+
+ const OUString & sParaIndent = getPropertyName(
+ PROP_PARA_FIRST_LINE_INDENT );
+ const OUString & sParaLeftMargin = getPropertyName(
+ PROP_PARA_LEFT_MARGIN );
+
+ for ( const auto& rParaProp : aParaProps )
+ {
+ if ( !hasFirstLineIndent && rParaProp.Name == sParaIndent )
+ {
+ aProps.realloc( aProps.getLength() + 1 );
+ auto pProps = aProps.getArray();
+ pProps[aProps.getLength( ) - 1] = rParaProp;
+ pProps[aProps.getLength( ) - 1].Name = sFirstLineIndent;
+ }
+ else if ( !hasIndentAt && rParaProp.Name == sParaLeftMargin )
+ {
+ aProps.realloc( aProps.getLength() + 1 );
+ auto pProps = aProps.getArray();
+ pProps[aProps.getLength( ) - 1] = rParaProp;
+ pProps[aProps.getLength( ) - 1].Name = sIndentAt;
+ }
+
+ }
+}
+
+NumPicBullet::NumPicBullet()
+ : m_nId(0)
+{
+}
+
+NumPicBullet::~NumPicBullet()
+{
+}
+
+void NumPicBullet::SetId(sal_Int32 nId)
+{
+ m_nId = nId;
+}
+
+void NumPicBullet::SetShape(uno::Reference<drawing::XShape> const& xShape)
+{
+ m_xShape = xShape;
+}
+
+
+//--------------------------------------- AbstractListDef implementation
+
+AbstractListDef::AbstractListDef( ) :
+ m_nId( -1 )
+{
+}
+
+AbstractListDef::~AbstractListDef( )
+{
+}
+
+void AbstractListDef::SetValue( sal_uInt32 nSprmId )
+{
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ break;
+ default:
+ OSL_FAIL( "this line should never be reached");
+ }
+}
+
+ListLevel::Pointer AbstractListDef::GetLevel( sal_uInt16 nLvl )
+{
+ ListLevel::Pointer pLevel;
+ if ( m_aLevels.size( ) > nLvl )
+ pLevel = m_aLevels[ nLvl ];
+ return pLevel;
+}
+
+void AbstractListDef::AddLevel( sal_uInt16 nLvl )
+{
+ if ( nLvl >= m_aLevels.size() )
+ m_aLevels.resize( nLvl+1 );
+
+ if (!m_aLevels[nLvl])
+ {
+ m_aLevels[nLvl] = new ListLevel;
+ }
+
+ m_pCurrentLevel = m_aLevels[nLvl];
+}
+
+uno::Sequence<uno::Sequence<beans::PropertyValue>> AbstractListDef::GetPropertyValues(bool bDefaults)
+{
+ uno::Sequence< uno::Sequence< beans::PropertyValue > > result( sal_Int32( m_aLevels.size( ) ) );
+ uno::Sequence< beans::PropertyValue >* aResult = result.getArray( );
+
+ int nLevels = m_aLevels.size( );
+ for ( int i = 0; i < nLevels; i++ )
+ {
+ if (m_aLevels[i])
+ aResult[i] = m_aLevels[i]->GetProperties(bDefaults);
+ }
+
+ return result;
+}
+
+const OUString& AbstractListDef::MapListId(OUString const& rId)
+{
+ if (!m_oListId)
+ {
+ m_oListId = rId;
+ }
+ return *m_oListId;
+}
+
+//---------------------------------------------- ListDef implementation
+
+ListDef::ListDef( )
+{
+}
+
+ListDef::~ListDef( )
+{
+}
+
+const OUString & ListDef::GetStyleName(sal_Int32 const nId,
+ uno::Reference<container::XNameContainer> const& xStyles)
+{
+ if (xStyles.is())
+ {
+ OUString sStyleName = "WWNum" + OUString::number( nId );
+
+ while (xStyles->hasByName(sStyleName)) // unique
+ {
+ sStyleName += "a";
+ }
+
+ m_StyleName = sStyleName;
+ }
+ else
+ {
+// fails in rtftok test assert(!m_StyleName.isEmpty()); // must be inited first
+ }
+
+ return m_StyleName;
+}
+
+uno::Sequence<uno::Sequence<beans::PropertyValue>> ListDef::GetMergedPropertyValues()
+{
+ if (!m_pAbstractDef)
+ return uno::Sequence< uno::Sequence< beans::PropertyValue > >();
+
+ // [1] Call the same method on the abstract list
+ uno::Sequence<uno::Sequence<beans::PropertyValue>> aAbstract
+ = m_pAbstractDef->GetPropertyValues(/*bDefaults=*/true);
+ auto aAbstractRange = asNonConstRange(aAbstract);
+
+ // [2] Call the upper class method
+ uno::Sequence<uno::Sequence<beans::PropertyValue>> aThis
+ = AbstractListDef::GetPropertyValues(/*bDefaults=*/false);
+
+ // Merge the results of [2] in [1]
+ sal_Int32 nThisCount = aThis.getLength( );
+ sal_Int32 nAbstractCount = aAbstract.getLength( );
+ for ( sal_Int32 i = 0; i < nThisCount && i < nAbstractCount; i++ )
+ {
+ uno::Sequence< beans::PropertyValue > level = aThis[i];
+ if (level.hasElements() && GetLevel(i)->HasValues())
+ {
+ // If the element contains something, merge it, but ignore stub overrides.
+ lcl_mergeProperties( level, aAbstractRange[i] );
+ }
+ }
+
+ return aAbstract;
+}
+
+static uno::Reference< container::XNameContainer > lcl_getUnoNumberingStyles(
+ uno::Reference<lang::XMultiServiceFactory> const& xFactory)
+{
+ uno::Reference< container::XNameContainer > xStyles;
+
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xFamilies( xFactory, uno::UNO_QUERY_THROW );
+ uno::Any oFamily = xFamilies->getStyleFamilies( )->getByName("NumberingStyles");
+
+ oFamily >>= xStyles;
+ }
+ catch ( const uno::Exception & )
+ {
+ }
+
+ return xStyles;
+}
+
+/// Rank the list in terms of suitability for becoming the Outline numbering rule in LO.
+sal_uInt16 ListDef::GetChapterNumberingWeight() const
+{
+ sal_Int16 nWeight = 0;
+ const sal_Int8 nAbstLevels = m_pAbstractDef ? m_pAbstractDef->Size() : 0;
+ for (sal_Int8 nLevel = 0; nLevel < nAbstLevels; ++nLevel)
+ {
+ const ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel(nLevel);
+ if (!pAbsLevel)
+ continue;
+ const StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle();
+ if (!pParaStyle)
+ continue;
+ const StyleSheetPropertyMap& rProps = *pParaStyle->m_pProperties;
+ // In LO, the level's paraStyle outlineLevel always matches this listLevel.
+ // An undefined listLevel is treated as the first level.
+ sal_Int8 nListLevel = std::clamp<sal_Int8>(rProps.GetListLevel(), 0, 9);
+ if (nListLevel != nLevel || rProps.GetOutlineLevel() != nLevel)
+ return 0;
+ else if (pAbsLevel->GetNumberingType(style::NumberingType::NUMBER_NONE)
+ != style::NumberingType::NUMBER_NONE)
+ {
+ // Arbitrarily chosen weighting factors - trying to round-trip LO choices if possible.
+ // LibreOffice always saves Outline rule (usually containing heading styles) as numId 1.
+ sal_uInt16 nWeightingFactor = GetId() == 1 ? 8 : 1;
+ if (pParaStyle->m_sStyleIdentifierD.startsWith("Heading") )
+ ++nWeightingFactor;
+ nWeight += nWeightingFactor;
+ }
+ }
+ return nWeight;
+}
+
+void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
+ uno::Reference<lang::XMultiServiceFactory> const& xFactory, sal_Int16 nOutline)
+{
+ // Get the UNO Numbering styles
+ uno::Reference< container::XNameContainer > xStyles = lcl_getUnoNumberingStyles( xFactory );
+
+ // Do the whole thing
+ if( !(!m_xNumRules.is() && xFactory.is() && xStyles.is( )) )
+ return;
+
+ try
+ {
+ // Create the numbering style
+ if (GetId() == nOutline)
+ m_StyleName = "Outline"; //SwNumRule.GetOutlineRuleName()
+ else
+ xStyles->insertByName(
+ GetStyleName(GetId(), xStyles),
+ css::uno::Any(xFactory->createInstance("com.sun.star.style.NumberingStyle")));
+
+ uno::Any oStyle = xStyles->getByName(GetStyleName());
+ uno::Reference< beans::XPropertySet > xStyle( oStyle, uno::UNO_QUERY_THROW );
+
+ // Get the default OOo Numbering style rules
+ uno::Any aRules = xStyle->getPropertyValue( getPropertyName( PROP_NUMBERING_RULES ) );
+ aRules >>= m_xNumRules;
+
+ uno::Sequence<uno::Sequence<beans::PropertyValue>> aProps = GetMergedPropertyValues();
+
+ sal_Int32 nAbstLevels = m_pAbstractDef ? m_pAbstractDef->Size() : 0;
+ sal_Int32 nLevel = 0;
+ while ( nLevel < nAbstLevels )
+ {
+ ListLevel::Pointer pAbsLevel = m_pAbstractDef->GetLevel( nLevel );
+ ListLevel::Pointer pLevel = GetLevel( nLevel );
+
+ // Get the merged level properties
+ auto aLvlProps = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aProps[nLevel]);
+
+ // Get the char style
+ auto aAbsCharStyleProps = pAbsLevel
+ ? pAbsLevel->GetCharStyleProperties()
+ : uno::Sequence<beans::PropertyValue>();
+ if ( pLevel )
+ {
+ uno::Sequence< beans::PropertyValue >& rAbsCharStyleProps = aAbsCharStyleProps;
+ uno::Sequence< beans::PropertyValue > aCharStyleProps =
+ pLevel->GetCharStyleProperties( );
+ uno::Sequence< beans::PropertyValue >& rCharStyleProps = aCharStyleProps;
+ lcl_mergeProperties( rAbsCharStyleProps, rCharStyleProps );
+ }
+
+ // Change the sequence into a vector
+ auto aStyleProps
+ = comphelper::sequenceToContainer<PropertyValueVector_t>(aAbsCharStyleProps);
+
+ //create (or find) a character style containing the character
+ // attributes of the symbol and apply it to the numbering level
+ OUString sStyle = rDMapper.getOrCreateCharStyle(aStyleProps, /*bAlwaysCreate=*/true);
+ aLvlProps.push_back(
+ comphelper::makePropertyValue(getPropertyName(PROP_CHAR_STYLE_NAME), sStyle));
+
+ OUString sText = pAbsLevel
+ ? pAbsLevel->GetBulletChar()
+ : OUString();
+ // Inherit <w:lvlText> from the abstract level in case the override would be empty.
+ if (pLevel && pLevel->HasBulletChar())
+ sText = pLevel->GetBulletChar( );
+
+ aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LIST_FORMAT), sText));
+
+ aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_POSITION_AND_SPACE_MODE), sal_Int16(text::PositionAndSpaceMode::LABEL_ALIGNMENT)));
+
+ // Replace the numbering rules for the level
+ m_xNumRules->replaceByIndex(nLevel, uno::Any(comphelper::containerToSequence(aLvlProps)));
+
+ // Handle the outline level here
+ if (GetId() == nOutline && pAbsLevel && pAbsLevel->GetParaStyle())
+ {
+ uno::Reference< text::XChapterNumberingSupplier > xOutlines (
+ xFactory, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexReplace > xOutlineRules =
+ xOutlines->getChapterNumberingRules( );
+
+ StyleSheetEntryPtr pParaStyle = pAbsLevel->GetParaStyle( );
+ pParaStyle->m_bAssignedAsChapterNumbering = true;
+ aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_HEADING_STYLE_NAME), pParaStyle->m_sConvertedStyleName));
+
+ xOutlineRules->replaceByIndex(nLevel, uno::Any(comphelper::containerToSequence(aLvlProps)));
+ }
+
+ nLevel++;
+ }
+
+ // Create the numbering style for these rules
+ const OUString & sNumRulesName = getPropertyName( PROP_NUMBERING_RULES );
+ xStyle->setPropertyValue( sNumRulesName, uno::Any( m_xNumRules ) );
+ }
+ catch( const lang::IllegalArgumentException& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "" );
+ assert( !"Incorrect argument to UNO call" );
+ }
+ catch( const uno::RuntimeException& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "" );
+ assert( !"Incorrect argument to UNO call" );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "" );
+ }
+
+}
+
+//------------------------------------- NumberingManager implementation
+
+
+ListsManager::ListsManager(DomainMapper& rDMapper,
+ uno::Reference<lang::XMultiServiceFactory> xFactory)
+ : LoggedProperties("ListsManager")
+ , LoggedTable("ListsManager")
+ , m_rDMapper(rDMapper)
+ , m_xFactory(std::move(xFactory))
+{
+}
+
+ListsManager::~ListsManager( )
+{
+ DisposeNumPicBullets();
+}
+
+void ListsManager::DisposeNumPicBullets( )
+{
+ uno::Reference<drawing::XShape> xShape;
+ for (const auto& rNumPicBullet : m_aNumPicBullets)
+ {
+ xShape = rNumPicBullet->GetShape();
+ if (xShape.is())
+ {
+ uno::Reference<lang::XComponent> xShapeComponent(xShape, uno::UNO_QUERY);
+ xShapeComponent->dispose();
+ }
+ }
+}
+
+void ListsManager::lcl_attribute( Id nName, Value& rVal )
+{
+ ListLevel::Pointer pCurrentLvl;
+
+ if (nName != NS_ooxml::LN_CT_NumPicBullet_numPicBulletId)
+ {
+ OSL_ENSURE( m_pCurrentDefinition, "current entry has to be set here");
+ if(!m_pCurrentDefinition)
+ return ;
+ pCurrentLvl = m_pCurrentDefinition->GetCurrentLevel( );
+ }
+ else
+ {
+ SAL_WARN_IF(!m_pCurrentNumPicBullet, "writerfilter", "current entry has to be set here");
+ if (!m_pCurrentNumPicBullet)
+ return;
+ }
+ int nIntValue = rVal.getInt();
+
+
+ switch(nName)
+ {
+ case NS_ooxml::LN_CT_LevelText_val:
+ {
+ if(pCurrentLvl)
+ {
+ //if the BulletChar is a soft-hyphen (0xad)
+ //replace it with a hard-hyphen (0x2d)
+ //-> this fixes missing hyphen export in PDF etc.
+ // see tdf#101626
+ std::string sLevelText( rVal.getString().replace(0xad, 0x2d).toUtf8() );
+
+ // DOCX level-text contains levels definition in format "%1.%2.%3"
+ // we need to convert it to LO internal representation: "%1%.%2%.%3%"
+ static const std::regex aTokenRegex("(%\\d)");
+ sLevelText = std::regex_replace(sLevelText, aTokenRegex, "$1%");
+ pCurrentLvl->SetBulletChar( OUString::fromUtf8(sLevelText) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_start:
+ case NS_ooxml::LN_CT_Lvl_numFmt:
+ case NS_ooxml::LN_CT_NumFmt_format:
+ case NS_ooxml::LN_CT_NumFmt_val:
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ if ( pCurrentLvl )
+ {
+ if (nName == NS_ooxml::LN_CT_NumFmt_format)
+ {
+ pCurrentLvl->SetCustomNumberFormat(rVal.getString());
+ }
+ else
+ {
+ pCurrentLvl->SetValue(nName, sal_Int32(nIntValue));
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Num_numId:
+ m_pCurrentDefinition->SetId( rVal.getString().toInt32( ) );
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_nsid:
+ m_pCurrentDefinition->SetId( nIntValue );
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ AbstractListDef::SetValue( nName );
+ break;
+ case NS_ooxml::LN_CT_NumLvl_ilvl:
+ //add a new level to the level vector and make it the current one
+ m_pCurrentDefinition->AddLevel(rVal.getString().toUInt32());
+ break;
+ case NS_ooxml::LN_CT_Lvl_ilvl:
+ m_pCurrentDefinition->AddLevel(rVal.getString().toUInt32());
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_abstractNumId:
+ {
+ // This one corresponds to the AbstractNum Id definition
+ // The reference to the abstract num is in the sprm method
+ sal_Int32 nVal = rVal.getString().toInt32();
+ m_pCurrentDefinition->SetId( nVal );
+ }
+ break;
+ case NS_ooxml::LN_CT_Ind_start:
+ case NS_ooxml::LN_CT_Ind_left:
+ if ( pCurrentLvl )
+ pCurrentLvl->Insert(
+ PROP_INDENT_AT, uno::Any( ConversionHelper::convertTwipToMM100( nIntValue ) ));
+ break;
+ case NS_ooxml::LN_CT_Ind_hanging:
+ if ( pCurrentLvl )
+ pCurrentLvl->Insert(
+ PROP_FIRST_LINE_INDENT, uno::Any( - ConversionHelper::convertTwipToMM100( nIntValue ) ));
+ break;
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ if ( pCurrentLvl )
+ pCurrentLvl->Insert(
+ PROP_FIRST_LINE_INDENT, uno::Any( ConversionHelper::convertTwipToMM100( nIntValue ) ));
+ break;
+ case NS_ooxml::LN_CT_Lvl_tplc: //template code - unsupported
+ case NS_ooxml::LN_CT_Lvl_tentative: //marks level as unused in the document - unsupported
+ break;
+ case NS_ooxml::LN_CT_TabStop_pos:
+ {
+ //no paragraph attributes in ListTable char style sheets
+ if ( pCurrentLvl )
+ pCurrentLvl->SetValue( nName,
+ ConversionHelper::convertTwipToMM100( nIntValue ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_TabStop_val:
+ {
+ // TODO Do something of that
+ }
+ break;
+ case NS_ooxml::LN_CT_NumPicBullet_numPicBulletId:
+ m_pCurrentNumPicBullet->SetId(rVal.getString().toInt32());
+ break;
+ default:
+ SAL_WARN("writerfilter", "ListsManager::lcl_attribute: unhandled token: " << nName);
+ }
+}
+
+void ListsManager::lcl_sprm( Sprm& rSprm )
+{
+ //fill the attributes of the style sheet
+ sal_uInt32 nSprmId = rSprm.getId();
+ if( !(m_pCurrentDefinition ||
+ nSprmId == NS_ooxml::LN_CT_Numbering_abstractNum ||
+ nSprmId == NS_ooxml::LN_CT_Numbering_num ||
+ (nSprmId == NS_ooxml::LN_CT_NumPicBullet_pict && m_pCurrentNumPicBullet) ||
+ nSprmId == NS_ooxml::LN_CT_Numbering_numPicBullet))
+ return;
+
+ static bool bIsStartVisited = false;
+ sal_Int32 nIntValue = rSprm.getValue()->getInt();
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_Numbering_abstractNum:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ {
+ //create a new Abstract list entry
+ OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
+ m_pCurrentDefinition = new AbstractListDef;
+ pProperties->resolve( *this );
+ //append it to the table
+ m_aAbstractLists.push_back( m_pCurrentDefinition );
+ m_pCurrentDefinition = AbstractListDef::Pointer();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Numbering_num:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ {
+ // Create a new list entry
+ OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
+ ListDef::Pointer listDef( new ListDef );
+ m_pCurrentDefinition = listDef.get();
+ pProperties->resolve( *this );
+ //append it to the table
+ m_aLists.push_back( listDef );
+
+ m_pCurrentDefinition = AbstractListDef::Pointer();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Numbering_numPicBullet:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ NumPicBullet::Pointer numPicBullet(new NumPicBullet());
+ m_pCurrentNumPicBullet = numPicBullet;
+ pProperties->resolve(*this);
+ m_aNumPicBullets.push_back(numPicBullet);
+ m_pCurrentNumPicBullet = NumPicBullet::Pointer();
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_NumPicBullet_pict:
+ {
+ uno::Reference<drawing::XShape> xShape = m_rDMapper.PopPendingShape();
+
+ m_pCurrentNumPicBullet->SetShape(xShape);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_lvlPicBulletId:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ uno::Reference<drawing::XShape> xShape;
+ for (const auto& rNumPicBullet : m_aNumPicBullets)
+ {
+ if (rNumPicBullet->GetId() == nIntValue)
+ {
+ xShape = rNumPicBullet->GetShape();
+ break;
+ }
+ }
+ if (xShape.is())
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ try
+ {
+ uno::Any aAny = xPropertySet->getPropertyValue("Graphic");
+ if (aAny.has<uno::Reference<graphic::XGraphic>>() && pCurrentLevel)
+ {
+ auto xGraphic = aAny.get<uno::Reference<graphic::XGraphic>>();
+ if (xGraphic.is())
+ {
+ uno::Reference<awt::XBitmap> xBitmap(xGraphic, uno::UNO_QUERY);
+ pCurrentLevel->SetGraphicBitmap(xBitmap);
+ }
+ }
+ }
+ catch (const beans::UnknownPropertyException&)
+ {}
+
+ // Respect only the aspect ratio of the picture, not its size.
+ awt::Size aPrefSize = xShape->getSize();
+ if ( aPrefSize.Height * aPrefSize.Width != 0 )
+ {
+ // See SwDefBulletConfig::InitFont(), default height is 14.
+ const int nFontHeight = 14;
+ // Point -> mm100.
+ const int nHeight = nFontHeight * 35;
+ int nWidth = (nHeight * aPrefSize.Width) / aPrefSize.Height;
+
+ awt::Size aSize( o3tl::toTwips(nWidth, o3tl::Length::mm100), o3tl::toTwips(nHeight, o3tl::Length::mm100) );
+ pCurrentLevel->SetGraphicSize( aSize );
+ }
+ else
+ {
+ awt::Size aSize( o3tl::toTwips(aPrefSize.Width, o3tl::Length::mm100), o3tl::toTwips(aPrefSize.Height, o3tl::Length::mm100) );
+ pCurrentLevel->SetGraphicSize( aSize );
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Num_abstractNumId:
+ {
+ sal_Int32 nAbstractNumId = rSprm.getValue()->getInt();
+ ListDef* pListDef = dynamic_cast< ListDef* >( m_pCurrentDefinition.get( ) );
+ if ( pListDef != nullptr )
+ {
+ // The current def should be a ListDef
+ pListDef->SetAbstractDefinition(
+ GetAbstractList( nAbstractNumId ) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_multiLevelType:
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_tmpl:
+ AbstractListDef::SetValue( nSprmId );
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_lvl:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_start:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ pCurrentLevel->SetValue( nSprmId, nIntValue );
+ bIsStartVisited = true;
+ break;
+ case NS_ooxml::LN_CT_Lvl_numFmt:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ if( !bIsStartVisited )
+ {
+ pCurrentLevel->SetValue( NS_ooxml::LN_CT_Lvl_start, 0 );
+ bIsStartVisited = true;
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_isLgl:
+ case NS_ooxml::LN_CT_Lvl_legacy:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ pCurrentLevel->SetValue(nSprmId, nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_suff:
+ {
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ SvxNumberFormat::LabelFollowedBy value = SvxNumberFormat::LISTTAB;
+ if( rSprm.getValue()->getString() == "tab" )
+ value = SvxNumberFormat::LISTTAB;
+ else if( rSprm.getValue()->getString() == "space" )
+ value = SvxNumberFormat::SPACE;
+ else if( rSprm.getValue()->getString() == "nothing" )
+ value = SvxNumberFormat::NOTHING;
+ else
+ SAL_WARN( "writerfilter", "Unknown ST_LevelSuffix value "
+ << rSprm.getValue()->getString());
+ pCurrentLevel->SetValue( nSprmId, value );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_lvlText:
+ case NS_ooxml::LN_CT_Lvl_rPr : //contains LN_EG_RPrBase_rFonts
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumLvl_lvl:
+ {
+ // overwrite level
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_lvlJc:
+ {
+ sal_Int16 nValue = text::HoriOrientation::NONE;
+ switch (nIntValue)
+ {
+ case NS_ooxml::LN_Value_ST_Jc_left:
+ case NS_ooxml::LN_Value_ST_Jc_start:
+ nValue = text::HoriOrientation::LEFT;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_center:
+ nValue = text::HoriOrientation::CENTER;
+ break;
+ case NS_ooxml::LN_Value_ST_Jc_right:
+ case NS_ooxml::LN_Value_ST_Jc_end:
+ nValue = text::HoriOrientation::RIGHT;
+ break;
+ }
+
+ if (nValue != text::HoriOrientation::NONE)
+ {
+ if (ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ pLevel->Insert(
+ PROP_ADJUST, uno::Any( nValue ) );
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_pPr:
+ case NS_ooxml::LN_CT_PPrBase_ind:
+ {
+ //todo: how to handle paragraph properties within numbering levels (except LeftIndent and FirstLineIndent)?
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_PPrBase_tabs:
+ case NS_ooxml::LN_CT_Tabs_tab:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if(pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_Lvl_pStyle:
+ {
+ OUString sStyleName = rSprm.getValue( )->getString( );
+ if (ListLevel::Pointer pLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
+ const StyleSheetEntryPtr pStyle = pStylesTable->FindStyleSheetByISTD( sStyleName );
+ pLevel->SetParaStyle( pStyle );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Num_lvlOverride:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumLvl_startOverride:
+ {
+ if(m_pCurrentDefinition)
+ {
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ pCurrentLevel->SetValue(NS_ooxml::LN_CT_NumLvl_startOverride, nIntValue);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_numStyleLink:
+ {
+ OUString sStyleName = rSprm.getValue( )->getString( );
+ m_pCurrentDefinition->SetNumStyleLink(sStyleName);
+ }
+ break;
+ case NS_ooxml::LN_CT_AbstractNum_styleLink:
+ {
+ OUString sStyleName = rSprm.getValue()->getString();
+ m_pCurrentDefinition->SetStyleLink(sStyleName);
+ }
+ break;
+ case NS_ooxml::LN_EG_RPrBase_rFonts: //contains font properties
+ case NS_ooxml::LN_EG_RPrBase_color:
+ case NS_ooxml::LN_EG_RPrBase_u:
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ case NS_ooxml::LN_EG_RPrBase_lang:
+ case NS_ooxml::LN_EG_RPrBase_eastAsianLayout:
+ //no break!
+ default:
+ if (ListLevel::Pointer pCurrentLevel = m_pCurrentDefinition->GetCurrentLevel())
+ {
+ m_rDMapper.PushListProperties(pCurrentLevel.get());
+ m_rDMapper.sprm( rSprm );
+ m_rDMapper.PopListProperties();
+ }
+ }
+}
+
+void ListsManager::lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref)
+{
+ if( m_rDMapper.IsOOXMLImport() || m_rDMapper.IsRTFImport() )
+ {
+ ref->resolve(*this);
+ }
+ else
+ {
+ // Create AbstractListDef's
+ OSL_ENSURE( !m_pCurrentDefinition, "current entry has to be NULL here");
+ m_pCurrentDefinition = new AbstractListDef( );
+ ref->resolve(*this);
+ //append it to the table
+ m_aAbstractLists.push_back( m_pCurrentDefinition );
+ m_pCurrentDefinition = AbstractListDef::Pointer();
+ }
+}
+
+AbstractListDef::Pointer ListsManager::GetAbstractList( sal_Int32 nId )
+{
+ for (const auto& listDef : m_aAbstractLists)
+ {
+ if (listDef->GetId( ) == nId)
+ {
+ if (listDef->GetNumStyleLink().getLength() > 0)
+ {
+ // If the abstract num has a style linked, check the linked style's number id.
+ StyleSheetTablePtr pStylesTable = m_rDMapper.GetStyleSheetTable( );
+
+ const StyleSheetEntryPtr pStyleSheetEntry =
+ pStylesTable->FindStyleSheetByISTD(listDef->GetNumStyleLink() );
+
+ const StyleSheetPropertyMap* pStyleSheetProperties =
+ pStyleSheetEntry ? pStyleSheetEntry->m_pProperties.get() : nullptr;
+
+ if( pStyleSheetProperties && pStyleSheetProperties->props().GetListId() >= 0 )
+ {
+ ListDef::Pointer pList = GetList( pStyleSheetProperties->props().GetListId() );
+ if ( pList!=nullptr )
+ return pList->GetAbstractDefinition();
+ }
+
+ // In stylesheet we did not found anything useful. Try to find base abstractnum having this stylelink
+ for (const auto & baseListDef : m_aAbstractLists)
+ {
+ if (baseListDef->GetStyleLink() == listDef->GetNumStyleLink())
+ {
+ return baseListDef;
+ }
+ }
+ }
+
+ // Standalone abstract list
+ return listDef;
+ }
+ }
+
+ return nullptr;
+}
+
+ListDef::Pointer ListsManager::GetList( sal_Int32 nId )
+{
+ ListDef::Pointer pList;
+ if (nId == -1)
+ return pList;
+
+ int nLen = m_aLists.size( );
+ int i = 0;
+ while ( !pList && i < nLen )
+ {
+ if ( m_aLists[i]->GetId( ) == nId )
+ pList = m_aLists[i];
+ i++;
+ }
+
+ // nId 0 is only valid for abstractNum, not numId (which has an abstract definition)
+ assert(!pList || nId || !pList->GetAbstractDefinition() || m_rDMapper.IsRTFImport());
+
+ return pList;
+}
+
+void ListsManager::CreateNumberingRules( )
+{
+ // Try to determine which numId would best work as LO's Chapter Numbering Outline rule.
+ // (The best fix for many import bugs is just to prevent ANY assignment as chapter numbering.)
+ sal_Int16 nChosenAsChapterNumberingId = -1;
+ sal_uInt16 nHighestWeight = 5; // arbitrarily chosen minimum threshold
+ for (const auto& rList : m_aLists)
+ {
+ sal_uInt16 nWeight = rList->GetChapterNumberingWeight();
+ if (nWeight > nHighestWeight)
+ {
+ nHighestWeight = nWeight;
+ nChosenAsChapterNumberingId = rList->GetId();
+ //Optimization: if the weight cannot be beaten anymore, then quit early
+ if (nHighestWeight > 17)
+ break;
+ }
+ }
+
+ // Loop over the definitions
+ for ( const auto& rList : m_aLists )
+ {
+ rList->CreateNumberingRules(m_rDMapper, m_xFactory, nChosenAsChapterNumberingId);
+ }
+ m_rDMapper.GetStyleSheetTable()->ReApplyInheritedOutlineLevelFromChapterNumbering();
+ m_rDMapper.GetStyleSheetTable()->ApplyNumberingStyleNameToParaStyles();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/NumberingManager.hxx b/sw/source/writerfilter/dmapper/NumberingManager.hxx
new file mode 100644
index 000000000000..64156ba60ceb
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/NumberingManager.hxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "PropertyMap.hxx"
+
+#include "DomainMapper.hxx"
+#include "LoggedResources.hxx"
+#include "StyleSheetTable.hxx"
+
+#include <editeng/numitem.hxx>
+
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+class StyleSheetEntry;
+
+
+/** Class representing the numbering level properties.
+ */
+class ListLevel : public PropertyMap
+{
+ sal_Int32 m_nIStartAt; //LN_CT_Lvl_start
+ sal_Int32 m_nStartOverride;
+ sal_Int32 m_nNFC; //LN_CT_Lvl_numFmt
+ /// LN_CT_NumFmt_format, in case m_nNFC is custom.
+ OUString m_aCustomNumberFormat;
+ sal_Int16 m_nXChFollow; //LN_IXCHFOLLOW
+ std::optional<OUString> m_sBulletChar;
+ css::awt::Size m_aGraphicSize;
+ css::uno::Reference<css::awt::XBitmap> m_xGraphicBitmap;
+ std::optional<sal_Int32> m_nTabstop;
+ tools::SvRef< StyleSheetEntry > m_pParaStyle;
+ bool m_bHasValues = false;
+ bool m_bIsLegal = false;
+
+public:
+
+ typedef tools::SvRef< ListLevel > Pointer;
+
+ ListLevel() :
+ m_nIStartAt(-1)
+ ,m_nStartOverride(-1)
+ ,m_nNFC(-1)
+ ,m_nXChFollow(SvxNumberFormat::LISTTAB)
+ {}
+
+ // Setters for the import
+ void SetValue( Id nId, sal_Int32 nValue );
+ void SetCustomNumberFormat(const OUString& rValue);
+ void SetBulletChar( const OUString& sValue ) { m_sBulletChar = sValue; };
+ void SetGraphicSize( const css::awt::Size& aValue ) { m_aGraphicSize = aValue; };
+
+ void SetGraphicBitmap(css::uno::Reference<css::awt::XBitmap> const& xGraphicBitmap)
+ { m_xGraphicBitmap = xGraphicBitmap; }
+ void SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle );
+
+ // Getters
+ sal_Int16 GetNumberingType(sal_Int16 nDefault) const;
+ bool HasBulletChar() const { return m_sBulletChar.has_value(); };
+ OUString GetBulletChar( ) const { return m_sBulletChar.has_value()? *m_sBulletChar : OUString(); };
+ const tools::SvRef< StyleSheetEntry >& GetParaStyle( ) const { return m_pParaStyle; };
+ sal_Int32 GetStartOverride() const { return m_nStartOverride; };
+ /// Determines if SetValue() was called at least once.
+ bool HasValues() const;
+
+ // UNO mapping functions
+ css::uno::Sequence<css::beans::PropertyValue> GetProperties(bool bDefaults);
+
+ css::uno::Sequence<css::beans::PropertyValue> GetCharStyleProperties();
+private:
+
+ css::uno::Sequence<css::beans::PropertyValue> GetLevelProperties(bool bDefaults);
+
+ void AddParaProperties(css::uno::Sequence<css::beans::PropertyValue>* pProps);
+};
+
+/// Represents a numbering picture bullet: an id and a graphic.
+class NumPicBullet final : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<NumPicBullet> Pointer;
+ NumPicBullet();
+ ~NumPicBullet() override;
+
+ void SetId(sal_Int32 nId);
+ sal_Int32 GetId() const { return m_nId;}
+ void SetShape(css::uno::Reference<css::drawing::XShape> const& xShape);
+ const css::uno::Reference<css::drawing::XShape>& GetShape() const { return m_xShape; }
+private:
+ sal_Int32 m_nId;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+};
+
+class AbstractListDef : public virtual SvRefBase
+{
+private:
+ // The ID member reflects either the abstractNumId or the numId
+ // depending on the use of the class
+ sal_Int32 m_nId;
+
+ // Properties of each level. This can also reflect the overridden
+ // levels of a numbering.
+ ::std::vector< ListLevel::Pointer > m_aLevels;
+
+ // Only used during the numbering import
+ ListLevel::Pointer m_pCurrentLevel;
+
+ // The style name linked to.
+ OUString m_sNumStyleLink;
+
+ // This abstract numbering is a base definition for this style
+ OUString m_sStyleLink;
+
+ /// list id to use for all derived numbering definitions
+ std::optional<OUString> m_oListId;
+
+public:
+ typedef tools::SvRef< AbstractListDef > Pointer;
+
+ AbstractListDef( );
+ virtual ~AbstractListDef( ) override;
+
+ // Setters using during the import
+ void SetId( sal_Int32 nId ) { m_nId = nId; };
+ static void SetValue( sal_uInt32 nSprmId );
+
+ // Accessors
+ sal_Int32 GetId( ) const { return m_nId; };
+
+ sal_Int16 Size( ) { return sal_Int16( m_aLevels.size( ) ); };
+ ListLevel::Pointer GetLevel( sal_uInt16 nLvl );
+ void AddLevel( sal_uInt16 nLvl );
+
+ const ListLevel::Pointer& GetCurrentLevel( ) const { return m_pCurrentLevel; };
+
+ css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValue> > GetPropertyValues(bool bDefaults);
+
+ void SetNumStyleLink(const OUString& sValue) { m_sNumStyleLink = sValue; };
+ const OUString& GetNumStyleLink() const { return m_sNumStyleLink; };
+
+ void SetStyleLink(const OUString& sValue) { m_sStyleLink = sValue; };
+ const OUString& GetStyleLink() const { return m_sStyleLink; };
+
+ const OUString& MapListId(OUString const& rId);
+};
+
+class ListDef : public AbstractListDef
+{
+private:
+ // Pointer to the abstract numbering
+ AbstractListDef::Pointer m_pAbstractDef;
+
+ // Cache for the UNO numbering rules
+ css::uno::Reference< css::container::XIndexReplace > m_xNumRules;
+
+ /// mapped list style name
+ OUString m_StyleName;
+
+public:
+ typedef tools::SvRef< ListDef > Pointer;
+
+ ListDef( );
+ virtual ~ListDef( ) override;
+
+ // Accessors
+ void SetAbstractDefinition(const AbstractListDef::Pointer& pAbstract) { m_pAbstractDef = pAbstract; };
+ const AbstractListDef::Pointer& GetAbstractDefinition( ) const { return m_pAbstractDef; };
+
+ // Mapping functions
+ const OUString & GetStyleName() const { return m_StyleName; };
+ const OUString & GetStyleName(sal_Int32 nId, css::uno::Reference<css::container::XNameContainer> const& xStyles);
+
+ css::uno::Sequence< css::uno::Sequence<css::beans::PropertyValue> > GetMergedPropertyValues();
+
+ sal_uInt16 GetChapterNumberingWeight() const;
+ void CreateNumberingRules(DomainMapper& rDMapper, css::uno::Reference<css::lang::XMultiServiceFactory> const& xFactory, sal_Int16 nOutline);
+
+ const css::uno::Reference<css::container::XIndexReplace>& GetNumberingRules() const { return m_xNumRules; }
+
+};
+
+/** This class provides access to the defined numbering styles.
+ */
+class ListsManager :
+ public LoggedProperties,
+ public LoggedTable
+{
+private:
+
+ DomainMapper& m_rDMapper;
+ css::uno::Reference<css::lang::XMultiServiceFactory> m_xFactory;
+
+ // The numbering entries
+ std::vector< NumPicBullet::Pointer > m_aNumPicBullets;
+ std::vector< AbstractListDef::Pointer > m_aAbstractLists;
+ std::vector< ListDef::Pointer > m_aLists;
+
+
+ // These members are used for import only
+ AbstractListDef::Pointer m_pCurrentDefinition;
+ NumPicBullet::Pointer m_pCurrentNumPicBullet;
+
+ AbstractListDef::Pointer GetAbstractList( sal_Int32 nId );
+
+ // Properties
+ virtual void lcl_attribute( Id nName, Value & rVal ) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+ // Table
+ virtual void lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+
+public:
+
+ ListsManager(DomainMapper& rDMapper, css::uno::Reference<css::lang::XMultiServiceFactory> xFactory);
+ virtual ~ListsManager() override;
+
+ typedef tools::SvRef< ListsManager > Pointer;
+
+ ListDef::Pointer GetList( sal_Int32 nId );
+
+ // Mapping methods
+ void CreateNumberingRules( );
+
+ // Dispose the NumPicBullets
+ void DisposeNumPicBullets( );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/OLEHandler.cxx b/sw/source/writerfilter/dmapper/OLEHandler.cxx
new file mode 100644
index 000000000000..e0671c8a21b6
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/OLEHandler.cxx
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "OLEHandler.hxx"
+#include "DomainMapper.hxx"
+#include "GraphicHelpers.hxx"
+
+#include <oox/ole/oleobjecthelper.hxx>
+#include <ooxml/resourceids.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/diagnose_ex.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/document/XEmbeddedObjectResolver.hpp>
+#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace writerfilter::dmapper {
+
+using namespace ::com::sun::star;
+
+
+OLEHandler::OLEHandler(DomainMapper& rDomainMapper) :
+LoggedProperties("OLEHandler"),
+ m_nWrapMode(text::WrapTextMode_THROUGHT),
+ m_rDomainMapper(rDomainMapper)
+{
+}
+
+
+OLEHandler::~OLEHandler()
+{
+}
+
+
+void OLEHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ OUString sStringValue = rVal.getString();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_OLEObject_Type:
+ break;
+ case NS_ooxml::LN_CT_OLEObject_ProgID:
+ m_sProgId = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_OLEObject_ShapeID:
+ break;
+ case NS_ooxml::LN_CT_OLEObject_DrawAspect:
+ m_sDrawAspect = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_OLEObject_ObjectID:
+ break;
+ case NS_ooxml::LN_CT_OLEObject_r_id:
+ break;
+ case NS_ooxml::LN_inputstream:
+ rVal.getAny() >>= m_xInputStream;
+ break;
+ case NS_ooxml::LN_CT_Object_dxaOrig:
+ m_sVisAreaWidth = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_Object_dyaOrig:
+ m_sVisAreaHeight = sStringValue;
+ break;
+ case NS_ooxml::LN_shape:
+ {
+ uno::Reference< drawing::XShape > xTempShape;
+ rVal.getAny() >>= xTempShape;
+
+ // Control shape is handled on a different code path
+ uno::Reference< lang::XServiceInfo > xSInfo( xTempShape, uno::UNO_QUERY_THROW );
+ if(xSInfo->supportsService("com.sun.star.drawing.ControlShape"))
+ {
+ m_rDomainMapper.hasControls(true);
+ break;
+ }
+
+ if( xTempShape.is() )
+ {
+ m_xShape.set( xTempShape );
+
+ // No need to set the wrapping here as it's either set in oox or will be set later
+
+ // Shapes in the header or footer should be in the background, since the default is WrapTextMode_THROUGH.
+ if (m_rDomainMapper.IsInHeaderFooter())
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xShapeProps(m_xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("Opaque", uno::Any(false));
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Exception in OLE Handler");
+ }
+ }
+ }
+ }
+ break;
+ default:
+ OSL_FAIL( "unknown attribute");
+ }
+}
+
+css::awt::Size OLEHandler::getSize() const
+{
+ if (!m_xShape)
+ return css::awt::Size();
+ return m_xShape->getSize();
+}
+
+css::uno::Reference<css::graphic::XGraphic> OLEHandler::getReplacement() const
+{
+ if (!m_xShape)
+ return nullptr;
+ uno::Reference<beans::XPropertySet> xShapeProps(m_xShape, uno::UNO_QUERY);
+ css::uno::Reference<css::graphic::XGraphic> xReplacement;
+ xShapeProps->getPropertyValue(getPropertyName(PROP_BITMAP)) >>= xReplacement;
+ return xReplacement;
+}
+
+void OLEHandler::lcl_sprm(Sprm & rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_OLEObject_OLEObject:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_wrap_wrap:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if ( pProperties )
+ {
+ tools::SvRef<WrapHandler> pHandler( new WrapHandler );
+ pProperties->resolve( *pHandler );
+
+ m_nWrapMode = pHandler->getWrapMode( );
+
+ try
+ {
+ uno::Reference< beans::XPropertySet > xShapeProps( m_xShape, uno::UNO_QUERY_THROW );
+
+ xShapeProps->setPropertyValue(
+ getPropertyName( PROP_SURROUND ),
+ uno::Any( static_cast<sal_Int32>(m_nWrapMode) ) );
+
+ // Through shapes in the header or footer(that spill into the body) should be in the background.
+ // It is just assumed that all shapes will spill into the body.
+ if( m_rDomainMapper.IsInHeaderFooter() )
+ xShapeProps->setPropertyValue("Opaque", uno::Any(m_nWrapMode != text::WrapTextMode_THROUGH));
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Exception in OLE Handler");
+ }
+ }
+ }
+ break;
+ default:
+ {
+ OSL_FAIL( "unknown attribute");
+ }
+ }
+}
+
+void OLEHandler::importStream(const uno::Reference<uno::XComponentContext>& xComponentContext, const uno::Reference<text::XTextDocument>& xTextDocument, const uno::Reference<text::XTextContent>& xOLE)
+{
+ OUString aFilterService;
+ if (m_sProgId == "Word.Document.12")
+ aFilterService = "com.sun.star.comp.Writer.WriterFilter";
+ else if (m_sProgId == "Excel.Sheet.12")
+ aFilterService = "com.sun.star.comp.oox.xls.ExcelFilter";
+ else if (m_sProgId == "Equation.3")
+ aFilterService = "com.sun.star.comp.Math.MathTypeFilter";
+ else
+ SAL_WARN("writerfilter", "OLEHandler::importStream: unhandled m_sProgId: " << m_sProgId);
+
+ if (!m_xInputStream.is() || aFilterService.isEmpty())
+ return;
+
+ // Create the filter service.
+ uno::Reference<uno::XInterface> xInterface = xComponentContext->getServiceManager()->createInstanceWithContext(aFilterService, xComponentContext);
+
+ // Set target document.
+ uno::Reference<document::XImporter> xImporter(xInterface, uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier> xSupplier(xOLE, uno::UNO_QUERY);
+ uno::Reference<lang::XComponent> xEmbeddedObject = xSupplier->getEmbeddedObject();
+ if (!xEmbeddedObject.is())
+ return;
+ xImporter->setTargetDocument( xEmbeddedObject );
+
+ // Import the input stream.
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["InputStream"] <<= m_xInputStream;
+ uno::Reference<document::XFilter> xFilter(xInterface, uno::UNO_QUERY);
+ xFilter->filter(aMediaDescriptor.getAsConstPropertyValueList());
+
+ // Now that the data is imported, update the (typically) changed stream name.
+ uno::Reference<beans::XPropertySet> xPropertySet(xOLE, uno::UNO_QUERY);
+ ::oox::ole::SaveInteropProperties(xTextDocument,
+ xPropertySet->getPropertyValue("StreamName").get<OUString>(), &m_aURL,
+ m_sProgId);
+}
+
+OUString OLEHandler::getCLSID() const
+{
+ OUString aRet;
+
+ // See officecfg/registry/data/org/openoffice/Office/Embedding.xcu.
+ if (m_sProgId == "Word.Document.12")
+ {
+ if (officecfg::Office::Common::Filter::Microsoft::Import::WinWordToWriter::get())
+ aRet = "8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6";
+ }
+ else if (m_sProgId == "Excel.Sheet.12")
+ {
+ if (officecfg::Office::Common::Filter::Microsoft::Import::ExcelToCalc::get())
+ aRet = "47BBB4CB-CE4C-4E80-A591-42D9AE74950F";
+ }
+ else if (m_sProgId == "Equation.3")
+ {
+ if (officecfg::Office::Common::Filter::Microsoft::Import::MathTypeToMath::get())
+ aRet = "078B7ABA-54FC-457F-8551-6147E776A997";
+ }
+ else
+ SAL_WARN("writerfilter", "OLEHandler::getCLSID: unhandled m_sProgId: " << m_sProgId);
+
+ return aRet;
+}
+
+OUString const & OLEHandler::GetDrawAspect() const
+{
+ return m_sDrawAspect;
+}
+
+OUString const & OLEHandler::GetVisAreaWidth() const
+{
+ return m_sVisAreaWidth;
+}
+
+OUString const & OLEHandler::GetVisAreaHeight() const
+{
+ return m_sVisAreaHeight;
+}
+
+OUString OLEHandler::copyOLEOStream(
+ uno::Reference<text::XTextDocument> const& xTextDocument)
+{
+ OUString sRet;
+ if( !m_xInputStream.is( ) )
+ return sRet;
+ try
+ {
+ uno::Reference < lang::XMultiServiceFactory > xFactory(xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference< document::XEmbeddedObjectResolver > xEmbeddedResolver(
+ xFactory->createInstance("com.sun.star.document.ImportEmbeddedObjectResolver"), uno::UNO_QUERY_THROW );
+ //hack to work with the ImportEmbeddedObjectResolver
+ static sal_Int32 nObjectCount = 100;
+ uno::Reference< container::XNameAccess > xNA( xEmbeddedResolver, uno::UNO_QUERY_THROW );
+ OUString aURL = "Obj" + OUString::number( nObjectCount++ );
+ uno::Reference < io::XOutputStream > xOLEStream;
+ if( (xNA->getByName( aURL ) >>= xOLEStream) && xOLEStream.is() )
+ {
+ const sal_Int32 nReadRequest = 0x1000;
+ uno::Sequence< sal_Int8 > aData;
+
+ while( true )
+ {
+ sal_Int32 nRead = m_xInputStream->readBytes( aData, nReadRequest );
+ xOLEStream->writeBytes( aData );
+ if( nRead < nReadRequest )
+ {
+ xOLEStream->closeOutput();
+ break;
+ }
+ }
+
+ ::oox::ole::SaveInteropProperties(xTextDocument, aURL, nullptr, m_sProgId);
+
+ OUString aPersistName( xEmbeddedResolver->resolveEmbeddedObjectURL( aURL ) );
+ sRet = aPersistName.copy( strlen("vnd.sun.star.EmbeddedObject:") );
+
+ }
+ uno::Reference< lang::XComponent > xComp( xEmbeddedResolver, uno::UNO_QUERY_THROW );
+ xComp->dispose();
+ m_aURL = aURL;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "OLEHandler::createOLEObject");
+ }
+ return sRet;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/OLEHandler.hxx b/sw/source/writerfilter/dmapper/OLEHandler.hxx
new file mode 100644
index 000000000000..67fed0128186
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/OLEHandler.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+
+namespace com::sun::star{
+ namespace graphic{
+ class XGraphic;
+ }
+ namespace io{
+ class XInputStream;
+ }
+ namespace text{
+ class XTextContent;
+ class XTextDocument;
+ }
+ namespace uno {
+ class XComponentContext;
+ }
+}
+namespace writerfilter::dmapper
+{
+class DomainMapper;
+/** Handler for OLE objects
+ */
+class OLEHandler : public LoggedProperties
+{
+ OUString m_sProgId;
+ OUString m_sDrawAspect;
+ OUString m_sVisAreaWidth;
+ OUString m_sVisAreaHeight;
+ /// The stream URL right after the import of the raw data.
+ OUString m_aURL;
+
+ css::text::WrapTextMode m_nWrapMode;
+
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+
+ css::uno::Reference<css::io::XInputStream> m_xInputStream;
+ DomainMapper& m_rDomainMapper;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ explicit OLEHandler(DomainMapper& rDomainMapper);
+ virtual ~OLEHandler() override;
+
+ const css::uno::Reference<css::drawing::XShape>& getShape() const { return m_xShape; };
+
+ bool isOLEObject() const { return m_xInputStream.is(); }
+
+ /// In case of a valid CLSID, import the native data to the previously created empty OLE object.
+ void importStream(const css::uno::Reference<css::uno::XComponentContext>& xComponentContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument,
+ const css::uno::Reference<css::text::XTextContent>& xOLE);
+
+ /// Get the CLSID of the OLE object, in case we can find one based on m_sProgId.
+ OUString getCLSID() const;
+
+ OUString const & GetDrawAspect() const;
+ OUString const & GetVisAreaWidth() const;
+ OUString const & GetVisAreaHeight() const;
+
+ OUString copyOLEOStream(css::uno::Reference<css::text::XTextDocument> const& xTextDocument);
+
+ css::awt::Size getSize() const;
+ css::uno::Reference<css::graphic::XGraphic> getReplacement() const;
+
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PageBordersHandler.cxx b/sw/source/writerfilter/dmapper/PageBordersHandler.cxx
new file mode 100644
index 000000000000..89548eb351ee
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PageBordersHandler.cxx
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "BorderHandler.hxx"
+#include "PageBordersHandler.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper {
+
+PgBorder::PgBorder( ) :
+ m_nDistance( 0 ),
+ m_ePos( BORDER_RIGHT ),
+ m_bShadow(false)
+{
+}
+
+PageBordersHandler::PageBordersHandler( ) :
+LoggedProperties("PageBordersHandler"),
+m_eBorderApply(SectionPropertyMap::BorderApply::ToAllInSection),
+m_eOffsetFrom(SectionPropertyMap::BorderOffsetFrom::Text)
+{
+}
+
+PageBordersHandler::~PageBordersHandler( )
+{
+}
+
+void PageBordersHandler::lcl_attribute( Id eName, Value& rVal )
+{
+ int nIntValue = rVal.getInt( );
+ switch ( eName )
+ {
+ case NS_ooxml::LN_CT_PageBorders_display:
+ {
+ switch ( nIntValue )
+ {
+ default:
+ case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_allPages:
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToAllInSection;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_firstPage:
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToFirstPageInSection;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_PageBorderDisplay_notFirstPage:
+ m_eBorderApply = SectionPropertyMap::BorderApply::ToAllButFirstInSection;
+ break;
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_PageBorders_offsetFrom:
+ {
+ switch ( nIntValue )
+ {
+ default:
+ case NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page:
+ m_eOffsetFrom = SectionPropertyMap::BorderOffsetFrom::Edge;
+ break;
+ case NS_ooxml::LN_Value_doc_ST_PageBorderOffset_text:
+ m_eOffsetFrom = SectionPropertyMap::BorderOffsetFrom::Text;
+ break;
+ }
+ }
+ break;
+ default:;
+ }
+}
+
+void PageBordersHandler::lcl_sprm( Sprm& rSprm )
+{
+ switch ( rSprm.getId( ) )
+ {
+ case NS_ooxml::LN_CT_PageBorders_top:
+ case NS_ooxml::LN_CT_PageBorders_left:
+ case NS_ooxml::LN_CT_PageBorders_bottom:
+ case NS_ooxml::LN_CT_PageBorders_right:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>( true );
+ pProperties->resolve(*pBorderHandler);
+ BorderPosition ePos = BorderPosition( 0 );
+ switch( rSprm.getId( ) )
+ {
+ case NS_ooxml::LN_CT_PageBorders_top:
+ ePos = BORDER_TOP;
+ break;
+ case NS_ooxml::LN_CT_PageBorders_left:
+ ePos = BORDER_LEFT;
+ break;
+ case NS_ooxml::LN_CT_PageBorders_bottom:
+ ePos = BORDER_BOTTOM;
+ break;
+ case NS_ooxml::LN_CT_PageBorders_right:
+ ePos = BORDER_RIGHT;
+ break;
+ default:;
+ }
+
+ PgBorder aPgBorder;
+ aPgBorder.m_rLine = pBorderHandler->getBorderLine( );
+ aPgBorder.m_nDistance = pBorderHandler->getLineDistance( );
+ aPgBorder.m_ePos = ePos;
+ aPgBorder.m_bShadow = pBorderHandler->getShadow();
+ if (pBorderHandler->getLineType() != NS_ooxml::LN_Value_ST_Border_none)
+ {
+ m_aBorders.push_back( aPgBorder );
+ }
+ }
+ }
+ break;
+ default:;
+ }
+}
+
+void PageBordersHandler::SetBorders( SectionPropertyMap* pSectContext )
+{
+ for (const PgBorder& rBorder : m_aBorders)
+ {
+ pSectContext->SetBorder( rBorder.m_ePos, rBorder.m_nDistance, rBorder.m_rLine, rBorder.m_bShadow );
+ }
+ pSectContext->SetBorderApply(m_eBorderApply);
+ pSectContext->SetBorderOffsetFrom(m_eOffsetFrom);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PageBordersHandler.hxx b/sw/source/writerfilter/dmapper/PageBordersHandler.hxx
new file mode 100644
index 000000000000..537d34b8104b
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PageBordersHandler.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "PropertyMap.hxx"
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/table/BorderLine2.hpp>
+
+#include <vector>
+
+namespace writerfilter::dmapper
+{
+class PgBorder
+{
+public:
+ css::table::BorderLine2 m_rLine;
+ sal_Int32 m_nDistance;
+ BorderPosition m_ePos;
+ bool m_bShadow;
+
+ PgBorder();
+};
+
+class PageBordersHandler : public LoggedProperties
+{
+private:
+ // See implementation of SectionPropertyMap::ApplyBorderToPageStyles
+ SectionPropertyMap::BorderApply m_eBorderApply;
+ SectionPropertyMap::BorderOffsetFrom m_eOffsetFrom;
+ std::vector<PgBorder> m_aBorders;
+
+ // Properties
+ virtual void lcl_attribute(Id eName, Value& rVal) override;
+ virtual void lcl_sprm(Sprm& rSprm) override;
+
+public:
+ PageBordersHandler();
+ virtual ~PageBordersHandler() override;
+
+ void SetBorders(SectionPropertyMap* pSectContext);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PropertyIds.cxx b/sw/source/writerfilter/dmapper/PropertyIds.cxx
new file mode 100644
index 000000000000..5aefa9d3b68b
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PropertyIds.cxx
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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"
+#include <frozen/bits/defines.h>
+#include <frozen/bits/elsa_std.h>
+#include <frozen/unordered_map.h>
+
+namespace writerfilter::dmapper{
+
+namespace
+{
+ constexpr auto constPropertyMap = frozen::make_unordered_map<PropertyIds, std::u16string_view>(
+ {
+ { PROP_CHAR_WEIGHT, u"CharWeight"},
+ { PROP_CHAR_POSTURE, u"CharPosture"},
+ { PROP_CHAR_STRIKEOUT, u"CharStrikeout"},
+ { PROP_CHAR_CONTOURED, u"CharContoured"},
+ { PROP_CHAR_SHADOWED, u"CharShadowed"},
+ { PROP_CHAR_CASE_MAP, u"CharCaseMap"},
+ { PROP_CHAR_COLOR, u"CharColor"},
+ { PROP_CHAR_COMPLEX_COLOR, u"CharComplexColor"},
+ { PROP_CHAR_RELIEF, u"CharRelief"},
+ { PROP_CHAR_UNDERLINE, u"CharUnderline"},
+ { PROP_CHAR_UNDERLINE_COLOR, u"CharUnderlineColor"},
+ { PROP_CHAR_UNDERLINE_COMPLEX_COLOR, u"CharUnderlineComplexColor"},
+ { PROP_CHAR_UNDERLINE_HAS_COLOR, u"CharUnderlineHasColor"},
+ { PROP_CHAR_WORD_MODE, u"CharWordMode"},
+ { PROP_CHAR_ESCAPEMENT, u"CharEscapement"},
+ { PROP_CHAR_ESCAPEMENT_HEIGHT, u"CharEscapementHeight"},
+ { PROP_CHAR_HEIGHT, u"CharHeight"},
+ { PROP_CHAR_HEIGHT_COMPLEX, u"CharHeightComplex"},
+ { PROP_CHAR_LOCALE, u"CharLocale"},
+ { PROP_CHAR_LOCALE_ASIAN, u"CharLocaleAsian"},
+ { PROP_CHAR_LOCALE_COMPLEX, u"CharLocaleComplex"},
+ { PROP_CHAR_WEIGHT_COMPLEX, u"CharWeightComplex"},
+ { PROP_CHAR_POSTURE_COMPLEX, u"CharPostureComplex"},
+ { PROP_CHAR_CHAR_KERNING, u"CharKerning"},
+ { PROP_CHAR_AUTO_KERNING, u"CharAutoKerning"},
+ { PROP_CHAR_SCALE_WIDTH, u"CharScaleWidth"},
+ { PROP_CHAR_STYLE_NAME, u"CharStyleName"},
+ { PROP_CHAR_FONT_NAME, u"CharFontName"},
+ { PROP_CHAR_FONT_CHAR_SET, u"CharFontCharSet"},
+ { PROP_CHAR_FONT_NAME_ASIAN, u"CharFontNameAsian"},
+ { PROP_CHAR_HEIGHT_ASIAN, u"CharHeightAsian"},
+ { PROP_CHAR_FONT_NAME_COMPLEX, u"CharFontNameComplex"},
+ { PROP_CHAR_HIDDEN, u"CharHidden"},
+ { PROP_CHAR_WEIGHT_ASIAN, u"CharWeightAsian"},
+ { PROP_CHAR_POSTURE_ASIAN, u"CharPostureAsian"},
+ { PROP_CHAR_BACK_COLOR, u"CharBackColor"},
+ { PROP_CHAR_BACKGROUND_COMPLEX_COLOR, u"CharBackgroundComplexColor"},
+ { PROP_CHAR_EMPHASIS, u"CharEmphasis"},
+ { PROP_CHAR_COMBINE_IS_ON, u"CharCombineIsOn"},
+ { PROP_CHAR_COMBINE_PREFIX, u"CharCombinePrefix"},
+ { PROP_CHAR_COMBINE_SUFFIX, u"CharCombineSuffix"},
+ { PROP_CHAR_ROTATION, u"CharRotation"},
+ { PROP_CHAR_ROTATION_IS_FIT_TO_LINE, u"CharRotationIsFitToLine"},
+ { PROP_CHAR_FLASH, u"CharFlash"},
+ { PROP_CHAR_LEFT_BORDER, u"CharLeftBorder"},
+ { PROP_CHAR_RIGHT_BORDER, u"CharRightBorder"},
+ { PROP_CHAR_TOP_BORDER, u"CharTopBorder"},
+ { PROP_CHAR_BOTTOM_BORDER, u"CharBottomBorder"},
+ { PROP_CHAR_LEFT_BORDER_DISTANCE, u"CharLeftBorderDistance"},
+ { PROP_CHAR_RIGHT_BORDER_DISTANCE, u"CharRightBorderDistance"},
+ { PROP_CHAR_TOP_BORDER_DISTANCE, u"CharTopBorderDistance"},
+ { PROP_CHAR_BOTTOM_BORDER_DISTANCE, u"CharBottomBorderDistance"},
+ { PROP_CHAR_BORDER_LEFT_COMPLEX_COLOR, u"CharLeftBorderComplexColor"},
+ { PROP_CHAR_BORDER_RIGHT_COMPLEX_COLOR, u"CharRightBorderComplexColor"},
+ { PROP_CHAR_BORDER_TOP_COMPLEX_COLOR, u"CharTopBorderComplexColor"},
+ { PROP_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, u"CharBottomBorderComplexColor"},
+ { PROP_CHAR_SHADOW_FORMAT, u"CharShadowFormat"},
+ { PROP_CHAR_HIGHLIGHT, u"CharHighlight"},
+ { PROP_PARA_STYLE_NAME, u"ParaStyleName"},
+ { PROP_PARA_ADJUST, u"ParaAdjust"},
+ { PROP_PARA_VERT_ALIGNMENT, u"ParaVertAlignment"},
+ { PROP_PARA_LAST_LINE_ADJUST, u"ParaLastLineAdjust"},
+ { PROP_PARA_RIGHT_MARGIN, u"ParaRightMargin"},
+ { PROP_PARA_LEFT_MARGIN, u"ParaLeftMargin"},
+ { PROP_PARA_FIRST_LINE_INDENT, u"ParaFirstLineIndent"},
+ { PROP_PARA_KEEP_TOGETHER, u"ParaKeepTogether"},
+ { PROP_PARA_TOP_MARGIN, u"ParaTopMargin"},
+ { PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING, u"ParaTopMarginBeforeAutoSpacing"},
+ { PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING, u"ParaBottomMarginAfterAutoSpacing"},
+ { PROP_PARA_CONTEXT_MARGIN, u"ParaContextMargin"},
+ { PROP_PARA_BOTTOM_MARGIN, u"ParaBottomMargin"},
+ { PROP_PARA_IS_HYPHENATION, u"ParaIsHyphenation"},
+ { PROP_PARA_HYPHENATION_NO_CAPS, u"ParaHyphenationNoCaps"},
+ { PROP_PARA_HYPHENATION_ZONE, u"ParaHyphenationZone"},
+ { PROP_PARA_HYPHENATION_KEEP, u"ParaHyphenationKeep"},
+ { PROP_PARA_HYPHENATION_KEEP_TYPE, u"ParaHyphenationKeepType"},
+ { PROP_PARA_LINE_NUMBER_COUNT, u"ParaLineNumberCount"},
+ { PROP_PARA_IS_HANGING_PUNCTUATION, u"ParaIsHangingPunctuation"},
+ { PROP_PARA_LINE_SPACING, u"ParaLineSpacing"},
+ { PROP_PARA_TAB_STOPS, u"ParaTabStops"},
+ { PROP_PARA_WIDOWS, u"ParaWidows"},
+ { PROP_PARA_ORPHANS, u"ParaOrphans"},
+ { PROP_PARA_LINE_NUMBER_START_VALUE, u"ParaLineNumberStartValue"},
+ { PROP_NUMBERING_LEVEL, u"NumberingLevel"},
+ { PROP_NUMBERING_RULES, u"NumberingRules"},
+ { PROP_NUMBERING_TYPE, u"NumberingType"},
+ { PROP_START_WITH, u"StartWith"},
+ { PROP_ADJUST, u"Adjust"},
+ { PROP_PARENT_NUMBERING, u"ParentNumbering"},
+ { PROP_RIGHT_MARGIN, u"RightMargin"},
+ { PROP_LEFT_MARGIN, u"LeftMargin"},
+ { PROP_TOP_MARGIN, u"TopMargin"},
+ { PROP_BOTTOM_MARGIN, u"BottomMargin"},
+ { PROP_FIRST_LINE_OFFSET, u"FirstLineOffset"},
+ { PROP_LEFT_BORDER, u"LeftBorder"},
+ { PROP_RIGHT_BORDER, u"RightBorder"},
+ { PROP_TOP_BORDER, u"TopBorder"},
+ { PROP_BOTTOM_BORDER, u"BottomBorder"},
+ { PROP_BORDER_LEFT_COMPLEX_COLOR, u"LeftBorderComplexColor"},
+ { PROP_BORDER_RIGHT_COMPLEX_COLOR, u"RightBorderComplexColor"},
+ { PROP_BORDER_TOP_COMPLEX_COLOR, u"TopBorderComplexColor"},
+ { PROP_BORDER_BOTTOM_COMPLEX_COLOR, u"BottomBorderComplexColor"},
+ { PROP_TABLE_BORDER, u"TableBorder"},
+ { PROP_TABLE_ROW_DELETE, u"TableRowDelete"},
+ { PROP_TABLE_ROW_INSERT, u"TableRowInsert"},
+ { PROP_TABLE_CELL_DELETE, u"TableCellDelete"},
+ { PROP_TABLE_CELL_INSERT, u"TableCellInsert"},
+ { PROP_LEFT_BORDER_DISTANCE, u"LeftBorderDistance"},
+ { PROP_RIGHT_BORDER_DISTANCE, u"RightBorderDistance"},
+ { PROP_TOP_BORDER_DISTANCE, u"TopBorderDistance"},
+ { PROP_BOTTOM_BORDER_DISTANCE, u"BottomBorderDistance"},
+ { PROP_CURRENT_PRESENTATION, u"CurrentPresentation"},
+ { PROP_IS_FIXED, u"IsFixed"},
+ { PROP_SUB_TYPE, u"SubType"},
+ { PROP_FILE_FORMAT, u"FileFormat"},
+ { PROP_HYPER_LINK_U_R_L, u"HyperLinkURL"},
+ { PROP_HYPERLINK, u"Hyperlink"},
+ { PROP_NUMBER_FORMAT, u"NumberFormat"},
+ { PROP_NAME, u"Name"},
+ { PROP_IS_INPUT, u"IsInput"},
+ { PROP_HINT, u"Hint"},
+ { PROP_FULL_NAME, u"FullName"},
+ { PROP_DESCRIPTION, u"Description"},
+ { PROP_MACRO_NAME, u"MacroName"},
+ { PROP_TITLE, u"Title"},
+ { PROP_CONTENT, u"Content"},
+ { PROP_INPUT_STREAM, u"InputStream"},
+ { PROP_GRAPHIC, u"Graphic"},
+ { PROP_ANCHOR_TYPE, u"AnchorType"},
+ { PROP_SIZE, u"Size"},
+ { PROP_HORI_ORIENT, u"HoriOrient"},
+ { PROP_HORI_ORIENT_POSITION, u"HoriOrientPosition"},
+ { PROP_HORI_ORIENT_RELATION, u"HoriOrientRelation"},
+ { PROP_VERT_ORIENT, u"VertOrient"},
+ { PROP_VERT_ORIENT_POSITION, u"VertOrientPosition"},
+ { PROP_VERT_ORIENT_RELATION, u"VertOrientRelation"},
+ { PROP_SIZE100th_M_M, u"Size100thMM"},
+ { PROP_SIZE_PIXEL, u"SizePixel"},
+ { PROP_SURROUND, u"Surround"},
+ { PROP_SURROUND_CONTOUR, u"SurroundContour"},
+ { PROP_ADJUST_CONTRAST, u"AdjustContrast"},
+ { PROP_ADJUST_LUMINANCE, u"AdjustLuminance"},
+ { PROP_GRAPHIC_COLOR_MODE, u"GraphicColorMode"},
+ { PROP_CONTOUR_OUTSIDE, u"ContourOutside"},
+ { PROP_CONTOUR_POLY_POLYGON, u"ContourPolyPolygon"},
+ { PROP_PAGE_TOGGLE, u"PageToggle"},
+ { PROP_BACK_COLOR, u"BackColor"},
+ { PROP_BACK_COMPLEX_COLOR, u"BackComplexColor"},
+ { PROP_BACK_COLOR_TRANSPARENCY, u"BackColorTransparency"},
+ { PROP_ALLOW_OVERLAP, u"AllowOverlap"},
+ { PROP_ALTERNATIVE_TEXT, u"AlternativeText"},
+ { PROP_HEADER_TEXT_LEFT, u"HeaderTextLeft"},
+ { PROP_HEADER_TEXT_FIRST, u"HeaderTextFirst"},
+ { PROP_HEADER_TEXT, u"HeaderText"},
+ { PROP_HEADER_IS_SHARED, u"HeaderIsShared"},
+ { PROP_HEADER_IS_ON, u"HeaderIsOn"},
+ { PROP_FIRST_IS_SHARED, u"FirstIsShared"},
+ { PROP_FOOTER_TEXT_LEFT, u"FooterTextLeft"},
+ { PROP_FOOTER_TEXT_FIRST, u"FooterTextFirst"},
+ { PROP_FOOTER_TEXT, u"FooterText"},
+ { PROP_FOOTER_IS_SHARED, u"FooterIsShared"},
+ { PROP_FOOTER_IS_ON, u"FooterIsOn"},
+ { PROP_FOOTNOTE_COUNTING, u"FootnoteCounting"},
+ { PROP_FOOTNOTE_LINE_ADJUST, u"FootnoteLineAdjust"},
+ { PROP_WIDTH, u"Width"},
+ { PROP_HEIGHT, u"Height"},
+ { PROP_TEXT_COLUMNS, u"TextColumns"},
+ { PROP_AUTOMATIC_DISTANCE, u"AutomaticDistance"},
+ { PROP_IS_LANDSCAPE, u"IsLandscape"},
+ { PROP_FIRST_PAGE, u"First Page"},
+ { PROP_PAGE_DESC_NAME, u"PageDescName"},
+ { PROP_PAGE_NUMBER_OFFSET, u"PageNumberOffset"},
+ { PROP_BREAK_TYPE, u"BreakType"},
+ { PROP_FOOTER_IS_DYNAMIC_HEIGHT, u"FooterIsDynamicHeight"},
+ { PROP_FOOTER_DYNAMIC_SPACING, u"FooterDynamicSpacing"},
+ { PROP_FOOTER_HEIGHT, u"FooterHeight"},
+ { PROP_FOOTER_BODY_DISTANCE, u"FooterBodyDistance"},
+ { PROP_HEADER_IS_DYNAMIC_HEIGHT, u"HeaderIsDynamicHeight"},
+ { PROP_HEADER_DYNAMIC_SPACING, u"HeaderDynamicSpacing"},
+ { PROP_HEADER_HEIGHT, u"HeaderHeight"},
+ { PROP_HEADER_BODY_DISTANCE, u"HeaderBodyDistance"},
+ { PROP_WRITING_MODE, u"WritingMode"},
+ { PROP_GRID_MODE, u"GridMode"},
+ { PROP_GRID_DISPLAY, u"GridDisplay"},
+ { PROP_GRID_PRINT, u"GridPrint"},
+ { PROP_GRID_LINES, u"GridLines"},
+ { PROP_GRID_BASE_HEIGHT, u"GridBaseHeight"},
+ { PROP_GRID_BASE_WIDTH, u"GridBaseWidth"},
+ { PROP_GRID_RUBY_HEIGHT, u"GridRubyHeight"},
+ { PROP_GRID_STANDARD_MODE, u"StandardPageMode"},
+ { PROP_IS_ON, u"IsOn"},
+ { PROP_RESTART_AT_EACH_PAGE, u"RestartAtEachPage"},
+ { PROP_COUNT_EMPTY_LINES, u"CountEmptyLines"},
+ { PROP_COUNT_LINES_IN_FRAMES, u"CountLinesInFrames"},
+ { PROP_INTERVAL, u"Interval"},
+ { PROP_DISTANCE, u"Distance"},
+ { PROP_NUMBER_POSITION, u"NumberPosition"},
+ { PROP_LEVEL, u"Level"},
+ { PROP_LEVEL_FOLLOW, u"LabelFollowedBy"},
+ { PROP_LEVEL_PARAGRAPH_STYLES, u"LevelParagraphStyles"},
+ { PROP_LEVEL_FORMAT, u"LevelFormat"},
+ { PROP_LEVEL_IS_LEGAL, u"IsLegal"},
+ { PROP_LIST_FORMAT, u"ListFormat"},
+ { PROP_TOKEN_TYPE, u"TokenType"},
+ { PROP_TOKEN_HYPERLINK_START, u"TokenHyperlinkStart"},
+ { PROP_TOKEN_HYPERLINK_END, u"TokenHyperlinkEnd"},
+ { PROP_TOKEN_CHAPTER_INFO, u"TokenChapterInfo"},
+ { PROP_CHAPTER_FORMAT, u"ChapterFormat"},
+ { PROP_TOKEN_TEXT, u"TokenText"},
+ { PROP_TEXT, u"Text"},
+ { PROP_CREATE_FROM_OUTLINE, u"CreateFromOutline"},
+ { PROP_CREATE_FROM_MARKS, u"CreateFromMarks"},
+ { PROP_STANDARD, u"Standard"},
+ { PROP_SPLIT, u"Split"},
+ { PROP_IS_SPLIT_ALLOWED, u"IsSplitAllowed"},
+ { META_PROP_VERTICAL_BORDER, u"VerticalBorder"},
+ { META_PROP_HORIZONTAL_BORDER, u"HorizontalBorder"},
+ { PROP_HEADER_ROW_COUNT, u"HeaderRowCount"},
+ { PROP_SIZE_TYPE, u"SizeType"},
+ { PROP_TABLE_COLUMN_SEPARATORS, u"TableColumnSeparators"},
+ { META_PROP_TABLE_STYLE_NAME, u"TableStyleName"},
+ { PROP_TABLE_REDLINE_PARAMS, u"TableRedlineParams"},
+ { PROP_REDLINE_AUTHOR, u"RedlineAuthor"},
+ { PROP_REDLINE_DATE_TIME, u"RedlineDateTime"},
+ { PROP_REDLINE_TYPE, u"RedlineType"},
+ { PROP_REDLINE_REVERT_PROPERTIES, u"RedlineRevertProperties"},
+ { PROP_IS_PROTECTED, u"IsProtected"},
+ { PROP_SIZE_PROTECTED, u"SizeProtected"},
+ { PROP_POSITION_PROTECTED, u"PositionProtected"},
+ { PROP_OPAQUE, u"Opaque"},
+ { PROP_VERTICAL_MERGE, u"VerticalMerge"},
+ { PROP_BULLET_CHAR, u"BulletChar"},
+ { PROP_BULLET_FONT_NAME, u"BulletFontName"},
+ { PROP_TABS_RELATIVE_TO_INDENT, u"TabsRelativeToIndent"},
+ { PROP_CREATE_FROM_LEVEL_PARAGRAPH_STYLES, u"CreateFromLevelParagraphStyles"},
+ { PROP_DROP_CAP_FORMAT, u"DropCapFormat"},
+ { PROP_REFERENCE_FIELD_FLAGS, u"ReferenceFieldFlags"},
+ { PROP_REFERENCE_FIELD_PART, u"ReferenceFieldPart"},
+ { PROP_SOURCE_NAME, u"SourceName"},
+ { PROP_REFERENCE_FIELD_SOURCE, u"ReferenceFieldSource"},
+ { PROP_WIDTH_TYPE, u"WidthType"},
+ { PROP_TBL_LOOK, u"TblLook"},
+ { PROP_TEXT_RANGE, u"TextRange"},
+ { PROP_TEXT_VERTICAL_ADJUST, u"TextVerticalAdjust"},
+ { PROP_SERVICE_CHAR_STYLE, u"com.sun.star.style.CharacterStyle"},
+ { PROP_SERVICE_PARA_STYLE, u"com.sun.star.style.ParagraphStyle"},
+ { PROP_CHARACTER_STYLES, u"CharacterStyles"},
+ { PROP_PARAGRAPH_STYLES, u"ParagraphStyles"},
+ { PROP_TABLE_BORDER_DISTANCES, u"TableBorderDistances"},
+ { META_PROP_CELL_MAR_TOP, u"MetaPropCellMarTop"},
+ { META_PROP_CELL_MAR_BOTTOM, u"MetaPropCellMarBottom"},
+ { META_PROP_CELL_MAR_LEFT, u"MetaPropCellMarLeft"},
+ { META_PROP_CELL_MAR_RIGHT, u"MetaPropCellMarRight"},
+ { PROP_START_AT, u"StartAt"},
+ { PROP_CHAR_PROP_HEIGHT, u"CharPropHeight"},
+ { PROP_CHAR_PROP_HEIGHT_ASIAN, u"CharPropHeightAsian"},
+ { PROP_CHAR_PROP_HEIGHT_COMPLEX, u"CharPropHeightComplex"},
+ { PROP_FORMAT, u"Format"},
+ { PROP_INSERT, u"Insert"},
+ { PROP_DELETE, u"Delete"},
+ { PROP_PARAGRAPH_FORMAT, u"ParagraphFormat"},
+ { PROP_STREAM_NAME, u"StreamName"},
+ { PROP_BITMAP, u"Bitmap"},
+ { PROP_IS_DATE, u"IsDate"},
+ { PROP_TAB_STOP_DISTANCE, u"TabStopDistance"},
+ { PROP_INDENT_AT, u"IndentAt"},
+ { PROP_FIRST_LINE_INDENT, u"FirstLineIndent"},
+ { PROP_NUMBERING_STYLE_NAME, u"NumberingStyleName"},
+ { PROP_OUTLINE_LEVEL, u"OutlineLevel"},
+ { PROP_LISTTAB_STOP_POSITION, u"ListtabStopPosition"},
+ { PROP_POSITION_AND_SPACE_MODE, u"PositionAndSpaceMode"},
+ { PROP_PARA_SPLIT, u"ParaSplit"},
+ { PROP_HELP, u"Help"},
+ { PROP_HEADING_STYLE_NAME, u"HeadingStyleName"},
+ { PROP_FRM_DIRECTION, u"FRMDirection"},
+ { PROP_EMBEDDED_OBJECT, u"EmbeddedObject"},
+ { PROP_IS_VISIBLE, u"IsVisible"},
+ { PROP_PAGE_STYLE_LAYOUT, u"PageStyleLayout"},
+ { PROP_Z_ORDER, u"ZOrder"},
+ { PROP_EMBED_FONTS, u"EmbedFonts"},
+ { PROP_EMBED_SYSTEM_FONTS, u"EmbedSystemFonts"},
+ { PROP_SHADOW_FORMAT, u"ShadowFormat"},
+ { PROP_RELATIVE_WIDTH, u"RelativeWidth"},
+ { PROP_IS_WIDTH_RELATIVE, u"IsWidthRelative"},
+ { PROP_GRAPHIC_BITMAP, u"GraphicBitmap"},
+ { PROP_GRAPHIC_SIZE, u"GraphicSize"},
+ { PROP_CHAR_SHADING_VALUE, u"CharShadingValue"},
+ { PROP_CHAR_SHADING_MARKER, u"CharShadingMarker"},
+ { PROP_LABEL_CATEGORY, u"LabelCategory"},
+ { PROP_MIRROR_INDENTS, u"MirrorIndents"},
+ { PROP_SURROUND_TEXT_WRAP_SMALL, u"SurroundTextWrapSmall"},
+ { PROP_PARA_SHADOW_FORMAT, u"ParaShadowFormat"},
+ { PROP_FOOTNOTE_LINE_RELATIVE_WIDTH, u"FootnoteLineRelativeWidth"},
+ { PROP_TBL_HEADER, u"TblHeader"},
+ { PROP_CHAR_THEME_NAME_ASCII, u"CharThemeNameAscii"},
+ { PROP_CHAR_THEME_NAME_CS, u"CharThemeNameCs"},
+ { PROP_CHAR_THEME_NAME_H_ANSI, u"CharThemeNameHAnsi"},
+ { PROP_CHAR_THEME_NAME_EAST_ASIA, u"CharThemeNameEastAsia"},
+ { PROP_CHAR_THEME_FONT_NAME_ASCII, u"CharThemeFontNameAscii"},
+ { PROP_CHAR_THEME_FONT_NAME_CS, u"CharThemeFontNameCs"},
+ { PROP_CHAR_THEME_FONT_NAME_EAST_ASIA, u"CharThemeFontNameEastAsia"},
+ { PROP_CHAR_THEME_COLOR, u"CharThemeColor"},
+ { PROP_CHAR_THEME_ORIGINAL_COLOR, u"CharThemeOriginalColor"},
+ { PROP_CHAR_THEME_COLOR_SHADE, u"CharThemeColorShade"},
+ { PROP_CHAR_THEME_FILL, u"CharThemeFill"},
+ { PROP_HORIZONTAL_MERGE, u"HorizontalMerge"},
+ { PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS, u"HideTabLeaderAndPageNumber"},
+ { PROP_TAB_IN_TOC, u"TabInTOC"},
+ { PROP_TOC_BOOKMARK, u"TOCBookmark"},
+ { PROP_TOC_NEW_LINE, u"TOCNewLine"},
+ { PROP_TOC_PARAGRAPH_OUTLINE_LEVEL, u"TOCParagraphOutlineLevel"},
+ { PROP_CHAR_THEME_COLOR_TINT, u"CharThemeColorTint"},
+ { PROP_CHAR_GLOW_TEXT_EFFECT, u"CharGlowTextEffect"},
+ { PROP_CHAR_SHADOW_TEXT_EFFECT, u"CharShadowTextEffect"},
+ { PROP_CHAR_REFLECTION_TEXT_EFFECT, u"CharReflectionTextEffect"},
+ { PROP_CHAR_TEXTOUTLINE_TEXT_EFFECT, u"CharTextOutlineTextEffect"},
+ { PROP_CHAR_TEXTFILL_TEXT_EFFECT, u"CharTextFillTextEffect"},
+ { PROP_CHAR_SCENE3D_TEXT_EFFECT, u"CharScene3DTextEffect"},
+ { PROP_CHAR_PROPS3D_TEXT_EFFECT, u"CharProps3DTextEffect"},
+ { PROP_CHAR_LIGATURES_TEXT_EFFECT, u"CharLigaturesTextEffect"},
+ { PROP_CHAR_NUMFORM_TEXT_EFFECT, u"CharNumFormTextEffect"},
+ { PROP_CHAR_NUMSPACING_TEXT_EFFECT, u"CharNumSpacingTextEffect"},
+ { PROP_CHAR_STYLISTICSETS_TEXT_EFFECT, u"CharStylisticSetsTextEffect"},
+ { PROP_CHAR_CNTXTALTS_TEXT_EFFECT, u"CharCntxtAltsTextEffect"},
+ { PROP_SDTPR, u"SdtPr"},
+ { PROP_CELL_INTEROP_GRAB_BAG, u"CellInteropGrabBag"},
+ { PROP_TABLE_INTEROP_GRAB_BAG, u"TableInteropGrabBag"},
+ { PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING, u"ApplyParagraphMarkFormatToNumbering"},
+ { PROP_SDT_END_BEFORE, u"SdtEndBefore"},
+ { PROP_PARA_SDT_END_BEFORE, u"ParaSdtEndBefore"},
+ { META_PROP_TABLE_LOOK, u"TableStyleLook"},
+ { PROP_PARA_CNF_STYLE, u"ParaCnfStyle"},
+ { PROP_CELL_CNF_STYLE, u"CellCnfStyle"},
+ { PROP_ROW_CNF_STYLE, u"RowCnfStyle"},
+ { PROP_CELL_HIDE_MARK, u"CellHideMark"},
+ { PROP_FOLLOW_TEXT_FLOW, u"IsFollowingTextFlow"},
+ { PROP_FILL_STYLE, u"FillStyle"},
+ { PROP_FILL_COLOR, u"FillColor"},
+ { PROP_FILL_COMPLEX_COLOR, u"FillComplexColor"},
+ { PROP_SNAP_TO_GRID, u"SnapToGrid"},
+ { PROP_GRID_SNAP_TO_CHARS, u"GridSnapToChars"},
+ { PROP_RUBY_STYLE, u"RubyCharStyleName"},
+ { PROP_RUBY_TEXT, u"RubyText"},
+ { PROP_RUBY_ADJUST, u"RubyAdjust"},
+ { PROP_RUBY_POSITION, u"RubyPosition"},
+ { PROP_DATABASE_NAME, u"DataBaseName"},
+ { PROP_COMMAND_TYPE, u"DataCommandType"},
+ { PROP_DATATABLE_NAME, u"DataTableName"},
+ { PROP_DATACOLUMN_NAME, u"DataColumnName"},
+ { PROP_CHAR_TRANSPARENCE, u"CharTransparence"},
+ { PROP_CELL_FORMULA, u"CellFormula"},
+ { PROP_CELL_FORMULA_CONVERTED, u"CellFormulaConverted"},
+ { PROP_GUTTER_MARGIN, u"GutterMargin"},
+ { PROP_RTL_GUTTER, u"RtlGutter"},
+ { PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF, u"CursorNotIgnoreTables"},
+ { PROP_PARA_CONNECT_BORDERS, u"ParaIsConnectBorder"},
+ { PROP_DECORATIVE, u"Decorative"},
+ { PROP_PAPER_TRAY, u"PrinterPaperTray"},
+ });
+} // end anonymous ns
+
+OUString getPropertyName( PropertyIds eId )
+{
+ auto iterator = constPropertyMap.find(eId);
+ if (iterator != constPropertyMap.end())
+ return OUString(iterator->second);
+
+ return OUString();
+}
+
+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
+ || eId == PROP_FILL_COMPLEX_COLOR;
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PropertyIds.hxx b/sw/source/writerfilter/dmapper/PropertyIds.hxx
new file mode 100644
index 000000000000..724648683335
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PropertyIds.hxx
@@ -0,0 +1,399 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace writerfilter::dmapper{
+// Ensure that Character Properties are placed between PROP_CHARACTER_STYLES and PROP_CHARACTER_END
+enum PropertyIds
+ {
+ INVALID = 0
+ ,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_ALLOW_OVERLAP
+ ,PROP_ALTERNATIVE_TEXT
+ ,PROP_ANCHOR_TYPE
+ ,PROP_AUTOMATIC_DISTANCE
+ ,PROP_BACK_COLOR
+ ,PROP_BACK_COMPLEX_COLOR
+ ,PROP_BACK_COLOR_TRANSPARENCY
+ ,PROP_BITMAP
+ ,PROP_BORDER_LEFT_COMPLEX_COLOR
+ ,PROP_BORDER_RIGHT_COMPLEX_COLOR
+ ,PROP_BORDER_TOP_COMPLEX_COLOR
+ ,PROP_BORDER_BOTTOM_COMPLEX_COLOR
+ ,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_BACKGROUND_COMPLEX_COLOR
+ ,PROP_CHAR_CASE_MAP
+ ,PROP_CHAR_CHAR_KERNING
+ ,PROP_CHAR_COLOR
+ ,PROP_CHAR_COMPLEX_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_BORDER_LEFT_COMPLEX_COLOR
+ ,PROP_CHAR_BORDER_RIGHT_COMPLEX_COLOR
+ ,PROP_CHAR_BORDER_TOP_COMPLEX_COLOR
+ ,PROP_CHAR_BORDER_BOTTOM_COMPLEX_COLOR
+ ,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_COMPLEX_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_DECORATIVE
+ ,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_FIRST_IS_SHARED
+ ,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_FOOTER_TEXT_FIRST
+ ,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_HEADER_TEXT_FIRST
+ ,PROP_HEADING_STYLE_NAME
+ ,PROP_HEIGHT
+ ,PROP_HELP
+ ,PROP_HINT
+ ,PROP_HORI_ORIENT
+ ,PROP_HORI_ORIENT_POSITION
+ ,PROP_HORI_ORIENT_RELATION
+ ,PROP_HYPER_LINK_U_R_L
+ ,PROP_HYPERLINK
+ ,PROP_INDENT_AT
+ ,PROP_INPUT_STREAM
+ ,PROP_INSERT
+ ,PROP_INTERVAL
+ ,PROP_IS_DATE
+ ,PROP_IS_FIXED
+ ,PROP_IS_INPUT
+ ,PROP_IS_LANDSCAPE
+ ,PROP_IS_ON
+ ,PROP_IS_SPLIT_ALLOWED
+ ,PROP_IS_VISIBLE
+ ,PROP_LABEL_CATEGORY
+ ,PROP_LEFT_BORDER
+ ,PROP_LEFT_BORDER_DISTANCE
+ ,PROP_LEFT_MARGIN
+ ,PROP_LEVEL
+ ,PROP_LEVEL_FOLLOW
+ ,PROP_LEVEL_FORMAT
+ ,PROP_LEVEL_PARAGRAPH_STYLES
+ ,PROP_LEVEL_IS_LEGAL
+ ,PROP_LISTTAB_STOP_POSITION
+ ,PROP_LIST_FORMAT
+ ,PROP_MACRO_NAME
+ ,PROP_NAME
+ ,PROP_NUMBERING_LEVEL
+ ,PROP_NUMBERING_RULES
+ ,PROP_NUMBERING_STYLE_NAME
+ ,PROP_NUMBERING_TYPE
+ ,PROP_NUMBER_FORMAT
+ ,PROP_NUMBER_POSITION
+ ,PROP_OPAQUE
+ ,PROP_OUTLINE_LEVEL
+ ,PROP_PAGE_DESC_NAME
+ ,PROP_PAGE_NUMBER_OFFSET
+ ,PROP_PAGE_TOGGLE
+ ,PROP_PARAGRAPH_FORMAT
+ ,PROP_PARAGRAPH_STYLES
+ ,PROP_PARA_ADJUST
+ ,PROP_PARA_BOTTOM_MARGIN
+ ,PROP_PARA_FIRST_LINE_INDENT
+ ,PROP_PARA_IS_HANGING_PUNCTUATION
+ ,PROP_PARA_IS_HYPHENATION
+ ,PROP_PARA_HYPHENATION_NO_CAPS
+ ,PROP_PARA_HYPHENATION_ZONE
+ ,PROP_PARA_HYPHENATION_KEEP
+ ,PROP_PARA_HYPHENATION_KEEP_TYPE
+ ,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_PAPER_TRAY
+ ,PROP_PARENT_NUMBERING
+ ,PROP_POSITION_AND_SPACE_MODE
+ ,PROP_POSITION_PROTECTED
+ ,PROP_IS_PROTECTED
+ ,PROP_REDLINE_AUTHOR
+ ,PROP_REDLINE_DATE_TIME
+ ,PROP_REDLINE_TYPE
+ ,PROP_REDLINE_REVERT_PROPERTIES
+ ,PROP_REFERENCE_FIELD_FLAGS
+ ,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_SURROUND
+ ,PROP_SURROUND_CONTOUR
+ ,PROP_TABLE_BORDER
+ ,PROP_TABLE_BORDER_DISTANCES
+ ,PROP_TABLE_COLUMN_SEPARATORS
+ ,PROP_TABLE_REDLINE_PARAMS
+ ,PROP_TABLE_ROW_DELETE
+ ,PROP_TABLE_ROW_INSERT
+ ,PROP_TABLE_CELL_DELETE
+ ,PROP_TABLE_CELL_INSERT
+ ,PROP_TABS_RELATIVE_TO_INDENT
+ ,PROP_TAB_STOP_DISTANCE
+ ,PROP_TEXT
+ ,PROP_TEXT_COLUMNS
+ ,PROP_TEXT_RANGE
+ ,PROP_TEXT_VERTICAL_ADJUST
+ ,PROP_TITLE
+ ,PROP_TOKEN_CHAPTER_INFO
+ ,PROP_TOKEN_HYPERLINK_END
+ ,PROP_TOKEN_HYPERLINK_START
+ ,PROP_TOKEN_TEXT
+ ,PROP_TOKEN_TYPE
+ ,PROP_TOP_BORDER
+ ,PROP_TOP_BORDER_DISTANCE
+ ,PROP_TOP_MARGIN
+ ,PROP_VERTICAL_MERGE
+ ,PROP_GRID_STANDARD_MODE
+ ,PROP_VERT_ORIENT
+ ,PROP_VERT_ORIENT_POSITION
+ ,PROP_VERT_ORIENT_RELATION
+ ,PROP_WIDTH
+ ,PROP_WIDTH_TYPE
+ ,PROP_TBL_LOOK
+ ,PROP_WRITING_MODE
+ ,PROP_FRM_DIRECTION
+ ,PROP_EMBEDDED_OBJECT
+ ,PROP_PARA_CONTEXT_MARGIN
+ ,PROP_PAGE_STYLE_LAYOUT
+ ,PROP_Z_ORDER
+ ,PROP_EMBED_FONTS
+ ,PROP_EMBED_SYSTEM_FONTS
+ ,PROP_SHADOW_FORMAT
+ ,PROP_RELATIVE_WIDTH
+ ,PROP_IS_WIDTH_RELATIVE
+ ,PROP_GRAPHIC_BITMAP
+ ,PROP_GRAPHIC_SIZE
+ ,PROP_MIRROR_INDENTS
+ ,PROP_SURROUND_TEXT_WRAP_SMALL
+ ,PROP_PARA_SHADOW_FORMAT
+ ,PROP_FOOTNOTE_LINE_RELATIVE_WIDTH
+ ,PROP_PARA_TOP_MARGIN_BEFORE_AUTO_SPACING
+ ,PROP_PARA_BOTTOM_MARGIN_AFTER_AUTO_SPACING
+ ,PROP_TBL_HEADER
+ ,PROP_HORIZONTAL_MERGE
+ ,PROP_HIDE_TAB_LEADER_AND_PAGE_NUMBERS
+ ,PROP_TAB_IN_TOC
+ ,PROP_TOC_BOOKMARK
+ ,PROP_TOC_NEW_LINE
+ ,PROP_TOC_PARAGRAPH_OUTLINE_LEVEL
+ ,PROP_SDTPR
+ ,PROP_CELL_INTEROP_GRAB_BAG
+ ,PROP_TABLE_INTEROP_GRAB_BAG
+ ,PROP_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING
+ ,PROP_SDT_END_BEFORE
+ ,PROP_PARA_SDT_END_BEFORE
+ ,META_PROP_TABLE_LOOK
+ ,PROP_PARA_CNF_STYLE
+ ,PROP_CELL_CNF_STYLE
+ ,PROP_ROW_CNF_STYLE
+ ,PROP_CELL_HIDE_MARK
+ ,PROP_FOLLOW_TEXT_FLOW
+ ,PROP_FILL_STYLE
+ ,PROP_FILL_COLOR
+ ,PROP_FILL_COMPLEX_COLOR
+ ,PROP_SNAP_TO_GRID
+ ,PROP_GRID_SNAP_TO_CHARS
+ ,PROP_RUBY_STYLE
+ ,PROP_RUBY_TEXT
+ ,PROP_RUBY_ADJUST
+ ,PROP_RUBY_POSITION
+ ,PROP_DATABASE_NAME
+ ,PROP_COMMAND_TYPE
+ ,PROP_DATATABLE_NAME
+ ,PROP_DATACOLUMN_NAME
+ ,PROP_CHAR_TRANSPARENCE
+ ,PROP_CELL_FORMULA
+ ,PROP_CELL_FORMULA_CONVERTED
+ ,PROP_GUTTER_MARGIN
+ ,PROP_RTL_GUTTER
+ ,PROP_CURSOR_NOT_IGNORE_TABLES_IN_HF
+ ,PROP_PARA_CONNECT_BORDERS
+ };
+
+//Returns the UNO string equivalent to eId.
+OUString getPropertyName(PropertyIds eId);
+
+bool isCharacterProperty(const PropertyIds eId);
+
+bool isParagraphProperty(const PropertyIds eId);
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PropertyMap.cxx b/sw/source/writerfilter/dmapper/PropertyMap.cxx
new file mode 100644
index 000000000000..3e836f831e63
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PropertyMap.cxx
@@ -0,0 +1,2170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "PropertyMap.hxx"
+#include "TagLogger.hxx"
+#include <ooxml/resourceids.hxx>
+#include "DomainMapper_Impl.hxx"
+#include "ConversionHelper.hxx"
+#include <editeng/boxitem.hxx>
+#include <i18nutil/paper.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/style/BreakType.hpp>
+#include <com/sun/star/style/PageStyleLayout.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/HorizontalAdjust.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/XRedline.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextFrame.hpp>
+#include <com/sun/star/text/XTextTablesSupplier.hpp>
+#include <com/sun/star/text/TextGridMode.hpp>
+#include <com/sun/star/text/XTextCopy.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include "PropertyMapHelper.hxx"
+#include <o3tl/sorted_vector.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <utility>
+
+#include <frozen/bits/defines.h>
+#include <frozen/bits/elsa_std.h>
+#include <frozen/unordered_set.h>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper {
+
+uno::Sequence< beans::PropertyValue > PropertyMap::GetPropertyValues( bool bCharGrabBag )
+{
+ using comphelper::makePropertyValue;
+
+ if ( !m_aValues.empty() || m_vMap.empty() )
+ return comphelper::containerToSequence( m_aValues );
+
+ size_t nCharGrabBag = 0;
+ size_t nParaGrabBag = 0;
+ size_t nCellGrabBag = 0;
+ size_t nRowGrabBag = 0;
+
+ const PropValue* pParaStyleProp = nullptr;
+ const PropValue* pCharStyleProp = nullptr;
+ const PropValue* pNumRuleProp = nullptr;
+
+ m_aValues.reserve( m_vMap.size() );
+ for ( const auto& rPropPair : m_vMap )
+ {
+ if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
+ nCharGrabBag++;
+ else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
+ nParaGrabBag++;
+ else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
+ nCellGrabBag++;
+ else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
+ {
+ uno::Sequence< beans::PropertyValue > aSeq;
+ rPropPair.second.getValue() >>= aSeq;
+ nCellGrabBag += aSeq.getLength();
+ }
+ else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
+ nRowGrabBag++;
+
+ if ( rPropPair.first == PROP_PARA_STYLE_NAME ) pParaStyleProp = &rPropPair.second;
+ if ( rPropPair.first == PROP_CHAR_STYLE_NAME ) pCharStyleProp = &rPropPair.second;
+ if ( rPropPair.first == PROP_NUMBERING_RULES ) pNumRuleProp = &rPropPair.second;
+ }
+
+ // Style names have to be the first elements within the property sequence
+ // otherwise they will overwrite 'hard' attributes
+ if ( pParaStyleProp != nullptr )
+ m_aValues.push_back( makePropertyValue( getPropertyName( PROP_PARA_STYLE_NAME ), pParaStyleProp->getValue() ) );
+ if ( pCharStyleProp != nullptr )
+ m_aValues.push_back( makePropertyValue( getPropertyName( PROP_CHAR_STYLE_NAME ), pCharStyleProp->getValue() ) );
+ if ( pNumRuleProp != nullptr )
+ m_aValues.push_back( makePropertyValue(getPropertyName( PROP_NUMBERING_RULES ), pNumRuleProp->getValue() ) );
+
+ // If there are any grab bag properties, we need one slot for them.
+ uno::Sequence< beans::PropertyValue > aCharGrabBagValues( nCharGrabBag );
+ uno::Sequence< beans::PropertyValue > aParaGrabBagValues( nParaGrabBag );
+ uno::Sequence< beans::PropertyValue > aCellGrabBagValues( nCellGrabBag );
+ uno::Sequence< beans::PropertyValue > aRowGrabBagValues ( nRowGrabBag );
+ beans::PropertyValue* pCharGrabBagValues = aCharGrabBagValues.getArray();
+ beans::PropertyValue* pParaGrabBagValues = aParaGrabBagValues.getArray();
+ beans::PropertyValue* pCellGrabBagValues = aCellGrabBagValues.getArray();
+ beans::PropertyValue* pRowGrabBagValues = aRowGrabBagValues.getArray();
+ // Record index for the next property to be added in each grab bag.
+ sal_Int32 nRowGrabBagValue = 0;
+ sal_Int32 nCellGrabBagValue = 0;
+ sal_Int32 nParaGrabBagValue = 0;
+ sal_Int32 nCharGrabBagValue = 0;
+
+ for ( const auto& rPropPair : m_vMap )
+ {
+ if ( rPropPair.first != PROP_PARA_STYLE_NAME &&
+ rPropPair.first != PROP_CHAR_STYLE_NAME &&
+ rPropPair.first != PROP_NUMBERING_RULES )
+ {
+ if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
+ {
+ if ( bCharGrabBag )
+ {
+ pCharGrabBagValues[nCharGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pCharGrabBagValues[nCharGrabBagValue].Value = rPropPair.second.getValue();
+ ++nCharGrabBagValue;
+ }
+ }
+ else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
+ {
+ pParaGrabBagValues[nParaGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pParaGrabBagValues[nParaGrabBagValue].Value = rPropPair.second.getValue();
+ ++nParaGrabBagValue;
+ }
+ else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
+ {
+ pCellGrabBagValues[nCellGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pCellGrabBagValues[nCellGrabBagValue].Value = rPropPair.second.getValue();
+ ++nCellGrabBagValue;
+ }
+ else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
+ {
+ pRowGrabBagValues[nRowGrabBagValue].Name = getPropertyName( rPropPair.first );
+ pRowGrabBagValues[nRowGrabBagValue].Value = rPropPair.second.getValue();
+ ++nRowGrabBagValue;
+ }
+ else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
+ {
+ uno::Sequence< beans::PropertyValue > aSeq;
+ rPropPair.second.getValue() >>= aSeq;
+ std::copy(std::cbegin(aSeq), std::cend(aSeq), pCellGrabBagValues + nCellGrabBagValue);
+ nCellGrabBagValue += aSeq.getLength();
+ }
+ else
+ {
+ m_aValues.push_back( makePropertyValue( getPropertyName( rPropPair.first ), rPropPair.second.getValue() ) );
+ }
+ }
+ }
+
+ if ( nCharGrabBag && bCharGrabBag )
+ m_aValues.push_back( makePropertyValue( "CharInteropGrabBag", uno::Any( aCharGrabBagValues ) ) );
+
+ if ( nParaGrabBag )
+ m_aValues.push_back( makePropertyValue( "ParaInteropGrabBag", uno::Any( aParaGrabBagValues ) ) );
+
+ if ( nCellGrabBag )
+ m_aValues.push_back( makePropertyValue( "CellInteropGrabBag", uno::Any( aCellGrabBagValues ) ) );
+
+ if ( nRowGrabBag )
+ m_aValues.push_back( makePropertyValue( "RowInteropGrabBag", uno::Any( aRowGrabBagValues ) ) );
+
+ return comphelper::containerToSequence( m_aValues );
+}
+
+std::vector< PropertyIds > PropertyMap::GetPropertyIds()
+{
+ std::vector< PropertyIds > aRet;
+ for ( const auto& rPropPair : m_vMap )
+ aRet.push_back( rPropPair.first );
+ return aRet;
+}
+
+#ifdef DBG_UTIL
+static void lcl_AnyToTag( const uno::Any& rAny )
+{
+ try {
+ sal_Int32 aInt = 0;
+ if ( rAny >>= aInt )
+ {
+ TagLogger::getInstance().attribute( "value", rAny );
+ }
+ else
+ {
+ TagLogger::getInstance().attribute( "unsignedValue", 0 );
+ }
+
+ sal_uInt32 auInt = 0;
+ rAny >>= auInt;
+ TagLogger::getInstance().attribute( "unsignedValue", auInt );
+
+ float aFloat = 0.0f;
+ if ( rAny >>= aFloat )
+ {
+ TagLogger::getInstance().attribute( "floatValue", rAny );
+ }
+ else
+ {
+ TagLogger::getInstance().attribute( "unsignedValue", 0 );
+ }
+
+ OUString aStr;
+ rAny >>= aStr;
+ TagLogger::getInstance().attribute( "stringValue", aStr );
+ }
+ catch ( ... )
+ {
+ }
+}
+#endif
+
+void PropertyMap::Insert( PropertyIds eId, const uno::Any& rAny, bool bOverwrite, GrabBagType i_GrabBagType, bool bDocDefault )
+{
+#ifdef DBG_UTIL
+ const OUString& rInsert = getPropertyName(eId);
+
+ TagLogger::getInstance().startElement("propertyMap.insert");
+ TagLogger::getInstance().attribute("name", rInsert);
+ lcl_AnyToTag(rAny);
+ TagLogger::getInstance().endElement();
+#endif
+
+ if ( !bOverwrite )
+ m_vMap.insert(std::make_pair(eId, PropValue(rAny, i_GrabBagType, bDocDefault)));
+ else
+ m_vMap[eId] = PropValue(rAny, i_GrabBagType);
+
+ Invalidate();
+}
+
+void PropertyMap::Erase( PropertyIds eId )
+{
+ // Safe call to erase, it throws no exceptions, even if eId is not in m_vMap
+ m_vMap.erase(eId);
+
+ Invalidate();
+}
+
+std::optional< PropertyMap::Property > PropertyMap::getProperty( PropertyIds eId ) const
+{
+ std::map< PropertyIds, PropValue >::const_iterator aIter = m_vMap.find( eId );
+ if ( aIter == m_vMap.end() )
+ return std::optional<Property>();
+ else
+ return std::make_pair( eId, aIter->second.getValue() );
+}
+
+bool PropertyMap::isSet( PropertyIds eId) const
+{
+ return m_vMap.find( eId ) != m_vMap.end();
+}
+
+bool PropertyMap::isDocDefault( PropertyIds eId ) const
+{
+ std::map< PropertyIds, PropValue >::const_iterator aIter = m_vMap.find( eId );
+ if ( aIter == m_vMap.end() )
+ return false;
+ else
+ return aIter->second.getIsDocDefault();
+}
+
+#ifdef DBG_UTIL
+void PropertyMap::dumpXml() const
+{
+ TagLogger::getInstance().startElement( "PropertyMap" );
+
+ for ( const auto& rPropPair : m_vMap )
+ {
+ TagLogger::getInstance().startElement( "property" );
+
+ TagLogger::getInstance().attribute( "name", getPropertyName( rPropPair.first ) );
+
+ switch ( rPropPair.first )
+ {
+ case PROP_TABLE_COLUMN_SEPARATORS:
+ lcl_DumpTableColumnSeparators( rPropPair.second.getValue() );
+ break;
+ default:
+ {
+ try
+ {
+ sal_Int32 aInt = 0;
+ rPropPair.second.getValue() >>= aInt;
+ TagLogger::getInstance().attribute( "value", aInt );
+
+ sal_uInt32 auInt = 0;
+ rPropPair.second.getValue() >>= auInt;
+ TagLogger::getInstance().attribute( "unsignedValue", auInt );
+
+ float aFloat = 0.0;
+ rPropPair.second.getValue() >>= aFloat;
+ TagLogger::getInstance().attribute( "floatValue", aFloat );
+
+ rPropPair.second.getValue() >>= auInt;
+ TagLogger::getInstance().attribute( "stringValue", std::u16string_view() );
+ }
+ catch ( ... )
+ {
+ }
+ }
+ break;
+ }
+
+ TagLogger::getInstance().endElement();
+ }
+
+ TagLogger::getInstance().endElement();
+}
+#endif
+
+void PropertyMap::InsertProps( const PropertyMapPtr& rMap, const bool bOverwrite )
+{
+ if ( !rMap )
+ return;
+
+ for ( const auto& rPropPair : rMap->m_vMap )
+ {
+ if ( bOverwrite || !m_vMap.count(rPropPair.first) )
+ {
+ if ( !bOverwrite && !rPropPair.second.getIsDocDefault() )
+ m_vMap.insert(std::make_pair(rPropPair.first, PropValue(rPropPair.second.getValue(), rPropPair.second.getGrabBagType(), true)));
+ else
+ m_vMap[rPropPair.first] = rPropPair.second;
+ }
+ }
+
+ insertTableProperties( rMap.get(), bOverwrite );
+
+ Invalidate();
+}
+
+void PropertyMap::insertTableProperties( const PropertyMap*, const bool )
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element( "PropertyMap.insertTableProperties" );
+#endif
+}
+
+void PropertyMap::printProperties()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement( "properties" );
+
+ for ( const auto& rPropPair : m_vMap )
+ {
+ SAL_INFO( "writerfilter", getPropertyName( rPropPair.first ) );
+
+ table::BorderLine2 aLine;
+ sal_Int32 nColor;
+ if ( rPropPair.second.getValue() >>= aLine )
+ {
+ TagLogger::getInstance().startElement( "borderline" );
+ TagLogger::getInstance().attribute( "color", aLine.Color );
+ TagLogger::getInstance().attribute( "inner", aLine.InnerLineWidth );
+ TagLogger::getInstance().attribute( "outer", aLine.OuterLineWidth );
+ TagLogger::getInstance().endElement();
+ }
+ else if ( rPropPair.second.getValue() >>= nColor )
+ {
+ TagLogger::getInstance().startElement( "color" );
+ TagLogger::getInstance().attribute( "number", nColor );
+ TagLogger::getInstance().endElement();
+ }
+ }
+
+ TagLogger::getInstance().endElement();
+#else
+ (void) this; // avoid loplugin:staticmethods
+#endif
+}
+
+SectionPropertyMap::SectionPropertyMap( bool bIsFirstSection )
+ : m_bIsFirstSection( bIsFirstSection )
+ , m_eBorderApply( BorderApply::ToAllInSection )
+ , m_eBorderOffsetFrom( BorderOffsetFrom::Text )
+ , m_bTitlePage( false )
+ , m_nColumnCount( 0 )
+ , m_nColumnDistance( 1249 )
+ , m_bSeparatorLineIsOn( false )
+ , m_bEvenlySpaced( false )
+ , m_nPageNumber( -1 )
+ , m_nPageNumberType( -1 )
+ , m_nBreakType( -1 )
+ , m_nLeftMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nRightMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nGutterMargin(0)
+ , m_nTopMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nBottomMargin( o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nHeaderTop( o3tl::convert(0.5, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nHeaderBottom( o3tl::convert(0.5, o3tl::Length::in, o3tl::Length::mm100) )
+ , m_nGridType( 0 )
+ , m_nGridLinePitch( 1 )
+ , m_nDxtCharSpace( 0 )
+ , m_bGridSnapToChars( true )
+ , m_nLnnMod( 0 )
+ , m_nLnc(NS_ooxml::LN_Value_ST_LineNumberRestart_newPage)
+ , m_ndxaLnn( 0 )
+ , m_nLnnMin( 0 )
+ , m_nPaperSourceFirst( 0 )
+ , m_nPaperSourceOther( 0 )
+ , m_bDynamicHeightTop( true )
+ , m_bDynamicHeightBottom( true )
+{
+#ifdef DBG_UTIL
+ static sal_Int32 nNumber = 0;
+ m_nDebugSectionNumber = nNumber++;
+#endif
+
+ for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
+ {
+ m_nBorderDistances[nBorder] = -1;
+ m_bBorderShadows[nBorder] = false;
+ }
+ // todo: set defaults in ApplyPropertiesToPageStyles
+ // initialize defaults
+ PaperInfo aLetter( PAPER_LETTER );
+ // page height, 1/100mm
+ Insert( PROP_HEIGHT, uno::Any( static_cast<sal_Int32>(aLetter.getHeight()) ) );
+ // page width, 1/100mm
+ Insert( PROP_WIDTH, uno::Any( static_cast<sal_Int32>(aLetter.getWidth()) ) );
+ // page left margin, 1/100 mm
+ Insert( PROP_LEFT_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page right margin, 1/100 mm
+ Insert( PROP_RIGHT_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page top margin, 1/100 mm
+ Insert( PROP_TOP_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page bottom margin, 1/100 mm
+ Insert( PROP_BOTTOM_MARGIN, uno::Any( sal_Int32(o3tl::convert(1, o3tl::Length::in, o3tl::Length::mm100)) ) );
+ // page style layout
+ Insert( PROP_PAGE_STYLE_LAYOUT, uno::Any( style::PageStyleLayout_ALL ) );
+ uno::Any aFalse( uno::Any( false ) );
+ Insert( PROP_GRID_DISPLAY, aFalse );
+ Insert( PROP_GRID_PRINT, aFalse );
+ Insert( PROP_GRID_MODE, uno::Any( text::TextGridMode::NONE ) );
+
+ if ( m_bIsFirstSection )
+ {
+ m_sPageStyleName = getPropertyName(PROP_STANDARD);
+ }
+}
+
+uno::Reference<beans::XPropertySet> SectionPropertyMap::GetPageStyle(DomainMapper_Impl& rDM_Impl)
+{
+ const uno::Reference< container::XNameContainer >& xPageStyles = rDM_Impl.GetPageStyles();
+ const uno::Reference < lang::XMultiServiceFactory >& xTextFactory = rDM_Impl.GetTextFactory();
+ uno::Reference<beans::XPropertySet> xReturnPageStyle;
+ try
+ {
+ if (m_sPageStyleName.isEmpty() && xPageStyles.is())
+ {
+ assert( !rDM_Impl.IsInFootOrEndnote() && "Don't create useless page styles" );
+
+ m_sPageStyleName = rDM_Impl.GetUnusedPageStyleName();
+
+ m_aPageStyle.set(xTextFactory->createInstance("com.sun.star.style.PageStyle"), uno::UNO_QUERY );
+ xPageStyles->insertByName(m_sPageStyleName, uno::Any(m_aPageStyle));
+ }
+ else if (!m_aPageStyle.is() && xPageStyles.is())
+ {
+ xPageStyles->getByName(m_sPageStyleName) >>= m_aPageStyle;
+ }
+ xReturnPageStyle = m_aPageStyle;
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION( "writerfilter" );
+ }
+
+ return xReturnPageStyle;
+}
+
+// removes the content - all the paragraphs of an input XText
+void SectionPropertyMap::removeXTextContent(uno::Reference<text::XText> const& rxText)
+{
+ uno::Reference<text::XText> xText(rxText);
+ if (!xText.is())
+ return;
+ xText->setString(OUString());
+ uno::Reference<text::XParagraphAppend> const xAppend(xText, uno::UNO_QUERY_THROW);
+ uno::Reference<lang::XComponent> const xParagraph(xAppend->finishParagraph(uno::Sequence<beans::PropertyValue>()), uno::UNO_QUERY_THROW);
+ xParagraph->dispose();
+}
+
+/** Set the header/footer sharing as defined by titlePage and evenAndOdd flags
+ * in the document and clear the content of anything not written during the import.
+ */
+void SectionPropertyMap::setHeaderFooterProperties(DomainMapper_Impl& rDM_Impl)
+{
+ if (!m_aPageStyle.is())
+ return;
+
+ bool bHasHeader = false;
+ bool bHasFooter = false;
+
+ const OUString& sHeaderIsOn = getPropertyName(PROP_HEADER_IS_ON);
+ const OUString& sFooterIsOn = getPropertyName(PROP_FOOTER_IS_ON);
+
+ m_aPageStyle->getPropertyValue(sHeaderIsOn) >>= bHasHeader;
+ m_aPageStyle->getPropertyValue(sFooterIsOn) >>= bHasFooter;
+
+ bool bEvenAndOdd = rDM_Impl.GetSettingsTable()->GetEvenAndOddHeaders();
+
+ if (bHasHeader && !m_bLeftHeader && !bEvenAndOdd)
+ {
+ auto aAny = m_aPageStyle->getPropertyValue(getPropertyName(PROP_HEADER_TEXT_LEFT));
+ uno::Reference<text::XText> xText(aAny, uno::UNO_QUERY);
+ if (xText.is())
+ SectionPropertyMap::removeXTextContent(xText);
+ }
+
+ if (bHasFooter && !m_bLeftFooter && !bEvenAndOdd)
+ {
+ auto aAny = m_aPageStyle->getPropertyValue(getPropertyName(PROP_FOOTER_TEXT_LEFT));
+ uno::Reference<text::XText> xText(aAny, uno::UNO_QUERY);
+ if (xText.is())
+ SectionPropertyMap::removeXTextContent(xText);
+ }
+
+ if (bHasHeader && !m_bFirstHeader && !m_bTitlePage)
+ {
+ auto aAny = m_aPageStyle->getPropertyValue(getPropertyName(PROP_HEADER_TEXT_FIRST));
+ uno::Reference<text::XText> xText(aAny, uno::UNO_QUERY);
+ if (xText.is())
+ SectionPropertyMap::removeXTextContent(xText);
+ }
+
+ if (bHasFooter && !m_bFirstFooter && !m_bTitlePage)
+ {
+ auto aAny = m_aPageStyle->getPropertyValue(getPropertyName(PROP_FOOTER_TEXT_FIRST));
+ uno::Reference<text::XText> xText(aAny, uno::UNO_QUERY);
+ if (xText.is())
+ SectionPropertyMap::removeXTextContent(xText);
+ }
+
+ m_aPageStyle->setPropertyValue(getPropertyName(PROP_HEADER_IS_SHARED), uno::Any(!bEvenAndOdd));
+ m_aPageStyle->setPropertyValue(getPropertyName(PROP_FOOTER_IS_SHARED), uno::Any(!bEvenAndOdd));
+ m_aPageStyle->setPropertyValue(getPropertyName(PROP_FIRST_IS_SHARED), uno::Any(!m_bTitlePage));
+
+ bool bHadFirstHeader = m_bHadFirstHeader && m_bTitlePage;
+ if (bHasHeader && !bHadFirstHeader && !m_bHadLeftHeader && !m_bHadRightHeader && rDM_Impl.IsNewDoc())
+ {
+ m_aPageStyle->setPropertyValue(sHeaderIsOn, uno::Any(false));
+ }
+}
+
+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::ApplyPaperSource(DomainMapper_Impl& rDM_Impl)
+{
+ uno::Reference<beans::XPropertySet> xFirst;
+ // todo: negative spacing (from ww8par6.cxx)
+ if (!m_sPageStyleName.isEmpty())
+ {
+ xFirst = GetPageStyle(rDM_Impl);
+ if ( xFirst.is() )
+ try
+ {
+ //TODO: which of the two tray values needs to be set? first/other - the interfaces requires the name of the tray!
+ xFirst->setPropertyValue(getPropertyName(PROP_PAPER_TRAY),
+ uno::Any(m_nPaperSourceFirst));
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "Paper source not found");
+ }
+ }
+}
+
+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;
+ // todo: negative spacing (from ww8par6.cxx)
+ if (!m_sPageStyleName.isEmpty())
+ xFirst = GetPageStyle(rDM_Impl);
+
+ // has to be sorted like enum BorderPosition: l-r-t-b
+ const PropertyIds aBorderIds[4] =
+ {
+ PROP_LEFT_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_TOP_BORDER,
+ PROP_BOTTOM_BORDER
+ };
+
+ const PropertyIds aBorderDistanceIds[4] =
+ {
+ PROP_LEFT_BORDER_DISTANCE,
+ PROP_RIGHT_BORDER_DISTANCE,
+ PROP_TOP_BORDER_DISTANCE,
+ PROP_BOTTOM_BORDER_DISTANCE
+ };
+
+ const PropertyIds aMarginIds[4] =
+ {
+ PROP_LEFT_MARGIN,
+ PROP_RIGHT_MARGIN,
+ PROP_TOP_MARGIN,
+ PROP_BOTTOM_MARGIN
+ };
+
+ for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
+ {
+ if ( m_oBorderLines[nBorder] )
+ {
+ const OUString & sBorderName = getPropertyName( aBorderIds[nBorder] );
+ if ( xFirst.is() )
+ xFirst->setPropertyValue( sBorderName, uno::Any( *m_oBorderLines[nBorder] ) );
+ }
+ if ( m_nBorderDistances[nBorder] >= 0 )
+ {
+ sal_uInt32 nLineWidth = 0;
+ if ( m_oBorderLines[nBorder] )
+ nLineWidth = m_oBorderLines[nBorder]->LineWidth;
+ if ( xFirst.is() )
+ SetBorderDistance( xFirst, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
+ m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth, rDM_Impl );
+ }
+ }
+
+ if ( m_bBorderShadows[BORDER_RIGHT] )
+ {
+ table::ShadowFormat aFormat = getShadowFromBorder( *m_oBorderLines[BORDER_RIGHT] );
+ if ( xFirst.is() )
+ xFirst->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::Any( aFormat ) );
+ }
+}
+
+table::ShadowFormat PropertyMap::getShadowFromBorder( const table::BorderLine2& rBorder )
+{
+ // In Word UI, shadow is a boolean property, in OOXML, it's a boolean
+ // property of each 4 border type, finally in Writer the border is a
+ // property of the page style, with shadow location, distance and
+ // color. See SwWW8ImplReader::SetShadow().
+ table::ShadowFormat aFormat;
+ aFormat.Color = sal_Int32(COL_BLACK);
+ aFormat.Location = table::ShadowLocation_BOTTOM_RIGHT;
+ aFormat.ShadowWidth = rBorder.LineWidth;
+ return aFormat;
+}
+
+void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XPropertySet >& xStyle,
+ PropertyIds eMarginId,
+ PropertyIds eDistId,
+ sal_Int32 nDistance,
+ BorderOffsetFrom eOffsetFrom,
+ sal_uInt32 nLineWidth,
+ DomainMapper_Impl& rDM_Impl )
+{
+ if (!xStyle.is())
+ return;
+ const OUString & sMarginName = getPropertyName( eMarginId );
+ const OUString & sBorderDistanceName = getPropertyName( eDistId );
+ uno::Any aMargin = xStyle->getPropertyValue( sMarginName );
+ sal_Int32 nMargin = 0;
+ aMargin >>= nMargin;
+ editeng::BorderDistanceFromWord(eOffsetFrom == BorderOffsetFrom::Edge, nMargin, nDistance,
+ nLineWidth);
+
+ if (eOffsetFrom == BorderOffsetFrom::Edge)
+ {
+ uno::Any aGutterMargin = xStyle->getPropertyValue( "GutterMargin" );
+ sal_Int32 nGutterMargin = 0;
+ aGutterMargin >>= nGutterMargin;
+
+ if (eMarginId == PROP_LEFT_MARGIN && !rDM_Impl.GetSettingsTable()->GetGutterAtTop())
+ {
+ nMargin -= nGutterMargin;
+ nDistance += nGutterMargin;
+ }
+
+ if (eMarginId == PROP_TOP_MARGIN && rDM_Impl.GetSettingsTable()->GetGutterAtTop())
+ {
+ nMargin -= nGutterMargin;
+ nDistance += nGutterMargin;
+ }
+ }
+
+ // Change the margins with the border distance
+ uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
+ uno::Sequence<OUString> aProperties { sMarginName, sBorderDistanceName };
+ uno::Sequence<uno::Any> aValues { uno::Any( nMargin ), uno::Any( nDistance ) };
+ xMultiSet->setPropertyValues( aProperties, aValues );
+}
+
+void SectionPropertyMap::DontBalanceTextColumns()
+{
+ try
+ {
+ if ( m_xColumnContainer.is() )
+ m_xColumnContainer->setPropertyValue( "DontBalanceTextColumns", uno::Any( true ) );
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::DontBalanceTextColumns" );
+ }
+}
+
+void SectionPropertyMap::ApplySectionProperties( const uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& /*rDM_Impl*/ )
+{
+ try
+ {
+ if ( xSection.is() )
+ {
+ std::optional< PropertyMap::Property > pProp = getProperty( PROP_WRITING_MODE );
+ if ( pProp )
+ xSection->setPropertyValue( "WritingMode", pProp->second );
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception in SectionPropertyMap::ApplySectionProperties");
+ }
+}
+
+void SectionPropertyMap::ApplyProtectionProperties( uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& rDM_Impl )
+{
+ try
+ {
+ // Word implements section protection differently than LO.
+ // PROP_IS_PROTECTED only applies if global setting GetProtectForm is enabled.
+ bool bIsProtected = rDM_Impl.GetSettingsTable()->GetProtectForm();
+ if ( bIsProtected )
+ {
+ // If form protection is enabled then section protection is enabled, unless explicitly disabled
+ if ( isSet(PROP_IS_PROTECTED) )
+ getProperty(PROP_IS_PROTECTED)->second >>= bIsProtected;
+ if ( !xSection.is() )
+ xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
+ if ( xSection.is() )
+ xSection->setPropertyValue( getPropertyName(PROP_IS_PROTECTED), uno::Any(bIsProtected) );
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "ApplyProtectionProperties failed setting PROP_IS_PROTECTED");
+ }
+}
+
+uno::Reference< text::XTextColumns > SectionPropertyMap::ApplyColumnProperties( const uno::Reference< beans::XPropertySet >& xColumnContainer,
+ DomainMapper_Impl& rDM_Impl )
+{
+ uno::Reference< text::XTextColumns > xColumns;
+ assert( m_nColumnCount > 1 && "ApplyColumnProperties called without any columns" );
+ try
+ {
+ const OUString & sTextColumns = getPropertyName( PROP_TEXT_COLUMNS );
+ if ( xColumnContainer.is() )
+ xColumnContainer->getPropertyValue( sTextColumns ) >>= xColumns;
+ uno::Reference< beans::XPropertySet > xColumnPropSet( xColumns, uno::UNO_QUERY_THROW );
+ if ( !m_bEvenlySpaced &&
+ ( sal_Int32(m_aColWidth.size()) == m_nColumnCount ) &&
+ ( (sal_Int32(m_aColDistance.size()) == m_nColumnCount - 1) || (sal_Int32(m_aColDistance.size()) == m_nColumnCount) ) )
+ {
+ // the column width in word is an absolute value, in OOo it's relative
+ // the distances are both absolute
+ sal_Int32 nColSum = 0;
+ for ( sal_Int32 nCol = 0; nCol < m_nColumnCount; ++nCol )
+ {
+ nColSum += m_aColWidth[nCol];
+ if ( nCol )
+ nColSum += m_aColDistance[nCol - 1];
+ }
+
+ sal_Int32 nRefValue = xColumns->getReferenceValue();
+ double fRel = nColSum ? double( nRefValue ) / double( nColSum ) : 0.0;
+ uno::Sequence< text::TextColumn > aColumns( m_nColumnCount );
+ text::TextColumn* pColumn = aColumns.getArray();
+
+ nColSum = 0;
+ for ( sal_Int32 nCol = 0; nCol < m_nColumnCount; ++nCol )
+ {
+ const double fLeft = nCol ? m_aColDistance[nCol - 1] / 2 : 0;
+ pColumn[nCol].LeftMargin = fLeft;
+ const double fRight = (nCol == m_nColumnCount - 1) ? 0 : m_aColDistance[nCol] / 2;
+ pColumn[nCol].RightMargin = fRight;
+ const double fWidth = m_aColWidth[nCol];
+ pColumn[nCol].Width = (fWidth + fLeft + fRight) * fRel;
+ nColSum += pColumn[nCol].Width;
+ }
+ if ( nColSum != nRefValue )
+ pColumn[m_nColumnCount - 1].Width += (nRefValue - nColSum);
+ assert( pColumn[m_nColumnCount - 1].Width >= 0 );
+
+ xColumns->setColumns( aColumns );
+ }
+ else
+ {
+ xColumns->setColumnCount( m_nColumnCount );
+ xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::Any( m_nColumnDistance ) );
+ }
+
+ if ( m_bSeparatorLineIsOn )
+ {
+ xColumnPropSet->setPropertyValue( "SeparatorLineIsOn", uno::Any( true ) );
+ xColumnPropSet->setPropertyValue( "SeparatorLineVerticalAlignment", uno::Any( style::VerticalAlignment_TOP ) );
+ xColumnPropSet->setPropertyValue( "SeparatorLineRelativeHeight", uno::Any( static_cast<sal_Int8>(100) ) );
+ xColumnPropSet->setPropertyValue( "SeparatorLineColor", uno::Any( static_cast<sal_Int32>(COL_BLACK) ) );
+ // 1 twip -> 2 mm100.
+ xColumnPropSet->setPropertyValue( "SeparatorLineWidth", uno::Any( static_cast<sal_Int32>(2) ) );
+ }
+ xColumnContainer->setPropertyValue( sTextColumns, uno::Any( xColumns ) );
+ // Set the columns to be unbalanced if that compatibility option is set or this is the last section.
+ m_xColumnContainer = xColumnContainer;
+ if ( rDM_Impl.GetSettingsTable()->GetNoColumnBalance() || rDM_Impl.GetIsLastSectionGroup() )
+ DontBalanceTextColumns();
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::ApplyColumnProperties" );
+ }
+ return xColumns;
+}
+
+bool SectionPropertyMap::HasHeader() const
+{
+ bool bRet = false;
+ if (m_aPageStyle.is())
+ m_aPageStyle->getPropertyValue(getPropertyName(PROP_HEADER_IS_ON)) >>= bRet;
+ return bRet;
+}
+
+bool SectionPropertyMap::HasFooter() const
+{
+ bool bRet = false;
+ if (m_aPageStyle.is())
+ m_aPageStyle->getPropertyValue(getPropertyName(PROP_FOOTER_IS_ON)) >>= bRet;
+ return bRet;
+}
+
+#define MIN_HEAD_FOOT_HEIGHT 100 // minimum header/footer height
+
+namespace
+{
+
+// Copy the content of the header/footer property to the target style
+void copyHeaderFooterTextProperty(const uno::Reference<beans::XPropertySet>& xSource,
+ const uno::Reference<beans::XPropertySet>& xTarget,
+ PropertyIds ePropId)
+{
+ if (!xSource.is() || !xTarget.is())
+ return;
+
+ try {
+ const OUString& sName = getPropertyName(ePropId);
+ SAL_INFO( "writerfilter", "Copying " << sName );
+ uno::Reference<text::XText> xTextTarget(xTarget->getPropertyValue(sName), uno::UNO_QUERY_THROW);
+ // remove any content already present or else it can become a mess
+ SectionPropertyMap::removeXTextContent(xTextTarget);
+ uno::Reference<text::XTextCopy> xTextCopyTarget(xTextTarget, uno::UNO_QUERY_THROW);
+ if (!xTextCopyTarget.is())
+ return;
+ uno::Reference<text::XTextCopy> xTextCopySource(xSource->getPropertyValue(sName), uno::UNO_QUERY_THROW);
+ if (!xTextCopySource.is())
+ return;
+ xTextCopyTarget->copyText(xTextCopySource);
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_INFO_EXCEPTION( "writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooterTextProperty( )" );
+ }
+}
+
+// Copies all the header and footer content and relevant flags from the source style to the target.
+void completeCopyHeaderFooter(const uno::Reference<beans::XPropertySet>& xSourceStyle,
+ const uno::Reference<beans::XPropertySet>& xTargetStyle,
+ bool const bMissingHeader, bool const bMissingFooter)
+{
+ if (!xSourceStyle.is() || !xTargetStyle.is())
+ return;
+
+ bool bSourceHasHeader = false;
+ bool bSourceHasFooter = false;
+ bool bSourceHeaderIsShared = true;
+ bool bSourceFooterIsShared = true;
+ bool bSourceFirstIsShared = true;
+
+ const OUString& sHeaderIsOn = getPropertyName(PROP_HEADER_IS_ON);
+ const OUString& sFooterIsOn = getPropertyName(PROP_FOOTER_IS_ON);
+ const OUString& sHeaderIsShared = getPropertyName(PROP_HEADER_IS_SHARED);
+ const OUString& sFooterIsShared = getPropertyName(PROP_FOOTER_IS_SHARED);
+ const OUString& sFirstIsShared = getPropertyName(PROP_FIRST_IS_SHARED);
+
+ xSourceStyle->getPropertyValue(sHeaderIsOn) >>= bSourceHasHeader;
+ xSourceStyle->getPropertyValue(sFooterIsOn) >>= bSourceHasFooter;
+ xSourceStyle->getPropertyValue(sHeaderIsShared) >>= bSourceHeaderIsShared;
+ xSourceStyle->getPropertyValue(sFooterIsShared) >>= bSourceFooterIsShared;
+ xSourceStyle->getPropertyValue(sFirstIsShared) >>= bSourceFirstIsShared;
+
+ xTargetStyle->setPropertyValue(sHeaderIsOn, uno::Any(bSourceHasHeader));
+ xTargetStyle->setPropertyValue(sFooterIsOn, uno::Any(bSourceHasFooter));
+ xTargetStyle->setPropertyValue(sHeaderIsShared, uno::Any(bSourceHeaderIsShared));
+ xTargetStyle->setPropertyValue(sFooterIsShared, uno::Any(bSourceFooterIsShared));
+ xTargetStyle->setPropertyValue(sFirstIsShared, uno::Any(bSourceFirstIsShared));
+
+ if (bSourceHasHeader)
+ {
+ if (!bSourceFirstIsShared)
+ copyHeaderFooterTextProperty(xSourceStyle, xTargetStyle, PROP_HEADER_TEXT_FIRST);
+ if (!bSourceHeaderIsShared)
+ copyHeaderFooterTextProperty(xSourceStyle, xTargetStyle, PROP_HEADER_TEXT_LEFT);
+ copyHeaderFooterTextProperty(xSourceStyle, xTargetStyle, PROP_HEADER_TEXT);
+ }
+
+ if (bSourceHasFooter)
+ {
+ if (!bSourceFirstIsShared)
+ copyHeaderFooterTextProperty(xSourceStyle, xTargetStyle, PROP_FOOTER_TEXT_FIRST);
+ if (!bSourceFooterIsShared)
+ copyHeaderFooterTextProperty(xSourceStyle, xTargetStyle, PROP_FOOTER_TEXT_LEFT);
+ copyHeaderFooterTextProperty(xSourceStyle, xTargetStyle, PROP_FOOTER_TEXT);
+ }
+ // tdf#153196 the copy is used for the first page, the source will be used
+ // on subsequent pages, so clear source's first page header/footer
+ if (!bSourceFirstIsShared)
+ {
+ xSourceStyle->setPropertyValue(sFirstIsShared, uno::Any(true));
+ }
+ // if there is *only* a first-footer, and no previous section from which
+ // to inherit a footer, the import process has created an empty footer
+ // that didn't exist in the file; remove it
+ if (bSourceHasHeader && bMissingHeader)
+ {
+ xSourceStyle->setPropertyValue(sHeaderIsOn, uno::Any(false));
+ }
+ if (bSourceHasFooter && bMissingFooter)
+ {
+ // setting "FooterIsShared" to true here does nothing, because it causes
+ // left footer to be stashed, which means it will be exported anyway
+ xSourceStyle->setPropertyValue(sFooterIsOn, uno::Any(false));
+ }
+}
+
+// Copy headers and footers from the previous page style.
+void copyHeaderFooter(const DomainMapper_Impl& rDM_Impl,
+ const uno::Reference< beans::XPropertySet >& xPreviousStyle,
+ const uno::Reference< beans::XPropertySet >& xStyle,
+ bool bCopyRightHeader, bool bCopyLeftHeader, bool bCopyFirstHeader,
+ bool bCopyRightFooter, bool bCopyLeftFooter, bool bCopyFirstFooter,
+ bool bEvenAndOdd, bool bTitlePage)
+{
+ if (!rDM_Impl.IsNewDoc())
+ { // see also DomainMapper_Impl::PushPageHeaderFooter()
+ return; // tdf#139737 SwUndoInserts cannot deal with new header/footer
+ }
+
+ if (!xPreviousStyle.is())
+ return;
+
+ bool bCopyHeader = bCopyRightHeader || bCopyLeftHeader || bCopyFirstHeader;
+ bool bCopyFooter = bCopyRightFooter || bCopyLeftFooter || bCopyFirstFooter;
+
+ if (!bCopyHeader && !bCopyFooter)
+ return;
+
+ bool bPreviousHasHeader = false;
+ bool bPreviousHasFooter = false;
+
+ bool bHasHeader = false;
+ bool bHasFooter = false;
+
+ const OUString& sHeaderIsOn = getPropertyName(PROP_HEADER_IS_ON);
+ const OUString& sFooterIsOn = getPropertyName(PROP_FOOTER_IS_ON);
+ const OUString& sHeaderIsShared = getPropertyName(PROP_HEADER_IS_SHARED);
+ const OUString& sFooterIsShared = getPropertyName(PROP_FOOTER_IS_SHARED);
+ const OUString& sFirstIsShared = getPropertyName(PROP_FIRST_IS_SHARED);
+
+ xPreviousStyle->getPropertyValue(sHeaderIsOn) >>= bPreviousHasHeader;
+ xPreviousStyle->getPropertyValue(sFooterIsOn) >>= bPreviousHasFooter;
+
+ xStyle->getPropertyValue(sHeaderIsOn) >>= bHasHeader;
+ xStyle->getPropertyValue(sFooterIsOn) >>= bHasFooter;
+
+ xStyle->setPropertyValue(sHeaderIsOn, uno::Any(bPreviousHasHeader || bHasHeader));
+ xStyle->setPropertyValue(sFooterIsOn, uno::Any(bPreviousHasFooter || bHasFooter));
+ xStyle->setPropertyValue(sHeaderIsShared, uno::Any(false));
+ xStyle->setPropertyValue(sFooterIsShared, uno::Any(false));
+ xStyle->setPropertyValue(sFirstIsShared, uno::Any(false));
+
+ if (bPreviousHasHeader && bCopyHeader)
+ {
+ if (bCopyRightHeader)
+ copyHeaderFooterTextProperty(xPreviousStyle, xStyle, PROP_HEADER_TEXT);
+ if (bCopyLeftHeader && bEvenAndOdd)
+ copyHeaderFooterTextProperty(xPreviousStyle, xStyle, PROP_HEADER_TEXT_LEFT);
+ if (bCopyFirstHeader && bTitlePage)
+ copyHeaderFooterTextProperty(xPreviousStyle, xStyle, PROP_HEADER_TEXT_FIRST);
+ }
+
+ if (bPreviousHasFooter && bCopyFooter)
+ {
+ if (bCopyRightFooter)
+ copyHeaderFooterTextProperty(xPreviousStyle, xStyle, PROP_FOOTER_TEXT);
+ if (bCopyLeftFooter && bEvenAndOdd)
+ copyHeaderFooterTextProperty(xPreviousStyle, xStyle, PROP_FOOTER_TEXT_LEFT);
+ if (bCopyFirstFooter && bTitlePage)
+ copyHeaderFooterTextProperty(xPreviousStyle, xStyle, PROP_FOOTER_TEXT_FIRST);
+ }
+
+ xStyle->setPropertyValue(sHeaderIsOn, uno::Any(bPreviousHasHeader || bHasHeader));
+ xStyle->setPropertyValue(sFooterIsOn, uno::Any(bPreviousHasFooter || bHasFooter));
+
+ xStyle->setPropertyValue(sHeaderIsShared, uno::Any(!bEvenAndOdd));
+ xStyle->setPropertyValue(sFooterIsShared, uno::Any(!bEvenAndOdd));
+ xStyle->setPropertyValue(sFirstIsShared, uno::Any(!bTitlePage));
+}
+
+} // end anonymous namespace
+
+
+// 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(DomainMapper_Impl& rDM_Impl )
+{
+ SAL_INFO( "writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()" );
+ SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
+ if (pLastContext)
+ {
+ uno::Reference<beans::XPropertySet> xPreviousStyle = pLastContext->GetPageStyle(rDM_Impl);
+ uno::Reference<beans::XPropertySet> xStyle = GetPageStyle(rDM_Impl);
+
+ bool bEvenAndOdd = rDM_Impl.GetSettingsTable()->GetEvenAndOddHeaders();
+
+ copyHeaderFooter(rDM_Impl, xPreviousStyle, xStyle,
+ m_bDefaultHeaderLinkToPrevious,
+ m_bEvenPageHeaderLinkToPrevious,
+ m_bFirstPageHeaderLinkToPrevious,
+ m_bDefaultFooterLinkToPrevious,
+ m_bEvenPageFooterLinkToPrevious,
+ m_bFirstPageFooterLinkToPrevious,
+ bEvenAndOdd, m_bTitlePage);
+ }
+ SAL_INFO( "writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()" );
+}
+
+void SectionPropertyMap::PrepareHeaderFooterProperties()
+{
+ sal_Int32 nTopMargin = m_nTopMargin;
+ sal_Int32 nHeaderHeight = m_nHeaderTop;
+ if (HasHeader())
+ {
+ nTopMargin = m_nHeaderTop;
+ nHeaderHeight = m_nTopMargin - m_nHeaderTop;
+
+ // minimum header height 1mm
+ if ( nHeaderHeight < MIN_HEAD_FOOT_HEIGHT )
+ nHeaderHeight = MIN_HEAD_FOOT_HEIGHT;
+ }
+
+ Insert(PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::Any(m_bDynamicHeightTop));
+ Insert(PROP_HEADER_DYNAMIC_SPACING, uno::Any(m_bDynamicHeightTop));
+ Insert(PROP_HEADER_BODY_DISTANCE, uno::Any(nHeaderHeight - MIN_HEAD_FOOT_HEIGHT));
+ Insert(PROP_HEADER_HEIGHT, uno::Any(nHeaderHeight));
+ // looks like PROP_HEADER_HEIGHT = height of the header + space between the header, and the body
+
+ sal_Int32 nBottomMargin = m_nBottomMargin;
+ sal_Int32 nFooterHeight = m_nHeaderBottom;
+ if (HasFooter())
+ {
+ nBottomMargin = m_nHeaderBottom;
+ nFooterHeight = m_nBottomMargin - m_nHeaderBottom;
+
+ // minimum footer height 1mm
+ if ( nFooterHeight < MIN_HEAD_FOOT_HEIGHT )
+ nFooterHeight = MIN_HEAD_FOOT_HEIGHT;
+ }
+
+ Insert(PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::Any(m_bDynamicHeightBottom));
+ Insert(PROP_FOOTER_DYNAMIC_SPACING, uno::Any(m_bDynamicHeightBottom));
+ Insert(PROP_FOOTER_BODY_DISTANCE, uno::Any(nFooterHeight - MIN_HEAD_FOOT_HEIGHT));
+ Insert(PROP_FOOTER_HEIGHT, uno::Any(nFooterHeight));
+
+ //now set the top/bottom margin for the follow page style
+ Insert( PROP_TOP_MARGIN, uno::Any( std::max<sal_Int32>(nTopMargin, 0) ) );
+ Insert( PROP_BOTTOM_MARGIN, uno::Any( std::max<sal_Int32>(nBottomMargin, 0) ) );
+}
+
+static uno::Reference< beans::XPropertySet > lcl_GetRangeProperties( bool bIsFirstSection,
+ DomainMapper_Impl& rDM_Impl,
+ const uno::Reference< text::XTextRange >& xStartingRange )
+{
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( bIsFirstSection && rDM_Impl.GetBodyText().is() )
+ {
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( rDM_Impl.GetBodyText(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
+ xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ if ( rDM_Impl.GetIsDummyParaAddedForTableInSection() && xEnum->hasMoreElements() )
+ xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ }
+ else if ( xStartingRange.is() )
+ xRangeProperties.set( xStartingRange, uno::UNO_QUERY_THROW );
+ return xRangeProperties;
+}
+
+void SectionPropertyMap::HandleMarginsHeaderFooter(DomainMapper_Impl& rDM_Impl)
+{
+ Insert( PROP_LEFT_MARGIN, uno::Any( m_nLeftMargin ) );
+ Insert( PROP_RIGHT_MARGIN, uno::Any( m_nRightMargin ) );
+ Insert(PROP_GUTTER_MARGIN, uno::Any(m_nGutterMargin));
+
+ // w:background is applied to every page in the document
+ if (!rDM_Impl.m_oBackgroundColor.has_value() && !rDM_Impl.IsRTFImport())
+ {
+ // DOCX has an interesting quirk, where if the fallback background color is not defined,
+ // then the fill is not applied either.
+
+ // Disable the imported fill from the default style
+ if (rDM_Impl.m_bCopyStandardPageStyleFill && m_sPageStyleName == "Standard")
+ {
+ rDM_Impl.m_bCopyStandardPageStyleFill = false;
+ m_aPageStyle->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE));
+ }
+ }
+ else if (rDM_Impl.m_bCopyStandardPageStyleFill) // complex fill: graphics/gradients/patterns
+ {
+ uno::Reference<beans::XPropertySet> xDefaultPageStyle(
+ rDM_Impl.GetPageStyles()->getByName("Standard"), uno::UNO_QUERY_THROW);
+ for (const beans::Property& rProp : m_aPageStyle->getPropertySetInfo()->getProperties())
+ {
+ try
+ {
+ const uno::Any aFillValue = xDefaultPageStyle->getPropertyValue(rProp.Name);
+ m_aPageStyle->setPropertyValue(rProp.Name, aFillValue);
+ }
+ catch (uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception setting page background fill");
+ }
+ }
+ }
+ else if (rDM_Impl.m_oBackgroundColor) // simple, solid color
+ Insert( PROP_BACK_COLOR, uno::Any( *rDM_Impl.m_oBackgroundColor ) );
+
+ // Check for missing footnote separator only in case there is at least
+ // one footnote.
+ if (rDM_Impl.m_StreamStateStack.top().bHasFtn && !rDM_Impl.m_bHasFtnSep)
+ {
+ // Set footnote line width to zero, document has no footnote separator.
+ Insert(PROP_FOOTNOTE_LINE_RELATIVE_WIDTH, uno::Any(sal_Int32(0)));
+ }
+ if ( rDM_Impl.m_bHasFtnSep )
+ {
+ //If default paragraph style is RTL, footnote separator should be right aligned
+ //and for RTL locales, LTR default paragraph style should present a left aligned footnote separator
+ try
+ {
+ uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
+ if ( xStylesSupplier.is() )
+ {
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xParagraphStyles;
+ if ( xStyleFamilies.is() )
+ xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles;
+ uno::Reference<beans::XPropertySet> xStandard;
+ if ( xParagraphStyles.is() )
+ xParagraphStyles->getByName("Standard") >>= xStandard;
+ if ( xStandard.is() )
+ {
+ sal_Int16 aWritingMode(0);
+ xStandard->getPropertyValue( getPropertyName(PROP_WRITING_MODE) ) >>= aWritingMode;
+ if( aWritingMode == text::WritingMode2::RL_TB )
+ Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::Any( sal_Int16(text::HorizontalAdjust_RIGHT) ), false );
+ else
+ Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::Any( sal_Int16(text::HorizontalAdjust_LEFT) ), false );
+ }
+ }
+ }
+ catch ( const uno::Exception& ) {}
+ }
+
+ /*** if headers/footers are available then the top/bottom margins of the
+ header/footer are copied to the top/bottom margin of the page
+ */
+ CopyLastHeaderFooter(rDM_Impl);
+ PrepareHeaderFooterProperties();
+
+ // tdf#119952: If top/bottom margin was negative during docx import,
+ // then the header/footer and the body could be on top of each other
+ // writer is unable to display both of them in the same position, but can be simulated
+ // by moving the header/footer text into a flyframe anchored to the header/footer,
+ // leaving an empty dummy header/footer.
+ rDM_Impl.ConvertHeaderFooterToTextFrame(m_bDynamicHeightTop, m_bDynamicHeightBottom);
+}
+
+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.
+ SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
+ //tdf124637 TODO: identify and skip special sections (like footnotes/endnotes)
+ if (pLastContext && m_sPageStyleName.isEmpty())
+ m_sPageStyleName = pLastContext->GetPageStyleName();
+ else
+ {
+ HandleMarginsHeaderFooter(rDM_Impl);
+ GetPageStyle(rDM_Impl);
+ if (rDM_Impl.IsNewDoc() && m_aPageStyle.is())
+ ApplyProperties_(m_aPageStyle);
+ }
+}
+
+void SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl)
+{
+ // Ignore Word 2010 and older.
+ if (rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() < 15)
+ return;
+
+ sal_Int32 nPageWidth = GetPageWidth();
+ sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
+
+ std::vector<AnchoredObjectsInfo>& rAnchoredObjectAnchors = rDM_Impl.m_aAnchoredObjectAnchors;
+ for (const auto& rAnchor : rAnchoredObjectAnchors)
+ {
+ // Ignore this paragraph when there are not enough shapes to trigger the Word bug we
+ // emulate.
+ if (rAnchor.m_aAnchoredObjects.size() < 4)
+ continue;
+
+ // Ignore this paragraph if none of the objects are wrapped in the background.
+ sal_Int32 nOpaqueCount = 0;
+ for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
+ {
+ // Ignore inline objects stored only for redlining.
+ if (rAnchored.m_xRedlineForInline)
+ continue;
+
+ uno::Reference<beans::XPropertySet> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
+ if (!xShape.is())
+ {
+ continue;
+ }
+
+ bool bOpaque = true;
+ xShape->getPropertyValue("Opaque") >>= bOpaque;
+ if (!bOpaque)
+ {
+ ++nOpaqueCount;
+ }
+ }
+ if (nOpaqueCount < 1)
+ {
+ continue;
+ }
+
+ // Analyze the anchored objects of this paragraph, now that we know the
+ // page width.
+ sal_Int32 nShapesWidth = 0;
+ for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
+ {
+ uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
+ if (!xShape.is())
+ continue;
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ if (!xPropertySet.is())
+ continue;
+
+ // Ignore objects with no wrapping.
+ text::WrapTextMode eWrap = text::WrapTextMode_THROUGH;
+ xPropertySet->getPropertyValue("Surround") >>= eWrap;
+ if (eWrap == text::WrapTextMode_THROUGH)
+ continue;
+
+ // Use the original left margin, in case GraphicImport::lcl_sprm() reduced the doc model
+ // one to 0.
+ sal_Int32 nLeftMargin = rAnchored.m_nLeftMargin;
+ sal_Int32 nRightMargin = 0;
+ xPropertySet->getPropertyValue("RightMargin") >>= nRightMargin;
+ nShapesWidth += xShape->getSize().Width + nLeftMargin + nRightMargin;
+ }
+
+ // Ignore cases when we have enough horizontal space for the shapes.
+ if (nTextAreaWidth > nShapesWidth)
+ continue;
+
+ sal_Int32 nHeight = 0;
+ for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
+ {
+ uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
+ if (!xShape.is())
+ continue;
+
+ nHeight += xShape->getSize().Height;
+ }
+
+ uno::Reference<beans::XPropertySet> xParagraph(rAnchor.m_xParagraph, uno::UNO_QUERY);
+ if (xParagraph.is())
+ {
+ sal_Int32 nTopMargin = 0;
+ xParagraph->getPropertyValue("ParaTopMargin") >>= nTopMargin;
+ // Increase top spacing of the paragraph to match Word layout
+ // behavior.
+ nTopMargin = std::max(nTopMargin, nHeight);
+ xParagraph->setPropertyValue("ParaTopMargin", uno::Any(nTopMargin));
+ }
+ }
+ rAnchoredObjectAnchors.clear();
+}
+
+void BeforeConvertToTextFrame(std::deque<css::uno::Any>& rFramedRedlines, std::vector<sal_Int32>& redPos, std::vector<sal_Int32>& redLen, std::vector<OUString>& redCell, std::vector<OUString>& redTable)
+{
+ // convert redline ranges to cursor movement and character length
+ for( size_t i = 0; i < rFramedRedlines.size(); i+=3)
+ {
+ uno::Reference<text::XText> xCell;
+ uno::Reference< text::XTextRange > xRange;
+ rFramedRedlines[i] >>= xRange;
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( xRange.is() )
+ {
+ OUString sTableName;
+ OUString sCellName;
+ xRangeProperties.set( xRange, uno::UNO_QUERY_THROW );
+ if (xRangeProperties->getPropertySetInfo()->hasPropertyByName("TextTable"))
+ {
+ uno::Any aTable = xRangeProperties->getPropertyValue("TextTable");
+ if ( aTable != uno::Any() )
+ {
+ uno::Reference<text::XTextTable> xTable;
+ aTable >>= xTable;
+ uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
+ xTableProperties->getPropertyValue("TableName") >>= sTableName;
+ }
+ if (xRangeProperties->getPropertySetInfo()->hasPropertyByName("Cell"))
+ {
+ uno::Any aCell = xRangeProperties->getPropertyValue("Cell");
+ if ( aCell != uno::Any() )
+ {
+ aCell >>= xCell;
+ uno::Reference<beans::XPropertySet> xCellProperties(xCell, uno::UNO_QUERY);
+ xCellProperties->getPropertyValue("CellName") >>= sCellName;
+ }
+ }
+ }
+ redTable.push_back(sTableName);
+ redCell.push_back(sCellName);
+ bool bOk = false;
+ if (!sTableName.isEmpty() && !sCellName.isEmpty())
+ {
+ uno::Reference<text::XTextCursor> xRangeCursor = xCell->createTextCursorByRange( xRange );
+ if ( xRangeCursor.is() )
+ {
+ bOk = true;
+ sal_Int32 nLen = xRange->getString().getLength();
+ redLen.push_back(nLen);
+ xRangeCursor->gotoStart(true);
+ redPos.push_back(xRangeCursor->getString().getLength() - nLen);
+ }
+ }
+ if (!bOk)
+ {
+ // missing cell or failed createTextCursorByRange()
+ redLen.push_back(-1);
+ redPos.push_back(-1);
+ }
+ }
+ }
+}
+
+void AfterConvertToTextFrame(DomainMapper_Impl& rDM_Impl, std::deque<css::uno::Any>& aFramedRedlines, std::vector<sal_Int32>& redPos, std::vector<sal_Int32>& redLen, std::vector<OUString>& redCell, std::vector<OUString>& redTable)
+{
+ uno::Reference<text::XTextTablesSupplier> xTextDocument(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xTables = xTextDocument->getTextTables();
+ for( size_t i = 0; i < aFramedRedlines.size(); i+=3)
+ {
+ OUString sType;
+ beans::PropertyValues aRedlineProperties( 3 );
+ // skip failed createTextCursorByRange()
+ if (redPos[i/3] == -1)
+ continue;
+ aFramedRedlines[i+1] >>= sType;
+ aFramedRedlines[i+2] >>= aRedlineProperties;
+ uno::Reference<text::XTextTable> xTable(xTables->getByName(redTable[i/3]), uno::UNO_QUERY);
+ uno::Reference<text::XText> xCell(xTable->getCellByName(redCell[i/3]), uno::UNO_QUERY);
+ uno::Reference<text::XTextCursor> xCrsr = xCell->createTextCursor();
+ xCrsr->goRight(redPos[i/3], false);
+ xCrsr->goRight(redLen[i/3], true);
+ uno::Reference < text::XRedline > xRedline( xCrsr, uno::UNO_QUERY_THROW );
+ try
+ {
+ xRedline->makeRedline( sType, aRedlineProperties );
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "makeRedline() failed");
+ }
+ }
+}
+
+void SectionPropertyMap::CreateEvenOddPageStyleCopy(DomainMapper_Impl& rDM_Impl, PageBreakType eBreakType)
+{
+ 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_aPageStyle);
+ uno::Reference<beans::XPropertySetInfo> pagePropertiesInfo(pageProperties->getPropertySetInfo());
+ const uno::Sequence<beans::Property> propertyList(pagePropertiesInfo->getProperties());
+
+ // Ignore write-only properties.
+ static constexpr frozen::unordered_set<std::u16string_view, 14> staticDenylist = {
+ u"FooterBackGraphicURL", u"BackGraphicURL", u"HeaderBackGraphicURL",
+ u"HeaderIsOn", u"FooterIsOn",
+ u"HeaderIsShared", u"FooterIsShared", u"FirstIsShared",
+ u"HeaderText", u"HeaderTextLeft", u"HeaderTextFirst",
+ u"FooterText", u"FooterTextLeft", u"FooterTextFirst" };
+
+ for (const auto& rProperty : propertyList)
+ {
+ if ((rProperty.Attributes & beans::PropertyAttribute::READONLY) == 0)
+ {
+ if (staticDenylist.find(rProperty.Name) == staticDenylist.end())
+ {
+ evenOddStyle->setPropertyValue(
+ rProperty.Name,
+ pageProperties->getPropertyValue(rProperty.Name));
+ }
+ }
+ }
+ evenOddStyle->setPropertyValue("FollowStyle", uno::Any(m_sPageStyleName));
+
+ rDM_Impl.GetPageStyles()->insertByName(evenOddStyleName, uno::Any(evenOddStyle));
+
+ if (rDM_Impl.IsNewDoc())
+ {
+ bool const bEvenAndOdd(rDM_Impl.GetSettingsTable()->GetEvenAndOddHeaders());
+ completeCopyHeaderFooter(pageProperties, evenOddStyle,
+ !rDM_Impl.SeenHeaderFooter(PagePartType::Header, PageType::RIGHT)
+ && (!bEvenAndOdd || !rDM_Impl.SeenHeaderFooter(PagePartType::Header, PageType::LEFT)),
+ !rDM_Impl.SeenHeaderFooter(PagePartType::Footer, PageType::RIGHT)
+ && (!bEvenAndOdd || !rDM_Impl.SeenHeaderFooter(PagePartType::Footer, PageType::LEFT)));
+ }
+
+ if (eBreakType == PageBreakType::Even)
+ evenOddStyle->setPropertyValue(getPropertyName(PROP_PAGE_STYLE_LAYOUT), uno::Any(style::PageStyleLayout_LEFT));
+ else if (eBreakType == PageBreakType::Odd)
+ evenOddStyle->setPropertyValue(getPropertyName(PROP_PAGE_STYLE_LAYOUT), uno::Any(style::PageStyleLayout_RIGHT));
+
+ m_sPageStyleName = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one).
+}
+
+void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
+{
+ SectionPropertyMap* pPrevSection = rDM_Impl.GetLastSectionContext();
+
+ // The default section type is nextPage.
+ if ( m_nBreakType == -1 )
+ m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextColumn )
+ {
+ // Word 2013+ seems to treat a section column break as a page break all the time.
+ // It always acts like a page break if there are no columns, or a different number of columns.
+ // Also, if this is the first section, the break type is basically irrelevant - works best as nextPage.
+ if ( rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() > 14
+ || !pPrevSection
+ || m_nColumnCount < 2
+ || m_nColumnCount != pPrevSection->ColumnCount()
+ )
+ {
+ m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ }
+ }
+ else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous )
+ {
+ // if page orientation differs from previous section, it can't be treated as continuous
+ if ( pPrevSection )
+ {
+ bool bIsLandscape = false;
+ std::optional< PropertyMap::Property > pProp = getProperty( PROP_IS_LANDSCAPE );
+ if ( pProp )
+ pProp->second >>= bIsLandscape;
+
+ bool bPrevIsLandscape = false;
+ pProp = pPrevSection->getProperty( PROP_IS_LANDSCAPE );
+ if ( pProp )
+ pProp->second >>= bPrevIsLandscape;
+
+ if ( bIsLandscape != bPrevIsLandscape )
+ m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ }
+ }
+
+ try
+ {
+ HandleIncreasedAnchoredObjectSpacing(rDM_Impl);
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "HandleIncreasedAnchoredObjectSpacing() failed");
+ }
+
+ if ( m_nLnnMod )
+ {
+ bool bFirst = rDM_Impl.IsLineNumberingSet();
+ rDM_Impl.SetLineNumbering( m_nLnnMod, m_nLnc, m_ndxaLnn );
+ if ( m_nLnnMin > 0 || (bFirst && m_nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newSection) )
+ {
+ //set the starting value at the beginning of the section
+ try
+ {
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( m_xStartingRange.is() )
+ {
+ xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
+ }
+ else
+ {
+ //set the start value at the beginning of the document
+ xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
+ }
+ // Writer is 1-based, Word is 0-based.
+ xRangeProperties->setPropertyValue(
+ getPropertyName(PROP_PARA_LINE_NUMBER_START_VALUE),
+ uno::Any(m_nLnnMin + 1));
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
+ }
+ }
+ }
+
+ if (m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous
+ && !rDM_Impl.IsInComments())
+ {
+ //todo: insert a section or access the already inserted section
+ uno::Reference< beans::XPropertySet > xSection =
+ rDM_Impl.appendTextSectionAfter( m_xStartingRange );
+ if ( xSection.is() )
+ {
+ if ( m_nColumnCount > 1 )
+ ApplyColumnProperties( xSection, rDM_Impl );
+
+ ApplyProtectionProperties( xSection, rDM_Impl );
+ }
+
+ try
+ {
+ setHeaderFooterProperties(rDM_Impl);
+ InheritOrFinalizePageStyles( rDM_Impl );
+ ApplySectionProperties( xSection, rDM_Impl ); //depends on InheritOrFinalizePageStyles
+ uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
+ if ( m_bIsFirstSection && !m_sPageStyleName.isEmpty() && xRangeProperties.is() )
+ {
+ xRangeProperties->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME), uno::Any(m_sPageStyleName));
+ }
+ 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 eBreakType;
+ if ((xElem->getPropertyValue("BreakType") >>= eBreakType) && eBreakType == style::BreakType_PAGE_BEFORE)
+ {
+ // tdf#112201: do *not* use m_sFirstPageStyleName here!
+ xElem->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME), uno::Any(m_sPageStyleName));
+ m_aPageStyle->setPropertyValue(getPropertyName(PROP_FIRST_IS_SHARED), uno::Any(true));
+ 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 eBreakType;
+ if ((xPSCursor->getPropertyValue("BreakType") >>= eBreakType) && eBreakType == style::BreakType_PAGE_BEFORE)
+ {
+ xPSCursor->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME), uno::Any(m_sPageStyleName));
+ m_aPageStyle->setPropertyValue(getPropertyName(PROP_FIRST_IS_SHARED), uno::Any(true));
+ isFound = true;
+ }
+ else
+ {
+ xPSCursor->getPropertyValue("CharHeight") >>= fCharHeight;
+ }
+ }
+ if (!isFound && fCharHeight <= 1.0)
+ {
+ // If still not found, see if the last paragraph is ~invisible, and work with
+ // the last-in-practice paragraph.
+ xPCursor->gotoPreviousParagraph(false);
+ uno::Reference<beans::XPropertySet> xPropertySet(xCursor, uno::UNO_QUERY_THROW);
+ OUString aPageDescName;
+ if ((xPropertySet->getPropertyValue("PageDescName") >>= aPageDescName) && !aPageDescName.isEmpty())
+ {
+ uno::Reference<beans::XPropertySet> xPageStyle(rDM_Impl.GetPageStyles()->getByName(aPageDescName), uno::UNO_QUERY);
+ xPageStyle->setPropertyValue("FollowStyle", uno::Any(m_sPageStyleName));
+ m_aPageStyle->setPropertyValue(getPropertyName(PROP_FIRST_IS_SHARED), uno::Any(true));
+ }
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ SAL_WARN( "writerfilter", "failed to set PageDescName!" );
+ }
+ }
+ // If the section is of type "New column" (0x01), then simply insert a column break.
+ // But only if there actually are columns on the page, otherwise a column break
+ // seems to be handled like a page break by MSO.
+ else if (m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextColumn
+ && m_nColumnCount > 1 && !rDM_Impl.IsInComments())
+ {
+ try
+ {
+ setHeaderFooterProperties(rDM_Impl);
+ InheritOrFinalizePageStyles( rDM_Impl );
+ /*TODO tdf#135343: Just inserting a column break sounds like the right idea, but the implementation is wrong.
+ * Somehow, the previous column section needs to be extended to cover this new text.
+ * Currently, it is completely broken, producing a no-column section that starts on a new page.
+ */
+ uno::Reference< beans::XPropertySet > xRangeProperties;
+ if ( m_xStartingRange.is() )
+ {
+ xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
+ }
+ else
+ {
+ //set the start value at the beginning of the document
+ xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
+ }
+ xRangeProperties->setPropertyValue( getPropertyName( PROP_BREAK_TYPE ), uno::Any( style::BreakType_COLUMN_BEFORE ) );
+ }
+ catch ( const uno::Exception& ) {}
+ }
+ else if (!rDM_Impl.IsInComments())
+ {
+ uno::Reference< beans::XPropertySet > xSection;
+ ApplyProtectionProperties( xSection, rDM_Impl );
+
+ //get the properties and create appropriate page styles
+ uno::Reference<beans::XPropertySet> xPageStyle;
+ //This part certainly is not needed for footnotes, so don't create unused page styles.
+ if ( !rDM_Impl.IsInFootOrEndnote() )
+ {
+ xPageStyle.set(GetPageStyle(rDM_Impl));
+ setHeaderFooterProperties(rDM_Impl);
+ HandleMarginsHeaderFooter(rDM_Impl);
+ }
+
+ if ( rDM_Impl.GetSettingsTable()->GetMirrorMarginSettings() )
+ {
+ Insert( PROP_PAGE_STYLE_LAYOUT, uno::Any( style::PageStyleLayout_MIRRORED ) );
+ }
+ uno::Reference< text::XTextColumns > xColumns;
+ if ( m_nColumnCount > 1 )
+ {
+ // prefer setting column properties into a section, not a page style if at all possible.
+ if ( !xSection.is() )
+ xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
+ if ( xSection.is() )
+ ApplyColumnProperties(xSection, rDM_Impl);
+ else if (xPageStyle.is())
+ xColumns = ApplyColumnProperties(xPageStyle, rDM_Impl);
+ }
+
+ // these BreakTypes are effectively page-breaks: don't evenly distribute text in columns before a page break;
+ if ( pPrevSection && pPrevSection->ColumnCount() )
+ pPrevSection->DontBalanceTextColumns();
+
+ //prepare text grid properties
+ sal_Int32 nHeight = 1;
+ std::optional< PropertyMap::Property > pProp = getProperty( PROP_HEIGHT );
+ if ( pProp )
+ pProp->second >>= nHeight;
+
+ sal_Int32 nWidth = 1;
+ pProp = getProperty( PROP_WIDTH );
+ if ( pProp )
+ pProp->second >>= nWidth;
+
+ sal_Int16 nWritingMode = text::WritingMode2::LR_TB;
+ pProp = getProperty( PROP_WRITING_MODE );
+ if ( pProp )
+ pProp->second >>= nWritingMode;
+
+ sal_Int32 nTextAreaHeight = nWritingMode == text::WritingMode2::LR_TB ?
+ nHeight - m_nTopMargin - m_nBottomMargin :
+ nWidth - m_nLeftMargin - m_nRightMargin;
+
+ sal_Int32 nGridLinePitch = m_nGridLinePitch;
+ //sep.dyaLinePitch
+ if ( nGridLinePitch < 1 || nGridLinePitch > 31680 )
+ {
+ SAL_WARN( "writerfilter", "sep.dyaLinePitch outside legal range: " << nGridLinePitch );
+ nGridLinePitch = 1;
+ }
+
+ const sal_Int32 nGridLines = nTextAreaHeight / nGridLinePitch;
+ sal_Int16 nGridType = m_nGridType;
+ if ( nGridLines >= 0 && nGridLines <= SAL_MAX_INT16 )
+ Insert( PROP_GRID_LINES, uno::Any( sal_Int16(nGridLines) ) );
+ else
+ nGridType = text::TextGridMode::NONE;
+
+ // PROP_GRID_MODE
+ if ( nGridType == text::TextGridMode::LINES_AND_CHARS )
+ {
+ if (!m_nDxtCharSpace)
+ nGridType = text::TextGridMode::LINES;
+ else
+ Insert( PROP_GRID_SNAP_TO_CHARS, uno::Any( m_bGridSnapToChars ) );
+ }
+
+ Insert( PROP_GRID_MODE, uno::Any( nGridType ) );
+
+ sal_Int32 nCharWidth = 423; //240 twip/ 12 pt
+ const StyleSheetEntryPtr pEntry = rDM_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( u"Standard" );
+ if ( pEntry )
+ {
+ std::optional< PropertyMap::Property > pPropHeight = pEntry->m_pProperties->getProperty( PROP_CHAR_HEIGHT_ASIAN );
+ if ( pPropHeight )
+ {
+ double fHeight = 0;
+ if ( pPropHeight->second >>= fHeight )
+ nCharWidth = ConversionHelper::convertTwipToMM100( static_cast<tools::Long>(fHeight * 20.0 + 0.5) );
+ }
+ }
+
+ //dxtCharSpace
+ if ( m_nDxtCharSpace )
+ {
+ sal_Int32 nCharSpace = m_nDxtCharSpace;
+ //main lives in top 20 bits, and is signed.
+ sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
+ nMain /= 0x1000;
+ nCharWidth += ConversionHelper::convertTwipToMM100( nMain * 20 );
+
+ sal_Int32 nFraction = (nCharSpace & 0x00000FFF);
+ nFraction = (nFraction * 20) / 0xFFF;
+ nCharWidth += ConversionHelper::convertTwipToMM100( nFraction );
+ }
+
+ if ( m_nPageNumberType >= 0 )
+ Insert( PROP_NUMBERING_TYPE, uno::Any( m_nPageNumberType ) );
+
+ // #i119558#, force to set document as standard page mode,
+ // refer to ww8 import process function "SwWW8ImplReader::SetDocumentGrid"
+ try
+ {
+ uno::Reference< beans::XPropertySet > xDocProperties;
+ xDocProperties.set( rDM_Impl.GetTextDocument(), uno::UNO_QUERY_THROW );
+ Insert(PROP_GRID_STANDARD_MODE, uno::Any(true));
+ xDocProperties->setPropertyValue("DefaultPageMode", uno::Any(false));
+ }
+ catch ( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
+ }
+
+ Insert( PROP_GRID_BASE_HEIGHT, uno::Any( nGridLinePitch ) );
+ Insert( PROP_GRID_BASE_WIDTH, uno::Any( nCharWidth ) );
+ Insert( PROP_GRID_RUBY_HEIGHT, uno::Any( sal_Int32( 0 ) ) );
+
+ if (rDM_Impl.IsNewDoc() && xPageStyle.is())
+ ApplyProperties_(xPageStyle);
+
+ ApplyBorderToPageStyles( rDM_Impl, m_eBorderApply, m_eBorderOffsetFrom );
+ ApplyPaperSource(rDM_Impl);
+
+ try
+ {
+ //now apply this break at the first paragraph of this section
+ uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
+
+ // Handle page breaks with odd/even page numbering. We need to use an extra page style for setting the page style
+ // to left/right, because if we set it to the normal style, we'd set it to "First Page"/"Default Style", which would
+ // break them (all default pages would be only left or right).
+ if (m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_evenPage)
+ {
+ CreateEvenOddPageStyleCopy(rDM_Impl, PageBreakType::Even);
+ }
+ else if (m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_oddPage)
+ {
+ CreateEvenOddPageStyleCopy(rDM_Impl, PageBreakType::Odd);
+ }
+
+ if (rDM_Impl.m_xAltChunkStartingRange.is())
+ {
+ xRangeProperties.set(rDM_Impl.m_xAltChunkStartingRange, uno::UNO_QUERY);
+ }
+ if (xRangeProperties.is() && (rDM_Impl.IsNewDoc() || rDM_Impl.IsAltChunk()))
+ {
+ // Avoid setting page style in case of autotext: so inserting the autotext at the
+ // end of the document does not introduce an unwanted page break.
+ // Also avoid setting the page style at the very beginning if it still is the default page style.
+ const OUString sPageStyle = m_sPageStyleName;
+ if (!rDM_Impl.IsReadGlossaries()
+ && !rDM_Impl.IsInFootOrEndnote()
+ && !(m_bIsFirstSection && sPageStyle == getPropertyName( PROP_STANDARD ) && m_nPageNumber < 0)
+ )
+ {
+ xRangeProperties->setPropertyValue(
+ getPropertyName( PROP_PAGE_DESC_NAME ),
+ uno::Any(sPageStyle) );
+ }
+
+ if (0 <= m_nPageNumber)
+ {
+ sal_Int16 nPageNumber = static_cast< sal_Int16 >(m_nPageNumber);
+ xRangeProperties->setPropertyValue(getPropertyName(PROP_PAGE_NUMBER_OFFSET),
+ uno::Any(nPageNumber));
+ }
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::CloseSectionGroup" );
+ }
+ }
+
+ // Now that the margins are known, resize relative width shapes because some shapes in LO do not support percentage-sizes
+ sal_Int32 nParagraphWidth = GetPageWidth() - m_nLeftMargin - m_nRightMargin;
+ if ( m_nColumnCount > 1 )
+ {
+ // skip custom-width columns since we don't know what column the shape is in.
+ if ( !m_aColWidth.empty() )
+ nParagraphWidth = 0;
+ else
+ nParagraphWidth = (nParagraphWidth - (m_nColumnDistance * (m_nColumnCount - 1))) / m_nColumnCount;
+ }
+ if ( nParagraphWidth > 0 )
+ {
+ const OUString & sPropRelativeWidth = getPropertyName(PROP_RELATIVE_WIDTH);
+ for ( const auto& xShape : m_xRelativeWidthShapes )
+ {
+ const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
+ if ( xShapePropertySet->getPropertySetInfo()->hasPropertyByName(sPropRelativeWidth) )
+ {
+ sal_uInt16 nPercent = 0;
+ try
+ {
+ xShapePropertySet->getPropertyValue(sPropRelativeWidth) >>= nPercent;
+ }
+ catch (const css::uno::RuntimeException& e)
+ {
+ // May happen e.g. when text frame has no frame format
+ // See sw/qa/extras/ooxmlimport/data/n779627.docx
+ SAL_WARN("writerfilter", "Getting relative width failed. " << e.Message);
+ }
+ if ( nPercent )
+ {
+ const sal_Int32 nWidth = nParagraphWidth * nPercent / 100;
+ xShape->setSize( awt::Size( nWidth, xShape->getSize().Height ) );
+ }
+ }
+ }
+ }
+ m_xRelativeWidthShapes.clear();
+
+ rDM_Impl.SetIsLastSectionGroup( false );
+ rDM_Impl.SetIsFirstParagraphInSection( true );
+
+ if ( !rDM_Impl.IsInFootOrEndnote() && !rDM_Impl.IsInComments() )
+ {
+ rDM_Impl.m_StreamStateStack.top().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(PagePartType ePartType, PageType eType)
+{
+ if (ePartType == PagePartType::Header)
+ {
+ switch (eType)
+ {
+ case PageType::FIRST: m_bFirstPageHeaderLinkToPrevious = false; break;
+ case PageType::LEFT: m_bEvenPageHeaderLinkToPrevious = false; break;
+ case PageType::RIGHT: m_bDefaultHeaderLinkToPrevious = false; break;
+ }
+ }
+ else if (ePartType == PagePartType::Footer)
+ {
+ switch (eType)
+ {
+ case PageType::FIRST: m_bFirstPageFooterLinkToPrevious = false; break;
+ case PageType::LEFT: m_bEvenPageFooterLinkToPrevious = false; break;
+ case PageType::RIGHT: m_bDefaultFooterLinkToPrevious = false; break;
+ }
+ }
+}
+
+namespace {
+
+class NamedPropertyValue
+{
+private:
+ OUString m_aName;
+
+public:
+ explicit NamedPropertyValue( OUString i_aStr )
+ : m_aName(std::move( i_aStr ))
+ {
+ }
+
+ bool operator() ( beans::PropertyValue const & aVal )
+ {
+ return aVal.Name == m_aName;
+ }
+};
+
+}
+
+void SectionPropertyMap::ApplyProperties_( const uno::Reference< beans::XPropertySet >& xStyle )
+{
+ uno::Reference< beans::XMultiPropertySet > const xMultiSet( xStyle, uno::UNO_QUERY );
+
+ std::vector< OUString > vNames;
+ std::vector< uno::Any > vValues;
+ {
+ // Convert GetPropertyValues() value into something useful
+ const uno::Sequence< beans::PropertyValue > vPropVals = GetPropertyValues();
+
+ //Temporarily store the items that are in grab bags
+ uno::Sequence< beans::PropertyValue > vCharVals;
+ uno::Sequence< beans::PropertyValue > vParaVals;
+ const beans::PropertyValue* pCharGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "CharInteropGrabBag" ) );
+ if ( pCharGrabBag != vPropVals.end() )
+ (pCharGrabBag->Value) >>= vCharVals;
+ const beans::PropertyValue* pParaGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "ParaInteropGrabBag" ) );
+ if ( pParaGrabBag != vPropVals.end() )
+ (pParaGrabBag->Value) >>= vParaVals;
+
+ for ( const beans::PropertyValue* pIter = vPropVals.begin(); pIter != vPropVals.end(); ++pIter )
+ {
+ if ( pIter != pCharGrabBag && pIter != pParaGrabBag
+ && pIter->Name != "IsProtected" //section-only property
+ )
+ {
+ vNames.push_back( pIter->Name );
+ vValues.push_back( pIter->Value );
+ }
+ }
+ for (const beans::PropertyValue& v : vCharVals)
+ {
+ vNames.push_back( v.Name );
+ vValues.push_back( v.Value );
+ }
+ for (const beans::PropertyValue& v : vParaVals)
+ {
+ vNames.push_back( v.Name );
+ vValues.push_back( v.Value );
+ }
+ }
+ if ( xMultiSet.is() )
+ {
+ try
+ {
+ xMultiSet->setPropertyValues( comphelper::containerToSequence( vNames ), comphelper::containerToSequence( vValues ) );
+ return;
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::ApplyProperties_" );
+ }
+ }
+ for ( size_t i = 0; i < vNames.size(); ++i )
+ {
+ try
+ {
+ if ( xStyle.is() )
+ xStyle->setPropertyValue( vNames[i], vValues[i] );
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "SectionPropertyMap::ApplyProperties_" );
+ }
+ }
+}
+
+sal_Int32 SectionPropertyMap::GetPageWidth() const
+{
+ return getProperty( PROP_WIDTH )->second.get<sal_Int32>();
+}
+
+StyleSheetPropertyMap::StyleSheetPropertyMap()
+ : mnListLevel( -1 )
+ , mnOutlineLevel( -1 )
+{
+}
+
+ParagraphProperties::ParagraphProperties()
+ : m_bFrameMode( false )
+ , m_nDropCap( NS_ooxml::LN_Value_doc_ST_DropCap_none )
+ , m_nLines( 0 )
+ , m_w( -1 )
+ , m_h( -1 )
+ , m_nWrap( text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE )
+ , m_hAnchor( -1 )
+ , m_vAnchor( -1 )
+ , m_x( -1 )
+ , m_bxValid( false )
+ , m_y( -1 )
+ , m_byValid( false )
+ , m_hSpace( -1 )
+ , m_vSpace( -1 )
+ , m_hRule( -1 )
+ , m_xAlign( -1 )
+ , m_yAlign( -1 )
+ , m_nDropCapLength( 0 )
+{
+}
+
+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/sw/source/writerfilter/dmapper/PropertyMap.hxx b/sw/source/writerfilter/dmapper/PropertyMap.hxx
new file mode 100644
index 000000000000..711ef47195a0
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PropertyMap.hxx
@@ -0,0 +1,651 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/text/XText.hpp>
+#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 <utility>
+#include <vector>
+#include <set>
+#include <deque>
+
+namespace com::sun::star {
+ namespace beans {
+ struct PropertyValue;
+ }
+ namespace container {
+ class XNameContainer;
+ }
+ namespace lang {
+ class XMultiServiceFactory;
+ }
+ namespace text {
+ class XTextRange;
+ class XTextColumns;
+ class XFootnote;
+ }
+ namespace table {
+ struct BorderLine2;
+ struct ShadowFormat;
+ }
+}
+
+namespace writerfilter::dmapper {
+
+class DomainMapper_Impl;
+struct 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 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( css::uno::Any aValue, GrabBagType i_GrabBagType, bool bDocDefault )
+ : m_aValue(std::move( aValue ))
+ , m_GrabBagType( i_GrabBagType )
+ , m_bIsDocDefault( bDocDefault )
+ {
+ }
+
+ PropValue( css::uno::Any aValue, GrabBagType i_GrabBagType )
+ : m_aValue(std::move( aValue ))
+ , 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 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();
+ }
+};
+
+/** Type of an page, which has an effect which headers and/or footers will be used. */
+enum class PageType
+{
+ FIRST,
+ LEFT,
+ RIGHT
+};
+
+/** Which page part we are referring to.
+ * This is mainly introduced to avoid having cryptic bools as input parameter.*/
+enum class PagePartType
+{
+ Header,
+ Footer
+};
+
+/** A page break type to force what the next page type will be.
+ * For example - the next page is forced to be even (left) or odd (right). */
+enum class PageBreakType
+{
+ Even,
+ Odd,
+ Both
+};
+
+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_sPageStyleName;
+ css::uno::Reference<css::beans::XPropertySet> m_aPageStyle;
+
+ std::optional< css::table::BorderLine2 > m_oBorderLines[4];
+ sal_Int32 m_nBorderDistances[4];
+ BorderApply m_eBorderApply;
+ BorderOffsetFrom m_eBorderOffsetFrom;
+ bool m_bBorderShadows[4];
+
+ bool m_bTitlePage;
+ sal_Int16 m_nColumnCount;
+ sal_Int32 m_nColumnDistance;
+ css::uno::Reference< css::beans::XPropertySet > m_xColumnContainer;
+ std::vector< sal_Int32 > m_aColWidth;
+ std::vector< sal_Int32 > m_aColDistance;
+
+ bool m_bSeparatorLineIsOn;
+ bool m_bEvenlySpaced;
+
+ sal_Int32 m_nPageNumber;
+ // Page number type is a value from css::style::NumberingType.
+ sal_Int16 m_nPageNumberType;
+ sal_Int32 m_nBreakType;
+
+ sal_Int32 m_nLeftMargin;
+ sal_Int32 m_nRightMargin;
+ sal_Int32 m_nGutterMargin;
+ sal_Int32 m_nTopMargin;
+ sal_Int32 m_nBottomMargin;
+ sal_Int32 m_nHeaderTop;
+ sal_Int32 m_nHeaderBottom;
+
+ sal_Int32 m_nGridType;
+ sal_Int32 m_nGridLinePitch;
+ sal_Int32 m_nDxtCharSpace;
+ bool m_bGridSnapToChars;
+
+ // line numbering
+ sal_Int32 m_nLnnMod;
+ sal_uInt32 m_nLnc;
+ sal_Int32 m_ndxaLnn;
+ sal_Int32 m_nLnnMin;
+
+ sal_Int32 m_nPaperSourceFirst;
+ sal_Int32 m_nPaperSourceOther;
+
+ bool m_bDynamicHeightTop;
+ bool m_bDynamicHeightBottom;
+
+ std::vector<css::uno::Reference<css::drawing::XShape>> m_xRelativeWidthShapes;
+
+ // The "Link To Previous" flag indicates whether the header/footer
+ // content should be taken from the previous section
+ bool m_bDefaultHeaderLinkToPrevious = true;
+ bool m_bEvenPageHeaderLinkToPrevious = true;
+ bool m_bFirstPageHeaderLinkToPrevious = true;
+ bool m_bDefaultFooterLinkToPrevious = true;
+ bool m_bEvenPageFooterLinkToPrevious = true;
+ bool m_bFirstPageFooterLinkToPrevious = true;
+
+ 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>& xPageStyle,
+ DomainMapper_Impl& rDM_Impl);
+
+ void CopyLastHeaderFooter(DomainMapper_Impl& rDM_Impl);
+
+ void CreateEvenOddPageStyleCopy(DomainMapper_Impl& rDM_Impl, PageBreakType eBreakType);
+
+ void PrepareHeaderFooterProperties();
+
+ bool HasHeader() const;
+ bool HasFooter() const;
+
+ static void SetBorderDistance( const css::uno::Reference< css::beans::XPropertySet >& xStyle,
+ PropertyIds eMarginId,
+ PropertyIds eDistId,
+ sal_Int32 nDistance,
+ BorderOffsetFrom eOffsetFrom,
+ sal_uInt32 nLineWidth,
+ DomainMapper_Impl& rDM_Impl );
+
+ /// Increases paragraph spacing according to Word 2013+ needs if necessary.
+ void HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl);
+
+public:
+ 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);
+
+ const OUString& GetPageStyleName()
+ {
+ return m_sPageStyleName;
+ }
+
+ bool getFirstPageHeader() { return m_bFirstPageHeaderLinkToPrevious; }
+ bool getFirstPageFooter() { return m_bFirstPageFooterLinkToPrevious; }
+
+ // @throws css::beans::UnknownPropertyException
+ // @throws css::beans::PropertyVetoException
+ // @throws css::lang::IllegalArgumentException
+ // @throws css::lang::WrappedTargetException
+ // @throws css::uno::RuntimeException
+ void InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Impl );
+
+ void SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const css::table::BorderLine2& rBorderLine, bool bShadow );
+ void SetBorderApply( BorderApply nSet ) { m_eBorderApply = nSet; }
+ void SetBorderOffsetFrom( BorderOffsetFrom nSet ) { m_eBorderOffsetFrom = nSet; }
+
+ void SetColumnCount( sal_Int16 nCount ) { m_nColumnCount = nCount; }
+ sal_Int16 ColumnCount() const { return m_nColumnCount; }
+
+ void SetColumnDistance( sal_Int32 nDist ) { m_nColumnDistance = nDist; }
+ void AppendColumnWidth( sal_Int32 nWidth ) { m_aColWidth.push_back( nWidth ); }
+ void AppendColumnSpacing( sal_Int32 nDist ) { m_aColDistance.push_back( nDist ); }
+
+ void SetTitlePage( bool bSet ) { m_bTitlePage = bSet; }
+ void SetSeparatorLine( bool bSet ) { m_bSeparatorLineIsOn = bSet; }
+ void SetEvenlySpaced( bool bSet ) { m_bEvenlySpaced = bSet; }
+ void SetPageNumber( sal_Int32 nSet ) { m_nPageNumber = nSet; }
+ void SetPageNumberType( sal_Int32 nSet ) { m_nPageNumberType = nSet; }
+ void SetBreakType( sal_Int32 nSet ) { m_nBreakType = nSet; }
+ // GetBreakType returns -1 if the breakType has not yet been identified for the section
+ sal_Int32 GetBreakType() const { return m_nBreakType; }
+
+ void SetLeftMargin( sal_Int32 nSet ) { m_nLeftMargin = nSet; }
+ sal_Int32 GetLeftMargin() const { return m_nLeftMargin; }
+ void SetRightMargin( sal_Int32 nSet ) { m_nRightMargin = nSet; }
+ sal_Int32 GetRightMargin() const { return m_nRightMargin; }
+ void SetTopMargin(sal_Int32 nSet) { m_bDynamicHeightTop = nSet >= 0; m_nTopMargin = std::abs(nSet); }
+ void SetBottomMargin( sal_Int32 nSet ) { m_bDynamicHeightBottom = nSet >= 0; m_nBottomMargin = std::abs(nSet); }
+ void SetHeaderTop( sal_Int32 nSet ) { m_nHeaderTop = nSet; }
+ void SetHeaderBottom( sal_Int32 nSet ) { m_nHeaderBottom = nSet; }
+ void SetGutterMargin( sal_Int32 nGutterMargin ) { m_nGutterMargin = nGutterMargin; }
+ sal_Int32 GetPageWidth() const;
+
+ void SetGridType( sal_Int32 nSet ) { m_nGridType = nSet; }
+ void SetGridLinePitch( sal_Int32 nSet ) { m_nGridLinePitch = nSet; }
+ void SetGridSnapToChars( bool bSet ) { m_bGridSnapToChars = bSet; }
+ void SetDxtCharSpace( sal_Int32 nSet ) { m_nDxtCharSpace = nSet; }
+
+ void SetLnnMod( sal_Int32 nValue ) { m_nLnnMod = nValue; }
+ void SetLnc( sal_Int32 nValue ) { m_nLnc = nValue; }
+ void SetdxaLnn( sal_Int32 nValue ) { m_ndxaLnn = nValue; }
+ void SetLnnMin( sal_Int32 nValue ) { m_nLnnMin = nValue; }
+
+ void SetPaperSource(sal_Int32 first, sal_Int32 other) { m_nPaperSourceFirst = first; m_nPaperSourceOther = other;}
+
+ 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 ApplyPaperSource(DomainMapper_Impl& rDM_Impl);
+ void CloseSectionGroup( DomainMapper_Impl& rDM_Impl );
+ // Handling of margins, header and footer for any kind of sections breaks.
+ void HandleMarginsHeaderFooter(DomainMapper_Impl& rDM_Impl);
+ void clearHeaderFooterLinkToPrevious(PagePartType ePartType, PageType eType);
+ void setHeaderFooterProperties(DomainMapper_Impl& rDM_Impl);
+
+ // Which headers/footer types are used (have been imported) by the current section.
+ bool m_bFirstHeader = false;
+ bool m_bFirstFooter = false;
+ bool m_bLeftHeader = false;
+ bool m_bLeftFooter = false;
+ bool m_bRightHeader = false;
+ bool m_bRightFooter = false;
+ bool m_bHadFirstHeader = false;
+ bool m_bHadLeftHeader = false;
+ bool m_bHadRightHeader = false;
+
+ static void removeXTextContent(css::uno::Reference<css::text::XText> const& rxText);
+};
+
+void BeforeConvertToTextFrame(std::deque<css::uno::Any>& rFramedRedlines, std::vector<sal_Int32>& redPos, std::vector<sal_Int32>& redLen, std::vector<OUString>& redCell, std::vector<OUString>& redTable);
+
+void AfterConvertToTextFrame(DomainMapper_Impl& rDM_Impl, std::deque<css::uno::Any>& aFramedRedlines, std::vector<sal_Int32>& redPos, std::vector<sal_Int32>& redLen, std::vector<OUString>& redCell, std::vector<OUString>& redTable);
+
+class ParagraphProperties : public SvRefBase
+{
+private:
+ bool m_bFrameMode;
+ sal_Int32 m_nDropCap; // drop, margin ST_DropCap
+ sal_Int32 m_nLines; // number of lines of the drop cap
+ sal_Int32 m_w; // width
+ sal_Int32 m_h; // height
+ css::text::WrapTextMode m_nWrap; // from ST_Wrap around, auto, none, notBeside, through, tight
+ sal_Int32 m_hAnchor; // page, from ST_HAnchor margin, page, text
+ sal_Int32 m_vAnchor; // around from ST_VAnchor margin, page, text
+ sal_Int32 m_x; // x-position
+ bool m_bxValid;
+ sal_Int32 m_y; // y-position
+ bool m_byValid;
+ sal_Int32 m_hSpace; // frame padding h
+ sal_Int32 m_vSpace; // frame padding v
+ sal_Int32 m_hRule; // from ST_HeightRule exact, atLeast, auto
+ sal_Int32 m_xAlign; // from ST_XAlign center, inside, left, outside, right
+ sal_Int32 m_yAlign; // from ST_YAlign bottom, center, inline, inside, outside, top
+ sal_Int8 m_nDropCapLength; // number of characters
+ OUString m_sParaStyleName;
+ OUString m_sParaId; // [MS-DOCX] sect. 2.2.4 "p and tr Extensions"
+
+ css::uno::Reference< css::text::XTextRange > m_xStartingRange; // start of a frame
+ css::uno::Reference< css::text::XTextRange > m_xEndingRange; // end of the frame
+ sal_Int32 m_nListId = -1;
+
+public:
+ ParagraphProperties();
+
+ ParagraphProperties(ParagraphProperties const &) = default;
+ ParagraphProperties(ParagraphProperties &&) = default;
+ ParagraphProperties & operator =(ParagraphProperties const &) = default;
+ ParagraphProperties & operator =(ParagraphProperties &&) = default;
+
+ sal_Int32 GetListId() const { return m_nListId; }
+ void SetListId( sal_Int32 nId ) { m_nListId = nId; }
+
+ bool IsFrameMode() const { return m_bFrameMode; }
+ void SetFrameMode( bool set = true ) { m_bFrameMode = set; }
+
+ sal_Int32 GetDropCap() const { return m_nDropCap; }
+ void SetDropCap( sal_Int32 nSet ) { m_nDropCap = nSet; }
+
+ sal_Int32 GetLines() const { return m_nLines; }
+ void SetLines( sal_Int32 nSet ) { m_nLines = nSet; }
+
+ sal_Int32 Getw() const { return m_w; }
+ void Setw( sal_Int32 nSet ) { m_w = nSet; }
+
+ sal_Int32 Geth() const { return m_h; }
+ void Seth( sal_Int32 nSet ) { m_h = nSet; }
+
+ css::text::WrapTextMode GetWrap() const { return m_nWrap; }
+ void SetWrap( css::text::WrapTextMode nSet ) { m_nWrap = nSet; }
+
+ sal_Int32 GethAnchor() const { return m_hAnchor; }
+ void SethAnchor( sal_Int32 nSet ) { m_hAnchor = nSet; }
+
+ sal_Int32 GetvAnchor() const { return m_vAnchor; }
+ void SetvAnchor( sal_Int32 nSet ) { m_vAnchor = nSet; }
+
+ sal_Int32 Getx() const { return m_x; }
+ void Setx( sal_Int32 nSet ) { m_x = nSet; m_bxValid = true; }
+ bool IsxValid() const { return m_bxValid; }
+
+ sal_Int32 Gety() const { return m_y; }
+ void Sety( sal_Int32 nSet ) { m_y = nSet; m_byValid = true; }
+ bool IsyValid() const { return m_byValid; }
+
+ void SethSpace( sal_Int32 nSet ) { m_hSpace = nSet; }
+ sal_Int32 GethSpace() const { return m_hSpace; }
+
+ sal_Int32 GetvSpace() const { return m_vSpace; }
+ void SetvSpace( sal_Int32 nSet ) { m_vSpace = nSet; }
+
+ sal_Int32 GethRule() const { return m_hRule; }
+ void SethRule( sal_Int32 nSet ) { m_hRule = nSet; }
+
+ sal_Int32 GetxAlign() const { return m_xAlign; }
+ void SetxAlign( sal_Int32 nSet ) { m_xAlign = nSet; }
+
+ sal_Int32 GetyAlign() const { return m_yAlign; }
+ void SetyAlign( sal_Int32 nSet ) { m_yAlign = nSet; }
+
+ sal_Int8 GetDropCapLength() const { return m_nDropCapLength; }
+ void SetDropCapLength( sal_Int8 nSet ) { m_nDropCapLength = nSet; }
+
+ const css::uno::Reference< css::text::XTextRange >& GetStartingRange() const { return m_xStartingRange; }
+ void SetStartingRange( const css::uno::Reference< css::text::XTextRange >& xSet ) { m_xStartingRange = xSet; }
+
+ const css::uno::Reference< css::text::XTextRange >& GetEndingRange() const { return m_xEndingRange; }
+ void SetEndingRange( const css::uno::Reference< css::text::XTextRange >& xSet ) { m_xEndingRange = xSet; }
+
+ const OUString& GetParaStyleName() const { return m_sParaStyleName; }
+ void SetParaStyleName( const OUString& rSet ) { m_sParaStyleName = rSet; }
+
+ const OUString& GetParaId() const { return m_sParaId; }
+ void SetParaId(const OUString& rSet) { m_sParaId = rSet; }
+
+ void ResetFrameProperties();
+};
+
+typedef tools::SvRef< ParagraphProperties > ParagraphPropertiesPtr;
+
+class ParagraphPropertiesPropertyMap: public PropertyMap {
+public:
+ ParagraphProperties & props() { return m_props; }
+
+ ParagraphProperties const & props() const { return m_props; }
+
+private:
+ ParagraphProperties m_props;
+};
+
+/*-------------------------------------------------------------------------
+ property map of a stylesheet
+ -----------------------------------------------------------------------*/
+
+#define WW_OUTLINE_MAX sal_Int16( 9 )
+#define WW_OUTLINE_MIN sal_Int16( 0 )
+
+class StyleSheetPropertyMap
+ : public ParagraphPropertiesPropertyMap
+{
+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 ParagraphPropertiesPropertyMap
+{
+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,
+ LEFT_MARGIN,
+ HORI_ORIENT,
+ TablePropertyMapTarget_MAX
+ };
+
+private:
+ struct ValidValue
+ {
+ sal_Int32 nValue;
+ bool bValid;
+
+ ValidValue()
+ : nValue( 0 )
+ , bValid( false )
+ {
+ }
+ };
+
+ ValidValue m_aValidValues[TablePropertyMapTarget_MAX];
+
+public:
+ explicit TablePropertyMap() {}
+
+ bool getValue( TablePropertyMapTarget eWhich, sal_Int32& nFill );
+ void setValue( TablePropertyMapTarget eWhich, sal_Int32 nSet );
+
+ virtual void insertTableProperties( const PropertyMap*, const bool bOverwrite = true ) override;
+};
+
+typedef tools::SvRef< TablePropertyMap > TablePropertyMapPtr;
+
+/// Information about a paragraph to be finished after a table end.
+struct TableParagraph
+{
+ css::uno::Reference<css::text::XTextRange> m_rStartParagraph;
+ css::uno::Reference<css::text::XTextRange> m_rEndParagraph;
+ PropertyMapPtr m_pPropertyMap;
+ css::uno::Reference<css::beans::XPropertySet> m_rPropertySet;
+};
+
+typedef std::shared_ptr< std::vector<TableParagraph> > TableParagraphVectorPtr;
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PropertyMapHelper.cxx b/sw/source/writerfilter/dmapper/PropertyMapHelper.cxx
new file mode 100644
index 000000000000..a944dc147aa4
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PropertyMapHelper.cxx
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/text/TableColumnSeparator.hpp>
+#include "TagLogger.hxx"
+#include "PropertyMapHelper.hxx"
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+void lcl_DumpTableColumnSeparators(const uno::Any& rTableColumnSeparators)
+{
+#ifdef DBG_UTIL
+ uno::Sequence<text::TableColumnSeparator> aSeq;
+ rTableColumnSeparators >>= aSeq;
+
+ TagLogger::getInstance().startElement("property.TableColumnSeparators");
+
+ sal_uInt32 nLength = aSeq.getLength();
+ for (sal_uInt32 n = 0; n < nLength; ++n)
+ {
+ TagLogger::getInstance().startElement("separator");
+
+ TagLogger::getInstance().attribute("position", aSeq[n].Position);
+ TagLogger::getInstance().attribute("visible", sal_uInt32(aSeq[n].IsVisible));
+
+ TagLogger::getInstance().endElement();
+ }
+
+ TagLogger::getInstance().endElement();
+#else
+ (void)rTableColumnSeparators;
+#endif // DBG_UTIL
+}
+
+#ifdef DBG_UTIL
+void lcl_DumpPropertyValues(beans::PropertyValues const& rValues)
+{
+ TagLogger::getInstance().startElement("propertyValues");
+
+ for (beans::PropertyValue const& propVal : rValues)
+ {
+ TagLogger::getInstance().startElement("propertyValue");
+
+ TagLogger::getInstance().attribute("name", propVal.Name);
+
+ try
+ {
+ sal_Int32 aInt = 0;
+ propVal.Value >>= aInt;
+ TagLogger::getInstance().attribute("value", aInt);
+ }
+ catch (...)
+ {
+ }
+
+ if (propVal.Name == "TableColumnSeparators")
+ {
+ lcl_DumpTableColumnSeparators(propVal.Value);
+ }
+
+ TagLogger::getInstance().endElement();
+ }
+ TagLogger::getInstance().endElement();
+}
+
+void lcl_DumpPropertyValueSeq(css::uno::Sequence<css::beans::PropertyValues> const& rPropValSeq)
+{
+ TagLogger::getInstance().startElement("PropertyValueSeq");
+
+ for (auto const& propVal : rPropValSeq)
+ {
+ lcl_DumpPropertyValues(propVal);
+ }
+
+ TagLogger::getInstance().endElement();
+}
+#endif // DBG_UTIL
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/PropertyMapHelper.hxx b/sw/source/writerfilter/dmapper/PropertyMapHelper.hxx
new file mode 100644
index 000000000000..472e1bcfa6f5
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/PropertyMapHelper.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/PropertyValues.hpp>
+
+namespace writerfilter::dmapper
+{
+void lcl_DumpTableColumnSeparators(const css::uno::Any& rTableColumnSeparators);
+#ifdef DBG_UTIL
+void lcl_DumpPropertyValues(css::beans::PropertyValues const& rValues);
+
+void lcl_DumpPropertyValueSeq(css::uno::Sequence<css::beans::PropertyValues> const& rPropValSeq);
+#endif // DBG_UTIL
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SdtHelper.cxx b/sw/source/writerfilter/dmapper/SdtHelper.cxx
new file mode 100644
index 000000000000..09e7903b5f98
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SdtHelper.cxx
@@ -0,0 +1,647 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "SdtHelper.hxx"
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <editeng/unoprnms.hxx>
+#include <sal/log.hxx>
+#include <utility>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
+#include <xmloff/odffields.hxx>
+#include <com/sun/star/text/XTextField.hpp>
+#include "DomainMapper_Impl.hxx"
+#include "StyleSheetTable.hxx"
+#include <officecfg/Office/Writer.hxx>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/document/XOOXMLDocumentPropertiesImporter.hpp>
+#include <ooxml/OOXMLDocument.hxx>
+#include <com/sun/star/xml/xpath/XPathAPI.hpp>
+#include <com/sun/star/xml/xpath/XPathException.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+using namespace ::css::xml::xpath;
+using namespace ::comphelper;
+
+/// w:sdt's w:dropDownList doesn't have width, so guess the size based on the longest string.
+static awt::Size lcl_getOptimalWidth(const StyleSheetTablePtr& pStyleSheet,
+ OUString const& rDefault, std::vector<OUString>& rItems)
+{
+ OUString aLongest = rDefault;
+ sal_Int32 nHeight = 0;
+ for (const OUString& rItem : rItems)
+ if (rItem.getLength() > aLongest.getLength())
+ aLongest = rItem;
+
+ MapMode aMap(MapUnit::Map100thMM);
+ OutputDevice* pOut = Application::GetDefaultDevice();
+ pOut->Push(vcl::PushFlags::FONT | vcl::PushFlags::MAPMODE);
+
+ PropertyMapPtr pDefaultCharProps = pStyleSheet->GetDefaultCharProps();
+ vcl::Font aFont(pOut->GetFont());
+ std::optional<PropertyMap::Property> aFontName
+ = pDefaultCharProps->getProperty(PROP_CHAR_FONT_NAME);
+ if (aFontName)
+ aFont.SetFamilyName(aFontName->second.get<OUString>());
+ std::optional<PropertyMap::Property> aHeight = pDefaultCharProps->getProperty(PROP_CHAR_HEIGHT);
+ if (aHeight)
+ {
+ nHeight = aHeight->second.get<double>() * 35; // points -> mm100
+ aFont.SetFontSize(Size(0, nHeight));
+ }
+ pOut->SetFont(aFont);
+ pOut->SetMapMode(aMap);
+ sal_Int32 nWidth = pOut->GetTextWidth(aLongest);
+
+ pOut->Pop();
+
+ // Border: see PDFWriterImpl::drawFieldBorder(), border size is font height / 4,
+ // so additional width / height needed is height / 2.
+ sal_Int32 nBorder = nHeight / 2;
+
+ // Width: space for the text + the square having the dropdown arrow.
+ return { nWidth + nBorder + nHeight, nHeight + nBorder };
+}
+
+SdtHelper::SdtHelper(DomainMapper_Impl& rDM_Impl,
+ css::uno::Reference<css::uno::XComponentContext> xContext)
+ : m_rDM_Impl(rDM_Impl)
+ , m_xComponentContext(std::move(xContext))
+ , m_aControlType(SdtControlType::unknown)
+ , m_bHasUnusedText(false)
+ , m_bHasElements(false)
+ , m_bOutsideAParagraph(false)
+ , m_bPropertiesXMLsLoaded(false)
+{
+}
+
+SdtHelper::~SdtHelper() = default;
+
+void SdtHelper::loadPropertiesXMLs()
+{
+ // Initialize properties xml storage (m_xPropertiesXMLs)
+ uno::Reference<uno::XInterface> xTemp
+ = m_xComponentContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.document.OOXMLDocumentPropertiesImporter", m_xComponentContext);
+ uno::Reference<document::XOOXMLDocumentPropertiesImporter> xImporter(xTemp, uno::UNO_QUERY);
+ if (!xImporter.is())
+ return;
+
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(
+ xml::dom::DocumentBuilder::create(m_xComponentContext));
+ if (!xDomBuilder.is())
+ return;
+
+ // Load core properties
+ try
+ {
+ auto xCorePropsStream = xImporter->getCorePropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ m_xPropertiesXMLs.insert(
+ { OUString("{6C3C8BC8-F283-45AE-878A-BAB7291924A1}"), // hardcoded id for core props
+ xDomBuilder->parse(xCorePropsStream) });
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading core properties XML");
+ }
+
+ // Load extended properties
+ try
+ {
+ auto xExtPropsStream
+ = xImporter->getExtendedPropertiesStream(m_rDM_Impl.m_xDocumentStorage);
+ m_xPropertiesXMLs.insert(
+ { OUString("{6668398D-A668-4E3E-A5EB-62B293D839F1}"), // hardcoded id for extended props
+ xDomBuilder->parse(xExtPropsStream) });
+ }
+ catch (const uno::Exception&)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: failed loading extended properties XML");
+ }
+
+ // TODO: some other property items?
+
+ // Add custom XMLs
+ uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmls
+ = m_rDM_Impl.getDocumentReference()->getCustomXmlDomList();
+ uno::Sequence<uno::Reference<xml::dom::XDocument>> aCustomXmlProps
+ = m_rDM_Impl.getDocumentReference()->getCustomXmlDomPropsList();
+ if (aCustomXmls.getLength())
+ {
+ uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+ xXpathAPI->registerNS("ds",
+ "http://schemas.openxmlformats.org/officeDocument/2006/customXml");
+ sal_Int32 nItem = 0;
+ // Hereby we assume that items from getCustomXmlDomList() and getCustomXmlDomPropsList()
+ // are matching each other:
+ // item1.xml -> itemProps1.xml, item2.xml -> itemProps2.xml
+ // This does works practically, but is it true in general?
+ for (const auto& xDoc : aCustomXmls)
+ {
+ // Retrieve storeid from properties xml
+ OUString aStoreId;
+ uno::Reference<XXPathObject> xResult
+ = xXpathAPI->eval(aCustomXmlProps[nItem], "string(/ds:datastoreItem/@ds:itemID)");
+
+ if (xResult.is() && xResult->getString().getLength())
+ {
+ aStoreId = xResult->getString();
+ }
+ else
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::loadPropertiesXMLs: can't fetch storeid for custom doc!");
+ }
+
+ m_xPropertiesXMLs.insert({ aStoreId, xDoc });
+ nItem++;
+ }
+ }
+
+ m_bPropertiesXMLsLoaded = true;
+}
+
+static void lcl_registerNamespaces(std::u16string_view sNamespaceString,
+ const uno::Reference<XXPathAPI>& xXPathAPI)
+{
+ // Split namespaces and register it in XPathAPI
+ auto aNamespaces = string::split(sNamespaceString, ' ');
+ for (const auto& sNamespace : aNamespaces)
+ {
+ // Here we have just one namespace in format "xmlns:ns0='http://someurl'"
+ auto aNamespace = string::split(sNamespace, '=');
+ if (aNamespace.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << sNamespace);
+ continue;
+ }
+
+ auto aNamespaceId = string::split(aNamespace[0], ':');
+ if (aNamespaceId.size() < 2)
+ {
+ SAL_WARN("writerfilter",
+ "SdtHelper::getValueFromDataBinding: invalid namespace: " << aNamespace[0]);
+ continue;
+ }
+
+ OUString sNamespaceURL = aNamespace[1];
+ sNamespaceURL = string::strip(sNamespaceURL, ' ');
+ sNamespaceURL = string::strip(sNamespaceURL, '\'');
+
+ xXPathAPI->registerNS(aNamespaceId[1], sNamespaceURL);
+ }
+}
+
+std::optional<OUString> SdtHelper::getValueFromDataBinding()
+{
+ // No xpath - nothing to do
+ if (m_sDataBindingXPath.isEmpty())
+ return {};
+
+ // Load properties XMLs
+ if (!m_bPropertiesXMLsLoaded)
+ loadPropertiesXMLs();
+
+ uno::Reference<XXPathAPI> xXpathAPI = XPathAPI::create(m_xComponentContext);
+
+ lcl_registerNamespaces(m_sDataBindingPrefixMapping, xXpathAPI);
+
+ // Find storage by store id and eval xpath there
+ const auto& aSourceIt = m_xPropertiesXMLs.find(m_sDataBindingStoreItemID);
+ if (aSourceIt != m_xPropertiesXMLs.end())
+ {
+ try
+ {
+ uno::Reference<XXPathObject> xResult
+ = xXpathAPI->eval(aSourceIt->second, m_sDataBindingXPath);
+
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength()
+ && xResult->getString().getLength())
+ {
+ return xResult->getString();
+ }
+ }
+ catch (const XPathException& e)
+ {
+ // XPath failed? Log and continue with next data document
+ SAL_WARN("writerfilter", "SdtHelper::failed running XPath: " << e.Message);
+ }
+ }
+
+ // Nothing found? Try to iterate storages and eval xpath
+ for (const auto& aSource : m_xPropertiesXMLs)
+ {
+ try
+ {
+ uno::Reference<XXPathObject> xResult
+ = xXpathAPI->eval(aSource.second, m_sDataBindingXPath);
+
+ if (xResult.is() && xResult->getNodeList() && xResult->getNodeList()->getLength()
+ && xResult->getString().getLength())
+ {
+ return xResult->getString();
+ }
+ }
+ catch (const XPathException& e)
+ {
+ // XPath failed? Log and continue with next data document
+ SAL_WARN("writerfilter", "SdtHelper::failed running XPath: " << e.Message);
+ }
+ }
+
+ // No data
+ return {};
+}
+
+void SdtHelper::createDropDownControl()
+{
+ assert(getControlType() == SdtControlType::dropDown
+ || getControlType() == SdtControlType::comboBox);
+
+ const bool bDropDown
+ = officecfg::Office::Writer::Filter::Import::DOCX::ImportComboBoxAsDropDown::get();
+ const OUString aDefaultText = m_aSdtTexts.makeStringAndClear();
+
+ if (bDropDown)
+ {
+ // create field
+ uno::Reference<css::text::XTextField> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.TextField.DropDown"),
+ uno::UNO_QUERY);
+
+ const auto it = std::find_if(
+ m_aDropDownItems.begin(), m_aDropDownItems.end(),
+ [aDefaultText](const OUString& item) -> bool { return !item.compareTo(aDefaultText); });
+
+ if (m_aDropDownItems.end() == it)
+ {
+ m_aDropDownItems.push_back(aDefaultText);
+ }
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("SelectedItem", uno::Any(aDefaultText));
+ xPropertySet->setPropertyValue("Items",
+ uno::Any(comphelper::containerToSequence(m_aDropDownItems)));
+
+ // add it into document
+ m_rDM_Impl.appendTextContent(xControlModel, uno::Sequence<beans::PropertyValue>());
+
+ m_bHasElements = true;
+ }
+ else
+ {
+ // create control
+ uno::Reference<awt::XControlModel> xControlModel(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.form.component.ComboBox"),
+ uno::UNO_QUERY);
+
+ // set properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlModel, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("DefaultText", uno::Any(aDefaultText));
+ xPropertySet->setPropertyValue("Dropdown", uno::Any(true));
+ xPropertySet->setPropertyValue("StringItemList",
+ uno::Any(comphelper::containerToSequence(m_aDropDownItems)));
+
+ // add it into document
+ createControlShape(
+ lcl_getOptimalWidth(m_rDM_Impl.GetStyleSheetTable(), aDefaultText, m_aDropDownItems),
+ xControlModel, uno::Sequence<beans::PropertyValue>());
+ }
+
+ // clean up
+ clear();
+}
+
+void SdtHelper::createPlainTextControl()
+{
+ assert(getControlType() == SdtControlType::plainText);
+
+ if (!m_xFieldStartRange.is())
+ return;
+
+ uno::Reference<text::XTextCursor> xCrsr;
+ uno::Reference<text::XText> xText;
+ if (m_rDM_Impl.HasTopText())
+ {
+ uno::Reference<text::XTextAppend> xTextAppend = m_rDM_Impl.GetTopTextAppend();
+ if (xTextAppend.is())
+ {
+ xText = m_rDM_Impl.GetTopTextAppend()->getEnd()->getText();
+ xCrsr = xText->createTextCursorByRange(m_xFieldStartRange);
+ }
+ }
+ if (!xCrsr.is())
+ return;
+
+ try
+ {
+ bool bIsInTable = (m_rDM_Impl.hasTableManager() && m_rDM_Impl.getTableManager().isInTable())
+ != (0 < m_rDM_Impl.m_StreamStateStack.top().nTableDepth)
+ && m_rDM_Impl.GetIsDummyParaAddedForTableInSection();
+ if (bIsInTable)
+ xCrsr->goRight(1, false);
+ xCrsr->gotoEnd(true);
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper",
+ "Cannot get the right text range for date field");
+ return;
+ }
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ xCrsr->setString(*oData);
+
+ uno::Reference<text::XTextContent> xContentControl(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.ContentControl"),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+
+ for (const beans::PropertyValue& prop : getInteropGrabBagAndClear())
+ {
+ OUString sPropertyName;
+ if (prop.Name == "ooxml:CT_SdtPr_showingPlcHdr")
+ sPropertyName = "ShowingPlaceHolder";
+ else if (prop.Name == "ooxml:CT_SdtPr_alias")
+ sPropertyName = "Alias";
+ else if (prop.Name == "ooxml:CT_SdtPr_tag")
+ sPropertyName = "Tag";
+ else if (prop.Name == "ooxml:CT_SdtPr_id")
+ sPropertyName = "Id";
+ else if (prop.Name == "ooxml:CT_SdtPr_tabIndex")
+ sPropertyName = "TabIndex";
+ else if (prop.Name == "ooxml:CT_SdtPr_lock")
+ sPropertyName = "Lock";
+ else if (prop.Name == "ooxml:CT_SdtPlaceholder_docPart"
+ || prop.Name == "ooxml:CT_SdtPr_dataBinding" || prop.Name == "ooxml:CT_SdtPr_color"
+ || prop.Name == "ooxml:CT_SdtPr_appearance" || prop.Name == "ooxml:CT_SdtPr_text")
+ {
+ uno::Sequence<beans::PropertyValue> aInternalGrabBag;
+ prop.Value >>= aInternalGrabBag;
+ for (const beans::PropertyValue& internalProp : aInternalGrabBag)
+ {
+ if (internalProp.Name == "ooxml:CT_SdtPlaceholder_docPart_val")
+ sPropertyName = "PlaceholderDocPart";
+ else if (internalProp.Name == "ooxml:CT_DataBinding_prefixMappings")
+ sPropertyName = "DataBindingPrefixMappings";
+ else if (internalProp.Name == "ooxml:CT_DataBinding_xpath")
+ sPropertyName = "DataBindingXpath";
+ else if (internalProp.Name == "ooxml:CT_DataBinding_storeItemID")
+ sPropertyName = "DataBindingStoreItemID";
+ else if (internalProp.Name == "ooxml:CT_SdtAppearance_val")
+ sPropertyName = "Appearance";
+ else if (internalProp.Name == "ooxml:CT_SdtColor_val")
+ sPropertyName = "Color";
+ else if (internalProp.Name == "ooxml:CT_SdtText_multiLine")
+ sPropertyName = "MultiLine";
+ if (!sPropertyName.isEmpty())
+ {
+ xContentControlProps->setPropertyValue(sPropertyName, internalProp.Value);
+ }
+ sPropertyName.clear();
+ }
+ }
+
+ if (!sPropertyName.isEmpty())
+ {
+ xContentControlProps->setPropertyValue(sPropertyName, prop.Value);
+ }
+ }
+
+ xContentControlProps->setPropertyValue("PlainText", uno::Any(true));
+
+ xText->insertTextContent(xCrsr, xContentControl, /*bAbsorb=*/true);
+
+ // clean up
+ clear();
+}
+
+void SdtHelper::createDateContentControl()
+{
+ if (!m_xFieldStartRange.is())
+ return;
+
+ uno::Reference<text::XTextCursor> xCrsr;
+ if (m_rDM_Impl.HasTopText())
+ {
+ uno::Reference<text::XTextAppend> xTextAppend = m_rDM_Impl.GetTopTextAppend();
+ if (xTextAppend.is())
+ {
+ xCrsr = xTextAppend->createTextCursorByRange(xTextAppend);
+ }
+ }
+ if (!xCrsr.is())
+ return;
+
+ try
+ {
+ xCrsr->gotoRange(m_xFieldStartRange, false);
+ // tdf#138093: Date selector reset, if placed inside table
+ // Modified to XOR relationship and adding dummy paragraph conditions
+ bool bIsInTable = (m_rDM_Impl.hasTableManager() && m_rDM_Impl.getTableManager().isInTable())
+ != (0 < m_rDM_Impl.m_StreamStateStack.top().nTableDepth)
+ && m_rDM_Impl.GetIsDummyParaAddedForTableInSection();
+ if (bIsInTable)
+ xCrsr->goRight(1, false);
+ xCrsr->gotoEnd(true);
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.dmapper",
+ "Cannot get the right text range for date field");
+ return;
+ }
+
+ uno::Reference<uno::XInterface> xFieldInterface
+ = m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.text.Fieldmark");
+ uno::Reference<text::XFormField> xFormField(xFieldInterface, uno::UNO_QUERY);
+ uno::Reference<text::XTextContent> xToInsert(xFormField, uno::UNO_QUERY);
+ if (!(xFormField.is() && xToInsert.is()))
+ return;
+
+ xToInsert->attach(uno::Reference<text::XTextRange>(xCrsr, uno::UNO_QUERY_THROW));
+ xFormField->setFieldType(ODF_FORMDATE);
+ uno::Reference<container::XNameContainer> xNameCont = xFormField->getParameters();
+ if (xNameCont.is())
+ {
+ OUString sDateFormat = m_sDateFormat.makeStringAndClear();
+
+ // Replace quotation mark used for marking static strings in date format
+ sDateFormat = sDateFormat.replaceAll("'", "\"");
+ xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT, uno::Any(sDateFormat));
+ xNameCont->insertByName(ODF_FORMDATE_DATEFORMAT_LANGUAGE,
+ uno::Any(m_sLocale.makeStringAndClear()));
+ }
+ OUString sFullDate = m_sDate.makeStringAndClear();
+
+ std::optional<OUString> oData = getValueFromDataBinding();
+ if (oData.has_value())
+ sFullDate = *oData;
+
+ if (!sFullDate.isEmpty())
+ {
+ sal_Int32 nTimeSep = sFullDate.indexOf("T");
+ if (nTimeSep != -1)
+ sFullDate = sFullDate.copy(0, nTimeSep);
+ xNameCont->insertByName(ODF_FORMDATE_CURRENTDATE, uno::Any(sFullDate));
+ }
+
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(m_rDM_Impl.GetTextDocument(),
+ uno::UNO_QUERY);
+ uno::Reference<util::XRefreshable> xRefreshable(xTextFieldsSupplier->getTextFields(),
+ uno::UNO_QUERY);
+ xRefreshable->refresh();
+
+ // Store all unused sdt parameters from grabbag
+ xNameCont->insertByName(UNO_NAME_MISC_OBJ_INTEROPGRABBAG,
+ uno::Any(getInteropGrabBagAndClear()));
+
+ clear();
+}
+
+void SdtHelper::createControlShape(awt::Size aSize,
+ uno::Reference<awt::XControlModel> const& xControlModel,
+ const uno::Sequence<beans::PropertyValue>& rGrabBag)
+{
+ uno::Reference<drawing::XControlShape> xControlShape(
+ m_rDM_Impl.GetTextFactory()->createInstance("com.sun.star.drawing.ControlShape"),
+ uno::UNO_QUERY);
+ xControlShape->setSize(aSize);
+ xControlShape->setControl(xControlModel);
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xControlShape, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::CENTER));
+
+ if (rGrabBag.hasElements())
+ xPropertySet->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG, uno::Any(rGrabBag));
+
+ uno::Reference<text::XTextContent> xTextContent(xControlShape, uno::UNO_QUERY);
+ m_rDM_Impl.appendTextContent(xTextContent, uno::Sequence<beans::PropertyValue>());
+ m_bHasElements = true;
+}
+
+void SdtHelper::appendToInteropGrabBag(const beans::PropertyValue& rValue)
+{
+ m_aGrabBag.push_back(rValue);
+}
+
+uno::Sequence<beans::PropertyValue> SdtHelper::getInteropGrabBagAndClear()
+{
+ uno::Sequence<beans::PropertyValue> aRet = comphelper::containerToSequence(m_aGrabBag);
+ m_aGrabBag.clear();
+ return aRet;
+}
+
+bool SdtHelper::isInteropGrabBagEmpty() const { return m_aGrabBag.empty(); }
+
+sal_Int32 SdtHelper::getInteropGrabBagSize() const { return m_aGrabBag.size(); }
+
+bool SdtHelper::containedInInteropGrabBag(const OUString& rValueName)
+{
+ return std::any_of(
+ m_aGrabBag.begin(), m_aGrabBag.end(),
+ [&rValueName](const beans::PropertyValue& i) { return i.Name == rValueName; });
+}
+
+void SdtHelper::SetShowingPlcHdr() { m_bShowingPlcHdr = true; }
+
+bool SdtHelper::GetShowingPlcHdr() const { return m_bShowingPlcHdr; }
+
+void SdtHelper::SetChecked() { m_bChecked = true; }
+
+bool SdtHelper::GetChecked() const { return m_bChecked; }
+
+void SdtHelper::SetCheckedState(const OUString& rCheckedState) { m_aCheckedState = rCheckedState; }
+
+const OUString& SdtHelper::GetCheckedState() const { return m_aCheckedState; }
+
+void SdtHelper::SetUncheckedState(const OUString& rUncheckedState)
+{
+ m_aUncheckedState = rUncheckedState;
+}
+
+const OUString& SdtHelper::GetUncheckedState() const { return m_aUncheckedState; }
+
+void SdtHelper::clear()
+{
+ m_aDropDownItems.clear();
+ m_aDropDownDisplayTexts.clear();
+ setControlType(SdtControlType::unknown);
+ m_nSdtType = 0;
+ m_sDataBindingPrefixMapping.clear();
+ m_sDataBindingXPath.clear();
+ m_sDataBindingStoreItemID.clear();
+ m_aGrabBag.clear();
+ m_bHasUnusedText = false;
+ m_bShowingPlcHdr = false;
+ m_bChecked = false;
+ m_aCheckedState.clear();
+ m_aUncheckedState.clear();
+ m_aPlaceholderDocPart.clear();
+ m_aColor.clear();
+ m_aAlias.clear();
+ m_aTag.clear();
+ m_nId = 0;
+ m_nTabIndex = 0;
+ m_aLock.clear();
+ m_xFieldStartRange.clear();
+}
+
+void SdtHelper::SetPlaceholderDocPart(const OUString& rPlaceholderDocPart)
+{
+ m_aPlaceholderDocPart = rPlaceholderDocPart;
+}
+
+const OUString& SdtHelper::GetPlaceholderDocPart() const { return m_aPlaceholderDocPart; }
+
+void SdtHelper::SetColor(const OUString& rColor) { m_aColor = rColor; }
+
+const OUString& SdtHelper::GetColor() const { return m_aColor; }
+
+void SdtHelper::SetAppearance(const OUString& rAppearance) { m_aAppearance = rAppearance; }
+
+const OUString& SdtHelper::GetAppearance() const { return m_aAppearance; }
+
+void SdtHelper::SetAlias(const OUString& rAlias) { m_aAlias = rAlias; }
+
+const OUString& SdtHelper::GetAlias() const { return m_aAlias; }
+
+void SdtHelper::SetTag(const OUString& rTag) { m_aTag = rTag; }
+
+const OUString& SdtHelper::GetTag() const { return m_aTag; }
+
+void SdtHelper::SetId(sal_Int32 nId) { m_nId = nId; }
+
+sal_Int32 SdtHelper::GetId() const { return m_nId; }
+
+void SdtHelper::SetTabIndex(sal_uInt32 nTabIndex) { m_nTabIndex = nTabIndex; }
+
+sal_uInt32 SdtHelper::GetTabIndex() const { return m_nTabIndex; }
+
+void SdtHelper::SetLock(const OUString& rLock) { m_aLock = rLock; }
+
+const OUString& SdtHelper::GetLock() const { return m_aLock; }
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SdtHelper.hxx b/sw/source/writerfilter/dmapper/SdtHelper.hxx
new file mode 100644
index 000000000000..85b95a48818b
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SdtHelper.hxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vector>
+#include <optional>
+#include <unordered_map>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star
+{
+namespace uno
+{
+class XComponentContext;
+}
+namespace awt
+{
+struct Size;
+class XControlModel;
+}
+}
+
+namespace writerfilter::dmapper
+{
+class DomainMapper_Impl;
+
+enum class SdtControlType
+{
+ datePicker,
+ dropDown,
+ plainText,
+ richText,
+ checkBox,
+ picture,
+ comboBox,
+ unsupported, // Sdt block is defined, but we still do not support such type of field
+ unknown
+};
+
+/**
+ * Helper to create form controls from w:sdt tokens.
+ *
+ * w:sdt tokens can't be imported as form fields, as w:sdt supports
+ * e.g. date picking as well.
+ */
+class SdtHelper final : public virtual SvRefBase
+{
+ DomainMapper_Impl& m_rDM_Impl;
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+
+ /// Items of the drop-down control: <w:listItem w:value="...">.
+ std::vector<OUString> m_aDropDownItems;
+ /// Display texts of a drop-down control: <w:listItem w:displayText="...">.
+ std::vector<OUString> m_aDropDownDisplayTexts;
+ /// Type of sdt control
+ SdtControlType m_aControlType;
+ sal_uInt32 m_nSdtType = 0;
+ /// Pieces of the default text -- currently used only by the dropdown control.
+ OUStringBuffer m_aSdtTexts;
+ /// Date ISO string contained in the w:date element, used by the date control.
+ OUStringBuffer m_sDate;
+ /// Date format string as it comes from the ooxml document.
+ OUStringBuffer m_sDateFormat;
+
+ /// <w:dataBinding w:prefixMappings="">
+ OUString m_sDataBindingPrefixMapping;
+ /// <w:dataBinding w:xpath="">
+ OUString m_sDataBindingXPath;
+ /// <w:dataBinding w:storeItemID="">
+ OUString m_sDataBindingStoreItemID;
+
+ /// Start range of the date or plain text field
+ css::uno::Reference<css::text::XTextRange> m_xFieldStartRange;
+ /// 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;
+ /// Has inserted texts for plain text control
+ bool m_bHasUnusedText;
+
+ bool m_bHasElements;
+ /// The last stored SDT element is outside paragraphs.
+ bool m_bOutsideAParagraph;
+
+ /// Storage for all properties documents as xml::dom::XDocument for later querying xpath for data
+ std::unordered_map<OUString, css::uno::Reference<css::xml::dom::XDocument>> m_xPropertiesXMLs;
+
+ /// Check if m_xPropertiesXMLs is initialized and loaded (need extra flag to distinguish
+ /// empty sequence from not yet initialized)
+ bool m_bPropertiesXMLsLoaded;
+
+ /// Current contents are placeholder text.
+ bool m_bShowingPlcHdr = false;
+
+ /// If this is a checkbox, is the checkbox checked?
+ bool m_bChecked = false;
+
+ /// If this is a checkbox, the value of a checked checkbox.
+ OUString m_aCheckedState;
+
+ /// If this is a checkbox, the value of an unchecked checkbox.
+ OUString m_aUncheckedState;
+
+ /// Create and append the drawing::XControlShape, containing the various models.
+ void createControlShape(css::awt::Size aSize,
+ css::uno::Reference<css::awt::XControlModel> const& xControlModel,
+ const css::uno::Sequence<css::beans::PropertyValue>& rGrabBag);
+
+ void loadPropertiesXMLs();
+
+ /// <w:placeholder>'s <w:docPart w:val="...">.
+ OUString m_aPlaceholderDocPart;
+
+ /// <w:sdtPr>'s <w15:color w:val="...">.
+ OUString m_aColor;
+
+ /// <w:sdtPr>'s <w15:appearance w:val="...">.
+ OUString m_aAppearance;
+
+ /// <w:sdtPr>'s <w:alias w:val="...">.
+ OUString m_aAlias;
+
+ /// <w:sdtPr>'s <w:tag w:val="...">.
+ OUString m_aTag;
+
+ /// <w:sdtPr>'s <w:id w:val="...">.
+ sal_Int32 m_nId = 0;
+
+ /// <w:sdtPr>'s <w:tabIndex w:val="...">.
+ sal_uInt32 m_nTabIndex = 0;
+
+ /// <w:sdtPr>'s <w:lock w:val="...">.
+ OUString m_aLock;
+
+public:
+ explicit SdtHelper(DomainMapper_Impl& rDM_Impl,
+ css::uno::Reference<css::uno::XComponentContext> xContext);
+ ~SdtHelper() override;
+
+ std::vector<OUString>& getDropDownItems() { return m_aDropDownItems; }
+ std::vector<OUString>& getDropDownDisplayTexts() { return m_aDropDownDisplayTexts; }
+ OUStringBuffer& getSdtTexts() { return m_aSdtTexts; }
+
+ OUStringBuffer& getDate() { return m_sDate; }
+
+ OUStringBuffer& getDateFormat() { return m_sDateFormat; }
+
+ void setDataBindingPrefixMapping(const OUString& sValue)
+ {
+ m_sDataBindingPrefixMapping = sValue;
+ }
+ const OUString& GetDataBindingPrefixMapping() const { return m_sDataBindingPrefixMapping; }
+
+ void setDataBindingXPath(const OUString& sValue) { m_sDataBindingXPath = sValue; }
+ const OUString& GetDataBindingXPath() const { return m_sDataBindingXPath; }
+
+ void setDataBindingStoreItemID(const OUString& sValue) { m_sDataBindingStoreItemID = sValue; }
+ const OUString& GetDataBindingStoreItemID() const { return m_sDataBindingStoreItemID; }
+
+ bool isFieldStartRangeSet() const { return m_xFieldStartRange.is(); }
+ void setFieldStartRange(const css::uno::Reference<css::text::XTextRange>& xStartRange)
+ {
+ m_xFieldStartRange = xStartRange;
+ }
+
+ OUStringBuffer& getLocale() { return m_sLocale; }
+ /// If createControlShape() was ever called.
+ bool hasElements() const { return m_bHasElements; }
+
+ void setOutsideAParagraph(bool bOutsideAParagraph)
+ {
+ m_bOutsideAParagraph = bOutsideAParagraph;
+ }
+
+ bool isOutsideAParagraph() const { return m_bOutsideAParagraph; }
+
+ SdtControlType getControlType() { return m_aControlType; }
+ void setControlType(SdtControlType aType) { m_aControlType = aType; }
+
+ void SetSdtType(sal_uInt32 nSdtType) { m_nSdtType = nSdtType; }
+ sal_uInt32 GetSdtType() const { return m_nSdtType; }
+
+ /// Create drop-down control from w:sdt's w:dropDownList.
+ void createDropDownControl();
+ /// Create date control from w:sdt's w:date.
+ void createDateContentControl();
+
+ void createPlainTextControl();
+
+ void appendToInteropGrabBag(const css::beans::PropertyValue& rValue);
+ css::uno::Sequence<css::beans::PropertyValue> getInteropGrabBagAndClear();
+ bool isInteropGrabBagEmpty() const;
+ bool containedInInteropGrabBag(const OUString& rValueName);
+ sal_Int32 getInteropGrabBagSize() const;
+
+ void setHasUnusedText(bool bHasUnusedText) { m_bHasUnusedText = bHasUnusedText; }
+ bool hasUnusedText() const { return m_bHasUnusedText; }
+
+ void SetShowingPlcHdr();
+ bool GetShowingPlcHdr() const;
+
+ void SetChecked();
+ bool GetChecked() const;
+ void SetCheckedState(const OUString& rCheckedState);
+ const OUString& GetCheckedState() const;
+ void SetUncheckedState(const OUString& rUncheckedState);
+ const OUString& GetUncheckedState() const;
+
+ /// Clear all collected attributes for further reuse
+ void clear();
+
+ void SetPlaceholderDocPart(const OUString& rPlaceholderDocPart);
+ const OUString& GetPlaceholderDocPart() const;
+
+ void SetColor(const OUString& rColor);
+ const OUString& GetColor() const;
+
+ void SetAppearance(const OUString& rAppearance);
+ const OUString& GetAppearance() const;
+
+ void SetAlias(const OUString& rAlias);
+ const OUString& GetAlias() const;
+
+ void SetTag(const OUString& rTag);
+ const OUString& GetTag() const;
+
+ void SetId(sal_Int32 nId);
+ sal_Int32 GetId() const;
+
+ void SetTabIndex(sal_uInt32 nTabIndex);
+ sal_uInt32 GetTabIndex() const;
+
+ void SetLock(const OUString& rLock);
+ const OUString& GetLock() const;
+
+ std::optional<OUString> getValueFromDataBinding();
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SectionColumnHandler.cxx b/sw/source/writerfilter/dmapper/SectionColumnHandler.cxx
new file mode 100644
index 000000000000..9fed9c34a68e
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SectionColumnHandler.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "SectionColumnHandler.hxx"
+#include "ConversionHelper.hxx"
+#include <ooxml/resourceids.hxx>
+#include <osl/diagnose.h>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+SectionColumnHandler::SectionColumnHandler()
+ : LoggedProperties("SectionColumnHandler")
+ , m_bEqualWidth(false)
+ , m_nSpace(1270) // 720 twips
+ , m_nNum(0)
+ , m_bSep(false)
+{
+ m_aTempColumn.nWidth = m_aTempColumn.nSpace = 0;
+}
+
+SectionColumnHandler::~SectionColumnHandler() {}
+
+void SectionColumnHandler::lcl_attribute(Id rName, Value& rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch (rName)
+ {
+ case NS_ooxml::LN_CT_Columns_equalWidth:
+ m_bEqualWidth = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_Columns_space:
+ m_nSpace = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Columns_num:
+ m_nNum = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Columns_sep:
+ m_bSep = (nIntValue != 0);
+ break;
+
+ case NS_ooxml::LN_CT_Column_w:
+ m_aTempColumn.nWidth = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Column_space:
+ m_aTempColumn.nSpace = ConversionHelper::convertTwipToMM100(nIntValue);
+ break;
+ default:
+ OSL_FAIL("SectionColumnHandler: unknown attribute");
+ }
+}
+
+void SectionColumnHandler::lcl_sprm(Sprm& rSprm)
+{
+ switch (rSprm.getId())
+ {
+ case NS_ooxml::LN_CT_Columns_col:
+ {
+ m_aTempColumn.nWidth = m_aTempColumn.nSpace = 0;
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ m_aCols.push_back(m_aTempColumn);
+ }
+ }
+ break;
+ default:
+ OSL_FAIL("SectionColumnHandler: unknown sprm");
+ }
+}
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SectionColumnHandler.hxx b/sw/source/writerfilter/dmapper/SectionColumnHandler.hxx
new file mode 100644
index 000000000000..cbef67460ed7
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SectionColumnHandler.hxx
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+
+namespace writerfilter::dmapper
+{
+struct Column_
+{
+ sal_Int32 nWidth;
+ sal_Int32 nSpace;
+};
+
+
+class SectionColumnHandler : public LoggedProperties
+{
+ bool m_bEqualWidth;
+ sal_Int32 m_nSpace;
+ sal_Int32 m_nNum;
+ bool m_bSep;
+ std::vector<Column_> m_aCols;
+
+ Column_ m_aTempColumn;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ SectionColumnHandler();
+ virtual ~SectionColumnHandler() override;
+
+ bool IsEqualWidth() const { return m_bEqualWidth; }
+ sal_Int32 GetSpace() const { return m_nSpace; }
+ sal_Int32 GetNum() const { return m_nNum; }
+ bool IsSeparator() const { return m_bSep; }
+
+ const std::vector<Column_>& GetColumns() const { return m_aCols;}
+
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SettingsTable.cxx b/sw/source/writerfilter/dmapper/SettingsTable.cxx
new file mode 100644
index 000000000000..a665a01c7209
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SettingsTable.cxx
@@ -0,0 +1,800 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "SettingsTable.hxx"
+#include "DocumentProtection.hxx"
+#include "TagLogger.hxx"
+#include "WriteProtection.hxx"
+
+#include <vector>
+
+#include <rtl/ustring.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <com/sun/star/text/ParagraphHyphenationKeepType.hpp>
+#include <com/sun/star/text/XDependentTextField.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <ooxml/OOXMLPropertySet.hxx>
+#include "ConversionHelper.hxx"
+#include "DomainMapper.hxx"
+#include "util.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter {
+namespace
+{
+/// Maps OOXML <w:zoom w:val="..."> to SvxZoomType.
+sal_Int16 lcl_GetZoomType(Id nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_Value_doc_ST_Zoom_fullPage:
+ return sal_Int16(SvxZoomType::WHOLEPAGE);
+ case NS_ooxml::LN_Value_doc_ST_Zoom_bestFit:
+ return sal_Int16(SvxZoomType::PAGEWIDTH);
+ case NS_ooxml::LN_Value_doc_ST_Zoom_textFit:
+ return sal_Int16(SvxZoomType::OPTIMAL);
+ }
+
+ return sal_Int16(SvxZoomType::PERCENT);
+}
+}
+
+namespace dmapper
+{
+
+struct SettingsTable_Impl
+{
+ int m_nDefaultTabStop;
+
+ bool m_bRecordChanges;
+ bool m_bShowInsDelChanges;
+ bool m_bShowFormattingChanges;
+ bool m_bShowMarkupChanges;
+ bool m_bLinkStyles;
+ sal_Int16 m_nZoomFactor;
+ sal_Int16 m_nZoomType = 0;
+ sal_Int32 m_nWordCompatibilityMode;
+ Id m_nView;
+ bool m_bEvenAndOddHeaders;
+ bool m_bUsePrinterMetrics;
+ bool embedTrueTypeFonts;
+ bool embedSystemFonts;
+ bool m_bDoNotUseHTMLParagraphAutoSpacing;
+ bool m_bNoColumnBalance;
+ bool m_bAutoHyphenation;
+ bool m_bNoHyphenateCaps;
+ sal_Int16 m_nHyphenationZone;
+ bool m_bWidowControl;
+ bool m_bLongerSpaceSequence;
+ bool m_bSplitPgBreakAndParaMark;
+ bool m_bMirrorMargin;
+ bool m_bDoNotExpandShiftReturn;
+ bool m_bDisplayBackgroundShape;
+ bool m_bNoLeading = false;
+ OUString m_sDecimalSymbol;
+ OUString m_sListSeparator;
+ std::vector<std::pair<OUString, OUString>> m_aDocVars;
+
+ uno::Sequence<beans::PropertyValue> m_pThemeFontLangProps;
+
+ std::vector<beans::PropertyValue> m_aCompatSettings;
+ uno::Sequence<beans::PropertyValue> m_pCurrentCompatSetting;
+ OUString m_aCurrentCompatSettingName;
+ OUString m_aCurrentCompatSettingUri;
+ OUString m_aCurrentCompatSettingValue;
+ OUString m_sCurrentDatabaseDataSource;
+
+ std::shared_ptr<DocumentProtection> m_pDocumentProtection;
+ std::shared_ptr<WriteProtection> m_pWriteProtection;
+ bool m_bGutterAtTop = false;
+ bool m_bDoNotBreakWrappedTables = false;
+ bool m_bAllowTextAfterFloatingTableBreak = false;
+
+ SettingsTable_Impl() :
+ m_nDefaultTabStop( 720 ) //default is 1/2 in
+ , m_bRecordChanges(false)
+ , m_bShowInsDelChanges(true)
+ , m_bShowFormattingChanges(false)
+ , m_bShowMarkupChanges(true)
+ , m_bLinkStyles(false)
+ , m_nZoomFactor(0)
+ , m_nWordCompatibilityMode(-1)
+ , m_nView(0)
+ , m_bEvenAndOddHeaders(false)
+ , m_bUsePrinterMetrics(false)
+ , embedTrueTypeFonts(false)
+ , embedSystemFonts(false)
+ , m_bDoNotUseHTMLParagraphAutoSpacing(false)
+ , m_bNoColumnBalance(false)
+ , m_bAutoHyphenation(false)
+ , m_bNoHyphenateCaps(false)
+ , m_nHyphenationZone(0)
+ , m_bWidowControl(false)
+ , m_bLongerSpaceSequence(false)
+ , m_bSplitPgBreakAndParaMark(false)
+ , m_bMirrorMargin(false)
+ , m_bDoNotExpandShiftReturn(false)
+ , m_bDisplayBackgroundShape(false)
+ , m_sDecimalSymbol(".")
+ , m_sListSeparator(",")
+ , m_pThemeFontLangProps(3)
+ , m_pCurrentCompatSetting(3)
+ {}
+};
+
+SettingsTable::SettingsTable(const DomainMapper& rDomainMapper)
+: LoggedProperties("SettingsTable")
+, LoggedTable("SettingsTable")
+, m_pImpl( new SettingsTable_Impl )
+{
+ if (rDomainMapper.IsRTFImport())
+ {
+ // HTML paragraph auto-spacing is opt-in for RTF, opt-out for OOXML.
+ m_pImpl->m_bDoNotUseHTMLParagraphAutoSpacing = true;
+ // Longer space sequence is opt-in for RTF, and not in OOXML.
+ m_pImpl->m_bLongerSpaceSequence = true;
+ m_pImpl->m_bDoNotBreakWrappedTables = true;
+ }
+ m_pImpl->m_pDocumentProtection = std::make_shared<DocumentProtection>();
+ m_pImpl->m_pWriteProtection = std::make_shared<WriteProtection>();
+}
+
+SettingsTable::~SettingsTable()
+{
+}
+
+void SettingsTable::lcl_attribute(Id nName, Value & val)
+{
+ int nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ switch(nName)
+ {
+ case NS_ooxml::LN_CT_Zoom_percent:
+ m_pImpl->m_nZoomFactor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Zoom_val:
+ m_pImpl->m_nZoomType = lcl_GetZoomType(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Language_val:
+ m_pImpl->m_pThemeFontLangProps.getArray()[0]
+ = comphelper::makePropertyValue("val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Language_eastAsia:
+ m_pImpl->m_pThemeFontLangProps.getArray()[1]
+ = comphelper::makePropertyValue("eastAsia", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_Language_bidi:
+ m_pImpl->m_pThemeFontLangProps.getArray()[2]
+ = comphelper::makePropertyValue("bidi", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_View_val:
+ m_pImpl->m_nView = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_DocVar_name:
+ m_pImpl->m_aDocVars.back().first = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_DocVar_val:
+ m_pImpl->m_aDocVars.back().second = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_CompatSetting_name:
+ m_pImpl->m_aCurrentCompatSettingName = sStringValue;
+ m_pImpl->m_pCurrentCompatSetting.getArray()[0]
+ = comphelper::makePropertyValue("name", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_CompatSetting_uri:
+ m_pImpl->m_aCurrentCompatSettingUri = sStringValue;
+ m_pImpl->m_pCurrentCompatSetting.getArray()[1]
+ = comphelper::makePropertyValue("uri", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_CompatSetting_val:
+ m_pImpl->m_aCurrentCompatSettingValue = sStringValue;
+ m_pImpl->m_pCurrentCompatSetting.getArray()[2]
+ = comphelper::makePropertyValue("val", sStringValue);
+ break;
+ case NS_ooxml::LN_CT_TrackChangesView_insDel:
+ m_pImpl->m_bShowInsDelChanges = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_TrackChangesView_formatting:
+ m_pImpl->m_bShowFormattingChanges = (nIntValue != 0);
+ break;
+ case NS_ooxml::LN_CT_TrackChangesView_markup:
+ m_pImpl->m_bShowMarkupChanges = (nIntValue != 0);
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void SettingsTable::lcl_sprm(Sprm& rSprm)
+{
+ sal_uInt32 nSprmId = rSprm.getId();
+
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = pValue->getInt();
+
+ switch(nSprmId)
+ {
+ case NS_ooxml::LN_CT_Settings_zoom: // 92469;
+ case NS_ooxml::LN_CT_Settings_proofState: // 92489;
+ case NS_ooxml::LN_CT_Settings_attachedTemplate: // 92491;
+ case NS_ooxml::LN_CT_Settings_hdrShapeDefaults: // 92544;
+ case NS_ooxml::LN_CT_Settings_footnotePr: // 92545;
+ case NS_ooxml::LN_CT_Settings_endnotePr: // 92546;
+ case NS_ooxml::LN_CT_Settings_compat: // 92547;
+ case NS_ooxml::LN_CT_Settings_themeFontLang: // 92552;
+ case NS_ooxml::LN_CT_Settings_shapeDefaults: // 92560;
+ case NS_ooxml::LN_CT_Settings_view:
+ //PropertySetValues - need to be resolved
+ {
+ resolveSprmProps(*this, rSprm);
+ }
+ break;
+ case NS_ooxml::LN_CT_Settings_stylePaneFormatFilter: // 92493;
+ break;
+ case NS_ooxml::LN_CT_Settings_defaultTabStop: // 92505;
+ m_pImpl->m_nDefaultTabStop = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_linkStyles: // 92663;
+ m_pImpl->m_bLinkStyles = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_evenAndOddHeaders:
+ m_pImpl->m_bEvenAndOddHeaders = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_noPunctuationKerning: // 92526;
+ break;
+ case NS_ooxml::LN_CT_Settings_characterSpacingControl: // 92527;
+ // doNotCompress, compressPunctuation, compressPunctuationAndJapaneseKana
+ break;
+ case NS_ooxml::LN_CT_Settings_doNotIncludeSubdocsInStats: // 92554; // Do Not Include Content in Text Boxes, Footnotes, and Endnotes in Document Statistics)
+ break;
+ case NS_ooxml::LN_CT_Settings_decimalSymbol: // 92562;
+ m_pImpl->m_sDecimalSymbol = pValue->getString();
+ break;
+ case NS_ooxml::LN_CT_Settings_listSeparator: // 92563;
+ m_pImpl->m_sListSeparator = pValue->getString();
+ break;
+ case NS_ooxml::LN_CT_Settings_rsids: // 92549; revision save Ids - probably not necessary
+ break;
+ case NS_ooxml::LN_CT_Settings_hyphenationZone: // 92508;
+ m_pImpl->m_nHyphenationZone = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_useFELayout: // 92422;
+ // useFELayout (Do Not Bypass East Asian/Complex Script Layout Code - support of old versions of Word - ignored)
+ break;
+ case NS_ooxml::LN_CT_Settings_trackRevisions:
+ {
+ m_pImpl->m_bRecordChanges = bool(rSprm.getValue( )->getInt( ) );
+ }
+ break;
+ case NS_ooxml::LN_CT_Settings_revisionView:
+ resolveSprmProps(*this, rSprm);
+ break;
+ case NS_ooxml::LN_CT_Settings_documentProtection:
+ resolveSprmProps(*(m_pImpl->m_pDocumentProtection), rSprm);
+ break;
+ case NS_ooxml::LN_CT_Settings_writeProtection:
+ resolveSprmProps(*(m_pImpl->m_pWriteProtection), rSprm);
+ break;
+ case NS_ooxml::LN_CT_Compat_usePrinterMetrics:
+ m_pImpl->m_bUsePrinterMetrics = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_embedTrueTypeFonts:
+ m_pImpl->embedTrueTypeFonts = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Settings_embedSystemFonts:
+ m_pImpl->embedSystemFonts = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Compat_doNotUseHTMLParagraphAutoSpacing:
+ m_pImpl->m_bDoNotUseHTMLParagraphAutoSpacing = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_splitPgBreakAndParaMark:
+ m_pImpl->m_bSplitPgBreakAndParaMark = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_mirrorMargins:
+ m_pImpl->m_bMirrorMargin = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_mailMerge:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ }
+ break;
+ case NS_ooxml::LN_CT_MailMerge_query:
+ {
+ // try to get the "database.table" name from the query saved previously
+ OUString sVal = pValue->getString();
+ if ( sVal.endsWith("$") && sVal.indexOf(".dbo.") > 0 )
+ {
+ sal_Int32 nSpace = sVal.lastIndexOf(' ');
+ sal_Int32 nDbo = sVal.lastIndexOf(".dbo.");
+ if ( nSpace > 0 && nSpace < nDbo - 1 )
+ {
+ m_pImpl->m_sCurrentDatabaseDataSource = OUString::Concat(sVal.subView(nSpace + 1, nDbo - nSpace - 1)) +
+ sVal.subView(nDbo + 4, sVal.getLength() - nDbo - 5);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Compat_compatSetting:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+
+ beans::PropertyValue aValue;
+ aValue.Name = "compatSetting";
+ aValue.Value <<= m_pImpl->m_pCurrentCompatSetting;
+ m_pImpl->m_aCompatSettings.push_back(aValue);
+
+ OString aCompatSettingValue = rtl::OUStringToOString(
+ m_pImpl->m_aCurrentCompatSettingValue, RTL_TEXTENCODING_UTF8);
+ if (m_pImpl->m_aCurrentCompatSettingName == "allowTextAfterFloatingTableBreak"
+ && m_pImpl->m_aCurrentCompatSettingUri == "http://schemas.microsoft.com/office/word"
+ && ooxml::GetBooleanValue(aCompatSettingValue))
+ {
+ m_pImpl->m_bAllowTextAfterFloatingTableBreak = true;
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Settings_docVars:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_DocVar:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ m_pImpl->m_aDocVars.push_back(std::make_pair(OUString(), OUString()));
+ pProperties->resolve(*this);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Compat_noColumnBalance:
+ m_pImpl->m_bNoColumnBalance = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_autoHyphenation:
+ m_pImpl->m_bAutoHyphenation = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_doNotHyphenateCaps:
+ m_pImpl->m_bNoHyphenateCaps = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_widowControl:
+ m_pImpl->m_bWidowControl = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Settings_longerSpaceSequence:
+ m_pImpl->m_bLongerSpaceSequence = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_doNotExpandShiftReturn:
+ m_pImpl->m_bDoNotExpandShiftReturn = true;
+ break;
+ case NS_ooxml::LN_CT_Settings_displayBackgroundShape:
+ m_pImpl->m_bDisplayBackgroundShape = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Compat_noLeading:
+ m_pImpl->m_bNoLeading = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Settings_gutterAtTop:
+ m_pImpl->m_bGutterAtTop = nIntValue != 0;
+ break;
+ case NS_ooxml::LN_CT_Compat_doNotBreakWrappedTables:
+ m_pImpl->m_bDoNotBreakWrappedTables = nIntValue != 0;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void SettingsTable::lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref)
+{
+ ref->resolve(*this);
+}
+
+//returns default TabStop in 1/100th mm
+int SettingsTable::GetDefaultTabStop() const
+{
+ return ConversionHelper::convertTwipToMM100( m_pImpl->m_nDefaultTabStop );
+}
+
+bool SettingsTable::GetLinkStyles() const
+{
+ return m_pImpl->m_bLinkStyles;
+}
+
+sal_Int16 SettingsTable::GetZoomFactor() const
+{
+ return m_pImpl->m_nZoomFactor;
+}
+
+sal_Int16 SettingsTable::GetZoomType() const { return m_pImpl->m_nZoomType; }
+
+Id SettingsTable::GetView() const
+{
+ return m_pImpl->m_nView;
+}
+
+bool SettingsTable::GetUsePrinterMetrics() const
+{
+ return m_pImpl->m_bUsePrinterMetrics;
+}
+
+bool SettingsTable::GetEvenAndOddHeaders() const
+{
+ return m_pImpl->m_bEvenAndOddHeaders;
+}
+
+bool SettingsTable::GetEmbedTrueTypeFonts() const
+{
+ return m_pImpl->embedTrueTypeFonts;
+}
+
+bool SettingsTable::GetEmbedSystemFonts() const
+{
+ return m_pImpl->embedSystemFonts;
+}
+
+bool SettingsTable::GetDoNotUseHTMLParagraphAutoSpacing() const
+{
+ return m_pImpl->m_bDoNotUseHTMLParagraphAutoSpacing;
+}
+
+bool SettingsTable::GetNoColumnBalance() const
+{
+ return m_pImpl->m_bNoColumnBalance;
+}
+
+bool SettingsTable::GetSplitPgBreakAndParaMark() const
+{
+ return m_pImpl->m_bSplitPgBreakAndParaMark;
+}
+
+bool SettingsTable::GetMirrorMarginSettings() const
+{
+ return m_pImpl->m_bMirrorMargin;
+}
+
+bool SettingsTable::GetDisplayBackgroundShape() const
+{
+ return m_pImpl->m_bDisplayBackgroundShape;
+}
+
+bool SettingsTable::GetDoNotExpandShiftReturn() const
+{
+ return m_pImpl->m_bDoNotExpandShiftReturn;
+}
+
+bool SettingsTable::GetProtectForm() const
+{
+ return m_pImpl->m_pDocumentProtection->getProtectForm()
+ && m_pImpl->m_pDocumentProtection->getEnforcement();
+}
+
+bool SettingsTable::GetReadOnly() const
+{
+ return m_pImpl->m_pWriteProtection->getRecommended()
+ || (m_pImpl->m_pDocumentProtection->getReadOnly()
+ && m_pImpl->m_pDocumentProtection->getEnforcement());
+}
+
+bool SettingsTable::GetNoHyphenateCaps() const
+{
+ return m_pImpl->m_bNoHyphenateCaps;
+}
+
+sal_Int16 SettingsTable::GetHyphenationZone() const
+{
+ return m_pImpl->m_nHyphenationZone;
+}
+
+const OUString & SettingsTable::GetDecimalSymbol() const
+{
+ return m_pImpl->m_sDecimalSymbol;
+}
+
+const OUString & SettingsTable::GetListSeparator() const
+{
+ return m_pImpl->m_sListSeparator;
+}
+
+
+uno::Sequence<beans::PropertyValue> const & SettingsTable::GetThemeFontLangProperties() const
+{
+ return m_pImpl->m_pThemeFontLangProps;
+}
+
+uno::Sequence<beans::PropertyValue> SettingsTable::GetCompatSettings() const
+{
+ if ( GetWordCompatibilityMode() == -1 )
+ {
+ // the default value for an undefined compatibilityMode is 12 (Word 2007)
+ uno::Sequence<beans::PropertyValue> aCompatSetting( comphelper::InitPropertySequence({
+ { "name", uno::Any(OUString("compatibilityMode")) },
+ { "uri", uno::Any(OUString("http://schemas.microsoft.com/office/word")) },
+ { "val", uno::Any(OUString("12")) } //12: Use word processing features specified in ECMA-376. This is the default.
+ }));
+
+ beans::PropertyValue aValue;
+ aValue.Name = "compatSetting";
+ aValue.Value <<= aCompatSetting;
+
+ m_pImpl->m_aCompatSettings.push_back(aValue);
+ }
+
+ return comphelper::containerToSequence(m_pImpl->m_aCompatSettings);
+}
+
+uno::Sequence<beans::PropertyValue> SettingsTable::GetDocumentProtectionSettings() const
+{
+ return m_pImpl->m_pDocumentProtection->toSequence();
+}
+
+uno::Sequence<beans::PropertyValue> SettingsTable::GetWriteProtectionSettings() const
+{
+ return m_pImpl->m_pWriteProtection->toSequence();
+}
+
+const OUString & SettingsTable::GetCurrentDatabaseDataSource() const
+{
+ return m_pImpl->m_sCurrentDatabaseDataSource;
+}
+
+static bool lcl_isDefault(const uno::Reference<beans::XPropertyState>& xPropertyState, const OUString& rPropertyName)
+{
+ return xPropertyState->getPropertyState(rPropertyName) == beans::PropertyState_DEFAULT_VALUE;
+}
+
+void SettingsTable::ApplyProperties(uno::Reference<text::XTextDocument> const& xDoc)
+{
+ uno::Reference< beans::XPropertySet> xDocProps( xDoc, uno::UNO_QUERY );
+ uno::Reference<lang::XMultiServiceFactory> xTextFactory(xDoc, uno::UNO_QUERY_THROW);
+ uno::Reference<beans::XPropertySet> xDocumentSettings(xTextFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW);
+
+ // Shared between DOCX and RTF, unconditional flags.
+ xDocumentSettings->setPropertyValue("TableRowKeep", uno::Any(true));
+ xDocumentSettings->setPropertyValue("AddVerticalFrameOffsets", uno::Any(true));
+
+ if (GetWordCompatibilityMode() <= 14)
+ {
+ xDocumentSettings->setPropertyValue("MsWordCompMinLineHeightByFly", uno::Any(true));
+ xDocumentSettings->setPropertyValue("TabOverMargin", uno::Any(true));
+ }
+
+ // Show changes value
+ if (xDocProps.is())
+ {
+ bool bHideChanges = !m_pImpl->m_bShowInsDelChanges || !m_pImpl->m_bShowMarkupChanges;
+ xDocProps->setPropertyValue("ShowChanges", uno::Any( !bHideChanges || m_pImpl->m_bShowFormattingChanges ) );
+ }
+
+ // Record changes value
+ if (xDocProps.is())
+ {
+ xDocProps->setPropertyValue("RecordChanges", uno::Any( m_pImpl->m_bRecordChanges ) );
+ // Password protected Record changes
+ if (m_pImpl->m_bRecordChanges && m_pImpl->m_pDocumentProtection->getRedlineProtection()
+ && m_pImpl->m_pDocumentProtection->getEnforcement())
+ {
+ // use dummy protection key to forbid disabling of Record changes without a notice
+ // (extending the recent GrabBag support) TODO support password verification...
+ css::uno::Sequence<sal_Int8> aDummyKey { 1 };
+ xDocProps->setPropertyValue("RedlineProtectionKey", uno::Any( aDummyKey ));
+ }
+ }
+
+ // Create or overwrite DocVars based on found in settings
+ if (m_pImpl->m_aDocVars.size())
+ {
+ uno::Reference< text::XTextFieldsSupplier > xFieldsSupplier(xDoc, uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xFieldMasterAccess = xFieldsSupplier->getTextFieldMasters();
+ for (const auto& docVar : m_pImpl->m_aDocVars)
+ {
+ uno::Reference< beans::XPropertySet > xMaster;
+ OUString sFieldMasterService("com.sun.star.text.FieldMaster.User." + docVar.first);
+
+ // Find or create Field Master
+ if (xFieldMasterAccess->hasByName(sFieldMasterService))
+ {
+ xMaster.set(xFieldMasterAccess->getByName(sFieldMasterService), uno::UNO_QUERY_THROW);
+ }
+ else
+ {
+ xMaster.set(xTextFactory->createInstance("com.sun.star.text.FieldMaster.User"), uno::UNO_QUERY_THROW);
+ xMaster->setPropertyValue(getPropertyName(PROP_NAME), uno::Any(docVar.first));
+ uno::Reference<text::XDependentTextField> xField(
+ xTextFactory->createInstance("com.sun.star.text.TextField.User"),
+ uno::UNO_QUERY);
+ xField->attachTextFieldMaster(xMaster);
+ }
+
+ xMaster->setPropertyValue(getPropertyName(PROP_CONTENT), uno::Any(docVar.second));
+ }
+ }
+
+ if (m_pImpl->m_bDoNotBreakWrappedTables)
+ {
+ // Map <w:doNotBreakWrappedTables> to the DoNotBreakWrappedTables compat flag.
+ xDocumentSettings->setPropertyValue("DoNotBreakWrappedTables", uno::Any(true));
+ }
+
+ if (m_pImpl->m_bAllowTextAfterFloatingTableBreak)
+ {
+ xDocumentSettings->setPropertyValue("AllowTextAfterFloatingTableBreak", uno::Any(true));
+ }
+
+ // Auto hyphenation: turns on hyphenation by default, <w:suppressAutoHyphens/> may still disable it at a paragraph level.
+ // Situation is similar for RTF_WIDOWCTRL, which turns on widow / orphan control by default.
+ if (!(m_pImpl->m_bAutoHyphenation || m_pImpl->m_bNoHyphenateCaps || m_pImpl->m_bWidowControl))
+ return;
+
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xDoc, uno::UNO_QUERY);
+ if (!xStyleFamiliesSupplier.is())
+ return;
+
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xParagraphStyles = xStyleFamilies->getByName("ParagraphStyles").get< uno::Reference<container::XNameContainer> >();
+ uno::Reference<style::XStyle> xDefault = xParagraphStyles->getByName("Standard").get< uno::Reference<style::XStyle> >();
+ uno::Reference<beans::XPropertyState> xPropertyState(xDefault, uno::UNO_QUERY);
+ if (m_pImpl->m_bAutoHyphenation && lcl_isDefault(xPropertyState, "ParaIsHyphenation"))
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaIsHyphenation", uno::Any(true));
+ }
+ if (m_pImpl->m_bNoHyphenateCaps)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaHyphenationNoCaps", uno::Any(true));
+ }
+ if (m_pImpl->m_nHyphenationZone)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaHyphenationZone", uno::Any(GetHyphenationZone()));
+ }
+ if (m_pImpl->m_bWidowControl && lcl_isDefault(xPropertyState, "ParaWidows") && lcl_isDefault(xPropertyState, "ParaOrphans"))
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ uno::Any aAny(static_cast<sal_Int8>(2));
+ xPropertySet->setPropertyValue("ParaWidows", aAny);
+ xPropertySet->setPropertyValue("ParaOrphans", aAny);
+ }
+
+ std::pair<bool, bool> aAllow = GetCompatSettingHasAndValue(u"allowHyphenationAtTrackBottom");
+ std::pair<bool, bool> aUse = GetCompatSettingHasAndValue(u"useWord2013TrackBottomHyphenation");
+ // if allowHyphenationAtTrackBottom is not true and useWord2013TrackBottomHyphenation is
+ // not present or it is true, set ParaHyphenationKeep to COLUMN
+ if ( !aAllow.second && ( !aUse.first || aUse.second ) )
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xDefault, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("ParaHyphenationKeep", uno::Any(true));
+ xPropertySet->setPropertyValue("ParaHyphenationKeepType", uno::Any(text::ParagraphHyphenationKeepType::COLUMN));
+ }
+}
+
+std::pair<bool, bool> SettingsTable::GetCompatSettingHasAndValue( std::u16string_view sCompatName ) const
+{
+ bool bHas = false;
+ 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();
+ bHas = true;
+ }
+ }
+
+ return std::pair<bool, bool>(bHas, bRet);
+}
+
+//Keep this function in-sync with the one in sw/.../docxattributeoutput.cxx
+sal_Int32 SettingsTable::GetWordCompatibilityMode() const
+{
+ if ( m_pImpl->m_nWordCompatibilityMode != -1 )
+ return m_pImpl->m_nWordCompatibilityMode;
+
+ for (const auto& rProp : m_pImpl->m_aCompatSettings)
+ {
+ if (rProp.Name == "compatSetting") //always true
+ {
+ css::uno::Sequence<css::beans::PropertyValue> aCurrentCompatSettings;
+ rProp.Value >>= aCurrentCompatSettings;
+
+ OUString sName;
+ aCurrentCompatSettings[0].Value >>= sName;
+ if ( sName != "compatibilityMode" )
+ continue;
+
+ OUString sUri;
+ aCurrentCompatSettings[1].Value >>= sUri;
+ if ( sUri != "http://schemas.microsoft.com/office/word" )
+ continue;
+
+ OUString sVal;
+ aCurrentCompatSettings[2].Value >>= sVal;
+ const sal_Int32 nValidMode = sVal.toInt32();
+ // if repeated, highest mode wins in MS Word. 11 is the first valid mode.
+ if ( nValidMode > 10 && nValidMode > m_pImpl->m_nWordCompatibilityMode )
+ m_pImpl->m_nWordCompatibilityMode = nValidMode;
+ }
+ }
+
+ return m_pImpl->m_nWordCompatibilityMode;
+}
+
+bool SettingsTable::GetLongerSpaceSequence() const
+{
+ return m_pImpl->m_bLongerSpaceSequence;
+}
+
+bool SettingsTable::GetNoLeading() const
+{
+ return m_pImpl->m_bNoLeading;
+}
+
+bool SettingsTable::GetGutterAtTop() const { return m_pImpl->m_bGutterAtTop; }
+
+bool SettingsTable::GetRecordChanges() const { return m_pImpl->m_bRecordChanges; }
+
+}//namespace dmapper
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SettingsTable.hxx b/sw/source/writerfilter/dmapper/SettingsTable.hxx
new file mode 100644
index 000000000000..f5ccb1bec96e
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SettingsTable.hxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <memory>
+
+namespace com::sun::star::lang
+{
+class XMultiServiceFactory;
+struct Locale;
+}
+
+namespace writerfilter::dmapper
+{
+class DomainMapper;
+
+struct SettingsTable_Impl;
+
+class SettingsTable : public LoggedProperties, public LoggedTable
+{
+ std::unique_ptr<SettingsTable_Impl> m_pImpl;
+
+public:
+ SettingsTable(const DomainMapper& rDomainMapper);
+ virtual ~SettingsTable() override;
+
+ //returns default TabStop in 1/100th mm
+ int GetDefaultTabStop() const;
+
+ /// Automatically update styles from document template?
+ bool GetLinkStyles() const;
+
+ /// What's the zoom factor set in percents?
+ sal_Int16 GetZoomFactor() const;
+
+ /// Gets the type of the zoom.
+ sal_Int16 GetZoomType() const;
+
+ /// What's the requested view? E.g. "web".
+ Id GetView() const;
+
+ bool GetEvenAndOddHeaders() const;
+
+ bool GetUsePrinterMetrics() const;
+
+ bool GetEmbedTrueTypeFonts() const;
+ bool GetEmbedSystemFonts() const;
+
+ bool GetDoNotUseHTMLParagraphAutoSpacing() const;
+ bool GetSplitPgBreakAndParaMark() const;
+ bool GetMirrorMarginSettings() const;
+ bool GetDisplayBackgroundShape() const;
+ bool GetDoNotExpandShiftReturn() const;
+ bool GetNoColumnBalance() const;
+ bool GetProtectForm() const;
+ bool GetReadOnly() const;
+ bool GetLongerSpaceSequence() const;
+ bool GetNoLeading() const;
+ bool GetNoHyphenateCaps() const;
+ sal_Int16 GetHyphenationZone() const;
+
+ const OUString& GetDecimalSymbol() const;
+ const OUString& GetListSeparator() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> const& GetThemeFontLangProperties() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> GetCompatSettings() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> GetDocumentProtectionSettings() const;
+
+ css::uno::Sequence<css::beans::PropertyValue> GetWriteProtectionSettings() const;
+
+ void ApplyProperties(css::uno::Reference<css::text::XTextDocument> const& xDoc);
+
+ std::pair<bool, bool> GetCompatSettingHasAndValue(std::u16string_view sCompatName) const;
+ sal_Int32 GetWordCompatibilityMode() const;
+
+ const OUString& GetCurrentDatabaseDataSource() const;
+ bool GetGutterAtTop() const;
+
+ bool GetRecordChanges() const;
+
+private:
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+ // Table
+ virtual void lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+};
+typedef tools::SvRef<SettingsTable> SettingsTablePtr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SmartTagHandler.cxx b/sw/source/writerfilter/dmapper/SmartTagHandler.cxx
new file mode 100644
index 000000000000..c92fa7c44be5
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SmartTagHandler.cxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "SmartTagHandler.hxx"
+
+#include <com/sun/star/rdf/Literal.hpp>
+#include <com/sun/star/rdf/URI.hpp>
+#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+namespace
+{
+OUString lcl_getTypePath(OUString& rType)
+{
+ OUString aRet;
+ if (rType.startsWith("urn:bails"))
+ {
+ rType = "urn:bails";
+ aRet = "tscp/bails.rdf";
+ }
+ return aRet;
+}
+}
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+SmartTagHandler::SmartTagHandler(uno::Reference<uno::XComponentContext> xComponentContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument)
+ : LoggedProperties("SmartTagHandler")
+ , m_xComponentContext(std::move(xComponentContext))
+ , m_xDocumentMetadataAccess(xTextDocument, uno::UNO_QUERY)
+{
+}
+
+SmartTagHandler::~SmartTagHandler() = default;
+
+void SmartTagHandler::lcl_attribute(Id nId, Value& rValue)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_Attr_name:
+ m_aAttributes.emplace_back(rValue.getString(), OUString());
+ break;
+ case NS_ooxml::LN_CT_Attr_val:
+ if (!m_aAttributes.empty())
+ m_aAttributes.back().second = rValue.getString();
+ break;
+ default:
+ SAL_WARN("writerfilter", "SmartTagHandler::lcl_attribute: unhandled attribute "
+ << nId << " (string value: '" << rValue.getString()
+ << "')");
+ break;
+ }
+}
+
+void SmartTagHandler::lcl_sprm(Sprm& rSprm)
+{
+ switch (rSprm.getId())
+ {
+ case NS_ooxml::LN_CT_SmartTagPr_attr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ pProperties->resolve(*this);
+ break;
+ }
+ }
+}
+
+void SmartTagHandler::setURI(const OUString& rURI) { m_aURI = rURI; }
+
+void SmartTagHandler::setElement(const OUString& rElement) { m_aElement = rElement; }
+
+void SmartTagHandler::handle(const uno::Reference<text::XTextRange>& xParagraph)
+{
+ if (m_aURI.isEmpty() || m_aElement.isEmpty() || m_aAttributes.empty())
+ return;
+
+ uno::Reference<rdf::XResource> xSubject(xParagraph, uno::UNO_QUERY);
+
+ for (const std::pair<OUString, OUString>& rAttribute : m_aAttributes)
+ {
+ OUString aTypeNS = rAttribute.first;
+ OUString aMetadataFilePath = lcl_getTypePath(aTypeNS);
+ if (aMetadataFilePath.isEmpty())
+ continue;
+
+ uno::Reference<rdf::XURI> xType = rdf::URI::create(m_xComponentContext, aTypeNS);
+ uno::Sequence<uno::Reference<rdf::XURI>> aGraphNames
+ = m_xDocumentMetadataAccess->getMetadataGraphsWithType(xType);
+ uno::Reference<rdf::XURI> xGraphName;
+ if (aGraphNames.hasElements())
+ xGraphName = aGraphNames[0];
+ else
+ {
+ uno::Sequence<uno::Reference<rdf::XURI>> xTypes = { xType };
+ xGraphName = m_xDocumentMetadataAccess->addMetadataFile(aMetadataFilePath, xTypes);
+ }
+ uno::Reference<rdf::XNamedGraph> xGraph
+ = m_xDocumentMetadataAccess->getRDFRepository()->getGraph(xGraphName);
+ uno::Reference<rdf::XURI> xKey = rdf::URI::create(m_xComponentContext, rAttribute.first);
+ uno::Reference<rdf::XLiteral> xValue
+ = rdf::Literal::create(m_xComponentContext, rAttribute.second);
+ xGraph->addStatement(xSubject, xKey, xValue);
+ }
+
+ m_aURI.clear();
+ m_aElement.clear();
+ m_aAttributes.clear();
+}
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/SmartTagHandler.hxx b/sw/source/writerfilter/dmapper/SmartTagHandler.hxx
new file mode 100644
index 000000000000..7999b9dcc22a
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/SmartTagHandler.hxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <vector>
+
+#include "LoggedResources.hxx"
+
+namespace com::sun::star
+{
+namespace rdf
+{
+class XDocumentMetadataAccess;
+}
+namespace text
+{
+class XTextDocument;
+class XTextRange;
+}
+namespace uno
+{
+class XComponentContext;
+}
+}
+
+namespace writerfilter::dmapper
+{
+/// Handler for smart tags, i.e. <w:smartTag> and below.
+class SmartTagHandler : public LoggedProperties
+{
+ css::uno::Reference<css::uno::XComponentContext> m_xComponentContext;
+ css::uno::Reference<css::rdf::XDocumentMetadataAccess> m_xDocumentMetadataAccess;
+ OUString m_aURI;
+ OUString m_aElement;
+ std::vector<std::pair<OUString, OUString>> m_aAttributes;
+
+public:
+ SmartTagHandler(css::uno::Reference<css::uno::XComponentContext> xComponentContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument);
+ ~SmartTagHandler() override;
+
+ void lcl_attribute(Id nId, Value& rValue) override;
+ void lcl_sprm(Sprm& rSprm) override;
+
+ void setURI(const OUString& rURI);
+ void setElement(const OUString& rElement);
+
+ /// Set m_aAttributes as RDF statements on xParagraph.
+ void handle(const css::uno::Reference<css::text::XTextRange>& xParagraph);
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/StyleSheetTable.cxx b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx
new file mode 100644
index 000000000000..1b5633b009fd
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/StyleSheetTable.cxx
@@ -0,0 +1,1830 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <utility>
+#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/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextFramesSupplier.hpp>
+#include <com/sun/star/text/XTextTable.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/style/ParagraphAdjust.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <map>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <o3tl/sorted_vector.hxx>
+
+using namespace ::com::sun::star;
+
+namespace writerfilter::dmapper
+{
+
+StyleSheetEntry::StyleSheetEntry() :
+ m_bIsDefaultStyle(false)
+ ,m_bAssignedAsChapterNumbering(false)
+ ,m_bInvalidHeight(false)
+ ,m_bHasUPE(false)
+ ,m_nStyleTypeCode(STYLE_TYPE_UNKNOWN)
+ ,m_pProperties(new StyleSheetPropertyMap)
+ ,m_bAutoRedefine(false)
+{
+}
+
+StyleSheetEntry::~StyleSheetEntry()
+{
+}
+
+TableStyleSheetEntry::TableStyleSheetEntry( StyleSheetEntry const & rEntry )
+{
+ m_bIsDefaultStyle = rEntry.m_bIsDefaultStyle;
+ m_bInvalidHeight = rEntry.m_bInvalidHeight;
+ m_bHasUPE = rEntry.m_bHasUPE;
+ m_nStyleTypeCode = STYLE_TYPE_TABLE;
+ m_sBaseStyleIdentifier = rEntry.m_sBaseStyleIdentifier;
+ m_sNextStyleIdentifier = rEntry.m_sNextStyleIdentifier;
+ m_sLinkStyleIdentifier = rEntry.m_sLinkStyleIdentifier;
+ m_sStyleName = rEntry.m_sStyleName;
+ m_sStyleIdentifierD = rEntry.m_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 = m_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 && !m_sBaseStyleIdentifier.isEmpty() && m_sBaseStyleIdentifier != m_sStyleIdentifierD )
+ {
+ const StyleSheetEntryPtr pParentStyleSheet = pStyleSheetTable->FindStyleSheetByISTD(m_sBaseStyleIdentifier);
+ if ( pParentStyleSheet )
+ pRet = pParentStyleSheet->GetMergedInheritedProperties(pStyleSheetTable);
+ }
+
+ if ( !pRet )
+ pRet = new PropertyMap;
+
+ pRet->InsertProps(m_pProperties.get());
+
+ return pRet;
+}
+
+static void lcl_mergeProps( const PropertyMapPtr& pToFill, const PropertyMapPtr& pToAdd, TblStyleType nStyleId )
+{
+ static const PropertyIds pPropsToCheck[] =
+ {
+ PROP_BOTTOM_BORDER,
+ PROP_TOP_BORDER,
+ PROP_RIGHT_BORDER,
+ PROP_LEFT_BORDER,
+ };
+
+ bool pRemoveInside[] =
+ {
+ ( nStyleId == TBL_STYLE_FIRSTROW ),
+ ( nStyleId == TBL_STYLE_LASTROW ),
+ ( nStyleId == TBL_STYLE_LASTCOL ),
+ ( nStyleId == TBL_STYLE_FIRSTCOL )
+ };
+
+ for ( unsigned i = 0 ; i != SAL_N_ELEMENTS(pPropsToCheck); i++ )
+ {
+ PropertyIds nId = pPropsToCheck[i];
+ std::optional<PropertyMap::Property> pProp = pToAdd->getProperty(nId);
+
+ if ( pProp )
+ {
+ if ( pRemoveInside[i] )
+ {
+ // Remove the insideH and insideV depending on the cell pos
+ PropertyIds nInsideProp = ( i < 2 ) ? META_PROP_HORIZONTAL_BORDER : META_PROP_VERTICAL_BORDER;
+ pToFill->Erase(nInsideProp);
+ }
+ }
+ }
+
+ pToFill->InsertProps(pToAdd);
+}
+
+PropertyMapPtr TableStyleSheetEntry::GetLocalPropertiesFromMask( sal_Int32 nMask )
+{
+ // Order from right to left
+ struct TblStyleTypeAndMask {
+ sal_Int32 mask;
+ TblStyleType type;
+ };
+
+ static const TblStyleTypeAndMask aOrderedStyleTable[] =
+ {
+ { 0x010, TBL_STYLE_BAND2HORZ },
+ { 0x020, TBL_STYLE_BAND1HORZ },
+ { 0x040, TBL_STYLE_BAND2VERT },
+ { 0x080, TBL_STYLE_BAND1VERT },
+ { 0x100, TBL_STYLE_LASTCOL },
+ { 0x200, TBL_STYLE_FIRSTCOL },
+ { 0x400, TBL_STYLE_LASTROW },
+ { 0x800, TBL_STYLE_FIRSTROW },
+ { 0x001, TBL_STYLE_SWCELL },
+ { 0x002, TBL_STYLE_SECELL },
+ { 0x004, TBL_STYLE_NWCELL },
+ { 0x008, TBL_STYLE_NECELL }
+ };
+
+ // Get the properties applying according to the mask
+ PropertyMapPtr pProps( new PropertyMap( ) );
+ for (const TblStyleTypeAndMask & i : aOrderedStyleTable)
+ {
+ TblStylePrs::iterator pIt = m_aStyles.find( i.type );
+ if ( ( nMask & i.mask ) && ( pIt != m_aStyles.end( ) ) )
+ lcl_mergeProps( pProps, pIt->second, i.type );
+ }
+ return pProps;
+}
+
+namespace {
+
+struct ListCharStylePropertyMap_t
+{
+ OUString sCharStyleName;
+ PropertyValueVector_t aPropertyValues;
+
+ ListCharStylePropertyMap_t(OUString _sCharStyleName, PropertyValueVector_t&& rPropertyValues):
+ sCharStyleName(std::move( _sCharStyleName )),
+ aPropertyValues( std::move(rPropertyValues) )
+ {}
+};
+
+}
+
+struct StyleSheetTable_Impl
+{
+ DomainMapper& m_rDMapper;
+ uno::Reference< text::XTextDocument> m_xTextDocument;
+ uno::Reference< beans::XPropertySet> m_xTextDefaults;
+ std::vector< StyleSheetEntryPtr > m_aStyleSheetEntries;
+ std::map< OUString, StyleSheetEntryPtr > m_aStyleSheetEntriesMap;
+ std::map<OUString, OUString> m_ClonedTOCStylesMap;
+ StyleSheetEntryPtr m_pCurrentEntry;
+ PropertyMapPtr m_pDefaultParaProps, m_pDefaultCharProps;
+ OUString m_sDefaultParaStyleName; //WW8 name
+ std::vector< ListCharStylePropertyMap_t > m_aListCharStylePropertyVector;
+ bool m_bHasImportedDefaultParaProps;
+ bool m_bIsNewDoc;
+
+ StyleSheetTable_Impl(DomainMapper& rDMapper, uno::Reference< text::XTextDocument> 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);
+ void ApplyClonedTOCStylesToXText(uno::Reference<text::XText> const& xText);
+};
+
+
+StyleSheetTable_Impl::StyleSheetTable_Impl(DomainMapper& rDMapper,
+ uno::Reference< text::XTextDocument> xTextDocument,
+ bool const bIsNewDoc)
+ : m_rDMapper( rDMapper ),
+ m_xTextDocument(std::move( xTextDocument )),
+ m_pDefaultParaProps(new PropertyMap),
+ m_pDefaultCharProps(new PropertyMap),
+ m_sDefaultParaStyleName("Normal"),
+ m_bHasImportedDefaultParaProps(false),
+ m_bIsNewDoc(bIsNewDoc)
+{
+ //set font height default to 10pt
+ uno::Any aVal( 10.0 );
+ m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT, aVal );
+ m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT_ASIAN, aVal );
+ m_pDefaultCharProps->Insert( PROP_CHAR_HEIGHT_COMPLEX, aVal );
+
+ // See SwDoc::RemoveAllFormatLanguageDependencies(), internal filters
+ // disable kerning by default, do the same here.
+ m_pDefaultCharProps->Insert(PROP_CHAR_AUTO_KERNING, uno::Any(false));
+}
+
+
+OUString StyleSheetTable_Impl::HasListCharStyle( const PropertyValueVector_t& rPropValues )
+{
+ for( const auto& rListVector : m_aListCharStylePropertyVector )
+ {
+ const auto& rPropertyValues = rListVector.aPropertyValues;
+ //if size is identical
+ if( rPropertyValues.size() == rPropValues.size() )
+ {
+ bool bBreak = false;
+ //then search for all contained properties
+ for( const auto& rPropVal1 : rPropValues)
+ {
+ //find the property
+ auto aListIter = std::find_if(rPropertyValues.begin(), rPropertyValues.end(),
+ [&rPropVal1](const css::beans::PropertyValue& rPropVal2) { return rPropVal2.Name == rPropVal1.Name; });
+ //set break flag if property hasn't been found
+ bBreak = (aListIter == rPropertyValues.end()) || (aListIter->Value != rPropVal1.Value);
+ if( bBreak )
+ break;
+ }
+ if( !bBreak )
+ return rListVector.sCharStyleName;
+ }
+ }
+ return OUString();
+}
+
+void StyleSheetTable_Impl::AppendLatentStyleProperty(const OUString& aName, Value const & rValue)
+{
+ beans::PropertyValue aValue;
+ aValue.Name = aName;
+ aValue.Value <<= rValue.getString();
+ m_pCurrentEntry->m_aLatentStyles.push_back(aValue);
+}
+
+void StyleSheetTable_Impl::SetPropertiesToDefault(const uno::Reference<style::XStyle>& xStyle)
+{
+ // See if the existing style has any non-default properties. If so, reset them back to default.
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ const uno::Sequence<beans::Property> aProperties = xPropertySetInfo->getProperties();
+ std::vector<OUString> aPropertyNames;
+ aPropertyNames.reserve(aProperties.getLength());
+ std::transform(aProperties.begin(), aProperties.end(), std::back_inserter(aPropertyNames),
+ [](const beans::Property& rProp) { return rProp.Name; });
+
+ uno::Reference<beans::XPropertyState> xPropertyState(xStyle, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyState> aStates = xPropertyState->getPropertyStates(comphelper::containerToSequence(aPropertyNames));
+ for (sal_Int32 i = 0; i < aStates.getLength(); ++i)
+ {
+ if (aStates[i] == beans::PropertyState_DIRECT_VALUE)
+ {
+ try
+ {
+ xPropertyState->setPropertyToDefault(aPropertyNames[i]);
+ }
+ catch(const uno::Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter", "setPropertyToDefault(" << aPropertyNames[i] << ") failed");
+ }
+ }
+ }
+}
+
+StyleSheetTable::StyleSheetTable(DomainMapper& rDMapper,
+ uno::Reference< text::XTextDocument> const& xTextDocument,
+ bool const bIsNewDoc)
+: LoggedProperties("StyleSheetTable")
+, LoggedTable("StyleSheetTable")
+, m_pImpl( new StyleSheetTable_Impl(rDMapper, xTextDocument, bIsNewDoc) )
+{
+}
+
+
+StyleSheetTable::~StyleSheetTable()
+{
+}
+
+void StyleSheetTable::SetDefaultParaProps(PropertyIds eId, const css::uno::Any& rAny)
+{
+ m_pImpl->m_pDefaultParaProps->Insert(eId, rAny, /*bOverwrite=*/false, NO_GRAB_BAG, /*bDocDefault=*/true);
+}
+
+PropertyMapPtr const & StyleSheetTable::GetDefaultParaProps() const
+{
+ return m_pImpl->m_pDefaultParaProps;
+}
+
+PropertyMapPtr const & StyleSheetTable::GetDefaultCharProps() const
+{
+ return m_pImpl->m_pDefaultCharProps;
+}
+
+void StyleSheetTable::lcl_attribute(Id Name, Value & val)
+{
+ OSL_ENSURE( m_pImpl->m_pCurrentEntry, "current entry has to be set here");
+ if(!m_pImpl->m_pCurrentEntry)
+ return ;
+ int nIntValue = val.getInt();
+ OUString sValue = val.getString();
+
+ // The default type is paragraph, and it needs to be processed first,
+ // because the NS_ooxml::LN_CT_Style_type handling may set m_pImpl->m_pCurrentEntry
+ // to point to a different object.
+ if( m_pImpl->m_pCurrentEntry->m_nStyleTypeCode == STYLE_TYPE_UNKNOWN )
+ {
+ if( Name != NS_ooxml::LN_CT_Style_type )
+ m_pImpl->m_pCurrentEntry->m_nStyleTypeCode = STYLE_TYPE_PARA;
+ }
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_Style_type:
+ {
+ SAL_WARN_IF( m_pImpl->m_pCurrentEntry->m_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->m_nStyleTypeCode = nType;
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_default:
+ m_pImpl->m_pCurrentEntry->m_bIsDefaultStyle = (nIntValue != 0);
+
+ if (m_pImpl->m_pCurrentEntry->m_nStyleTypeCode != STYLE_TYPE_UNKNOWN)
+ {
+ // "If this attribute is specified by multiple styles, then the last instance shall be used."
+ if (m_pImpl->m_pCurrentEntry->m_bIsDefaultStyle
+ && m_pImpl->m_pCurrentEntry->m_nStyleTypeCode == STYLE_TYPE_PARA
+ && !m_pImpl->m_pCurrentEntry->m_sStyleIdentifierD.isEmpty())
+ {
+ m_pImpl->m_sDefaultParaStyleName = m_pImpl->m_pCurrentEntry->m_sStyleIdentifierD;
+ }
+
+ beans::PropertyValue aValue;
+ aValue.Name = "default";
+ aValue.Value <<= m_pImpl->m_pCurrentEntry->m_bIsDefaultStyle;
+ m_pImpl->m_pCurrentEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_customStyle:
+ if (m_pImpl->m_pCurrentEntry->m_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->m_sStyleIdentifierD = sValue;
+ if(m_pImpl->m_pCurrentEntry->m_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->m_sStyleName = sStringValue;
+ if(m_pImpl->m_pCurrentEntry->m_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->m_sBaseStyleIdentifier = sStringValue;
+ if(m_pImpl->m_pCurrentEntry->m_nStyleTypeCode == STYLE_TYPE_TABLE)
+ {
+ TableStyleSheetEntry* pTableEntry = static_cast<TableStyleSheetEntry *>(m_pImpl->m_pCurrentEntry.get());
+ beans::PropertyValue aValue;
+ aValue.Name = "basedOn";
+ aValue.Value <<= sStringValue;
+ pTableEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_link:
+ m_pImpl->m_pCurrentEntry->m_sLinkStyleIdentifier = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_Style_next:
+ m_pImpl->m_pCurrentEntry->m_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->m_bAutoRedefine = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Style_tcPr:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties && m_pImpl->m_pCurrentEntry->m_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.m_pProperties->InsertProps(pTblStylePrHandler->getProperties());
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_trPr:
+ break;
+ case NS_ooxml::LN_CT_Style_rsid:
+ case NS_ooxml::LN_CT_Style_qFormat:
+ case NS_ooxml::LN_CT_Style_semiHidden:
+ case NS_ooxml::LN_CT_Style_unhideWhenUsed:
+ case NS_ooxml::LN_CT_Style_uiPriority:
+ case NS_ooxml::LN_CT_Style_locked:
+ if (m_pImpl->m_pCurrentEntry->m_nStyleTypeCode != STYLE_TYPE_UNKNOWN)
+ {
+ StyleSheetEntryPtr pEntry = m_pImpl->m_pCurrentEntry;
+ beans::PropertyValue aValue;
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_Style_rsid:
+ {
+ // We want the rsid as a hex string, but always with the length of 8.
+ OUStringBuffer aBuf = OUString::number(nIntValue, 16);
+ OUStringBuffer aStr;
+ comphelper::string::padToLength(aStr, 8 - aBuf.getLength(), '0');
+ aStr.append(aBuf.getStr());
+
+ aValue.Name = "rsid";
+ aValue.Value <<= aStr.makeStringAndClear();
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_qFormat:
+ aValue.Name = "qFormat";
+ break;
+ case NS_ooxml::LN_CT_Style_semiHidden:
+ aValue.Name = "semiHidden";
+ break;
+ case NS_ooxml::LN_CT_Style_unhideWhenUsed:
+ aValue.Name = "unhideWhenUsed";
+ break;
+ case NS_ooxml::LN_CT_Style_uiPriority:
+ {
+ aValue.Name = "uiPriority";
+ aValue.Value <<= OUString::number(nIntValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_locked:
+ aValue.Name = "locked";
+ break;
+ }
+ pEntry->AppendInteropGrabBag(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_Style_tblPr: //contains table properties
+ case NS_ooxml::LN_CT_Style_tblStylePr: //contains to table properties
+ case NS_ooxml::LN_CT_TblPrBase_tblInd: //table properties - at least width value and type
+ case NS_ooxml::LN_EG_RPrBase_rFonts: //table fonts
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pTblStylePrHandler = std::make_shared<TblStylePrHandler>( m_pImpl->m_rDMapper );
+ pProperties->resolve( *pTblStylePrHandler );
+
+ // Add the properties to the table style
+ TblStyleType nType = pTblStylePrHandler->getType( );
+ PropertyMapPtr pProps = pTblStylePrHandler->getProperties( );
+ StyleSheetEntry * pEntry = m_pImpl->m_pCurrentEntry.get();
+
+ TableStyleSheetEntry * pTableEntry = dynamic_cast<TableStyleSheetEntry*>( pEntry );
+ if (nType == TBL_STYLE_UNKNOWN)
+ {
+ pEntry->m_pProperties->InsertProps(pProps);
+ }
+ else
+ {
+ if (pTableEntry != nullptr)
+ pTableEntry->AddTblStylePr( nType, pProps );
+ }
+
+ if (nSprmId == NS_ooxml::LN_CT_Style_tblPr)
+ {
+ if (pTableEntry != nullptr)
+ pTableEntry->AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tblPr"));
+ }
+ else if (nSprmId == NS_ooxml::LN_CT_Style_tblStylePr)
+ {
+ pTblStylePrHandler->appendInteropGrabBag("type", pTblStylePrHandler->getTypeString());
+ if (pTableEntry != nullptr)
+ pTableEntry->AppendInteropGrabBag(pTblStylePrHandler->getInteropGrabBag("tblStylePr"));
+ }
+ }
+ break;
+ }
+ case NS_ooxml::LN_CT_PPrDefault_pPr:
+ case NS_ooxml::LN_CT_DocDefaults_pPrDefault:
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(true);
+
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultParaProps );
+ resolveSprmProps( m_pImpl->m_rDMapper, rSprm );
+ if ( nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault && m_pImpl->m_pDefaultParaProps &&
+ !m_pImpl->m_pDefaultParaProps->isSet( PROP_PARA_TOP_MARGIN ) )
+ {
+ SetDefaultParaProps( PROP_PARA_TOP_MARGIN, uno::Any( sal_Int32(0) ) );
+ }
+ m_pImpl->m_rDMapper.PopStyleSheetProperties();
+ applyDefaults( true );
+ m_pImpl->m_bHasImportedDefaultParaProps = true;
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_pPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(false);
+ break;
+ case NS_ooxml::LN_CT_RPrDefault_rPr:
+ case NS_ooxml::LN_CT_DocDefaults_rPrDefault:
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_rPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(true);
+
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pDefaultCharProps );
+ resolveSprmProps( m_pImpl->m_rDMapper, rSprm );
+ m_pImpl->m_rDMapper.PopStyleSheetProperties();
+ applyDefaults( false );
+ if (nSprmId == NS_ooxml::LN_CT_DocDefaults_rPrDefault)
+ m_pImpl->m_rDMapper.SetDocDefaultsImport(false);
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_jc: //table alignment - row properties!
+ m_pImpl->m_pCurrentEntry->m_pProperties->Insert( PROP_HORI_ORIENT,
+ uno::Any( ConversionHelper::convertTableJustification( nIntValue )));
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_jc: //table alignment - row properties!
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblBorders: //table borders, might be defined in table style
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>(m_pImpl->m_rDMapper.IsOOXMLImport());
+ pProperties->resolve(*pBorderHandler);
+ m_pImpl->m_pCurrentEntry->m_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->m_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->m_pProperties.get() );
+ if ( !pTblHandler->sprm( rSprm ) )
+ {
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->m_pProperties.get() );
+
+ PropertyMapPtr pProps(new PropertyMap());
+ if (m_pImpl->m_pCurrentEntry->m_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->m_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->m_pProperties->InsertProps(pProps);
+
+ m_pImpl->m_rDMapper.PopStyleSheetProperties( );
+ }
+ }
+ break;
+}
+}
+
+
+void StyleSheetTable::lcl_entry(const writerfilter::Reference<Properties>::Pointer_t& ref)
+{
+ //create a new style entry
+ OSL_ENSURE( !m_pImpl->m_pCurrentEntry, "current entry has to be NULL here");
+ m_pImpl->m_pCurrentEntry = StyleSheetEntryPtr(new StyleSheetEntry);
+ m_pImpl->m_rDMapper.PushStyleSheetProperties( m_pImpl->m_pCurrentEntry->m_pProperties.get() );
+ ref->resolve(*this);
+ m_pImpl->m_rDMapper.ProcessDeferredStyleCharacterProperties();
+ //append it to the table
+ m_pImpl->m_rDMapper.PopStyleSheetProperties();
+ if( !m_pImpl->m_rDMapper.IsOOXMLImport() || !m_pImpl->m_pCurrentEntry->m_sStyleName.isEmpty())
+ {
+ m_pImpl->m_pCurrentEntry->m_sConvertedStyleName = ConvertStyleName( m_pImpl->m_pCurrentEntry->m_sStyleName );
+ m_pImpl->m_aStyleSheetEntries.push_back( m_pImpl->m_pCurrentEntry );
+ m_pImpl->m_aStyleSheetEntriesMap.emplace( m_pImpl->m_pCurrentEntry->m_sStyleIdentifierD, m_pImpl->m_pCurrentEntry );
+ }
+ else
+ {
+ //TODO: this entry contains the default settings - they have to be added to the settings
+ }
+
+ if (!m_pImpl->m_pCurrentEntry->m_aLatentStyles.empty())
+ {
+ // We have latent styles for this entry, then process them.
+ std::vector<beans::PropertyValue>& rLatentStyles = m_pImpl->m_pCurrentEntry->m_aLatentStyles;
+
+ if (!m_pImpl->m_pCurrentEntry->m_aLsdExceptions.empty())
+ {
+ std::vector<beans::PropertyValue>& rLsdExceptions = m_pImpl->m_pCurrentEntry->m_aLsdExceptions;
+ beans::PropertyValue aValue;
+ aValue.Name = "lsdExceptions";
+ aValue.Value <<= comphelper::containerToSequence(rLsdExceptions);
+ rLatentStyles.push_back(aValue);
+ }
+
+ uno::Sequence<beans::PropertyValue> aLatentStyles( comphelper::containerToSequence(rLatentStyles) );
+
+ // We can put all latent style info directly to the document interop
+ // grab bag, as we can be sure that only a single style entry has
+ // latent style info.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_pImpl->m_xTextDocument, uno::UNO_QUERY);
+ auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(xPropertySet->getPropertyValue("InteropGrabBag").get< uno::Sequence<beans::PropertyValue> >());
+ beans::PropertyValue aValue;
+ aValue.Name = "latentStyles";
+ aValue.Value <<= aLatentStyles;
+ aGrabBag.push_back(aValue);
+ xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+
+ m_pImpl->m_pCurrentEntry = StyleSheetEntryPtr();
+}
+/*-------------------------------------------------------------------------
+ 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) -> const uno::Any& { 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) -> const OUString& { return rValue.Name; });
+ return comphelper::containerToSequence(aRet);
+}
+
+void StyleSheetTable::ApplyNumberingStyleNameToParaStyles()
+{
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xParaStyles;
+ xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xParaStyles;
+
+ if ( !xParaStyles.is() )
+ return;
+
+ for ( const auto& pEntry : m_pImpl->m_aStyleSheetEntries )
+ {
+ StyleSheetPropertyMap* pStyleSheetProperties = nullptr;
+ if ( pEntry->m_nStyleTypeCode == STYLE_TYPE_PARA && (pStyleSheetProperties = pEntry->m_pProperties.get()) )
+ {
+ // ListId 0 means turn off numbering - to cancel inheritance - so make sure that can be set.
+ if (pStyleSheetProperties->props().GetListId() > -1)
+ {
+ uno::Reference< style::XStyle > xStyle;
+ xParaStyles->getByName( ConvertStyleName(pEntry->m_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->props().GetListId() );
+ if ( !sNumberingStyleName.isEmpty()
+ || !pStyleSheetProperties->props().GetListId() )
+ xPropertySet->setPropertyValue( getPropertyName(PROP_NUMBERING_STYLE_NAME), uno::Any(sNumberingStyleName) );
+
+ // Word 2010+ (not Word 2003, and Word 2007 is completely broken)
+ // does something rather strange. It does not allow two paragraph styles
+ // to share the same listLevel on a numbering rule.
+ // Consider this style to just be body level if already used previously.
+ m_pImpl->m_rDMapper.ValidateListLevel(pEntry->m_sStyleIdentifierD);
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying numbering style name to Paragraph styles");
+ }
+}
+
+/* Counteract the destructive tendencies of LibreOffice's Chapter Numbering
+ *
+ * Any assignment to Chapter Numbering will erase the numbering-like properties of inherited styles.
+ * So go through the list of styles and any that inherit from a Chapter Numbering style
+ * should have the Outline Level reapplied.
+ */
+void StyleSheetTable::ReApplyInheritedOutlineLevelFromChapterNumbering()
+{
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xParaStyles;
+ xStyleFamilies->getByName(getPropertyName(PROP_PARAGRAPH_STYLES)) >>= xParaStyles;
+
+ if (!xParaStyles.is())
+ return;
+
+ for (const auto& pEntry : m_pImpl->m_aStyleSheetEntries)
+ {
+ if (pEntry->m_nStyleTypeCode != STYLE_TYPE_PARA || pEntry->m_sBaseStyleIdentifier.isEmpty())
+ continue;
+
+ StyleSheetEntryPtr pParent = FindStyleSheetByISTD(pEntry->m_sBaseStyleIdentifier);
+ if (!pParent || !pParent->m_bAssignedAsChapterNumbering)
+ continue;
+
+ uno::Reference< style::XStyle > xStyle;
+ xParaStyles->getByName(pEntry->m_sConvertedStyleName) >>= xStyle;
+ if (!xStyle.is())
+ continue;
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW);
+ const sal_Int16 nListId = pEntry->m_pProperties->props().GetListId();
+ const OUString& sParentNumberingStyleName
+ = m_pImpl->m_rDMapper.GetListStyleName(pParent->m_pProperties->props().GetListId());
+ if (nListId == -1 && !sParentNumberingStyleName.isEmpty())
+ {
+ xPropertySet->setPropertyValue(getPropertyName(PROP_NUMBERING_STYLE_NAME),
+ uno::Any(sParentNumberingStyleName));
+ }
+
+ sal_Int16 nOutlineLevel = pEntry->m_pProperties->GetOutlineLevel();
+ if (nOutlineLevel != -1)
+ continue;
+
+ nOutlineLevel = pParent->m_pProperties->GetOutlineLevel();
+ assert(nOutlineLevel >= WW_OUTLINE_MIN && nOutlineLevel < WW_OUTLINE_MAX);
+
+ // convert MS level to LO equivalent outline level
+ ++nOutlineLevel;
+
+ xPropertySet->setPropertyValue(getPropertyName(PROP_OUTLINE_LEVEL), uno::Any(nOutlineLevel));
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Failed applying outlineLevel to Paragraph styles");
+ }
+}
+
+void StyleSheetTable_Impl::ApplyClonedTOCStylesToXText(uno::Reference<text::XText> const& xText)
+{
+ uno::Reference<container::XEnumerationAccess> const xEA(xText, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumeration> const xParaEnum(xEA->createEnumeration());
+
+ while (xParaEnum->hasMoreElements())
+ {
+ uno::Reference<lang::XServiceInfo> const xElem(xParaEnum->nextElement(), uno::UNO_QUERY_THROW);
+ if (xElem->supportsService(u"com.sun.star.text.Paragraph"_ustr))
+ {
+ uno::Reference<beans::XPropertySet> const xPara(xElem, uno::UNO_QUERY_THROW);
+ OUString styleName;
+ if (xPara->getPropertyValue(u"ParaStyleName"_ustr) >>= styleName)
+ {
+ auto const it(m_ClonedTOCStylesMap.find(styleName));
+ if (it != m_ClonedTOCStylesMap.end())
+ {
+ xPara->setPropertyValue(u"ParaStyleName"_ustr, uno::Any(it->second));
+ }
+ }
+ }
+ else if (xElem->supportsService(u"com.sun.star.text.TextTable"_ustr))
+ {
+ uno::Reference<text::XTextTable> const xTable(xElem, uno::UNO_QUERY_THROW);
+ uno::Sequence<OUString> const cells(xTable->getCellNames());
+ for (OUString const& rCell : cells)
+ {
+ uno::Reference<text::XText> const xCell(xTable->getCellByName(rCell), uno::UNO_QUERY_THROW);
+ ApplyClonedTOCStylesToXText(xCell);
+ }
+ }
+ }
+}
+
+/**
+ Replace the applied en-US Word built-in styles that were referenced from
+ TOC fields (also STYLEREF and likely AUTOTEXTLIST) with the localised clones.
+
+ With the style cloned, and the clone referenced, the ToX should work in
+ Writer and also, when exported to DOCX, in Word.
+ */
+void StyleSheetTable::ApplyClonedTOCStyles()
+{
+ if (m_pImpl->m_ClonedTOCStylesMap.empty()
+ || !m_pImpl->m_bIsNewDoc) // avoid modifying pre-existing content
+ {
+ return;
+ }
+ SAL_INFO("writerfilter.dmapper", "Applying cloned styles to make TOC work");
+ // ignore header / footer, irrelevant for ToX
+ // text frames
+ uno::Reference<text::XTextFramesSupplier> const xDocTFS(m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumerationAccess> const xFrames(xDocTFS->getTextFrames(), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XEnumeration> const xFramesEnum(xFrames->createEnumeration());
+ while (xFramesEnum->hasMoreElements())
+ {
+ uno::Reference<text::XText> const xFrame(xFramesEnum->nextElement(), uno::UNO_QUERY_THROW);
+ m_pImpl->ApplyClonedTOCStylesToXText(xFrame);
+ }
+ // body
+ uno::Reference<text::XText> const xBody(m_pImpl->m_xTextDocument->getText());
+ m_pImpl->ApplyClonedTOCStylesToXText(xBody);
+}
+
+OUString StyleSheetTable::CloneTOCStyle(FontTablePtr const& rFontTable, StyleSheetEntryPtr const pStyle, OUString const& rNewName)
+{
+ StyleSheetEntryPtr const pClone(new StyleSheetEntry(*pStyle));
+ pClone->m_sStyleIdentifierD = rNewName;
+ pClone->m_sStyleName = rNewName;
+ pClone->m_sConvertedStyleName = ConvertStyleName(rNewName);
+ m_pImpl->m_aStyleSheetEntries.push_back(pClone);
+ // add it so it will be found if referenced from another TOC
+ m_pImpl->m_aStyleSheetEntriesMap.emplace(rNewName, pClone);
+ m_pImpl->m_ClonedTOCStylesMap.emplace(pStyle->m_sStyleName, pClone->m_sConvertedStyleName);
+ std::vector<StyleSheetEntryPtr> const styles{ pClone };
+ ApplyStyleSheetsImpl(rFontTable, styles);
+ return pClone->m_sConvertedStyleName;
+}
+
+void StyleSheetTable::ApplyStyleSheets( const FontTablePtr& rFontTable )
+{
+ return ApplyStyleSheetsImpl(rFontTable, m_pImpl->m_aStyleSheetEntries);
+}
+
+void StyleSheetTable::ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std::vector<StyleSheetEntryPtr> const& rEntries)
+{
+ try
+ {
+ uno::Reference< style::XStyleFamiliesSupplier > xStylesSupplier( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameContainer> xCharStyles;
+ uno::Reference<container::XNameContainer> xParaStyles;
+ uno::Reference<container::XNameContainer> xNumberingStyles;
+
+ xStyleFamilies->getByName(getPropertyName( PROP_CHARACTER_STYLES )) >>= xCharStyles;
+ xStyleFamilies->getByName(getPropertyName( PROP_PARAGRAPH_STYLES )) >>= xParaStyles;
+ xStyleFamilies->getByName("NumberingStyles") >>= xNumberingStyles;
+ if(xCharStyles.is() && xParaStyles.is())
+ {
+ std::vector< ::std::pair<OUString, uno::Reference<style::XStyle>> > aMissingParent;
+ std::vector< ::std::pair<OUString, uno::Reference<style::XStyle>> > aMissingFollow;
+ std::vector<std::pair<OUString, uno::Reference<style::XStyle>>> aMissingLink;
+ std::vector<beans::PropertyValue> aTableStylesVec;
+ for (auto& pEntry : rEntries)
+ {
+ if( pEntry->m_nStyleTypeCode == STYLE_TYPE_UNKNOWN && !pEntry->m_sStyleName.isEmpty() )
+ pEntry->m_nStyleTypeCode = STYLE_TYPE_PARA; // unspecified style types are considered paragraph styles
+
+ if( pEntry->m_nStyleTypeCode == STYLE_TYPE_CHAR || pEntry->m_nStyleTypeCode == STYLE_TYPE_PARA || pEntry->m_nStyleTypeCode == STYLE_TYPE_LIST )
+ {
+ bool bParaStyle = pEntry->m_nStyleTypeCode == STYLE_TYPE_PARA;
+ bool bCharStyle = pEntry->m_nStyleTypeCode == STYLE_TYPE_CHAR;
+ bool bListStyle = pEntry->m_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->m_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->m_sBaseStyleIdentifier.isEmpty() //imported style has no inheritance
+ && !xStyle->getParentStyle().isEmpty() ) //built-in style has a default inheritance
+ {
+ xStyle->setParentStyle( "" );
+ }
+ }
+ }
+ else
+ {
+ bInsert = true;
+ xStyle.set(xDocFactory->createInstance(
+ bParaStyle ?
+ getPropertyName( PROP_SERVICE_PARA_STYLE ) :
+ (bListStyle ? OUString("com.sun.star.style.NumberingStyle") : getPropertyName( PROP_SERVICE_CHAR_STYLE ))),
+ uno::UNO_QUERY_THROW);
+
+ // Numbering styles have to be inserted early, as e.g. the NumberingRules property is only available after insertion.
+ if (bListStyle)
+ {
+ xStyles->insertByName( sConvertedStyleName, uno::Any( xStyle ) );
+ xStyle.set(xStyles->getByName(sConvertedStyleName), uno::UNO_QUERY_THROW);
+
+ StyleSheetPropertyMap* pPropertyMap = pEntry->m_pProperties.get();
+ if (pPropertyMap && pPropertyMap->props().GetListId() == -1)
+ {
+ // No properties? Word default is 'none', Writer one is 'arabic', handle this.
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexReplace> xNumberingRules;
+ xPropertySet->getPropertyValue("NumberingRules") >>= xNumberingRules;
+ uno::Reference<container::XIndexAccess> xIndexAccess(xNumberingRules, uno::UNO_QUERY_THROW);
+ for (sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i)
+ {
+ uno::Sequence< beans::PropertyValue > aLvlProps{
+ comphelper::makePropertyValue(
+ "NumberingType", style::NumberingType::NUMBER_NONE)
+ };
+ xNumberingRules->replaceByIndex(i, uno::Any(aLvlProps));
+ xPropertySet->setPropertyValue("NumberingRules", uno::Any(xNumberingRules));
+ }
+ }
+ }
+ }
+ if( !pEntry->m_sBaseStyleIdentifier.isEmpty() )
+ {
+ try
+ {
+ //TODO: Handle cases where a paragraph <> character style relation is needed
+ StyleSheetEntryPtr pParent = FindStyleSheetByISTD( pEntry->m_sBaseStyleIdentifier );
+ // Writer core doesn't support numbering styles having a parent style, it seems
+ if (pParent && !bListStyle)
+ {
+ const OUString sParentStyleName = ConvertStyleName( pParent->m_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->m_pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false );
+
+ //now it's time to set the default parameters - for paragraph styles
+ //Fonts: Western first entry in font table
+ //CJK: second entry
+ //CTL: third entry, if it exists
+
+ sal_uInt32 nFontCount = rFontTable->size();
+ if( !m_pImpl->m_rDMapper.IsOOXMLImport() && nFontCount > 2 )
+ {
+ uno::Any aTwoHundredFortyTwip(12.);
+
+ // font size to 240 twip (12 pts) for all if not set
+ pEntry->m_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->m_pProperties->Insert(PROP_CHAR_FONT_NAME, uno::Any( sWesternFontName ), false);
+
+ // CJK ... apply second font
+ const FontEntry::Pointer_t pCJKFontEntry(rFontTable->getFontEntry( 2 ));
+ pEntry->m_pProperties->Insert(PROP_CHAR_FONT_NAME_ASIAN, uno::Any( pCJKFontEntry->sFontName ), false);
+ pEntry->m_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->m_pProperties->Insert(PROP_CHAR_FONT_NAME_COMPLEX, uno::Any( pCTLFontEntry->sFontName ), false);
+ pEntry->m_pProperties->Insert(PROP_CHAR_HEIGHT_COMPLEX, aTwoHundredFortyTwip, false);
+ }
+ }
+ }
+
+ auto aPropValues = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(pEntry->m_pProperties->GetPropertyValues());
+
+ if (bParaStyle || bCharStyle)
+ {
+ // delay adding LinkStyle property: all styles need to be created first
+ if (!pEntry->m_sLinkStyleIdentifier.isEmpty())
+ {
+ StyleSheetEntryPtr pLinkStyle
+ = FindStyleSheetByISTD(pEntry->m_sLinkStyleIdentifier);
+ if (pLinkStyle && !pLinkStyle->m_sStyleName.isEmpty())
+ aMissingLink.emplace_back(ConvertStyleName(pLinkStyle->m_sStyleName),
+ xStyle);
+ }
+ }
+
+ if( bParaStyle )
+ {
+ // delay adding FollowStyle property: all styles need to be created first
+ if ( !pEntry->m_sNextStyleIdentifier.isEmpty() )
+ {
+ StyleSheetEntryPtr pFollowStyle = FindStyleSheetByISTD( pEntry->m_sNextStyleIdentifier );
+ if ( pFollowStyle && !pFollowStyle->m_sStyleName.isEmpty() )
+ aMissingFollow.emplace_back( ConvertStyleName( pFollowStyle->m_sStyleName ), xStyle );
+ }
+
+ // Set the outline levels
+ StyleSheetPropertyMap* pStyleSheetProperties = pEntry ? pEntry->m_pProperties.get() : nullptr;
+
+ if ( pStyleSheetProperties )
+ {
+ sal_Int16 nLvl = pStyleSheetProperties->GetOutlineLevel();
+ // convert MS body Level (9) to LO body level (0) and equivalent outline levels
+ if (nLvl != -1)
+ {
+ if (nLvl == WW_OUTLINE_MAX)
+ nLvl = 0;
+ else
+ ++nLvl;
+
+ beans::PropertyValue aLvlVal(getPropertyName(PROP_OUTLINE_LEVEL), 0,
+ uno::Any(nLvl),
+ beans::PropertyState_DIRECT_VALUE);
+ aPropValues.push_back(aLvlVal);
+ }
+ }
+
+ uno::Reference< beans::XPropertyState >xState( xStyle, uno::UNO_QUERY_THROW );
+ if( sConvertedStyleName == "Contents Heading" ||
+ sConvertedStyleName == "User Index Heading" ||
+ sConvertedStyleName == "Index Heading" )
+ {
+ // remove Left/RightMargin values from TOX heading styles
+ //left margin is set to NULL by default
+ xState->setPropertyToDefault(getPropertyName( PROP_PARA_LEFT_MARGIN ));
+ }
+ else if ( sConvertedStyleName == "Text body" )
+ xState->setPropertyToDefault(getPropertyName( PROP_PARA_BOTTOM_MARGIN ));
+ else if ( sConvertedStyleName == "Heading 1" ||
+ sConvertedStyleName == "Heading 2" ||
+ sConvertedStyleName == "Heading 3" ||
+ sConvertedStyleName == "Heading 4" ||
+ sConvertedStyleName == "Heading 5" ||
+ sConvertedStyleName == "Heading 6" ||
+ sConvertedStyleName == "Heading 7" ||
+ sConvertedStyleName == "Heading 8" ||
+ sConvertedStyleName == "Heading 9" )
+ {
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT_ASIAN ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_WEIGHT_COMPLEX ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE_ASIAN ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_POSTURE_COMPLEX ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_ASIAN ));
+ xState->setPropertyToDefault(getPropertyName( PROP_CHAR_PROP_HEIGHT_COMPLEX));
+
+ }
+ }
+
+ if ( !aPropValues.empty() )
+ {
+ PropValVector aSortedPropVals;
+ for (const beans::PropertyValue& rValue : aPropValues)
+ {
+ // Don't add the style name properties
+ bool bIsParaStyleName = rValue.Name == "ParaStyleName";
+ bool bIsCharStyleName = rValue.Name == "CharStyleName";
+ if ( !bIsParaStyleName && !bIsCharStyleName )
+ {
+ aSortedPropVals.Insert(rValue);
+ }
+ }
+
+ try
+ {
+ uno::Reference< beans::XMultiPropertySet > xMultiPropertySet( xStyle, uno::UNO_QUERY_THROW);
+ try
+ {
+ xMultiPropertySet->setPropertyValues( aSortedPropVals.getNames(), aSortedPropVals.getValues() );
+ }
+ catch ( const uno::Exception& )
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY_THROW);
+ for ( const beans::PropertyValue& rValue : aSortedPropVals.getProperties() )
+ {
+ try
+ {
+ xPropertySet->setPropertyValue( rValue.Name, rValue.Value );
+ }
+ catch ( const uno::Exception& )
+ {
+ SAL_WARN( "writerfilter", "StyleSheetTable::ApplyStyleSheets could not set property " << rValue.Name );
+ }
+ }
+ }
+ // Duplicate MSWord's single footnote reference into Footnote Characters and Footnote anchor
+ if( pEntry->m_sStyleName.equalsIgnoreAsciiCase("footnote reference")
+ || pEntry->m_sStyleName.equalsIgnoreAsciiCase("endnote reference") )
+ {
+ uno::Reference< style::XStyle > xCopyStyle;
+ if( pEntry->m_sStyleName.equalsIgnoreAsciiCase("footnote reference") )
+ xStyles->getByName( "Footnote anchor" ) >>= xCopyStyle;
+ else
+ xStyles->getByName( "Endnote anchor" ) >>= xCopyStyle;
+
+ xMultiPropertySet.set( xCopyStyle, uno::UNO_QUERY_THROW);
+ xMultiPropertySet->setPropertyValues( aSortedPropVals.getNames(), aSortedPropVals.getValues() );
+ }
+ }
+ catch( const lang::WrappedTargetException& rWrapped)
+ {
+#ifdef DBG_UTIL
+ OUString aMessage("StyleSheetTable::ApplyStyleSheets: Some style properties could not be set");
+ beans::UnknownPropertyException aUnknownPropertyException;
+
+ if (rWrapped.TargetException >>= aUnknownPropertyException)
+ aMessage += ": " + aUnknownPropertyException.Message;
+
+ SAL_WARN("writerfilter", aMessage);
+#else
+ (void) rWrapped;
+#endif
+ }
+ catch( const uno::Exception& )
+ {
+ OSL_FAIL( "Some style properties could not be set");
+ }
+ }
+ // Numbering style got inserted earlier.
+ if(bInsert && !bListStyle)
+ {
+ const OUString sParentStyle = xStyle->getParentStyle();
+ if( !sParentStyle.isEmpty() && !xStyles->hasByName( sParentStyle ) )
+ aMissingParent.emplace_back( sParentStyle, xStyle );
+
+ xStyles->insertByName( sConvertedStyleName, uno::Any( xStyle) );
+ }
+
+ beans::PropertyValues aGrabBag = pEntry->GetInteropGrabBagSeq();
+ uno::Reference<beans::XPropertySet> xPropertySet(xStyle, uno::UNO_QUERY);
+ if (aGrabBag.hasElements())
+ {
+ xPropertySet->setPropertyValue("StyleInteropGrabBag", uno::Any(aGrabBag));
+ }
+
+ // Only paragraph styles support automatic updates.
+ if (pEntry->m_bAutoRedefine && bParaStyle)
+ xPropertySet->setPropertyValue("IsAutoUpdate", uno::Any(true));
+ }
+ else if(pEntry->m_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->m_pProperties->InsertProps( m_pImpl->m_pDefaultCharProps, /*bOverwrite=*/false );
+ pEntry->m_pProperties->InsertProps( m_pImpl->m_pDefaultParaProps, /*bOverwrite=*/false );
+ }
+ }
+
+ // Update the styles that were created before their parents or next-styles
+ for( auto const & iter : aMissingParent )
+ {
+ iter.second->setParentStyle( iter.first );
+ }
+
+ for( auto const & iter : aMissingFollow )
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(iter.second, uno::UNO_QUERY);
+ xPropertySet->setPropertyValue( "FollowStyle", uno::Any(iter.first) );
+ }
+ catch( uno::Exception & ) {}
+ }
+
+ // Update the styles that were created before their linked styles.
+ for (auto const& rLinked : aMissingLink)
+ {
+ try
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(rLinked.second,
+ uno::UNO_QUERY);
+ xPropertySet->setPropertyValue("LinkStyle", uno::Any(rLinked.first));
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION(
+ "writerfilter",
+ "StyleSheetTable::ApplyStyleSheets: failed to set LinkStyle");
+ }
+ }
+
+ if (!aTableStylesVec.empty())
+ {
+ // If we had any table styles, add a new document-level InteropGrabBag entry for them.
+ uno::Reference<beans::XPropertySet> xPropertySet(m_pImpl->m_xTextDocument, uno::UNO_QUERY);
+ uno::Any aAny = xPropertySet->getPropertyValue("InteropGrabBag");
+ auto aGrabBag = comphelper::sequenceToContainer< std::vector<beans::PropertyValue> >(aAny.get< uno::Sequence<beans::PropertyValue> >());
+ beans::PropertyValue aValue;
+ aValue.Name = "tableStyles";
+ aValue.Value <<= comphelper::containerToSequence(aTableStylesVec);
+ aGrabBag.push_back(aValue);
+ xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(comphelper::containerToSequence(aGrabBag)));
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("writerfilter", "Styles could not be imported completely");
+ }
+}
+
+
+StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByISTD(const OUString& sIndex)
+{
+ auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(sIndex);
+ if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end())
+ return findIt->second;
+ return StyleSheetEntryPtr();
+}
+
+
+StyleSheetEntryPtr StyleSheetTable::FindStyleSheetByConvertedStyleName(std::u16string_view sIndex)
+{
+ StyleSheetEntryPtr pRet;
+ for(const StyleSheetEntryPtr & rpEntry : m_pImpl->m_aStyleSheetEntries)
+ {
+ if( rpEntry->m_sConvertedStyleName == sIndex)
+ {
+ pRet = rpEntry;
+ break;
+ }
+ }
+ return pRet;
+}
+
+
+StyleSheetEntryPtr StyleSheetTable::FindDefaultParaStyle()
+{
+ return FindStyleSheetByISTD( m_pImpl->m_sDefaultParaStyleName );
+}
+
+const StyleSheetEntryPtr & StyleSheetTable::GetCurrentEntry() const
+{
+ return m_pImpl->m_pCurrentEntry;
+}
+
+OUString StyleSheetTable::ConvertStyleName( const OUString& rWWName, bool bExtendedSearch)
+{
+ OUString sRet( rWWName );
+ if( bExtendedSearch )
+ {
+ //search for the rWWName in the IdentifierD of the existing styles and convert the sStyleName member
+ auto findIt = m_pImpl->m_aStyleSheetEntriesMap.find(rWWName);
+ if (findIt != m_pImpl->m_aStyleSheetEntriesMap.end())
+ {
+ if (!findIt->second->m_sConvertedStyleName.isEmpty())
+ return findIt->second->m_sConvertedStyleName;
+ sRet = findIt->second->m_sStyleName;
+ }
+ }
+
+ // create a map only once
+ // This maps Word's special style manes to Writer's (the opposite to what MSWordStyles::GetWWId
+ // and ww::GetEnglishNameFromSti do on export). The mapping gives a Writer's style name, which
+ // will point to a style with specific RES_POOL* in its m_nPoolFormatId. Then on export, the
+ // pool format id will map to a ww::sti enum value, and finally to a Word style name. Keep this
+ // part in sync with the export functions mentioned above!
+ // In addition to "standard" names, some case variations are handled here; and also there are
+ // a number of strange mappings like "BodyTextIndentItalic" -> "Text body indent italic", which
+ // map something unused in Word to something unused in Writer :-/
+ static const std::map< OUString, OUString> StyleNameMap {
+ { "Normal", "Standard" }, // RES_POOLCOLL_STANDARD
+ { "heading 1", "Heading 1" }, // RES_POOLCOLL_HEADLINE1
+ { "heading 2", "Heading 2" }, // RES_POOLCOLL_HEADLINE2
+ { "heading 3", "Heading 3" }, // RES_POOLCOLL_HEADLINE3
+ { "heading 4", "Heading 4" }, // RES_POOLCOLL_HEADLINE4
+ { "heading 5", "Heading 5" }, // RES_POOLCOLL_HEADLINE5
+ { "heading 6", "Heading 6" }, // RES_POOLCOLL_HEADLINE6
+ { "heading 7", "Heading 7" }, // RES_POOLCOLL_HEADLINE7
+ { "heading 8", "Heading 8" }, // RES_POOLCOLL_HEADLINE8
+ { "heading 9", "Heading 9" }, // RES_POOLCOLL_HEADLINE9
+ { "Heading 1", "Heading 1" }, // RES_POOLCOLL_HEADLINE1
+ { "Heading 2", "Heading 2" }, // RES_POOLCOLL_HEADLINE2
+ { "Heading 3", "Heading 3" }, // RES_POOLCOLL_HEADLINE3
+ { "Heading 4", "Heading 4" }, // RES_POOLCOLL_HEADLINE4
+ { "Heading 5", "Heading 5" }, // RES_POOLCOLL_HEADLINE5
+ { "Heading 6", "Heading 6" }, // RES_POOLCOLL_HEADLINE6
+ { "Heading 7", "Heading 7" }, // RES_POOLCOLL_HEADLINE7
+ { "Heading 8", "Heading 8" }, // RES_POOLCOLL_HEADLINE8
+ { "Heading 9", "Heading 9" }, // RES_POOLCOLL_HEADLINE9
+ { "Index 1", "Index 1" }, // RES_POOLCOLL_TOX_IDX1
+ { "Index 2", "Index 2" }, // RES_POOLCOLL_TOX_IDX2
+ { "Index 3", "Index 3" }, // RES_POOLCOLL_TOX_IDX3
+// { "Index 4", "" },
+// { "Index 5", "" },
+// { "Index 6", "" },
+// { "Index 7", "" },
+// { "Index 8", "" },
+// { "Index 9", "" },
+ { "TOC 1", "Contents 1" }, // RES_POOLCOLL_TOX_CNTNT1
+ { "TOC 2", "Contents 2" }, // RES_POOLCOLL_TOX_CNTNT2
+ { "TOC 3", "Contents 3" }, // RES_POOLCOLL_TOX_CNTNT3
+ { "TOC 4", "Contents 4" }, // RES_POOLCOLL_TOX_CNTNT4
+ { "TOC 5", "Contents 5" }, // RES_POOLCOLL_TOX_CNTNT5
+ { "TOC 6", "Contents 6" }, // RES_POOLCOLL_TOX_CNTNT6
+ { "TOC 7", "Contents 7" }, // RES_POOLCOLL_TOX_CNTNT7
+ { "TOC 8", "Contents 8" }, // RES_POOLCOLL_TOX_CNTNT8
+ { "TOC 9", "Contents 9" }, // RES_POOLCOLL_TOX_CNTNT9
+ { "TOC Heading", "Contents Heading" }, // RES_POOLCOLL_TOX_CNTNTH
+ { "TOCHeading", "Contents Heading" }, // RES_POOLCOLL_TOX_CNTNTH
+ { "toc 1", "Contents 1" }, // RES_POOLCOLL_TOX_CNTNT1
+ { "toc 2", "Contents 2" }, // RES_POOLCOLL_TOX_CNTNT2
+ { "toc 3", "Contents 3" }, // RES_POOLCOLL_TOX_CNTNT3
+ { "toc 4", "Contents 4" }, // RES_POOLCOLL_TOX_CNTNT4
+ { "toc 5", "Contents 5" }, // RES_POOLCOLL_TOX_CNTNT5
+ { "toc 6", "Contents 6" }, // RES_POOLCOLL_TOX_CNTNT6
+ { "toc 7", "Contents 7" }, // RES_POOLCOLL_TOX_CNTNT7
+ { "toc 8", "Contents 8" }, // RES_POOLCOLL_TOX_CNTNT8
+ { "toc 9", "Contents 9" }, // RES_POOLCOLL_TOX_CNTNT9
+ { "TOC1", "Contents 1" }, // RES_POOLCOLL_TOX_CNTNT1
+ { "TOC2", "Contents 2" }, // RES_POOLCOLL_TOX_CNTNT2
+ { "TOC3", "Contents 3" }, // RES_POOLCOLL_TOX_CNTNT3
+ { "TOC4", "Contents 4" }, // RES_POOLCOLL_TOX_CNTNT4
+ { "TOC5", "Contents 5" }, // RES_POOLCOLL_TOX_CNTNT5
+ { "TOC6", "Contents 6" }, // RES_POOLCOLL_TOX_CNTNT6
+ { "TOC7", "Contents 7" }, // RES_POOLCOLL_TOX_CNTNT7
+ { "TOC8", "Contents 8" }, // RES_POOLCOLL_TOX_CNTNT8
+ { "TOC9", "Contents 9" }, // RES_POOLCOLL_TOX_CNTNT9
+// { "Normal Indent", "" },
+ { "footnote text", "Footnote" }, // RES_POOLCOLL_FOOTNOTE
+ { "Footnote Text", "Footnote" }, // RES_POOLCOLL_FOOTNOTE
+ { "Annotation Text", "Marginalia" }, // RES_POOLCOLL_MARGINAL
+ { "Header", "Header" }, // RES_POOLCOLL_HEADER
+ { "header", "Header" }, // RES_POOLCOLL_HEADER
+ { "Footer", "Footer" }, // RES_POOLCOLL_FOOTER
+ { "footer", "Footer" }, // RES_POOLCOLL_FOOTER
+ { "Index Heading", "Index Heading" }, // RES_POOLCOLL_TOX_IDXH
+ { "Caption", "Caption" }, // RES_POOLCOLL_LABEL
+ { "table of figures", "Figure Index 1" }, // RES_POOLCOLL_TOX_ILLUS1
+ { "Table of Figures", "Figure Index 1" }, // RES_POOLCOLL_TOX_ILLUS1
+ { "Envelope Address", "Addressee" }, // RES_POOLCOLL_ENVELOPE_ADDRESS
+ { "Envelope Return", "Sender" }, // RES_POOLCOLL_SEND_ADDRESS
+ { "footnote reference", "Footnote Symbol" }, // RES_POOLCHR_FOOTNOTE; tdf#82173
+ { "Footnote Reference", "Footnote Symbol" }, // RES_POOLCHR_FOOTNOTE; tdf#82173
+// { "Annotation Reference", "" },
+ { "Line Number", "Line numbering" }, // RES_POOLCHR_LINENUM
+ { "Page Number", "Page Number" }, // RES_POOLCHR_PAGENO
+ { "endnote reference", "Endnote Symbol" }, // RES_POOLCHR_ENDNOTE; tdf#82173
+ { "Endnote Reference", "Endnote Symbol" }, // RES_POOLCHR_ENDNOTE; tdf#82173
+ { "endnote text", "Endnote" }, // RES_POOLCOLL_ENDNOTE
+ { "Endnote Text", "Endnote" }, // RES_POOLCOLL_ENDNOTE
+ { "Table of Authorities", "Bibliography Heading" }, // RES_POOLCOLL_TOX_AUTHORITIESH
+// { "Macro Text", "" },
+// { "TOA Heading", "" },
+ { "List", "List" }, // RES_POOLCOLL_NUMBER_BULLET_BASE
+// { "List 2", "" },
+// { "List 3", "" },
+// { "List 4", "" },
+// { "List 5", "" },
+ { "List Bullet", "List 1" }, // RES_POOLCOLL_BULLET_LEVEL1
+ { "List Bullet 2", "List 2" }, // RES_POOLCOLL_BULLET_LEVEL2
+ { "List Bullet 3", "List 3" }, // RES_POOLCOLL_BULLET_LEVEL3
+ { "List Bullet 4", "List 4" }, // RES_POOLCOLL_BULLET_LEVEL4
+ { "List Bullet 5", "List 5" }, // RES_POOLCOLL_BULLET_LEVEL5
+ { "List Number", "Numbering 1" }, // RES_POOLCOLL_NUM_LEVEL1
+ { "List Number 2", "Numbering 2" }, // RES_POOLCOLL_NUM_LEVEL2
+ { "List Number 3", "Numbering 3" }, // RES_POOLCOLL_NUM_LEVEL3
+ { "List Number 4", "Numbering 4" }, // RES_POOLCOLL_NUM_LEVEL4
+ { "List Number 5", "Numbering 5" }, // RES_POOLCOLL_NUM_LEVEL5
+ { "Title", "Title" }, // RES_POOLCOLL_DOC_TITLE
+ { "Closing", "Appendix" }, // RES_POOLCOLL_DOC_APPENDIX
+ { "Signature", "Signature" }, // RES_POOLCOLL_SIGNATURE
+// { "Default Paragraph Font", "" },
+ { "DefaultParagraphFont", "Default Paragraph Font" },
+ { "Body Text", "Text body" }, // RES_POOLCOLL_TEXT
+ { "BodyText", "Text body" }, // RES_POOLCOLL_TEXT
+ { "BodyTextIndentItalic", "Text body indent italic" },
+ { "Body Text Indent", "Text body indent" }, // RES_POOLCOLL_TEXT_MOVE
+ { "BodyTextIndent", "Text body indent" }, // RES_POOLCOLL_TEXT_MOVE
+ { "BodyTextIndent2", "Text body indent2" },
+ { "List Continue", "List 1 Cont." }, // RES_POOLCOLL_BULLET_NONUM1
+ { "List Continue 2", "List 2 Cont." }, // RES_POOLCOLL_BULLET_NONUM2
+ { "List Continue 3", "List 3 Cont." }, // RES_POOLCOLL_BULLET_NONUM3
+ { "List Continue 4", "List 4 Cont." }, // RES_POOLCOLL_BULLET_NONUM4
+ { "List Continue 5", "List 5 Cont." }, // RES_POOLCOLL_BULLET_NONUM5
+// { "Message Header", "" },
+ { "Subtitle", "Subtitle" }, // RES_POOLCOLL_DOC_SUBTITLE
+ { "Salutation", "Salutation" }, // RES_POOLCOLL_GREETING
+// { "Date", "" },
+ { "Body Text First Indent", "First line indent" }, // RES_POOLCOLL_TEXT_IDENT
+// { "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" }, // RES_POOLCHR_INET_NORMAL
+ { "FollowedHyperlink", "Visited Internet Link" }, // RES_POOLCHR_INET_VISIT
+ { "Strong", "Strong Emphasis" }, // RES_POOLCHR_HTML_STRONG
+ { "Emphasis", "Emphasis" }, // RES_POOLCHR_HTML_EMPHASIS
+// { "Document Map", "" },
+// { "Plain Text", "" },
+ { "NoList", "No List" },
+ { "AbstractHeading", "Abstract Heading" },
+ { "AbstractBody", "Abstract Body" },
+ { "PageNumber", "Page Number" }, // RES_POOLCHR_PAGENO
+ { "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;
+ }();
+ // Similar to SwStyleNameMapper convention (where a " (user)" suffix is used to
+ // disambiguate user styles with reserved names in localization where respective
+ // built-in styles have different UI names), we add a " (WW)" suffix here. Unlike
+ // the " (user)" suffix, it is not hidden from the UI; it will be handled when
+ // exported to Word formats - see MSWordStyles::BuildWwNames.
+ // We can't use the " (user)" suffix, because that system is built upon the assumption
+ // that UI names of respective built-in styles are different from the user style name.
+ // That is not necessarily true here, since the current localization may not change
+ // the UI names of built-in styles.
+ if (ReservedStyleNames.find(sRet) != ReservedStyleNames.end() || sRet.endsWith(" (WW)"))
+ sRet += " (WW)";
+ }
+
+ return sRet;
+}
+
+void StyleSheetTable::applyDefaults(bool bParaProperties)
+{
+ try{
+
+ if (!m_pImpl->m_bIsNewDoc)
+ {
+ // tdf#72942: do not corrupts original styles in master document
+ // during inserting of text from second document
+ return;
+ }
+
+ if(!m_pImpl->m_xTextDefaults.is())
+ {
+ m_pImpl->m_xTextDefaults.set(
+ m_pImpl->m_rDMapper.GetTextFactory()->createInstance("com.sun.star.text.Defaults"),
+ uno::UNO_QUERY_THROW );
+ }
+
+ // WARNING: these defaults only take effect IF there is a DocDefaults style section. Normally there is, but not always.
+ if( bParaProperties && m_pImpl->m_pDefaultParaProps)
+ {
+ // tdf#87533 LO will have different defaults here, depending on the locale. Import with documented defaults
+ SetDefaultParaProps(PROP_WRITING_MODE, uno::Any(sal_Int16(text::WritingMode_LR_TB)));
+ SetDefaultParaProps(PROP_PARA_ADJUST, uno::Any(sal_Int16(style::ParagraphAdjust_LEFT)));
+
+ // Widow/Orphan -> set both to two if not already set
+ uno::Any aTwo(sal_Int8(2));
+ SetDefaultParaProps(PROP_PARA_WIDOWS, aTwo);
+ SetDefaultParaProps(PROP_PARA_ORPHANS, aTwo);
+
+ uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(m_pImpl->m_xTextDocument, uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xParagraphStyles;
+ xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles;
+ uno::Reference<beans::XPropertySet> xDefault;
+ // This is the built-in default style that every style inherits from
+ xParagraphStyles->getByName("Paragraph style") >>= xDefault;
+
+ const uno::Sequence< beans::PropertyValue > aPropValues = m_pImpl->m_pDefaultParaProps->GetPropertyValues();
+ for( const auto& rPropValue : aPropValues )
+ {
+ try
+ {
+ xDefault->setPropertyValue(rPropValue.Name, rPropValue.Value);
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "setPropertyValue");
+ }
+ }
+ }
+ if( !bParaProperties && m_pImpl->m_pDefaultCharProps )
+ {
+ // tdf#108350: Earlier in DomainMapper for DOCX, Calibri/11pt was set to match MSWord 2007+,
+ // but that is valid only if DocDefaults_rPrDefault is omitted.
+ // Now that DocDefaults_rPrDefault is known, the defaults should be reset to Times New Roman/10pt.
+ if ( m_pImpl->m_rDMapper.IsOOXMLImport() )
+ m_pImpl->m_xTextDefaults->setPropertyValue( getPropertyName(PROP_CHAR_FONT_NAME), css::uno::Any(OUString("Times New Roman")) );
+
+ const uno::Sequence< beans::PropertyValue > aPropValues = m_pImpl->m_pDefaultCharProps->GetPropertyValues();
+ for( const auto& rPropValue : aPropValues )
+ {
+ try
+ {
+ m_pImpl->m_xTextDefaults->setPropertyValue( rPropValue.Name, rPropValue.Value );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "exception");
+ }
+ }
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+}
+
+
+OUString StyleSheetTable::getOrCreateCharStyle( PropertyValueVector_t& rCharProperties, bool bAlwaysCreate )
+{
+ //find out if any of the styles already has the required properties then return its name
+ OUString sListLabel = m_pImpl->HasListCharStyle(rCharProperties);
+ // Don't try to reuse an existing character style if requested.
+ if( !sListLabel.isEmpty() && !bAlwaysCreate)
+ return sListLabel;
+
+ //create a new one otherwise
+ const uno::Reference< container::XNameContainer >& xCharStyles = m_pImpl->m_rDMapper.GetCharacterStyles();
+ sListLabel = m_pImpl->m_rDMapper.GetUnusedCharacterStyleName();
+ uno::Reference< lang::XMultiServiceFactory > xDocFactory( m_pImpl->m_xTextDocument, uno::UNO_QUERY_THROW );
+ try
+ {
+ uno::Reference< style::XStyle > xStyle( xDocFactory->createInstance(
+ getPropertyName( PROP_SERVICE_CHAR_STYLE )), uno::UNO_QUERY_THROW);
+ uno::Reference< beans::XPropertySet > xStyleProps(xStyle, uno::UNO_QUERY_THROW );
+ for( const auto& rCharProp : rCharProperties)
+ {
+ try
+ {
+ xStyleProps->setPropertyValue( rCharProp.Name, rCharProp.Value );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "StyleSheetTable::getOrCreateCharStyle - Style::setPropertyValue");
+ }
+ }
+ xCharStyles->insertByName( sListLabel, uno::Any( xStyle) );
+ m_pImpl->m_aListCharStylePropertyVector.emplace_back( sListLabel, std::vector(rCharProperties) );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "writerfilter", "StyleSheetTable::getOrCreateCharStyle");
+ }
+
+ return sListLabel;
+}
+
+}//namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/StyleSheetTable.hxx b/sw/source/writerfilter/dmapper/StyleSheetTable.hxx
new file mode 100644
index 000000000000..2308257a32b2
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/StyleSheetTable.hxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <memory>
+#include "TblStylePrHandler.hxx"
+
+#include "DomainMapper.hxx"
+#include <com/sun/star/beans/PropertyValues.hpp>
+#include "PropertyMap.hxx"
+#include "FontTable.hxx"
+#include "LoggedResources.hxx"
+
+namespace com::sun::star::text { class XTextDocument; }
+
+
+namespace writerfilter::dmapper
+{
+
+
+enum StyleType
+{
+ STYLE_TYPE_UNKNOWN,
+ STYLE_TYPE_PARA,
+ STYLE_TYPE_CHAR,
+ STYLE_TYPE_TABLE,
+ STYLE_TYPE_LIST
+};
+class StyleSheetTable;
+typedef tools::SvRef<StyleSheetTable> StyleSheetTablePtr;
+
+struct StyleSheetTable_Impl;
+class StyleSheetEntry : public virtual SvRefBase
+{
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+public:
+ OUString m_sStyleIdentifierD; // WW8 name
+ bool m_bIsDefaultStyle;
+ bool m_bAssignedAsChapterNumbering;
+ bool m_bInvalidHeight;
+ bool m_bHasUPE; //universal property expansion
+ StyleType m_nStyleTypeCode; //sgc
+ OUString m_sBaseStyleIdentifier;
+ OUString m_sNextStyleIdentifier;
+ OUString m_sLinkStyleIdentifier;
+ OUString m_sStyleName;
+ const tools::SvRef<StyleSheetPropertyMap> m_pProperties;
+ OUString m_sConvertedStyleName;
+ std::vector<css::beans::PropertyValue> m_aLatentStyles; ///< Attributes of latentStyles
+ std::vector<css::beans::PropertyValue> m_aLsdExceptions; ///< List of lsdException attribute lists
+ bool m_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();
+ StyleSheetEntry(StyleSheetEntry const&) = default;
+ virtual ~StyleSheetEntry() override;
+};
+
+typedef tools::SvRef<StyleSheetEntry> StyleSheetEntryPtr;
+
+class DomainMapper;
+class StyleSheetTable :
+ public LoggedProperties,
+ public LoggedTable
+{
+ std::unique_ptr<StyleSheetTable_Impl> m_pImpl;
+
+public:
+ StyleSheetTable(DomainMapper& rDMapper, css::uno::Reference<css::text::XTextDocument> const& xTextDocument, bool bIsNewDoc);
+ virtual ~StyleSheetTable() override;
+
+ void ReApplyInheritedOutlineLevelFromChapterNumbering();
+ void ApplyNumberingStyleNameToParaStyles();
+ void ApplyStyleSheets( const FontTablePtr& rFontTable );
+ StyleSheetEntryPtr FindStyleSheetByISTD(const OUString& sIndex);
+ StyleSheetEntryPtr FindStyleSheetByConvertedStyleName(std::u16string_view rIndex);
+ StyleSheetEntryPtr FindDefaultParaStyle();
+
+ OUString ConvertStyleName( const OUString& rWWName, bool bExtendedSearch = false );
+ OUString CloneTOCStyle(FontTablePtr const& rFontTable, StyleSheetEntryPtr const pStyle, OUString const& rName);
+ void ApplyClonedTOCStyles();
+
+ 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(const writerfilter::Reference<Properties>::Pointer_t& ref) override;
+
+ void applyDefaults(bool bParaProperties);
+
+ void ApplyStyleSheetsImpl(const FontTablePtr& rFontTable, std::vector<StyleSheetEntryPtr> const& rEntries);
+};
+
+
+class TableStyleSheetEntry :
+ public StyleSheetEntry
+{
+public:
+ // Adds a new tblStylePr to the table style entry. This method
+ // fixes some possible properties conflicts, like borders ones.
+ void AddTblStylePr( TblStyleType nType, const PropertyMapPtr& pProps );
+
+ // Gets all the properties
+ // + corresponding to the mask,
+ // + from the parent styles
+
+ // @param mask mask describing which properties to return
+ PropertyMapPtr GetProperties( sal_Int32 nMask);
+
+ TableStyleSheetEntry( StyleSheetEntry const & aEntry );
+ virtual ~TableStyleSheetEntry( ) override;
+
+private:
+ typedef std::map<TblStyleType, PropertyMapPtr> TblStylePrs;
+ TblStylePrs m_aStyles;
+ PropertyMapPtr GetLocalPropertiesFromMask( sal_Int32 nMask );
+};
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TDefTableHandler.cxx b/sw/source/writerfilter/dmapper/TDefTableHandler.cxx
new file mode 100644
index 000000000000..9626beb595bc
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TDefTableHandler.cxx
@@ -0,0 +1,538 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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();
+}
+
+model::ThemeColorType TDefTableHandler::getThemeColorTypeIndex(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_Value_St_ThemeColor_dark1:
+ return model::ThemeColorType::Dark1;
+ case NS_ooxml::LN_Value_St_ThemeColor_light1:
+ return model::ThemeColorType::Light1;
+ case NS_ooxml::LN_Value_St_ThemeColor_dark2:
+ return model::ThemeColorType::Dark2;
+ case NS_ooxml::LN_Value_St_ThemeColor_light2:
+ return model::ThemeColorType::Light2;
+ case NS_ooxml::LN_Value_St_ThemeColor_accent1:
+ return model::ThemeColorType::Accent1;
+ case NS_ooxml::LN_Value_St_ThemeColor_accent2:
+ return model::ThemeColorType::Accent2;
+ case NS_ooxml::LN_Value_St_ThemeColor_accent3:
+ return model::ThemeColorType::Accent3;
+ case NS_ooxml::LN_Value_St_ThemeColor_accent4:
+ return model::ThemeColorType::Accent4;
+ case NS_ooxml::LN_Value_St_ThemeColor_accent5:
+ return model::ThemeColorType::Accent5;
+ case NS_ooxml::LN_Value_St_ThemeColor_accent6:
+ return model::ThemeColorType::Accent6;
+ case NS_ooxml::LN_Value_St_ThemeColor_hyperlink:
+ return model::ThemeColorType::Hyperlink;
+ case NS_ooxml::LN_Value_St_ThemeColor_followedHyperlink:
+ return model::ThemeColorType::FollowedHyperlink;
+ case NS_ooxml::LN_Value_St_ThemeColor_none:
+ return model::ThemeColorType::Unknown;
+ case NS_ooxml::LN_Value_St_ThemeColor_background1:
+ return model::ThemeColorType::Light1;
+ case NS_ooxml::LN_Value_St_ThemeColor_text1:
+ return model::ThemeColorType::Dark1;
+ case NS_ooxml::LN_Value_St_ThemeColor_background2:
+ return model::ThemeColorType::Light2;
+ case NS_ooxml::LN_Value_St_ThemeColor_text2:
+ return model::ThemeColorType::Dark2;
+ default:
+ break;
+ }
+ return model::ThemeColorType::Unknown;
+}
+
+model::ThemeColorUsage TDefTableHandler::getThemeColorUsage(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_Value_St_ThemeColor_background1:
+ case NS_ooxml::LN_Value_St_ThemeColor_background2:
+ return model::ThemeColorUsage::Background;
+ case NS_ooxml::LN_Value_St_ThemeColor_text1:
+ case NS_ooxml::LN_Value_St_ThemeColor_text2:
+ return model::ThemeColorUsage::Text;
+ default:
+ break;
+ }
+ return model::ThemeColorUsage::Unknown;
+}
+
+void TDefTableHandler::lcl_attribute(Id rName, Value & rVal)
+{
+ sal_Int32 nIntValue = rVal.getInt();
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_Border_sz:
+ // width of a single line in 1/8 pt, max of 32 pt -> twip * 5 / 2.
+ m_nLineWidth = nIntValue * 5 / 2;
+ appendGrabBag("sz", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_val:
+ m_nLineType = nIntValue;
+ appendGrabBag("val", TDefTableHandler::getBorderTypeString(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_color:
+ appendGrabBag("color", msfilter::util::ConvertColorOU(Color(ColorTransparency,nIntValue)));
+ m_nLineColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Border_space:
+ appendGrabBag("space", OUString::number(nIntValue));
+ break;
+ case NS_ooxml::LN_CT_Border_shadow:
+ //if 1 then line has shadow - unsupported
+ case NS_ooxml::LN_CT_Border_frame:
+ // ignored
+ break;
+ case NS_ooxml::LN_CT_Border_themeColor:
+ appendGrabBag("themeColor", TDefTableHandler::getThemeColorTypeString(nIntValue));
+ m_eThemeColorType = TDefTableHandler::getThemeColorTypeIndex(nIntValue);
+ break;
+ case NS_ooxml::LN_CT_Border_themeTint:
+ m_nThemeTint = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Border_themeShade:
+ m_nThemeShade = nIntValue;
+ break;
+ default:
+ OSL_FAIL("unknown attribute");
+ }
+}
+
+
+void TDefTableHandler::localResolve(Id rName, const writerfilter::Reference<Properties>::Pointer_t& pProperties)
+{
+ if( !pProperties )
+ return;
+
+ m_nLineWidth = m_nLineType = m_nLineColor = 0;
+ std::vector<beans::PropertyValue> aSavedGrabBag;
+ if (!m_aInteropGrabBagName.isEmpty())
+ {
+ aSavedGrabBag = m_aInteropGrabBag;
+ m_aInteropGrabBag.clear();
+ }
+ pProperties->resolve( *this );
+ table::BorderLine2 aBorderLine;
+ ConversionHelper::MakeBorderLine(m_nLineWidth, m_nLineType, m_nLineColor, aBorderLine, /*bIsOOXML=*/true);
+ const bool rtl = false; // TODO
+ switch( rName )
+ {
+ case NS_ooxml::LN_CT_TcBorders_top:
+ m_aTopBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("top"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_start:
+ if( rtl )
+ m_aRightBorderLines.push_back(aBorderLine);
+ else
+ m_aLeftBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("start"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_left:
+ m_aLeftBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("left"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_bottom:
+ m_aBottomBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("bottom"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_end:
+ if( rtl )
+ m_aLeftBorderLines.push_back(aBorderLine);
+ else
+ m_aRightBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("end"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_right:
+ m_aRightBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("right"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_insideH:
+ m_aInsideHBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("insideH"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_insideV:
+ m_aInsideVBorderLines.push_back(aBorderLine);
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("insideV"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_tl2br:
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("tl2br"));
+ break;
+ case NS_ooxml::LN_CT_TcBorders_tr2bl:
+ if (!m_aInteropGrabBagName.isEmpty())
+ aSavedGrabBag.push_back(getInteropGrabBag("tr2bl"));
+ break;
+ default:;
+ }
+ if (!m_aInteropGrabBagName.isEmpty())
+ m_aInteropGrabBag = aSavedGrabBag;
+}
+
+
+void TDefTableHandler::lcl_sprm(Sprm & rSprm)
+{
+ switch( rSprm.getId() )
+ {
+ case NS_ooxml::LN_CT_TcBorders_top:
+ case NS_ooxml::LN_CT_TcBorders_left:
+ case NS_ooxml::LN_CT_TcBorders_start:
+ case NS_ooxml::LN_CT_TcBorders_bottom:
+ case NS_ooxml::LN_CT_TcBorders_right:
+ case NS_ooxml::LN_CT_TcBorders_end:
+ case NS_ooxml::LN_CT_TcBorders_insideH:
+ case NS_ooxml::LN_CT_TcBorders_insideV:
+ case NS_ooxml::LN_CT_TcBorders_tl2br:
+ case NS_ooxml::LN_CT_TcBorders_tr2bl:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ localResolve( rSprm.getId(), pProperties );
+ }
+ break;
+ default:;
+ }
+}
+
+void TDefTableHandler::fillCellProperties( const ::tools::SvRef< TablePropertyMap >& pCellProperties ) const
+{
+ if( !m_aTopBorderLines.empty() )
+ pCellProperties->Insert( PROP_TOP_BORDER, uno::Any( m_aTopBorderLines[0] ) );
+ if( !m_aLeftBorderLines.empty() )
+ pCellProperties->Insert( PROP_LEFT_BORDER, uno::Any( m_aLeftBorderLines[0] ) );
+ if( !m_aBottomBorderLines.empty() )
+ pCellProperties->Insert( PROP_BOTTOM_BORDER, uno::Any( m_aBottomBorderLines[0] ) );
+ if( !m_aRightBorderLines.empty() )
+ pCellProperties->Insert( PROP_RIGHT_BORDER, uno::Any( m_aRightBorderLines[0] ) );
+ if( !m_aInsideHBorderLines.empty() )
+ pCellProperties->Insert( META_PROP_HORIZONTAL_BORDER, uno::Any( m_aInsideHBorderLines[0] ) );
+ if( !m_aInsideVBorderLines.empty() )
+ pCellProperties->Insert( META_PROP_VERTICAL_BORDER, uno::Any( m_aInsideVBorderLines[0] ) );
+
+ if (m_eThemeColorType != model::ThemeColorType::Unknown)
+ {
+ model::ComplexColor aComplexColor;
+ aComplexColor.setThemeColor(m_eThemeColorType);
+
+ if (m_nThemeTint > 0 )
+ {
+ sal_Int16 nTint = sal_Int16((255.0 - m_nThemeTint) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Tint, nTint});
+ }
+ if (m_nThemeShade > 0)
+ {
+ sal_Int16 nShade = sal_Int16((255.0 - m_nThemeShade) * 10000.0 / 255.0);
+ aComplexColor.addTransformation({model::TransformationType::Shade, nShade});
+ }
+ }
+}
+
+
+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/sw/source/writerfilter/dmapper/TDefTableHandler.hxx b/sw/source/writerfilter/dmapper/TDefTableHandler.hxx
new file mode 100644
index 000000000000..7b02d4ae0907
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TDefTableHandler.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <vector>
+#include <docmodel/theme/ThemeColorType.hxx>
+#include <docmodel/color/ComplexColor.hxx>
+
+namespace com::sun::star{
+ namespace table {
+ struct BorderLine2;
+ }
+ namespace beans {
+ struct PropertyValue;
+ }
+}
+
+namespace writerfilter::dmapper
+{
+class PropertyMap;
+class TablePropertyMap;
+class TDefTableHandler : public LoggedProperties
+{
+ std::vector<css::table::BorderLine2> m_aLeftBorderLines;
+ std::vector<css::table::BorderLine2> m_aRightBorderLines;
+ std::vector<css::table::BorderLine2> m_aTopBorderLines;
+ std::vector<css::table::BorderLine2> m_aBottomBorderLines;
+ std::vector<css::table::BorderLine2> m_aInsideHBorderLines;
+ std::vector<css::table::BorderLine2> m_aInsideVBorderLines;
+
+ //values of the current border
+ sal_Int32 m_nLineWidth;
+ sal_Int32 m_nLineType;
+ sal_Int32 m_nLineColor;
+
+ model::ThemeColorType m_eThemeColorType = model::ThemeColorType::Unknown;
+ sal_Int32 m_nThemeShade = 0;
+ sal_Int32 m_nThemeTint = 0;
+
+ 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);
+ static model::ThemeColorType getThemeColorTypeIndex(sal_Int32 nType);
+ static model::ThemeColorUsage getThemeColorUsage(sal_Int32 nType);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TableData.hxx b/sw/source/writerfilter/dmapper/TableData.hxx
new file mode 100644
index 000000000000..ded929696e5a
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TableData.hxx
@@ -0,0 +1,419 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/text/XTextRange.hpp>
+
+#include "PropertyMap.hxx"
+
+#include <utility>
+#include <vector>
+
+namespace writerfilter::dmapper
+{
+
+/**
+ Class containing the data to describe a table cell.
+ */
+class CellData final : public virtual SvRefBase
+{
+ /**
+ Handle to start of cell.
+ */
+ css::uno::Reference<css::text::XTextRange> mStart;
+
+ /**
+ Handle to end of cell.
+ */
+ css::uno::Reference<css::text::XTextRange> mEnd;
+
+ /**
+ Pointer to properties of cell.
+ */
+ TablePropertyMapPtr mpProps;
+
+ bool mbOpen;
+
+ sal_uInt32 m_nGridSpan; ///< number of grid columns in the parent table's table grid which this cell defines
+
+public:
+ typedef tools::SvRef<CellData> Pointer_t;
+
+ CellData(css::uno::Reference<css::text::XTextRange> const & start, TablePropertyMapPtr pProps)
+ : mStart(start), mEnd(start), mpProps(std::move(pProps)), mbOpen(true)
+ , m_nGridSpan(1)
+ {
+ }
+
+ /**
+ Set the end handle of a cell.
+
+ @param end the end handle of the cell
+ */
+ void setEnd(css::uno::Reference<css::text::XTextRange> const & end) { mEnd = end; mbOpen = false; }
+
+ /**
+ Adds properties to the cell.
+
+ @param pProps the properties to add
+ */
+ void insertProperties(TablePropertyMapPtr pProps)
+ {
+ if( mpProps )
+ mpProps->InsertProps(pProps.get());
+ else
+ mpProps = pProps;
+ }
+
+ /**
+ Return start handle of the cell.
+ */
+ const css::uno::Reference<css::text::XTextRange>& getStart() const { return mStart; }
+
+ /**
+ Return end handle of the cell.
+ */
+ const css::uno::Reference<css::text::XTextRange>& getEnd() const { return mEnd; }
+
+ /**
+ Return properties of the cell.
+ */
+ const TablePropertyMapPtr& getProperties() const { return mpProps; }
+
+ bool isOpen() const { return mbOpen; }
+
+ sal_uInt32 getGridSpan() const { return m_nGridSpan; }
+ void setGridSpan( sal_uInt32 nSpan ) { m_nGridSpan = nSpan; }
+
+ void SetStart(const css::uno::Reference<css::text::XTextRange>& xStart) { mStart = xStart; }
+
+ bool IsValid() const;
+};
+
+/**
+ Class to handle data of a table row.
+ */
+class RowData final : public virtual SvRefBase
+{
+ typedef ::std::vector<CellData::Pointer_t> Cells;
+
+ /**
+ the cell data of the row
+ */
+ Cells mCells;
+
+ /**
+ the properties of the row
+ */
+ mutable TablePropertyMapPtr mpProperties;
+
+ sal_uInt32 m_nGridBefore; ///< number of grid columns in the parent table's table grid which must be skipped before the contents of this table row are added to the parent table
+ sal_uInt32 m_nGridAfter; ///< number of grid columns in the parent table's table grid which shall be left after the last cell in the table row
+
+public:
+ typedef tools::SvRef<RowData> Pointer_t;
+
+ RowData()
+ : m_nGridBefore(0)
+ , m_nGridAfter(0)
+ {
+ }
+
+ RowData(const RowData& rRowData)
+ : SvRefBase(), mCells(rRowData.mCells), mpProperties(rRowData.mpProperties)
+ , m_nGridBefore(rRowData.m_nGridBefore)
+ , m_nGridAfter(rRowData.m_nGridAfter)
+ {
+ }
+
+ /**
+ Add a cell to the row.
+
+ @param start the start handle of the cell
+ @param end the end handle of the cell
+ @param pProps the properties of the cell
+ @param bAddBefore true: add an empty cell at beginning of the row for gridBefore
+ */
+ void addCell(const css::uno::Reference<css::text::XTextRange>& start, const 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();
+ }
+
+ void SetCellStart(const css::uno::Reference<css::text::XTextRange>& xStart)
+ {
+ if (mCells.empty())
+ {
+ return;
+ }
+
+ mCells.back()->SetStart(xStart);
+ }
+
+ bool IsCellValid() const
+ {
+ return !mCells.empty() && mCells.back()->IsValid();
+ }
+
+ /**
+ 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(const TablePropertyMapPtr& pProps)
+ {
+ if (!mCells.empty())
+ mCells.back()->insertProperties(pProps);
+ }
+
+ /**
+ Return number of cells in the row.
+ */
+ unsigned int getCellCount() const
+ {
+ return mCells.size();
+ }
+
+ /**
+ Return start handle of a cell in the row.
+
+ @param i index of the cell
+ */
+ const css::uno::Reference<css::text::XTextRange>& getCellStart(unsigned int i) const
+ {
+ return mCells[i]->getStart();
+ }
+
+ /**
+ Return end handle of a cell in the row.
+
+ @param i index of the cell
+ */
+ const css::uno::Reference<css::text::XTextRange>& getCellEnd(unsigned int i) const
+ {
+ return mCells[i]->getEnd();
+ }
+
+ /**
+ Return the properties of a cell in the row.
+
+ @param i index of the cell
+ */
+ TablePropertyMapPtr const & getCellProperties(unsigned int i) const
+ {
+ return mCells[i]->getProperties();
+ }
+
+ /**
+ Return properties of the row.
+ */
+ const TablePropertyMapPtr& getProperties() const
+ {
+ return mpProperties;
+ }
+
+ sal_uInt32 getGridBefore() const { return m_nGridBefore; }
+ void setGridBefore(sal_uInt32 nSkipGrids) { m_nGridBefore = nSkipGrids; }
+ sal_uInt32 getGridAfter() const { return m_nGridAfter; }
+ void setGridAfter(sal_uInt32 nSkipGrids) { m_nGridAfter = nSkipGrids; }
+ sal_uInt32 getGridSpan(sal_uInt32 i) { return mCells[i]->getGridSpan(); }
+ std::vector< sal_uInt32 > getGridSpans()
+ {
+ std::vector< sal_uInt32 > nRet;
+ for (auto const& aCell: mCells)
+ nRet.push_back(aCell->getGridSpan());
+ return nRet;
+ }
+ void setCurrentGridSpan(sal_uInt32 nSpan, bool bFirstCell = false)
+ {
+ if ( mCells.size() )
+ {
+ if ( bFirstCell )
+ mCells.front()->setGridSpan(nSpan);
+ else
+ mCells.back()->setGridSpan(nSpan);
+ }
+ }
+};
+
+/**
+ Class that holds the data of a table.
+ */
+class TableData : public virtual SvRefBase
+{
+ typedef ::std::vector<RowData::Pointer_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).
+ */
+ RowData::Pointer_t mpRow;
+
+ /**
+ depth of the current table in a hierarchy of tables
+ */
+ unsigned int mnDepth;
+
+ /**
+ initialize mpRow
+ */
+ void newRow() { mpRow = RowData::Pointer_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(const 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, const 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();
+ }
+
+ void SetCellStart(const css::uno::Reference<css::text::XTextRange>& xStart)
+ {
+ mpRow->SetCellStart(xStart);
+ }
+
+ bool IsCellValid() const
+ {
+ return mpRow->IsCellValid();
+ }
+
+ /**
+ Insert properties to the current cell of the current row.
+
+ @param pProps the properties to add
+ */
+ void insertCellProperties(const 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
+ */
+ RowData::Pointer_t const & getRow(unsigned int i) const
+ {
+ return mRows[i];
+ }
+
+ const RowData::Pointer_t& getCurrentRow() const
+ {
+ return mpRow;
+ }
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TableManager.cxx b/sw/source/writerfilter/dmapper/TableManager.cxx
new file mode 100644
index 000000000000..6a0c70a39f52
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TableManager.cxx
@@ -0,0 +1,686 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <comphelper/diagnose_ex.hxx>
+
+using namespace com::sun::star;
+
+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.back();
+
+ pTableData->addCell(rHandle, pProps);
+ }
+}
+
+bool TableManager::isIgnore() const { return isRowEnd(); }
+
+sal_uInt32 TableManager::getGridBefore(sal_uInt32 nRow)
+{
+ if (!isInTable())
+ {
+ SAL_WARN("writerfilter", "TableManager::getGridBefore called while not in table");
+ return 0;
+ }
+ if (nRow >= mTableDataStack.back()->getRowCount())
+ return 0;
+ return mTableDataStack.back()->getRow(nRow)->getGridBefore();
+}
+
+sal_uInt32 TableManager::getCurrentGridBefore()
+{
+ return mTableDataStack.back()->getCurrentRow()->getGridBefore();
+}
+
+void TableManager::setCurrentGridBefore(sal_uInt32 nSkipGrids)
+{
+ mTableDataStack.back()->getCurrentRow()->setGridBefore(nSkipGrids);
+}
+
+sal_uInt32 TableManager::getGridAfter(sal_uInt32 nRow)
+{
+ if (!isInTable())
+ {
+ SAL_WARN("writerfilter", "TableManager::getGridAfter called while not in table");
+ return 0;
+ }
+ if (nRow >= mTableDataStack.back()->getRowCount())
+ return 0;
+ return mTableDataStack.back()->getRow(nRow)->getGridAfter();
+}
+
+void TableManager::setCurrentGridAfter(sal_uInt32 nSkipGrids)
+{
+ assert(isInTable());
+ mTableDataStack.back()->getCurrentRow()->setGridAfter(nSkipGrids);
+}
+
+std::vector<sal_uInt32> TableManager::getCurrentGridSpans()
+{
+ return mTableDataStack.back()->getCurrentRow()->getGridSpans();
+}
+
+void TableManager::setCurrentGridSpan(sal_uInt32 nGridSpan, bool bFirstCell)
+{
+ mTableDataStack.back()->getCurrentRow()->setCurrentGridSpan(nGridSpan, bFirstCell);
+}
+
+sal_uInt32 TableManager::findColumn(const sal_uInt32 nRow, const sal_uInt32 nCell)
+{
+ if (nRow >= mTableDataStack.back()->getRowCount())
+ return SAL_MAX_UINT32;
+
+ RowData::Pointer_t pRow = mTableDataStack.back()->getRow(nRow);
+ if (!pRow || nCell < pRow->getGridBefore()
+ || nCell >= pRow->getCellCount() - pRow->getGridAfter())
+ {
+ return SAL_MAX_UINT32;
+ }
+
+ // The gridSpans provide a one-based index, so add up all the spans of the PREVIOUS columns,
+ // and that result will provide the first possible zero-based number for the desired column.
+ sal_uInt32 nColumn = 0;
+ for (sal_uInt32 n = 0; n < nCell; ++n)
+ nColumn += pRow->getGridSpan(n);
+ return nColumn;
+}
+
+sal_uInt32 TableManager::findColumnCell(const sal_uInt32 nRow, const sal_uInt32 nCol)
+{
+ if (nRow >= mTableDataStack.back()->getRowCount())
+ return SAL_MAX_UINT32;
+
+ RowData::Pointer_t pRow = mTableDataStack.back()->getRow(nRow);
+ if (!pRow || nCol < pRow->getGridBefore())
+ return SAL_MAX_UINT32;
+
+ sal_uInt32 nCell = 0;
+ sal_uInt32 nGrids = 0;
+ // The gridSpans give us a one-based index, but requested column is zero-based - so keep that in mind.
+ const sal_uInt32 nMaxCell = pRow->getCellCount() - pRow->getGridAfter() - 1;
+ for (const auto& rSpan : pRow->getGridSpans())
+ {
+ nGrids += rSpan;
+ if (nCol < nGrids)
+ return nCell;
+
+ ++nCell;
+ if (nCell > nMaxCell)
+ break;
+ }
+ return SAL_MAX_UINT32; // must be in gridAfter or invalid column request
+}
+
+void TableManager::endOfRowAction() {}
+
+void TableManager::endOfCellAction() {}
+
+void TableManager::insertTableProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.insertTableProps");
+#endif
+
+ if (getTableProps() && getTableProps() != pProps)
+ getTableProps()->InsertProps(pProps.get());
+ else
+ mState.setTableProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::insertRowProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.insertRowProps");
+#endif
+
+ if (getRowProps())
+ getRowProps()->InsertProps(pProps.get());
+ else
+ mState.setRowProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::cellProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.cellProps");
+#endif
+
+ if (getCellProps())
+ getCellProps()->InsertProps(pProps.get());
+ else
+ mState.setCellProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::tableExceptionProps(const TablePropertyMapPtr& pProps)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.tableExceptionProps");
+#endif
+
+ if (getTableExceptionProps())
+ getTableExceptionProps()->InsertProps(pProps.get());
+ else
+ mState.setTableExceptionProps(pProps);
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::utext(const sal_Unicode* const data, std::size_t const len)
+{
+ // optimization: cell/row end characters are the last characters in a run
+
+ if (len > 0)
+ {
+ sal_Unicode const nChar = data[len - 1];
+ 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.back();
+
+ 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.back();
+
+ if (pTableData != nullptr)
+ {
+ if (!pTableData->isCellOpen())
+ openCell(getHandle(), pProps);
+ else
+ pTableData->insertCellProperties(pProps);
+ }
+ }
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::endParagraphGroup()
+{
+ sal_Int32 nTableDepthDifference = mnTableDepthNew - mnTableDepth;
+
+ TablePropertyMapPtr pEmptyProps;
+
+ while (nTableDepthDifference > 0)
+ {
+ ensureOpenCell(pEmptyProps);
+ startLevel();
+
+ --nTableDepthDifference;
+ }
+ while (nTableDepthDifference < 0)
+ {
+ endLevel();
+
+ ++nTableDepthDifference;
+ }
+
+ mnTableDepth = mnTableDepthNew;
+
+ if (mnTableDepth <= 0)
+ return;
+
+ if (isRowEnd())
+ {
+ endOfRowAction();
+ mTableDataStack.back()->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.back();
+
+ 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);
+ }
+ 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()
+{
+ uno::Reference<text::XTextCursor> xCursor;
+ if (mpTableDataHandler != nullptr)
+ {
+ if (mTableDataStack.size() > 1)
+ {
+ // This is an inner table: create a cursor from the outer cell's start position, in case
+ // that would become invalid during the current table resolution.
+ TableData::Pointer_t pUpperTableData = mTableDataStack[mTableDataStack.size() - 2];
+ RowData::Pointer_t pRow = pUpperTableData->getCurrentRow();
+ unsigned int nCells = pRow->getCellCount();
+ if (nCells > 0)
+ {
+ uno::Reference<text::XTextRange> xCellStart = pRow->getCellStart(nCells - 1);
+ if (xCellStart.is())
+ {
+ try
+ {
+ xCursor = xCellStart->getText()->createTextCursorByRange(
+ xCellStart->getStart());
+ if (xCursor.is())
+ {
+ xCursor->goLeft(1, false);
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION(
+ "writerfilter",
+ "TableManager::endLevel: createTextCursorByRange() failed");
+ }
+ }
+ }
+ }
+ resolveCurrentTable();
+ }
+
+ // Store the unfinished row as it will be used for the next table
+ if (mbKeepUnfinishedRow)
+ mpUnfinishedRow = mTableDataStack.back()->getCurrentRow();
+ mState.endLevel();
+ mTableDataStack.pop_back();
+
+ TableData::Pointer_t pTableData;
+
+ if (!mTableDataStack.empty())
+ pTableData = mTableDataStack.back();
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.endLevel");
+ TagLogger::getInstance().attribute("level", mTableDataStack.size());
+#endif
+
+ if (pTableData != nullptr)
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().attribute("openCell", pTableData->isCellOpen() ? "yes" : "no");
+#endif
+ if (pTableData->isCellOpen() && !pTableData->IsCellValid() && xCursor.is())
+ {
+ // The inner table is resolved and we have an outer table, but the currently opened
+ // cell's start position is no longer valid. Try to move the cursor back to where it was
+ // and update the cell start position accordingly.
+ try
+ {
+ xCursor->goRight(1, false);
+ pTableData->SetCellStart(xCursor->getStart());
+ }
+ catch (const uno::RuntimeException&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter", "TableManager::endLevel: goRight() failed");
+ }
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TableManager::startLevel()
+{
+#ifdef DBG_UTIL
+ TableData::Pointer_t pTableData;
+
+ if (!mTableDataStack.empty())
+ pTableData = mTableDataStack.back();
+
+ TagLogger::getInstance().startElement("tablemanager.startLevel");
+ TagLogger::getInstance().attribute("level", mTableDataStack.size());
+
+ if (pTableData != nullptr)
+ TagLogger::getInstance().attribute("openCell", pTableData->isCellOpen() ? "yes" : "no");
+
+ TagLogger::getInstance().endElement();
+#endif
+
+ TableData::Pointer_t pTableData2(new TableData(mTableDataStack.size()));
+
+ // If we have an unfinished row stored here, then push it to the new TableData
+ if (mpUnfinishedRow)
+ {
+ for (unsigned int i = 0; i < mpUnfinishedRow->getCellCount(); ++i)
+ {
+ pTableData2->addCell(mpUnfinishedRow->getCellStart(i),
+ mpUnfinishedRow->getCellProperties(i));
+ pTableData2->endCell(mpUnfinishedRow->getCellEnd(i));
+ pTableData2->getCurrentRow()->setCurrentGridSpan(mpUnfinishedRow->getGridSpan(i));
+ }
+ pTableData2->getCurrentRow()->setGridBefore(mpUnfinishedRow->getGridBefore());
+ pTableData2->getCurrentRow()->setGridAfter(mpUnfinishedRow->getGridAfter());
+ mpUnfinishedRow.clear();
+ }
+
+ mTableDataStack.push_back(pTableData2);
+ mState.startLevel();
+}
+
+bool TableManager::isInTable()
+{
+ bool bInTable = false;
+ if (!mTableDataStack.empty())
+ bInTable = mTableDataStack.back()->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.back();
+
+ // Add borderless w:gridBefore cell(s) to the row
+ sal_uInt32 nGridBefore = getCurrentGridBefore();
+ if (pTableData && nGridBefore > 0 && pTableData->getCurrentRow()->getCellCount() > 0)
+ {
+ const css::uno::Reference<css::text::XTextRange>& xRowStart
+ = pTableData->getCurrentRow()->getCellStart(0);
+ if (xRowStart.is())
+ {
+ try
+ {
+ // valid TextRange for table creation (not a nested table)?
+ xRowStart->getText()->createTextCursorByRange(xRowStart);
+
+ for (unsigned int i = 0; i < nGridBefore; ++i)
+ {
+ css::table::BorderLine2 aBorderLine;
+ aBorderLine.Color = 0;
+ aBorderLine.InnerLineWidth = 0;
+ aBorderLine.OuterLineWidth = 0;
+ TablePropertyMapPtr pCellProperties(new TablePropertyMap);
+ pCellProperties->Insert(PROP_TOP_BORDER, css::uno::Any(aBorderLine));
+ pCellProperties->Insert(PROP_LEFT_BORDER, css::uno::Any(aBorderLine));
+ pCellProperties->Insert(PROP_BOTTOM_BORDER, css::uno::Any(aBorderLine));
+ pCellProperties->Insert(PROP_RIGHT_BORDER, css::uno::Any(aBorderLine));
+ pTableData->getCurrentRow()->addCell(xRowStart, pCellProperties,
+ /*bAddBefore=*/true);
+ }
+ }
+ catch (css::uno::Exception const&)
+ {
+ // don't add gridBefore cells in not valid TextRange
+ setCurrentGridBefore(0);
+ setCurrentGridSpan(getCurrentGridSpans().front() + nGridBefore,
+ /*bFirstCell=*/true);
+ }
+ }
+ }
+
+ setRowEnd(true);
+}
+
+void TableManager::endCell()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("tablemanager.endCell");
+#endif
+
+ setCellEnd(true);
+}
+
+void TableManager::inCell()
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("tablemanager.inCell");
+#endif
+ setInCell(true);
+
+ if (mnTableDepthNew < 1)
+ mnTableDepthNew = 1;
+}
+
+void TableManager::cellDepth(sal_uInt32 nDepth)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("tablemanager.cellDepth");
+ TagLogger::getInstance().attribute("depth", nDepth);
+ TagLogger::getInstance().endElement();
+#endif
+
+ mnTableDepthNew = nDepth;
+}
+
+void TableManager::setCellLastParaAfterAutospacing(bool bIsAfterAutospacing)
+{
+ m_bCellLastParaAfterAutospacing = bIsAfterAutospacing;
+}
+
+TableManager::TableManager()
+ : mnTableDepthNew(0)
+ , mnTableDepth(0)
+ , mbKeepUnfinishedRow(false)
+{
+ setRowEnd(false);
+ setInCell(false);
+ setCellEnd(false);
+ m_bCellLastParaAfterAutospacing = false;
+}
+
+TableManager::~TableManager() = default;
+
+bool CellData::IsValid() const
+{
+ if (!mStart.is())
+ {
+ return false;
+ }
+
+ try
+ {
+ mStart->getStart();
+ }
+ catch (const uno::RuntimeException&)
+ {
+ return false;
+ }
+
+ return true;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TableManager.hxx b/sw/source/writerfilter/dmapper/TableManager.hxx
new file mode 100644
index 000000000000..f98c992a3595
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TableManager.hxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <stack>
+
+#include "PropertyMap.hxx"
+#include "TableData.hxx"
+
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::dmapper
+{
+
+class DomainMapperTableHandler;
+
+/**
+ The table manager.
+
+ This class gets forwarded events from the tokenizer. It gathers the
+ table data and after ending the table generates events for the
+ table structure. The events have to be handles by a TableDataHandler.
+
+ */
+class TableManager : public virtual SvRefBase
+{
+ class TableManagerState final
+ {
+ /**
+ properties of the current cell
+ */
+ TablePropertyMapPtr mpCellProps;
+
+ /**
+ properties of the current row
+ */
+ TablePropertyMapPtr mpRowProps;
+
+ /**
+ table exception properties of the current row
+ */
+ TablePropertyMapPtr mpTableExceptionProps;
+
+ /**
+ properties of the current table
+ */
+ std::stack<TablePropertyMapPtr> mTableProps;
+
+ /**
+ true if at the end of a row
+ */
+ bool mbRowEnd;
+
+ /**
+ true when in a cell
+ */
+ bool mbInCell;
+
+ /**
+ true when at the end of a cell
+ */
+ bool mbCellEnd;
+
+ public:
+ /**
+ Constructor
+ */
+ TableManagerState()
+ : mbRowEnd(false), mbInCell(false), mbCellEnd(false)
+ {
+ }
+
+ void startLevel()
+ {
+ TablePropertyMapPtr pProps;
+ mTableProps.push(pProps);
+ }
+
+ void endLevel()
+ {
+ mTableProps.pop();
+ }
+
+ /**
+ Reset to initial state at beginning of row.
+ */
+ void resetCellSpecifics()
+ {
+ mbRowEnd = false;
+ mbInCell = false;
+ mbCellEnd = false;
+ }
+
+ void resetCellProps()
+ {
+ // copy tblPrEx table exception properties, if they exist
+ if (getTableExceptionProps().is())
+ {
+ mpCellProps = new TablePropertyMap;
+ mpCellProps->InsertProps(getTableExceptionProps().get());
+ }
+ else
+ mpCellProps.clear();
+ }
+
+ void setCellProps(const 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(const TablePropertyMapPtr& pProps)
+ {
+ mpRowProps = pProps;
+ }
+
+ const TablePropertyMapPtr& getRowProps() const
+ {
+ return mpRowProps;
+ }
+
+ void setTableExceptionProps(const TablePropertyMapPtr& pProps)
+ {
+ mpTableExceptionProps = pProps;
+ // set table exception properties of the first cell
+ resetCellProps();
+ }
+
+ const TablePropertyMapPtr& getTableExceptionProps() const
+ {
+ return mpTableExceptionProps;
+ }
+
+ void resetTableProps()
+ {
+ if (mTableProps.size() > 0)
+ mTableProps.top().clear();
+ }
+
+ void setTableProps(const 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::vector<TableData::Pointer_t> mTableDataStack;
+ RowData::Pointer_t mpUnfinishedRow;
+ bool mbKeepUnfinishedRow;
+
+ bool m_bCellLastParaAfterAutospacing;
+
+ /**
+ handler for resolveCurrentTable
+ */
+ tools::SvRef<DomainMapperTableHandler> mpTableDataHandler;
+
+ /**
+ Set flag which indicates the current handle is in a cell.
+ */
+ void inCell();
+
+ /**
+ Set flag which indicate the current handle is at the end of a cell.
+ */
+ void endCell();
+
+ /**
+ Set the table depth of the current cell.
+
+ @param nDepth the cell depth
+ */
+ void cellDepth(sal_uInt32 nDepth);
+
+ /**
+ Set flag indication the current handle is at the end of a row.
+ */
+ void endRow();
+
+ /**
+ Resolve the current table to the TableDataHandler.
+ */
+ void resolveCurrentTable();
+
+ /**
+ Open a cell at current level.
+ */
+
+ void openCell(const css::uno::Reference<css::text::XTextRange>& rHandle, const TablePropertyMapPtr& pProps);
+
+ /**
+ Close a cell at current level.
+ */
+ void closeCell(const css::uno::Reference<css::text::XTextRange>& rHandle);
+
+ /**
+ Ensure a cell is open at the current level.
+ */
+ void ensureOpenCell(const TablePropertyMapPtr& pProps);
+
+protected:
+ /**
+ Return the current table difference, i.e. 1 if we are in the first cell of a new table, etc.
+ */
+ sal_Int32 getTableDepthDifference() const { return mnTableDepthNew - mnTableDepth; }
+
+ sal_uInt32 getTableDepth() const { return mnTableDepthNew; }
+
+ /**
+ Action to be carried out at the end of the last paragraph of a
+ cell.
+ */
+ virtual void endOfCellAction();
+
+ /**
+ Action to be carried out at the end of the "table row"
+ paragraph.
+ */
+ virtual void endOfRowAction();
+ /** let the derived class clear their table related data
+ */
+ virtual void clearData();
+
+ /** Should we keep the unfinished row in endLevel to initialize the table
+ data in the following startLevel.
+ */
+ void setKeepUnfinishedRow(bool bKeep)
+ {
+ mbKeepUnfinishedRow = bKeep;
+ }
+
+
+public:
+ TableManager();
+ ~TableManager();
+
+ /**
+ Set handler for resolveCurrentTable.
+
+ @param pTableDataHandler the handler
+ */
+ void setHandler(const tools::SvRef<DomainMapperTableHandler>& pTableDataHandler);
+
+ /**
+ Set the current handle.
+
+ @param rHandle the handle
+ */
+ void handle(const css::uno::Reference<css::text::XTextRange>& rHandle);
+
+ /**
+ Start a new table level.
+
+ A new context is pushed onto the table data stack,
+ */
+ virtual void startLevel();
+
+ /**
+ End a table level.
+
+ The current table is resolved and the context is popped from
+ the stack.
+ */
+ virtual void endLevel();
+
+ /**
+ * Signal that the next paragraph definitely won't be part of any table.
+ */
+ void endTable()
+ {
+ setRowEnd(false);
+ }
+
+ /**
+ Tells whether a table has been started or not
+ */
+ bool isInTable();
+
+ /**
+ Handle the start of a paragraph group.
+ */
+ void startParagraphGroup();
+
+ /**
+ Handle the end of a paragraph group.
+ */
+ void endParagraphGroup();
+
+ /**
+ Handle an SPRM at current handle.
+
+ @param rSprm the SPRM
+ */
+ virtual bool sprm(Sprm & rSprm);
+
+ /**
+ Handle occurrence of character 0x7.
+ */
+ void handle0x7();
+
+ /**
+ Handle 8 bit text at current handle.
+
+ @param data array of characters
+ @param len number of characters to handle
+ */
+ void text(const sal_uInt8 * data, size_t len);
+
+ /**
+ Handle 16 bit text at current handle.
+
+ @param data array of characters
+ @param len number of characters to handle
+ */
+ void utext(const sal_Unicode * data, size_t len);
+
+ /**
+ Handle properties of the current cell.
+
+ @param pProps the properties
+ */
+ virtual void cellProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Handle properties of the current row.
+
+ @param pProps the properties
+ */
+ virtual void insertRowProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Handle table exception properties of the current row.
+
+ @param pProps the properties
+ */
+ virtual void tableExceptionProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Handle properties of the current table.
+
+ @param pProps the properties
+ */
+ virtual void insertTableProps(const TablePropertyMapPtr& pProps);
+
+ /**
+ Return if table manager has detected paragraph to ignore.
+
+ If this function returns true the current paragraph contains
+ only control information, e.g. end of row.
+ */
+ bool isIgnore() const;
+
+ sal_uInt32 getGridBefore(sal_uInt32 nRow);
+ sal_uInt32 getCurrentGridBefore();
+ void setCurrentGridBefore( sal_uInt32 nSkipGrids );
+ sal_uInt32 getGridAfter(sal_uInt32 nRow);
+ void setCurrentGridAfter( sal_uInt32 nSkipGrids );
+ std::vector<sal_uInt32> getCurrentGridSpans();
+ void setCurrentGridSpan( sal_uInt32 nGridSpan, bool bFirstCell = false );
+ /// Given a zero-based row/cell, return the zero-based grid it belongs to, or SAL_MAX_UINT16 for invalid.
+ sal_uInt32 findColumn( const sal_uInt32 nRow, const sal_uInt32 nCell );
+ /// Given a zero-based row/col, return the zero-based cell describing that grid, or SAL_MAX_UINT16 for invalid.
+ sal_uInt32 findColumnCell( const sal_uInt32 nRow, const sal_uInt32 nCol );
+
+ void setCellLastParaAfterAutospacing(bool bIsAfterAutospacing);
+ bool isCellLastParaAfterAutospacing() const {return m_bCellLastParaAfterAutospacing;}
+};
+
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TablePositionHandler.cxx b/sw/source/writerfilter/dmapper/TablePositionHandler.cxx
new file mode 100644
index 000000000000..62d423d29515
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TablePositionHandler.cxx
@@ -0,0 +1,160 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "TablePositionHandler.hxx"
+#include "ConversionHelper.hxx"
+#include "TagLogger.hxx"
+#include <ooxml/resourceids.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <comphelper/sequenceashashmap.hxx>
+
+namespace writerfilter::dmapper
+{
+using namespace ::com::sun::star;
+
+TablePositionHandler::TablePositionHandler()
+ : LoggedProperties("TablePositionHandler")
+{
+}
+
+TablePositionHandler::~TablePositionHandler() = default;
+
+void TablePositionHandler::lcl_attribute(Id nId, Value& rVal)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_TblPPr_vertAnchor:
+ m_aVertAnchor = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpYSpec:
+ m_aYSpec = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_horzAnchor:
+ m_aHorzAnchor = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpXSpec:
+ m_aXSpec = rVal.getString();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpY:
+ m_nY = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_tblpX:
+ m_nX = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_leftFromText:
+ m_nLeftFromText = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_rightFromText:
+ m_nRightFromText = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_topFromText:
+ m_nTopFromText = rVal.getInt();
+ break;
+ case NS_ooxml::LN_CT_TblPPr_bottomFromText:
+ m_nBottomFromText = rVal.getInt();
+ break;
+ default:
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ break;
+ }
+}
+
+void TablePositionHandler::lcl_sprm(Sprm& /*rSprm*/) {}
+
+uno::Sequence<beans::PropertyValue> TablePositionHandler::getTablePosition() const
+{
+ comphelper::SequenceAsHashMap aFrameProperties;
+
+ aFrameProperties["LeftBorderDistance"] <<= sal_Int32(0);
+ aFrameProperties["RightBorderDistance"] <<= sal_Int32(0);
+ aFrameProperties["TopBorderDistance"] <<= sal_Int32(0);
+ aFrameProperties["BottomBorderDistance"] <<= sal_Int32(0);
+
+ aFrameProperties["LeftMargin"] <<= ConversionHelper::convertTwipToMM100(m_nLeftFromText);
+ aFrameProperties["RightMargin"] <<= ConversionHelper::convertTwipToMM100(m_nRightFromText);
+ aFrameProperties["TopMargin"] <<= ConversionHelper::convertTwipToMM100(m_nTopFromText);
+ aFrameProperties["BottomMargin"] <<= ConversionHelper::convertTwipToMM100(m_nBottomFromText);
+
+ table::BorderLine2 aEmptyBorder;
+ aFrameProperties["TopBorder"] <<= aEmptyBorder;
+ aFrameProperties["BottomBorder"] <<= aEmptyBorder;
+ aFrameProperties["LeftBorder"] <<= aEmptyBorder;
+ aFrameProperties["RightBorder"] <<= aEmptyBorder;
+
+ // Horizontal positioning
+ sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
+ if (m_aXSpec == "center")
+ nHoriOrient = text::HoriOrientation::CENTER;
+ else if (m_aXSpec == "inside")
+ nHoriOrient = text::HoriOrientation::INSIDE;
+ else if (m_aXSpec == "left")
+ nHoriOrient = text::HoriOrientation::LEFT;
+ else if (m_aXSpec == "outside")
+ nHoriOrient = text::HoriOrientation::OUTSIDE;
+ else if (m_aXSpec == "right")
+ nHoriOrient = text::HoriOrientation::RIGHT;
+
+ sal_Int16 nHoriOrientRelation;
+ if (m_aHorzAnchor == "margin")
+ nHoriOrientRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ else if (m_aHorzAnchor == "page")
+ nHoriOrientRelation = text::RelOrientation::PAGE_FRAME;
+ else if (m_aHorzAnchor == "text")
+ nHoriOrientRelation = text::RelOrientation::FRAME;
+
+ aFrameProperties["HoriOrient"] <<= nHoriOrient;
+ aFrameProperties["HoriOrientRelation"] <<= nHoriOrientRelation;
+ aFrameProperties["HoriOrientPosition"] <<= ConversionHelper::convertTwipToMM100(m_nX);
+
+ // Vertical positioning
+ sal_Int16 nVertOrient = text::VertOrientation::NONE;
+ if (m_aYSpec == "bottom")
+ nVertOrient = text::VertOrientation::BOTTOM;
+ else if (m_aYSpec == "center")
+ nVertOrient = text::VertOrientation::CENTER;
+ else if (m_aYSpec == "top")
+ nVertOrient = text::VertOrientation::TOP;
+ // TODO There are a few cases we can't map ATM.
+
+ sal_Int16 nVertOrientRelation;
+ if (m_aVertAnchor == "margin")
+ nVertOrientRelation = text::RelOrientation::PAGE_PRINT_AREA;
+ else if (m_aVertAnchor == "page")
+ nVertOrientRelation = text::RelOrientation::PAGE_FRAME;
+ else if (m_aVertAnchor == "text")
+ nVertOrientRelation = text::RelOrientation::FRAME;
+
+ aFrameProperties["VertOrient"] <<= nVertOrient;
+ aFrameProperties["VertOrientRelation"] <<= nVertOrientRelation;
+ aFrameProperties["VertOrientPosition"] <<= ConversionHelper::convertTwipToMM100(m_nY);
+ aFrameProperties["FillTransparence"] <<= sal_Int32(100);
+
+ if (m_nTableOverlap == NS_ooxml::LN_Value_ST_TblOverlap_never)
+ {
+ // NS_ooxml::LN_Value_ST_TblOverlap_overlap is the default, both in OOXML and in Writer.
+ aFrameProperties["AllowOverlap"] <<= false;
+ }
+
+ 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/sw/source/writerfilter/dmapper/TablePositionHandler.hxx b/sw/source/writerfilter/dmapper/TablePositionHandler.hxx
new file mode 100644
index 000000000000..1b9d9c808391
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TablePositionHandler.hxx
@@ -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/.
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+
+namespace com::sun::star::beans
+{
+struct PropertyValue;
+}
+
+namespace writerfilter::dmapper
+{
+/// Handler for floating table positioning
+class TablePositionHandler : public LoggedProperties
+{
+ OUString m_aVertAnchor{ "margin" };
+ OUString m_aYSpec;
+ OUString m_aHorzAnchor{ "text" };
+ OUString m_aXSpec;
+ sal_Int32 m_nY = 0;
+ sal_Int32 m_nX = 0;
+ sal_Int32 m_nLeftFromText = 0;
+ sal_Int32 m_nRightFromText = 0;
+ sal_Int32 m_nTopFromText = 0;
+ sal_Int32 m_nBottomFromText = 0;
+ Id m_nTableOverlap = 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; }
+
+ void setTableOverlap(Id nTableOverlap) { m_nTableOverlap = nTableOverlap; }
+
+ TablePositionHandler();
+ ~TablePositionHandler() override;
+
+ /** Compute the UNO properties for the frame containing the table based
+ on the received tokens.
+
+ Note that the properties will need to be adjusted with the table
+ properties before actually using them.
+ */
+ css::uno::Sequence<css::beans::PropertyValue> getTablePosition() const;
+
+ bool operator==(const TablePositionHandler& rHandler) const;
+};
+
+using TablePositionHandlerPtr = tools::SvRef<TablePositionHandler>;
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TablePropertiesHandler.cxx b/sw/source/writerfilter/dmapper/TablePropertiesHandler.cxx
new file mode 100644
index 000000000000..8ea3eae5c056
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TablePropertiesHandler.cxx
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "BorderHandler.hxx"
+#include "CellColorHandler.hxx"
+#include "CellMarginHandler.hxx"
+#include "ConversionHelper.hxx"
+#include "MeasureHandler.hxx"
+#include "TrackChangesHandler.hxx"
+#include "TablePropertiesHandler.hxx"
+#include "TagLogger.hxx"
+#include "TDefTableHandler.hxx"
+#include "DomainMapperTableManager.hxx"
+
+#include <ooxml/resourceids.hxx>
+
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <oox/token/tokens.hxx>
+
+using namespace com::sun::star;
+using namespace oox;
+
+namespace writerfilter::dmapper {
+
+ TablePropertiesHandler::TablePropertiesHandler() :
+ m_pCurrentInteropGrabBag(nullptr),
+ m_pTableManager( nullptr )
+ {
+ }
+
+ bool TablePropertiesHandler::sprm(Sprm & rSprm)
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TablePropertiesHandler.sprm");
+ TagLogger::getInstance().attribute("sprm", rSprm.toString());
+#endif
+
+ bool bRet = true;
+ sal_uInt32 nSprmId = rSprm.getId();
+ Value::Pointer_t pValue = rSprm.getValue();
+ sal_Int32 nIntValue = (pValue ? pValue->getInt() : 0);
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TrPrBase_jc:
+ case NS_ooxml::LN_CT_TblPrBase_jc:
+ {
+ sal_Int16 nOrient = ConversionHelper::convertTableJustification( nIntValue );
+ TablePropertyMapPtr pTableMap( new TablePropertyMap );
+ pTableMap->setValue( TablePropertyMap::HORI_ORIENT, nOrient );
+ insertTableProps( pTableMap );
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_trHeight:
+ {
+ //contains unit and value
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ { //contains attributes x2902 (LN_unit) and x17e2 (LN_trleft)
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ pPropMap->Insert( PROP_SIZE_TYPE, uno::Any( pMeasureHandler->GetRowHeightSizeType() ), false);
+ pPropMap->Insert( PROP_HEIGHT, uno::Any(pMeasureHandler->getMeasureValue() ));
+
+ insertRowProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPr_ins:
+ case NS_ooxml::LN_CT_TrPr_del:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ sal_Int32 nToken = sal_Int32();
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TrPr_ins:
+ nToken = XML_tableRowInsert;
+ break;
+ case NS_ooxml::LN_CT_TrPr_del:
+ nToken = XML_tableRowDelete;
+ break;
+ }
+ auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>( nToken );
+ pProperties->resolve(*pTrackChangesHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ // Add the 'track changes' properties to the 'table row' via UNO.
+ // This way - in the SW core - when it receives this - it will create a new 'Table Redline' object for that row
+ uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties();
+ pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::Any( aTableRedlineProperties ));
+ insertRowProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_cellIns:
+ case NS_ooxml::LN_CT_TcPrBase_cellDel:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ sal_Int32 nToken;
+ switch( nSprmId )
+ {
+ case NS_ooxml::LN_CT_TcPrBase_cellIns:
+ nToken = XML_tableCellInsert;
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_cellDel:
+ nToken = XML_tableCellDelete;
+ break;
+ default:
+ throw lang::IllegalArgumentException("illegal redline token type", nullptr, 0);
+ break;
+ }
+ auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>( nToken );
+ pProperties->resolve(*pTrackChangesHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+
+ // Add the 'track changes' properties to the 'table row' via UNO.
+ // This way - in the SW core - when it receives this - it will create a new 'Table Redline' object for that row
+ uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties();
+ pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::Any( aTableRedlineProperties ));
+ cellProps(pPropMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_cantSplit:
+ {
+ //row can't break across pages if nIntValue == 1
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->Insert( PROP_IS_SPLIT_ALLOWED, uno::Any( nIntValue != 1 ) );
+ insertRowProps(pPropMap);
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_vAlign:
+ {
+ sal_Int16 nVertOrient = text::VertOrientation::NONE;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_VerticalJc_center: nVertOrient = text::VertOrientation::CENTER; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_bottom: nVertOrient = text::VertOrientation::BOTTOM; break;
+ default:;
+ }
+ TablePropertyMapPtr pCellPropMap( new TablePropertyMap() );
+ pCellPropMap->Insert( PROP_VERT_ORIENT, uno::Any( nVertOrient ) );
+ //todo: in ooxml import the value of m_ncell is wrong
+ cellProps( pCellPropMap );
+ if (m_pCurrentInteropGrabBag)
+ {
+ OUString aVertOrient;
+ switch( nIntValue )
+ {
+ case NS_ooxml::LN_Value_ST_VerticalJc_top: aVertOrient = "top"; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_center: aVertOrient = "center"; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_both: aVertOrient = "both"; break;
+ case NS_ooxml::LN_Value_ST_VerticalJc_bottom: aVertOrient = "bottom"; break;
+ }
+ if (!aVertOrient.isEmpty())
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = "vAlign";
+ aValue.Value <<= aVertOrient;
+ m_pCurrentInteropGrabBag->push_back(aValue);
+ }
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblBorders: //table borders, might be defined in table style
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>(true);
+ if (m_pCurrentInteropGrabBag)
+ pBorderHandler->enableInteropGrabBag("tblBorders");
+ pProperties->resolve(*pBorderHandler);
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pBorderHandler->getInteropGrabBag());
+ TablePropertyMapPtr pTablePropMap( new TablePropertyMap );
+ pTablePropMap->InsertProps(pBorderHandler->getProperties());
+
+#ifdef DBG_UTIL
+ pTablePropMap->dumpXml();
+#endif
+ insertTableProps( pTablePropMap );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblLayout:
+ {
+ DomainMapperTableManager* pManager = dynamic_cast<DomainMapperTableManager*>(m_pTableManager);
+ if (pManager)
+ pManager->SetLayoutType(static_cast<sal_uInt32>(nIntValue));
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrEx_tblBorders:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties)
+ {
+ auto pBorderHandler = std::make_shared<BorderHandler>(true);
+ pProperties->resolve(*pBorderHandler);
+ TablePropertyMapPtr pTablePropMap( new TablePropertyMap );
+ pTablePropMap->InsertProps(pBorderHandler->getProperties());
+
+#ifdef DBG_UTIL
+ pTablePropMap->dumpXml();
+#endif
+ tableExceptionProps( pTablePropMap );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_tcBorders ://cell borders
+ //contains CT_TcBorders_left, right, top, bottom
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ //in OOXML there's one set of borders at each cell (if there is any)
+ tools::SvRef< TDefTableHandler > pTDefTableHandler( new TDefTableHandler());
+ if (m_pCurrentInteropGrabBag)
+ pTDefTableHandler->enableInteropGrabBag("tcBorders");
+ pProperties->resolve( *pTDefTableHandler );
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pTDefTableHandler->getInteropGrabBag());
+ TablePropertyMapPtr pCellPropMap( new TablePropertyMap );
+ pTDefTableHandler->fillCellProperties( pCellPropMap );
+ cellProps( pCellPropMap );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_tcMar:
+
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ auto pCellMarginHandler = std::make_shared<CellMarginHandler>();
+ if (m_pCurrentInteropGrabBag)
+ pCellMarginHandler->enableInteropGrabBag("tcMar");
+ pProperties->resolve(*pCellMarginHandler);
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pCellMarginHandler->getInteropGrabBag());
+ TablePropertyMapPtr pCellProperties(new TablePropertyMap);
+ if (pCellMarginHandler->m_bTopMarginValid)
+ pCellProperties->Insert(PROP_TOP_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nTopMargin));
+ if (pCellMarginHandler->m_bLeftMarginValid)
+ pCellProperties->Insert(PROP_LEFT_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nLeftMargin));
+ if (pCellMarginHandler->m_bBottomMarginValid)
+ pCellProperties->Insert(PROP_BOTTOM_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nBottomMargin));
+ if (pCellMarginHandler->m_bRightMarginValid)
+ pCellProperties->Insert(PROP_RIGHT_BORDER_DISTANCE, uno::Any(pCellMarginHandler->m_nRightMargin));
+ cellProps(pCellProperties);
+ }
+ }
+ break;
+/* // tdf#123189 skip to keep MSO interoperability
+ case NS_ooxml::LN_CT_TblPrBase_shd:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties.get())
+ {
+ std::shared_ptr<CellColorHandler> pCellColorHandler( new CellColorHandler);
+ pProperties->resolve( *pCellColorHandler );
+ TablePropertyMapPtr pTablePropMap( new TablePropertyMap );
+ insertTableProps( pCellColorHandler->getProperties() );
+ }
+ }
+*/
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_shd:
+ {
+ // each color sprm contains as much colors as cells are in a row
+ //LN_CT_TcPrBase_shd: cell shading contains: LN_CT_Shd_val, LN_CT_Shd_fill, LN_CT_Shd_color
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellColorHandler = std::make_shared<CellColorHandler>();
+ pCellColorHandler->enableInteropGrabBag("shd"); //enable to store shd unsupported props in grab bag
+ pProperties->resolve( *pCellColorHandler );
+ TablePropertyMapPtr pPropertyMap = pCellColorHandler->getProperties();
+ beans::PropertyValue aGrabBag = pCellColorHandler->getInteropGrabBag();
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(aGrabBag);
+ pPropertyMap->Insert( PROP_CELL_INTEROP_GRAB_BAG, aGrabBag.Value );
+ cellProps( pPropertyMap );
+ }
+ }
+ break;
+//OOXML table properties
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar: //cell margins
+ {
+ //contains LN_CT_TblCellMar_top, LN_CT_TblCellMar_left, LN_CT_TblCellMar_bottom, LN_CT_TblCellMar_right
+ // LN_CT_TblCellMar_start, LN_CT_TblCellMar_end
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ auto pCellMarginHandler = std::make_shared<CellMarginHandler>();
+ if (m_pCurrentInteropGrabBag)
+ pCellMarginHandler->enableInteropGrabBag("tblCellMar");
+ pProperties->resolve( *pCellMarginHandler );
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pCellMarginHandler->getInteropGrabBag());
+ TablePropertyMapPtr pMarginProps( new TablePropertyMap );
+ if( pCellMarginHandler->m_bTopMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_TOP, pCellMarginHandler->m_nTopMargin );
+ if( pCellMarginHandler->m_bBottomMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_BOTTOM, pCellMarginHandler->m_nBottomMargin );
+ if( pCellMarginHandler->m_bLeftMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_LEFT, pCellMarginHandler->m_nLeftMargin );
+ if( pCellMarginHandler->m_bRightMarginValid )
+ pMarginProps->setValue( TablePropertyMap::CELL_MAR_RIGHT, pCellMarginHandler->m_nRightMargin );
+ insertTableProps(pMarginProps);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblInd:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if (pProperties)
+ {
+ MeasureHandlerPtr pHandler(new MeasureHandler);
+ if (m_pCurrentInteropGrabBag)
+ pHandler->enableInteropGrabBag("tblInd");
+ pProperties->resolve( *pHandler );
+ if (m_pCurrentInteropGrabBag)
+ m_pCurrentInteropGrabBag->push_back(pHandler->getInteropGrabBag());
+ TablePropertyMapPtr pTblIndMap(new TablePropertyMap);
+ sal_uInt32 nTblInd = pHandler->getMeasureValue();
+ pTblIndMap->setValue( TablePropertyMap::LEFT_MARGIN, nTblInd);
+ insertTableProps(pTblIndMap);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TcPrBase_hideMark:
+ if (nIntValue)
+ {
+ TablePropertyMapPtr pPropMap(new TablePropertyMap());
+ pPropMap->Insert(PROP_CELL_HIDE_MARK, uno::Any(nIntValue));
+ cellProps(pPropMap);
+ }
+ break;
+ default:
+ // Not handled here, give the next handler a chance.
+ bRet = false;
+ // However, these logically belong here, so save the value if necessary.
+ switch (nSprmId)
+ {
+ case NS_ooxml::LN_CT_TblPrBase_tblStyleRowBandSize:
+ case NS_ooxml::LN_CT_TblPrBase_tblStyleColBandSize:
+ if (m_pCurrentInteropGrabBag)
+ {
+ beans::PropertyValue aValue;
+ aValue.Name = (nSprmId == NS_ooxml::LN_CT_TblPrBase_tblStyleRowBandSize ? std::u16string_view(u"tblStyleRowBandSize") : std::u16string_view(u"tblStyleColBandSize"));
+ aValue.Value <<= nIntValue;
+ m_pCurrentInteropGrabBag->push_back(aValue);
+ }
+ break;
+ }
+ break;
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+
+ return bRet;
+ }
+
+ void TablePropertiesHandler::SetInteropGrabBag(std::vector<beans::PropertyValue>& rValue)
+ {
+ m_pCurrentInteropGrabBag = &rValue;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TablePropertiesHandler.hxx b/sw/source/writerfilter/dmapper/TablePropertiesHandler.hxx
new file mode 100644
index 000000000000..9d8f90dc3925
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TablePropertiesHandler.hxx
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "PropertyMap.hxx"
+
+#include "TableManager.hxx"
+#include <dmapper/resourcemodel.hxx>
+
+#include <vector>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+
+class TablePropertiesHandler final : public virtual SvRefBase
+{
+private:
+ PropertyMapPtr m_pCurrentProperties;
+ std::vector<css::beans::PropertyValue>* m_pCurrentInteropGrabBag;
+ TableManager* m_pTableManager;
+
+public:
+ TablePropertiesHandler();
+
+ bool sprm(Sprm & sprm);
+
+ void SetTableManager( TableManager* pTableManager )
+ {
+ m_pTableManager = pTableManager;
+ }
+
+ void SetProperties(const PropertyMapPtr& pProperties)
+ {
+ m_pCurrentProperties = pProperties;
+ }
+
+ void SetInteropGrabBag(std::vector<css::beans::PropertyValue>& rValue);
+
+private:
+
+ void cellProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->cellProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+
+ void insertRowProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->insertRowProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+
+ void tableExceptionProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->tableExceptionProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+
+ void insertTableProps( TablePropertyMapPtr pProps )
+ {
+ if ( m_pTableManager )
+ m_pTableManager->insertTableProps( pProps );
+ else
+ m_pCurrentProperties->InsertProps(pProps.get());
+ };
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TagLogger.cxx b/sw/source/writerfilter/dmapper/TagLogger.cxx
new file mode 100644
index 000000000000..7a96b4aa6041
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TagLogger.cxx
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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()
+ : m_pWriter( nullptr ), m_pName( "DOMAINMAPPER" )
+ {
+ }
+
+ TagLogger::~TagLogger()
+ {
+ m_pWriter = nullptr;
+ m_pName = nullptr;
+ }
+
+#ifdef DBG_UTIL
+ void TagLogger::setFileName( const std::string & filename )
+ {
+ if ( m_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 += m_pName;
+ fileName += ".xml";
+
+ m_pWriter = xmlNewTextWriterFilename( fileName.c_str(), 0 );
+ xmlTextWriterSetIndent(m_pWriter,1);
+ (void)xmlTextWriterSetIndentString(m_pWriter, BAD_CAST(" "));
+ xmlTextWriterSetIndent( m_pWriter, 4 );
+ }
+
+ void TagLogger::startDocument()
+ {
+ if (!m_pWriter)
+ return;
+ (void)xmlTextWriterStartDocument( m_pWriter, nullptr, nullptr, nullptr );
+ (void)xmlTextWriterStartElement( m_pWriter, BAD_CAST( "root" ) );
+ }
+
+ void TagLogger::endDocument()
+ {
+ if (!m_pWriter)
+ return;
+ (void)xmlTextWriterEndDocument( m_pWriter );
+ xmlFreeTextWriter( m_pWriter );
+ m_pWriter = nullptr;
+ }
+
+#endif
+
+ TagLogger& TagLogger::getInstance()
+ {
+ static TagLogger theTagLogger;
+ return theTagLogger;
+ }
+
+#ifdef DBG_UTIL
+ void TagLogger::element(const std::string & name)
+ {
+ startElement(name);
+ endElement();
+ }
+
+ void TagLogger::unoPropertySet(const uno::Reference<beans::XPropertySet>& rPropSet)
+ {
+ uno::Reference<beans::XPropertySetInfo> xPropSetInfo(rPropSet->getPropertySetInfo());
+ const uno::Sequence<beans::Property> aProps(xPropSetInfo->getProperties());
+
+ startElement( "unoPropertySet" );
+
+ for (beans::Property const & prop : aProps)
+ {
+ startElement( "property" );
+ OUString sName(prop.Name);
+
+ attribute( "name", sName );
+ try
+ {
+ attribute( "value", rPropSet->getPropertyValue( sName ) );
+ }
+ catch (const uno::Exception &)
+ {
+ startElement( "exception" );
+
+ chars(std::string("getPropertyValue(\""));
+ chars(sName);
+ chars(std::string("\")"));
+
+ endElement( );
+ }
+ endElement( );
+ }
+ endElement( );
+ }
+
+ void TagLogger::startElement(const std::string & name)
+ {
+ if (!m_pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ (void)xmlTextWriterStartElement( m_pWriter, xmlName );
+ xmlFree( xmlName );
+ }
+#endif
+
+ void TagLogger::attribute(const std::string & name, const std::string & value)
+ {
+ if (!m_pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ xmlChar* xmlValue = xmlCharStrdup( value.c_str() );
+ (void)xmlTextWriterWriteAttribute( m_pWriter, xmlName, xmlValue );
+
+ xmlFree( xmlValue );
+ xmlFree( xmlName );
+ }
+
+#ifdef DBG_UTIL
+ void TagLogger::attribute(const std::string & name, std::u16string_view value)
+ {
+ attribute( name, std::string(OUStringToOString( value, RTL_TEXTENCODING_ASCII_US )) );
+ }
+
+ void TagLogger::attribute(const std::string & name, sal_uInt32 value)
+ {
+ if (!m_pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ (void)xmlTextWriterWriteFormatAttribute( m_pWriter, xmlName,
+ "%" SAL_PRIuUINT32, value );
+ xmlFree( xmlName );
+ }
+
+ void TagLogger::attribute(const std::string & name, float value)
+ {
+ if (!m_pWriter)
+ return;
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ (void)xmlTextWriterWriteFormatAttribute( m_pWriter, xmlName,
+ "%f", value );
+ xmlFree( xmlName );
+ }
+
+ void TagLogger::attribute(const std::string & name, const uno::Any& aAny)
+ {
+ if (!m_pWriter)
+ return;
+
+ sal_Int32 nInt = 0;
+ float nFloat = 0.0;
+ OUString aStr;
+
+ xmlChar* xmlName = xmlCharStrdup( name.c_str() );
+ if ( aAny >>= nInt )
+ {
+ (void)xmlTextWriterWriteFormatAttribute( m_pWriter, xmlName,
+ "%" SAL_PRIdINT32, nInt );
+ }
+ else if ( aAny >>= nFloat )
+ {
+ (void)xmlTextWriterWriteFormatAttribute( m_pWriter, xmlName,
+ "%f", nFloat );
+ }
+ else if ( aAny >>= aStr )
+ {
+ attribute( name, aStr );
+ }
+ xmlFree( xmlName );
+ }
+
+ void TagLogger::chars(const std::string & rChars)
+ {
+ if (!m_pWriter)
+ return;
+ xmlChar* xmlChars = xmlCharStrdup( rChars.c_str() );
+ (void)xmlTextWriterWriteString( m_pWriter, xmlChars );
+ xmlFree( xmlChars );
+ }
+
+ void TagLogger::chars(std::u16string_view rChars)
+ {
+ chars(std::string(OUStringToOString(rChars, RTL_TEXTENCODING_ASCII_US)));
+ }
+
+ void TagLogger::endElement()
+ {
+ if (!m_pWriter)
+ return;
+ (void)xmlTextWriterEndElement( m_pWriter );
+ }
+
+#endif
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TagLogger.hxx b/sw/source/writerfilter/dmapper/TagLogger.hxx
new file mode 100644
index 000000000000..f6d38096255f
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TagLogger.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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <string>
+#include <string_view>
+#include <type_traits>
+#include <libxml/xmlwriter.h>
+
+namespace writerfilter
+{
+
+ class TagLogger
+ {
+ private:
+ xmlTextWriterPtr m_pWriter;
+ const char* m_pName;
+
+ public:
+ explicit TagLogger();
+ ~TagLogger();
+
+ static TagLogger& getInstance();
+
+#ifdef DBG_UTIL
+ void setFileName(const std::string & filename);
+ void startDocument();
+ void endDocument();
+
+ void element(const std::string & name);
+ void unoPropertySet(const css::uno::Reference<css::beans::XPropertySet>& rPropSet);
+ void startElement(const std::string & name);
+#endif
+ void attribute(const std::string & name, const std::string & value);
+#ifdef DBG_UTIL
+ void attribute(const std::string & name, std::u16string_view value);
+ void attribute(const std::string & name, sal_uInt32 value);
+ template<typename T> std::enable_if_t<std::is_integral_v<T>, void>
+ attribute(const std::string & name, T value)
+ { return attribute(name, static_cast<sal_uInt32>(value)); }
+ void attribute(const std::string & name, float value);
+ void attribute(const std::string & name, const css::uno::Any& aAny);
+ void chars(const std::string & chars);
+ void chars(std::u16string_view chars);
+ void endElement();
+#endif
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TblStylePrHandler.cxx b/sw/source/writerfilter/dmapper/TblStylePrHandler.cxx
new file mode 100644
index 000000000000..13656e169ba7
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TblStylePrHandler.cxx
@@ -0,0 +1,259 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "TblStylePrHandler.hxx"
+#include "TagLogger.hxx"
+#include "CellMarginHandler.hxx"
+#include "PropertyMap.hxx"
+#include "MeasureHandler.hxx"
+#include <ooxml/resourceids.hxx>
+#include <comphelper/sequence.hxx>
+
+
+using namespace css;
+
+namespace writerfilter::dmapper {
+
+TblStylePrHandler::TblStylePrHandler( DomainMapper & rDMapper ) :
+LoggedProperties("TblStylePrHandler"),
+m_rDMapper( rDMapper ),
+m_pTablePropsHandler(new TablePropertiesHandler()),
+m_nType( TBL_STYLE_UNKNOWN ),
+m_pProperties( new PropertyMap )
+{
+}
+
+TblStylePrHandler::~TblStylePrHandler( )
+{
+}
+
+OUString TblStylePrHandler::getTypeString() const
+{
+ switch (m_nType)
+ {
+ case TBL_STYLE_WHOLETABLE: return "wholeTable";
+ case TBL_STYLE_FIRSTROW: return "firstRow";
+ case TBL_STYLE_LASTROW: return "lastRow";
+ case TBL_STYLE_FIRSTCOL: return "firstCol";
+ case TBL_STYLE_LASTCOL: return "lastCol";
+ case TBL_STYLE_BAND1VERT: return "band1Vert";
+ case TBL_STYLE_BAND2VERT: return "band2Vert";
+ case TBL_STYLE_BAND1HORZ: return "band1Horz";
+ case TBL_STYLE_BAND2HORZ: return "band2Horz";
+ case TBL_STYLE_NECELL: return "neCell";
+ case TBL_STYLE_NWCELL: return "nwCell";
+ case TBL_STYLE_SECELL: return "seCell";
+ case TBL_STYLE_SWCELL: return "swCell";
+ default: break;
+ }
+ return OUString();
+}
+
+void TblStylePrHandler::lcl_attribute(Id rName, Value & rVal)
+{
+
+ switch ( rName )
+ {
+ case NS_ooxml::LN_CT_TblStyleOverrideType:
+ {
+ switch (rVal.getInt())
+ {
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_wholeTable:
+ m_nType = TBL_STYLE_WHOLETABLE;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_firstRow:
+ m_nType = TBL_STYLE_FIRSTROW;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_lastRow:
+ m_nType = TBL_STYLE_LASTROW;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_firstCol:
+ m_nType = TBL_STYLE_FIRSTCOL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_lastCol:
+ m_nType = TBL_STYLE_LASTCOL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band1Vert:
+ m_nType = TBL_STYLE_BAND1VERT;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band2Vert:
+ m_nType = TBL_STYLE_BAND2VERT;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band1Horz:
+ m_nType = TBL_STYLE_BAND1HORZ;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_band2Horz:
+ m_nType = TBL_STYLE_BAND2HORZ;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_neCell:
+ m_nType = TBL_STYLE_NECELL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_nwCell:
+ m_nType = TBL_STYLE_NWCELL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_seCell:
+ m_nType = TBL_STYLE_SECELL;
+ break;
+ case NS_ooxml::LN_Value_ST_TblStyleOverrideType_swCell:
+ m_nType = TBL_STYLE_SWCELL;
+ break;
+ }
+ }
+ break;
+ }
+}
+
+void TblStylePrHandler::lcl_sprm(Sprm & rSprm)
+{
+#ifdef DBG_UTIL
+ TagLogger::getInstance().startElement("TblStylePrHandler.sprm");
+ TagLogger::getInstance().attribute("sprm", rSprm.toString());
+#endif
+
+ switch ( rSprm.getId( ) )
+ {
+ case NS_ooxml::LN_CT_PPrBase:
+ case NS_ooxml::LN_EG_RPrBase:
+ case NS_ooxml::LN_CT_TblPrBase:
+ case NS_ooxml::LN_CT_TrPrBase:
+ case NS_ooxml::LN_CT_TcPrBase:
+ {
+ std::vector<beans::PropertyValue> aSavedGrabBag;
+ bool bGrabBag = rSprm.getId() == NS_ooxml::LN_CT_PPrBase ||
+ rSprm.getId() == NS_ooxml::LN_EG_RPrBase ||
+ rSprm.getId() == NS_ooxml::LN_CT_TblPrBase ||
+ rSprm.getId() == NS_ooxml::LN_CT_TrPrBase ||
+ rSprm.getId() == NS_ooxml::LN_CT_TcPrBase;
+ if (bGrabBag)
+ {
+ std::swap(aSavedGrabBag, m_aInteropGrabBag);
+ }
+ resolveSprmProps( rSprm );
+ if (bGrabBag)
+ {
+ if (rSprm.getId() == NS_ooxml::LN_CT_PPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("pPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_EG_RPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("rPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_CT_TblPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("tblPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_CT_TrPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("trPr"));
+ else if (rSprm.getId() == NS_ooxml::LN_CT_TcPrBase)
+ aSavedGrabBag.push_back(getInteropGrabBag("tcPr"));
+ std::swap(m_aInteropGrabBag, aSavedGrabBag);
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TrPrBase_tblHeader:
+ {
+ m_pProperties->Insert( PROP_HEADER_ROW_COUNT, uno::Any(sal_Int32(1)));
+ beans::PropertyValue aValue;
+ aValue.Name = "tblHeader";
+ aValue.Value <<= true;
+ m_aInteropGrabBag.push_back(aValue);
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblInd:
+ {
+ //contains unit and value
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ {
+ MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
+ pProperties->resolve(*pMeasureHandler);
+ TablePropertyMapPtr pPropMap( new TablePropertyMap );
+ pPropMap->setValue( TablePropertyMap::LEFT_MARGIN, pMeasureHandler->getMeasureValue() );
+ m_pProperties->Insert( PROP_LEFT_MARGIN, uno::Any(pMeasureHandler->getMeasureValue()) );
+ }
+ }
+ break;
+ case NS_ooxml::LN_CT_TblPrBase_tblCellMar:
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if ( pProperties )
+ {
+ auto pCellMarginHandler = std::make_shared<CellMarginHandler>();
+ pCellMarginHandler->enableInteropGrabBag("tblCellMar");
+ pProperties->resolve( *pCellMarginHandler );
+ m_aInteropGrabBag.push_back(pCellMarginHandler->getInteropGrabBag());
+
+ if( pCellMarginHandler->m_bTopMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_TOP, uno::Any(pCellMarginHandler->m_nTopMargin) );
+ if( pCellMarginHandler->m_bBottomMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_BOTTOM, uno::Any(pCellMarginHandler->m_nBottomMargin) );
+ if( pCellMarginHandler->m_bLeftMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_LEFT, uno::Any(pCellMarginHandler->m_nLeftMargin) );
+ if( pCellMarginHandler->m_bRightMarginValid )
+ m_pProperties->Insert( META_PROP_CELL_MAR_RIGHT, uno::Any(pCellMarginHandler->m_nRightMargin) );
+ }
+ }
+ break;
+ default:
+ // Tables specific properties have to handled here
+ m_pTablePropsHandler->SetProperties( m_pProperties );
+ m_pTablePropsHandler->SetInteropGrabBag(m_aInteropGrabBag);
+ bool bRet = m_pTablePropsHandler->sprm( rSprm );
+
+ if ( !bRet )
+ {
+ // The DomainMapper can handle some of the properties
+ m_rDMapper.PushStyleSheetProperties( m_pProperties, true );
+ // Just pass a non-empty string, the array will have a single element anyway.
+ m_rDMapper.enableInteropGrabBag("TblStylePrHandler");
+ m_rDMapper.sprm( rSprm );
+ uno::Sequence<beans::PropertyValue> aGrabBag = m_rDMapper.getInteropGrabBag().Value.get< uno::Sequence<beans::PropertyValue> >();
+ if (aGrabBag.hasElements())
+ m_aInteropGrabBag.push_back(aGrabBag[0]);
+ m_rDMapper.PopStyleSheetProperties( true );
+ }
+ }
+
+#ifdef DBG_UTIL
+ TagLogger::getInstance().endElement();
+#endif
+}
+
+void TblStylePrHandler::resolveSprmProps(Sprm & rSprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( pProperties )
+ pProperties->resolve(*this);
+}
+
+void TblStylePrHandler::appendInteropGrabBag(const OUString& aKey, const OUString& aValue)
+{
+ beans::PropertyValue aProperty;
+ aProperty.Name = aKey;
+ aProperty.Value <<= aValue;
+ m_aInteropGrabBag.push_back(aProperty);
+}
+
+beans::PropertyValue TblStylePrHandler::getInteropGrabBag(const OUString& aName)
+{
+ beans::PropertyValue aRet;
+ aRet.Name = aName;
+
+ aRet.Value <<= comphelper::containerToSequence(m_aInteropGrabBag);
+ return aRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TblStylePrHandler.hxx b/sw/source/writerfilter/dmapper/TblStylePrHandler.hxx
new file mode 100644
index 000000000000..4be7d379a647
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TblStylePrHandler.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "TablePropertiesHandler.hxx"
+
+#include "DomainMapper.hxx"
+#include "LoggedResources.hxx"
+#include <memory>
+#include <vector>
+
+namespace writerfilter::dmapper {
+
+class DomainMapper;
+
+enum TblStyleType
+{
+ TBL_STYLE_UNKNOWN,
+ TBL_STYLE_WHOLETABLE,
+ TBL_STYLE_FIRSTROW,
+ TBL_STYLE_LASTROW,
+ TBL_STYLE_FIRSTCOL,
+ TBL_STYLE_LASTCOL,
+ TBL_STYLE_BAND1VERT,
+ TBL_STYLE_BAND2VERT,
+ TBL_STYLE_BAND1HORZ,
+ TBL_STYLE_BAND2HORZ,
+ TBL_STYLE_NECELL,
+ TBL_STYLE_NWCELL,
+ TBL_STYLE_SECELL,
+ TBL_STYLE_SWCELL
+};
+
+class TblStylePrHandler : public LoggedProperties
+{
+private:
+ DomainMapper & m_rDMapper;
+ std::unique_ptr<TablePropertiesHandler> m_pTablePropsHandler;
+
+ TblStyleType m_nType;
+ PropertyMapPtr m_pProperties;
+ std::vector<css::beans::PropertyValue> m_aInteropGrabBag;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value & val) override;
+ virtual void lcl_sprm(Sprm & sprm) override;
+
+public:
+ explicit TblStylePrHandler( DomainMapper & rDMapper );
+ virtual ~TblStylePrHandler( ) override;
+
+ const PropertyMapPtr& getProperties() const { return m_pProperties; };
+ TblStyleType getType() const { return m_nType; };
+ OUString getTypeString() const;
+ void appendInteropGrabBag(const OUString& aKey, const OUString& aValue);
+ css::beans::PropertyValue getInteropGrabBag(const OUString& aName);
+
+private:
+
+ void resolveSprmProps(Sprm & rSprm);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TextEffectsHandler.cxx b/sw/source/writerfilter/dmapper/TextEffectsHandler.cxx
new file mode 100644
index 000000000000..35d7efbbfee2
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TextEffectsHandler.cxx
@@ -0,0 +1,806 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <sal/config.h>
+
+#include <map>
+
+#include "TextEffectsHandler.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/string.hxx>
+#include <ooxml/resourceids.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+
+namespace writerfilter::dmapper
+{
+
+using namespace com::sun::star;
+
+namespace
+{
+
+OUString lclGetNameForElementId(sal_uInt32 aId)
+{
+ static std::map<sal_uInt32, OUString> aIdMap;
+ if(aIdMap.empty())
+ {
+ aIdMap[NS_ooxml::LN_EG_ColorChoice_srgbClr] = "srgbClr";
+ aIdMap[NS_ooxml::LN_EG_ColorChoice_schemeClr] = "schemeClr";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_tint] = "tint";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_shade] = "shade";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_alpha] = "alpha";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_hueMod] = "hueMod";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_sat] = "sat";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_satOff] = "satOff";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_satMod] = "satMod";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_lum] = "lum";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_lumOff] = "lumOff";
+ aIdMap[NS_ooxml::LN_EG_ColorTransform_lumMod] = "lumMod";
+ aIdMap[NS_ooxml::LN_EG_FillProperties_noFill] = "noFill";
+ aIdMap[NS_ooxml::LN_EG_FillProperties_solidFill] = "solidFill";
+ aIdMap[NS_ooxml::LN_EG_FillProperties_gradFill] = "gradFill";
+ aIdMap[NS_ooxml::LN_CT_GradientFillProperties_gsLst] = "gsLst";
+ aIdMap[NS_ooxml::LN_CT_GradientStopList_gs] = "gs";
+ aIdMap[NS_ooxml::LN_CT_GradientStop_pos] = "pos";
+ aIdMap[NS_ooxml::LN_EG_ShadeProperties_lin] = "lin";
+ aIdMap[NS_ooxml::LN_EG_ShadeProperties_path] = "path";
+ aIdMap[NS_ooxml::LN_CT_PathShadeProperties_fillToRect] = "fillToRect";
+ aIdMap[NS_ooxml::LN_EG_LineDashProperties_prstDash] = "prstDash";
+ aIdMap[NS_ooxml::LN_EG_LineJoinProperties_round] = "round";
+ aIdMap[NS_ooxml::LN_EG_LineJoinProperties_bevel] = "bevel";
+ aIdMap[NS_ooxml::LN_EG_LineJoinProperties_miter] = "miter";
+ aIdMap[NS_ooxml::LN_CT_Scene3D_camera] = "camera";
+ aIdMap[NS_ooxml::LN_CT_Scene3D_lightRig] = "lightRig";
+ aIdMap[NS_ooxml::LN_CT_LightRig_rot] = "rot";
+ aIdMap[NS_ooxml::LN_CT_Props3D_bevelT] = "bevelT";
+ aIdMap[NS_ooxml::LN_CT_Props3D_bevelB] = "bevelB";
+ aIdMap[NS_ooxml::LN_CT_Props3D_extrusionClr] = "extrusionClr";
+ aIdMap[NS_ooxml::LN_CT_Props3D_contourClr] = "contourClr";
+ aIdMap[NS_ooxml::LN_CT_StylisticSets_styleSet] = "styleSet";
+ aIdMap[NS_ooxml::LN_cntxtAlts_cntxtAlts] = "cntxtAlts";
+ }
+ return aIdMap[aId];
+}
+
+constexpr OUString constAttributesSequenceName = u"attributes"_ustr;
+
+}
+
+OUString TextEffectsHandler::getSchemeColorValTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_SchemeColorVal_bg1: return "bg1";
+ case NS_ooxml::LN_ST_SchemeColorVal_tx1: return "tx1";
+ case NS_ooxml::LN_ST_SchemeColorVal_bg2: return "bg2";
+ case NS_ooxml::LN_ST_SchemeColorVal_tx2: return "tx2";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent1: return "accent1";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent2: return "accent2";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent3: return "accent3";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent4: return "accent4";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent5: return "accent5";
+ case NS_ooxml::LN_ST_SchemeColorVal_accent6: return "accent6";
+ case NS_ooxml::LN_ST_SchemeColorVal_hlink: return "hlink";
+ case NS_ooxml::LN_ST_SchemeColorVal_folHlink: return "folHlink";
+ case NS_ooxml::LN_ST_SchemeColorVal_dk1: return "dk1";
+ case NS_ooxml::LN_ST_SchemeColorVal_lt1: return "lt1";
+ case NS_ooxml::LN_ST_SchemeColorVal_dk2: return "dk2";
+ case NS_ooxml::LN_ST_SchemeColorVal_lt2: return "lt2";
+ case NS_ooxml::LN_ST_SchemeColorVal_phClr: return "phClr";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getRectAlignmentString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_RectAlignment_none: return "none";
+ case NS_ooxml::LN_ST_RectAlignment_tl: return "tl";
+ case NS_ooxml::LN_ST_RectAlignment_t: return "t";
+ case NS_ooxml::LN_ST_RectAlignment_tr: return "tr";
+ case NS_ooxml::LN_ST_RectAlignment_l: return "l";
+ case NS_ooxml::LN_ST_RectAlignment_ctr: return "ctr";
+ case NS_ooxml::LN_ST_RectAlignment_r: return "r";
+ case NS_ooxml::LN_ST_RectAlignment_bl: return "bl";
+ case NS_ooxml::LN_ST_RectAlignment_b: return "b";
+ case NS_ooxml::LN_ST_RectAlignment_br: return "br";
+
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getLineCapString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_LineCap_rnd: return "rnd";
+ case NS_ooxml::LN_ST_LineCap_sq: return "sq";
+ case NS_ooxml::LN_ST_LineCap_flat: return "flat";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getCompoundLineString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_CompoundLine_sng: return "sng";
+ case NS_ooxml::LN_ST_CompoundLine_dbl: return "dbl";
+ case NS_ooxml::LN_ST_CompoundLine_thickThin: return "thickThin";
+ case NS_ooxml::LN_ST_CompoundLine_thinThick: return "thinThick";
+ case NS_ooxml::LN_ST_CompoundLine_tri: return "tri";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPenAlignmentString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PenAlignment_ctr: return "ctr";
+ case NS_ooxml::LN_ST_PenAlignment_in: return "in";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getOnOffString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_OnOff_true: return "true";
+ case NS_ooxml::LN_ST_OnOff_false: return "false";
+ case NS_ooxml::LN_ST_OnOff_1: return "1";
+ case NS_ooxml::LN_ST_OnOff_0: return "0";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPathShadeTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PathShadeType_shape: return "shape";
+ case NS_ooxml::LN_ST_PathShadeType_circle: return "circle";
+ case NS_ooxml::LN_ST_PathShadeType_rect: return "rect";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPresetLineDashValString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PresetLineDashVal_solid: return "solid";
+ case NS_ooxml::LN_ST_PresetLineDashVal_dot: return "dot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDot: return "sysDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_dash: return "dash";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDash: return "sysDash";
+ case NS_ooxml::LN_ST_PresetLineDashVal_lgDash: return "lgDash";
+ case NS_ooxml::LN_ST_PresetLineDashVal_dashDot: return "dashDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDashDot: return "sysDashDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_lgDashDot: return "lgDashDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_lgDashDotDot: return "lgDashDotDot";
+ case NS_ooxml::LN_ST_PresetLineDashVal_sysDashDotDot: return "sysDashDotDot";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPresetCameraTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueTopLeft: return "legacyObliqueTopLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueTop: return "legacyObliqueTop";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueTopRight: return "legacyObliqueTopRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueLeft: return "legacyObliqueLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueFront: return "legacyObliqueFront";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueRight: return "legacyObliqueRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueBottomLeft: return "legacyObliqueBottomLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueBottom: return "legacyObliqueBottom";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyObliqueBottomRight: return "legacyObliqueBottomRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveTopLeft: return "legacyPerspectiveTopLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveTop: return "legacyPerspectiveTop";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveTopRight: return "legacyPerspectiveTopRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveLeft: return "legacyPerspectiveLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveFront: return "legacyPerspectiveFront";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveRight: return "legacyPerspectiveRight";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveBottomLeft: return "legacyPerspectiveBottomLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveBottom: return "legacyPerspectiveBottom";
+ case NS_ooxml::LN_ST_PresetCameraType_legacyPerspectiveBottomRight: return "legacyPerspectiveBottomRight";
+ case NS_ooxml::LN_ST_PresetCameraType_orthographicFront: return "orthographicFront";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricTopUp: return "isometricTopUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricTopDown: return "isometricTopDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricBottomUp: return "isometricBottomUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricBottomDown: return "isometricBottomDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricLeftUp: return "isometricLeftUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricLeftDown: return "isometricLeftDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricRightUp: return "isometricRightUp";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricRightDown: return "isometricRightDown";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis1Left: return "isometricOffAxis1Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis1Right: return "isometricOffAxis1Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis1Top: return "isometricOffAxis1Top";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis2Left: return "isometricOffAxis2Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis2Right: return "isometricOffAxis2Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis2Top: return "isometricOffAxis2Top";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis3Left: return "isometricOffAxis3Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis3Right: return "isometricOffAxis3Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis3Bottom: return "isometricOffAxis3Bottom";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis4Left: return "isometricOffAxis4Left";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis4Right: return "isometricOffAxis4Right";
+ case NS_ooxml::LN_ST_PresetCameraType_isometricOffAxis4Bottom: return "isometricOffAxis4Bottom";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueTopLeft: return "obliqueTopLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueTop: return "obliqueTop";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueTopRight: return "obliqueTopRight";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueLeft: return "obliqueLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueRight: return "obliqueRight";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueBottomLeft: return "obliqueBottomLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueBottom: return "obliqueBottom";
+ case NS_ooxml::LN_ST_PresetCameraType_obliqueBottomRight: return "obliqueBottomRight";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveFront: return "perspectiveFront";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveLeft: return "perspectiveLeft";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveRight: return "perspectiveRight";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveAbove: return "perspectiveAbove";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveBelow: return "perspectiveBelow";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveAboveLeftFacing: return "perspectiveAboveLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveAboveRightFacing: return "perspectiveAboveRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveContrastingLeftFacing: return "perspectiveContrastingLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveContrastingRightFacing: return "perspectiveContrastingRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicLeftFacing: return "perspectiveHeroicLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicRightFacing: return "perspectiveHeroicRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicExtremeLeftFacing: return "perspectiveHeroicExtremeLeftFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveHeroicExtremeRightFacing: return "perspectiveHeroicExtremeRightFacing";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveRelaxed: return "perspectiveRelaxed";
+ case NS_ooxml::LN_ST_PresetCameraType_perspectiveRelaxedModerately: return "perspectiveRelaxedModerately";
+ default: break;
+ }
+ return OUString();
+}
+
+
+OUString TextEffectsHandler::getLightRigTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat1: return "legacyFlat1";
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat2: return "legacyFlat2";
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat3: return "legacyFlat3";
+ case NS_ooxml::LN_ST_LightRigType_legacyFlat4: return "legacyFlat4";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal1: return "legacyNormal1";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal2: return "legacyNormal2";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal3: return "legacyNormal3";
+ case NS_ooxml::LN_ST_LightRigType_legacyNormal4: return "legacyNormal4";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh1: return "legacyHarsh1";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh2: return "legacyHarsh2";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh3: return "legacyHarsh3";
+ case NS_ooxml::LN_ST_LightRigType_legacyHarsh4: return "legacyHarsh4";
+ case NS_ooxml::LN_ST_LightRigType_threePt: return "threePt";
+ case NS_ooxml::LN_ST_LightRigType_balanced: return "balanced";
+ case NS_ooxml::LN_ST_LightRigType_soft: return "soft";
+ case NS_ooxml::LN_ST_LightRigType_harsh: return "harsh";
+ case NS_ooxml::LN_ST_LightRigType_flood: return "flood";
+ case NS_ooxml::LN_ST_LightRigType_contrasting: return "contrasting";
+ case NS_ooxml::LN_ST_LightRigType_morning: return "morning";
+ case NS_ooxml::LN_ST_LightRigType_sunrise: return "sunrise";
+ case NS_ooxml::LN_ST_LightRigType_sunset: return "sunset";
+ case NS_ooxml::LN_ST_LightRigType_chilly: return "chilly";
+ case NS_ooxml::LN_ST_LightRigType_freezing: return "freezing";
+ case NS_ooxml::LN_ST_LightRigType_flat: return "flat";
+ case NS_ooxml::LN_ST_LightRigType_twoPt: return "twoPt";
+ case NS_ooxml::LN_ST_LightRigType_glow: return "glow";
+ case NS_ooxml::LN_ST_LightRigType_brightRoom: return "brightRoom";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getLightRigDirectionString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_LightRigDirection_tl: return "tl";
+ case NS_ooxml::LN_ST_LightRigDirection_t: return "t";
+ case NS_ooxml::LN_ST_LightRigDirection_tr: return "tr";
+ case NS_ooxml::LN_ST_LightRigDirection_l: return "l";
+ case NS_ooxml::LN_ST_LightRigDirection_r: return "r";
+ case NS_ooxml::LN_ST_LightRigDirection_bl: return "bl";
+ case NS_ooxml::LN_ST_LightRigDirection_b: return "b";
+ case NS_ooxml::LN_ST_LightRigDirection_br: return "br";
+
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getBevelPresetTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_BevelPresetType_relaxedInset: return "relaxedInset";
+ case NS_ooxml::LN_ST_BevelPresetType_circle: return "circle";
+ case NS_ooxml::LN_ST_BevelPresetType_slope: return "slope";
+ case NS_ooxml::LN_ST_BevelPresetType_cross: return "cross";
+ case NS_ooxml::LN_ST_BevelPresetType_angle: return "angle";
+ case NS_ooxml::LN_ST_BevelPresetType_softRound: return "softRound";
+ case NS_ooxml::LN_ST_BevelPresetType_convex: return "convex";
+ case NS_ooxml::LN_ST_BevelPresetType_coolSlant: return "coolSlant";
+ case NS_ooxml::LN_ST_BevelPresetType_divot: return "divot";
+ case NS_ooxml::LN_ST_BevelPresetType_riblet: return "riblet";
+ case NS_ooxml::LN_ST_BevelPresetType_hardEdge: return "hardEdge";
+ case NS_ooxml::LN_ST_BevelPresetType_artDeco: return "artDeco";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getPresetMaterialTypeString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyMatte: return "legacyMatte";
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyPlastic: return "legacyPlastic";
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyMetal: return "legacyMetal";
+ case NS_ooxml::LN_ST_PresetMaterialType_legacyWireframe: return "legacyWireframe";
+ case NS_ooxml::LN_ST_PresetMaterialType_matte: return "matte";
+ case NS_ooxml::LN_ST_PresetMaterialType_plastic: return "plastic";
+ case NS_ooxml::LN_ST_PresetMaterialType_metal: return "metal";
+ case NS_ooxml::LN_ST_PresetMaterialType_warmMatte: return "warmMatte";
+ case NS_ooxml::LN_ST_PresetMaterialType_translucentPowder: return "translucentPowder";
+ case NS_ooxml::LN_ST_PresetMaterialType_powder: return "powder";
+ case NS_ooxml::LN_ST_PresetMaterialType_dkEdge: return "dkEdge";
+ case NS_ooxml::LN_ST_PresetMaterialType_softEdge: return "softEdge";
+ case NS_ooxml::LN_ST_PresetMaterialType_clear: return "clear";
+ case NS_ooxml::LN_ST_PresetMaterialType_flat: return "flat";
+ case NS_ooxml::LN_ST_PresetMaterialType_softmetal: return "softmetal";
+ case NS_ooxml::LN_ST_PresetMaterialType_none: return "none";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getLigaturesString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_Ligatures_none: return "none";
+ case NS_ooxml::LN_ST_Ligatures_standard: return "standard";
+ case NS_ooxml::LN_ST_Ligatures_contextual: return "contextual";
+ case NS_ooxml::LN_ST_Ligatures_historical: return "historical";
+ case NS_ooxml::LN_ST_Ligatures_discretional: return "discretional";
+ case NS_ooxml::LN_ST_Ligatures_standardContextual: return "standardContextual";
+ case NS_ooxml::LN_ST_Ligatures_standardHistorical: return "standardHistorical";
+ case NS_ooxml::LN_ST_Ligatures_contextualHistorical: return "contextualHistorical";
+ case NS_ooxml::LN_ST_Ligatures_standardDiscretional: return "standardDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_contextualDiscretional: return "contextualDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_historicalDiscretional: return "historicalDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_standardContextualHistorical: return "standardContextualHistorical";
+ case NS_ooxml::LN_ST_Ligatures_standardContextualDiscretional: return "standardContextualDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_standardHistoricalDiscretional: return "standardHistoricalDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_contextualHistoricalDiscretional: return "contextualHistoricalDiscretional";
+ case NS_ooxml::LN_ST_Ligatures_all: return "all";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getNumFormString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_NumForm_default: return "default";
+ case NS_ooxml::LN_ST_NumForm_lining: return "lining";
+ case NS_ooxml::LN_ST_NumForm_oldStyle: return "oldStyle";
+ default: break;
+ }
+ return OUString();
+}
+
+OUString TextEffectsHandler::getNumSpacingString(sal_Int32 nType)
+{
+ switch (nType)
+ {
+ case NS_ooxml::LN_ST_NumSpacing_default: return "default";
+ case NS_ooxml::LN_ST_NumSpacing_proportional: return "proportional";
+ case NS_ooxml::LN_ST_NumSpacing_tabular: return "tabular";
+ default: break;
+ }
+ return OUString();
+}
+
+void TextEffectsHandler::convertElementIdToPropertyId(sal_Int32 aElementId)
+{
+ switch(aElementId)
+ {
+ case NS_ooxml::LN_glow_glow:
+ maPropertyId = PROP_CHAR_GLOW_TEXT_EFFECT;
+ maElementName = "glow";
+ break;
+ case NS_ooxml::LN_shadow_shadow:
+ maPropertyId = PROP_CHAR_SHADOW_TEXT_EFFECT;
+ maElementName = "shadow";
+ break;
+ case NS_ooxml::LN_reflection_reflection:
+ maPropertyId = PROP_CHAR_REFLECTION_TEXT_EFFECT;
+ maElementName = "reflection";
+ break;
+ case NS_ooxml::LN_textOutline_textOutline:
+ maPropertyId = PROP_CHAR_TEXTOUTLINE_TEXT_EFFECT;
+ maElementName = "textOutline";
+ break;
+ case NS_ooxml::LN_textFill_textFill:
+ maPropertyId = PROP_CHAR_TEXTFILL_TEXT_EFFECT;
+ maElementName = "textFill";
+ break;
+ case NS_ooxml::LN_scene3d_scene3d:
+ maPropertyId = PROP_CHAR_SCENE3D_TEXT_EFFECT;
+ maElementName = "scene3d";
+ break;
+ case NS_ooxml::LN_props3d_props3d:
+ maPropertyId = PROP_CHAR_PROPS3D_TEXT_EFFECT;
+ maElementName = "props3d";
+ break;
+ case NS_ooxml::LN_ligatures_ligatures:
+ maPropertyId = PROP_CHAR_LIGATURES_TEXT_EFFECT;
+ maElementName = "ligatures";
+ break;
+ case NS_ooxml::LN_numForm_numForm:
+ maPropertyId = PROP_CHAR_NUMFORM_TEXT_EFFECT;
+ maElementName = "numForm";
+ break;
+ case NS_ooxml::LN_numSpacing_numSpacing:
+ maPropertyId = PROP_CHAR_NUMSPACING_TEXT_EFFECT;
+ maElementName = "numSpacing";
+ break;
+ case NS_ooxml::LN_stylisticSets_stylisticSets:
+ maPropertyId = PROP_CHAR_STYLISTICSETS_TEXT_EFFECT;
+ maElementName = "stylisticSets";
+ break;
+ case NS_ooxml::LN_cntxtAlts_cntxtAlts:
+ maPropertyId = PROP_CHAR_CNTXTALTS_TEXT_EFFECT;
+ maElementName = "cntxtAlts";
+ break;
+ default:
+ break;
+ }
+}
+
+TextEffectsHandler::TextEffectsHandler(sal_uInt32 aElementId) :
+ LoggedProperties("TextEffectsHandler")
+{
+ convertElementIdToPropertyId(aElementId);
+ mpGrabBagStack.reset(new oox::GrabBagStack(maElementName));
+}
+
+TextEffectsHandler::~TextEffectsHandler()
+{
+}
+
+
+void TextEffectsHandler::lcl_attribute(Id aName, Value& aValue)
+{
+ if (mpGrabBagStack->getCurrentName() != constAttributesSequenceName)
+ mpGrabBagStack->push(constAttributesSequenceName);
+
+ switch(aName)
+ {
+ case NS_ooxml::LN_CT_Percentage_val:
+ case NS_ooxml::LN_CT_PositiveFixedPercentage_val:
+ case NS_ooxml::LN_CT_PositivePercentage_val:
+ mpGrabBagStack->addInt32("val", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Glow_rad:
+ mpGrabBagStack->addInt32("rad", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_SchemeColor_val:
+ {
+ OUString aString = getSchemeColorValTypeString(sal_Int32(aValue.getInt()));
+ mpGrabBagStack->addString("val", aString);
+ }
+ break;
+ case NS_ooxml::LN_CT_SRgbColor_val:
+ {
+ OUString aBuffer = OUString::number(aValue.getInt(), 16);
+ OUStringBuffer aString;
+ comphelper::string::padToLength(aString, 6 - aBuffer.getLength(), '0');
+ aString.append(aBuffer.getStr());
+ mpGrabBagStack->addString("val", aString.makeStringAndClear().toAsciiUpperCase());
+ }
+ break;
+ case NS_ooxml::LN_CT_Shadow_blurRad:
+ case NS_ooxml::LN_CT_Reflection_blurRad:
+ mpGrabBagStack->addInt32("blurRad", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_stA:
+ mpGrabBagStack->addInt32("stA", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_stPos:
+ mpGrabBagStack->addInt32("stPos", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_endA:
+ mpGrabBagStack->addInt32("endA", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_endPos:
+ mpGrabBagStack->addInt32("endPos", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_dist:
+ case NS_ooxml::LN_CT_Reflection_dist:
+ mpGrabBagStack->addInt32("dist", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_dir:
+ case NS_ooxml::LN_CT_Reflection_dir:
+ mpGrabBagStack->addInt32("dir", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Reflection_fadeDir:
+ mpGrabBagStack->addInt32("fadeDir", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_sx:
+ case NS_ooxml::LN_CT_Reflection_sx:
+ mpGrabBagStack->addInt32("sx", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_sy:
+ case NS_ooxml::LN_CT_Reflection_sy:
+ mpGrabBagStack->addInt32("sy", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_kx:
+ case NS_ooxml::LN_CT_Reflection_kx:
+ mpGrabBagStack->addInt32("kx", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_ky:
+ case NS_ooxml::LN_CT_Reflection_ky:
+ mpGrabBagStack->addInt32("ky", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Shadow_algn:
+ case NS_ooxml::LN_CT_Reflection_algn:
+ {
+ uno::Any aAny(getRectAlignmentString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("algn", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_w:
+ mpGrabBagStack->addInt32("w", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_cap:
+ {
+ uno::Any aAny(getLineCapString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("cap", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_cmpd:
+ {
+ uno::Any aAny(getCompoundLineString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("cmpd", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_TextOutlineEffect_algn:
+ {
+ uno::Any aAny(getPenAlignmentString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("algn", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_GradientStop_pos:
+ mpGrabBagStack->addInt32("pos", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_LinearShadeProperties_ang:
+ mpGrabBagStack->addInt32("ang", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_LinearShadeProperties_scaled:
+ {
+ uno::Any aAny(getOnOffString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("scaled", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_PathShadeProperties_path:
+ {
+ uno::Any aAny(getPathShadeTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("path", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_l:
+ mpGrabBagStack->addInt32("l", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_t:
+ mpGrabBagStack->addInt32("t", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_r:
+ mpGrabBagStack->addInt32("r", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_RelativeRect_b:
+ mpGrabBagStack->addInt32("b", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_PresetLineDashProperties_val:
+ {
+ uno::Any aAny(getPresetLineDashValString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_LineJoinMiterProperties_lim:
+ mpGrabBagStack->addInt32("lim", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Camera_prst:
+ {
+ uno::Any aAny(getPresetCameraTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("prst", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_LightRig_rig:
+ {
+ uno::Any aAny(getLightRigTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("rig", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_LightRig_dir:
+ {
+ uno::Any aAny(getLightRigDirectionString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("dir", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_SphereCoords_lat:
+ mpGrabBagStack->addInt32("lat", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_SphereCoords_lon:
+ mpGrabBagStack->addInt32("lon", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_SphereCoords_rev:
+ mpGrabBagStack->addInt32("rev", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Props3D_extrusionH:
+ mpGrabBagStack->addInt32("extrusionH", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Props3D_contourW:
+ mpGrabBagStack->addInt32("contourW", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Props3D_prstMaterial:
+ {
+ uno::Any aAny(getPresetMaterialTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("prstMaterial", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_Bevel_w:
+ mpGrabBagStack->addInt32("w", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Bevel_h:
+ mpGrabBagStack->addInt32("h", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_Bevel_prst:
+ {
+ uno::Any aAny(getBevelPresetTypeString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("prst", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_Ligatures_val:
+ {
+ uno::Any aAny(getLigaturesString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumForm_val:
+ {
+ uno::Any aAny(getNumFormString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_NumSpacing_val:
+ {
+ uno::Any aAny(getNumSpacingString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ case NS_ooxml::LN_CT_StyleSet_id:
+ mpGrabBagStack->addInt32("id", sal_Int32(aValue.getInt()));
+ break;
+ case NS_ooxml::LN_CT_StyleSet_val:
+ case NS_ooxml::LN_CT_OnOff_val:
+ {
+ uno::Any aAny(getOnOffString(sal_Int32(aValue.getInt())));
+ mpGrabBagStack->appendElement("val", aAny);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void TextEffectsHandler::lcl_sprm(Sprm& rSprm)
+{
+ if (mpGrabBagStack->getCurrentName() == constAttributesSequenceName)
+ mpGrabBagStack->pop();
+
+ sal_uInt32 nSprmId = rSprm.getId();
+ OUString aElementName = lclGetNameForElementId(nSprmId);
+ if(aElementName.isEmpty())
+ {
+ // Element is unknown -> leave.
+ return;
+ }
+
+ mpGrabBagStack->push(aElementName);
+
+ writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
+ if( !pProperties )
+ return;
+
+ pProperties->resolve( *this );
+
+ if (mpGrabBagStack->getCurrentName() == constAttributesSequenceName)
+ mpGrabBagStack->pop();
+
+ mpGrabBagStack->pop();
+}
+
+beans::PropertyValue TextEffectsHandler::getInteropGrabBag()
+{
+ beans::PropertyValue aReturn = mpGrabBagStack->getRootProperty();
+ mpGrabBagStack.reset();
+ return aReturn;
+}
+
+sal_uInt8 TextEffectsHandler::GetTextFillSolidFillAlpha(const css::beans::PropertyValue& rValue)
+{
+ if (rValue.Name != "textFill")
+ {
+ return 0;
+ }
+
+ uno::Sequence<beans::PropertyValue> aPropertyValues;
+ rValue.Value >>= aPropertyValues;
+ comphelper::SequenceAsHashMap aMap(aPropertyValues);
+ auto it = aMap.find("solidFill");
+ if (it == aMap.end())
+ {
+ return 0;
+ }
+
+ comphelper::SequenceAsHashMap aSolidFillMap(it->second);
+ it = aSolidFillMap.find("srgbClr");
+ if (it == aSolidFillMap.end())
+ {
+ it = aSolidFillMap.find("schemeClr");
+ 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/sw/source/writerfilter/dmapper/TextEffectsHandler.hxx b/sw/source/writerfilter/dmapper/TextEffectsHandler.hxx
new file mode 100644
index 000000000000..30a8435b2829
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TextEffectsHandler.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include "PropertyIds.hxx"
+
+#include <oox/helper/grabbagstack.hxx>
+
+#include <memory>
+#include <optional>
+
+namespace writerfilter::dmapper
+{
+/// Class to process all text effects like glow, textOutline, ...
+class TextEffectsHandler : public LoggedProperties
+{
+private:
+ std::optional<PropertyIds> maPropertyId;
+ OUString maElementName;
+ std::unique_ptr<oox::GrabBagStack> mpGrabBagStack;
+
+ void convertElementIdToPropertyId(sal_Int32 aElementId);
+
+public:
+ explicit TextEffectsHandler(sal_uInt32 aElementId);
+ virtual ~TextEffectsHandler() override;
+
+ const std::optional<PropertyIds>& getGrabBagPropertyId() const { return maPropertyId; }
+
+ css::beans::PropertyValue getInteropGrabBag();
+
+ static OUString getSchemeColorValTypeString(sal_Int32 nType);
+ static OUString getRectAlignmentString(sal_Int32 nType);
+ static OUString getLineCapString(sal_Int32 nType);
+ static OUString getCompoundLineString(sal_Int32 nType);
+ static OUString getPenAlignmentString(sal_Int32 nType);
+ static OUString getOnOffString(sal_Int32 nType);
+ static OUString getPathShadeTypeString(sal_Int32 nType);
+ static OUString getPresetLineDashValString(sal_Int32 nType);
+ static OUString getPresetCameraTypeString(sal_Int32 nType);
+ static OUString getLightRigTypeString(sal_Int32 nType);
+ static OUString getLightRigDirectionString(sal_Int32 nType);
+ static OUString getBevelPresetTypeString(sal_Int32 nType);
+ static OUString getPresetMaterialTypeString(sal_Int32 nType);
+ static OUString getLigaturesString(sal_Int32 nType);
+ static OUString getNumFormString(sal_Int32 nType);
+ static OUString getNumSpacingString(sal_Int32 nType);
+
+ static sal_uInt8 GetTextFillSolidFillAlpha(const css::beans::PropertyValue& rValue);
+
+ // LoggedProperties
+ virtual void lcl_attribute(Id aName, Value& aValue) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/ThemeColorHandler.hxx b/sw/source/writerfilter/dmapper/ThemeColorHandler.hxx
new file mode 100644
index 000000000000..012b4ee3472f
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/ThemeColorHandler.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include "PropertyIds.hxx"
+
+#include <oox/helper/grabbagstack.hxx>
+#include <docmodel/uno/UnoComplexColor.hxx>
+
+#include <memory>
+#include <optional>
+
+namespace writerfilter::dmapper
+{
+/// Class to process all text effects like glow, textOutline, ...
+class ThemeColorHandler : public LoggedProperties
+{
+public:
+ sal_Int32 mnColor = 0;
+ sal_Int32 mnIndex = -1;
+ sal_Int32 mnTint = 0;
+ sal_Int32 mnShade = 0;
+
+ explicit ThemeColorHandler()
+ : LoggedProperties("ThemeColorHandler")
+ {
+ }
+
+ virtual void lcl_attribute(Id aName, Value& rValue) override
+ {
+ sal_Int32 nIntValue = rValue.getInt();
+
+ switch (aName)
+ {
+ case NS_ooxml::LN_CT_Color_val:
+ mnColor = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Color_themeColor:
+ mnIndex = nIntValue;
+ break;
+
+ case NS_ooxml::LN_CT_Color_themeTint:
+ mnTint = nIntValue;
+ break;
+
+ case NS_ooxml::LN_CT_Color_themeShade:
+ mnShade = nIntValue;
+ break;
+ }
+ }
+
+ virtual void lcl_sprm(Sprm& /*sprm*/) override {}
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/ThemeHandler.cxx b/sw/source/writerfilter/dmapper/ThemeHandler.cxx
new file mode 100644
index 000000000000..1acd7073f69c
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/ThemeHandler.cxx
@@ -0,0 +1,423 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 "ThemeHandler.hxx"
+#include <i18nlangtag/languagetag.hxx>
+#include <ooxml/resourceids.hxx>
+#include <docmodel/theme/Theme.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+namespace
+{
+OUString 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();
+ }
+}
+
+OUString fromLocaleToScriptTag(const OUString& sLocale)
+{
+ return fromLCIDToScriptTag(LanguageTag::convertToLanguageType(sLocale));
+}
+
+OUString resolveMajorMinorTypeFace(model::FontScheme const& rFontSheme, const Id id)
+{
+ switch (id)
+ {
+ case NS_ooxml::LN_Value_ST_Theme_majorEastAsia:
+ return rFontSheme.getMajorAsian().maTypeface;
+ case NS_ooxml::LN_Value_ST_Theme_majorBidi:
+ return rFontSheme.getMajorComplex().maTypeface;
+ case NS_ooxml::LN_Value_ST_Theme_majorAscii:
+ case NS_ooxml::LN_Value_ST_Theme_majorHAnsi:
+ return rFontSheme.getMajorLatin().maTypeface;
+ break;
+ case NS_ooxml::LN_Value_ST_Theme_minorEastAsia:
+ return rFontSheme.getMinorAsian().maTypeface;
+ case NS_ooxml::LN_Value_ST_Theme_minorBidi:
+ return rFontSheme.getMinorComplex().maTypeface;
+ case NS_ooxml::LN_Value_ST_Theme_minorAscii:
+ case NS_ooxml::LN_Value_ST_Theme_minorHAnsi:
+ return rFontSheme.getMinorLatin().maTypeface;
+ break;
+ default:
+ break;
+ }
+ return OUString();
+}
+
+OUString resolveSupplementalFontList(model::FontScheme const& rFontSheme, const Id id,
+ std::u16string_view rLangAsia, std::u16string_view rLangBidi)
+{
+ switch (id)
+ {
+ case NS_ooxml::LN_Value_ST_Theme_majorEastAsia:
+ return rFontSheme.findMajorSupplementalTypeface(rLangAsia);
+ case NS_ooxml::LN_Value_ST_Theme_majorBidi:
+ return rFontSheme.findMajorSupplementalTypeface(rLangBidi);
+ case NS_ooxml::LN_Value_ST_Theme_minorEastAsia:
+ return rFontSheme.findMinorSupplementalTypeface(rLangAsia);
+ case NS_ooxml::LN_Value_ST_Theme_minorBidi:
+ return rFontSheme.findMinorSupplementalTypeface(rLangBidi);
+ default:
+ break;
+ }
+ return OUString();
+}
+
+} // end anonymous namespace
+
+ThemeHandler::ThemeHandler(oox::drawingml::ThemePtr const& pTheme,
+ const css::uno::Sequence<css::beans::PropertyValue>& rLangProperties)
+ : mpTheme(pTheme)
+{
+ for (const auto& rProperty : rLangProperties)
+ {
+ OUString sLocaleName;
+ rProperty.Value >>= sLocaleName;
+ if (rProperty.Name == "eastAsia")
+ maThemeFontLangEastAsia = fromLocaleToScriptTag(sLocaleName);
+ if (rProperty.Name == "bidi")
+ maThemeFontLangBidi = fromLocaleToScriptTag(sLocaleName);
+ }
+}
+
+OUString ThemeHandler::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 ThemeHandler::getFontNameForTheme(const Id id) const
+{
+ auto pModelTheme = mpTheme->getTheme();
+ model::FontScheme const& rFontScheme = pModelTheme->getFontScheme();
+ OUString aSupplementalTypeFace = resolveSupplementalFontList(
+ rFontScheme, id, maThemeFontLangEastAsia, maThemeFontLangBidi);
+ if (!aSupplementalTypeFace.isEmpty())
+ return aSupplementalTypeFace;
+ OUString aTypeFace = resolveMajorMinorTypeFace(rFontScheme, id);
+ return aTypeFace;
+}
+
+} //namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/ThemeHandler.hxx b/sw/source/writerfilter/dmapper/ThemeHandler.hxx
new file mode 100644
index 000000000000..8d7574991b29
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/ThemeHandler.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <i18nlangtag/lang.h>
+#include <memory>
+#include <oox/drawingml/theme.hxx>
+#include <ooxml/resourceids.hxx>
+
+namespace writerfilter::dmapper
+{
+class ThemeHandler
+{
+private:
+ oox::drawingml::ThemePtr mpTheme;
+ OUString maThemeFontLangEastAsia;
+ OUString maThemeFontLangBidi;
+
+public:
+ ThemeHandler(oox::drawingml::ThemePtr const& pTheme,
+ const css::uno::Sequence<css::beans::PropertyValue>& rLangProperties);
+ OUString getFontNameForTheme(const Id id) const;
+ static OUString getStringForTheme(const Id id);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TrackChangesHandler.cxx b/sw/source/writerfilter/dmapper/TrackChangesHandler.cxx
new file mode 100644
index 000000000000..47a52d6df695
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TrackChangesHandler.cxx
@@ -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/.
+ */
+#include <comphelper/propertyvalue.hxx>
+#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
+{
+ 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;
+ }
+ return {
+ comphelper::makePropertyValue(getPropertyName(PROP_REDLINE_TYPE ), uno::Any(sType)),
+ comphelper::makePropertyValue(getPropertyName(PROP_REDLINE_AUTHOR), uno::Any(m_pRedlineParams->m_sAuthor)),
+ comphelper::makePropertyValue(getPropertyName(PROP_REDLINE_DATE_TIME), uno::Any(ConversionHelper::ConvertDateStringToDateTime( m_pRedlineParams->m_sDate )))
+ //comphelper::makePropertyValue(getPropertyName(PROP_REDLINE_REVERT_PROPERTIES), uno::Any(pRedline->m_aRevertProperties))
+ };
+}
+
+void TrackChangesHandler::lcl_sprm(Sprm &) {}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/TrackChangesHandler.hxx b/sw/source/writerfilter/dmapper/TrackChangesHandler.hxx
new file mode 100644
index 000000000000..b3417ccced1f
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/TrackChangesHandler.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <dmapper/PropertyMap.hxx>
+
+namespace writerfilter::dmapper
+{
+/** Handler for sprms that contain 'track changes' attributes
+ - Author
+ - Date
+ - ID
+ (This class is based on work done in 'MeasureHandler')
+ */
+class TrackChangesHandler : public LoggedProperties
+{
+ RedlineParamsPtr m_pRedlineParams;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+public:
+ explicit TrackChangesHandler(sal_Int32 nToken);
+ virtual ~TrackChangesHandler() override;
+
+ /// Compute the UNO properties for the track changes object based on the received tokens.
+ css::uno::Sequence<css::beans::PropertyValue> getRedlineProperties() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/WrapPolygonHandler.cxx b/sw/source/writerfilter/dmapper/WrapPolygonHandler.cxx
new file mode 100644
index 000000000000..319fae5c4cb0
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/WrapPolygonHandler.cxx
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/PointSequence.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <comphelper/sequence.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include "WrapPolygonHandler.hxx"
+#include "util.hxx"
+
+#include <sal/log.hxx>
+
+namespace writerfilter {
+
+using namespace com::sun::star;
+
+namespace dmapper {
+
+WrapPolygon::WrapPolygon()
+{
+}
+
+WrapPolygon::~WrapPolygon()
+{
+}
+
+void WrapPolygon::addPoint(const awt::Point & rPoint)
+{
+ mPoints.push_back(rPoint);
+}
+
+WrapPolygon::Points_t::const_iterator WrapPolygon::begin() const
+{
+ return mPoints.begin();
+}
+
+WrapPolygon::Points_t::const_iterator WrapPolygon::end() const
+{
+ return mPoints.end();
+}
+
+WrapPolygon::Pointer_t WrapPolygon::move(const awt::Point & rPoint) const
+{
+ WrapPolygon::Pointer_t pResult(new WrapPolygon);
+
+ Points_t::const_iterator aIt = begin();
+ Points_t::const_iterator aItEnd = end();
+
+ while (aIt != aItEnd)
+ {
+ awt::Point aPoint(aIt->X + rPoint.X, aIt->Y + rPoint.Y);
+ pResult->addPoint(aPoint);
+ ++aIt;
+ }
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::scale(const Fraction & rFractionX, const Fraction & rFractionY) const
+{
+ WrapPolygon::Pointer_t pResult(new WrapPolygon);
+
+ Points_t::const_iterator aIt = begin();
+ Points_t::const_iterator aItEnd = end();
+
+ while (aIt != aItEnd)
+ {
+ awt::Point aPoint((Fraction(tools::Long(aIt->X)) * rFractionX).operator long(), (Fraction(tools::Long(aIt->Y)) * rFractionY).operator long());
+ pResult->addPoint(aPoint);
+ ++aIt;
+ }
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::correctWordWrapPolygon(const awt::Size & rSrcSize) const
+{
+ WrapPolygon::Pointer_t pResult;
+
+ const tools::Long nWrap100Percent = 21600;
+
+ Fraction aMove(nWrap100Percent, rSrcSize.Width);
+ aMove = aMove * Fraction(convertTwipToMm100(15), 1);
+ awt::Point aMovePoint(aMove.operator long(), 0);
+ pResult = move(aMovePoint);
+
+ Fraction aScaleX = nWrap100Percent / (nWrap100Percent + aMove);
+ Fraction aScaleY = nWrap100Percent / (nWrap100Percent - aMove);
+ pResult = pResult->scale(aScaleX, aScaleY);
+
+ Fraction aScaleSrcX(rSrcSize.Width, nWrap100Percent);
+ Fraction aScaleSrcY(rSrcSize.Height, nWrap100Percent);
+ pResult = pResult->scale(aScaleSrcX, aScaleSrcY);
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::correctWordWrapPolygonPixel(const awt::Size & rSrcSize) const
+{
+ WrapPolygon::Pointer_t pResult;
+
+ /*
+ * https://msdn.microsoft.com/en-us/library/ee342530.aspx
+ *
+ * Image wrapping polygons in Microsoft Word use a fixed coordinate space
+ * that is 21600 units x 21600 units. Coordinate (0,0) is the upper left
+ * corner of the image and coordinate (21600,21600) is the lower right
+ * corner of the image. Microsoft Word scales the size of the wrapping
+ * polygon units to fit the size of the image. The 21600 value is a legacy
+ * artifact from the drawing layer of early versions of Microsoft Office.
+ */
+ const tools::Long nWrap100Percent = 21600;
+
+ Fraction aScaleX(rSrcSize.Width, nWrap100Percent);
+ Fraction aScaleY(rSrcSize.Height, nWrap100Percent);
+ pResult = scale(aScaleX, aScaleY);
+
+ return pResult;
+}
+
+WrapPolygon::Pointer_t WrapPolygon::correctCrop(const awt::Size& rGraphicSize,
+ const text::GraphicCrop& rGraphicCrop) const
+{
+ WrapPolygon::Pointer_t pResult;
+
+ Fraction aScaleX(rGraphicSize.Width - rGraphicCrop.Left - rGraphicCrop.Right,
+ rGraphicSize.Width);
+ Fraction aScaleY(rGraphicSize.Height - rGraphicCrop.Top - rGraphicCrop.Bottom,
+ rGraphicSize.Height);
+ pResult = scale(aScaleX, aScaleY);
+
+ awt::Point aMove(rGraphicCrop.Left, rGraphicCrop.Top);
+ pResult = pResult->move(aMove);
+
+ return pResult;
+}
+
+drawing::PointSequenceSequence WrapPolygon::getPointSequenceSequence() const
+{
+ return { comphelper::containerToSequence(mPoints) };
+}
+
+WrapPolygonHandler::WrapPolygonHandler()
+ : LoggedProperties("WrapPolygonHandler")
+ , mpPolygon(new WrapPolygon)
+ , mnX(0)
+ , mnY(0)
+{
+}
+
+WrapPolygonHandler::~WrapPolygonHandler()
+{
+}
+
+void WrapPolygonHandler::lcl_attribute(Id Name, Value & val)
+{
+ sal_Int32 nIntValue = val.getInt();
+
+ switch(Name)
+ {
+ case NS_ooxml::LN_CT_Point2D_x:
+ mnX = nIntValue;
+ break;
+ case NS_ooxml::LN_CT_Point2D_y:
+ mnY = nIntValue;
+ break;
+ default:
+ SAL_WARN("writerfilter", "WrapPolygonHandler::lcl_attribute: unhandled token: " << Name);
+ break;
+ }
+}
+
+void WrapPolygonHandler::lcl_sprm(Sprm & _sprm)
+{
+ switch (_sprm.getId())
+ {
+ case NS_ooxml::LN_CT_WrapPath_lineTo:
+ case NS_ooxml::LN_CT_WrapPath_start:
+ {
+ resolveSprmProps(*this, _sprm);
+
+ awt::Point aPoint(mnX, mnY);
+ mpPolygon->addPoint(aPoint);
+ }
+ break;
+ default:
+ SAL_WARN("writerfilter", "WrapPolygonHandler::lcl_sprm: unhandled token: " << _sprm.getId());
+ break;
+ }
+}
+
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/WrapPolygonHandler.hxx b/sw/source/writerfilter/dmapper/WrapPolygonHandler.hxx
new file mode 100644
index 000000000000..8d3e1a3d8493
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/WrapPolygonHandler.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/drawing/PointSequenceSequence.hpp>
+#include "LoggedResources.hxx"
+#include <tools/fract.hxx>
+#include <vector>
+
+namespace com::sun::star::text
+{
+struct GraphicCrop;
+}
+
+namespace writerfilter::dmapper
+{
+/// Handles <wp:wrapPolygon> from DOCX and the pWrapPolygonVertices shape property from RTF.
+class WrapPolygon final : public virtual SvRefBase
+{
+public:
+ typedef std::vector<css::awt::Point> Points_t;
+ typedef ::tools::SvRef<WrapPolygon> Pointer_t;
+
+private:
+ Points_t mPoints;
+
+public:
+ WrapPolygon();
+ ~WrapPolygon() override;
+
+ void addPoint(const css::awt::Point& rPoint);
+
+ Points_t::const_iterator begin() const;
+ Points_t::const_iterator end() const;
+
+ WrapPolygon::Pointer_t move(const css::awt::Point& rMove) const;
+ WrapPolygon::Pointer_t scale(const Fraction& rFractionX, const Fraction& rFractionY) const;
+ WrapPolygon::Pointer_t correctWordWrapPolygon(const css::awt::Size& rSrcSize) const;
+ WrapPolygon::Pointer_t correctWordWrapPolygonPixel(const css::awt::Size& rSrcSize) const;
+ WrapPolygon::Pointer_t correctCrop(const css::awt::Size& rGraphicSize,
+ const css::text::GraphicCrop& rGraphicCrop) const;
+ css::drawing::PointSequenceSequence getPointSequenceSequence() const;
+};
+
+class WrapPolygonHandler : public LoggedProperties
+{
+public:
+ WrapPolygonHandler();
+ virtual ~WrapPolygonHandler() override;
+
+ const WrapPolygon::Pointer_t& getPolygon() const { return mpPolygon; }
+
+private:
+ WrapPolygon::Pointer_t mpPolygon;
+
+ sal_Int32 mnX;
+ sal_Int32 mnY;
+
+ // Properties
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/WriteProtection.cxx b/sw/source/writerfilter/dmapper/WriteProtection.cxx
new file mode 100644
index 000000000000..c300ab09e303
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/WriteProtection.cxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "WriteProtection.hxx"
+#include "TagLogger.hxx"
+
+#include <comphelper/propertyvalue.hxx>
+#include <ooxml/resourceids.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::dmapper
+{
+WriteProtection::WriteProtection()
+ : LoggedProperties("WriteProtection")
+ , m_nCryptProviderType(NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES)
+ , m_CryptSpinCount(0)
+ , m_bRecommended(false)
+{
+}
+
+WriteProtection::~WriteProtection() {}
+
+void WriteProtection::lcl_attribute(Id nName, Value& val)
+{
+ int nIntValue = val.getInt();
+ OUString sStringValue = val.getString();
+
+ switch (nName)
+ {
+ case NS_ooxml::LN_AG_Password_cryptProviderType: // 92025
+ m_nCryptProviderType = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmClass: // 92026
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgClass_hash) // 92023
+ m_sCryptAlgorithmClass = "hash";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmType: // 92027
+ if (nIntValue == NS_ooxml::LN_Value_doc_ST_AlgType_typeAny) // 92024
+ m_sCryptAlgorithmType = "typeAny";
+ break;
+ case NS_ooxml::LN_AG_Password_cryptAlgorithmSid: // 92028
+ {
+ sal_Int32 nCryptAlgorithmSid = sStringValue.toInt32();
+ switch (nCryptAlgorithmSid)
+ {
+ case 1:
+ m_sAlgorithmName = "MD2";
+ break;
+ case 2:
+ m_sAlgorithmName = "MD4";
+ break;
+ case 3:
+ m_sAlgorithmName = "MD5";
+ break;
+ case 4:
+ m_sAlgorithmName = "SHA-1";
+ break;
+ case 5:
+ m_sAlgorithmName = "MAC";
+ break;
+ case 6:
+ m_sAlgorithmName = "RIPEMD";
+ break;
+ case 7:
+ m_sAlgorithmName = "RIPEMD-160";
+ break;
+ case 9:
+ m_sAlgorithmName = "HMAC";
+ break;
+ case 12:
+ m_sAlgorithmName = "SHA-256";
+ break;
+ case 13:
+ m_sAlgorithmName = "SHA-384";
+ break;
+ case 14:
+ m_sAlgorithmName = "SHA-512";
+ break;
+ default:; // 8, 10, 11, any other value: Undefined.
+ }
+ }
+ break;
+ case NS_ooxml::LN_AG_Password_cryptSpinCount: // 92029
+ m_CryptSpinCount = nIntValue;
+ break;
+ case NS_ooxml::LN_AG_Password_hash: // 92035
+ m_sHash = sStringValue;
+ break;
+ case NS_ooxml::LN_AG_Password_salt: // 92036
+ m_sSalt = sStringValue;
+ break;
+ case NS_ooxml::LN_CT_WriteProtection_recommended:
+ m_bRecommended = nIntValue;
+ break;
+ default:
+ {
+#ifdef DBG_UTIL
+ TagLogger::getInstance().element("unhandled");
+#endif
+ }
+ }
+}
+
+void WriteProtection::lcl_sprm(Sprm& /*rSprm*/) {}
+
+uno::Sequence<beans::PropertyValue> WriteProtection::toSequence() const
+{
+ uno::Sequence<beans::PropertyValue> aResult;
+ if (!m_sAlgorithmName.isEmpty() && !m_sSalt.isEmpty() && !m_sHash.isEmpty()
+ && m_sCryptAlgorithmClass == "hash" && m_sCryptAlgorithmType == "typeAny")
+ {
+ aResult = { comphelper::makePropertyValue("algorithm-name", m_sAlgorithmName),
+ comphelper::makePropertyValue("salt", m_sSalt),
+ comphelper::makePropertyValue("iteration-count", m_CryptSpinCount),
+ comphelper::makePropertyValue("hash", m_sHash) };
+ }
+
+ return aResult;
+}
+
+} //namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/WriteProtection.hxx b/sw/source/writerfilter/dmapper/WriteProtection.hxx
new file mode 100644
index 000000000000..21b420b4bcd9
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/WriteProtection.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "LoggedResources.hxx"
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace writerfilter::dmapper
+{
+class WriteProtection : public LoggedProperties
+{
+private:
+ /** Provider type
+ *
+ * Possible values:
+ * "rsaAES" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaAES
+ * "rsaFull" - NS_ooxml::LN_Value_doc_ST_CryptProv_rsaFull
+ */
+ sal_Int32 m_nCryptProviderType;
+ OUString m_sCryptAlgorithmClass;
+ OUString m_sCryptAlgorithmType;
+ sal_Int32 m_CryptSpinCount;
+ OUString m_sAlgorithmName;
+ OUString m_sHash;
+ OUString m_sSalt;
+ bool m_bRecommended;
+
+ virtual void lcl_attribute(Id Name, Value& val) override;
+ virtual void lcl_sprm(Sprm& sprm) override;
+
+public:
+ WriteProtection();
+ virtual ~WriteProtection() override;
+
+ css::uno::Sequence<css::beans::PropertyValue> toSequence() const;
+
+ bool getRecommended() const { return m_bRecommended; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/domainmapperfactory.cxx b/sw/source/writerfilter/dmapper/domainmapperfactory.cxx
new file mode 100644
index 000000000000..e52d5d2e8dec
--- /dev/null
+++ b/sw/source/writerfilter/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));
+
+ if (getenv("SW_DEBUG_WRITERFILTER"))
+ TagLogger::getInstance().setFileName(sURLc);
+ TagLogger::getInstance().startDocument();
+#endif
+
+ return { new DomainMapper(xContext, xInputStream, xModel, bRepairStorage, eDocumentType,
+ rMediaDesc) };
+}
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/dmapper/util.cxx b/sw/source/writerfilter/dmapper/util.cxx
new file mode 100644
index 000000000000..3e22cbb72784
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/util.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string>
+#include "util.hxx"
+
+namespace writerfilter::dmapper
+{
+using namespace com::sun::star;
+
+std::string XTextRangeToString(uno::Reference<text::XTextRange> const& textRange)
+{
+ std::string result;
+
+#ifdef DBG_UTIL
+ if (textRange)
+ {
+ OUString aOUStr;
+
+ try
+ {
+ aOUStr = textRange->getString();
+ }
+ catch (const uno::Exception& rException)
+ {
+ result += "(exception: ";
+ result += rException.Message.toUtf8().getStr();
+ result += ")";
+ }
+
+ OString aOStr = OUStringToOString(aOUStr, 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/sw/source/writerfilter/dmapper/util.hxx b/sw/source/writerfilter/dmapper/util.hxx
new file mode 100644
index 000000000000..9d172331a7ca
--- /dev/null
+++ b/sw/source/writerfilter/dmapper/util.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/text/XTextRange.hpp>
+#include <string>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::dmapper
+{
+std::string XTextRangeToString(css::uno::Reference<css::text::XTextRange> const& textRange);
+void resolveSprmProps(Properties& rHandler, Sprm& rSprm);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/filter/RtfFilter.cxx b/sw/source/writerfilter/filter/RtfFilter.cxx
new file mode 100644
index 000000000000..8f80b85353b2
--- /dev/null
+++ b/sw/source/writerfilter/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 <comphelper/diagnose_ex.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <unotools/streamwrap.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/scopeguard.hxx>
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include <rtftok/RTFDocument.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Invokes the RTF tokenizer + dmapper or RtfExportFilter in sw via UNO.
+class RtfFilter
+ : public cppu::WeakImplHelper<document::XFilter, document::XImporter, document::XExporter,
+ lang::XInitialization, lang::XServiceInfo>
+{
+ uno::Reference<uno::XComponentContext> m_xContext;
+ uno::Reference<lang::XComponent> m_xSrcDoc, m_xDstDoc;
+
+public:
+ explicit RtfFilter(uno::Reference<uno::XComponentContext> xContext);
+
+ // XFilter
+ sal_Bool SAL_CALL filter(const uno::Sequence<beans::PropertyValue>& rDescriptor) override;
+ void SAL_CALL cancel() override;
+
+ // XImporter
+ void SAL_CALL setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XExporter
+ void SAL_CALL setSourceDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XInitialization
+ void SAL_CALL initialize(const uno::Sequence<uno::Any>& rArguments) override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+}
+
+RtfFilter::RtfFilter(uno::Reference<uno::XComponentContext> xContext)
+ : m_xContext(std::move(xContext))
+{
+}
+
+sal_Bool RtfFilter::filter(const uno::Sequence<beans::PropertyValue>& rDescriptor)
+{
+ if (m_xSrcDoc.is())
+ {
+ uno::Reference<lang::XMultiServiceFactory> xMSF(m_xContext->getServiceManager(),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<uno::XInterface> xIfc(
+ xMSF->createInstance("com.sun.star.comp.Writer.RtfExport"), uno::UNO_SET_THROW);
+ uno::Reference<document::XExporter> xExporter(xIfc, uno::UNO_QUERY_THROW);
+ uno::Reference<document::XFilter> xFilter(xIfc, uno::UNO_QUERY_THROW);
+ xExporter->setSourceDocument(m_xSrcDoc);
+ return xFilter->filter(rDescriptor);
+ }
+
+ bool bResult(false);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+
+ uno::Reference<beans::XPropertySet> xDocProps;
+ if (m_xDstDoc.is()) // not in cppunittest?
+ {
+ xDocProps.set(m_xDstDoc, uno::UNO_QUERY);
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(true));
+ }
+ comphelper::ScopeGuard g([xDocProps] {
+ if (xDocProps.is()) // not in cppunittest?
+ {
+ // note: pStream.clear calls RemoveLastParagraph()
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(false));
+ }
+ });
+
+ try
+ {
+ utl::MediaDescriptor aMediaDesc(rDescriptor);
+ bool bRepairStorage = aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
+ bool bIsNewDoc = !aMediaDesc.getUnpackedValueOrDefault("InsertMode", false);
+ uno::Reference<io::XInputStream> xInputStream;
+
+ aMediaDesc.addInputStream();
+ aMediaDesc[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
+
+ // If this is set, write to this file, instead of the real document during paste.
+ char* pEnv = getenv("SW_DEBUG_RTF_PASTE_TO");
+ OUString aOutStr;
+ if (!bIsNewDoc && pEnv
+ && osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pEnv), aOutStr)
+ == osl::FileBase::E_None)
+ {
+ std::unique_ptr<SvStream> pOut(
+ utl::UcbStreamHelper::CreateStream(aOutStr, StreamMode::WRITE));
+ std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xInputStream));
+ pOut->WriteStream(*pIn);
+ return true;
+ }
+
+ // If this is set, read from this file, instead of the real clipboard during paste.
+ pEnv = getenv("SW_DEBUG_RTF_PASTE_FROM");
+ if (!bIsNewDoc && pEnv)
+ {
+ OUString aInStr;
+ osl::FileBase::getFileURLFromSystemPath(OUString::fromUtf8(pEnv), aInStr);
+ std::unique_ptr<SvStream> pStream
+ = utl::UcbStreamHelper::CreateStream(aInStr, StreamMode::READ);
+ uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(std::move(pStream)));
+ xInputStream.set(xStream, uno::UNO_QUERY);
+ }
+
+ uno::Reference<frame::XFrame> xFrame = aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_FRAME, uno::Reference<frame::XFrame>());
+
+ xStatusIndicator = aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_STATUSINDICATOR, uno::Reference<task::XStatusIndicator>());
+
+ writerfilter::Stream::Pointer_t pStream(
+ writerfilter::dmapper::DomainMapperFactory::createMapper(
+ m_xContext, xInputStream, m_xDstDoc, bRepairStorage,
+ writerfilter::dmapper::SourceDocumentType::RTF, aMediaDesc));
+ writerfilter::rtftok::RTFDocument::Pointer_t pDocument(
+ writerfilter::rtftok::RTFDocumentFactory::createDocument(
+ m_xContext, xInputStream, m_xDstDoc, xFrame, xStatusIndicator, aMediaDesc));
+ pDocument->resolve(*pStream);
+ bResult = true;
+ }
+ catch (const io::WrongFormatException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ // cannot throw WrongFormatException directly :(
+ throw lang::WrappedTargetRuntimeException("", getXWeak(), 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/sw/source/writerfilter/filter/WriterFilter.cxx b/sw/source/writerfilter/filter/WriterFilter.cxx
new file mode 100644
index 000000000000..8935f462636f
--- /dev/null
+++ b/sw/source/writerfilter/filter/WriterFilter.cxx
@@ -0,0 +1,367 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <comphelper/diagnose_ex.hxx>
+#include <comphelper/scopeguard.hxx>
+
+using namespace ::com::sun::star;
+
+static OUString lcl_GetExceptionMessageRec(xml::sax::SAXException const& e);
+
+static OUString lcl_GetExceptionMessage(xml::sax::SAXException const& e)
+{
+ OUString const thisMessage("SAXParseException: \"" + e.Message + "\"");
+ OUString const restMessage(lcl_GetExceptionMessageRec(e));
+ return restMessage + "\n" + thisMessage;
+}
+static OUString lcl_GetExceptionMessage(xml::sax::SAXParseException const& e)
+{
+ OUString const thisMessage("SAXParseException: '" + e.Message + "', Stream '" + e.SystemId
+ + "', Line " + OUString::number(e.LineNumber) + ", Column "
+ + OUString::number(e.ColumnNumber));
+ OUString const restMessage(lcl_GetExceptionMessageRec(e));
+ return restMessage + "\n" + thisMessage;
+}
+
+static OUString lcl_GetExceptionMessageRec(xml::sax::SAXException const& e)
+{
+ xml::sax::SAXParseException saxpe;
+ if (e.WrappedException >>= saxpe)
+ {
+ return lcl_GetExceptionMessage(saxpe);
+ }
+ xml::sax::SAXException saxe;
+ if (e.WrappedException >>= saxe)
+ {
+ return lcl_GetExceptionMessage(saxe);
+ }
+ uno::Exception ue;
+ if (e.WrappedException >>= ue)
+ {
+ return ue.Message;
+ }
+ return {};
+}
+
+namespace
+{
+/// Common DOCX filter, calls DocxExportFilter via UNO or does the DOCX import.
+class WriterFilter
+ : public cppu::WeakImplHelper<document::XFilter, document::XImporter, document::XExporter,
+ lang::XInitialization, lang::XServiceInfo>
+{
+ uno::Reference<uno::XComponentContext> m_xContext;
+ uno::Reference<lang::XComponent> m_xSrcDoc, m_xDstDoc;
+ uno::Sequence<uno::Any> m_xInitializationArguments;
+
+public:
+ explicit WriterFilter(uno::Reference<uno::XComponentContext> xContext)
+ : m_xContext(std::move(xContext))
+ {
+ }
+
+ // XFilter
+ sal_Bool SAL_CALL filter(const uno::Sequence<beans::PropertyValue>& rDescriptor) override;
+ void SAL_CALL cancel() override;
+
+ // XImporter
+ void SAL_CALL setTargetDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XExporter
+ void SAL_CALL setSourceDocument(const uno::Reference<lang::XComponent>& xDoc) override;
+
+ // XInitialization
+ void SAL_CALL initialize(const uno::Sequence<uno::Any>& rArguments) override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+}
+
+sal_Bool WriterFilter::filter(const uno::Sequence<beans::PropertyValue>& rDescriptor)
+{
+ if (m_xSrcDoc.is())
+ {
+ uno::Reference<lang::XMultiServiceFactory> xMSF(m_xContext->getServiceManager(),
+ uno::UNO_QUERY_THROW);
+ uno::Reference<uno::XInterface> xIfc;
+ try
+ {
+ xIfc.set(xMSF->createInstance("com.sun.star.comp.Writer.DocxExport"),
+ uno::UNO_SET_THROW);
+ }
+ catch (uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (uno::Exception& e)
+ {
+ uno::Any a(cppu::getCaughtException());
+ throw lang::WrappedTargetRuntimeException("wrapped " + a.getValueTypeName() + ": "
+ + e.Message,
+ uno::Reference<uno::XInterface>(), a);
+ }
+
+ uno::Reference<lang::XInitialization> xInit(xIfc, uno::UNO_QUERY_THROW);
+ xInit->initialize(m_xInitializationArguments);
+
+ uno::Reference<document::XExporter> xExprtr(xIfc, uno::UNO_QUERY_THROW);
+ uno::Reference<document::XFilter> xFltr(xIfc, uno::UNO_QUERY_THROW);
+ xExprtr->setSourceDocument(m_xSrcDoc);
+ return xFltr->filter(rDescriptor);
+ }
+ if (m_xDstDoc.is())
+ {
+ uno::Reference<beans::XPropertySet> const xDocProps(m_xDstDoc, uno::UNO_QUERY);
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(true));
+ comphelper::ScopeGuard g([xDocProps] {
+ xDocProps->setPropertyValue("UndocumentedWriterfilterHack", uno::Any(false));
+ });
+ utl::MediaDescriptor aMediaDesc(rDescriptor);
+ bool bRepairStorage = aMediaDesc.getUnpackedValueOrDefault("RepairPackage", false);
+ bool bSkipImages
+ = aMediaDesc.getUnpackedValueOrDefault("FilterOptions", OUString()) == "SkipImages";
+
+ uno::Reference<io::XInputStream> xInputStream;
+ try
+ {
+ // use the oox.core.FilterDetect implementation to extract the decrypted ZIP package
+ rtl::Reference<::oox::core::FilterDetect> xDetector(
+ new ::oox::core::FilterDetect(m_xContext));
+ xInputStream = xDetector->extractUnencryptedPackage(aMediaDesc);
+ }
+ catch (uno::Exception&)
+ {
+ }
+
+ if (!xInputStream.is())
+ return false;
+
+ writerfilter::Stream::Pointer_t pStream(
+ writerfilter::dmapper::DomainMapperFactory::createMapper(
+ m_xContext, xInputStream, m_xDstDoc, bRepairStorage,
+ writerfilter::dmapper::SourceDocumentType::OOXML, aMediaDesc));
+ //create the tokenizer and domain mapper
+ writerfilter::ooxml::OOXMLStream::Pointer_t pDocStream
+ = writerfilter::ooxml::OOXMLDocumentFactory::createStream(m_xContext, xInputStream,
+ bRepairStorage);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator
+ = aMediaDesc.getUnpackedValueOrDefault(utl::MediaDescriptor::PROP_STATUSINDICATOR,
+ uno::Reference<task::XStatusIndicator>());
+ writerfilter::ooxml::OOXMLDocument::Pointer_t pDocument(
+ writerfilter::ooxml::OOXMLDocumentFactory::createDocument(pDocStream, xStatusIndicator,
+ bSkipImages, rDescriptor));
+
+ uno::Reference<frame::XModel> xModel(m_xDstDoc, uno::UNO_QUERY_THROW);
+ pDocument->setModel(xModel);
+
+ uno::Reference<drawing::XDrawPageSupplier> xDrawings(m_xDstDoc, uno::UNO_QUERY_THROW);
+ uno::Reference<drawing::XDrawPage> xDrawPage(xDrawings->getDrawPage(), uno::UNO_SET_THROW);
+ pDocument->setDrawPage(xDrawPage);
+
+ try
+ {
+ pDocument->resolve(*pStream);
+ }
+ catch (xml::sax::SAXParseException const& e)
+ {
+ // note: SfxObjectShell checks for WrongFormatException
+ io::WrongFormatException wfe(lcl_GetExceptionMessage(e));
+ throw lang::WrappedTargetRuntimeException("", getXWeak(), uno::Any(wfe));
+ }
+ catch (xml::sax::SAXException const& e)
+ {
+ // note: SfxObjectShell checks for WrongFormatException
+ io::WrongFormatException wfe(lcl_GetExceptionMessage(e));
+ throw lang::WrappedTargetRuntimeException("", getXWeak(), uno::Any(wfe));
+ }
+ catch (uno::RuntimeException const&)
+ {
+ throw;
+ }
+ catch (uno::Exception const&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ SAL_WARN("writerfilter",
+ "WriterFilter::filter(): failed with " << exceptionToString(anyEx));
+ throw lang::WrappedTargetRuntimeException("", getXWeak(), anyEx);
+ }
+
+ // Adding some properties to the document's grab bag for interoperability purposes:
+ comphelper::SequenceAsHashMap aGrabBagProperties;
+
+ // Adding the saved Theme DOM
+ aGrabBagProperties["OOXTheme"] <<= pDocument->getThemeDom();
+
+ // Adding the saved custom xml DOM
+ aGrabBagProperties["OOXCustomXml"] <<= pDocument->getCustomXmlDomList();
+ aGrabBagProperties["OOXCustomXmlProps"] <<= pDocument->getCustomXmlDomPropsList();
+
+ // Adding the saved Glossary Document DOM to the document's grab bag
+ aGrabBagProperties["OOXGlossary"] <<= pDocument->getGlossaryDocDom();
+ aGrabBagProperties["OOXGlossaryDom"] <<= pDocument->getGlossaryDomList();
+
+ // Adding the saved embedding document to document's grab bag
+ aGrabBagProperties["OOXEmbeddings"] <<= pDocument->getEmbeddingsList();
+
+ oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(m_xDstDoc, aGrabBagProperties);
+
+ writerfilter::ooxml::OOXMLStream::Pointer_t pVBAProjectStream(
+ writerfilter::ooxml::OOXMLDocumentFactory::createStream(
+ pDocStream, writerfilter::ooxml::OOXMLStream::VBAPROJECT));
+ oox::StorageRef xVbaPrjStrg = std::make_shared<::oox::ole::OleStorage>(
+ m_xContext, pVBAProjectStream->getDocumentStream(), false);
+ if (xVbaPrjStrg && xVbaPrjStrg->isStorage())
+ {
+ ::oox::ole::VbaProject aVbaProject(m_xContext, xModel, u"Writer");
+ uno::Reference<frame::XFrame> xFrame = aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_FRAME, uno::Reference<frame::XFrame>());
+
+ // if no XFrame try fallback to what we can glean from the Model
+ if (!xFrame.is())
+ {
+ uno::Reference<frame::XController> xController = xModel->getCurrentController();
+ xFrame = xController.is() ? xController->getFrame() : nullptr;
+ }
+
+ oox::GraphicHelper gHelper(m_xContext, xFrame, xVbaPrjStrg);
+ aVbaProject.importVbaProject(*xVbaPrjStrg, gHelper);
+
+ writerfilter::ooxml::OOXMLStream::Pointer_t pVBADataStream(
+ writerfilter::ooxml::OOXMLDocumentFactory::createStream(
+ pDocStream, writerfilter::ooxml::OOXMLStream::VBADATA));
+ if (pVBADataStream)
+ {
+ uno::Reference<io::XInputStream> xDataStream = pVBADataStream->getDocumentStream();
+ if (xDataStream.is())
+ aVbaProject.importVbaData(xDataStream);
+ }
+ }
+
+ pStream.clear();
+
+ // note: pStream.clear calls RemoveLastParagraph()
+
+ return true;
+ }
+ return false;
+}
+
+void WriterFilter::cancel() {}
+
+void WriterFilter::setTargetDocument(const uno::Reference<lang::XComponent>& xDoc)
+{
+ m_xDstDoc = xDoc;
+
+ // Set some compatibility options that are valid for the DOCX format
+ uno::Reference<lang::XMultiServiceFactory> xFactory(xDoc, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xSettings(
+ xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
+
+ xSettings->setPropertyValue("UseOldNumbering", uno::Any(false));
+ xSettings->setPropertyValue("IgnoreFirstLineIndentInNumbering", uno::Any(false));
+ xSettings->setPropertyValue(u"NoGapAfterNoteNumber"_ustr, uno::Any(true));
+ xSettings->setPropertyValue("DoNotResetParaAttrsForNumFont", uno::Any(false));
+ xSettings->setPropertyValue("UseFormerLineSpacing", uno::Any(false));
+ xSettings->setPropertyValue("AddParaSpacingToTableCells", uno::Any(true));
+ xSettings->setPropertyValue("AddParaLineSpacingToTableCells", uno::Any(true));
+ xSettings->setPropertyValue("UseFormerObjectPositioning", uno::Any(false));
+ xSettings->setPropertyValue("ConsiderTextWrapOnObjPos", uno::Any(true));
+ xSettings->setPropertyValue("UseFormerTextWrapping", uno::Any(false));
+ xSettings->setPropertyValue("IgnoreTabsAndBlanksForLineCalculation", uno::Any(true));
+ xSettings->setPropertyValue("InvertBorderSpacing", uno::Any(true));
+ xSettings->setPropertyValue("CollapseEmptyCellPara", uno::Any(true));
+ // tdf#142404 TabOverSpacing (new for compatibilityMode15/Word2013+) is a subset of TabOverMargin
+ // (which applied to DOCX <= compatibilityMode14).
+ // TabOverMargin looks at tabs beyond the normal text area,
+ // while TabOverSpacing only refers to a tab beyond the paragraph margin.
+ xSettings->setPropertyValue("TabOverSpacing", uno::Any(true));
+ xSettings->setPropertyValue("UnbreakableNumberings", uno::Any(true));
+
+ xSettings->setPropertyValue("ClippedPictures", uno::Any(true));
+ xSettings->setPropertyValue("BackgroundParaOverDrawings", uno::Any(true));
+ xSettings->setPropertyValue("TreatSingleColumnBreakAsPageBreak", uno::Any(true));
+ xSettings->setPropertyValue("PropLineSpacingShrinksFirstLine", uno::Any(true));
+ xSettings->setPropertyValue("DoNotCaptureDrawObjsOnPage", uno::Any(true));
+ xSettings->setPropertyValue("DisableOffPagePositioning", uno::Any(true));
+ xSettings->setPropertyValue("DropCapPunctuation", uno::Any(true));
+ // rely on default for HyphenateURLs=false
+ // rely on default for APPLY_TEXT_ATTR_TO_EMPTY_LINE_AT_END_OF_PARAGRAPH=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/sw/source/writerfilter/inc/dmapper/CommentProperties.hxx b/sw/source/writerfilter/inc/dmapper/CommentProperties.hxx
new file mode 100644
index 000000000000..c554418108c4
--- /dev/null
+++ b/sw/source/writerfilter/inc/dmapper/CommentProperties.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+namespace writerfilter
+{
+/**
+ A container for the extended comment properties linked to the last paragraph of a comment
+
+ Corresponds to the data available in w15:commentEx elements from commentsExtended stream
+ ([MS-DOCX]): resolved state and parent (referring to comment that this one answers to).
+
+ @since 7.2
+*/
+struct CommentProperties
+{
+ bool bDone;
+ OUString sParaIdParent;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/source/writerfilter/inc/dmapper/DomainMapperFactory.hxx b/sw/source/writerfilter/inc/dmapper/DomainMapperFactory.hxx
new file mode 100644
index 000000000000..ea7ab81e1a1b
--- /dev/null
+++ b/sw/source/writerfilter/inc/dmapper/DomainMapperFactory.hxx
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <dmapper/resourcemodel.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace utl
+{
+class MediaDescriptor;
+}
+
+namespace writerfilter::dmapper
+{
+enum class SourceDocumentType
+{
+ OOXML,
+ RTF
+};
+
+/// Interface to create a DomainMapper instance.
+class DomainMapperFactory
+{
+public:
+ static Stream::Pointer_t
+ createMapper(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xModel, bool bRepairStorage,
+ SourceDocumentType eDocumentType, utl::MediaDescriptor const& rMediaDesc);
+};
+
+// export just for test
+SAL_DLLPUBLIC_EXPORT std::tuple<OUString, std::vector<OUString>, std::vector<OUString>>
+splitFieldCommand(std::u16string_view rCommand);
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx b/sw/source/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
new file mode 100644
index 000000000000..b5bb27eea81b
--- /dev/null
+++ b/sw/source/writerfilter/inc/dmapper/GraphicZOrderHelper.hxx
@@ -0,0 +1,34 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <map>
+
+namespace writerfilter::dmapper
+{
+class GraphicZOrderHelper
+{
+public:
+ void addItem(css::uno::Reference<css::beans::XPropertySet> const& props,
+ sal_Int64 relativeHeight);
+
+ // must run adjustRelativeHeight before findZOrder - to set zOrder priorities
+ static void adjustRelativeHeight(sal_Int64& rRelativeHeight, bool bIsZIndex, bool bIsBehindText,
+ bool bIsInHeader);
+ sal_Int32 findZOrder(sal_Int64 relativeHeight, bool bOldStyle = false);
+
+private:
+ using Items = std::map<sal_Int64, css::uno::Reference<css::beans::XPropertySet>>;
+ Items m_items;
+};
+
+} // namespace writerfilter::dmapper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/inc/dmapper/resourcemodel.hxx b/sw/source/writerfilter/inc/dmapper/resourcemodel.hxx
new file mode 100644
index 000000000000..5b64de51ba2c
--- /dev/null
+++ b/sw/source/writerfilter/inc/dmapper/resourcemodel.hxx
@@ -0,0 +1,420 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <string>
+#include <sal/types.h>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <tools/ref.hxx>
+
+/**
+ @file resourcemodel.hxx
+
+ The classes in this file define the interfaces for the resource
+ model of the DocTokenizer:
+
+ @image html doctok.png
+
+ A resource is a set of events that describe an object. A resource
+ is only an abstract concept. It is not instantiated to a class.
+
+ A reference to a resource represents the object that the resource
+ describes. The reference can be resolved thereby generating the
+ events of the resource.
+
+ A handler receives the events generated by resolving a
+ reference. There are several types of handlers each accepting their
+ specific set of events.
+
+ References always have a parameter determining the kind of handler
+ they send the events they generate to. The set of events generated
+ by resolving the reference is a subset of the events received by
+ the handler.
+*/
+
+typedef sal_uInt32 Id;
+
+namespace writerfilter
+{
+struct CommentProperties;
+
+/**
+ Reference to a resource that generates events and sends them to a
+ handler.
+
+ The reference can be resolved, i.e. the resource generates its
+ events. The events must be suitable for the handler type given by
+ the template parameter.
+
+ @attention The parameter of the template does not determine the
+ type of the reference's target. It determines the type of the handler!
+
+ Example:
+
+ A Word document can be represented as a stream of events. Event
+ types in a Word document are text, properties, tables, starts and
+ ends of groups. These can be handled by a stream handler (@see
+ Stream). Thus a reference to a Word document is resolved by
+ sending these events to a stream handler.
+*/
+
+template <class T> class SAL_DLLPUBLIC_TEMPLATE Reference : public virtual SvRefBase
+{
+public:
+ /**
+ Pointer to reference
+
+ @attention The ownership of a reference is transferred when
+ the reference is passed.
+ */
+ typedef tools::SvRef<Reference<T>> Pointer_t;
+
+ /**
+ Resolves the reference.
+
+ The events of the references target resource are generated and
+ send to a handler.
+
+ @param rHandler handler which receives the events
+ */
+ virtual void resolve(T& rHandler) = 0;
+
+ Reference() = default;
+ Reference(Reference const&) = default;
+ Reference(Reference&&) = default;
+ Reference& operator=(Reference const&) = default;
+ Reference& operator=(Reference&&) = default;
+
+protected:
+ ~Reference() override {}
+};
+
+class Value;
+class Sprm;
+
+/**
+ Handler for properties.
+ */
+class Properties : public virtual SvRefBase
+{
+public:
+ /**
+ Receives an attribute.
+
+ @param name name of the attribute
+ @param val value of the attribute
+ */
+ virtual void attribute(Id name, Value& val) = 0;
+
+ /**
+ Receives a SPRM.
+
+ @param sprm the SPRM received
+ */
+ virtual void sprm(Sprm& sprm) = 0;
+
+protected:
+ ~Properties() override {}
+};
+
+/**
+ Handler for tables.
+ */
+class Table : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<Table> Pointer_t;
+
+ /**
+ Receives an entry of the table.
+
+ @param pos position of the entry in the table
+ @param ref reference to properties of the entry
+ */
+ virtual void entry(int pos, writerfilter::Reference<Properties>::Pointer_t ref) = 0;
+
+protected:
+ ~Table() override {}
+};
+
+/**
+ Handler for binary objects.
+ */
+class BinaryObj
+{
+public:
+ /**
+ Receives binary data of the object.
+
+ @param buf pointer to buffer containing the data
+ @param len size of buffer
+ */
+ virtual void data(const sal_uInt8* buf, size_t len) = 0;
+
+protected:
+ ~BinaryObj() {}
+};
+
+const sal_uInt8 cFieldLock = 0x8;
+const sal_uInt8 cFieldStart = 0x13;
+const sal_uInt8 cFieldSep = 0x14;
+const sal_uInt8 cFieldEnd = 0x15;
+
+namespace ooxml
+{
+class OOXMLDocument;
+}
+
+/**
+ Handler for a stream.
+ */
+class Stream : public virtual SvRefBase
+{
+public:
+ /**
+ Pointer to this stream.
+ */
+ typedef tools::SvRef<Stream> Pointer_t;
+
+ /**
+ Receives start mark for group with the same section properties.
+ */
+ virtual void startSectionGroup() = 0;
+
+ /**
+ Receives end mark for group with the same section properties.
+ */
+ virtual void endSectionGroup() = 0;
+
+ /// The current section is the last one in this body text.
+ virtual void markLastSectionGroup(){};
+
+ virtual void setDocumentReference(writerfilter::ooxml::OOXMLDocument* pDocument) = 0;
+
+ /**
+ Receives start mark for group with the same paragraph properties.
+ */
+ virtual void startParagraphGroup() = 0;
+
+ /**
+ Receives end mark for group with the same paragraph properties.
+ */
+ virtual void endParagraphGroup() = 0;
+
+ virtual void markLastParagraphInSection(){};
+ virtual void markLastParagraph() {} // When finishing this paragraph, do not add new paragraph
+
+ /**
+ Receives start mark for group with the same character properties.
+ */
+ virtual void startCharacterGroup() = 0;
+
+ /**
+ Receives end mark for group with the same character properties.
+ */
+ virtual void endCharacterGroup() = 0;
+
+ /**
+ Receives a shape.
+ */
+ virtual void startShape(css::uno::Reference<css::drawing::XShape> const& xShape) = 0;
+
+ virtual void endShape() = 0;
+
+ /**
+ Receives a text-box-content.
+ */
+ virtual void startTextBoxContent() = 0;
+
+ virtual void endTextBoxContent() = 0;
+
+ /**
+ Receives 8-bit per character text.
+
+ @param data buffer containing the text
+ @param len number of characters in the text
+ */
+ virtual void text(const sal_uInt8* data, size_t len) = 0;
+
+ /**
+ Receives 16-bit per character text.
+
+ @param data buffer containing the text
+ @param len number of characters in the text.
+ */
+ virtual void utext(const sal_Unicode* 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(const 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, const 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, const writerfilter::Reference<Stream>::Pointer_t& ref) = 0;
+
+ /**
+ Debugging: Receives information about current point in stream.
+
+ @param info the information
+ */
+ virtual void info(const std::string& info) = 0;
+
+ /// Receives start mark for glossary document entry.
+ virtual void startGlossaryEntry() = 0;
+
+ /// Receives end mark for glossary document entry.
+ virtual void endGlossaryEntry() = 0;
+
+ /// Receives identifier for node entry.
+ virtual void checkId(const sal_Int32 nId) = 0;
+
+ virtual void commentProps(const OUString& /*sId*/, const CommentProperties& /*rProps*/) {}
+
+protected:
+ ~Stream() override {}
+};
+
+/**
+ A value.
+
+ The methods of this class may throw exceptions if a certain aspect
+ makes no sense for a certain value, e.g. the integer value of a
+ string.
+ */
+class Value : public virtual SvRefBase
+{
+public:
+ /**
+ Pointer to a value.
+ */
+ typedef tools::SvRef<Value> Pointer_t;
+
+ /**
+ Returns integer representation of the value.
+ */
+ virtual int getInt() const = 0;
+
+ /**
+ Returns string representation of the value.
+ */
+ virtual OUString getString() const = 0;
+
+ /**
+ Returns representation of the value as uno::Any.
+ */
+ virtual css::uno::Any getAny() const = 0;
+
+ /**
+ Returns properties of this value.
+ */
+ virtual writerfilter::Reference<Properties>::Pointer_t getProperties() = 0;
+
+ /**
+ Returns binary object of this value.
+ */
+ virtual writerfilter::Reference<BinaryObj>::Pointer_t getBinary() = 0;
+
+ /**
+ Returns string representation of this value.
+ */
+#ifdef DBG_UTIL
+ virtual std::string toString() const = 0;
+#endif
+};
+
+/**
+ An SPRM: Section, Paragraph and Run Modifier
+
+ */
+class Sprm : public virtual SvRefBase
+{
+public:
+ typedef tools::SvRef<Sprm> Pointer_t;
+
+ /**
+ Returns id of the SPRM.
+ */
+ virtual sal_uInt32 getId() const = 0;
+
+ /**
+ Returns value of the SPRM.
+ */
+ virtual Value::Pointer_t getValue() = 0;
+
+ /**
+ Returns reference to properties contained in the SPRM.
+
+ */
+ virtual writerfilter::Reference<Properties>::Pointer_t getProps() = 0;
+
+ /**
+ Returns name of sprm.
+ */
+#ifdef DBG_UTIL
+ virtual std::string getName() const = 0;
+#endif
+
+ /**
+ Returns string representation of sprm.
+ */
+#ifdef DBG_UTIL
+ virtual std::string toString() const = 0;
+#endif
+
+protected:
+ ~Sprm() override {}
+};
+
+typedef sal_Int32 Token_t;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/inc/ooxml/OOXMLDocument.hxx b/sw/source/writerfilter/inc/ooxml/OOXMLDocument.hxx
new file mode 100644
index 000000000000..91a4aeec5a3f
--- /dev/null
+++ b/sw/source/writerfilter/inc/ooxml/OOXMLDocument.hxx
@@ -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 .
+ */
+#pragma once
+
+#include <sal/types.h>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <dmapper/resourcemodel.hxx>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <oox/shape/ShapeContextHandler.hxx>
+#include <oox/drawingml/theme.hxx>
+
+/**
+ @file OOXMLDocument.hxx
+
+ <h1>Import of OOXML WordprocessingML Documents</h1>
+
+ The following picture shows the classes involved in importing OOXML
+ WordprocessingML documents.
+
+ @image html ooxmlimportchain.png
+
+ The DOCX consists of parts. Each part is an XML document. The
+ OOXMLDocument opens the DOCX and creates a SAX parser for the part
+ containing the main document content. The OOXMLDocument creates a
+ SAX handler, too. This handler is set as the handler for the events
+ created by the parser. Finally the OOXMLDocument initiates the
+ parsing process.
+
+ The SAX handler hosts a stack of contexts. Each context is an
+ instance of a class derived from OOXMLContext. There is a context
+ class for each <define> in the model.xml.
+
+ For a detailed information about how the contexts are handled see
+ the documentation for OOXMLContext.
+
+ The contexts know how to convert an element in OOXML to the
+ intermediate format that the domain mapper understands. They
+ enumerate the according entity in OOXML by sending the according
+ events to the domain mapper.
+
+ The domain mapper knows how to convert the intermediate format to
+ API calls. It takes the events sent by the contexts and uses the
+ core API to insert the according elements to the core.
+ */
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLStream : public virtual SvRefBase
+{
+public:
+ enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING,
+ FOOTNOTES, ENDNOTES, COMMENTS, COMMENTS_EXTENDED, THEME, CUSTOMXML, CUSTOMXMLPROPS, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER, VBADATA };
+ typedef tools::SvRef<OOXMLStream> Pointer_t;
+
+ /**
+ Returns fast parser for this stream.
+ */
+ virtual css::uno::Reference<css::xml::sax::XFastParser> getFastParser() = 0;
+
+ virtual css::uno::Reference<css::io::XInputStream> getDocumentStream() = 0;
+
+ /**
+ Returns component context for this stream.
+ */
+ virtual css::uno::Reference<css::uno::XComponentContext> getContext() = 0;
+
+ /**
+ Returns target URL from relationships for a given id.
+
+ @param rId the id to look for
+
+ @return the URL found or an empty string
+ */
+ virtual OUString getTargetForId(const OUString & rId) = 0;
+
+ virtual const OUString & getTarget() const = 0;
+
+ virtual css::uno::Reference<css::xml::sax::XFastTokenHandler>
+ getFastTokenHandler() = 0;
+
+};
+
+class OOXMLDocument : public writerfilter::Reference<Stream>
+{
+public:
+ /**
+ Pointer to this stream.
+ */
+ typedef tools::SvRef<OOXMLDocument> Pointer_t;
+
+ /**
+ Resolves this document to a stream handler.
+
+ @param rStream stream handler to resolve this document to
+ */
+ virtual void resolve(Stream & rStream) override = 0;
+
+ /**
+ Resolves a footnote to a stream handler.
+
+ A footnote is resolved if either the note type or
+ note id matches.
+
+ @param rStream stream handler to resolve to
+ @param rNoteType type of footnote to resolve
+ @param rNoteId id of the footnote to resolve
+ */
+ virtual void resolveFootnote(Stream & rStream,
+ Id aNoteType,
+ const sal_Int32 nNoteId) = 0;
+ /**
+ Resolves an endnote to a stream handler.
+
+ An endnote is resolved if either the note type or
+ note id matches.
+
+ @param rStream stream handler to resolve to
+ @param rNoteType type of footnote to resolve
+ @param rNoteId id of the endnote to resolve
+ */
+ virtual void resolveEndnote(Stream & rStream,
+ Id aNoteType,
+ const sal_Int32 NoteId) = 0;
+
+ /**
+ Resolves a comment to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param rComment id of the comment to resolve
+ */
+ virtual void resolveComment(Stream & rStream,
+ const sal_Int32 nCommentId) = 0;
+
+ /**
+ Resolves a picture to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param rPictureId id of the picture to resolve
+ */
+ virtual void resolvePicture(Stream & rStream,
+ const OUString & rPictureId) = 0;
+
+ /**
+ Resolves a header to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param type type of header to resolve:
+ NS_ooxml::LN_Value_ST_HrdFtr_even header on even page
+ NS_ooxml::LN_Value_ST_HrdFtr_default header on right page
+ NS_ooxml::LN_Value_ST_HrdFtr_first header on first page
+
+ @param rId id of the header
+ */
+ virtual void resolveHeader(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) = 0;
+
+ /**
+ Resolves a footer to a stream handler.
+
+ @param rStream stream handler to resolve to
+ @param type type of footer to resolve:
+ NS_ooxml::LN_Value_ST_HrdFtr_even header on even page
+ NS_ooxml::LN_Value_ST_HrdFtr_default header on right page
+ NS_ooxml::LN_Value_ST_HrdFtr_first header on first page
+
+ @param rId id of the header
+ */
+ virtual void resolveFooter(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) = 0;
+
+
+ /**
+ Returns target URL from relationships for a given id.
+
+ @param rId the id to look for
+
+ @return the URL found or an empty string
+ */
+ virtual OUString getTargetForId(const OUString & rId) = 0;
+
+ virtual void setModel(css::uno::Reference<css::frame::XModel> xModel) = 0;
+ virtual css::uno::Reference<css::frame::XModel> getModel() = 0;
+ virtual void setDrawPage(css::uno::Reference<css::drawing::XDrawPage> xDrawPage) = 0;
+ virtual css::uno::Reference<css::drawing::XDrawPage> getDrawPage() = 0;
+ virtual css::uno::Reference<css::io::XInputStream> getInputStreamForId(const OUString & rId) = 0;
+ virtual void setXNoteId(const sal_Int32 nId) = 0;
+ virtual sal_Int32 getXNoteId() const = 0;
+ virtual const OUString & getTarget() const = 0;
+ virtual rtl::Reference<oox::shape::ShapeContextHandler> getShapeContext( ) = 0;
+ virtual void setShapeContext(const rtl::Reference<oox::shape::ShapeContextHandler>& xContext) = 0;
+ virtual const oox::drawingml::ThemePtr & getTheme() const = 0;
+
+ /// Push context of drawingML shapes, so nested shapes are handled separately.
+ virtual void pushShapeContext() = 0;
+ /// Pop context of a previously pushed drawingML shape.
+ virtual void popShapeContext() = 0;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getThemeDom( ) = 0;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom( ) = 0;
+ virtual css::uno::Sequence<css::uno::Sequence< css::beans::NamedValue> > getGlossaryDomList() = 0;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomList( ) = 0;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomPropsList( ) = 0;
+ virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() = 0;
+};
+
+
+class OOXMLDocumentFactory
+{
+public:
+ static OOXMLStream::Pointer_t
+ createStream(const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ const css::uno::Reference<css::io::XInputStream>& rStream,
+ bool bRepairStorage);
+
+ static OOXMLStream::Pointer_t
+ createStream(const OOXMLStream::Pointer_t& pStream,
+ OOXMLStream::StreamType_t nStreamType);
+
+ static OOXMLStream::Pointer_t
+ createStream(const OOXMLStream::Pointer_t& pStream, const OUString & rId);
+
+ static OOXMLDocument *
+ createDocument(const OOXMLStream::Pointer_t& pStream,
+ const css::uno::Reference<css::task::XStatusIndicator>& xStatusIndicator,
+ bool bSkipImage, const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor);
+
+};
+
+std::string fastTokenToId(sal_uInt32 nToken);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/inc/ooxml/QNameToString.hxx b/sw/source/writerfilter/inc/ooxml/QNameToString.hxx
new file mode 100644
index 000000000000..d7d27d302bd2
--- /dev/null
+++ b/sw/source/writerfilter/inc/ooxml/QNameToString.hxx
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <string>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter
+{
+#ifdef DBG_UTIL
+std::string QNameToString(Id);
+#endif
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/inc/rtftok/RTFDocument.hxx b/sw/source/writerfilter/inc/rtftok/RTFDocument.hxx
new file mode 100644
index 000000000000..44d0173a6f3e
--- /dev/null
+++ b/sw/source/writerfilter/inc/rtftok/RTFDocument.hxx
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <unotools/mediadescriptor.hxx>
+
+namespace writerfilter::rtftok
+{
+/// The RTFDocument opens and resolves the RTF document.
+class RTFDocument : public writerfilter::Reference<Stream>
+{
+public:
+ /// Pointer to this stream.
+ using Pointer_t = tools::SvRef<RTFDocument>;
+
+ /// Resolves this document to a stream handler.
+ void resolve(Stream& rHandler) override = 0;
+};
+
+/// Interface to create an RTFDocument instance.
+class RTFDocumentFactory
+{
+public:
+ static RTFDocument::Pointer_t
+ createDocument(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor);
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/Handler.cxx b/sw/source/writerfilter/ooxml/Handler.cxx
new file mode 100644
index 000000000000..7cbd9b6bfdc3
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/Handler.cxx
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ooxml/resourceids.hxx>
+#include "Handler.hxx"
+
+#include <sal/log.hxx>
+
+namespace writerfilter::ooxml
+{
+
+/*
+ class OOXMLFootnoteHandler
+ */
+OOXMLFootnoteHandler::OOXMLFootnoteHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLFootnoteHandler::~OOXMLFootnoteHandler()
+{
+}
+
+void OOXMLFootnoteHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_FtnEdnRef_id:
+ mpFastContext->resolveFootnote(sal_Int32(val.getInt()));
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFootnoteHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLEndnoteHandler
+ */
+OOXMLEndnoteHandler::OOXMLEndnoteHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLEndnoteHandler::~OOXMLEndnoteHandler()
+{
+}
+
+void OOXMLEndnoteHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_FtnEdnRef_id:
+ mpFastContext->resolveEndnote(sal_Int32(val.getInt()));
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLEndnoteHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLCommentHandler
+*/
+OOXMLCommentHandler::OOXMLCommentHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLCommentHandler::~OOXMLCommentHandler()
+{
+}
+
+void OOXMLCommentHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Markup_id:
+ mpFastContext->resolveComment(val.getInt());
+ break;
+ default:
+ ;
+ }
+}
+
+void OOXMLCommentHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLOLEHandler
+*/
+OOXMLOLEHandler::OOXMLOLEHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLOLEHandler::~OOXMLOLEHandler()
+{
+}
+
+void OOXMLOLEHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_OLEObject_r_id:
+ try {
+ mpFastContext->resolveData(val.getString());
+ }
+ catch (const ::css::uno::Exception&)
+ {
+ // Can't resolve OLE stream
+ SAL_WARN("writerfilter.ooxml", "Failed to open OLE stream!");
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+void OOXMLOLEHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+OOXMLEmbeddedFontHandler::OOXMLEmbeddedFontHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLEmbeddedFontHandler::~OOXMLEmbeddedFontHandler()
+{
+}
+
+void OOXMLEmbeddedFontHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Rel_id:
+ mpFastContext->resolveData(val.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLEmbeddedFontHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLFooterHandler
+ */
+OOXMLFooterHandler::OOXMLFooterHandler(OOXMLFastContextHandler * pContext)
+ : mpFastContext(pContext), mnType(0)
+{
+}
+
+void OOXMLFooterHandler::finalize()
+{
+ mpFastContext->resolveFooter(mnType, msStreamId);
+}
+
+void OOXMLFooterHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_HdrFtrRef_id:
+ msStreamId = val.getString();
+ break;
+ case NS_ooxml::LN_CT_HdrFtrRef_type:
+ mnType = val.getInt();
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFooterHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLHeaderHandler
+ */
+OOXMLHeaderHandler::OOXMLHeaderHandler(OOXMLFastContextHandler * pContext)
+ : mpFastContext(pContext), mnType(0)
+{
+}
+
+void OOXMLHeaderHandler::finalize()
+{
+ mpFastContext->resolveHeader(mnType, msStreamId);
+}
+
+void OOXMLHeaderHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_HdrFtrRef_id:
+ msStreamId = val.getString();
+ break;
+ case NS_ooxml::LN_CT_HdrFtrRef_type:
+ mnType = val.getInt();
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLHeaderHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLBreakHandler
+ */
+OOXMLBreakHandler::OOXMLBreakHandler(OOXMLFastContextHandler* pContext, Stream &rStream)
+: mnType(0),
+ mpFastContext(pContext),
+ mrStream(rStream)
+{
+}
+
+OOXMLBreakHandler::~OOXMLBreakHandler()
+{
+ if (mpFastContext)
+ {
+ mrStream.props(mpFastContext->getPropertySet().get());
+ mpFastContext->clearProps();
+ }
+
+ sal_uInt8 tmpBreak[1];
+ switch (mnType)
+ {
+ case NS_ooxml::LN_Value_ST_BrType_column:
+ tmpBreak[0] = 0x0E;
+ break;
+ case NS_ooxml::LN_Value_ST_BrType_page:
+ tmpBreak[0] = 0x0C;
+ break;
+ case NS_ooxml::LN_Value_ST_BrType_textWrapping:
+ default: // when no attribute type is present, the spec assume textWrapping
+ tmpBreak[0] = 0x0A;
+ break;
+ }
+ mrStream.text(&tmpBreak[0], 1);
+}
+
+void OOXMLBreakHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Br_type:
+ mnType = val.getInt();
+ break;
+ case NS_ooxml::LN_CT_Br_clear:
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLBreakHandler::sprm(Sprm & /*sprm*/)
+{
+}
+
+/*
+ class OOXMLPictureHandler
+ */
+OOXMLPictureHandler::OOXMLPictureHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLPictureHandler::~OOXMLPictureHandler()
+{
+}
+
+void OOXMLPictureHandler::attribute(Id name, Value & val)
+{
+ if (name == NS_ooxml::LN_AG_Blob_r_embed)
+ mpFastContext->resolvePicture(val.getString());
+ else
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProps
+ (val.getProperties());
+ if (pProps)
+ pProps->resolve(*this);
+ }
+}
+
+void OOXMLPictureHandler::sprm(Sprm & rSprm)
+{
+ writerfilter::Reference<Properties>::Pointer_t pProps
+ (rSprm.getProps());
+
+ if (pProps)
+ pProps->resolve(*this);
+}
+
+/**
+ class OOXMLHyperlinkHandler
+ */
+
+OOXMLHyperlinkHandler::OOXMLHyperlinkHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLHyperlinkHandler::~OOXMLHyperlinkHandler()
+{
+}
+
+void OOXMLHyperlinkHandler::writetext()
+{
+ OUString sReturn = " HYPERLINK \"" + mURL + "\"" + mFieldCode;
+ mpFastContext->text(sReturn);
+}
+
+void OOXMLHyperlinkHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Hyperlink_tgtFrame:
+ mFieldCode += " \\t \"";
+ mFieldCode += val.getString();
+ mFieldCode += "\"";
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_tooltip:
+ mFieldCode += " \\o \"";
+ mFieldCode += val.getString();
+ mFieldCode += "\"";
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_docLocation:
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_history:
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_anchor:
+ mFieldCode += " \\l \"";
+ mFieldCode += val.getString();
+ mFieldCode += "\"";
+ break;
+ case NS_ooxml::LN_CT_Hyperlink_r_id:
+ mURL = mpFastContext->getTargetForId(val.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLHyperlinkHandler::sprm(Sprm & /*rSprm*/)
+{
+}
+
+/**
+ class OOXMLHyperlinkURLHandler
+ */
+
+OOXMLHyperlinkURLHandler::OOXMLHyperlinkURLHandler(OOXMLFastContextHandler * pContext)
+: mpFastContext(pContext)
+{
+}
+
+OOXMLHyperlinkURLHandler::~OOXMLHyperlinkURLHandler()
+{
+ mpFastContext->clearProps();
+ mpFastContext->newProperty(NS_ooxml::LN_CT_Hyperlink_URL, OOXMLValue::Pointer_t(new OOXMLStringValue(mURL)));
+}
+
+void OOXMLHyperlinkURLHandler::attribute(Id name, Value & val)
+{
+ switch (name)
+ {
+ case NS_ooxml::LN_CT_Hyperlink_URL:
+ mURL = mpFastContext->getTargetForId(val.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLHyperlinkURLHandler::sprm(Sprm & /*rSprm*/)
+{
+}
+
+OOXMLAltChunkHandler::OOXMLAltChunkHandler(OOXMLFastContextHandler* pContext)
+ : mpFastContext(pContext)
+{
+}
+
+OOXMLAltChunkHandler::~OOXMLAltChunkHandler()
+{
+ mpFastContext->clearProps();
+ mpFastContext->newProperty(NS_ooxml::LN_CT_AltChunk,
+ OOXMLValue::Pointer_t(new OOXMLStringValue(m_aStreamName)));
+}
+
+void OOXMLAltChunkHandler::attribute(Id nName, Value& rValue)
+{
+ switch (nName)
+ {
+ case NS_ooxml::LN_CT_AltChunk:
+ m_aStreamName = mpFastContext->getTargetForId(rValue.getString());
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLAltChunkHandler::sprm(Sprm& /*rSprm*/) {}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/Handler.hxx b/sw/source/writerfilter/ooxml/Handler.hxx
new file mode 100644
index 000000000000..df6673d44318
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/Handler.hxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+#include "OOXMLFastContextHandler.hxx"
+
+namespace writerfilter::ooxml
+{
+class OOXMLFootnoteHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLFootnoteHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLFootnoteHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLEndnoteHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLEndnoteHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLEndnoteHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLFooterHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString msStreamId;
+ sal_Int32 mnType;
+
+public:
+ explicit OOXMLFooterHandler(OOXMLFastContextHandler* pContext);
+ void finalize();
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLHeaderHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString msStreamId;
+ sal_Int32 mnType;
+
+public:
+ explicit OOXMLHeaderHandler(OOXMLFastContextHandler* pContext);
+ void finalize();
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLCommentHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLCommentHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLCommentHandler() override;
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLOLEHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLOLEHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLOLEHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLEmbeddedFontHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLEmbeddedFontHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLEmbeddedFontHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLBreakHandler : public Properties
+{
+ sal_Int32 mnType;
+ OOXMLFastContextHandler* mpFastContext;
+ Stream& mrStream;
+
+public:
+ explicit OOXMLBreakHandler(OOXMLFastContextHandler* pContext, Stream& rStream);
+ virtual ~OOXMLBreakHandler() override;
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLPictureHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+
+public:
+ explicit OOXMLPictureHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLPictureHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLHyperlinkHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString mFieldCode;
+ OUString mURL;
+
+public:
+ explicit OOXMLHyperlinkHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLHyperlinkHandler() override;
+ void writetext();
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+class OOXMLHyperlinkURLHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString mURL;
+
+public:
+ explicit OOXMLHyperlinkURLHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLHyperlinkURLHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+
+/// Looks up the stream name for a '<w:altChunk r:id="..."/>' reference.
+class OOXMLAltChunkHandler : public Properties
+{
+ OOXMLFastContextHandler* mpFastContext;
+ OUString m_aStreamName;
+
+public:
+ explicit OOXMLAltChunkHandler(OOXMLFastContextHandler* pContext);
+ virtual ~OOXMLAltChunkHandler() override;
+
+ virtual void attribute(Id name, Value& val) override;
+ virtual void sprm(Sprm& sprm) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.cxx b/sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.cxx
new file mode 100644
index 000000000000..f33d9bed0e0e
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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>
+
+#include <utility>
+
+namespace writerfilter::ooxml
+{
+
+using namespace ::com::sun::star;
+
+OOXMLBinaryObjectReference::OOXMLBinaryObjectReference
+(OOXMLStream::Pointer_t pStream)
+: mpStream(std::move(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/sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.hxx b/sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.hxx
new file mode 100644
index 000000000000..09502f208199
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLBinaryObjectReference.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+#include <ooxml/OOXMLDocument.hxx>
+#include <vector>
+
+namespace writerfilter::ooxml
+{
+class OOXMLBinaryObjectReference : public writerfilter::Reference<BinaryObj>
+{
+ OOXMLStream::Pointer_t mpStream;
+ std::vector<sal_Int8> mSequence;
+ bool mbRead;
+
+ void read();
+
+public:
+ explicit OOXMLBinaryObjectReference(OOXMLStream::Pointer_t pStream);
+ virtual ~OOXMLBinaryObjectReference() override;
+
+ virtual void resolve(BinaryObj& rHandler) override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLDocumentImpl.cxx b/sw/source/writerfilter/ooxml/OOXMLDocumentImpl.cxx
new file mode 100644
index 000000000000..0530969fbccc
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLDocumentImpl.cxx
@@ -0,0 +1,911 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/sequenceashashmap.hxx>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/graphic/GraphicMapper.hpp>
+#include <ooxml/resourceids.hxx>
+#include <oox/drawingml/theme.hxx>
+#include <oox/shape/ShapeFilterBase.hxx>
+#include "OOXMLStreamImpl.hxx"
+#include "OOXMLDocumentImpl.hxx"
+#include "OOXMLBinaryObjectReference.hxx"
+#include "OOXMLFastDocumentHandler.hxx"
+#include "OOXMLPropertySet.hxx"
+
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <comphelper/sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <unotools/mediadescriptor.hxx>
+
+#include <iostream>
+#include <sfx2/objsh.hxx>
+#include <utility>
+
+// 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 pStream, uno::Reference<task::XStatusIndicator> xStatusIndicator, bool bSkipImages, const uno::Sequence<beans::PropertyValue>& rDescriptor)
+ : mpStream(std::move(pStream))
+ , mxStatusIndicator(std::move(xStatusIndicator))
+ , mnXNoteId(0)
+ , mbIsSubstream(false)
+ , mbSkipImages(bSkipImages)
+ , mnPercentSize(0)
+ , mnProgressLastPos(0)
+ , mnProgressCurrentPos(0)
+ , mnProgressEndPos(0)
+ , m_rBaseURL(utl::MediaDescriptor(rDescriptor).getUnpackedValueOrDefault("DocumentBaseURL", OUString()))
+ , maMediaDescriptor(rDescriptor)
+ , mxGraphicMapper(graphic::GraphicMapper::create(mpStream->getContext()))
+{
+ pushShapeContext();
+}
+
+OOXMLDocumentImpl::~OOXMLDocumentImpl()
+{
+}
+
+void OOXMLDocumentImpl::resolveFastSubStream(Stream & rStreamHandler,
+ OOXMLStream::StreamType_t nType)
+{
+ OOXMLStream::Pointer_t pStream;
+ try
+ {
+ pStream = OOXMLDocumentFactory::createStream(mpStream, nType);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "resolveFastSubStream: exception while "
+ "resolving stream " << nType);
+ return;
+ }
+ OOXMLStream::Pointer_t savedStream = mpStream;
+ mpStream = pStream;
+
+ uno::Reference<xml::sax::XFastParser> xParser(mpStream->getFastParser());
+
+ if (xParser.is())
+ {
+ uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+ rtl::Reference<OOXMLFastDocumentHandler> pDocHandler =
+ new OOXMLFastDocumentHandler(xContext, &rStreamHandler, this, mnXNoteId);
+
+ uno::Reference<xml::sax::XFastTokenHandler> xTokenHandler(mpStream->getFastTokenHandler());
+
+ xParser->setFastDocumentHandler(pDocHandler);
+ xParser->setTokenHandler(xTokenHandler);
+
+ uno::Reference<io::XInputStream> xInputStream = mpStream->getDocumentStream();
+
+ if (xInputStream.is())
+ {
+ struct xml::sax::InputSource oInputSource;
+ oInputSource.aInputStream = xInputStream;
+ xParser->parseStream(oInputSource);
+
+ xInputStream->closeInput();
+ }
+ }
+
+ mpStream = std::move(savedStream);
+}
+
+void OOXMLDocumentImpl::resolveFastSubStreamWithId(Stream & rStream,
+ const writerfilter::Reference<Stream>::Pointer_t& pStream,
+ sal_uInt32 nId)
+{
+ rStream.substream(nId, pStream);
+}
+
+uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::importSubStream(OOXMLStream::StreamType_t nType)
+{
+ uno::Reference<xml::dom::XDocument> xRet;
+
+ OOXMLStream::Pointer_t pStream;
+ try
+ {
+ pStream = OOXMLDocumentFactory::createStream(mpStream, nType);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "importing stream " << nType);
+ return xRet;
+ }
+
+ uno::Reference<io::XInputStream> xInputStream = pStream->getDocumentStream();
+ if (xInputStream.is())
+ {
+ try
+ {
+ uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(xml::dom::DocumentBuilder::create(xContext));
+ xRet = xDomBuilder->parse(xInputStream);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "parsing stream " << nType);
+ return xRet;
+ }
+ }
+
+ if (OOXMLStream::CUSTOMXML == nType)
+ {
+ importSubStreamRelations(pStream, OOXMLStream::CUSTOMXMLPROPS);
+ }
+ else if (OOXMLStream::CHARTS == nType)
+ {
+ importSubStreamRelations(pStream, OOXMLStream::EMBEDDINGS);
+ }
+
+ return xRet;
+}
+
+
+void OOXMLDocumentImpl::importSubStreamRelations(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nType)
+{
+ uno::Reference<xml::dom::XDocument> xRelation;
+ OOXMLStream::Pointer_t cStream;
+ try
+ {
+ cStream = OOXMLDocumentFactory::createStream(pStream, nType);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.ooxml", "importSubStreamRelations: exception while "
+ "importing stream " << nType);
+ return;
+ }
+
+ uno::Reference<io::XInputStream> xcpInputStream = cStream->getDocumentStream();
+
+ if (!xcpInputStream.is())
+ return;
+
+ // importing itemprops files for item.xml from customXml.
+ if (OOXMLStream::CUSTOMXMLPROPS == nType)
+ {
+ try
+ {
+ uno::Reference<uno::XComponentContext> xcpContext(pStream->getContext());
+ uno::Reference<xml::dom::XDocumentBuilder> xDomBuilder(xml::dom::DocumentBuilder::create(xcpContext));
+ xRelation = xDomBuilder->parse(xcpInputStream);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "parsing stream " << nType);
+ mxCustomXmlProsDom = xRelation;
+ }
+
+ if(xRelation.is())
+ {
+ mxCustomXmlProsDom = xRelation;
+ }
+ }
+ else if(OOXMLStream::EMBEDDINGS == nType)
+ {
+ mxEmbeddings = xcpInputStream;
+ }
+ else if(OOXMLStream::CHARTS == nType)
+ {
+ importSubStreamRelations(cStream, OOXMLStream::EMBEDDINGS);
+ }
+
+
+}
+
+void OOXMLDocumentImpl::setXNoteId(const sal_Int32 nId)
+{
+ mnXNoteId = nId;
+}
+
+sal_Int32 OOXMLDocumentImpl::getXNoteId() const
+{
+ return mnXNoteId;
+}
+
+const OUString & OOXMLDocumentImpl::getTarget() const
+{
+ return mpStream->getTarget();
+}
+
+writerfilter::Reference<Stream>::Pointer_t
+OOXMLDocumentImpl::getSubStream(const OUString & rId)
+{
+ OOXMLStream::Pointer_t pStream
+ (OOXMLDocumentFactory::createStream(mpStream, rId));
+
+ OOXMLDocumentImpl * pTemp;
+ // Do not pass status indicator to sub-streams: they are typically marginal in size, so we just track the main document for now.
+ writerfilter::Reference<Stream>::Pointer_t pRet( pTemp =
+ new OOXMLDocumentImpl(std::move(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)
+{
+ // See above, no status indicator for the note stream, either.
+ OOXMLDocumentImpl * pDocument = new OOXMLDocumentImpl(OOXMLDocumentFactory::createStream(mpStream, nType),
+ uno::Reference<task::XStatusIndicator>(), mbSkipImages, maMediaDescriptor);
+ pDocument->setXNoteId(nId);
+ pDocument->setModel(getModel());
+ pDocument->setDrawPage(getDrawPage());
+
+ return writerfilter::Reference<Stream>::Pointer_t(pDocument);
+}
+
+void OOXMLDocumentImpl::resolveFootnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId)
+{
+ if (!mpXFootnoteStream)
+ mpXFootnoteStream = getXNoteStream(OOXMLStream::FOOTNOTES, nNoteId);
+
+ Id nId;
+ switch (aType)
+ {
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_separator:
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_continuationSeparator:
+ nId = aType;
+ break;
+ default:
+ nId = NS_ooxml::LN_footnote;
+ break;
+ }
+
+ resolveFastSubStreamWithId(rStream, mpXFootnoteStream, nId);
+}
+
+void OOXMLDocumentImpl::resolveEndnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId)
+{
+ if (!mpXEndnoteStream)
+ mpXEndnoteStream = getXNoteStream(OOXMLStream::ENDNOTES, nNoteId);
+
+ Id nId;
+ switch (aType)
+ {
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_separator:
+ case NS_ooxml::LN_Value_doc_ST_FtnEdn_continuationSeparator:
+ nId = aType;
+ break;
+ default:
+ nId = NS_ooxml::LN_endnote;
+ break;
+ }
+
+ resolveFastSubStreamWithId(rStream, mpXEndnoteStream, nId);
+}
+
+void OOXMLDocumentImpl::resolveCommentsExtendedStream(Stream& rStream)
+{
+ resolveFastSubStream(rStream, OOXMLStream::COMMENTS_EXTENDED);
+}
+
+void OOXMLDocumentImpl::resolveComment(Stream & rStream,
+ const sal_Int32 nId)
+{
+ if (!mbCommentsExtendedResolved)
+ {
+ resolveCommentsExtendedStream(rStream);
+ mbCommentsExtendedResolved = true;
+ }
+
+ writerfilter::Reference<Stream>::Pointer_t pStream =
+ getXNoteStream(OOXMLStream::COMMENTS, nId);
+
+ resolveFastSubStreamWithId(rStream, pStream, NS_ooxml::LN_annotation);
+}
+
+OOXMLPropertySet * OOXMLDocumentImpl::getPicturePropSet
+(const OUString & rId)
+{
+ OOXMLStream::Pointer_t xStream
+ (OOXMLDocumentFactory::createStream(mpStream, rId));
+
+ writerfilter::Reference<BinaryObj>::Pointer_t xPicture
+ (new OOXMLBinaryObjectReference(std::move(xStream)));
+
+ OOXMLValue::Pointer_t pPayloadValue(new OOXMLBinaryValue(std::move(xPicture)));
+
+ 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> xStatusIndicator)
+ :mxStatusIndicator(std::move(xStatusIndicator))
+ {
+ }
+
+ ~StatusIndicatorGuard()
+ {
+ if (mxStatusIndicator.is())
+ mxStatusIndicator->end();
+ }
+
+private:
+ css::uno::Reference<css::task::XStatusIndicator> mxStatusIndicator;
+};
+}
+
+void OOXMLDocumentImpl::resolve(Stream & rStream)
+{
+ StatusIndicatorGuard aStatusIndicatorGuard(mxStatusIndicator);
+
+ if (utl::MediaDescriptor(maMediaDescriptor).getUnpackedValueOrDefault("ReadGlossaries", false))
+ {
+ resolveFastSubStream(rStream, OOXMLStream::GLOSSARY);
+ return;
+ }
+
+ uno::Reference<xml::sax::XFastParser> xParser(mpStream->getFastParser());
+
+ if (mxModel.is())
+ {
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(mxModel, uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+ comphelper::SequenceAsHashMap aMap(xDocumentProperties->getDocumentStatistics());
+ if (aMap.find("ParagraphCount") != aMap.end())
+ {
+ sal_Int32 nValue;
+ if (aMap["ParagraphCount"] >>= nValue)
+ {
+ if (mxStatusIndicator.is())
+ {
+ // We want to care about the progress if we know the estimated paragraph count and we have given a status indicator as well.
+ // Set the end position only here, so later it's enough to check if that is non-zero in incrementProgress().
+ mnProgressEndPos = nValue;
+ OUString aDocLoad(SvxResId(RID_SVXSTR_DOC_LOAD));
+ mxStatusIndicator->start(aDocLoad, mnProgressEndPos);
+ mnPercentSize = mnProgressEndPos / 100;
+ }
+ }
+ }
+ }
+
+ if (!xParser.is())
+ return;
+
+ uno::Reference<uno::XComponentContext> xContext(mpStream->getContext());
+
+ rStream.setDocumentReference(this);
+
+ rtl::Reference<OOXMLFastDocumentHandler> pDocHandler =
+ new OOXMLFastDocumentHandler(xContext, &rStream, this, mnXNoteId);
+ pDocHandler->setIsSubstream( mbIsSubstream );
+ uno::Reference < xml::sax::XFastTokenHandler > xTokenHandler(mpStream->getFastTokenHandler());
+
+ resolveFastSubStream(rStream, OOXMLStream::SETTINGS);
+ mxThemeDom = importSubStream(OOXMLStream::THEME);
+ resolveFastSubStream(rStream, OOXMLStream::THEME);
+ // Convert the oox::Theme to the draw page
+ {
+ auto pThemePtr = getTheme();
+ if (pThemePtr)
+ pThemePtr->addTheme(getDrawPage());
+ }
+ mxGlossaryDocDom = importSubStream(OOXMLStream::GLOSSARY);
+ if (mxGlossaryDocDom.is())
+ resolveGlossaryStream(rStream);
+
+ resolveEmbeddingsStream(mpStream);
+
+ // Custom xml's are handled as part of grab bag.
+ resolveCustomXmlStream(rStream);
+
+ resolveFastSubStream(rStream, OOXMLStream::FONTTABLE);
+ resolveFastSubStream(rStream, OOXMLStream::STYLES);
+ resolveFastSubStream(rStream, OOXMLStream::NUMBERING);
+
+ xParser->setFastDocumentHandler( pDocHandler );
+ xParser->setTokenHandler( xTokenHandler );
+
+ xml::sax::InputSource aParserInput;
+ aParserInput.sSystemId = mpStream->getTarget();
+ aParserInput.aInputStream = mpStream->getDocumentStream();
+ try
+ {
+ xParser->parseStream(aParserInput);
+ }
+ catch (xml::sax::SAXException const&)
+ {
+ // 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())
+ throw;
+ }
+ catch (uno::RuntimeException const&)
+ {
+ throw;
+ }
+ // note: cannot throw anything other than SAXException out of here?
+ catch (uno::Exception const&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ SAL_WARN("writerfilter.ooxml", "OOXMLDocumentImpl::resolve(): " << exceptionToString(anyEx));
+ throw lang::WrappedTargetRuntimeException("", nullptr, anyEx);
+ }
+ catch (...)
+ {
+ SAL_WARN("writerfilter.ooxml",
+ "OOXMLDocumentImpl::resolve(): non-UNO exception");
+ }
+}
+
+void OOXMLDocumentImpl::incrementProgress()
+{
+ mnProgressCurrentPos++;
+ // 1) If we know the end
+ // 2) We progressed enough that updating makes sense
+ // 3) We did not reach the end yet (possible in case the doc stat is misleading)
+ if (mnProgressEndPos && mnProgressCurrentPos > (mnProgressLastPos + mnPercentSize) && mnProgressLastPos < mnProgressEndPos)
+ {
+ mnProgressLastPos = mnProgressCurrentPos;
+ if (mxStatusIndicator.is())
+ mxStatusIndicator->setValue(mnProgressLastPos);
+ }
+}
+
+void OOXMLDocumentImpl::resolveCustomXmlStream(Stream & rStream)
+{
+ // Resolving all item[n].xml files from CustomXml folder.
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess;
+ xRelationshipAccess.set(dynamic_cast<OOXMLStreamImpl&>(*mpStream).accessDocumentStream(), uno::UNO_QUERY);
+ if (!xRelationshipAccess.is())
+ return;
+
+ static const char sCustomType[] = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml";
+ static const char sCustomTypeStrict[] = "http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
+ bool bFound = false;
+ const uno::Sequence<uno::Sequence< beans::StringPair>> aSeqs = xRelationshipAccess->getAllRelationships();
+ std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomList;
+ std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList;
+ for (const uno::Sequence<beans::StringPair>& aSeq : aSeqs)
+ {
+ for (const beans::StringPair& aPair : aSeq)
+ {
+ // Need to resolve only customxml files from document relationships.
+ // Skipping other files.
+ if (aPair.Second == sCustomType ||
+ aPair.Second == sCustomTypeStrict)
+ bFound = true;
+ else if (aPair.First == "Target" && bFound)
+ {
+ // Adding value to extern variable customTarget. It will be used in ooxmlstreamimpl
+ // to ensure customxml target is visited in lcl_getTarget.
+ customTarget = aPair.Second;
+ }
+ }
+
+ if (bFound)
+ {
+ uno::Reference<xml::dom::XDocument> customXmlTemp = importSubStream(OOXMLStream::CUSTOMXML);
+ // This will add all item[n].xml with its relationship file i.e itemprops.xml to
+ // grabbag list.
+ if (mxCustomXmlProsDom.is() && customXmlTemp.is())
+ {
+ aCustomXmlDomList.push_back(customXmlTemp);
+ aCustomXmlDomPropsList.push_back(mxCustomXmlProsDom);
+ resolveFastSubStream(rStream, OOXMLStream::CUSTOMXML);
+ }
+
+ bFound = false;
+ }
+ }
+
+ mxCustomXmlDomList = comphelper::containerToSequence(aCustomXmlDomList);
+ mxCustomXmlDomPropsList = comphelper::containerToSequence(aCustomXmlDomPropsList);
+}
+
+namespace
+{
+constexpr OUStringLiteral sSettingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
+constexpr OUStringLiteral sStylesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+constexpr OUStringLiteral sFonttableType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
+constexpr OUStringLiteral sWebSettings = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
+constexpr OUStringLiteral sSettingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
+constexpr OUStringLiteral sStylesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
+constexpr OUStringLiteral sFonttableTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
+constexpr OUStringLiteral sWebSettingsStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
+
+constexpr OUString sId = u"Id"_ustr;
+constexpr OUStringLiteral sType = u"Type";
+constexpr OUString sTarget = u"Target"_ustr;
+constexpr OUStringLiteral sTargetMode = u"TargetMode";
+constexpr OUString sContentType = u"_contentType"_ustr;
+constexpr OUStringLiteral sRelDom = u"_relDom";
+constexpr OUStringLiteral sSettingsContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml";
+constexpr OUStringLiteral sStylesContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml";
+constexpr OUStringLiteral sWebsettingsContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml";
+constexpr OUStringLiteral sFonttableContentType = u"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml";
+}
+
+// See DocxExport::WriteGlossary
+void OOXMLDocumentImpl::resolveGlossaryStream(Stream & /*rStream*/)
+{
+ OOXMLStream::Pointer_t pStream;
+ try
+ {
+ pStream = OOXMLDocumentFactory::createStream(mpStream, OOXMLStream::GLOSSARY);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "resolveGlossaryStream: exception while "
+ "createStream for glossary" << OOXMLStream::GLOSSARY);
+ return;
+ }
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess;
+ xRelationshipAccess.set(dynamic_cast<OOXMLStreamImpl&>(*pStream).accessDocumentStream(), uno::UNO_QUERY);
+ if (!xRelationshipAccess.is())
+ return;
+
+
+ const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs = xRelationshipAccess->getAllRelationships();
+ std::vector< uno::Sequence<beans::NamedValue> > aGlossaryDomList;
+ for (const uno::Sequence< beans::StringPair >& aSeq : aSeqs)
+ {
+ comphelper::NamedValueCollection aRelDefinition;
+ for (const auto& [name, value] : aSeq)
+ aRelDefinition.put(name, value);
+
+ const OUString gType = aRelDefinition.getOrDefault(sType, OUString{});
+ OOXMLStream::StreamType_t nType(OOXMLStream::UNKNOWN);
+ if (gType == sSettingsType || gType == sSettingsTypeStrict)
+ {
+ nType = OOXMLStream::SETTINGS;
+ aRelDefinition.put(sContentType, sSettingsContentType);
+ }
+ else if (gType == sStylesType || gType == sStylesTypeStrict)
+ {
+ nType = OOXMLStream::STYLES;
+ aRelDefinition.put(sContentType, sStylesContentType);
+ }
+ else if (gType == sWebSettings || gType == sWebSettingsStrict)
+ {
+ nType = OOXMLStream::WEBSETTINGS;
+ aRelDefinition.put(sContentType, sWebsettingsContentType);
+ }
+ else if (gType == sFonttableType || gType == sFonttableTypeStrict)
+ {
+ nType = OOXMLStream::FONTTABLE;
+ aRelDefinition.put(sContentType, sFonttableContentType);
+ }
+ else if (aRelDefinition.getOrDefault(sTargetMode, OUString{}) != "External")
+ {
+ // Some internal relation, but we don't create a DOM for it here yet?
+ SAL_WARN("writerfilter.ooxml", "Unknown type of glossary internal relation: "
+ "Id=\"" + aRelDefinition.getOrDefault<OUString>(sId, {}) + "\" "
+ "Type=\"" + gType + "\" "
+ "Target=\"" + aRelDefinition.getOrDefault<OUString>(sTarget, {}) + "\"");
+ continue;
+ }
+
+ if (nType != OOXMLStream::UNKNOWN)
+ {
+ try
+ {
+ auto gStream = OOXMLDocumentFactory::createStream(pStream, nType);
+ uno::Reference xInputStream = gStream->getDocumentStream();
+ uno::Reference xContext(pStream->getContext());
+ uno::Reference xDomBuilder(xml::dom::DocumentBuilder::create(xContext));
+ uno::Reference xDom = xDomBuilder->parse(xInputStream);
+ aRelDefinition.put(sRelDom, xDom);
+ }
+ catch (uno::Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("writerfilter.ooxml", "importSubStream: exception while "
+ "parsing stream of Type" << nType);
+ }
+ }
+ aGlossaryDomList.push_back(aRelDefinition.getNamedValues());
+ }
+ mxGlossaryDomList = comphelper::containerToSequence(aGlossaryDomList);
+}
+
+void OOXMLDocumentImpl::resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream)
+{
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess;
+ xRelationshipAccess.set(dynamic_cast<OOXMLStreamImpl&>(*pStream).accessDocumentStream(), uno::UNO_QUERY);
+ if (xRelationshipAccess.is())
+ {
+ static constexpr OUStringLiteral sChartType(u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart");
+ static constexpr OUStringLiteral sChartTypeStrict(u"http://purl.oclc.org/ooxml/officeDocument/relationships/chart");
+ static constexpr OUStringLiteral sFootersType(u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer");
+ static constexpr OUStringLiteral sFootersTypeStrict(u"http://purl.oclc.org/ooxml/officeDocument/relationships/footer");
+ static constexpr OUStringLiteral sHeaderType(u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header");
+ static constexpr OUStringLiteral sHeaderTypeStrict(u"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;
+ m_aEmbeddings.push_back(embeddingsTemp);
+ mxEmbeddings.clear();
+ }
+ bFound = false;
+ bHeaderFooterFound = false;
+ }
+ }
+ }
+ if (!m_aEmbeddings.empty())
+ mxEmbeddingsList = comphelper::containerToSequence(m_aEmbeddings);
+}
+
+uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::getGlossaryDocDom( )
+{
+ return mxGlossaryDocDom;
+}
+
+uno::Sequence<uno::Sequence< beans::NamedValue> > OOXMLDocumentImpl::getGlossaryDomList()
+{
+ return mxGlossaryDomList;
+}
+
+uno::Reference<io::XInputStream> OOXMLDocumentImpl::getInputStreamForId(const OUString & rId)
+{
+ OOXMLStream::Pointer_t pStream(OOXMLDocumentFactory::createStream(mpStream, rId));
+
+ return pStream->getDocumentStream();
+}
+
+void OOXMLDocumentImpl::setModel(uno::Reference<frame::XModel> xModel)
+{
+ mxModel.set(xModel);
+}
+
+uno::Reference<frame::XModel> OOXMLDocumentImpl::getModel()
+{
+ return mxModel;
+}
+
+void OOXMLDocumentImpl::setDrawPage(uno::Reference<drawing::XDrawPage> xDrawPage)
+{
+ mxDrawPage.set(xDrawPage);
+}
+
+uno::Reference<drawing::XDrawPage> OOXMLDocumentImpl::getDrawPage()
+{
+ return mxDrawPage;
+}
+
+const uno::Sequence<beans::PropertyValue>& OOXMLDocumentImpl::getMediaDescriptor() const
+{
+ return maMediaDescriptor;
+}
+
+void OOXMLDocumentImpl::setShapeContext(const rtl::Reference<oox::shape::ShapeContextHandler>& xContext)
+{
+ if (!maShapeContexts.empty())
+ maShapeContexts.top() = xContext;
+}
+
+rtl::Reference<oox::shape::ShapeContextHandler> OOXMLDocumentImpl::getShapeContext( )
+{
+ if (!maShapeContexts.empty())
+ return maShapeContexts.top();
+ else
+ return {};
+}
+
+void OOXMLDocumentImpl::pushShapeContext()
+{
+ maShapeContexts.push({});
+}
+
+void OOXMLDocumentImpl::popShapeContext()
+{
+ if (!maShapeContexts.empty())
+ maShapeContexts.pop();
+}
+
+uno::Reference<xml::dom::XDocument> OOXMLDocumentImpl::getThemeDom( )
+{
+ return mxThemeDom;
+}
+
+uno::Sequence<uno::Reference<xml::dom::XDocument> > OOXMLDocumentImpl::getCustomXmlDomList( )
+{
+ return mxCustomXmlDomList;
+}
+
+uno::Sequence<uno::Reference<xml::dom::XDocument> > OOXMLDocumentImpl::getCustomXmlDomPropsList( )
+{
+ return mxCustomXmlDomPropsList;
+}
+
+uno::Sequence<beans::PropertyValue > OOXMLDocumentImpl::getEmbeddingsList( )
+{
+ return mxEmbeddingsList;
+}
+
+const rtl::Reference<oox::shape::ShapeFilterBase>& OOXMLDocumentImpl::getShapeFilterBase()
+{
+ if (!mxShapeFilterBase)
+ mxShapeFilterBase = new oox::shape::ShapeFilterBase(mpStream->getContext());
+ return mxShapeFilterBase;
+}
+
+const rtl::Reference<oox::drawingml::ThemeFilterBase>& OOXMLDocumentImpl::getThemeFilterBase()
+{
+ if (!mxThemeFilterBase)
+ mxThemeFilterBase = new oox::drawingml::ThemeFilterBase(mpStream->getContext());
+ return mxThemeFilterBase;
+}
+
+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/sw/source/writerfilter/ooxml/OOXMLDocumentImpl.hxx b/sw/source/writerfilter/ooxml/OOXMLDocumentImpl.hxx
new file mode 100644
index 000000000000..87aae13ab94f
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLDocumentImpl.hxx
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <ooxml/OOXMLDocument.hxx>
+
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/graphic/XGraphicMapper.hpp>
+
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <oox/drawingml/ThemeFilterBase.hxx>
+
+#include "OOXMLPropertySet.hxx"
+
+#include <vector>
+#include <stack>
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLDocumentImpl : public OOXMLDocument
+{
+ OOXMLStream::Pointer_t mpStream;
+ css::uno::Reference<css::task::XStatusIndicator> mxStatusIndicator;
+ writerfilter::Reference<Stream>::Pointer_t mpXFootnoteStream;
+ writerfilter::Reference<Stream>::Pointer_t mpXEndnoteStream;
+ sal_Int32 mnXNoteId;
+
+ css::uno::Reference<css::frame::XModel> mxModel;
+ css::uno::Reference<css::drawing::XDrawPage> mxDrawPage;
+ css::uno::Reference<css::xml::dom::XDocument> mxGlossaryDocDom;
+ css::uno::Sequence < css::uno::Sequence< css::beans::NamedValue > > mxGlossaryDomList;
+ /// Stack of shape contexts, 1 element for VML, 1 element / nesting level for drawingML.
+ std::stack< rtl::Reference<oox::shape::ShapeContextHandler> > maShapeContexts;
+ css::uno::Reference<css::xml::dom::XDocument> mxThemeDom;
+ css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxCustomXmlDomList;
+ css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > mxCustomXmlDomPropsList;
+ css::uno::Reference<css::xml::dom::XDocument> mxCustomXmlProsDom;
+ css::uno::Reference<css::io::XInputStream> mxEmbeddings;
+ css::uno::Sequence < css::beans::PropertyValue > mxEmbeddingsList;
+ std::vector<css::beans::PropertyValue> m_aEmbeddings;
+ bool mbIsSubstream;
+ bool mbSkipImages;
+ /// How many paragraphs equal to 1 percent?
+ sal_Int32 mnPercentSize;
+ /// Position progress when it was last updated, possibly not after every paragraph in case of large documents.
+ sal_Int32 mnProgressLastPos;
+ /// Current position progress, updated after every paragraph.
+ sal_Int32 mnProgressCurrentPos;
+ /// End position, i.e. the estimated number of paragraphs.
+ sal_Int32 mnProgressEndPos;
+ /// DocumentBaseURL
+ OUString m_rBaseURL;
+ css::uno::Sequence<css::beans::PropertyValue> maMediaDescriptor;
+ /// Graphic mapper
+ css::uno::Reference<css::graphic::XGraphicMapper> mxGraphicMapper;
+ // For a document there is a single theme in document.xml.rels
+ // and the same is used by header and footer as well.
+ oox::drawingml::ThemePtr mpTheme;
+ rtl::Reference<oox::shape::ShapeFilterBase> mxShapeFilterBase;
+ rtl::Reference<oox::drawingml::ThemeFilterBase> mxThemeFilterBase;
+
+ bool mbCommentsExtendedResolved = false;
+
+private:
+ void resolveFastSubStream(Stream & rStream,
+ OOXMLStream::StreamType_t nType);
+
+ static void resolveFastSubStreamWithId(Stream & rStream,
+ const writerfilter::Reference<Stream>::Pointer_t& pStream,
+ sal_uInt32 nId);
+
+ css::uno::Reference<css::xml::dom::XDocument> importSubStream(OOXMLStream::StreamType_t nType);
+
+ void importSubStreamRelations(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nType);
+
+ writerfilter::Reference<Stream>::Pointer_t
+ getSubStream(const OUString & rId);
+
+ writerfilter::Reference<Stream>::Pointer_t
+ getXNoteStream(OOXMLStream::StreamType_t nType, const sal_Int32 nNoteId);
+
+ void resolveCustomXmlStream(Stream & rStream);
+ void resolveGlossaryStream(Stream & rStream);
+ void resolveEmbeddingsStream(const OOXMLStream::Pointer_t& pStream);
+ void resolveCommentsExtendedStream(Stream & rStream);
+
+public:
+ OOXMLDocumentImpl(OOXMLStream::Pointer_t pStream, css::uno::Reference<css::task::XStatusIndicator> xStatusIndicator, bool bSkipImages, const css::uno::Sequence<css::beans::PropertyValue>& rDescriptor);
+ virtual ~OOXMLDocumentImpl() override;
+
+ virtual void resolve(Stream & rStream) override;
+
+ virtual void resolveFootnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId) override;
+ virtual void resolveEndnote(Stream & rStream,
+ Id aType,
+ const sal_Int32 nNoteId) override;
+ virtual void resolveHeader(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) override;
+ virtual void resolveFooter(Stream & rStream,
+ const sal_Int32 type,
+ const OUString & rId) override;
+
+ virtual void resolveComment(Stream & rStream, const sal_Int32 nId) override;
+
+ OOXMLPropertySet * getPicturePropSet(const OUString & rId);
+ virtual void resolvePicture(Stream & rStream, const OUString & rId) override;
+
+ virtual OUString getTargetForId(const OUString & rId) override;
+
+ virtual void setModel(css::uno::Reference<css::frame::XModel> xModel) override;
+ virtual css::uno::Reference<css::frame::XModel> getModel() override;
+ virtual void setDrawPage(css::uno::Reference<css::drawing::XDrawPage> xDrawPage) override;
+ virtual css::uno::Reference<css::drawing::XDrawPage> getDrawPage() override;
+ virtual css::uno::Reference<css::io::XInputStream> getInputStreamForId(const OUString & rId) override;
+ virtual void setXNoteId(const sal_Int32 nId) override;
+ virtual sal_Int32 getXNoteId() const override;
+ virtual const OUString & getTarget() const override;
+ virtual rtl::Reference<oox::shape::ShapeContextHandler> getShapeContext( ) override;
+ virtual void setShapeContext(const rtl::Reference<oox::shape::ShapeContextHandler>& xContext) override;
+ virtual const oox::drawingml::ThemePtr & getTheme() const override
+ {
+ return mpTheme;
+ }
+ void pushShapeContext() override;
+ void popShapeContext() override;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getThemeDom() override;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomList() override;
+ virtual css::uno::Sequence<css::uno::Reference<css::xml::dom::XDocument> > getCustomXmlDomPropsList() override;
+ virtual css::uno::Reference<css::xml::dom::XDocument> getGlossaryDocDom() override;
+ virtual css::uno::Sequence<css::uno::Sequence< css::beans::NamedValue> > getGlossaryDomList() override;
+ virtual css::uno::Sequence<css::beans::PropertyValue > getEmbeddingsList() override;
+
+ void incrementProgress();
+ bool IsSkipImages() const { return mbSkipImages; };
+ OUString const& GetDocumentBaseURL() const { return m_rBaseURL; };
+ const css::uno::Sequence<css::beans::PropertyValue>& getMediaDescriptor() const;
+
+ const css::uno::Reference<css::graphic::XGraphicMapper>& getGraphicMapper() const
+ {
+ return mxGraphicMapper;
+ }
+
+ void setTheme(const oox::drawingml::ThemePtr& pTheme) { mpTheme = pTheme; }
+
+ const rtl::Reference<oox::shape::ShapeFilterBase> & getShapeFilterBase();
+ const rtl::Reference<oox::drawingml::ThemeFilterBase> & getThemeFilterBase();
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFactory.cxx b/sw/source/writerfilter/ooxml/OOXMLFactory.cxx
new file mode 100644
index 000000000000..b11cf07c2900
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFactory.cxx
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sax/fastattribs.hxx>
+#include "OOXMLFactory.hxx"
+
+namespace writerfilter::ooxml {
+
+using namespace com::sun::star;
+
+
+OOXMLFactory_ns::~OOXMLFactory_ns()
+{
+}
+
+
+void OOXMLFactory::attributes(OOXMLFastContextHandler * pHandler,
+ const uno::Reference< xml::sax::XFastAttributeList > & xAttribs)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (!pFactory)
+ return;
+
+ sax_fastparser::FastAttributeList& rAttribs =
+ sax_fastparser::castToFastAttributeList( xAttribs );
+
+ const AttributeInfo *pAttr = pFactory->getAttributeInfoArray(nDefine);
+ if (!pAttr)
+ return;
+
+ for (; pAttr->m_nToken != -1; ++pAttr)
+ {
+ sal_Int32 nToken = pAttr->m_nToken;
+ sal_Int32 nAttrIndex = rAttribs.getAttributeIndex(nToken);
+ if (nAttrIndex == -1)
+ continue;
+
+ Id nId = pFactory->getResourceId(nDefine, nToken);
+
+ OOXMLValue::Pointer_t xValue;
+ switch (pAttr->m_nResource)
+ {
+ case ResourceType::Boolean:
+ xValue = OOXMLBooleanValue::Create(rAttribs.getAsViewByIndex(nAttrIndex));
+ break;
+ case ResourceType::String:
+ xValue = new OOXMLStringValue(rAttribs.getValueByIndex(nAttrIndex));
+ break;
+ case ResourceType::Integer:
+ xValue = OOXMLIntegerValue::Create(rAttribs.getAsIntegerByIndex(nAttrIndex));
+ break;
+ case ResourceType::Hex:
+ xValue = new OOXMLHexValue(rAttribs.getAsViewByIndex(nAttrIndex));
+ break;
+ case ResourceType::HexColor:
+ xValue = new OOXMLHexColorValue(rAttribs.getAsViewByIndex(nAttrIndex));
+ break;
+ case ResourceType::TwipsMeasure_asSigned:
+ case ResourceType::TwipsMeasure_asZero:
+ xValue = new OOXMLTwipsMeasureValue(rAttribs.getAsViewByIndex(nAttrIndex));
+ if (xValue->getInt() < 0)
+ {
+ if (pAttr->m_nResource == ResourceType::TwipsMeasure_asZero)
+ xValue = OOXMLIntegerValue::Create(0);
+ }
+ break;
+ case ResourceType::HpsMeasure:
+ xValue = new OOXMLHpsMeasureValue(rAttribs.getAsViewByIndex(nAttrIndex));
+ break;
+ case ResourceType::MeasurementOrPercent:
+ xValue = new OOXMLMeasurementOrPercentValue(rAttribs.getAsViewByIndex(nAttrIndex));
+ break;
+ case ResourceType::List:
+ if (sal_uInt32 nValue;
+ pFactory->getListValue(pAttr->m_nRef, rAttribs.getAsViewByIndex(nAttrIndex), nValue))
+ {
+ xValue = OOXMLIntegerValue::Create(nValue);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (xValue)
+ {
+ pHandler->newProperty(nId, xValue);
+ pFactory->attributeAction(pHandler, nToken, xValue);
+ }
+ }
+}
+
+uno::Reference< xml::sax::XFastContextHandler>
+OOXMLFactory::createFastChildContext(OOXMLFastContextHandler * pHandler,
+ Token_t Element)
+{
+ Id nDefine = pHandler->getDefine();
+
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ uno::Reference< xml::sax::XFastContextHandler> ret;
+
+ //Avoid handling unknown tokens and recursing to death
+ if ((Element & 0xffff) < oox::XML_TOKEN_COUNT)
+ ret = createFastChildContextFromFactory(pHandler, pFactory, Element);
+
+ return ret;
+}
+
+void OOXMLFactory::characters(OOXMLFastContextHandler * pHandler,
+ const OUString & rString)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (pFactory)
+ {
+ pFactory->charactersAction(pHandler, rString);
+ }
+}
+
+void OOXMLFactory::startAction(OOXMLFastContextHandler * pHandler)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (pFactory)
+ {
+ pFactory->startAction(pHandler);
+ }
+}
+
+void OOXMLFactory::endAction(OOXMLFastContextHandler * pHandler)
+{
+ Id nDefine = pHandler->getDefine();
+ OOXMLFactory_ns::Pointer_t pFactory = getFactoryForNamespace(nDefine);
+
+ if (pFactory)
+ {
+ pFactory->endAction(pHandler);
+ }
+}
+
+void OOXMLFactory_ns::startAction(OOXMLFastContextHandler *)
+{
+}
+
+void OOXMLFactory_ns::endAction(OOXMLFastContextHandler *)
+{
+}
+
+void OOXMLFactory_ns::charactersAction(OOXMLFastContextHandler *, const OUString &)
+{
+}
+
+void OOXMLFactory_ns::attributeAction(OOXMLFastContextHandler *, Token_t, const OOXMLValue::Pointer_t&)
+{
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFactory.hxx b/sw/source/writerfilter/ooxml/OOXMLFactory.hxx
new file mode 100644
index 000000000000..146bc5d61631
--- /dev/null
+++ b/sw/source/writerfilter/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 .
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+
+#include "OOXMLFastContextHandler.hxx"
+#include "OOXMLFastContextHandlerTheme.hxx"
+
+namespace writerfilter::ooxml {
+
+enum class ResourceType {
+ NoResource,
+ Table,
+ Stream,
+ List,
+ Integer,
+ Properties,
+ Hex,
+ HexColor,
+ String,
+ Shape,
+ Boolean,
+ Value,
+ XNote,
+ TextTableCell,
+ TextTableRow,
+ TextTable,
+ PropertyTable,
+ Math,
+ Any,
+ TwipsMeasure_asSigned,
+ TwipsMeasure_asZero,
+ HpsMeasure,
+ MeasurementOrPercent,
+ CommentEx,
+ Theme,
+};
+
+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, std::string_view aValue, 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,
+ const OOXMLFactory_ns::Pointer_t& pFactory, Token_t Element);
+};
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
new file mode 100644
index 000000000000..a0881fb9f362
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
@@ -0,0 +1,2384 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <ooxml/resourceids.hxx>
+#include <oox/mathml/imexport.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/shape/ShapeFilterBase.hxx>
+#include <sal/log.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <tools/globname.hxx>
+#include <comphelper/classids.hxx>
+#include <sfx2/sfxbasemodel.hxx>
+#include "OOXMLFastContextHandler.hxx"
+#include "OOXMLFactory.hxx"
+#include "Handler.hxx"
+#include <dmapper/CommentProperties.hxx>
+#include <dmapper/PropertyIds.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include "OOXMLPropertySet.hxx"
+#include <dmapper/GraphicHelpers.hxx>
+
+const sal_Unicode uCR = 0xd;
+const sal_Unicode uFtnEdnRef = 0x2;
+const sal_Unicode uFtnEdnSep = 0x3;
+const sal_Unicode uFtnSep = 0x5;
+const sal_Unicode uTab = 0x9;
+const sal_Unicode uPgNum = 0x0;
+const sal_Unicode uNoBreakHyphen = 0x2011;
+const sal_Unicode uSoftHyphen = 0xAD;
+
+const sal_uInt8 cFtnEdnCont = 0x4;
+
+namespace writerfilter::ooxml
+{
+using namespace ::com::sun::star;
+using namespace oox;
+using namespace ::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),
+ m_inPositionV(false),
+ mbAllowInCell(true),
+ mbIsVMLfound(false),
+ m_xContext(context),
+ m_bDiscardChildren(false),
+ m_bTookChoice(false)
+{
+ if (!mpParserState)
+ mpParserState = new OOXMLParserState();
+
+ mpParserState->incContextCount();
+}
+
+OOXMLFastContextHandler::OOXMLFastContextHandler(OOXMLFastContextHandler * pContext)
+: mpParent(pContext),
+ mId(0),
+ mnDefine(0),
+ mnToken(oox::XML_TOKEN_COUNT),
+ mnMathJcVal(pContext->mnMathJcVal),
+ mbIsMathPara(pContext->mbIsMathPara),
+ mpStream(pContext->mpStream),
+ mpParserState(pContext->mpParserState),
+ mnTableDepth(pContext->mnTableDepth),
+ m_inPositionV(pContext->m_inPositionV),
+ mbAllowInCell(pContext->mbAllowInCell),
+ mbIsVMLfound(pContext->mbIsVMLfound),
+ m_xContext(pContext->m_xContext),
+ m_bDiscardChildren(pContext->m_bDiscardChildren),
+ m_bTookChoice(pContext->m_bTookChoice)
+{
+ if (!mpParserState)
+ mpParserState = new OOXMLParserState();
+
+ mpParserState->incContextCount();
+}
+
+OOXMLFastContextHandler::~OOXMLFastContextHandler()
+{
+}
+
+bool OOXMLFastContextHandler::prepareMceContext(Token_t nElement, const uno::Reference<xml::sax::XFastAttributeList>& rAttribs)
+{
+ switch (oox::getBaseToken(nElement))
+ {
+ case XML_AlternateContent:
+ {
+ SavedAlternateState aState;
+ aState.m_bDiscardChildren = m_bDiscardChildren;
+ m_bDiscardChildren = false;
+ aState.m_bTookChoice = m_bTookChoice;
+ m_bTookChoice = false;
+ mpParserState->getSavedAlternateStates().push_back(aState);
+ }
+ break;
+ case XML_Choice:
+ {
+ OUString aRequires = rAttribs->getOptionalValue(XML_Requires);
+ static const char* aFeatures[] = {
+ "wps",
+ "wpg",
+ "w14",
+ "wpc",
+ };
+ for (const char *p : aFeatures)
+ {
+ if (aRequires.equalsAscii(p))
+ {
+ m_bTookChoice = true;
+ return false;
+ }
+ }
+ return true;
+ }
+ break;
+ case XML_Fallback:
+ // If Choice is already taken, then let's ignore the Fallback.
+ return m_bTookChoice;
+ default:
+ SAL_WARN("writerfilter", "OOXMLFastContextHandler::prepareMceContext: unhandled element:" << oox::getBaseToken(nElement));
+ break;
+ }
+ return false;
+}
+
+// xml::sax::XFastContextHandler:
+void SAL_CALL OOXMLFastContextHandler::startFastElement
+(sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ // Set xml:space value early, to allow child contexts use it when dealing with strings.
+ if (Attribs && Attribs->hasAttribute(oox::NMSP_xml | oox::XML_space))
+ {
+ mbPreserveSpace = Attribs->getValue(oox::NMSP_xml | oox::XML_space) == "preserve";
+ mbPreserveSpaceSet = true;
+ }
+ if (Element == W_TOKEN(footnote) || Element == W_TOKEN(endnote))
+ {
+ // send uFtnSep to sign new footnote content, but skip footnote separators
+ if (!Attribs->hasAttribute(W_TOKEN(type)) ||
+ ( Attribs->getValue(W_TOKEN(type)) != "separator" &&
+ Attribs->getValue(W_TOKEN(type)) != "continuationSeparator" &&
+ Attribs->getValue(W_TOKEN(type)) != "continuationNotice" ))
+ {
+ mpParserState->setStartFootnote(true);
+ }
+ }
+ else if (Element == (NMSP_officeMath | XML_oMathPara))
+ {
+ mnMathJcVal = eMathParaJc::CENTER;
+ mbIsMathPara = true;
+ }
+ else if (Element == (NMSP_officeMath | XML_jc) && mpParent && mpParent->mpParent )
+ {
+ mbIsMathPara = true;
+ auto aAttrLst = Attribs->getFastAttributes();
+ if (aAttrLst[0].Value == "center") mpParent->mpParent->mnMathJcVal = eMathParaJc::CENTER;
+ if (aAttrLst[0].Value == "left") mpParent->mpParent->mnMathJcVal = eMathParaJc::LEFT;
+ if (aAttrLst[0].Value == "right") mpParent->mpParent->mnMathJcVal = eMathParaJc::RIGHT;
+ }
+
+ if (oox::getNamespace(Element) == NMSP_mce)
+ m_bDiscardChildren = prepareMceContext(Element, Attribs);
+
+ else if (!m_bDiscardChildren)
+ {
+ attributes(Attribs);
+ lcl_startFastElement(Element, Attribs);
+ }
+}
+
+void SAL_CALL OOXMLFastContextHandler::startUnknownElement
+(const OUString & /*Namespace*/, const OUString & /*Name*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+}
+
+void SAL_CALL OOXMLFastContextHandler::endFastElement(sal_Int32 Element)
+{
+ if (Element == (NMSP_mce | XML_Choice) || Element == (NMSP_mce | XML_Fallback))
+ m_bDiscardChildren = false;
+ else if (Element == (NMSP_mce | XML_AlternateContent))
+ {
+ SavedAlternateState aState(mpParserState->getSavedAlternateStates().back());
+ mpParserState->getSavedAlternateStates().pop_back();
+ m_bDiscardChildren = aState.m_bDiscardChildren;
+ m_bTookChoice = aState.m_bTookChoice;
+ }
+ else if (!m_bDiscardChildren)
+ lcl_endFastElement(Element);
+}
+
+void OOXMLFastContextHandler::lcl_startFastElement
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ OOXMLFactory::startAction(this);
+ if( Element == (NMSP_dmlWordDr|XML_positionV) )
+ m_inPositionV = true;
+ else if( Element == (NMSP_dmlWordDr|XML_positionH) )
+ m_inPositionV = false;
+}
+
+void OOXMLFastContextHandler::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ OOXMLFactory::endAction(this);
+}
+
+void SAL_CALL OOXMLFastContextHandler::endUnknownElement
+(const OUString & , const OUString & )
+{
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+ OOXMLFastContextHandler::createFastChildContext
+(sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+ if (oox::getNamespace(Element) != NMSP_mce && !m_bDiscardChildren)
+ xResult.set(lcl_createFastChildContext(Element, Attribs));
+ else if (oox::getNamespace(Element) == NMSP_mce)
+ xResult = this;
+
+ return xResult;
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+ OOXMLFastContextHandler::lcl_createFastChildContext
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ return OOXMLFactory::createFastChildContext(this, Element);
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandler::createUnknownChildContext
+(const OUString &,
+ const OUString &,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ return uno::Reference< xml::sax::XFastContextHandler >
+ (new OOXMLFastContextHandler(*const_cast<const OOXMLFastContextHandler *>(this)));
+}
+
+void SAL_CALL OOXMLFastContextHandler::characters
+(const OUString & aChars)
+{
+ lcl_characters(aChars);
+}
+
+void OOXMLFastContextHandler::lcl_characters
+(const OUString & rString)
+{
+ if (!m_bDiscardChildren)
+ OOXMLFactory::characters(this, rString);
+}
+
+void OOXMLFastContextHandler::setStream(Stream * pStream)
+{
+ mpStream = pStream;
+}
+
+OOXMLValue::Pointer_t OOXMLFastContextHandler::getValue() const
+{
+ return OOXMLValue::Pointer_t();
+}
+
+void OOXMLFastContextHandler::attributes
+(const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ OOXMLFactory::attributes(this, Attribs);
+}
+
+void OOXMLFastContextHandler::startAction()
+{
+ OOXMLFactory::startAction(this);
+}
+
+void OOXMLFastContextHandler::endAction()
+{
+ OOXMLFactory::endAction(this);
+}
+
+void OOXMLFastContextHandler::setId(Id rId)
+{
+ mId = rId;
+}
+
+Id OOXMLFastContextHandler::getId() const
+{
+ return mId;
+}
+
+void OOXMLFastContextHandler::setDefine(Id nDefine)
+{
+ mnDefine = nDefine;
+}
+
+
+void OOXMLFastContextHandler::setToken(Token_t nToken)
+{
+ mnToken = nToken;
+}
+
+Token_t OOXMLFastContextHandler::getToken() const
+{
+ return mnToken;
+}
+
+void OOXMLFastContextHandler::sendTableDepth() const
+{
+ if (mnTableDepth <= 0)
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::setHandle()
+{
+ mpParserState->setHandle();
+ mpStream->info(mpParserState->getHandle());
+}
+
+void OOXMLFastContextHandler::startCharacterGroup()
+{
+ if (!isForwardEvents())
+ return;
+
+ if (mpParserState->isInCharacterGroup())
+ endCharacterGroup();
+
+ if (! mpParserState->isInParagraphGroup())
+ startParagraphGroup();
+
+ if (! mpParserState->isInCharacterGroup())
+ {
+ mpStream->startCharacterGroup();
+ mpParserState->setInCharacterGroup(true);
+ mpParserState->resolveCharacterProperties(*mpStream);
+ if (mpParserState->isStartFootnote())
+ {
+ mpStream->utext(&uFtnSep, 1);
+ mpParserState->setStartFootnote(false);
+ }
+ }
+
+ // tdf#108714 : if we have a postponed break information,
+ // then apply it now, before any other paragraph content.
+ mpParserState->resolvePostponedBreak(*mpStream);
+}
+
+void OOXMLFastContextHandler::endCharacterGroup()
+{
+ if (isForwardEvents() && mpParserState->isInCharacterGroup())
+ {
+ mpStream->endCharacterGroup();
+ mpParserState->setInCharacterGroup(false);
+ }
+}
+
+void OOXMLFastContextHandler::pushBiDiEmbedLevel() {}
+
+void OOXMLFastContextHandler::popBiDiEmbedLevel() {}
+
+void OOXMLFastContextHandler::startParagraphGroup()
+{
+ if (!isForwardEvents())
+ return;
+
+ if (mpParserState->GetFloatingTableEnded())
+ {
+ mpParserState->SetFloatingTableEnded(false);
+ }
+
+ if (mpParserState->isInParagraphGroup())
+ endParagraphGroup();
+
+ if (! mpParserState->isInSectionGroup())
+ startSectionGroup();
+
+ if ( mpParserState->isInParagraphGroup())
+ return;
+
+ mpStream->startParagraphGroup();
+ mpParserState->setInParagraphGroup(true);
+
+ if (const auto& pPropSet = getPropertySet())
+ {
+ OOXMLPropertySetEntryToString aHandler(NS_ooxml::LN_AG_Parids_paraId);
+ pPropSet->resolve(aHandler);
+ if (const OUString& sText = aHandler.getString(); !sText.isEmpty())
+ {
+ OOXMLStringValue::Pointer_t pVal = new OOXMLStringValue(sText);
+ OOXMLPropertySet::Pointer_t pPropertySet(new OOXMLPropertySet);
+ pPropertySet->add(NS_ooxml::LN_AG_Parids_paraId, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pPropertySet.get());
+ }
+ }
+}
+
+void OOXMLFastContextHandler::endParagraphGroup()
+{
+ if (isForwardEvents())
+ {
+ if (mpParserState->isInCharacterGroup())
+ endCharacterGroup();
+
+ if (mpParserState->isInParagraphGroup())
+ {
+ mpStream->endParagraphGroup();
+ mpParserState->setInParagraphGroup(false);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::startSdt()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtBlock_sdtContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::endSdt()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtBlock_sdtEndContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::startSdtRun()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtRun_sdtContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::endSdtRun()
+{
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_CT_SdtRun_sdtEndContent, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props(pProps.get());
+}
+
+void OOXMLFastContextHandler::startSectionGroup()
+{
+ if (isForwardEvents())
+ {
+ if (mpParserState->isInSectionGroup())
+ endSectionGroup();
+
+ if (! mpParserState->isInSectionGroup())
+ {
+ mpStream->info(mpParserState->getHandle());
+ mpStream->startSectionGroup();
+ mpParserState->setInSectionGroup(true);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::endSectionGroup()
+{
+ if (isForwardEvents())
+ {
+ if (mpParserState->isInParagraphGroup())
+ endParagraphGroup();
+
+ if (mpParserState->isInSectionGroup())
+ {
+ mpStream->endSectionGroup();
+ mpParserState->setInSectionGroup(false);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::setLastParagraphInSection()
+{
+ mpParserState->setLastParagraphInSection(true);
+ mpStream->markLastParagraphInSection( );
+}
+
+void OOXMLFastContextHandler::setLastSectionGroup()
+{
+ mpStream->markLastSectionGroup( );
+}
+
+void OOXMLFastContextHandler::newProperty
+(Id /*nId*/, const OOXMLValue::Pointer_t& /*pVal*/)
+{
+}
+
+void OOXMLFastContextHandler::setPropertySet
+(const OOXMLPropertySet::Pointer_t& /* pPropertySet */)
+{
+}
+
+OOXMLPropertySet::Pointer_t OOXMLFastContextHandler::getPropertySet() const
+{
+ return OOXMLPropertySet::Pointer_t();
+}
+
+void OOXMLFastContextHandler::startField()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldStart, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::fieldSeparator()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldSep, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::endField()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldEnd, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::lockField()
+{
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->text(&cFieldLock, 1);
+ endCharacterGroup();
+}
+
+void OOXMLFastContextHandler::ftnednref()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uFtnEdnRef, 1);
+}
+
+void OOXMLFastContextHandler::ftnednsep()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uFtnEdnSep, 1);
+}
+
+void OOXMLFastContextHandler::ftnedncont()
+{
+ if (isForwardEvents())
+ mpStream->text(&cFtnEdnCont, 1);
+}
+
+void OOXMLFastContextHandler::pgNum()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uPgNum, 1);
+}
+
+void OOXMLFastContextHandler::tab()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uTab, 1);
+}
+
+void OOXMLFastContextHandler::symbol()
+{
+ if (isForwardEvents())
+ sendPropertiesWithId(NS_ooxml::LN_EG_RunInnerContent_sym);
+}
+
+void OOXMLFastContextHandler::cr()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uCR, 1);
+}
+
+void OOXMLFastContextHandler::noBreakHyphen()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uNoBreakHyphen, 1);
+}
+
+void OOXMLFastContextHandler::softHyphen()
+{
+ if (isForwardEvents())
+ mpStream->utext(&uSoftHyphen, 1);
+}
+
+void OOXMLFastContextHandler::handleLastParagraphInSection()
+{
+ if (mpParserState->isLastParagraphInSection())
+ {
+ mpParserState->setLastParagraphInSection(false);
+ startSectionGroup();
+ }
+}
+
+void OOXMLFastContextHandler::endOfParagraph()
+{
+ if (! mpParserState->isInCharacterGroup())
+ startCharacterGroup();
+ if (isForwardEvents())
+ mpStream->utext(&uCR, 1);
+
+ mpParserState->getDocument()->incrementProgress();
+}
+
+void OOXMLFastContextHandler::startTxbxContent()
+{
+/*
+ This usually means there are recursive <w:p> elements, and the ones
+ inside and outside of w:txbxContent should not interfere (e.g.
+ the lastParagraphInSection setting). So save the whole state
+ and possibly start new groups for the nested content (not section
+ group though, as that'd cause the txbxContent to be moved onto
+ another page, I'm not sure how that should work exactly).
+*/
+ mpParserState->startTxbxContent();
+ startParagraphGroup();
+}
+
+void OOXMLFastContextHandler::endTxbxContent()
+{
+ endParagraphGroup();
+ mpParserState->endTxbxContent();
+}
+
+namespace {
+// XML schema defines white space as one of four characters:
+// #x9 (tab), #xA (line feed), #xD (carriage return), and #x20 (space)
+bool IsXMLWhitespace(sal_Unicode cChar)
+{
+ return cChar == 0x9 || cChar == 0xA || cChar == 0xD || cChar == 0x20;
+}
+
+OUString TrimXMLWhitespace(const OUString & sText)
+{
+ sal_Int32 nTrimmedStart = 0;
+ const sal_Int32 nLen = sText.getLength();
+ sal_Int32 nTrimmedEnd = nLen - 1;
+ while (nTrimmedStart < nLen && IsXMLWhitespace(sText[nTrimmedStart]))
+ ++nTrimmedStart;
+ while (nTrimmedStart <= nTrimmedEnd && IsXMLWhitespace(sText[nTrimmedEnd]))
+ --nTrimmedEnd;
+ if ((nTrimmedStart == 0) && (nTrimmedEnd == nLen - 1))
+ return sText;
+ else if (nTrimmedStart > nTrimmedEnd)
+ return OUString();
+ else
+ return sText.copy(nTrimmedStart, nTrimmedEnd-nTrimmedStart+1);
+}
+}
+
+void OOXMLFastContextHandler::text(const OUString & sText)
+{
+ if (!isForwardEvents())
+ return;
+
+ // tdf#108806: CRLFs in XML were converted to \n before this point.
+ // These must be converted to spaces before further processing.
+ OUString sNormalizedText = sText.replaceAll("\n", " ");
+ // tdf#108995: by default, leading and trailing white space is ignored;
+ // tabs are converted to spaces
+ if (!IsPreserveSpace())
+ {
+ sNormalizedText = TrimXMLWhitespace(sNormalizedText).replaceAll("\t", " ");
+ }
+ mpStream->utext(sNormalizedText.getStr(), sNormalizedText.getLength());
+}
+
+void OOXMLFastContextHandler::positionOffset(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->positionOffset(rText, m_inPositionV);
+}
+
+void OOXMLFastContextHandler::ignore()
+{
+}
+
+void OOXMLFastContextHandler::alignH(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->align(rText, /*bVertical=*/false);
+}
+
+void OOXMLFastContextHandler::alignV(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->align(rText, /*bVertical=*/true);
+}
+
+void OOXMLFastContextHandler::positivePercentage(const OUString& rText)
+{
+ if (isForwardEvents())
+ mpStream->positivePercentage(rText);
+}
+
+void OOXMLFastContextHandler::startGlossaryEntry()
+{
+ if (isForwardEvents())
+ mpStream->startGlossaryEntry();
+}
+
+void OOXMLFastContextHandler::endGlossaryEntry()
+{
+ if (isForwardEvents())
+ mpStream->endGlossaryEntry();
+}
+
+void OOXMLFastContextHandler::propagateCharacterProperties()
+{
+ mpParserState->setCharacterProperties(getPropertySet());
+}
+
+void OOXMLFastContextHandler::propagateCellProperties()
+{
+ mpParserState->setCellProperties(getPropertySet());
+}
+
+void OOXMLFastContextHandler::propagateRowProperties()
+{
+ mpParserState->setRowProperties(getPropertySet());
+}
+
+void OOXMLFastContextHandler::propagateTableProperties()
+{
+ OOXMLPropertySet::Pointer_t pProps = getPropertySet();
+
+ mpParserState->setTableProperties(pProps);
+}
+
+void OOXMLFastContextHandler::sendCellProperties()
+{
+ mpParserState->resolveCellProperties(*mpStream);
+}
+
+void OOXMLFastContextHandler::sendRowProperties()
+{
+ mpParserState->resolveRowProperties(*mpStream);
+}
+
+void OOXMLFastContextHandler::sendTableProperties()
+{
+ mpParserState->resolveTableProperties(*mpStream);
+}
+
+void OOXMLFastContextHandler::clearTableProps()
+{
+ mpParserState->setTableProperties(new OOXMLPropertySet());
+}
+
+void OOXMLFastContextHandler::sendPropertiesWithId(Id nId)
+{
+ OOXMLValue::Pointer_t pValue(new OOXMLPropertySetValue(getPropertySet()));
+ OOXMLPropertySet::Pointer_t pPropertySet(new OOXMLPropertySet);
+
+ pPropertySet->add(nId, pValue, OOXMLProperty::SPRM);
+ mpStream->props(pPropertySet.get());
+}
+
+void OOXMLFastContextHandler::clearProps()
+{
+ setPropertySet(new OOXMLPropertySet());
+}
+
+void OOXMLFastContextHandler::setDefaultBooleanValue()
+{
+}
+
+void OOXMLFastContextHandler::setDefaultIntegerValue()
+{
+}
+
+void OOXMLFastContextHandler::setDefaultHexValue()
+{
+}
+
+void OOXMLFastContextHandler::setDefaultStringValue()
+{
+}
+
+void OOXMLFastContextHandler::setDocument(OOXMLDocumentImpl* pDocument)
+{
+ mpParserState->setDocument(pDocument);
+}
+
+OOXMLDocumentImpl* OOXMLFastContextHandler::getDocument()
+{
+ return mpParserState->getDocument();
+}
+
+void OOXMLFastContextHandler::setForwardEvents(bool bForwardEvents)
+{
+ mpParserState->setForwardEvents(bForwardEvents);
+}
+
+bool OOXMLFastContextHandler::isForwardEvents() const
+{
+ return mpParserState->isForwardEvents();
+}
+
+void OOXMLFastContextHandler::setXNoteId(const sal_Int32 nId)
+{
+ mpParserState->setXNoteId(nId);
+}
+
+void OOXMLFastContextHandler::setXNoteId(const OOXMLValue::Pointer_t& pValue)
+{
+ mpParserState->setXNoteId(sal_Int32(pValue->getInt()));
+}
+
+sal_Int32 OOXMLFastContextHandler::getXNoteId() const
+{
+ return mpParserState->getXNoteId();
+}
+
+void OOXMLFastContextHandler::resolveFootnote
+(const sal_Int32 nId)
+{
+ mpParserState->getDocument()->resolveFootnote
+ (*mpStream, 0, nId);
+}
+
+void OOXMLFastContextHandler::resolveEndnote(const sal_Int32 nId)
+{
+ mpParserState->getDocument()->resolveEndnote
+ (*mpStream, 0, nId);
+}
+
+void OOXMLFastContextHandler::resolveComment(const sal_Int32 nId)
+{
+ mpParserState->getDocument()->resolveComment(*mpStream, nId);
+}
+
+void OOXMLFastContextHandler::resolvePicture(const OUString & rId)
+{
+ mpParserState->getDocument()->resolvePicture(*mpStream, rId);
+}
+
+void OOXMLFastContextHandler::resolveHeader
+(const sal_Int32 type, const OUString & rId)
+{
+ mpParserState->getDocument()->resolveHeader(*mpStream, type, rId);
+}
+
+void OOXMLFastContextHandler::resolveFooter
+(const sal_Int32 type, const OUString & rId)
+{
+ mpParserState->getDocument()->resolveFooter(*mpStream, type, rId);
+}
+
+// Add the data pointed to by the reference as another property.
+void OOXMLFastContextHandler::resolveData(const OUString & rId)
+{
+ OOXMLDocument * objDocument = getDocument();
+ SAL_WARN_IF(!objDocument, "writerfilter", "no document to resolveData");
+ if (!objDocument)
+ return;
+
+ uno::Reference<io::XInputStream> xInputStream
+ (objDocument->getInputStreamForId(rId));
+
+ OOXMLValue::Pointer_t aValue(new OOXMLInputStreamValue(xInputStream));
+
+ newProperty(NS_ooxml::LN_inputstream, aValue);
+}
+
+OUString OOXMLFastContextHandler::getTargetForId
+(const OUString & rId)
+{
+ return mpParserState->getDocument()->getTargetForId(rId);
+}
+
+void OOXMLFastContextHandler::sendPropertyToParent()
+{
+ if (mpParent != nullptr)
+ {
+ OOXMLPropertySet::Pointer_t pProps(mpParent->getPropertySet());
+
+ if (pProps)
+ {
+ pProps->add(mId, getValue(), OOXMLProperty::SPRM);
+ }
+ }
+}
+
+void OOXMLFastContextHandler::sendPropertiesToParent()
+{
+ if (mpParent == nullptr)
+ return;
+
+ OOXMLPropertySet::Pointer_t pParentProps(mpParent->getPropertySet());
+
+ if (!pParentProps)
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(getPropertySet());
+
+ if (pProps)
+ {
+ OOXMLValue::Pointer_t pValue
+ (new OOXMLPropertySetValue(getPropertySet()));
+
+ pParentProps->add(getId(), pValue, OOXMLProperty::SPRM);
+
+ }
+}
+
+bool OOXMLFastContextHandler::IsPreserveSpace() const
+{
+ // xml:space attribute applies to all elements within the content of the element where it is specified,
+ // unless overridden with another instance of the xml:space attribute
+ if (mbPreserveSpaceSet)
+ return mbPreserveSpace;
+ if (mpParent)
+ return mpParent->IsPreserveSpace();
+ return false; // default value
+}
+
+/*
+ class OOXMLFastContextHandlerStream
+ */
+
+OOXMLFastContextHandlerStream::OOXMLFastContextHandlerStream
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext),
+ mpPropertySetAttrs(new OOXMLPropertySet)
+{
+}
+
+OOXMLFastContextHandlerStream::~OOXMLFastContextHandlerStream()
+{
+}
+
+void OOXMLFastContextHandlerStream::newProperty(Id nId,
+ const OOXMLValue::Pointer_t& pVal)
+{
+ if (nId != 0x0)
+ {
+ mpPropertySetAttrs->add(nId, pVal, OOXMLProperty::ATTRIBUTE);
+ }
+}
+
+void OOXMLFastContextHandlerStream::sendProperty(Id nId)
+{
+ OOXMLPropertySetEntryToString aHandler(nId);
+ getPropertySetAttrs()->resolve(aHandler);
+ const OUString & sText = aHandler.getString();
+ mpStream->utext(sText.getStr(), sText.getLength());
+}
+
+
+OOXMLPropertySet::Pointer_t OOXMLFastContextHandlerStream::getPropertySet()
+ const
+{
+ return getPropertySetAttrs();
+}
+
+void OOXMLFastContextHandlerStream::handleHyperlink()
+{
+ OOXMLHyperlinkHandler aHyperlinkHandler(this);
+ getPropertySetAttrs()->resolve(aHyperlinkHandler);
+ aHyperlinkHandler.writetext();
+}
+
+/*
+ class OOXMLFastContextHandlerProperties
+ */
+OOXMLFastContextHandlerProperties::OOXMLFastContextHandlerProperties
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext), mpPropertySet(new OOXMLPropertySet),
+ mbResolve(false)
+{
+ if (pContext->getResource() == STREAM)
+ mbResolve = true;
+}
+
+OOXMLFastContextHandlerProperties::~OOXMLFastContextHandlerProperties()
+{
+}
+
+void OOXMLFastContextHandlerProperties::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ try
+ {
+ endAction();
+
+ if (mbResolve)
+ {
+ if (isForwardEvents())
+ {
+ mpStream->props(mpPropertySet.get());
+ }
+ }
+ else
+ {
+ sendPropertiesToParent();
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const xml::sax::SAXException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception& e)
+ {
+ auto a = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(e.Message, e.Context, a);
+ }
+}
+
+OOXMLValue::Pointer_t OOXMLFastContextHandlerProperties::getValue() const
+{
+ return OOXMLValue::Pointer_t(new OOXMLPropertySetValue(mpPropertySet));
+}
+
+void OOXMLFastContextHandlerProperties::newProperty
+(Id nId, const OOXMLValue::Pointer_t& pVal)
+{
+ if (nId != 0x0)
+ {
+ mpPropertySet->add(nId, pVal, OOXMLProperty::ATTRIBUTE);
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleXNotes()
+{
+ switch (mnToken)
+ {
+ case W_TOKEN(footnoteReference):
+ {
+ OOXMLFootnoteHandler aFootnoteHandler(this);
+ mpPropertySet->resolve(aFootnoteHandler);
+ }
+ break;
+ case W_TOKEN(endnoteReference):
+ {
+ OOXMLEndnoteHandler aEndnoteHandler(this);
+ mpPropertySet->resolve(aEndnoteHandler);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleHdrFtr()
+{
+ switch (mnToken)
+ {
+ case W_TOKEN(footerReference):
+ {
+ OOXMLFooterHandler aFooterHandler(this);
+ mpPropertySet->resolve(aFooterHandler);
+ aFooterHandler.finalize();
+ }
+ break;
+ case W_TOKEN(headerReference):
+ {
+ OOXMLHeaderHandler aHeaderHandler(this);
+ mpPropertySet->resolve(aHeaderHandler);
+ aHeaderHandler.finalize();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleComment()
+{
+ OOXMLCommentHandler aCommentHandler(this);
+ getPropertySet()->resolve(aCommentHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handlePicture()
+{
+ OOXMLPictureHandler aPictureHandler(this);
+ getPropertySet()->resolve(aPictureHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handleBreak()
+{
+ if(isForwardEvents())
+ {
+ OOXMLBreakHandler aBreakHandler(this, *mpStream);
+ getPropertySet()->resolve(aBreakHandler);
+ }
+}
+
+// tdf#108714 : allow <w:br> at block level (despite this is illegal according to ECMA-376-1:2016)
+void OOXMLFastContextHandlerProperties::handleOutOfOrderBreak()
+{
+ if(isForwardEvents())
+ {
+ mpParserState->setPostponedBreak(getPropertySet());
+ }
+}
+
+void OOXMLFastContextHandlerProperties::handleOLE()
+{
+ OOXMLOLEHandler aOLEHandler(this);
+ getPropertySet()->resolve(aOLEHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handleFontRel()
+{
+ OOXMLEmbeddedFontHandler handler(this);
+ getPropertySet()->resolve(handler);
+}
+
+void OOXMLFastContextHandlerProperties::handleHyperlinkURL() {
+ OOXMLHyperlinkURLHandler aHyperlinkURLHandler(this);
+ getPropertySet()->resolve(aHyperlinkURLHandler);
+}
+
+void OOXMLFastContextHandlerProperties::handleAltChunk()
+{
+ OOXMLAltChunkHandler aHandler(this);
+ getPropertySet()->resolve(aHandler);
+}
+
+void OOXMLFastContextHandlerProperties::setPropertySet
+(const OOXMLPropertySet::Pointer_t& pPropertySet)
+{
+ if (pPropertySet)
+ mpPropertySet = pPropertySet;
+}
+
+OOXMLPropertySet::Pointer_t
+OOXMLFastContextHandlerProperties::getPropertySet() const
+{
+ return mpPropertySet;
+}
+
+/*
+ * class OOXMLFasContextHandlerPropertyTable
+ */
+
+OOXMLFastContextHandlerPropertyTable::OOXMLFastContextHandlerPropertyTable
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandlerProperties(pContext)
+{
+}
+
+OOXMLFastContextHandlerPropertyTable::~OOXMLFastContextHandlerPropertyTable()
+{
+}
+
+void OOXMLFastContextHandlerPropertyTable::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ OOXMLTable::ValuePointer_t pTmpVal
+ (new OOXMLPropertySetValue(mpPropertySet->clone()));
+
+ mTable.add(pTmpVal);
+
+ writerfilter::Reference<Table>::Pointer_t pTable(mTable.clone());
+
+ mpStream->table(mId, pTable);
+
+ endAction();
+}
+
+/*
+ class OOXMLFastContextHandlerValue
+*/
+
+OOXMLFastContextHandlerValue::OOXMLFastContextHandlerValue
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerValue::~OOXMLFastContextHandlerValue()
+{
+}
+
+void OOXMLFastContextHandlerValue::setValue(const OOXMLValue::Pointer_t& pValue)
+{
+ mpValue = pValue;
+}
+
+OOXMLValue::Pointer_t OOXMLFastContextHandlerValue::getValue() const
+{
+ return mpValue;
+}
+
+void OOXMLFastContextHandlerValue::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ sendPropertyToParent();
+
+ endAction();
+}
+
+void OOXMLFastContextHandlerValue::setDefaultBooleanValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue = OOXMLBooleanValue::Create(true);
+ setValue(pValue);
+ }
+}
+
+void OOXMLFastContextHandlerValue::setDefaultIntegerValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue = OOXMLIntegerValue::Create(0);
+ setValue(pValue);
+ }
+}
+
+void OOXMLFastContextHandlerValue::setDefaultHexValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue(new OOXMLHexValue(sal_uInt32(0)));
+ setValue(pValue);
+ }
+}
+
+void OOXMLFastContextHandlerValue::setDefaultStringValue()
+{
+ if (!mpValue)
+ {
+ OOXMLValue::Pointer_t pValue(new OOXMLStringValue(OUString()));
+ setValue(pValue);
+ }
+}
+
+// ECMA-376-1:2016 17.3.2.8; https://www.unicode.org/reports/tr9/#Explicit_Directional_Embeddings
+void OOXMLFastContextHandlerValue::pushBiDiEmbedLevel()
+{
+ const bool bRtl
+ = mpValue && mpValue->getInt() == NS_ooxml::LN_Value_ST_Direction_rtl;
+ OOXMLFactory::characters(this, bRtl ? u"\u202B"_ustr : u"\u202A"_ustr); // RLE / LRE
+}
+
+void OOXMLFastContextHandlerValue::popBiDiEmbedLevel()
+{
+ OOXMLFactory::characters(this, u"\u202C"_ustr); // PDF (POP DIRECTIONAL FORMATTING)
+}
+
+void OOXMLFastContextHandlerValue::handleGridAfter()
+{
+ if (!getValue())
+ return;
+
+ if (OOXMLFastContextHandler* pTableRowProperties = getParent())
+ {
+ if (OOXMLFastContextHandler* pTableRow = pTableRowProperties->getParent())
+ // Save the value into the table row context, so it can be handled
+ // right before the end of the row.
+ pTableRow->setGridAfter(getValue());
+ }
+}
+
+/*
+ class OOXMLFastContextHandlerTable
+*/
+
+OOXMLFastContextHandlerTable::OOXMLFastContextHandlerTable
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTable::~OOXMLFastContextHandlerTable()
+{
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandlerTable::createFastChildContext
+(sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ addCurrentChild();
+
+ mCurrentChild.set(OOXMLFastContextHandler::createFastChildContext(Element, Attribs));
+
+ return mCurrentChild;
+}
+
+void OOXMLFastContextHandlerTable::lcl_endFastElement
+(Token_t /*Element*/)
+{
+ addCurrentChild();
+
+ writerfilter::Reference<Table>::Pointer_t pTable(mTable.clone());
+ if (isForwardEvents() && mId != 0x0)
+ {
+ mpStream->table(mId, pTable);
+ }
+}
+
+void OOXMLFastContextHandlerTable::addCurrentChild()
+{
+ OOXMLFastContextHandler * pHandler = dynamic_cast<OOXMLFastContextHandler*>(mCurrentChild.get());
+ if (pHandler != nullptr)
+ {
+ OOXMLValue::Pointer_t pValue(pHandler->getValue());
+
+ if (pValue)
+ {
+ OOXMLTable::ValuePointer_t pTmpVal(pValue->clone());
+ mTable.add(pTmpVal);
+ }
+ }
+}
+
+/*
+ class OOXMLFastContextHandlerXNote
+ */
+
+OOXMLFastContextHandlerXNote::OOXMLFastContextHandlerXNote
+ (OOXMLFastContextHandler * pContext)
+ : OOXMLFastContextHandlerProperties(pContext)
+ , mbForwardEventsSaved(false)
+ , mnMyXNoteId(0)
+ , mnMyXNoteType(0)
+{
+}
+
+OOXMLFastContextHandlerXNote::~OOXMLFastContextHandlerXNote()
+{
+}
+
+void OOXMLFastContextHandlerXNote::lcl_startFastElement
+(Token_t /*Element*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ mbForwardEventsSaved = isForwardEvents();
+
+ // If this is the note we're looking for or this is the footnote separator one.
+ if (mnMyXNoteId == getXNoteId() ||
+ static_cast<sal_uInt32>(mnMyXNoteType) == NS_ooxml::LN_Value_doc_ST_FtnEdn_separator ||
+ mpParserState->isStartFootnote())
+ setForwardEvents(true);
+ else
+ setForwardEvents(false);
+
+ startAction();
+}
+
+void OOXMLFastContextHandlerXNote::lcl_endFastElement
+(Token_t Element)
+{
+ endAction();
+
+ OOXMLFastContextHandlerProperties::lcl_endFastElement(Element);
+
+ setForwardEvents(mbForwardEventsSaved);
+}
+
+void OOXMLFastContextHandlerXNote::checkId(const OOXMLValue::Pointer_t& pValue)
+{
+ mnMyXNoteId = sal_Int32(pValue->getInt());
+ mpStream->checkId(mnMyXNoteId);
+}
+
+void OOXMLFastContextHandlerXNote::checkType(const OOXMLValue::Pointer_t& pValue)
+{
+ mnMyXNoteType = pValue->getInt();
+}
+
+/*
+ class OOXMLFastContextHandlerTextTableCell
+ */
+
+OOXMLFastContextHandlerTextTableCell::OOXMLFastContextHandlerTextTableCell
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTextTableCell::~OOXMLFastContextHandlerTextTableCell()
+{
+}
+
+void OOXMLFastContextHandlerTextTableCell::startCell()
+{
+ if (isForwardEvents())
+ {
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tcStart, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+ }
+}
+
+void OOXMLFastContextHandlerTextTableCell::endCell()
+{
+ if (!isForwardEvents())
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tblCell, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tcEnd, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+}
+
+/*
+ class OOXMLFastContextHandlerTextTableRow
+ */
+
+OOXMLFastContextHandlerTextTableRow::OOXMLFastContextHandlerTextTableRow
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTextTableRow::~OOXMLFastContextHandlerTextTableRow()
+{
+}
+
+void OOXMLFastContextHandlerTextTableRow::startRow()
+{
+}
+
+void OOXMLFastContextHandlerTextTableRow::endRow()
+{
+ if (mpGridAfter)
+ {
+ // Grid after is the same as grid before, the empty cells are just
+ // inserted after the real ones, not before.
+ handleGridBefore(mpGridAfter);
+ mpGridAfter = nullptr;
+ }
+
+ startParagraphGroup();
+
+ if (isForwardEvents())
+ {
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_tblRow, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+ }
+
+ startCharacterGroup();
+
+ if (isForwardEvents())
+ mpStream->utext(&uCR, 1);
+
+ endCharacterGroup();
+ endParagraphGroup();
+}
+
+namespace {
+OOXMLValue::Pointer_t fakeNoBorder()
+{
+ OOXMLPropertySet::Pointer_t pProps( new OOXMLPropertySet );
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(0);
+ pProps->add(NS_ooxml::LN_CT_Border_val, pVal, OOXMLProperty::ATTRIBUTE);
+ OOXMLValue::Pointer_t pValue( new OOXMLPropertySetValue( pProps ));
+ return pValue;
+}
+}
+
+// Handle w:gridBefore here by faking necessary input that'll fake cells. I'm apparently
+// not insane enough to find out how to add cells in dmapper.
+void OOXMLFastContextHandlerTextTableRow::handleGridBefore( const OOXMLValue::Pointer_t& val )
+{
+ // start removing: disable for w:gridBefore
+ if (!mpGridAfter)
+ return;
+
+ int count = val->getInt();
+ for( int i = 0;
+ i < count;
+ ++i )
+ {
+ endOfParagraph();
+
+ if (isForwardEvents())
+ {
+ // This whole part is OOXMLFastContextHandlerTextTableCell::endCell() .
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(mnTableDepth);
+ pProps->add(NS_ooxml::LN_tblDepth, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLIntegerValue::Create(1);
+ pProps->add(NS_ooxml::LN_inTbl, pVal, OOXMLProperty::SPRM);
+ }
+ {
+ OOXMLValue::Pointer_t pVal = OOXMLBooleanValue::Create(mnTableDepth > 0);
+ pProps->add(NS_ooxml::LN_tblCell, pVal, OOXMLProperty::SPRM);
+ }
+
+ mpStream->props(pProps.get());
+
+ // fake <w:tcBorders> with no border
+ OOXMLPropertySet::Pointer_t pCellProps( new OOXMLPropertySet );
+ {
+ OOXMLPropertySet::Pointer_t pBorderProps( new OOXMLPropertySet );
+ static Id borders[] = { NS_ooxml::LN_CT_TcBorders_top, NS_ooxml::LN_CT_TcBorders_bottom,
+ NS_ooxml::LN_CT_TcBorders_start, NS_ooxml::LN_CT_TcBorders_end };
+ for(sal_uInt32 border : borders)
+ pBorderProps->add(border, fakeNoBorder(), OOXMLProperty::SPRM);
+ OOXMLValue::Pointer_t pValue( new OOXMLPropertySetValue( pBorderProps ));
+ pCellProps->add(NS_ooxml::LN_CT_TcPrBase_tcBorders, pValue, OOXMLProperty::SPRM);
+ mpParserState->setCellProperties(pCellProps);
+ }
+ }
+
+ sendCellProperties();
+ endParagraphGroup();
+ }
+}
+
+/*
+ class OOXMLFastContextHandlerTextTable
+ */
+
+OOXMLFastContextHandlerTextTable::OOXMLFastContextHandlerTextTable
+(OOXMLFastContextHandler * pContext)
+: OOXMLFastContextHandler(pContext)
+{
+}
+
+OOXMLFastContextHandlerTextTable::~OOXMLFastContextHandlerTextTable()
+{
+ clearTableProps();
+}
+
+void OOXMLFastContextHandlerTextTable::lcl_startFastElement
+(Token_t /*Element*/,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ if (mpParserState->GetFloatingTableEnded())
+ {
+ // We're starting a new table, but the previous table was floating. Insert a dummy paragraph
+ // to ensure that the floating table has a suitable anchor. The function calls here are a
+ // subset of '<resource name="CT_P" resource="Stream">' in model.xml:
+ startParagraphGroup();
+ sendTableDepth();
+ endOfParagraph();
+ }
+
+ 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--;
+
+ OOXMLPropertySet::Pointer_t pTableProps = mpParserState->GetTableProperties();
+ if (pTableProps)
+ {
+ for (const auto& rTableProp : *pTableProps)
+ {
+ if (rTableProp->getId() == NS_ooxml::LN_CT_TblPrBase_tblpPr)
+ {
+ mpParserState->SetFloatingTableEnded(true);
+ break;
+ }
+ }
+ }
+
+ 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())
+ {
+ if (Element == DGM_TOKEN(relIds) || Element == WPC_TOKEN(wpc))
+ {
+ // It is a SmartArt or a WordprocessingCanvas. Make size available for generated group.
+ // Search for PropertySet in parents
+ OOXMLFastContextHandler* pHandler = getParent();
+ while (pHandler && pHandler->getId() != NS_ooxml::LN_anchor_anchor
+ && pHandler->getId() != NS_ooxml::LN_inline_inline)
+ {
+ pHandler = pHandler->getParent();
+ }
+ // Search for extent
+ if (pHandler)
+ {
+ if (const OOXMLPropertySet::Pointer_t pPropSet = pHandler->getPropertySet())
+ {
+ auto aIt = pPropSet->begin();
+ auto aItEnd = pPropSet->end();
+ while (aIt != aItEnd && (*aIt)->getId() != NS_ooxml::LN_CT_Inline_extent
+ && (*aIt)->getId() != NS_ooxml::LN_CT_Anchor_extent)
+ {
+ ++aIt;
+ }
+ if (aIt != aItEnd)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties = (*aIt)->getProps();
+ if (pProperties)
+ {
+ writerfilter::dmapper::ExtentHandler::Pointer_t pExtentHandler(new writerfilter::dmapper::ExtentHandler());
+ pProperties->resolve(*pExtentHandler);
+ mrShapeContext->setSize(pExtentHandler->getExtent());
+ }
+ }
+ }
+ }
+ }
+ mrShapeContext->startFastElement(Element, Attribs);
+ }
+}
+
+void SAL_CALL OOXMLFastContextHandlerShape::startUnknownElement
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mrShapeContext.is())
+ mrShapeContext->startUnknownElement(Namespace, Name, Attribs);
+}
+
+void OOXMLFastContextHandlerShape::setToken(Token_t nToken)
+{
+ if (nToken == Token_t(NMSP_wps | XML_wsp) || nToken == Token_t(NMSP_dmlPicture | XML_pic))
+ {
+ // drawingML shapes are independent, <wps:bodyPr> is not parsed after
+ // shape contents without pushing/popping the stack.
+ m_bShapeContextPushed = true;
+ getDocument()->pushShapeContext();
+ }
+
+ mrShapeContext = getDocument()->getShapeContext();
+ if (!mrShapeContext.is())
+ {
+ // Define the shape context for the whole document
+ mrShapeContext = new oox::shape::ShapeContextHandler(getDocument()->getShapeFilterBase());
+ getDocument()->setShapeContext(mrShapeContext);
+ auto pThemePtr = getDocument()->getTheme();
+ if (pThemePtr)
+ mrShapeContext->setTheme(pThemePtr);
+ }
+
+ mrShapeContext->setModel(getDocument()->getModel());
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocSupplier(getDocument()->getModel(), uno::UNO_QUERY_THROW);
+ mrShapeContext->setDocumentProperties(xDocSupplier->getDocumentProperties());
+ mrShapeContext->setDrawPage(getDocument()->getDrawPage());
+ mrShapeContext->setMediaDescriptor(getDocument()->getMediaDescriptor());
+
+ mrShapeContext->setRelationFragmentPath(mpParserState->getTarget());
+
+ // Floating tables (table inside a textframe) have issues with fullWPG,
+ // so disable the fullWPGsupport in tables until that issue is not fixed.
+ mrShapeContext->setFullWPGSupport(!mnTableDepth);
+
+ auto xGraphicMapper = getDocument()->getGraphicMapper();
+
+ if (xGraphicMapper.is())
+ mrShapeContext->setGraphicMapper(xGraphicMapper);
+
+ OOXMLFastContextHandler::setToken(nToken);
+
+ if (mrShapeContext.is())
+ mrShapeContext->pushStartToken(nToken);
+}
+
+void OOXMLFastContextHandlerShape::sendShape( Token_t Element )
+{
+ if ( !mrShapeContext.is() || m_bShapeSent )
+ return;
+
+ awt::Point aPosition = mpStream->getPositionOffset();
+ mrShapeContext->setPosition(aPosition);
+ uno::Reference<drawing::XShape> xShape(mrShapeContext->getShape());
+ m_bShapeSent = true;
+ if (!xShape.is())
+ return;
+
+ OOXMLValue::Pointer_t
+ pValue(new OOXMLShapeValue(xShape));
+ newProperty(NS_ooxml::LN_shape, pValue);
+
+ bool bIsPicture = Element == ( NMSP_dmlPicture | XML_pic );
+
+ //tdf#87569: Fix table layout with correcting anchoring
+ //If anchored object is in table, Word calculates its position from cell border
+ //instead of page (what is set in the sample document)
+ uno::Reference<beans::XPropertySet> xShapePropSet(xShape, uno::UNO_QUERY);
+ if (mnTableDepth > 0 && xShapePropSet.is() && mbIsVMLfound) //if we had a table
+ {
+ bool bForceShapeIntoCell = mbAllowInCell;
+ // According to tdf#153909 and GraphicImport's LN_shape handling,
+ // through-anchored shapes should not force the shape into the cell
+ if (bForceShapeIntoCell)
+ {
+ text::WrapTextMode nSurround = text::WrapTextMode_NONE;
+ xShapePropSet->getPropertyValue("Surround") >>= nSurround;
+ sal_Int32 nHoriRelation = -1;
+ xShapePropSet->getPropertyValue("HoriOrientRelation") >>= nHoriRelation;
+ bForceShapeIntoCell = (nSurround != text::WrapTextMode_THROUGH)
+ || (nHoriRelation != text::RelOrientation::FRAME);
+ }
+ xShapePropSet->setPropertyValue(dmapper::getPropertyName(dmapper::PROP_FOLLOW_TEXT_FLOW),
+ uno::Any(bForceShapeIntoCell));
+ }
+ // Notify the dmapper that the shape is ready to use
+ if ( !bIsPicture )
+ {
+ mpStream->startShape( xShape );
+ m_bShapeStarted = true;
+ }
+}
+
+bool OOXMLFastContextHandlerShape::isDMLGroupShape() const
+{
+ return (mrShapeContext->getFullWPGSupport() && mrShapeContext->isWordProcessingGroupShape())
+ || mrShapeContext->isWordprocessingCanvas();
+};
+
+void OOXMLFastContextHandlerShape::lcl_endFastElement
+(Token_t Element)
+{
+ if (!isForwardEvents())
+ return;
+
+ if (mrShapeContext.is())
+ {
+ mrShapeContext->endFastElement(Element);
+ sendShape( Element );
+ }
+
+ OOXMLFastContextHandlerProperties::lcl_endFastElement(Element);
+
+ // Ending the shape should be the last thing to do
+ bool bIsPicture = Element == ( NMSP_dmlPicture | XML_pic );
+ if ( !bIsPicture && m_bShapeStarted)
+ mpStream->endShape( );
+}
+
+void SAL_CALL OOXMLFastContextHandlerShape::endUnknownElement
+(const OUString & Namespace,
+ const OUString & Name)
+{
+ if (mrShapeContext.is())
+ mrShapeContext->endUnknownElement(Namespace, Name);
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+OOXMLFastContextHandlerShape::lcl_createFastChildContext
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ // we need to share a single theme across all the shapes, but we parse it
+ // in ShapeContextHandler. So if it has been parsed there, propagate it to
+ // the document.
+ if (mrShapeContext && mrShapeContext->getTheme() && !getDocument()->getTheme())
+ {
+ auto pThemePtr = mrShapeContext->getTheme();
+ getDocument()->setTheme(pThemePtr);
+ }
+
+ uno::Reference< xml::sax::XFastContextHandler > xContextHandler;
+
+ bool bGroupShape = Element == Token_t(NMSP_vml | XML_group);
+ // drawingML version also counts as a group shape.
+ if (!mrShapeContext->getFullWPGSupport())
+ bGroupShape |= mrShapeContext->getStartToken() == Token_t(NMSP_wpg | XML_wgp);
+ mbIsVMLfound = (getNamespace(Element) == NMSP_vmlOffice) || (getNamespace(Element) == NMSP_vml);
+ switch (oox::getNamespace(Element))
+ {
+ case NMSP_doc:
+ case NMSP_vmlWord:
+ case NMSP_vmlOffice:
+ if (!bGroupShape)
+ xContextHandler.set(OOXMLFactory::createFastChildContextFromStart(this, Element));
+ [[fallthrough]];
+ default:
+ if (!xContextHandler.is())
+ {
+ if (mrShapeContext.is())
+ {
+ uno::Reference<XFastContextHandler> pChildContext =
+ mrShapeContext->createFastChildContext(Element, Attribs);
+
+ rtl::Reference<OOXMLFastContextHandlerWrapper> pWrapper =
+ new OOXMLFastContextHandlerWrapper(this,
+ pChildContext,
+ this);
+
+ //tdf129888 store allowincell attribute of the VML shape
+ if (Attribs->hasAttribute(NMSP_vmlOffice | XML_allowincell))
+ mbAllowInCell
+ = !(Attribs->getValue(NMSP_vmlOffice | XML_allowincell) == "f");
+
+ if (!bGroupShape)
+ {
+ pWrapper->addNamespace(NMSP_doc);
+ pWrapper->addNamespace(NMSP_vmlWord);
+ pWrapper->addNamespace(NMSP_vmlOffice);
+ pWrapper->addToken( NMSP_vml|XML_textbox );
+ }
+ xContextHandler.set(pWrapper);
+ }
+ else
+ xContextHandler.set(this);
+ }
+ break;
+ }
+
+ // VML import of shape text is already handled by
+ // OOXMLFastContextHandlerWrapper::lcl_createFastChildContext(), here we
+ // handle the WPS import of shape text, as there the parent context is a
+ // Shape one, so a different situation.
+ if (Element == static_cast<sal_Int32>(NMSP_wps | XML_txbx) ||
+ Element == static_cast<sal_Int32>(NMSP_wps | XML_linkedTxbx) )
+ sendShape(Element);
+
+ return xContextHandler;
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandlerShape::createUnknownChildContext
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+
+ if (mrShapeContext.is())
+ xResult.set(mrShapeContext->createUnknownChildContext
+ (Namespace, Name, Attribs));
+
+ return xResult;
+}
+
+void OOXMLFastContextHandlerShape::lcl_characters
+(const OUString & aChars)
+{
+ if (mrShapeContext.is())
+ mrShapeContext->characters(aChars);
+}
+
+/*
+ class OOXMLFastContextHandlerWrapper
+*/
+
+OOXMLFastContextHandlerWrapper::OOXMLFastContextHandlerWrapper
+(OOXMLFastContextHandler * pParent,
+ uno::Reference<XFastContextHandler> const & xContext,
+ rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler)
+ : OOXMLFastContextHandler(pParent),
+ mxWrappedContext(xContext),
+ mxShapeHandler(xShapeHandler)
+{
+ setId(pParent->getId());
+ setToken(pParent->getToken());
+ setPropertySet(pParent->getPropertySet());
+}
+
+OOXMLFastContextHandlerWrapper::~OOXMLFastContextHandlerWrapper()
+{
+}
+
+void SAL_CALL OOXMLFastContextHandlerWrapper::startUnknownElement
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->startUnknownElement(Namespace, Name, Attribs);
+}
+
+void SAL_CALL OOXMLFastContextHandlerWrapper::endUnknownElement
+(const OUString & Namespace,
+ const OUString & Name)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->endUnknownElement(Namespace, Name);
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastContextHandlerWrapper::createUnknownChildContext
+(const OUString & Namespace,
+ const OUString & Name,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+
+ if (mxWrappedContext.is())
+ xResult = mxWrappedContext->createUnknownChildContext
+ (Namespace, Name, Attribs);
+ else
+ xResult.set(this);
+
+ return xResult;
+}
+
+void OOXMLFastContextHandlerWrapper::attributes
+(const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->attributes(Attribs);
+ }
+}
+
+OOXMLFastContextHandler::ResourceEnum_t
+OOXMLFastContextHandlerWrapper::getResource() const
+{
+ return UNKNOWN;
+}
+
+void OOXMLFastContextHandlerWrapper::addNamespace(Id nId)
+{
+ mMyNamespaces.insert(nId);
+}
+
+void OOXMLFastContextHandlerWrapper::addToken( Token_t Token )
+{
+ mMyTokens.insert( Token );
+}
+
+void OOXMLFastContextHandlerWrapper::lcl_startFastElement
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->startFastElement(Element, Attribs);
+
+ if (mxShapeHandler->isDMLGroupShape()
+ && (Element == Token_t(NMSP_wps | XML_txbx)
+ || Element == Token_t(NMSP_wps | XML_linkedTxbx)))
+ {
+ mpStream->startTextBoxContent();
+ }
+}
+
+void OOXMLFastContextHandlerWrapper::lcl_endFastElement
+(Token_t Element)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->endFastElement(Element);
+
+ if (mxShapeHandler->isDMLGroupShape()
+ && (Element == Token_t(NMSP_wps | XML_txbx)
+ || Element == Token_t(NMSP_wps | XML_linkedTxbx)))
+ {
+ mpStream->endTextBoxContent();
+ }
+}
+
+uno::Reference< xml::sax::XFastContextHandler >
+OOXMLFastContextHandlerWrapper::lcl_createFastChildContext
+(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
+{
+ uno::Reference< xml::sax::XFastContextHandler > xResult;
+
+ bool bInNamespaces = mMyNamespaces.find(oox::getNamespace(Element)) != mMyNamespaces.end();
+ bool bInTokens = mMyTokens.find( Element ) != mMyTokens.end( );
+
+ // We have methods to _add_ individual tokens or whole namespaces to be
+ // processed by writerfilter (instead of oox), but we have no method to
+ // filter out a single token. Just hardwire the 'wrap' and 'signatureline' tokens
+ // here until we need a more generic solution.
+ bool bIsWrap = Element == static_cast<sal_Int32>(NMSP_vmlWord | XML_wrap);
+ bool bIsSignatureLine = Element == static_cast<sal_Int32>(NMSP_vmlOffice | XML_signatureline);
+ bool bSkipImages = getDocument()->IsSkipImages() && oox::getNamespace(Element) == NMSP_dml &&
+ (oox::getBaseToken(Element) != XML_linkedTxbx) && (oox::getBaseToken(Element) != XML_txbx);
+
+ if ( bInNamespaces && ((!bIsWrap && !bIsSignatureLine)
+ || mxShapeHandler->isShapeSent()) )
+ {
+ xResult.set(OOXMLFactory::createFastChildContextFromStart(this, Element));
+ }
+ else if (mxWrappedContext.is() && !bSkipImages)
+ {
+ rtl::Reference<OOXMLFastContextHandlerWrapper> pWrapper =
+ new OOXMLFastContextHandlerWrapper
+ (this, mxWrappedContext->createFastChildContext(Element, Attribs),
+ mxShapeHandler);
+ pWrapper->mMyNamespaces = mMyNamespaces;
+ pWrapper->mMyTokens = mMyTokens;
+ pWrapper->setPropertySet(getPropertySet());
+ xResult.set(pWrapper);
+ }
+ else
+ {
+ xResult.set(this);
+ }
+
+ if ( bInTokens )
+ mxShapeHandler->sendShape( Element );
+
+ return xResult;
+}
+
+void OOXMLFastContextHandlerWrapper::lcl_characters
+(const OUString & aChars)
+{
+ if (mxWrappedContext.is())
+ mxWrappedContext->characters(aChars);
+}
+
+OOXMLFastContextHandler *
+OOXMLFastContextHandlerWrapper::getFastContextHandler() const
+{
+ if (mxWrappedContext.is())
+ return dynamic_cast<OOXMLFastContextHandler *>(mxWrappedContext.get());
+
+ return nullptr;
+}
+
+void OOXMLFastContextHandlerWrapper::newProperty
+(Id nId, const OOXMLValue::Pointer_t& pVal)
+{
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->newProperty(nId, pVal);
+ }
+}
+
+void OOXMLFastContextHandlerWrapper::setPropertySet
+(const OOXMLPropertySet::Pointer_t& pPropertySet)
+{
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pHandler->setPropertySet(pPropertySet);
+ }
+
+ mpPropertySet = pPropertySet;
+}
+
+OOXMLPropertySet::Pointer_t OOXMLFastContextHandlerWrapper::getPropertySet()
+ const
+{
+ OOXMLPropertySet::Pointer_t pResult(mpPropertySet);
+
+ if (mxWrappedContext.is())
+ {
+ OOXMLFastContextHandler * pHandler = getFastContextHandler();
+ if (pHandler != nullptr)
+ pResult = pHandler->getPropertySet();
+ }
+
+ return pResult;
+}
+
+std::string OOXMLFastContextHandlerWrapper::getType() const
+{
+ std::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)
+ , m_depthCount( 0 )
+{
+}
+
+void OOXMLFastContextHandlerLinear::lcl_startFastElement(Token_t Element,
+ const uno::Reference< xml::sax::XFastAttributeList >& Attribs)
+{
+ m_buffer.appendOpeningTag( Element, Attribs );
+ ++m_depthCount;
+}
+
+void OOXMLFastContextHandlerLinear::lcl_endFastElement(Token_t Element)
+{
+ m_buffer.appendClosingTag( Element );
+ if( --m_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)
+{
+ m_buffer.appendCharacters( aChars );
+}
+
+/*
+ class OOXMLFastContextHandlerLinear
+ */
+
+OOXMLFastContextHandlerMath::OOXMLFastContextHandlerMath(OOXMLFastContextHandler* pContext)
+ : OOXMLFastContextHandlerLinear(pContext)
+{
+}
+
+void OOXMLFastContextHandlerMath::process()
+{
+ SvGlobalName name( SO3_SM_CLASSID );
+ comphelper::EmbeddedObjectContainer container;
+ OUString aName;
+ uno::Sequence<beans::PropertyValue> objArgs{ comphelper::makePropertyValue(
+ "DefaultParentBaseURL", getDocument()->GetDocumentBaseURL()) };
+ uno::Reference<embed::XEmbeddedObject> ref =
+ container.CreateEmbeddedObject(name.GetByteSequence(), objArgs, aName);
+ assert(ref.is());
+ if (!ref.is())
+ return;
+ uno::Reference< uno::XInterface > component(ref->getComponent(), uno::UNO_QUERY_THROW);
+ if( oox::FormulaImExportBase* import
+ = dynamic_cast< oox::FormulaImExportBase* >( component.get()))
+ import->readFormulaOoxml( m_buffer );
+ if (!isForwardEvents())
+ return;
+
+ OOXMLPropertySet::Pointer_t pProps(new OOXMLPropertySet);
+ OOXMLValue::Pointer_t pVal( new OOXMLStarMathValue( ref ));
+ if (mbIsMathPara)
+ {
+ switch (mnMathJcVal)
+ {
+ case eMathParaJc::CENTER:
+ pProps->add(NS_ooxml::LN_Value_math_ST_Jc_centerGroup, pVal,
+ OOXMLProperty::ATTRIBUTE);
+ break;
+ case eMathParaJc::LEFT:
+ pProps->add(NS_ooxml::LN_Value_math_ST_Jc_left, pVal,
+ OOXMLProperty::ATTRIBUTE);
+ break;
+ case eMathParaJc::RIGHT:
+ pProps->add(NS_ooxml::LN_Value_math_ST_Jc_right, pVal,
+ OOXMLProperty::ATTRIBUTE);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ pProps->add(NS_ooxml::LN_starmath, pVal, OOXMLProperty::ATTRIBUTE);
+ mpStream->props( pProps.get() );
+}
+
+OOXMLFastContextHandlerCommentEx::OOXMLFastContextHandlerCommentEx(
+ OOXMLFastContextHandler* pContext)
+ : OOXMLFastContextHandler(pContext)
+{
+}
+
+void OOXMLFastContextHandlerCommentEx::lcl_endFastElement(Token_t /*Element*/)
+{
+ mpStream->commentProps(m_sParaId, { m_bDone, m_sParentId });
+}
+
+void OOXMLFastContextHandlerCommentEx::att_paraId(const OOXMLValue::Pointer_t& pValue)
+{
+ m_sParaId = pValue->getString();
+}
+
+void OOXMLFastContextHandlerCommentEx::att_done(const OOXMLValue::Pointer_t& pValue)
+{
+ if (pValue->getInt())
+ m_bDone = true;
+}
+
+void OOXMLFastContextHandlerCommentEx::att_paraIdParent(const OOXMLValue::Pointer_t& pValue)
+{
+ m_sParentId = pValue->getString();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx
new file mode 100644
index 000000000000..4dfb05d91503
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.hxx
@@ -0,0 +1,634 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <set>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XFastContextHandler.hpp>
+#include <oox/mathml/importutils.hxx>
+#include <rtl/ref.hxx>
+#include "OOXMLParserState.hxx"
+#include "OOXMLPropertySet.hxx"
+
+namespace writerfilter::ooxml
+{
+class OOXMLDocumentImpl;
+
+class OOXMLFastContextHandler: public ::cppu::WeakImplHelper<css::xml::sax::XFastContextHandler>
+{
+public:
+ typedef tools::SvRef<OOXMLFastContextHandler> Pointer_t;
+
+ enum ResourceEnum_t { UNKNOWN, STREAM, PROPERTIES, TABLE, SHAPE };
+
+ explicit OOXMLFastContextHandler(css::uno::Reference< css::uno::XComponentContext > const & context);
+
+ explicit OOXMLFastContextHandler(OOXMLFastContextHandler * pContext);
+
+ OOXMLFastContextHandler(OOXMLFastContextHandler const &) = default;
+
+ virtual ~OOXMLFastContextHandler() override;
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startFastElement (sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override final;
+
+ virtual void SAL_CALL startUnknownElement(const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL endFastElement(sal_Int32 Element) override;
+
+ virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override;
+
+ virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(sal_Int32 Element,
+ const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext(const OUString & Namespace, const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL characters(const OUString & aChars) override;
+
+ // local
+
+ void setStream(Stream * pStream);
+
+ /**
+ Return value of this context(element).
+
+ @return the value
+ */
+ virtual OOXMLValue::Pointer_t getValue() const;
+
+ /**
+ Returns a string describing the type of the context.
+
+ This is the name of the define normally.
+
+ @return type string
+ */
+ virtual std::string getType() const { return "??"; }
+
+ virtual ResourceEnum_t getResource() const { return STREAM; }
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void attributes(const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ virtual void newProperty(Id aId, const OOXMLValue::Pointer_t& pVal);
+ virtual void setPropertySet(const OOXMLPropertySet::Pointer_t& pPropertySet);
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const;
+
+ virtual void setToken(Token_t nToken);
+ virtual Token_t getToken() const;
+
+ void resolveFootnote(const sal_Int32 nId);
+ void resolveEndnote(const sal_Int32 nId);
+ void resolveComment(const sal_Int32 nId);
+ void resolvePicture(const OUString & rId);
+ void resolveHeader(const sal_Int32 type,
+ const OUString & rId);
+ void resolveFooter(const sal_Int32 type,
+ const OUString & rId);
+ void resolveData(const OUString & rId);
+
+ OUString getTargetForId(const OUString & rId);
+
+ void setDocument(OOXMLDocumentImpl* pDocument);
+ OOXMLDocumentImpl* getDocument();
+ void setXNoteId(const OOXMLValue::Pointer_t& pValue);
+ void setXNoteId(const sal_Int32 nId);
+ sal_Int32 getXNoteId() const;
+ void setForwardEvents(bool bForwardEvents);
+ bool isForwardEvents() const;
+ virtual void setId(Id nId);
+ virtual Id getId() const;
+
+ void setDefine(Id nDefine);
+ Id getDefine() const { return mnDefine;}
+
+ const OOXMLParserState::Pointer_t& getParserState() const { return mpParserState;}
+
+ void sendTableDepth() const;
+ void setHandle();
+
+ void startSectionGroup();
+ void setLastParagraphInSection();
+ void setLastSectionGroup();
+ void endSectionGroup();
+ void startParagraphGroup();
+ void endParagraphGroup();
+ void startCharacterGroup();
+ void endCharacterGroup();
+ virtual void pushBiDiEmbedLevel();
+ virtual void popBiDiEmbedLevel();
+ void startSdt();
+ void endSdt();
+ void startSdtRun();
+ void endSdtRun();
+
+ void startField();
+ void fieldSeparator();
+ void endField();
+ void lockField();
+ void ftnednref();
+ void ftnedncont();
+ void ftnednsep();
+ void pgNum();
+ void tab();
+ void symbol();
+ void cr();
+ void noBreakHyphen();
+ void softHyphen();
+ void handleLastParagraphInSection();
+ void endOfParagraph();
+ void text(const OUString & sText);
+ void positionOffset(const OUString & sText);
+ static void ignore();
+ void alignH(const OUString & sText);
+ void alignV(const OUString & sText);
+ void positivePercentage(const OUString& rText);
+ void startGlossaryEntry();
+ void endGlossaryEntry();
+ void startTxbxContent();
+ void endTxbxContent();
+ void propagateCharacterProperties();
+ void propagateTableProperties();
+ void propagateRowProperties();
+ void propagateCellProperties();
+ void sendPropertiesWithId(Id nId);
+ void sendPropertiesToParent();
+ void sendCellProperties();
+ void sendRowProperties();
+ void sendTableProperties();
+ void clearTableProps();
+ void clearProps();
+
+ virtual void setDefaultBooleanValue();
+ virtual void setDefaultIntegerValue();
+ virtual void setDefaultHexValue();
+ virtual void setDefaultStringValue();
+
+ void sendPropertyToParent();
+ OOXMLFastContextHandler* getParent() const { return mpParent; }
+ void setGridAfter(const OOXMLValue::Pointer_t& pGridAfter) { mpGridAfter = pGridAfter; }
+
+protected:
+ OOXMLFastContextHandler * mpParent;
+ Id mId;
+ Id mnDefine;
+ Token_t mnToken;
+
+ // the formula insertion mode: inline/newline(left, center, right)
+ sal_Int8 mnMathJcVal;
+ bool mbIsMathPara;
+ enum eMathParaJc
+ {
+ INLINE, //The equation is anchored as inline to the text
+ CENTER, //The equation is center aligned
+ LEFT, //The equation is left aligned
+ RIGHT //The equation is right aligned
+ };
+ // the stream to send the stream events to.
+ Stream * mpStream;
+
+ // the current global parser state
+ OOXMLParserState::Pointer_t mpParserState;
+
+ // the table depth of this context
+ unsigned int mnTableDepth;
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void lcl_endFastElement(Token_t Element);
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs);
+
+ /// @throws css::uno::RuntimeException
+ /// @throws css::xml::sax::SAXException
+ virtual void lcl_characters(const OUString & aChars);
+
+ void startAction();
+ void endAction();
+
+ bool m_inPositionV;
+ bool mbAllowInCell; // o:allowincell
+ bool mbIsVMLfound;
+ OOXMLValue::Pointer_t mpGridAfter;
+
+private:
+ void operator =(OOXMLFastContextHandler const &) = delete;
+ /// Handles AlternateContent. Returns true, if children of the current element should be ignored.
+ bool prepareMceContext(Token_t nElement, const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs);
+
+ // 2.10 of XML 1.0 specification
+ bool IsPreserveSpace() const;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ bool m_bDiscardChildren;
+ bool m_bTookChoice; ///< Did we take the Choice or want Fallback instead?
+ bool mbPreserveSpace = false;
+ bool mbPreserveSpaceSet = false;
+
+};
+
+class OOXMLFastContextHandlerStream : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerStream(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerStream() override;
+
+ virtual ResourceEnum_t getResource() const override { return STREAM; }
+
+ const OOXMLPropertySet::Pointer_t& getPropertySetAttrs() const { return mpPropertySetAttrs;}
+
+ virtual void newProperty(Id aId, const OOXMLValue::Pointer_t& pVal) override;
+ void sendProperty(Id nId);
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const override;
+
+ void handleHyperlink();
+
+private:
+ mutable OOXMLPropertySet::Pointer_t mpPropertySetAttrs;
+};
+
+class OOXMLFastContextHandlerProperties : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerProperties(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerProperties() override;
+
+ virtual OOXMLValue::Pointer_t getValue() const override;
+ virtual ResourceEnum_t getResource() const override { return PROPERTIES; }
+
+ virtual void newProperty(Id nId, const OOXMLValue::Pointer_t& pVal) override;
+
+ void handleXNotes();
+ void handleHdrFtr();
+ void handleComment();
+ void handlePicture();
+ void handleBreak();
+ void handleOutOfOrderBreak();
+ void handleOLE();
+ void handleFontRel();
+ void handleHyperlinkURL();
+ void handleAltChunk();
+
+ virtual void setPropertySet(const OOXMLPropertySet::Pointer_t& pPropertySet) override;
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const override;
+
+protected:
+ /// the properties
+ OOXMLPropertySet::Pointer_t mpPropertySet;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+private:
+
+ bool mbResolve;
+};
+
+class OOXMLFastContextHandlerPropertyTable :
+ public OOXMLFastContextHandlerProperties
+{
+public:
+ explicit OOXMLFastContextHandlerPropertyTable(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerPropertyTable() override;
+
+private:
+ OOXMLTable mTable;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+};
+
+class OOXMLFastContextHandlerValue :
+ public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerValue(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerValue() override;
+
+ void setValue(const OOXMLValue::Pointer_t& pValue);
+ virtual OOXMLValue::Pointer_t getValue() const override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual std::string getType() const override { return "Value"; }
+
+ virtual void setDefaultBooleanValue() override;
+ virtual void setDefaultIntegerValue() override;
+ virtual void setDefaultHexValue() override;
+ virtual void setDefaultStringValue() override;
+
+ virtual void pushBiDiEmbedLevel() override;
+ virtual void popBiDiEmbedLevel() override;
+
+ void handleGridAfter();
+
+private:
+ OOXMLValue::Pointer_t mpValue;
+};
+
+class OOXMLFastContextHandlerTable : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTable(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerTable() override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext (sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+private:
+ OOXMLTable mTable;
+
+ css::uno::Reference<css::xml::sax::XFastContextHandler> mCurrentChild;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual ResourceEnum_t getResource() const override { return TABLE; }
+
+ virtual std::string getType() const override { return "Table"; }
+
+ void addCurrentChild();
+};
+
+class OOXMLFastContextHandlerXNote : public OOXMLFastContextHandlerProperties
+{
+public:
+ explicit OOXMLFastContextHandlerXNote(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerXNote() override;
+
+ void checkId(const OOXMLValue::Pointer_t& pValue);
+
+ void checkType(const OOXMLValue::Pointer_t& pValue);
+
+ virtual std::string getType() const override { return "XNote"; }
+
+private:
+ bool mbForwardEventsSaved;
+ sal_Int32 mnMyXNoteId;
+ sal_Int32 mnMyXNoteType;
+
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual ResourceEnum_t getResource() const override { return STREAM; }
+};
+
+class OOXMLFastContextHandlerTextTableCell : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTextTableCell(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerTextTableCell() override;
+
+ virtual std::string getType() const override { return "TextTableCell"; }
+
+ void startCell();
+ void endCell();
+};
+
+class OOXMLFastContextHandlerTextTableRow : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTextTableRow(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerTextTableRow() override;
+
+ virtual std::string getType() const override { return "TextTableRow"; }
+
+ static void startRow();
+ void endRow();
+ void handleGridBefore( const OOXMLValue::Pointer_t& val );
+};
+
+class OOXMLFastContextHandlerTextTable : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerTextTable(OOXMLFastContextHandler * pContext);
+
+ virtual ~OOXMLFastContextHandlerTextTable() override;
+
+ virtual std::string getType() const override { return "TextTable"; }
+
+ // tdf#111550
+ // when <w:tbl> appears as direct child of <w:p>, we need to rearrange this paragraph
+ // to merge with the table's first paragraph (that's what Word does in this case)
+ void start_P_Tbl();
+protected:
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+};
+
+class OOXMLFastContextHandlerShape: public OOXMLFastContextHandlerProperties
+{
+ bool m_bShapeSent;
+ bool m_bShapeStarted;
+ /// Is it necessary to pop the stack in the dtor?
+ bool m_bShapeContextPushed;
+ rtl::Reference<oox::shape::ShapeContextHandler> mrShapeContext;
+
+public:
+ explicit OOXMLFastContextHandlerShape(OOXMLFastContextHandler * pContext);
+ virtual ~OOXMLFastContextHandlerShape() override;
+
+ virtual std::string getType() const override { return "Shape"; }
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startUnknownElement (const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext(const OUString & Namespace, const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void setToken(Token_t nToken) override;
+
+ virtual ResourceEnum_t getResource() const override { return SHAPE; }
+
+ void sendShape( Token_t Element );
+ bool isShapeSent( ) const { return m_bShapeSent; }
+ bool isDMLGroupShape() const;
+
+protected:
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext (Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_characters(const OUString & aChars) override;
+
+};
+
+/**
+ OOXMLFastContextHandlerWrapper wraps an OOXMLFastContextHandler.
+
+ The method calls for the interface css::xml::sax::XFastContextHandler are
+ forwarded to the wrapped OOXMLFastContextHandler.
+ */
+class OOXMLFastContextHandlerWrapper : public OOXMLFastContextHandler
+{
+public:
+ OOXMLFastContextHandlerWrapper(OOXMLFastContextHandler * pParent,
+ css::uno::Reference<css::xml::sax::XFastContextHandler> const & xContext,
+ rtl::Reference<OOXMLFastContextHandlerShape> const & xShapeHandler);
+ virtual ~OOXMLFastContextHandlerWrapper() override;
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startUnknownElement(const OUString & Namespace, const OUString & Name, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext (const OUString & Namespace, const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void attributes(const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual ResourceEnum_t getResource() const override;
+
+ void addNamespace(Id nId);
+ void addToken( Token_t Element );
+
+ virtual void newProperty(Id nId, const OOXMLValue::Pointer_t& pVal) override;
+ virtual void setPropertySet(const OOXMLPropertySet::Pointer_t& pPropertySet) override;
+ virtual OOXMLPropertySet::Pointer_t getPropertySet() const override;
+
+ virtual std::string getType() const override;
+
+protected:
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_characters(const OUString & aChars) override;
+
+ virtual void setId(Id nId) override;
+ virtual Id getId() const override;
+
+ virtual void setToken(Token_t nToken) override;
+ virtual Token_t getToken() const override;
+
+private:
+ css::uno::Reference<css::xml::sax::XFastContextHandler> mxWrappedContext;
+ rtl::Reference<OOXMLFastContextHandlerShape> mxShapeHandler;
+ std::set<Id> mMyNamespaces;
+ std::set<Token_t> mMyTokens;
+ OOXMLPropertySet::Pointer_t mpPropertySet;
+
+ OOXMLFastContextHandler * getFastContextHandler() const;
+};
+
+/**
+ A class that converts from XFastParser/XFastContextHandler usage to a liner XML stream of data.
+
+ The purpose of this class is to convert the rather complex XFastContextHandler-based XML
+ processing that requires context subclasses, callbacks, etc. into a linear stream of XML tokens
+ that can be handled simply by reading the tokens one by one and directly processing them.
+ See the oox::formulaimport::XmlStream class documentation for more information.
+
+ Usage: Create a subclass of OOXMLFastContextHandlerLinear, reimplemented getType() to provide
+ type of the subclass and process() to actually process the XML stream. Also make sure to
+ add a line like the following to model.xml (for class OOXMLFastContextHandlerMath):
+
+ <resource name="CT_OMath" resource="Math"/>
+
+ @since 3.5
+*/
+class OOXMLFastContextHandlerLinear: public OOXMLFastContextHandlerProperties
+{
+public:
+ explicit OOXMLFastContextHandlerLinear(OOXMLFastContextHandler * pContext);
+ /**
+ Return the type of the class, as written in model.xml .
+ */
+ virtual std::string getType() const override = 0;
+
+protected:
+ /**
+ Called when the tokens for the element, its content and sub-elements have been linearized
+ and should be processed. The data member @ref buffer contains the converted data.
+ */
+ virtual void process() = 0;
+
+ virtual void lcl_startFastElement(Token_t Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > lcl_createFastChildContext(Token_t Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+
+ virtual void lcl_characters(const OUString & aChars) override;
+
+ // should be private, but not much point in making deep copies of it
+ oox::formulaimport::XmlStreamBuilder m_buffer;
+
+private:
+ int m_depthCount;
+};
+
+class OOXMLFastContextHandlerMath: public OOXMLFastContextHandlerLinear
+{
+public:
+ explicit OOXMLFastContextHandlerMath(OOXMLFastContextHandler * pContext);
+ virtual std::string getType() const override { return "Math"; }
+protected:
+ virtual void process() override;
+};
+
+/**
+ A class that reads individual w15:commentEx elements from commentsExtended stream [MS-DOCX].
+
+ It is used to pre-populate the extended comment properties in domain mapper. The stream
+ contains information about resolved state of the comments ("done" attribute) and the parent
+ comment (the one that this comment answers to).
+
+ Note that the data is linked to paraId identifiers (also introduced in [MS-DOCX]), which
+ correspond to paragraphs, not directly to comment ids.
+
+ @since 7.2
+*/
+class OOXMLFastContextHandlerCommentEx : public OOXMLFastContextHandler
+{
+public:
+ explicit OOXMLFastContextHandlerCommentEx(OOXMLFastContextHandler* pContext);
+
+ virtual std::string getType() const override { return "CommentEx"; }
+ virtual void lcl_endFastElement(Token_t Element) override;
+
+ void att_paraId(const OOXMLValue::Pointer_t& pValue);
+ void att_done(const OOXMLValue::Pointer_t& pValue);
+ void att_paraIdParent(const OOXMLValue::Pointer_t& pValue);
+
+private:
+ OUString m_sParaId;
+ bool m_bDone = false;
+ OUString m_sParentId {};
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.cxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.cxx
new file mode 100644
index 000000000000..0167f0416a26
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.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 <sal/log.hxx>
+#include "OOXMLFastContextHandlerTheme.hxx"
+#include <oox/drawingml/theme.hxx>
+#include <oox/token/namespaces.hxx>
+
+using namespace ::com::sun::star;
+
+namespace writerfilter::ooxml
+{
+OOXMLFastContextHandlerTheme::OOXMLFastContextHandlerTheme(OOXMLFastContextHandler* pContext)
+ : OOXMLFastContextHandler(pContext)
+{
+}
+
+uno::Reference<xml::sax::XFastContextHandler>
+OOXMLFastContextHandlerTheme::lcl_createFastChildContext(
+ Token_t Element, const uno::Reference<xml::sax::XFastAttributeList>& Attribs)
+{
+ if (mpThemeFragmentHandler.is())
+ return mpThemeFragmentHandler->createFastChildContext(Element, Attribs);
+
+ return this;
+}
+
+void OOXMLFastContextHandlerTheme::lcl_startFastElement(
+ Token_t Element, const uno::Reference<xml::sax::XFastAttributeList>& Attribs)
+{
+ if (!mpThemeFragmentHandler.is())
+ {
+ auto xThemeFilterBase = getDocument()->getThemeFilterBase();
+ OUString aThemeFragmentPath
+ = xThemeFilterBase->getFragmentPathFromFirstTypeFromOfficeDoc(u"theme");
+ auto pThemePtr = getDocument()->getTheme();
+ if (!pThemePtr)
+ {
+ pThemePtr = std::make_shared<oox::drawingml::Theme>();
+ auto pTheme = std::make_shared<model::Theme>();
+ pThemePtr->setTheme(pTheme);
+ getDocument()->setTheme(pThemePtr);
+ }
+ mpThemeFragmentHandler = new oox::drawingml::ThemeFragmentHandler(
+ *xThemeFilterBase, aThemeFragmentPath, *pThemePtr, *pThemePtr->getTheme());
+ }
+
+ if (mpThemeFragmentHandler.is())
+ mpThemeFragmentHandler->startFastElement(Element, Attribs);
+}
+
+void OOXMLFastContextHandlerTheme::lcl_endFastElement(Token_t Element)
+{
+ if (mpThemeFragmentHandler.is())
+ mpThemeFragmentHandler->endFastElement(Element);
+}
+
+void OOXMLFastContextHandlerTheme::lcl_characters(const OUString& aChars)
+{
+ if (mpThemeFragmentHandler.is())
+ mpThemeFragmentHandler->characters(aChars);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.hxx b/sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.hxx
new file mode 100644
index 000000000000..9622406f7867
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandlerTheme.hxx
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <docmodel/theme/Theme.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XFastContextHandler.hpp>
+#include <oox/mathml/importutils.hxx>
+#include <oox/drawingml/themefragmenthandler.hxx>
+#include <rtl/ref.hxx>
+#include "OOXMLParserState.hxx"
+#include "OOXMLPropertySet.hxx"
+#include "OOXMLFastContextHandler.hxx"
+
+namespace writerfilter::ooxml
+{
+class OOXMLFastContextHandlerTheme : public OOXMLFastContextHandler
+{
+private:
+ rtl::Reference<oox::drawingml::ThemeFragmentHandler> mpThemeFragmentHandler;
+
+public:
+ explicit OOXMLFastContextHandlerTheme(OOXMLFastContextHandler* pContext);
+ std::string getType() const override { return "Theme"; }
+
+protected:
+ void lcl_startFastElement(
+ Token_t Element,
+ const css::uno::Reference<css::xml::sax::XFastAttributeList>& Attribs) override;
+ void lcl_endFastElement(Token_t Element) override;
+ 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;
+};
+
+} // end namespace writerfilter::ooxml
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.cxx b/sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.cxx
new file mode 100644
index 000000000000..0e831bd35627
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.cxx
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "OOXMLFastDocumentHandler.hxx"
+#include "OOXMLFastContextHandler.hxx"
+#include "OOXMLFactory.hxx"
+#include <sal/log.hxx>
+#include <utility>
+
+namespace writerfilter::ooxml
+{
+using namespace ::com::sun::star;
+
+
+OOXMLFastDocumentHandler::OOXMLFastDocumentHandler(
+ uno::Reference< uno::XComponentContext > context,
+ Stream* pStream,
+ OOXMLDocumentImpl* pDocument,
+ sal_Int32 nXNoteId )
+ : m_xContext(std::move(context))
+ , mpStream( pStream )
+ , mpDocument( pDocument )
+ , mnXNoteId( nXNoteId )
+{
+}
+
+OOXMLFastDocumentHandler::~OOXMLFastDocumentHandler() {}
+
+// css::xml::sax::XFastContextHandler:
+void SAL_CALL OOXMLFastDocumentHandler::startFastElement(sal_Int32 Element
+, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ SAL_INFO("writerfilter", "start element:" << fastTokenToId(Element));
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::startUnknownElement
+(const OUString & Namespace
+, const OUString & Name
+, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ SAL_INFO("writerfilter", "start unknown element:" << Namespace << ":" << Name);
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::endFastElement(sal_Int32 Element)
+{
+ SAL_INFO("writerfilter", "end element:" << fastTokenToId(Element));
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::endUnknownElement
+(const OUString & Namespace
+, const OUString & Name)
+{
+ SAL_INFO("writerfilter", "end unknown element:" << Namespace << ":" << Name);
+}
+
+rtl::Reference< OOXMLFastContextHandler > const &
+OOXMLFastDocumentHandler::getContextHandler() const
+{
+ if (!mxContextHandler.is())
+ {
+ mxContextHandler = new OOXMLFastContextHandler(m_xContext);
+ mxContextHandler->setStream(mpStream);
+ mxContextHandler->setDocument(mpDocument);
+ mxContextHandler->setXNoteId(mnXNoteId);
+ mxContextHandler->setForwardEvents(true);
+ }
+
+ return mxContextHandler;
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+ OOXMLFastDocumentHandler::createFastChildContext
+(::sal_Int32 Element,
+ const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ if ( mpStream == nullptr && mpDocument == nullptr )
+ {
+ // document handler has been created as unknown child - see <OOXMLFastDocumentHandler::createUnknownChildContext(..)>
+ // --> do not provide a child context
+ return nullptr;
+ }
+
+ return OOXMLFactory::createFastChildContextFromStart(getContextHandler().get(), Element);
+}
+
+uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
+OOXMLFastDocumentHandler::createUnknownChildContext
+(const OUString & Namespace
+, const OUString & Name
+, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/)
+{
+ SAL_INFO("writerfilter", "createUnknownChildContext:" << Namespace << ":"<< Name);
+
+ return uno::Reference< xml::sax::XFastContextHandler >
+ ( new OOXMLFastDocumentHandler( m_xContext, nullptr, nullptr, 0 ) );
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::characters(const OUString & /*aChars*/)
+{
+}
+
+// css::xml::sax::XFastDocumentHandler:
+void SAL_CALL OOXMLFastDocumentHandler::startDocument()
+{
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::endDocument()
+{
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::processingInstruction( const OUString& /*rTarget*/, const OUString& /*rData*/ )
+{
+}
+
+void SAL_CALL OOXMLFastDocumentHandler::setDocumentLocator
+(const uno::Reference< xml::sax::XLocator > & /*xLocator*/)
+{
+}
+
+void OOXMLFastDocumentHandler::setIsSubstream( bool bSubstream )
+{
+ if ( mpStream != nullptr && mpDocument != nullptr )
+ {
+ getContextHandler( )->getParserState( )->setInSectionGroup( bSubstream );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.hxx b/sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.hxx
new file mode 100644
index 000000000000..3d28d2bd742c
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastDocumentHandler.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
+#include <dmapper/resourcemodel.hxx>
+#include <ooxml/OOXMLDocumentImpl.hxx>
+#include <rtl/ref.hxx>
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLFastContextHandler;
+
+class OOXMLFastDocumentHandler : public cppu::WeakImplHelper<css::xml::sax::XFastDocumentHandler>
+{
+public:
+ OOXMLFastDocumentHandler(
+ css::uno::Reference< css::uno::XComponentContext > context,
+ Stream* pStream,
+ OOXMLDocumentImpl* pDocument,
+ sal_Int32 nXNoteId );
+ virtual ~OOXMLFastDocumentHandler() override;
+
+ // css::xml::sax::XFastDocumentHandler:
+ virtual void SAL_CALL startDocument() override;
+ virtual void SAL_CALL endDocument() override;
+ virtual void SAL_CALL processingInstruction( const OUString& rTarget, const OUString& rData ) override;
+ virtual void SAL_CALL setDocumentLocator
+ (const css::uno::Reference< css::xml::sax::XLocator > & xLocator) override;
+
+ // css::xml::sax::XFastContextHandler:
+ virtual void SAL_CALL startFastElement
+ (::sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual void SAL_CALL startUnknownElement
+ (const OUString & Namespace,
+ const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual void SAL_CALL endFastElement(::sal_Int32 Element) override;
+ virtual void SAL_CALL endUnknownElement
+ (const OUString & Namespace,
+ const OUString & Name) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
+ createFastChildContext
+ (::sal_Int32 Element,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL
+ createUnknownChildContext
+ (const OUString & Namespace,
+ const OUString & Name,
+ const css::uno::Reference< css::xml::sax::XFastAttributeList > & Attribs) override;
+ virtual void SAL_CALL characters(const OUString & aChars) override;
+
+ void setIsSubstream( bool bSubstream );
+
+private:
+ OOXMLFastDocumentHandler(OOXMLFastDocumentHandler const &) = delete;
+ void operator =(OOXMLFastDocumentHandler const &) = delete;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ Stream * mpStream;
+ OOXMLDocumentImpl* mpDocument;
+ sal_Int32 mnXNoteId;
+ mutable rtl::Reference<OOXMLFastContextHandler> mxContextHandler;
+ rtl::Reference<OOXMLFastContextHandler> const & getContextHandler() const;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastHelper.hxx b/sw/source/writerfilter/ooxml/OOXMLFastHelper.hxx
new file mode 100644
index 000000000000..ecb8b6943b11
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLFastHelper.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "OOXMLFastContextHandler.hxx"
+
+namespace writerfilter::ooxml
+{
+
+template <class T>
+class OOXMLFastHelper
+{
+public:
+ static rtl::Reference<OOXMLFastContextHandler> createAndSetParentAndDefine
+ (OOXMLFastContextHandler * pHandler, sal_uInt32 nToken, Id nId, Id nDefine);
+
+ static void newProperty(OOXMLFastContextHandler * pHandler,
+ Id nId, sal_Int32 nValue);
+};
+
+template <class T>
+rtl::Reference<OOXMLFastContextHandler> OOXMLFastHelper<T>::createAndSetParentAndDefine (OOXMLFastContextHandler * pHandler, sal_uInt32 nToken, Id nId, Id nDefine)
+{
+ rtl::Reference<OOXMLFastContextHandler> pTmp = new T(pHandler);
+
+ pTmp->setToken(nToken);
+ pTmp->setId(nId);
+ pTmp->setDefine(nDefine);
+
+ return pTmp;
+}
+
+template <class T>
+void OOXMLFastHelper<T>::newProperty(OOXMLFastContextHandler * pHandler,
+ Id nId,
+ sal_Int32 nVal)
+{
+ OOXMLValue::Pointer_t pVal(T::Create(nVal));
+
+ pHandler->newProperty(nId, pVal);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLParserState.cxx b/sw/source/writerfilter/ooxml/OOXMLParserState.cxx
new file mode 100644
index 000000000000..b8cc55377b5b
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLParserState.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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),
+ m_inTxbxContent(false),
+ m_savedInParagraphGroup(false),
+ m_savedInCharacterGroup(false),
+ m_savedLastParagraphInSection(false),
+ mbStartFootnote(false)
+{
+}
+
+OOXMLParserState::~OOXMLParserState()
+{
+}
+
+void OOXMLParserState::setLastParagraphInSection(bool bLastParagraphInSection)
+{
+ mbLastParagraphInSection = bLastParagraphInSection;
+}
+
+
+void OOXMLParserState::setInSectionGroup(bool bInSectionGroup)
+{
+ mbInSectionGroup = bInSectionGroup;
+}
+
+
+void OOXMLParserState::setInParagraphGroup(bool bInParagraphGroup)
+{
+ mbInParagraphGroup = bInParagraphGroup;
+}
+
+
+void OOXMLParserState::setInCharacterGroup(bool bInCharacterGroup)
+{
+ mbInCharacterGroup = bInCharacterGroup;
+}
+
+void OOXMLParserState::setForwardEvents(bool bForwardEvents)
+{
+ mbForwardEvents = bForwardEvents;
+}
+
+
+std::string OOXMLParserState::getHandle() const
+{
+ return std::to_string(mnHandle);
+}
+
+void OOXMLParserState::setHandle()
+{
+ mnHandle = mnContexts;
+}
+
+void OOXMLParserState::setDocument(OOXMLDocumentImpl* pDocument)
+{
+ mpDocument = pDocument;
+}
+
+
+void OOXMLParserState::setXNoteId(const sal_Int32 nId)
+{
+ mpDocument->setXNoteId(nId);
+}
+
+sal_Int32 OOXMLParserState::getXNoteId() const
+{
+ return mpDocument->getXNoteId();
+}
+
+const OUString & OOXMLParserState::getTarget() const
+{
+ return mpDocument->getTarget();
+}
+
+void OOXMLParserState::resolveCharacterProperties(Stream & rStream)
+{
+ if (mpCharacterProps)
+ {
+ rStream.props(mpCharacterProps.get());
+ mpCharacterProps = new OOXMLPropertySet;
+ }
+}
+
+void OOXMLParserState::setCharacterProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mpCharacterProps)
+ mpCharacterProps = pProps;
+ else
+ mpCharacterProps->add(pProps);
+}
+
+void OOXMLParserState::setCellProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mCellProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rCellProps = mCellProps.top();
+
+ if (!rCellProps)
+ rCellProps = pProps;
+ else
+ rCellProps->add(pProps);
+ }
+}
+
+void OOXMLParserState::setRowProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mRowProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rRowProps = mRowProps.top();
+
+ if (!rRowProps)
+ rRowProps = pProps;
+ else
+ rRowProps->add(pProps);
+ }
+}
+
+void OOXMLParserState::resolveCellProperties(Stream & rStream)
+{
+ if (!mCellProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rCellProps = mCellProps.top();
+
+ if (rCellProps)
+ {
+ rStream.props(rCellProps.get());
+ rCellProps = new OOXMLPropertySet;
+ }
+ }
+}
+
+void OOXMLParserState::resolveRowProperties(Stream & rStream)
+{
+ if (!mRowProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rRowProps = mRowProps.top();
+
+ if (rRowProps)
+ {
+ rStream.props(rRowProps.get());
+ rRowProps = new OOXMLPropertySet;
+ }
+ }
+}
+
+void OOXMLParserState::resolveTableProperties(Stream & rStream)
+{
+ if (!mTableProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rTableProps = mTableProps.top();
+
+ if (rTableProps)
+ {
+ rStream.props(rTableProps.get());
+ // Don't clean the table props to send them again for each row
+ // This mimics the behaviour from RTF tokenizer.
+ }
+ }
+}
+
+void OOXMLParserState::setTableProperties(const OOXMLPropertySet::Pointer_t& pProps)
+{
+ if (!mTableProps.empty())
+ {
+ OOXMLPropertySet::Pointer_t & rTableProps = mTableProps.top();
+ if (!rTableProps)
+ rTableProps = pProps;
+ else
+ rTableProps->add(pProps);
+ }
+}
+
+OOXMLPropertySet::Pointer_t OOXMLParserState::GetTableProperties() const
+{
+ if (mTableProps.empty())
+ {
+ return nullptr;
+ }
+
+ return mTableProps.top();
+}
+
+// tdf#108714
+void OOXMLParserState::resolvePostponedBreak(Stream & rStream)
+{
+ for (const auto & rBreak: mvPostponedBreaks)
+ {
+ OOXMLBreakHandler aBreakHandler(nullptr, rStream);
+ rBreak->resolve(aBreakHandler);
+ }
+ mvPostponedBreaks.clear();
+}
+
+void OOXMLParserState::setPostponedBreak(const OOXMLPropertySet::Pointer_t & pProps)
+{
+ mvPostponedBreaks.push_back(pProps);
+}
+
+void OOXMLParserState::startTable()
+{
+ OOXMLPropertySet::Pointer_t pCellProps;
+ OOXMLPropertySet::Pointer_t pRowProps;
+ OOXMLPropertySet::Pointer_t pTableProps;
+
+ mCellProps.push(pCellProps);
+ mRowProps.push(pRowProps);
+ mTableProps.push(pTableProps);
+}
+
+void OOXMLParserState::endTable()
+{
+ mCellProps.pop();
+ mRowProps.pop();
+ mTableProps.pop();
+}
+
+void OOXMLParserState::incContextCount()
+{
+ mnContexts++;
+}
+
+void OOXMLParserState::startTxbxContent()
+{
+ SAL_WARN_IF(m_inTxbxContent, "writerfilter", "Nested w:txbxContent");
+
+ m_inTxbxContent = true;
+ // Do not save and reset section group state, it'd cause a new page.
+// savedInSectionGroup = mbInSectionGroup;
+ m_savedInParagraphGroup = mbInParagraphGroup;
+ m_savedInCharacterGroup = mbInCharacterGroup;
+ m_savedLastParagraphInSection = mbLastParagraphInSection;
+// mbInSectionGroup = false;
+ mbInParagraphGroup = false;
+ mbInCharacterGroup = false;
+ mbLastParagraphInSection = false;
+}
+
+void OOXMLParserState::endTxbxContent()
+{
+ if( !m_inTxbxContent )
+ {
+ SAL_WARN( "writerfilter", "Non-matching closing w:txbxContent" );
+ return;
+ }
+// mbInSectionGroup = savedInSectionGroup;
+ mbInParagraphGroup = m_savedInParagraphGroup;
+ mbInCharacterGroup = m_savedInCharacterGroup;
+ mbLastParagraphInSection = m_savedLastParagraphInSection;
+ m_inTxbxContent = false;
+}
+
+void OOXMLParserState::setStartFootnote(bool bStartFootnote)
+{
+ mbStartFootnote = bStartFootnote;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLParserState.hxx b/sw/source/writerfilter/ooxml/OOXMLParserState.hxx
new file mode 100644
index 000000000000..626f8cdf326c
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLParserState.hxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <stack>
+#include "OOXMLDocumentImpl.hxx"
+#include "OOXMLPropertySet.hxx"
+
+namespace writerfilter::ooxml
+{
+/**
+ * Struct to store our 'alternate state'. If multiple mc:AlternateContent
+ * elements arrive, then while the inner ones are active, the original state is
+ * saved away, and once they inner goes out of scope, the original state is
+ * restored.
+ */
+struct SavedAlternateState
+{
+ bool m_bDiscardChildren;
+ bool m_bTookChoice; ///< Did we take the Choice or want Fallback instead?
+};
+
+class OOXMLParserState final : public virtual SvRefBase
+{
+ bool mbInSectionGroup;
+ bool mbInParagraphGroup;
+ bool mbInCharacterGroup;
+ bool mbLastParagraphInSection;
+ bool mbForwardEvents;
+ unsigned int mnContexts;
+ unsigned int mnHandle;
+ OOXMLDocumentImpl* mpDocument;
+ OOXMLPropertySet::Pointer_t mpCharacterProps;
+ std::stack<OOXMLPropertySet::Pointer_t> mCellProps;
+ std::stack<OOXMLPropertySet::Pointer_t> mRowProps;
+ std::stack<OOXMLPropertySet::Pointer_t> mTableProps;
+ bool m_inTxbxContent;
+ // these 4 save when inTxbxContent
+ bool m_savedInParagraphGroup;
+ bool m_savedInCharacterGroup;
+ bool m_savedLastParagraphInSection;
+ std::vector<SavedAlternateState> maSavedAlternateStates;
+ std::vector<OOXMLPropertySet::Pointer_t> mvPostponedBreaks;
+ bool mbStartFootnote;
+ /// We just ended a floating table. Starting a paragraph or table resets this.
+ bool m_bFloatingTableEnded = false;
+
+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);
+ OOXMLPropertySet::Pointer_t GetTableProperties() const;
+ // tdf#108714
+ void resolvePostponedBreak(Stream& rStream);
+ void setPostponedBreak(const OOXMLPropertySet::Pointer_t& pProps);
+
+ void startTable();
+ void endTable();
+
+ void incContextCount();
+
+ void startTxbxContent();
+ void endTxbxContent();
+
+ void setStartFootnote(bool bStartFootnote);
+ bool isStartFootnote() const { return mbStartFootnote; }
+
+ void SetFloatingTableEnded(bool bFloatingTableEnded)
+ {
+ m_bFloatingTableEnded = bFloatingTableEnded;
+ }
+ bool GetFloatingTableEnded() const { return m_bFloatingTableEnded; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLPropertySet.cxx b/sw/source/writerfilter/ooxml/OOXMLPropertySet.cxx
new file mode 100644
index 000000000000..f29efe875aee
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLPropertySet.cxx
@@ -0,0 +1,844 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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>
+#include <o3tl/string_view.hxx>
+#include <utility>
+
+namespace writerfilter::ooxml
+{
+using namespace com::sun::star;
+
+OOXMLProperty::OOXMLProperty(Id id, OOXMLValue::Pointer_t pValue,
+ OOXMLProperty::Type_t eType)
+ : mId(id), mpValue(std::move(pValue)), meType(eType)
+{
+}
+
+OOXMLProperty::~OOXMLProperty()
+{
+}
+
+sal_uInt32 OOXMLProperty::getId() const
+{
+ return mId;
+}
+
+Value::Pointer_t OOXMLProperty::getValue()
+{
+ Value::Pointer_t pResult;
+
+ if (mpValue)
+ pResult = Value::Pointer_t(mpValue->clone());
+ else
+ pResult = Value::Pointer_t(new OOXMLValue());
+
+ return pResult;
+}
+
+writerfilter::Reference<Properties>::Pointer_t OOXMLProperty::getProps()
+{
+ writerfilter::Reference<Properties>::Pointer_t pResult;
+
+ if (mpValue)
+ pResult = mpValue->getProperties();
+
+ return pResult;
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLProperty::getName() const
+{
+ std::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
+std::string OOXMLProperty::toString() const
+{
+ std::string sResult = "(";
+
+ sResult += getName();
+ sResult += ", ";
+ if (mpValue)
+ sResult += mpValue->toString();
+ else
+ sResult +="(null)";
+ sResult +=")";
+
+ return sResult;
+}
+#endif
+
+void OOXMLProperty::resolve(writerfilter::Properties & rProperties)
+{
+ switch (meType)
+ {
+ case SPRM:
+ if (mId != 0x0)
+ rProperties.sprm(*this);
+ break;
+ case ATTRIBUTE:
+ rProperties.attribute(mId, *getValue());
+ break;
+ }
+}
+
+/*
+ class OOXMLValue
+*/
+
+OOXMLValue::OOXMLValue()
+{
+}
+
+OOXMLValue::~OOXMLValue()
+{
+}
+
+int OOXMLValue::getInt() const
+{
+ return 0;
+}
+
+OUString OOXMLValue::getString() const
+{
+ return OUString();
+}
+
+uno::Any OOXMLValue::getAny() const
+{
+ return uno::Any();
+}
+
+writerfilter::Reference<Properties>::Pointer_t OOXMLValue::getProperties()
+{
+ return writerfilter::Reference<Properties>::Pointer_t();
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t OOXMLValue::getBinary()
+{
+ return writerfilter::Reference<BinaryObj>::Pointer_t();
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLValue::toString() const
+{
+ return "OOXMLValue";
+}
+#endif
+
+OOXMLValue * OOXMLValue::clone() const
+{
+ return new OOXMLValue(*this);
+}
+
+/*
+ class OOXMLBinaryValue
+ */
+
+OOXMLBinaryValue::OOXMLBinaryValue(OOXMLBinaryObjectReference::Pointer_t pBinaryObj)
+: mpBinaryObj(std::move(pBinaryObj))
+{
+}
+
+OOXMLBinaryValue::~OOXMLBinaryValue()
+{
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t OOXMLBinaryValue::getBinary()
+{
+ return mpBinaryObj;
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLBinaryValue::toString() const
+{
+ return "BinaryObj";
+}
+#endif
+
+OOXMLValue * OOXMLBinaryValue::clone() const
+{
+ return new OOXMLBinaryValue(mpBinaryObj);
+}
+
+/*
+ class OOXMLBooleanValue
+*/
+
+bool GetBooleanValue(std::string_view pValue)
+{
+ return pValue == "true"
+ || pValue == "True"
+ || pValue == "1"
+ || pValue == "on"
+ || 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(std::string_view 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
+std::string OOXMLBooleanValue::toString() const
+{
+ return mbValue ? "true" : "false";
+}
+#endif
+
+OOXMLValue * OOXMLBooleanValue::clone() const
+{
+ return new OOXMLBooleanValue(*this);
+}
+
+/*
+ class OOXMLStringValue
+*/
+
+OOXMLStringValue::OOXMLStringValue(OUString sStr)
+: mStr(std::move(sStr))
+{
+}
+
+OOXMLStringValue::~OOXMLStringValue()
+{
+}
+
+uno::Any OOXMLStringValue::getAny() const
+{
+ return uno::Any(mStr);
+}
+
+OUString OOXMLStringValue::getString() const
+{
+ return mStr;
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLStringValue::toString() const
+{
+ return std::string(OUStringToOString(mStr, RTL_TEXTENCODING_ASCII_US));
+}
+#endif
+
+OOXMLValue * OOXMLStringValue::clone() const
+{
+ return new OOXMLStringValue(*this);
+}
+
+/*
+ class OOXMLInputStreamValue
+ */
+OOXMLInputStreamValue::OOXMLInputStreamValue(uno::Reference<io::XInputStream> xInputStream)
+: mxInputStream(std::move(xInputStream))
+{
+}
+
+OOXMLInputStreamValue::~OOXMLInputStreamValue()
+{
+}
+
+uno::Any OOXMLInputStreamValue::getAny() const
+{
+ return uno::Any(mxInputStream);
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLInputStreamValue::toString() const
+{
+ return "InputStream";
+}
+#endif
+
+OOXMLValue * OOXMLInputStreamValue::clone() const
+{
+ return new OOXMLInputStreamValue(mxInputStream);
+}
+
+/**
+ class OOXMLPropertySet
+*/
+
+OOXMLPropertySet::OOXMLPropertySet()
+{
+}
+
+OOXMLPropertySet::~OOXMLPropertySet()
+{
+}
+
+void OOXMLPropertySet::resolve(Properties & rHandler)
+{
+ // The pProp->resolve(rHandler) call below can cause elements to
+ // be appended to mProperties. I don't think it can cause elements
+ // to be deleted. But let's check with < here just to be safe that
+ // the indexing below works.
+ for (size_t nIt = 0; nIt < mProperties.size(); ++nIt)
+ {
+ OOXMLProperty::Pointer_t pProp = mProperties[nIt];
+
+ if (pProp)
+ pProp->resolve(rHandler);
+ }
+}
+
+OOXMLPropertySet::OOXMLProperties_t::iterator OOXMLPropertySet::begin()
+{
+ return mProperties.begin();
+}
+
+OOXMLPropertySet::OOXMLProperties_t::iterator OOXMLPropertySet::end()
+{
+ return mProperties.end();
+}
+
+OOXMLPropertySet::OOXMLProperties_t::const_iterator
+OOXMLPropertySet::begin() const
+{
+ return mProperties.begin();
+}
+
+OOXMLPropertySet::OOXMLProperties_t::const_iterator
+OOXMLPropertySet::end() const
+{
+ return mProperties.end();
+}
+
+void OOXMLPropertySet::add(const OOXMLProperty::Pointer_t& pProperty)
+{
+ if (pProperty && pProperty->getId() != 0x0)
+ {
+ mProperties.push_back(pProperty);
+ }
+}
+
+void OOXMLPropertySet::add(Id id, const OOXMLValue::Pointer_t& pValue, OOXMLProperty::Type_t eType)
+{
+ OOXMLProperty::Pointer_t pProperty(new OOXMLProperty(id, pValue, eType));
+ add(pProperty);
+}
+
+void OOXMLPropertySet::add(const OOXMLPropertySet::Pointer_t& pPropertySet)
+{
+ const OOXMLPropertySet * pSet = pPropertySet.get();
+
+ if (pSet != nullptr)
+ {
+ mProperties.insert( mProperties.end(), pSet->mProperties.begin(), pSet->mProperties.end() );
+ }
+}
+
+OOXMLPropertySet * OOXMLPropertySet::clone() const
+{
+ return new OOXMLPropertySet(*this);
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLPropertySet::toString()
+{
+ std::string sResult = "[";
+ char sBuffer[256];
+ snprintf(sBuffer, sizeof(sBuffer), "%p", this);
+ sResult += sBuffer;
+ sResult += ":";
+
+ OOXMLProperties_t::iterator aItBegin = begin();
+ OOXMLProperties_t::iterator aItEnd = end();
+
+ for (OOXMLProperties_t::iterator aIt = aItBegin; aIt != aItEnd; ++aIt)
+ {
+ if (aIt != aItBegin)
+ sResult += ", ";
+
+ if (*aIt)
+ sResult += (*aIt)->toString();
+ else
+ sResult += "0x0";
+ }
+
+ sResult += "]";
+
+ return sResult;
+}
+#endif
+
+/*
+ class OOXMLPropertySetValue
+*/
+
+OOXMLPropertySetValue::OOXMLPropertySetValue(OOXMLPropertySet::Pointer_t pPropertySet)
+ : mpPropertySet(std::move(pPropertySet))
+{
+}
+
+OOXMLPropertySetValue::~OOXMLPropertySetValue()
+{
+}
+
+writerfilter::Reference<Properties>::Pointer_t OOXMLPropertySetValue::getProperties()
+{
+ return writerfilter::Reference<Properties>::Pointer_t
+ (mpPropertySet->clone());
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLPropertySetValue::toString() const
+{
+ char sBuffer[256];
+
+ snprintf(sBuffer, sizeof(sBuffer), "t:%p, m:%p", this, mpPropertySet.get());
+
+ return "OOXMLPropertySetValue(" + std::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
+std::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(std::string_view pValue)
+: mnValue(o3tl::toUInt32(pValue, 16))
+{
+}
+
+OOXMLHexValue::~OOXMLHexValue()
+{
+}
+
+int OOXMLHexValue::getInt() const
+{
+ return mnValue;
+}
+
+OOXMLValue * OOXMLHexValue::clone() const
+{
+ return new OOXMLHexValue(*this);
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLHexValue::toString() const
+{
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "0x%" SAL_PRIxUINT32, mnValue);
+
+ return buffer;
+}
+#endif
+
+/*
+ class OOXMLHexColorValue
+*/
+OOXMLHexColorValue::OOXMLHexColorValue(std::string_view pValue)
+ : OOXMLHexValue(sal_uInt32(COL_AUTO))
+{
+ if (pValue == "auto")
+ return;
+
+ mnValue = o3tl::toUInt32(pValue, 16);
+
+ // Convert hash-encoded values (like #FF0080)
+ const sal_Int32 nLen = pValue.size();
+ 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.data(), 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(std::string_view pValue, sal_uInt32 npPt)
+{
+ double val = o3tl::toDouble(pValue); // will ignore the trailing unit
+
+ if (pValue.ends_with("pt"))
+ {
+ val *= npPt;
+ }
+ else if (pValue.ends_with("cm"))
+ {
+ val = o3tl::convert(val, o3tl::Length::cm, o3tl::Length::pt) * npPt;
+ }
+ else if (pValue.ends_with("mm"))
+ {
+ val = o3tl::convert(val, o3tl::Length::mm, o3tl::Length::pt) * npPt;
+ }
+ else if (pValue.ends_with("in"))
+ {
+ val = o3tl::convert(val, o3tl::Length::in, o3tl::Length::pt) * npPt;
+ }
+ else if (pValue.ends_with("pc") || pValue.ends_with("pi"))
+ {
+ val = o3tl::convert(val, o3tl::Length::pc, o3tl::Length::pt) * npPt;
+ }
+
+ mnValue = std::round(val);
+}
+
+OOXMLUniversalMeasureValue::~OOXMLUniversalMeasureValue()
+{
+}
+
+int OOXMLUniversalMeasureValue::getInt() const
+{
+ return mnValue;
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLUniversalMeasureValue::toString() const
+{
+ return std::string(OString::number(mnValue));
+}
+#endif
+
+// OOXMLMeasurementOrPercentValue
+// ECMA-376 5th ed. Part 1 , 17.18.107; 17.18.11
+OOXMLMeasurementOrPercentValue::OOXMLMeasurementOrPercentValue(std::string_view pValue)
+{
+ double val = o3tl::toDouble(pValue); // will ignore the trailing unit
+
+ int nLen = pValue.size();
+ 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
+std::string OOXMLMeasurementOrPercentValue::toString() const
+{
+ return std::string(OString::number(mnValue));
+}
+#endif
+
+/*
+ class OOXMLShapeValue
+ */
+
+
+OOXMLShapeValue::OOXMLShapeValue(uno::Reference<drawing::XShape> xShape)
+: mrShape(std::move(xShape))
+{
+}
+
+OOXMLShapeValue::~OOXMLShapeValue()
+{
+}
+
+uno::Any OOXMLShapeValue::getAny() const
+{
+ return uno::Any(mrShape);
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLShapeValue::toString() const
+{
+ return "Shape";
+}
+#endif
+
+OOXMLValue * OOXMLShapeValue::clone() const
+{
+ return new OOXMLShapeValue(mrShape);
+}
+
+/*
+ class OOXMLStarMathValue
+ */
+
+
+OOXMLStarMathValue::OOXMLStarMathValue( uno::Reference< embed::XEmbeddedObject > c )
+: m_component(std::move(c))
+{
+}
+
+OOXMLStarMathValue::~OOXMLStarMathValue()
+{
+}
+
+uno::Any OOXMLStarMathValue::getAny() const
+{
+ return uno::Any(m_component);
+}
+
+#ifdef DBG_UTIL
+std::string OOXMLStarMathValue::toString() const
+{
+ return "StarMath";
+}
+#endif
+
+OOXMLValue * OOXMLStarMathValue::clone() const
+{
+ return new OOXMLStarMathValue( m_component );
+}
+
+/*
+ class OOXMLTableImpl
+ */
+
+OOXMLTable::OOXMLTable()
+{
+}
+
+OOXMLTable::~OOXMLTable()
+{
+}
+
+
+void OOXMLTable::resolve(Table & rTable)
+{
+ Table * pTable = &rTable;
+
+ int nPos = 0;
+
+ for (const auto& rPropSet : mPropertySets)
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ (rPropSet->getProperties());
+
+ if (pProperties)
+ pTable->entry(nPos, pProperties);
+
+ ++nPos;
+ }
+}
+
+void OOXMLTable::add(const ValuePointer_t& pPropertySet)
+{
+ if (pPropertySet)
+ mPropertySets.push_back(pPropertySet);
+}
+
+OOXMLTable * OOXMLTable::clone() const
+{
+ return new OOXMLTable(*this);
+}
+
+/*
+ class: OOXMLPropertySetEntryToString
+*/
+
+OOXMLPropertySetEntryToString::OOXMLPropertySetEntryToString(Id nId)
+: mnId(nId)
+{
+}
+
+OOXMLPropertySetEntryToString::~OOXMLPropertySetEntryToString()
+{
+}
+
+void OOXMLPropertySetEntryToString::sprm(Sprm & /*rSprm*/)
+{
+}
+
+void OOXMLPropertySetEntryToString::attribute(Id nId, Value & rValue)
+{
+ if (nId == mnId)
+ mStr = rValue.getString();
+}
+
+/*
+ class: OOXMLPropertySetEntryToInteger
+*/
+
+OOXMLPropertySetEntryToInteger::OOXMLPropertySetEntryToInteger(Id nId)
+: mnId(nId), mnValue(0)
+{
+}
+
+OOXMLPropertySetEntryToInteger::~OOXMLPropertySetEntryToInteger()
+{
+}
+
+void OOXMLPropertySetEntryToInteger::sprm(Sprm & /*rSprm*/)
+{
+}
+
+void OOXMLPropertySetEntryToInteger::attribute(Id nId, Value & rValue)
+{
+ if (nId == mnId)
+ mnValue = rValue.getInt();
+}
+
+/*
+ class: OOXMLPropertySetEntryToBool
+*/
+
+OOXMLPropertySetEntryToBool::OOXMLPropertySetEntryToBool(Id nId)
+ : mnId(nId), mValue(false)
+{}
+
+OOXMLPropertySetEntryToBool::~OOXMLPropertySetEntryToBool() {}
+
+void OOXMLPropertySetEntryToBool::sprm(Sprm & /*rSprm*/) {}
+
+void OOXMLPropertySetEntryToBool::attribute(Id nId, Value & rValue)
+{
+ if (nId == mnId)
+ mValue = (rValue.getInt() != 0);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLPropertySet.hxx b/sw/source/writerfilter/ooxml/OOXMLPropertySet.hxx
new file mode 100644
index 000000000000..465873963a78
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLPropertySet.hxx
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+#include "OOXMLBinaryObjectReference.hxx"
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::ooxml
+{
+class OOXMLValue : public Value
+{
+public:
+ typedef tools::SvRef<OOXMLValue> Pointer_t;
+ OOXMLValue();
+ virtual ~OOXMLValue() override;
+
+ OOXMLValue(OOXMLValue const&) = default;
+ OOXMLValue(OOXMLValue&&) = default;
+ OOXMLValue& operator=(OOXMLValue const&) = default;
+ OOXMLValue& operator=(OOXMLValue&&) = default;
+
+ virtual int getInt() const override;
+ ;
+ virtual OUString getString() const override;
+ virtual css::uno::Any getAny() const override;
+ virtual writerfilter::Reference<Properties>::Pointer_t getProperties() override;
+ virtual writerfilter::Reference<BinaryObj>::Pointer_t getBinary() override;
+#ifdef DBG_UTIL
+ virtual std::string toString() const override;
+#endif
+ virtual OOXMLValue* clone() const;
+};
+
+class OOXMLProperty final : 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, 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 final : public OOXMLValue
+{
+ mutable OOXMLBinaryObjectReference::Pointer_t mpBinaryObj;
+
+public:
+ explicit OOXMLBinaryValue(OOXMLBinaryObjectReference::Pointer_t 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;
+};
+
+bool GetBooleanValue(std::string_view pValue);
+
+class OOXMLBooleanValue final : public OOXMLValue
+{
+ bool mbValue;
+ explicit OOXMLBooleanValue(bool bValue);
+
+public:
+ static OOXMLValue::Pointer_t const& Create(bool bValue);
+ static OOXMLValue::Pointer_t const& Create(std::string_view 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 final : public OOXMLValue
+{
+ OUString mStr;
+
+public:
+ explicit OOXMLStringValue(OUString sStr);
+ 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 final : public OOXMLValue
+{
+ css::uno::Reference<css::io::XInputStream> mxInputStream;
+
+public:
+ explicit OOXMLInputStreamValue(css::uno::Reference<css::io::XInputStream> 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 final : 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 final : 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 final : public OOXMLValue
+{
+ OOXMLPropertySet::Pointer_t mpPropertySet;
+
+public:
+ explicit OOXMLPropertySetValue(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 final : 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(std::string_view 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 final : public OOXMLHexValue
+{
+public:
+ explicit OOXMLHexColorValue(std::string_view pValue);
+};
+
+class OOXMLUniversalMeasureValue : public OOXMLValue
+{
+private:
+ int mnValue;
+
+public:
+ OOXMLUniversalMeasureValue(std::string_view 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 final : public OOXMLUniversalMeasureValue
+{
+public:
+ explicit OOXMLNthPtMeasureValue(std::string_view 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 final : public OOXMLValue
+{
+ int mnValue;
+
+public:
+ explicit OOXMLMeasurementOrPercentValue(std::string_view 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 final : public OOXMLValue
+{
+ css::uno::Reference<css::drawing::XShape> mrShape;
+
+public:
+ explicit OOXMLShapeValue(css::uno::Reference<css::drawing::XShape> xShape);
+ 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 final : public OOXMLValue
+{
+ css::uno::Reference<css::embed::XEmbeddedObject> m_component;
+
+public:
+ explicit OOXMLStarMathValue(css::uno::Reference<css::embed::XEmbeddedObject> 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 final : 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 final : 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 final : public Properties
+{
+ Id mnId;
+ bool mValue;
+
+public:
+ explicit OOXMLPropertySetEntryToBool(Id nId);
+ virtual ~OOXMLPropertySetEntryToBool() override;
+
+ virtual void sprm(Sprm& rSprm) override;
+ virtual void attribute(Id nId, Value& rValue) override;
+
+ bool getValue() const { return mValue; }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLStreamImpl.cxx b/sw/source/writerfilter/ooxml/OOXMLStreamImpl.cxx
new file mode 100644
index 000000000000..aa2567ad53b2
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLStreamImpl.cxx
@@ -0,0 +1,449 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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>
+#include <utility>
+
+namespace writerfilter::ooxml
+{
+
+using namespace com::sun::star;
+
+OOXMLStreamImpl::OOXMLStreamImpl
+(uno::Reference<uno::XComponentContext> const & xContext,
+ uno::Reference<io::XInputStream> xStorageStream,
+ StreamType_t nType, bool bRepairStorage)
+: mxContext(xContext), mxStorageStream(std::move(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, OUString sId)
+: mxContext(rOOXMLStream.mxContext),
+ mxStorageStream(rOOXMLStream.mxStorageStream),
+ mxStorage(rOOXMLStream.mxStorage),
+ mnStreamType(UNKNOWN),
+ msId(std::move(sId)),
+ 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 constexpr OUStringLiteral sDocumentType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
+ static constexpr OUStringLiteral sStylesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
+ static constexpr OUStringLiteral sNumberingType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
+ static constexpr OUStringLiteral sFonttableType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable";
+ static constexpr OUStringLiteral sFootnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes";
+ static constexpr OUStringLiteral sEndnotesType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes";
+ static constexpr OUStringLiteral sCommentsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
+ static constexpr OUStringLiteral sThemeType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
+ static constexpr OUString sCustomType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml"_ustr;
+ static constexpr OUStringLiteral sCustomPropsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps";
+ static constexpr OUStringLiteral sGlossaryType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument";
+ static constexpr OUStringLiteral sWebSettings = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings";
+ static constexpr OUStringLiteral sSettingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings";
+ static constexpr OUString sChartType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"_ustr;
+ static constexpr OUString sEmbeddingsType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/package"_ustr;
+ static constexpr OUString sFooterType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer"_ustr;
+ static constexpr OUString sHeaderType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header"_ustr;
+ static constexpr OUStringLiteral sOleObjectType = u"http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";
+ static constexpr OUString sCommentsExtendedType = u"http://schemas.microsoft.com/office/2011/relationships/commentsExtended"_ustr;
+ // OOXML strict
+ static constexpr OUStringLiteral sDocumentTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument";
+ static constexpr OUStringLiteral sStylesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/styles";
+ static constexpr OUStringLiteral sNumberingTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/numbering";
+ static constexpr OUStringLiteral sFonttableTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/fontTable";
+ static constexpr OUStringLiteral sFootnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footnotes";
+ static constexpr OUStringLiteral sEndnotesTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/endnotes";
+ static constexpr OUStringLiteral sCommentsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/comments";
+ static constexpr OUStringLiteral sThemeTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/theme";
+ static constexpr OUStringLiteral sCustomTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXml";
+ static constexpr OUStringLiteral sCustomPropsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/customXmlProps";
+ static constexpr OUStringLiteral sGlossaryTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/glossaryDocument";
+ static constexpr OUStringLiteral sWebSettingsStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/webSettings";
+ static constexpr OUStringLiteral sSettingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/settings";
+ static constexpr OUStringLiteral sChartTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/chart";
+ static constexpr OUStringLiteral sEmbeddingsTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/package";
+ static constexpr OUStringLiteral sFootersTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/footer";
+ static constexpr OUStringLiteral sHeaderTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/header";
+ static constexpr OUStringLiteral sOleObjectTypeStrict = u"http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject";
+ static constexpr OUString sVBAProjectType = u"http://schemas.microsoft.com/office/2006/relationships/vbaProject"_ustr;
+ static constexpr OUString sVBADataType = u"http://schemas.microsoft.com/office/2006/relationships/wordVbaData"_ustr;
+
+ OUString sStreamType;
+ OUString sStreamTypeStrict;
+
+ switch (nStreamType)
+ {
+ case VBAPROJECT:
+ sStreamType = sVBAProjectType;
+ sStreamTypeStrict = sVBAProjectType;
+ break;
+ case VBADATA:
+ sStreamType = sVBADataType;
+ sStreamTypeStrict = sVBADataType;
+ break;
+ case DOCUMENT:
+ sStreamType = sDocumentType;
+ sStreamTypeStrict = sDocumentTypeStrict;
+ break;
+ case STYLES:
+ sStreamType = sStylesType;
+ sStreamTypeStrict = sStylesTypeStrict;
+ break;
+ case NUMBERING:
+ sStreamType = sNumberingType;
+ sStreamTypeStrict = sNumberingTypeStrict;
+ break;
+ case FONTTABLE:
+ sStreamType = sFonttableType;
+ sStreamTypeStrict = sFonttableTypeStrict;
+ break;
+ case FOOTNOTES:
+ sStreamType = sFootnotesType;
+ sStreamTypeStrict = sFootnotesTypeStrict;
+ break;
+ case ENDNOTES:
+ sStreamType = sEndnotesType;
+ sStreamTypeStrict = sEndnotesTypeStrict;
+ break;
+ case COMMENTS:
+ sStreamType = sCommentsType;
+ sStreamTypeStrict = sCommentsTypeStrict;
+ break;
+ case THEME:
+ sStreamType = sThemeType;
+ sStreamTypeStrict = sThemeTypeStrict;
+ break;
+ case CUSTOMXML:
+ sStreamType = sCustomType;
+ sStreamTypeStrict = sCustomTypeStrict;
+ break;
+ case CUSTOMXMLPROPS:
+ sStreamType = sCustomPropsType;
+ sStreamTypeStrict = sCustomPropsTypeStrict;
+ break;
+ case SETTINGS:
+ sStreamType = sSettingsType;
+ sStreamTypeStrict = sSettingsTypeStrict;
+ break;
+ case GLOSSARY:
+ sStreamType = sGlossaryType;
+ sStreamTypeStrict = sGlossaryTypeStrict;
+ break;
+ case WEBSETTINGS:
+ sStreamType = sWebSettings;
+ sStreamTypeStrict = sWebSettingsStrict;
+ break;
+ case CHARTS:
+ sStreamType = sChartType;
+ sStreamTypeStrict = sChartTypeStrict;
+ break;
+ case EMBEDDINGS:
+ sStreamType = sEmbeddingsType;
+ sStreamTypeStrict = sEmbeddingsTypeStrict;
+ break;
+ case FOOTER:
+ sStreamType = sFooterType;
+ sStreamTypeStrict = sFootersTypeStrict;
+ break;
+ case HEADER:
+ sStreamType = sHeaderType;
+ sStreamTypeStrict = sHeaderTypeStrict;
+ break;
+ case COMMENTS_EXTENDED:
+ sStreamType = sCommentsExtendedType;
+ sStreamTypeStrict = sCommentsExtendedType;
+ break;
+ default:
+ break;
+ }
+
+ if (xRelationshipAccess.is())
+ {
+ const uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
+ xRelationshipAccess->getAllRelationships();
+
+ for (const uno::Sequence< beans::StringPair > &rSeq : aSeqs)
+ {
+ bool bExternalTarget = false;
+ OUString sMyTarget;
+ for (const beans::StringPair &rPair : rSeq)
+ {
+ if (rPair.First == sType &&
+ ( rPair.Second == sStreamType ||
+ rPair.Second == sStreamTypeStrict ))
+ bFound = true;
+ else if(rPair.First == sType &&
+ ((rPair.Second == sOleObjectType ||
+ rPair.Second == sOleObjectTypeStrict) &&
+ nStreamType == EMBEDDINGS))
+ {
+ bFound = true;
+ }
+ else if (rPair.First == sId &&
+ rPair.Second == rId)
+ bFound = true;
+ else if (rPair.First == sTarget)
+ {
+ // checking item[n].xml is not visited already.
+ if(customTarget != rPair.Second && (sStreamType == sCustomType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
+ {
+ bFound = false;
+ }
+ else
+ {
+ sMyTarget = rPair.Second;
+ }
+ }
+ else if (rPair.First == sTargetMode &&
+ rPair.Second == sExternal)
+ bExternalTarget = true;
+ }
+
+ if (bFound)
+ {
+ if (bExternalTarget)
+ rDocumentTarget = sMyTarget;
+ else
+ {
+ // 'Target' is a relative Uri, so a 'Target=/path'
+ // with a base Uri of file://base/foo will resolve to
+ // file://base/word. We need something more than some
+ // simple string concatenation here to handle that.
+ uno::Reference<uri::XUriReference> xPart = xFac->parse(sMyTarget);
+ uno::Reference<uri::XUriReference> xAbs = xFac->makeAbsolute(xBase, xPart, true, uri::RelativeUriExcessParentSegments_RETAIN);
+ if (!xAbs)
+ {
+ //it was invalid gibberish
+ bFound = false;
+ }
+ else
+ {
+ rDocumentTarget = xAbs->getPath();
+ // path will start with the fragment separator. need to
+ // remove that
+ rDocumentTarget = rDocumentTarget.copy( 1 );
+ if(sStreamType == sEmbeddingsType)
+ embeddingsTarget = rDocumentTarget;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+OUString OOXMLStreamImpl::getTargetForId(const OUString & rId)
+{
+ OUString sTarget;
+
+ uno::Reference<embed::XRelationshipAccess> xRelationshipAccess
+ (mxDocumentStream, uno::UNO_QUERY_THROW);
+
+ if (lcl_getTarget(xRelationshipAccess, UNKNOWN, rId, sTarget))
+ return sTarget;
+
+ return OUString();
+}
+
+void OOXMLStreamImpl::init()
+{
+ bool bFound = lcl_getTarget(mxRelationshipAccess,
+ mnStreamType, msId, msTarget);
+
+ if (!bFound)
+ return;
+
+ sal_Int32 nLastIndex = msTarget.lastIndexOf('/');
+ if (nLastIndex >= 0)
+ msPath = msTarget.copy(0, nLastIndex + 1);
+
+ uno::Reference<embed::XHierarchicalStorageAccess>
+ xHierarchicalStorageAccess(mxStorage, uno::UNO_QUERY);
+
+ if (xHierarchicalStorageAccess.is())
+ {
+ uno::Any aAny(xHierarchicalStorageAccess->
+ openStreamElementByHierarchicalName
+ (msTarget, embed::ElementModes::SEEKABLEREAD));
+ aAny >>= mxDocumentStream;
+ // Non-cached ID lookup works by accessing mxDocumentStream as an embed::XRelationshipAccess.
+ // So when it changes, we should empty the cache.
+ maIdCache.clear();
+ }
+}
+
+uno::Reference<io::XInputStream> OOXMLStreamImpl::getDocumentStream()
+{
+ uno::Reference<io::XInputStream> xResult;
+
+ if (mxDocumentStream.is())
+ xResult = mxDocumentStream->getInputStream();
+
+ return xResult;
+}
+
+uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
+{
+ return mxContext;
+}
+
+uno::Reference <xml::sax::XFastTokenHandler> OOXMLStreamImpl::getFastTokenHandler()
+{
+ if (! mxFastTokenHandler.is())
+ mxFastTokenHandler.set(new oox::core::FastTokenHandler());
+
+ return mxFastTokenHandler;
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const uno::Reference<uno::XComponentContext>& xContext,
+ const uno::Reference<io::XInputStream>& rStream,
+ bool bRepairStorage)
+{
+ OOXMLStreamImpl * pStream = new OOXMLStreamImpl(xContext, rStream,
+ OOXMLStream::DOCUMENT, bRepairStorage);
+ return OOXMLStream::Pointer_t(pStream);
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const OOXMLStream::Pointer_t& pStream, OOXMLStream::StreamType_t nStreamType)
+{
+ OOXMLStream::Pointer_t pRet;
+
+ if (nStreamType != OOXMLStream::VBADATA)
+ {
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ pRet = new OOXMLStreamImpl(*pImpl, nStreamType);
+ }
+ else
+ {
+ // VBADATA is not a relation of the document, but of the VBAPROJECT stream.
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ {
+ OOXMLStreamImpl aProject(*pImpl, OOXMLStream::VBAPROJECT);
+ pRet = new OOXMLStreamImpl(aProject, OOXMLStream::VBADATA);
+ }
+ }
+
+ return pRet;
+}
+
+OOXMLStream::Pointer_t
+OOXMLDocumentFactory::createStream
+(const OOXMLStream::Pointer_t& pStream, const OUString & rId)
+{
+ OOXMLStream::Pointer_t pRet;
+ if (OOXMLStreamImpl* pImpl = dynamic_cast<OOXMLStreamImpl *>(pStream.get()))
+ pRet = new OOXMLStreamImpl(*pImpl, rId);
+ return pRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/OOXMLStreamImpl.hxx b/sw/source/writerfilter/ooxml/OOXMLStreamImpl.hxx
new file mode 100644
index 000000000000..ec65290c6214
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/OOXMLStreamImpl.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <map>
+
+#include <ooxml/OOXMLDocument.hxx>
+#include <com/sun/star/embed/XRelationshipAccess.hpp>
+
+extern OUString customTarget;
+extern OUString embeddingsTarget;
+
+namespace writerfilter::ooxml
+{
+
+class OOXMLStreamImpl : public OOXMLStream
+{
+ void init();
+
+ css::uno::Reference<css::uno::XComponentContext> mxContext;
+ css::uno::Reference<css::io::XInputStream> mxStorageStream;
+ css::uno::Reference<css::embed::XStorage> mxStorage;
+ css::uno::Reference<css::embed::XRelationshipAccess> mxRelationshipAccess;
+ css::uno::Reference<css::io::XStream> mxDocumentStream;
+ css::uno::Reference<css::xml::sax::XFastParser> mxFastParser;
+ css::uno::Reference<css::xml::sax::XFastTokenHandler> mxFastTokenHandler;
+
+ StreamType_t mnStreamType;
+
+ OUString msId;
+ OUString msPath;
+ OUString msTarget;
+
+ /// Cache holding an Id <-> Target map of external relations.
+ std::map<OUString, OUString> maIdCache;
+
+ bool lcl_getTarget(const css::uno::Reference<css::embed::XRelationshipAccess>& xRelationshipAccess,
+ StreamType_t nStreamType,
+ const OUString & rId,
+ OUString & rDocumentTarget);
+public:
+ typedef tools::SvRef<OOXMLStreamImpl> Pointer_t;
+
+ OOXMLStreamImpl
+ (OOXMLStreamImpl const & rStream, StreamType_t nType);
+ OOXMLStreamImpl
+ (css::uno::Reference<css::uno::XComponentContext> const & xContext,
+ css::uno::Reference<css::io::XInputStream> xStorageStream,
+ StreamType_t nType, bool bRepairStorage);
+ OOXMLStreamImpl(OOXMLStreamImpl const & rStream, OUString aId);
+
+ virtual ~OOXMLStreamImpl() override;
+
+ virtual css::uno::Reference<css::xml::sax::XFastParser> getFastParser() override;
+ virtual css::uno::Reference<css::io::XInputStream> getDocumentStream() override;
+ virtual css::uno::Reference<css::uno::XComponentContext> getContext() override;
+ virtual OUString getTargetForId(const OUString & rId) override;
+ virtual const OUString & getTarget() const override;
+
+ virtual css::uno::Reference<css::xml::sax::XFastTokenHandler> getFastTokenHandler() override;
+
+ // Giving access to mxDocumentStream. It is needed by resolving custom xml to get list of customxml's used in document.
+ const css::uno::Reference<css::io::XStream>& accessDocumentStream() { return mxDocumentStream;}
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/ooxml/README b/sw/source/writerfilter/ooxml/README
new file mode 100644
index 000000000000..c72b341aef65
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/ooxml/factory_ns.py b/sw/source/writerfilter/ooxml/factory_ns.py
new file mode 100644
index 000000000000..18b07aba1c62
--- /dev/null
+++ b/sw/source/writerfilter/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, std::string_view aValue, 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/sw/source/writerfilter/ooxml/factoryimpl.py b/sw/source/writerfilter/ooxml/factoryimpl.py
new file mode 100644
index 000000000000..40618b95faca
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/factoryimpl.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from xml.dom import minidom
+import sys
+
+
+def getElementsByTagNamesNS(parent, ns, names, ret=minidom.NodeList()):
+ for node in parent.childNodes:
+ if node.nodeType == minidom.Node.ELEMENT_NODE and node.namespaceURI == ns and node.tagName in names:
+ ret.append(node)
+ getElementsByTagNamesNS(node, ns, names, ret)
+ return ret
+
+
+def createFastChildContextFromFactory(model):
+ print("""uno::Reference<xml::sax::XFastContextHandler> OOXMLFactory::createFastChildContextFromFactory
+(OOXMLFastContextHandler* pHandler, const OOXMLFactory_ns::Pointer_t& pFactory, Token_t Element)
+{
+ uno::Reference <xml::sax::XFastContextHandler> aResult;
+ const Id nDefine = pHandler->getDefine();
+
+ if (pFactory.get() != NULL)
+ {
+ ResourceType nResource;
+ Id nElementId;
+ if (pFactory->getElementId(nDefine, Element, nResource, nElementId))
+ {
+ const Id nId = pFactory->getResourceId(nDefine, Element);
+
+ switch (nResource)
+ {""")
+ resources = [
+ "List", "Integer", "Hex", "HexColor", "String",
+ "TwipsMeasure_asSigned", "TwipsMeasure_asZero",
+ "HpsMeasure", "Boolean", "MeasurementOrPercent",
+ ]
+ for resource in [r.getAttribute("resource") for r in model.getElementsByTagName("resource")]:
+ if resource not in resources:
+ resources.append(resource)
+ print(""" case ResourceType::%s:
+ aResult.set(OOXMLFastHelper<OOXMLFastContextHandler%s>::createAndSetParentAndDefine(pHandler, Element, nId, nElementId));
+ break;""" % (resource, resource))
+ print(""" case ResourceType::Any:
+ aResult.set(createFastChildContextFromStart(pHandler, Element));
+ break;
+ default:
+ break;
+ }
+
+ }
+ }
+
+ return aResult;
+}
+""")
+
+
+def getFactoryForNamespace(model):
+ print("""OOXMLFactory_ns::Pointer_t OOXMLFactory::getFactoryForNamespace(Id nId)
+{
+ OOXMLFactory_ns::Pointer_t pResult;
+
+ switch (oox::getNamespace(nId))
+ {""")
+
+ for namespace in [ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]:
+ id = namespace.replace('-', '_')
+ print(""" case NN_%s:
+ pResult = OOXMLFactory_%s::getInstance();
+ break;""" % (id, id))
+ print(""" default:
+ break;
+ }
+
+ return pResult;
+}
+""")
+
+
+def createFastChildContextFromStart(model):
+ print("""uno::Reference<xml::sax::XFastContextHandler> OOXMLFactory::createFastChildContextFromStart
+(OOXMLFastContextHandler* pHandler, Token_t Element)
+{
+ uno::Reference<xml::sax::XFastContextHandler> aResult;
+ OOXMLFactory_ns::Pointer_t pFactory;
+
+""")
+
+ for namespace in [ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]:
+ id = namespace.replace('-', '_')
+ print(""" if (!aResult.is())
+ {
+ pFactory = getFactoryForNamespace(NN_%s);
+ aResult.set(createFastChildContextFromFactory(pHandler, pFactory, Element));
+ }""" % id)
+
+ print("""
+ return aResult;
+}
+""")
+
+
+def fastTokenToId(model):
+ print("""
+std::string fastTokenToId(sal_uInt32 nToken)
+{
+ std::string sResult;
+#ifdef DBG_UTIL
+
+ switch (oox::getNamespace(nToken))
+ {""")
+
+ aliases = []
+ for alias in sorted(ooxUrlAliases.values()):
+ if alias not in aliases:
+ aliases.append(alias)
+ print(""" case oox::NMSP_%s:
+ sResult += "%s:";
+ break;""" % (alias, alias))
+ print(""" }
+
+ switch (nToken & 0xffff)
+ {""")
+
+ tokens = [""]
+ for token in [t.getAttribute("localname") for t in getElementsByTagNamesNS(model, "http://relaxng.org/ns/structure/1.0", ["element", "attribute"])]:
+ if token not in tokens:
+ tokens.append(token)
+ print(""" case oox::XML_%s:
+ sResult += "%s";
+ break;""" % (token, token))
+
+ print(""" }
+#else
+ (void)nToken;
+#endif
+ return sResult;
+}
+""")
+
+
+def getFastParser():
+ print("""uno::Reference <xml::sax::XFastParser> OOXMLStreamImpl::getFastParser()
+{
+ if (!mxFastParser.is())
+ {
+ mxFastParser = css::xml::sax::FastParser::create(mxContext);
+ // the threaded parser is about 20% slower loading writer documents
+ css::uno::Reference< css::lang::XInitialization > xInit( mxFastParser, css::uno::UNO_QUERY_THROW );
+ css::uno::Sequence< css::uno::Any > args{ css::uno::Any(OUString("DisableThreadedParser")) };
+ xInit->initialize(args);
+""")
+ for url in sorted(ooxUrlAliases.keys()):
+ print(""" mxFastParser->registerNamespace("%s", oox::NMSP_%s);""" % (url, ooxUrlAliases[url]))
+ print(""" }
+
+ return mxFastParser;
+}
+
+/// @endcond
+}}""")
+
+
+def createImpl(model):
+ print("""
+#include <com/sun/star/xml/sax/FastParser.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include "ooxml/OOXMLFactory.hxx"
+#include "ooxml/OOXMLFastHelper.hxx"
+#include "ooxml/OOXMLStreamImpl.hxx"
+""")
+
+ for namespace in [ns.getAttribute("name") for ns in model.getElementsByTagName("namespace")]:
+ print('#include "OOXMLFactory_%s.hxx"' % namespace)
+
+ print("""namespace writerfilter {
+namespace ooxml {
+
+using namespace com::sun::star;
+
+/// @cond GENERATED
+""")
+
+ createFastChildContextFromFactory(model)
+ getFactoryForNamespace(model)
+ createFastChildContextFromStart(model)
+ fastTokenToId(model)
+ getFastParser()
+
+
+def parseNamespaces(fro):
+ sock = open(fro)
+ for i in sock.readlines():
+ line = i.strip()
+ alias, url = line.split(' ')[1:] # first column is ID, not interesting for us
+ ooxUrlAliases[url] = alias
+ sock.close()
+
+
+namespacesPath = sys.argv[1]
+ooxUrlAliases = {}
+parseNamespaces(namespacesPath)
+modelPath = sys.argv[2]
+model = minidom.parse(modelPath)
+createImpl(model)
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/writerfilter/ooxml/factoryimpl_ns.py b/sw/source/writerfilter/ooxml/factoryimpl_ns.py
new file mode 100644
index 000000000000..d4d5a2f67dc6
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/factoryimpl_ns.py
@@ -0,0 +1,755 @@
+#!/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
+
+
+# factoryConstructor
+
+
+def factoryConstructor(nsLabel):
+ print("""OOXMLFactory_%s::OOXMLFactory_%s()
+{
+}""" % (nsLabel, nsLabel))
+ print()
+
+
+# factoryDestructor
+
+
+def factoryDestructor(nsLabel):
+ print("""OOXMLFactory_%s::~OOXMLFactory_%s()
+{
+}""" % (nsLabel, nsLabel))
+ print()
+
+
+# factoryGetInstance
+
+
+def factoryGetInstance(nsLabel):
+ print("""OOXMLFactory_ns::Pointer_t OOXMLFactory_%s::m_pInstance;
+
+OOXMLFactory_ns::Pointer_t OOXMLFactory_%s::getInstance()
+{
+ if (!m_pInstance)
+ m_pInstance = new OOXMLFactory_%s();
+
+ return m_pInstance;
+}""" % (nsLabel, nsLabel, nsLabel))
+ print()
+
+
+# factoryAttributeToResourceMap
+
+
+def nsToLabel(nsNode):
+ return nsNode.getAttribute("name").replace('-', '_')
+
+
+def getChildByName(parentNode, childName):
+ elementNodes = [i for i in parentNode.childNodes if i.localName == childName]
+ assert len(elementNodes) == 1
+ return elementNodes[0]
+
+
+def resourceForAttribute(nsNode, attrNode):
+ resourceName = ""
+
+ for refNode in getChildrenByName(attrNode, "ref"):
+ refName = refNode.getAttribute("name")
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == refName]:
+ resourceName = resourceNode.getAttribute("resource")
+ break
+ if not len(resourceName):
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ resourceName = resourceForAttribute(nsNode, define)
+ break
+ if len(resourceName):
+ break
+
+ if not len(resourceName):
+ if len([i for i in attrNode.getElementsByTagName("data") if i.getAttribute("type") in ("base64Binary", "string")]):
+ resourceName = "String"
+ elif len([i for i in attrNode.getElementsByTagName("data") if i.getAttribute("type") == "boolean"]):
+ resourceName = "Boolean"
+ elif len([i for i in attrNode.getElementsByTagName("data") if i.getAttribute("type") in ("unsignedInt", "integer", "int")]):
+ resourceName = "Integer"
+ else:
+ dataNodes = attrNode.getElementsByTagName("data")
+ if len(dataNodes):
+ t = dataNodes[0].getAttribute("type")
+ # Denylist existing unexpected data types.
+ if t not in ("token", "long", "decimal", "float", "byte", "ST_DecimalNumber", "positiveInteger"):
+ raise Exception("unexpected data type: " + dataNodes[0].getAttribute("type"))
+ return resourceName
+
+
+def idForNamespace(nsNode):
+ return "NN_%s" % nsNode.getAttribute("name").replace('-', '_')
+
+
+def localIdForDefine(defineNode):
+ return "DEFINE_%s" % defineNode.getAttribute("name")
+
+
+def idForDefine(nsNode, defineNode):
+ return "%s|%s" % (idForNamespace(nsNode), localIdForDefine(defineNode))
+
+
+def fastNamespace(attrNode):
+ return "oox::NMSP_%s" % attrNode.getAttribute("prefix")
+
+
+def fastLocalName(attrNode):
+ if len(attrNode.getAttribute("localname")):
+ return "oox::XML_%s" % attrNode.getAttribute("localname")
+ else:
+ return "oox::XML_TOKEN_COUNT"
+
+
+def fastToken(attrNode):
+ ret = []
+ if len(attrNode.getAttribute("prefix")):
+ ret.append("%s|" % fastNamespace(attrNode))
+ ret.append(fastLocalName(attrNode))
+ return "".join(ret)
+
+
+def collectAttributeToResource(nsNode, defineNode):
+ ret_dict = {}
+ ret_order = []
+ for refNode in getChildrenByName(defineNode, "ref"):
+ refName = refNode.getAttribute("name")
+ parent = refNode.parentNode
+ if parent.localName in ("element", "attribute"):
+ continue
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ ret = collectAttributeToResource(nsNode, define)
+ ret_dict.update(ret[0])
+ ret_order.extend(ret[1])
+
+ attrNodes = defineNode.getElementsByTagName("attribute")
+ for attrNode in attrNodes:
+ attrToken = fastToken(attrNode)
+ resourceName = resourceForAttribute(nsNode, attrNode)
+ refDefine = "0"
+ if len(resourceName):
+ for refNode in attrNode.getElementsByTagName("ref"):
+ refName = refNode.getAttribute("name")
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ refDefine = idForDefine(nsNode, define)
+ ret_dict[attrToken] = "ResourceType::%s, %s" % (resourceName, refDefine)
+ ret_order.append(attrToken)
+
+ return [ret_dict, ret_order]
+
+
+def factoryAttributeToResourceMapInner(nsNode, defineNode):
+ ret = []
+ attributes = collectAttributeToResource(nsNode, defineNode)
+ already_used = set()
+ for k in attributes[1]:
+ if k not 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 first not in values:
+ values[first] = []
+
+ values[first].append([name, value])
+
+
+def printValueData(values):
+ if "" in values:
+ output_else = ""
+ for i in values[""]:
+ print(" %sif (aValue == \"%s\") { rOutValue = %s; return true; }" % (output_else, i[0], i[1]))
+ output_else = "else "
+ print(" else switch (aValue[0])")
+ else:
+ print(" if (aValue.empty())")
+ print(" return false;")
+ print(" switch (aValue[0])")
+
+ print(" {")
+ for k in sorted(values.keys()):
+ if k != "":
+ print(" case '%s':" % k)
+ output_else = ""
+ for i in values[k]:
+ print(" %sif (aValue == \"%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, std::string_view aValue, sal_uInt32& rOutValue)
+{
+ (void) aValue;
+ (void) rOutValue;
+
+ switch (nId)
+ {""" % nsToLabel(nsNode))
+
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("resource") == "List"]:
+ print(" case %s:" % idForDefine(nsNode, resourceNode))
+ values = {}
+ for valueNode in getChildrenByName(resourceNode, "value"):
+ valueData = ""
+ if len(valueNode.childNodes):
+ valueData = valueNode.childNodes[0].data
+ appendValueData(values, valueData, idToLabel(valueNode.getAttribute("tokenid")))
+ printValueData(values)
+ print(" return false;")
+
+ print(""" default:
+ break;
+ }
+
+ return false;
+}
+""")
+
+
+# factoryCreateElementMap
+
+
+def contextResource(files, nsNode, refNode):
+ refName = refNode.getAttribute("name")
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == refName]:
+ return resourceNode.getAttribute("resource")
+
+ for includeNode in getChildrenByName(getChildByName(nsNode, "grammar"), "include"):
+ namespaceNode = files[includeNode.getAttribute("href")]
+ for resourceNode in [i for i in getChildrenByName(namespaceNode, "resource") if i.getAttribute("name") == refName]:
+ return resourceNode.getAttribute("resource")
+
+ if refName == "BUILT_IN_ANY_TYPE":
+ return "Any"
+ else:
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for resourceNode in [i for i in getChildrenByName(namespaceNode, "resource") if i.getAttribute("name") == refName]:
+ return resourceNode.getAttribute("resource")
+ return ""
+
+
+def idForRef(nsNode, refNode):
+ refName = refNode.getAttribute("name")
+ result1 = ""
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ result1 = idForDefine(nsNode, define)
+ if refName == "BUILT_IN_ANY_TYPE":
+ return "0"
+ elif result1 == "":
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for define in [i for i in getChildrenByName(getChildByName(namespaceNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ return idForDefine(namespaceNode, define)
+ else:
+ return result1
+
+
+def factoryCreateElementMapInner(files, nsNode, defineNode, resourceNamespaceNode=None):
+ if not resourceNamespaceNode:
+ resourceNamespaceNode = nsNode
+ ret = {}
+ for refNode in defineNode.getElementsByTagName("ref"):
+ parent = refNode.parentNode
+ if parent.localName in ("element", "attribute"):
+ continue
+ refName = refNode.getAttribute("name")
+
+ block = {}
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ block = factoryCreateElementMapInner(files, nsNode, define)
+
+ if len(block) == 0:
+ block1 = {}
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for define in [i for i in getChildrenByName(getChildByName(namespaceNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ block1.update(factoryCreateElementMapInner(files, namespaceNode, define, nsNode))
+ else:
+ block1 = block
+
+ if len(block1):
+ ret.update(block1)
+
+ for elementNode in defineNode.getElementsByTagName("element"):
+ resource = ""
+ for refNode in getChildrenByName(elementNode, "ref"):
+ refName = refNode.getAttribute("name")
+ resource = contextResource(files, resourceNamespaceNode, refNode)
+ if len(resource):
+ break
+ if len(resource):
+ ret[fastToken(elementNode)] = " case %s: rOutResource = ResourceType::%s; rOutElement = %s; break;" % (fastToken(elementNode), resource, idForRef(nsNode, getChildByName(elementNode, "ref")))
+
+ return ret
+
+
+def factoryCreateElementMapFromStart(files, nsNode):
+ for startNode in getChildrenByName(nsNode, "start"):
+ startName = startNode.getAttribute("name")
+ block = None
+ for defineNode in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == startName]:
+ block = factoryCreateElementMapInner(files, nsNode, defineNode)
+ print(" /* start: %s*/" % startName)
+ if block:
+ for k in block.keys():
+ print(block[k])
+
+
+def factoryCreateElementMap(files, nsNode):
+ print("""bool OOXMLFactory_%s::getElementId(Id nDefine, Id nId, ResourceType& rOutResource, Id& rOutElement)
+{
+ (void) rOutResource;
+ (void) rOutElement;
+
+ switch (nDefine)
+ {""" % nsToLabel(nsNode))
+
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = factoryCreateElementMapInner(files, nsNode, defineNode)
+ if len(inner):
+ print(" case %s:" % idForDefine(nsNode, defineNode))
+ print(" switch (nId)")
+ print(" {")
+ for k in sorted(inner.keys()):
+ print(inner[k])
+ print(" default: return false;")
+ print(" }")
+ print(" return true;")
+ print(" default:")
+ print(" switch (nId)")
+ print(" {")
+ factoryCreateElementMapFromStart(files, nsNode)
+ print(""" default: return false;
+ }
+ return true;
+ }
+}
+""")
+
+
+# factoryActions
+
+
+def charactersActionForValues(nsNode, refNode):
+ ret = []
+
+ refName = refNode.getAttribute("name")
+ for defineNode in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ ret.append(" {")
+ ret.append(" // %s" % defineNode.getAttribute("name"))
+ for dataNode in getChildrenByName(defineNode, "data"):
+ if dataNode.getAttribute("type") == "int":
+ ret.append(" OOXMLValue::Pointer_t pValue(new OOXMLIntegerValue(sText));")
+ ret.append(" pValueHandler->setValue(pValue);")
+ ret.append(" }")
+
+ return ret
+
+
+def factoryChooseAction(actionNode):
+ ret = []
+ extra_space = ""
+ if actionNode.hasAttribute("tokenid"):
+ ret.append(" if (sal::static_int_cast<Id>(pHandler->getId()) == %s)" % idToLabel(actionNode.getAttribute("tokenid")))
+ ret.append(" {")
+ extra_space = " "
+ for condNode in getChildrenByName(actionNode, "cond"):
+ ret.append(" {")
+ ret.append(" OOXMLPropertySetEntryToInteger aHandler(%s);" % idToLabel(condNode.getAttribute("tokenid")))
+ ret.append(" if (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))")
+ ret.append(" pStream->getPropertySetAttrs()->resolve(aHandler);")
+ ret.append("")
+ ret.append(" if (sal::static_int_cast<Id>(aHandler.getValue()) == %s)" % idToLabel(condNode.getAttribute("value")))
+ ret.append(" {")
+ extra_space = " "
+
+ if actionNode.getAttribute("action") in ("handleXNotes", "handleHdrFtr", "handleComment", "handlePicture", "handleBreak", "handleOutOfOrderBreak", "handleOLE", "handleFontRel", "handleHyperlinkURL", "handleAltChunk"):
+ ret.append(" %sif (OOXMLFastContextHandlerProperties* pProperties = dynamic_cast<OOXMLFastContextHandlerProperties*>(pHandler))" % extra_space)
+ ret.append(" %s pProperties->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") == "propagateCharacterPropertiesAsSet":
+ ret.append(" %spHandler->propagateCharacterPropertiesAsSet(%s);" % (extra_space, idToLabel(actionNode.getAttribute("sendtokenid"))))
+ elif actionNode.getAttribute("action") in ("startCell", "endCell"):
+ ret.append(" %sif (OOXMLFastContextHandlerTextTableCell* pTextTableCell = dynamic_cast<OOXMLFastContextHandlerTextTableCell*>(pHandler))" % extra_space)
+ ret.append(" %s pTextTableCell->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") in ("startRow", "endRow"):
+ ret.append(" %sif (OOXMLFastContextHandlerTextTableRow* pTextTableRow = dynamic_cast<OOXMLFastContextHandlerTextTableRow*>(pHandler))" % extra_space)
+ ret.append(" %s pTextTableRow->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") == "handleGridAfter":
+ ret.append(" %sif (OOXMLFastContextHandlerValue* pValueHandler = dynamic_cast<OOXMLFastContextHandlerValue*>(pHandler))" % extra_space)
+ ret.append(" %s pValueHandler->%s();" % (extra_space, actionNode.getAttribute("action")))
+ # tdf#111550
+ elif actionNode.getAttribute("action") in ("start_P_Tbl"):
+ ret.append(" %sif (OOXMLFastContextHandlerTextTable* pTextTable = dynamic_cast<OOXMLFastContextHandlerTextTable*>(pHandler))" % extra_space)
+ ret.append(" %s pTextTable->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") in ("sendProperty", "handleHyperlink"):
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % extra_space)
+ ret.append(" %s pStream->%s();" % (extra_space, actionNode.getAttribute("action")))
+ elif actionNode.getAttribute("action") == "fieldstart":
+ ret.append(" %spHandler->startField();" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldsep":
+ ret.append(" %spHandler->fieldSeparator();" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldend":
+ ret.append(" %spHandler->endField();" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldlock":
+ ret.append(" %s{" % (extra_space))
+ ret.append(" %sOOXMLPropertySetEntryToBool aHandler(NS_ooxml::LN_CT_FldChar_fldLock);" % (extra_space))
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % (extra_space))
+ ret.append(" %spStream->getPropertySetAttrs()->resolve(aHandler);" % (extra_space))
+ ret.append(" %sif (aHandler.getValue())" % (extra_space))
+ ret.append(" %spHandler->lockField();" % (extra_space))
+ ret.append(" %s}" % (extra_space))
+ elif actionNode.getAttribute("action") == "fieldlock_simple":
+ ret.append(" %s{" % (extra_space))
+ ret.append(" %sOOXMLPropertySetEntryToBool aHandler(NS_ooxml::LN_CT_SimpleField_fldLock);" % (extra_space))
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % (extra_space))
+ ret.append(" %spStream->getPropertySetAttrs()->resolve(aHandler);" % (extra_space))
+ ret.append(" %sif (aHandler.getValue())" % (extra_space))
+ ret.append(" %spHandler->lockField();" % (extra_space))
+ ret.append(" %s}" % (extra_space))
+ elif actionNode.getAttribute("action") == "printproperty":
+ ret.append(" %sif (OOXMLFastContextHandlerStream* pStream = dynamic_cast<OOXMLFastContextHandlerStream*>(pHandler))" % extra_space)
+ ret.append(" %s pStream->sendProperty(%s);" % (extra_space, idToLabel(actionNode.getAttribute("sendtokenid"))))
+ elif actionNode.getAttribute("action") == "sendPropertiesWithId":
+ ret.append(" %spHandler->sendPropertiesWithId(%s);" % (extra_space, idToLabel(actionNode.getAttribute("sendtokenid"))))
+ elif actionNode.getAttribute("action") == "text":
+ ret.append(" %spHandler->text(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "positionOffset":
+ ret.append(" %spHandler->positionOffset(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "positivePercentage":
+ ret.append(" %spHandler->positivePercentage(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "alignH":
+ ret.append(" %spHandler->alignH(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "alignV":
+ ret.append(" %spHandler->alignV(sText);" % (extra_space))
+ elif actionNode.getAttribute("action") == "tokenproperty":
+ ret.append(" %sOOXMLFastHelper<OOXMLIntegerValue>::newProperty(pHandler, %s, pHandler->getToken());" % (extra_space, idToLabel("ooxml:token")))
+ else:
+ ret.append(" %spHandler->%s();" % (extra_space, actionNode.getAttribute("action")))
+
+ for condNode in getChildrenByName(actionNode, "cond"):
+ ret.append(" }")
+ ret.append(" }")
+ if actionNode.hasAttribute("tokenid"):
+ ret.append(" }")
+
+ return ret
+
+
+def factoryAction(nsNode, action):
+ switchblock1 = []
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if len([j for j in getChildrenByName(i, "action") if j.getAttribute("name") == action])]:
+ switchblock1.append("case %s:" % idForDefine(nsNode, resourceNode))
+ for actionNode in [i for i in getChildrenByName(resourceNode, "action") if i.getAttribute("name") == action]:
+ switchblock1.extend(factoryChooseAction(actionNode))
+ switchblock1.append(" break;")
+ switchblock1.append("")
+
+ switchblock2 = []
+ if action == "characters":
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("resource") == "Value"]:
+ if not len(getChildrenByName(resourceNode, "attribute")):
+ resourceName = resourceNode.getAttribute("name")
+ switchblock2.append("case %s:" % idForDefine(nsNode, resourceNode))
+ ret = []
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == resourceName]:
+ for refNode in getChildrenByName(define, "ref"):
+ ret.extend(charactersActionForValues(nsNode, refNode))
+ switchblock2.extend(ret)
+ switchblock2.append(" break;")
+
+ sys.stdout.write("void OOXMLFactory_%s::%sAction(OOXMLFastContextHandler*" % (nsToLabel(nsNode), action))
+ if len(switchblock1) or len(switchblock2):
+ sys.stdout.write(" pHandler")
+ if action == "characters":
+ sys.stdout.write(", const OUString&")
+ if "sText" in "".join(switchblock1) or "sText" in "".join(switchblock2):
+ sys.stdout.write(" sText")
+ print(")")
+ print("{")
+ if len(switchblock1) or len(switchblock2):
+ print(" sal_uInt32 nDefine = pHandler->getDefine();")
+ if len(switchblock1):
+ print(" switch (nDefine)")
+ print(" {")
+ if switchblock1[-1] == "":
+ switchblock1 = switchblock1[:-1]
+ sys.stdout.write(" ")
+ print("\n ".join(switchblock1))
+ print()
+ print(" default:")
+ print(" break;")
+ print(" }")
+ if len(switchblock2):
+ print(" switch (nDefine)")
+ print(" {")
+ print("\n ".join(switchblock2))
+ print()
+ print(" default:")
+ print(" break;")
+ print(" }")
+ print("}")
+
+
+def factoryActions(nsNode):
+ actions = []
+ for resourceNode in getChildrenByName(nsNode, "resource"):
+ for actionNode in getChildrenByName(resourceNode, "action"):
+ actionName = actionNode.getAttribute("name")
+ if actionName != "characters" and actionName not in actions:
+ actions.append(actionName)
+ for action in sorted(actions):
+ factoryAction(nsNode, action)
+ print()
+ factoryAction(nsNode, "characters")
+ print()
+
+
+# factoryGetResourceId
+
+
+def collectTokenToId(nsNode, defineNode):
+ ret = {}
+ for refNode in defineNode.getElementsByTagName("ref"):
+ refName = refNode.getAttribute("name")
+ parent = refNode.parentNode
+ if parent.localName in ("element", "attribute"):
+ continue
+ refblock1 = {}
+ for define in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ refblock1.update(collectTokenToId(nsNode, define))
+ if not len(refblock1):
+ for namespaceNode in getChildrenByName(nsNode.parentNode, "namespace"):
+ for define in [i for i in getChildrenByName(getChildByName(namespaceNode, "grammar"), "define") if i.getAttribute("name") == refName]:
+ ret.update(collectTokenToId(namespaceNode, define))
+ else:
+ ret.update(refblock1)
+
+ defineName = defineNode.getAttribute("name")
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == defineName]:
+ for node in [i for i in resourceNode.childNodes if i.localName in ("element", "attribute")]:
+ if node.hasAttribute("tokenid"):
+ ret[fastToken(node)] = idToLabel(node.getAttribute("tokenid"))
+
+ return ret
+
+
+def factoryTokenToIdMapInner(nsNode, defineNode):
+ ids = collectTokenToId(nsNode, defineNode)
+ ret = []
+ for i in sorted(ids.keys()):
+ ret.append(" case %s: return %s;" % (i, ids[i]))
+
+ return ret
+
+
+def factoryGetResourceId(nsNode):
+ print("""Id OOXMLFactory_%s::getResourceId(Id nDefine, sal_Int32 nToken)
+{
+ (void) nDefine;
+ (void) nToken;
+
+ switch (nDefine)
+ {""" % nsToLabel(nsNode))
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = "\n".join(factoryTokenToIdMapInner(nsNode, defineNode))
+ if len(inner):
+ print(" case %s:" % idForDefine(nsNode, defineNode))
+ print(" switch (nToken)")
+ print(" {")
+ print(inner)
+ print(" }")
+ print(" break;")
+ print(" default:")
+ print(" switch (nToken)")
+ print(" {")
+ for startNode in getChildrenByName(nsNode, "start"):
+ startName = startNode.getAttribute("name")
+ for defineNode in [i for i in getChildrenByName(getChildByName(nsNode, "grammar"), "define") if i.getAttribute("name") == startName]:
+ inner = factoryTokenToIdMapInner(nsNode, defineNode)
+ if len(inner):
+ print("\n".join(inner))
+ print(""" }
+ break;
+ }
+ return 0;
+}
+""")
+
+
+# factoryAttributeAction
+
+
+def factoryAttributeActionDefineInner(nsNode, defineNode):
+ ret = []
+
+ defineName = defineNode.getAttribute("name")
+ block = []
+ output_else = ""
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == defineName]:
+ for attributeNode in getChildrenByName(resourceNode, "attribute"):
+ if attributeNode.hasAttribute("action"):
+ block.append(" %sif (nToken == static_cast<Token_t>(%s))" % (output_else, fastToken(attributeNode)))
+ block.append(" pHandler->%s(pValue);" % attributeNode.getAttribute("action"))
+ output_else = "else "
+ if len(block):
+ resource = ""
+ for resourceNode in [i for i in getChildrenByName(nsNode, "resource") if i.getAttribute("name") == defineName]:
+ resource = resourceNode.getAttribute("resource")
+ break
+ ret.append(" if (OOXMLFastContextHandler%s* pHandler = dynamic_cast<OOXMLFastContextHandler%s*>(_pHandler))" % (resource, resource))
+ ret.append(" {")
+ ret.extend(block)
+ ret.append(" }")
+
+ return ret
+
+
+def factoryAttributeActionInner(nsNode):
+ ret = []
+
+ for defineNode in getChildrenByName(getChildByName(nsNode, "grammar"), "define"):
+ inner = factoryAttributeActionDefineInner(nsNode, defineNode)
+ if len(inner):
+ ret.append(" case %s:" % idForDefine(nsNode, defineNode))
+ ret.extend(inner)
+ ret.append(" break;")
+
+ return ret
+
+
+def factoryAttributeAction(nsNode):
+ nsLabel = nsToLabel(nsNode)
+ inner = factoryAttributeActionInner(nsNode)
+ if len(inner):
+ print("""void OOXMLFactory_%s::attributeAction(OOXMLFastContextHandler* _pHandler, Token_t nToken, const OOXMLValue::Pointer_t& pValue)
+{
+ switch (_pHandler->getDefine())
+ {""" % nsLabel)
+ print("\n".join(inner))
+ print(" default:")
+ print(" break;")
+ print(" }")
+ print("}")
+ print()
+ else:
+ print("void OOXMLFactory_%s::attributeAction(OOXMLFastContextHandler*, Token_t, const OOXMLValue::Pointer_t&)" % nsLabel)
+ print("{")
+ print("}")
+ print()
+
+
+# createImpl
+
+
+def getChildrenByName(parentNode, childName):
+ return [i for i in parentNode.childNodes if i.localName == childName]
+
+
+def createImpl(modelNode, nsName):
+ print("""
+#include "ooxml/resourceids.hxx"
+#include "OOXMLFactory_%s.hxx"
+#include "ooxml/OOXMLFastHelper.hxx"
+#include "oox/token/tokens.hxx"
+
+#ifdef _MSC_VER
+#pragma warning(disable:4060) // switch statement contains no 'case' or 'default' labels
+#pragma warning(disable:4065) // switch statement contains 'default' but no 'case' labels
+#pragma warning(disable:4702) // unreachable code
+#endif
+
+namespace writerfilter {
+namespace ooxml {
+
+using namespace com::sun::star;
+
+/// @cond GENERATED""" % nsName)
+ print()
+
+ files = {}
+ for nsNode in getChildrenByName(modelNode, "namespace"):
+ files[nsNode.getAttribute("name")] = nsNode
+
+ for nsNode in [i for i in getChildrenByName(modelNode, "namespace") if i.getAttribute("name") == nsName]:
+ nsLabel = nsToLabel(nsNode)
+
+ 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/sw/source/writerfilter/ooxml/factoryinc.py b/sw/source/writerfilter/ooxml/factoryinc.py
new file mode 100644
index 000000000000..ec07f7fda1ce
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/ooxml/model.xml b/sw/source/writerfilter/ooxml/model.xml
new file mode 100644
index 000000000000..2f84e72c0615
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/model.xml
@@ -0,0 +1,19426 @@
+<?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:adec="http://schemas.microsoft.com/office/drawing/2017/decorative"
+ xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"
+ xmlns:dgm="http://schemas.openxmlformats.org/drawingml/2006/diagram"
+ xmlns:lc="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"
+ xmlns:o="urn:schemas-microsoft-com:office:office"
+ xmlns:p="urn:schemas-microsoft-com:office:powerpoint"
+ xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+ xmlns:v="urn:schemas-microsoft-com:vml"
+ xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
+ xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
+ xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
+ xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
+ xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
+ 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="Theme" 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="adec_decorative_val">
+ <attribute name="val">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="adec_decorative">
+ <element name="adec:decorative">
+ <ref name="adec_decorative_val"/>
+ </element>
+ </define>
+ <define name="CT_OfficeArtExtension">
+ <choice>
+ <!-- add implemented extensions here so they can be processed -->
+ <ref name="adec_decorative"/>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </choice>
+ <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="CT_OfficeArtExtension" resource="Stream">
+ <element name="adec:decorative" tokenid="ooxml:CT_OfficeArtExtension_Decorative"/>
+ </resource>
+ <!-- this is not ideal, but unlike more obvious variants it appears to work -->
+ <resource name="adec_decorative" resource="Stream"/>
+ <resource name="adec_decorative_val" resource="Properties">
+ <attribute name="val" tokenid="ooxml:OfficeArtExtension_Decorative_val"/>
+ </resource>
+ <resource name="ST_Coordinate" resource="Integer"/>
+ <resource name="ST_PositiveCoordinate" resource="Integer"/>
+ <resource name="ST_Angle" resource="Integer"/>
+ <resource name="CT_Angle" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Angle_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="CT_PositiveFixedAngle" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PositiveFixedAngle_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Percentage" resource="Integer"/>
+ <resource name="CT_Percentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Percentage_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_PositivePercentage" resource="Value">
+ <action name="characters" action="positivePercentage"/>
+ </resource>
+ <resource name="CT_PositivePercentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PositivePercentage_val" action="setValue"/>
+ </resource>
+ <resource name="CT_FixedPercentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FixedPercentage_val" action="setValue"/>
+ </resource>
+ <resource name="CT_PositiveFixedPercentage" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PositiveFixedPercentage_val" action="setValue"/>
+ </resource>
+ <resource name="CT_Point2D" resource="Properties">
+ <attribute name="x" tokenid="ooxml:CT_Point2D_x"/>
+ <attribute name="y" tokenid="ooxml:CT_Point2D_y"/>
+ </resource>
+ <resource name="CT_PositiveSize2D" resource="Properties">
+ <attribute name="cx" tokenid="ooxml:CT_PositiveSize2D_cx"/>
+ <attribute name="cy" tokenid="ooxml:CT_PositiveSize2D_cy"/>
+ </resource>
+ <resource name="CT_ScRgbColor" resource="Properties">
+ <attribute name="r" tokenid="ooxml:CT_ScRgbColor_r"/>
+ <attribute name="g" tokenid="ooxml:CT_ScRgbColor_g"/>
+ <attribute name="b" tokenid="ooxml:CT_ScRgbColor_b"/>
+ </resource>
+ <resource name="ST_HexBinary3" resource="Hex"/>
+ <resource name="CT_SRgbColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SRgbColor_val"/>
+ </resource>
+ <resource name="CT_HslColor" resource="Properties">
+ <attribute name="hue" tokenid="ooxml:CT_HslColor_hue"/>
+ <attribute name="sat" tokenid="ooxml:CT_HslColor_sat"/>
+ <attribute name="lum" tokenid="ooxml:CT_HslColor_lum"/>
+ </resource>
+ <resource name="ST_SystemColorVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_scrollBar">scrollBar</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_background">background</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_activeCaption">activeCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_inactiveCaption">inactiveCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menu">menu</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_window">window</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_windowFrame">windowFrame</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menuText">menuText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_windowText">windowText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_captionText">captionText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_activeBorder">activeBorder</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_inactiveBorder">inactiveBorder</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_appWorkspace">appWorkspace</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_highlight">highlight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_highlightText">highlightText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnFace">btnFace</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnShadow">btnShadow</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_grayText">grayText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnText">btnText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_inactiveCaptionText">inactiveCaptionText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_btnHighlight">btnHighlight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_3dDkShadow">3dDkShadow</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_3dLight">3dLight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_infoText">infoText</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_infoBk">infoBk</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_hotLight">hotLight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_gradientActiveCaption">gradientActiveCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_gradientInactiveCaption">gradientInactiveCaption</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menuHighlight">menuHighlight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SystemColorVal_menuBar">menuBar</value>
+ </resource>
+ <resource name="CT_SystemColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SystemColor_val"/>
+ <attribute name="lastClr" tokenid="ooxml:CT_SystemColor_lastClr"/>
+ </resource>
+ <resource name="ST_SchemeColorVal" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_bg1">bg1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_tx1">tx1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_bg2">bg2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_tx2">tx2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent1">accent1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent2">accent2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent3">accent3</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent4">accent4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent5">accent5</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_accent6">accent6</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_hlink">hlink</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_folHlink">folHlink</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_phClr">phClr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_dk1">dk1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_lt1">lt1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_dk2">dk2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_SchemeColorVal_lt2">lt2</value>
+ </resource>
+ <resource name="CT_SchemeColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SchemeColor_val"/>
+ </resource>
+ <resource name="ST_PresetColorVal" resource="List">
+ <value tokenid="ooxml:Value_ST_PresetColorVal_aliceBlue">aliceBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_antiqueWhite">antiqueWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_aqua">aqua</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_aquamarine">aquamarine</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_azure">azure</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_beige">beige</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_bisque">bisque</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_black">black</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_blanchedAlmond">blanchedAlmond</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_blue">blue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_blueViolet">blueViolet</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_brown">brown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_burlyWood">burlyWood</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cadetBlue">cadetBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_chartreuse">chartreuse</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_chocolate">chocolate</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_coral">coral</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cornflowerBlue">cornflowerBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cornsilk">cornsilk</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_crimson">crimson</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_cyan">cyan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_deepPink">deepPink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_deepSkyBlue">deepSkyBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dimGray">dimGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkBlue">dkBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkCyan">dkCyan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkGoldenrod">dkGoldenrod</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkGray">dkGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkGreen">dkGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkKhaki">dkKhaki</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkMagenta">dkMagenta</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkOliveGreen">dkOliveGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkOrange">dkOrange</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkOrchid">dkOrchid</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkRed">dkRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSalmon">dkSalmon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSeaGreen">dkSeaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSlateBlue">dkSlateBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkSlateGray">dkSlateGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkTurquoise">dkTurquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dkViolet">dkViolet</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_dodgerBlue">dodgerBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_firebrick">firebrick</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_floralWhite">floralWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_forestGreen">forestGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_fuchsia">fuchsia</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_gainsboro">gainsboro</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ghostWhite">ghostWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_gold">gold</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_goldenrod">goldenrod</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_gray">gray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_green">green</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_greenYellow">greenYellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_honeydew">honeydew</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_hotPink">hotPink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_indianRed">indianRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_indigo">indigo</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ivory">ivory</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_khaki">khaki</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lavender">lavender</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lavenderBlush">lavenderBlush</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lawnGreen">lawnGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lemonChiffon">lemonChiffon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_lime">lime</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_limeGreen">limeGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_linen">linen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltBlue">ltBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltCoral">ltCoral</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltCyan">ltCyan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltGoldenrodYellow">ltGoldenrodYellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltGray">ltGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltGreen">ltGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltPink">ltPink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSalmon">ltSalmon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSeaGreen">ltSeaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSkyBlue">ltSkyBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSlateGray">ltSlateGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltSteelBlue">ltSteelBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_ltYellow">ltYellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_magenta">magenta</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_maroon">maroon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medAquamarine">medAquamarine</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medBlue">medBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medOrchid">medOrchid</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medPurple">medPurple</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medSeaGreen">medSeaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medSlateBlue">medSlateBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medSpringGreen">medSpringGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medTurquoise">medTurquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_medVioletRed">medVioletRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_midnightBlue">midnightBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_mintCream">mintCream</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_mistyRose">mistyRose</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_moccasin">moccasin</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_navajoWhite">navajoWhite</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_navy">navy</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_oldLace">oldLace</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_olive">olive</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_oliveDrab">oliveDrab</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_orange">orange</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_orangeRed">orangeRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_orchid">orchid</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleGoldenrod">paleGoldenrod</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleGreen">paleGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleTurquoise">paleTurquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_paleVioletRed">paleVioletRed</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_papayaWhip">papayaWhip</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_peachPuff">peachPuff</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_peru">peru</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_pink">pink</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_plum">plum</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_powderBlue">powderBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_purple">purple</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_red">red</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_rosyBrown">rosyBrown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_royalBlue">royalBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_saddleBrown">saddleBrown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_salmon">salmon</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_sandyBrown">sandyBrown</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_seaGreen">seaGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_seaShell">seaShell</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_sienna">sienna</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_silver">silver</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_skyBlue">skyBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_slateBlue">slateBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_slateGray">slateGray</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_snow">snow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_springGreen">springGreen</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_steelBlue">steelBlue</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_tan">tan</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_teal">teal</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_thistle">thistle</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_tomato">tomato</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_turquoise">turquoise</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_violet">violet</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_wheat">wheat</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_white">white</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_whiteSmoke">whiteSmoke</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_yellow">yellow</value>
+ <value tokenid="ooxml:Value_ST_PresetColorVal_yellowGreen">yellowGreen</value>
+ </resource>
+ <resource name="CT_PresetColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PresetColor_val"/>
+ </resource>
+ <resource name="CT_Transform2D" resource="Properties">
+ <element name="off" tokenid="ooxml:CT_Transform2D_off"/>
+ <element name="ext" tokenid="ooxml:CT_Transform2D_ext"/>
+ <attribute name="rot" tokenid="ooxml:CT_Transform2D_rot"/>
+ <attribute name="flipH" tokenid="ooxml:CT_Transform2D_flipH"/>
+ <attribute name="flipV" tokenid="ooxml:CT_Transform2D_flipV"/>
+ </resource>
+ <resource name="ST_RectAlignment" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_tl">tl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_t">t</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_tr">tr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_l">l</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_r">r</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_bl">bl</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_b">b</value>
+ <value tokenid="ooxml:Value_drawingml_ST_RectAlignment_br">br</value>
+ </resource>
+ <resource name="EG_ColorChoice" resource="Properties">
+ <element name="scrgbClr" tokenid="ooxml:EG_ColorChoice_scrgbClr"/>
+ <element name="srgbClr" tokenid="ooxml:EG_ColorChoice_srgbClr"/>
+ <element name="hslClr" tokenid="ooxml:EG_ColorChoice_hslClr"/>
+ <element name="sysClr" tokenid="ooxml:EG_ColorChoice_sysClr"/>
+ <element name="schemeClr" tokenid="ooxml:EG_ColorChoice_schemeClr"/>
+ <element name="prstClr" tokenid="ooxml:EG_ColorChoice_prstClr"/>
+ </resource>
+ <resource name="CT_Color" resource="Properties"/>
+ <resource name="CT_ColorMRU" resource="Properties"/>
+ <resource name="ST_BlackWhiteMode" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_clr">clr</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_auto">auto</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_gray">gray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_ltGray">ltGray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_invGray">invGray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_grayWhite">grayWhite</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_blackGray">blackGray</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_blackWhite">blackWhite</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_black">black</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_white">white</value>
+ <value tokenid="ooxml:Value_drawingml_ST_BlackWhiteMode_hidden">hidden</value>
+ </resource>
+ <resource name="AG_Blob" resource="Properties">
+ <attribute name="r:embed" tokenid="ooxml:AG_Blob_r_embed"/>
+ <attribute name="r:link" tokenid="ooxml:AG_Blob_r_link"/>
+ </resource>
+ <resource name="ST_DrawingElementId" resource="Integer"/>
+ </namespace>
+ <namespace name="dml-documentProperties">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <include href="dml-shapeGeometry"/>
+ <define name="AG_Locking">
+ <attribute name="noGrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noSelect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noRot">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeAspect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noMove">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noResize">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noEditPoints">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noAdjustHandles">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeArrowheads">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeShapeType">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_ConnectorLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Locking"/>
+ </define>
+ <define name="CT_ShapeLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Locking"/>
+ <attribute name="noTextEdit">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <ref name="AG_Locking"/>
+ <attribute name="noCrop">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_GroupLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="noGrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noUngrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noSelect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noRot">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeAspect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noMove">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noResize">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_GraphicalObjectFrameLocking">
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="noGrp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noDrilldown">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noSelect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noChangeAspect">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noMove">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="noResize">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualDrawingProps">
+ <element name="a:hlinkClick">
+ <ref name="CT_Hyperlink_URL"/>
+ </element>
+ <element name="hlinkHover">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="id">
+ <ref name="ST_DrawingElementId"/>
+ </attribute>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="descr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hidden">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="title">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Hyperlink_URL">
+ <attribute name="r:id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualDrawingShapeProps">
+ <element name="spLocks">
+ <ref name="CT_ShapeLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="txBox">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualConnectorProperties">
+ <element name="cxnSpLocks">
+ <ref name="CT_ConnectorLocking"/>
+ </element>
+ <element name="stCxn">
+ <ref name="CT_Connection"/>
+ </element>
+ <element name="endCxn">
+ <ref name="CT_Connection"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ <define name="CT_NonVisualPictureProperties">
+ <element name="picLocks">
+ <ref name="CT_PictureLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ <attribute name="preferRelativeResize">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_NonVisualGroupDrawingShapeProps">
+ <element name="grpSpLocks">
+ <ref name="CT_GroupLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ <define name="CT_NonVisualGraphicFrameProperties">
+ <element name="graphicFrameLocks">
+ <ref name="CT_GraphicalObjectFrameLocking"/>
+ </element>
+ <element name="extLst">
+ <ref name="CT_OfficeArtExtensionList"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="CT_Hyperlink_URL" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_Hyperlink_URL"/>
+ <action name="start" action="handleHyperlinkURL"/>
+ </resource>
+ <resource name="CT_GraphicalObjectFrameLocking" resource="Properties">
+ <element name="extLst" tokenid="ooxml:CT_GraphicalObjectFrameLocking_extLst"/>
+ <attribute name="noGrp" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noGrp"/>
+ <attribute name="noDrilldown" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noDrilldown"/>
+ <attribute name="noSelect" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noSelect"/>
+ <attribute name="noChangeAspect" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noChangeAspect"/>
+ <attribute name="noMove" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noMove"/>
+ <attribute name="noResize" tokenid="ooxml:CT_GraphicalObjectFrameLocking_noResize"/>
+ </resource>
+ <resource name="CT_OfficeArtExtensionList" resource="Properties">
+ <element name="ext" tokenid="ooxml:CT_OfficeArtExtension"/>
+ </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"/>
+ <ref name="wpc"/>
+ <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"/>
+ <element name="wpc" tokenid="ooxml:CT_GraphicalObjectData_wpc"/>
+ <attribute name="uri" tokenid="ooxml:CT_GraphicalObjectData_uri"/>
+ </resource>
+ <resource name="CT_GraphicalObject" resource="Properties">
+ <element name="graphicData" tokenid="ooxml:CT_GraphicalObject_graphicData"/>
+ </resource>
+ <resource name="graphic" resource="Properties">
+ <element name="graphic" tokenid="ooxml:graphic_graphic"/>
+ </resource>
+ </namespace>
+ <namespace name="wp14">
+ <start name="sizeRelH"/>
+ <start name="sizeRelV"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing">
+ <define name="ST_SizeRelFromH">
+ <choice>
+ <value>margin</value>
+ <value>page</value>
+ <value>leftMargin</value>
+ <value>rightMargin</value>
+ <value>insideMargin</value>
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="ST_SizeRelFromV">
+ <choice>
+ <value>margin</value>
+ <value>page</value>
+ <value>topMargin</value>
+ <value>bottomMargin</value>
+ <value>insideMargin</value>
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="CT_SizeRelH">
+ <element name="pctWidth">
+ <ref name="ST_PositivePercentage"/>
+ </element>
+ <attribute name="relativeFrom">
+ <ref name="ST_SizeRelFromH"/>
+ </attribute>
+ </define>
+ <define name="CT_SizeRelV">
+ <element name="pctHeight">
+ <ref name="ST_PositivePercentage"/>
+ </element>
+ <attribute name="relativeFrom">
+ <ref name="ST_SizeRelFromV"/>
+ </attribute>
+ </define>
+ <define name="sizeRelH">
+ <element name="sizeRelH">
+ <ref name="CT_SizeRelH"/>
+ </element>
+ </define>
+ <define name="sizeRelV">
+ <element name="sizeRelV">
+ <ref name="CT_SizeRelV"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_SizeRelFromH" resource="List">
+ <value tokenid="ooxml:ST_SizeRelFromH_margin">margin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_page">page</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_leftMargin">leftMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_rightMargin">rightMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromH_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="ST_SizeRelFromV" resource="List">
+ <value tokenid="ooxml:ST_SizeRelFromV_margin">margin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_page">page</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_topMargin">topMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_bottomMargin">bottomMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:ST_SizeRelFromV_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="CT_SizeRelH" resource="Properties">
+ <element name="pctWidth" tokenid="ooxml:CT_SizeRelH_pctWidth"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_SizeRelH_relativeFrom"/>
+ </resource>
+ <resource name="CT_SizeRelV" resource="Properties">
+ <element name="pctHeight" tokenid="ooxml:CT_SizeRelV_pctHeight"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_SizeRelV_relativeFrom"/>
+ </resource>
+ <resource name="sizeRelH" resource="Properties">
+ <element name="sizeRelH" tokenid="ooxml:sizeRelH_sizeRelH"/>
+ </resource>
+ <resource name="sizeRelV" resource="Properties">
+ <element name="sizeRelV" tokenid="ooxml:sizeRelV_sizeRelV"/>
+ </resource>
+ </namespace>
+ <namespace name="w14">
+ <start name="glow"/>
+ <start name="shadow"/>
+ <start name="reflection"/>
+ <start name="textOutline"/>
+ <start name="textFill"/>
+ <start name="scene3d"/>
+ <start name="props3d"/>
+ <start name="ligatures"/>
+ <start name="numForm"/>
+ <start name="numSpacing"/>
+ <start name="stylisticSets"/>
+ <start name="cntxtAlts"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2010/wordml" attributeFormDefault="qualified">
+ <define name="ST_SchemeColorVal">
+ <choice>
+ <value>bg1</value>
+ <value>tx1</value>
+ <value>bg2</value>
+ <value>tx2</value>
+ <value>accent1</value>
+ <value>accent2</value>
+ <value>accent3</value>
+ <value>accent4</value>
+ <value>accent5</value>
+ <value>accent6</value>
+ <value>hlink</value>
+ <value>folHlink</value>
+ <value>dk1</value>
+ <value>lt1</value>
+ <value>dk2</value>
+ <value>lt2</value>
+ <value>phClr</value>
+ </choice>
+ </define>
+ <define name="ST_RectAlignment">
+ <choice>
+ <value>none</value>
+ <value>tl</value>
+ <value>t</value>
+ <value>tr</value>
+ <value>l</value>
+ <value>ctr</value>
+ <value>r</value>
+ <value>bl</value>
+ <value>b</value>
+ <value>br</value>
+ </choice>
+ </define>
+ <define name="ST_LineCap">
+ <choice>
+ <value>rnd</value>
+ <value>sq</value>
+ <value>flat</value>
+ </choice>
+ </define>
+ <define name="ST_CompoundLine">
+ <choice>
+ <value>sng</value>
+ <value>dbl</value>
+ <value>thickThin</value>
+ <value>thinThick</value>
+ <value>tri</value>
+ </choice>
+ </define>
+ <define name="ST_PenAlignment">
+ <choice>
+ <value>ctr</value>
+ <value>in</value>
+ </choice>
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <value>true</value>
+ <value>false</value>
+ <value>0</value>
+ <value>1</value>
+ </choice>
+ </define>
+ <define name="ST_PathShadeType">
+ <choice>
+ <value>shape</value>
+ <value>circle</value>
+ <value>rect</value>
+ </choice>
+ </define>
+ <define name="ST_PresetLineDashVal">
+ <choice>
+ <value>solid</value>
+ <value>dot</value>
+ <value>sysDot</value>
+ <value>dash</value>
+ <value>sysDash</value>
+ <value>lgDash</value>
+ <value>dashDot</value>
+ <value>sysDashDot</value>
+ <value>lgDashDot</value>
+ <value>lgDashDotDot</value>
+ <value>sysDashDotDot</value>
+ </choice>
+ </define>
+ <define name="ST_PresetCameraType">
+ <choice>
+ <value>legacyObliqueTopLeft</value>
+ <value>legacyObliqueTop</value>
+ <value>legacyObliqueTopRight</value>
+ <value>legacyObliqueLeft</value>
+ <value>legacyObliqueFront</value>
+ <value>legacyObliqueRight</value>
+ <value>legacyObliqueBottomLeft</value>
+ <value>legacyObliqueBottom</value>
+ <value>legacyObliqueBottomRight</value>
+ <value>legacyPerspectiveTopLeft</value>
+ <value>legacyPerspectiveTop</value>
+ <value>legacyPerspectiveTopRight</value>
+ <value>legacyPerspectiveLeft</value>
+ <value>legacyPerspectiveFront</value>
+ <value>legacyPerspectiveRight</value>
+ <value>legacyPerspectiveBottomLeft</value>
+ <value>legacyPerspectiveBottom</value>
+ <value>legacyPerspectiveBottomRight</value>
+ <value>orthographicFront</value>
+ <value>isometricTopUp</value>
+ <value>isometricTopDown</value>
+ <value>isometricBottomUp</value>
+ <value>isometricBottomDown</value>
+ <value>isometricLeftUp</value>
+ <value>isometricLeftDown</value>
+ <value>isometricRightUp</value>
+ <value>isometricRightDown</value>
+ <value>isometricOffAxis1Left</value>
+ <value>isometricOffAxis1Right</value>
+ <value>isometricOffAxis1Top</value>
+ <value>isometricOffAxis2Left</value>
+ <value>isometricOffAxis2Right</value>
+ <value>isometricOffAxis2Top</value>
+ <value>isometricOffAxis3Left</value>
+ <value>isometricOffAxis3Right</value>
+ <value>isometricOffAxis3Bottom</value>
+ <value>isometricOffAxis4Left</value>
+ <value>isometricOffAxis4Right</value>
+ <value>isometricOffAxis4Bottom</value>
+ <value>obliqueTopLeft</value>
+ <value>obliqueTop</value>
+ <value>obliqueTopRight</value>
+ <value>obliqueLeft</value>
+ <value>obliqueRight</value>
+ <value>obliqueBottomLeft</value>
+ <value>obliqueBottom</value>
+ <value>obliqueBottomRight</value>
+ <value>perspectiveFront</value>
+ <value>perspectiveLeft</value>
+ <value>perspectiveRight</value>
+ <value>perspectiveAbove</value>
+ <value>perspectiveBelow</value>
+ <value>perspectiveAboveLeftFacing</value>
+ <value>perspectiveAboveRightFacing</value>
+ <value>perspectiveContrastingLeftFacing</value>
+ <value>perspectiveContrastingRightFacing</value>
+ <value>perspectiveHeroicLeftFacing</value>
+ <value>perspectiveHeroicRightFacing</value>
+ <value>perspectiveHeroicExtremeLeftFacing</value>
+ <value>perspectiveHeroicExtremeRightFacing</value>
+ <value>perspectiveRelaxed</value>
+ <value>perspectiveRelaxedModerately</value>
+ </choice>
+ </define>
+ <define name="ST_LightRigType">
+ <choice>
+ <value>legacyFlat1</value>
+ <value>legacyFlat2</value>
+ <value>legacyFlat3</value>
+ <value>legacyFlat4</value>
+ <value>legacyNormal1</value>
+ <value>legacyNormal2</value>
+ <value>legacyNormal3</value>
+ <value>legacyNormal4</value>
+ <value>legacyHarsh1</value>
+ <value>legacyHarsh2</value>
+ <value>legacyHarsh3</value>
+ <value>legacyHarsh4</value>
+ <value>threePt</value>
+ <value>balanced</value>
+ <value>soft</value>
+ <value>harsh</value>
+ <value>flood</value>
+ <value>contrasting</value>
+ <value>morning</value>
+ <value>sunrise</value>
+ <value>sunset</value>
+ <value>chilly</value>
+ <value>freezing</value>
+ <value>flat</value>
+ <value>twoPt</value>
+ <value>glow</value>
+ <value>brightRoom</value>
+ </choice>
+ </define>
+ <define name="ST_LightRigDirection">
+ <choice>
+ <value>tl</value>
+ <value>t</value>
+ <value>tr</value>
+ <value>l</value>
+ <value>r</value>
+ <value>bl</value>
+ <value>b</value>
+ <value>br</value>
+ </choice>
+ </define>
+ <define name="ST_BevelPresetType">
+ <choice>
+ <value>relaxedInset</value>
+ <value>circle</value>
+ <value>slope</value>
+ <value>cross</value>
+ <value>angle</value>
+ <value>softRound</value>
+ <value>convex</value>
+ <value>coolSlant</value>
+ <value>divot</value>
+ <value>riblet</value>
+ <value>hardEdge</value>
+ <value>artDeco</value>
+ </choice>
+ </define>
+ <define name="ST_PresetMaterialType">
+ <choice>
+ <value>legacyMatte</value>
+ <value>legacyPlastic</value>
+ <value>legacyMetal</value>
+ <value>legacyWireframe</value>
+ <value>matte</value>
+ <value>plastic</value>
+ <value>metal</value>
+ <value>warmMatte</value>
+ <value>translucentPowder</value>
+ <value>powder</value>
+ <value>dkEdge</value>
+ <value>softEdge</value>
+ <value>clear</value>
+ <value>flat</value>
+ <value>softmetal</value>
+ <value>none</value>
+ </choice>
+ </define>
+ <define name="ST_Ligatures">
+ <choice>
+ <value>none</value>
+ <value>standard</value>
+ <value>contextual</value>
+ <value>historical</value>
+ <value>discretional</value>
+ <value>standardContextual</value>
+ <value>standardHistorical</value>
+ <value>contextualHistorical</value>
+ <value>standardDiscretional</value>
+ <value>contextualDiscretional</value>
+ <value>historicalDiscretional</value>
+ <value>standardContextualHistorical</value>
+ <value>standardContextualDiscretional</value>
+ <value>standardHistoricalDiscretional</value>
+ <value>contextualHistoricalDiscretional</value>
+ <value>all</value>
+ </choice>
+ </define>
+ <define name="ST_NumForm">
+ <choice>
+ <value>default</value>
+ <value>lining</value>
+ <value>oldStyle</value>
+ </choice>
+ </define>
+ <define name="ST_NumSpacing">
+ <choice>
+ <value>default</value>
+ <value>proportional</value>
+ <value>tabular</value>
+ </choice>
+ </define>
+
+ <define name="ST_PositiveCoordinate">
+ <data type="long"/>
+ </define>
+ <define name="ST_HexColorRGB">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_PositiveFixedPercentage">
+ <data type="long"/>
+ </define>
+ <define name="ST_PositivePercentage">
+ <data type="long"/>
+ </define>
+ <define name="ST_Percentage">
+ <data type="long"/>
+ </define>
+ <define name="ST_PositiveFixedAngle">
+ <data type="int"/>
+ </define>
+ <define name="ST_FixedAngle">
+ <data type="int"/>
+ </define>
+ <define name="ST_LineWidth">
+ <data type="int"/>
+ </define>
+ <define name="ST_UnsignedDecimalNumber">
+ <data type="unsignedLong"/>
+ </define>
+
+ <define name="EG_ColorChoice">
+ <choice>
+ <element name="srgbClr">
+ <ref name="CT_SRgbColor"/>
+ </element>
+ <element name="schemeClr">
+ <ref name="CT_SchemeColor"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_ColorTransform">
+ <choice>
+ <element name="tint">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="shade">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="alpha">
+ <ref name="CT_PositiveFixedPercentage"/>
+ </element>
+ <element name="hueMod">
+ <ref name="CT_PositivePercentage"/>
+ </element>
+ <element name="sat">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="satOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="satMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lum">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lumOff">
+ <ref name="CT_Percentage"/>
+ </element>
+ <element name="lumMod">
+ <ref name="CT_Percentage"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_FillProperties">
+ <choice>
+ <element name="noFill">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="solidFill">
+ <ref name="CT_SolidColorFillProperties"/>
+ </element>
+ <element name="gradFill">
+ <ref name="CT_GradientFillProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_ShadeProperties">
+ <choice>
+ <element name="lin">
+ <ref name="CT_LinearShadeProperties"/>
+ </element>
+ <element name="path">
+ <ref name="CT_PathShadeProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_LineDashProperties">
+ <choice>
+ <element name="prstDash">
+ <ref name="CT_PresetLineDashProperties"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_LineJoinProperties">
+ <choice>
+ <element name="round">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="bevel">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="miter">
+ <ref name="CT_LineJoinMiterProperties"/>
+ </element>
+ </choice>
+ </define>
+
+ <define name="CT_SRgbColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_HexColorRGB"/>
+ </attribute>
+ </define>
+ <define name="CT_SchemeColor">
+ <ref name="EG_ColorTransform"/>
+ <attribute name="val">
+ <ref name="ST_SchemeColorVal"/>
+ </attribute>
+ </define>
+ <define name="CT_PositiveFixedPercentage">
+ <attribute name="val">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_PositivePercentage">
+ <attribute name="val">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Percentage">
+ <attribute name="val">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Empty">
+ </define>
+ <define name="CT_SolidColorFillProperties">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_GradientFillProperties">
+ <element name="gsLst">
+ <ref name="CT_GradientStopList"/>
+ </element>
+ <ref name="EG_ShadeProperties"/>
+ </define>
+ <define name="CT_LinearShadeProperties">
+ <attribute name="ang">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="scaled">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_PathShadeProperties">
+ <element name="fillToRect">
+ <ref name="CT_RelativeRect"/>
+ </element>
+ <attribute name="path">
+ <ref name="ST_PathShadeType"/>
+ </attribute>
+ </define>
+ <define name="CT_GradientStopList">
+ <element name="gs">
+ <ref name="CT_GradientStop"/>
+ </element>
+ </define>
+ <define name="CT_GradientStop">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="pos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_RelativeRect">
+ <attribute name="l">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ </define>
+ <define name="CT_PresetLineDashProperties">
+ <attribute name="val">
+ <ref name="ST_PresetLineDashVal"/>
+ </attribute>
+ </define>
+ <define name="CT_LineJoinMiterProperties">
+ <attribute name="lim">
+ <ref name="ST_PositivePercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_Camera">
+ <attribute name="prst">
+ <ref name="ST_PresetCameraType"/>
+ </attribute>
+ </define>
+ <define name="CT_LightRig">
+ <element name="rot">
+ <ref name="CT_SphereCoords"/>
+ </element>
+ <attribute name="rig">
+ <ref name="ST_LightRigType"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_LightRigDirection"/>
+ </attribute>
+ </define>
+ <define name="CT_SphereCoords">
+ <attribute name="lat">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="lon">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="rev">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_Bevel">
+ <attribute name="w">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="prst">
+ <ref name="ST_BevelPresetType"/>
+ </attribute>
+ </define>
+ <define name="CT_Color">
+ <ref name="EG_ColorChoice"/>
+ </define>
+ <define name="CT_StyleSet">
+ <attribute name="id">
+ <ref name="ST_UnsignedDecimalNumber"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_OnOff">
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+
+
+ <!-- Main Elements-->
+ <define name="CT_Glow">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="rad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_Shadow">
+ <ref name="EG_ColorChoice"/>
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_Reflection">
+ <attribute name="blurRad">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="stA">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="stPos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="endA">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="endPos">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="dist">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="dir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="fadeDir">
+ <ref name="ST_PositiveFixedAngle"/>
+ </attribute>
+ <attribute name="sx">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="sy">
+ <ref name="ST_Percentage"/>
+ </attribute>
+ <attribute name="kx">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="ky">
+ <ref name="ST_FixedAngle"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_RectAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_TextOutlineEffect">
+ <ref name="EG_FillProperties"/>
+ <ref name="EG_LineDashProperties"/>
+ <ref name="EG_LineJoinProperties"/>
+ <attribute name="w">
+ <ref name="ST_LineWidth"/>
+ </attribute>
+ <attribute name="cap">
+ <ref name="ST_LineCap"/>
+ </attribute>
+ <attribute name="cmpd">
+ <ref name="ST_CompoundLine"/>
+ </attribute>
+ <attribute name="algn">
+ <ref name="ST_PenAlignment"/>
+ </attribute>
+ </define>
+ <define name="CT_FillTextEffect">
+ <ref name="EG_FillProperties"/>
+ </define>
+ <define name="CT_Scene3D">
+ <element name="camera">
+ <ref name="CT_Camera"/>
+ </element>
+ <element name="lightRig">
+ <ref name="CT_LightRig"/>
+ </element>
+ </define>
+ <define name="CT_Props3D">
+ <element name="bevelT">
+ <ref name="CT_Bevel"/>
+ </element>
+ <element name="bevelB">
+ <ref name="CT_Bevel"/>
+ </element>
+ <element name="extrusionClr">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="contourClr">
+ <ref name="CT_Color"/>
+ </element>
+ <attribute name="extrusionH">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="contourW">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="prstMaterial">
+ <ref name="ST_PresetMaterialType"/>
+ </attribute>
+ </define>
+ <define name="CT_Ligatures">
+ <attribute name="val">
+ <ref name="ST_Ligatures"/>
+ </attribute>
+ </define>
+ <define name="CT_NumForm">
+ <attribute name="val">
+ <ref name="ST_NumForm"/>
+ </attribute>
+ </define>
+ <define name="CT_NumSpacing">
+ <attribute name="val">
+ <ref name="ST_NumSpacing"/>
+ </attribute>
+ </define>
+ <define name="CT_StylisticSets">
+ <element name="styleSet">
+ <ref name="CT_StyleSet"/>
+ </element>
+ </define>
+
+ <define name="glow">
+ <element name="glow">
+ <ref name="CT_Glow"/>
+ </element>
+ </define>
+ <define name="shadow">
+ <element name="shadow">
+ <ref name="CT_Shadow"/>
+ </element>
+ </define>
+ <define name="reflection">
+ <element name="reflection">
+ <ref name="CT_Reflection"/>
+ </element>
+ </define>
+ <define name="textOutline">
+ <element name="textOutline">
+ <ref name="CT_TextOutlineEffect"/>
+ </element>
+ </define>
+ <define name="textFill">
+ <element name="textFill">
+ <ref name="CT_FillTextEffect"/>
+ </element>
+ </define>
+ <define name="scene3d">
+ <element name="scene3d">
+ <ref name="CT_Scene3D"/>
+ </element>
+ </define>
+ <define name="props3d">
+ <element name="props3d">
+ <ref name="CT_Props3D"/>
+ </element>
+ </define>
+ <define name="ligatures">
+ <element name="ligatures">
+ <ref name="CT_Ligatures"/>
+ </element>
+ </define>
+ <define name="numForm">
+ <element name="numForm">
+ <ref name="CT_NumForm"/>
+ </element>
+ </define>
+ <define name="numSpacing">
+ <element name="numSpacing">
+ <ref name="CT_NumSpacing"/>
+ </element>
+ </define>
+ <define name="stylisticSets">
+ <element name="stylisticSets">
+ <ref name="CT_StylisticSets"/>
+ </element>
+ </define>
+ <define name="cntxtAlts">
+ <element name="cntxtAlts">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+
+ <define name="ST_String">
+ <data type="string"/>
+ </define>
+ <define name="CT_String">
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtCheckbox">
+ <element name="checked">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="checkedState">
+ <ref name="CT_String"/>
+ </element>
+ <element name="uncheckedState">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ </grammar>
+
+ <!-- Simple Types Resource Definitions -->
+ <resource name="CT_String" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_String_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SdtCheckbox" resource="Properties">
+ <element name="checked" tokenid="ooxml:CT_SdtCheckbox_checked"/>
+ <element name="checkedState" tokenid="ooxml:CT_SdtCheckbox_checkedState"/>
+ <element name="uncheckedState" tokenid="ooxml:CT_SdtCheckbox_uncheckedState"/>
+ </resource>
+ <resource name="ST_SchemeColorVal" resource="List">
+ <value tokenid="ooxml:ST_SchemeColorVal_bg1">bg1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_tx1">tx1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_bg2">bg2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_tx2">tx2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent1">accent1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent2">accent2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent3">accent3</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent4">accent4</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent5">accent5</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_accent6">accent6</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_hlink">hlink</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_folHlink">folHlink</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_dk1">dk1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_lt1">lt1</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_dk2">dk2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_lt2">lt2</value>
+ <value tokenid="ooxml:ST_SchemeColorVal_phClr">phClr</value>
+ </resource>
+ <resource name="ST_RectAlignment" resource="List">
+ <value tokenid="ooxml:ST_RectAlignment_none">none</value>
+ <value tokenid="ooxml:ST_RectAlignment_tl">tl</value>
+ <value tokenid="ooxml:ST_RectAlignment_t">t</value>
+ <value tokenid="ooxml:ST_RectAlignment_tr">tr</value>
+ <value tokenid="ooxml:ST_RectAlignment_l">l</value>
+ <value tokenid="ooxml:ST_RectAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:ST_RectAlignment_r">r</value>
+ <value tokenid="ooxml:ST_RectAlignment_bl">bl</value>
+ <value tokenid="ooxml:ST_RectAlignment_b">b</value>
+ <value tokenid="ooxml:ST_RectAlignment_br">br</value>
+ </resource>
+ <resource name="ST_LineCap" resource="List">
+ <value tokenid="ooxml:ST_LineCap_rnd">rnd</value>
+ <value tokenid="ooxml:ST_LineCap_sq">sq</value>
+ <value tokenid="ooxml:ST_LineCap_flat">flat</value>
+ </resource>
+ <resource name="ST_CompoundLine" resource="List">
+ <value tokenid="ooxml:ST_CompoundLine_sng">sng</value>
+ <value tokenid="ooxml:ST_CompoundLine_dbl">dbl</value>
+ <value tokenid="ooxml:ST_CompoundLine_thickThin">thickThin</value>
+ <value tokenid="ooxml:ST_CompoundLine_thinThick">thinThick</value>
+ <value tokenid="ooxml:ST_CompoundLine_tri">tri</value>
+ </resource>
+ <resource name="ST_PenAlignment" resource="List">
+ <value tokenid="ooxml:ST_PenAlignment_ctr">ctr</value>
+ <value tokenid="ooxml:ST_PenAlignment_in">in</value>
+ </resource>
+ <resource name="ST_OnOff" resource="List">
+ <value tokenid="ooxml:ST_OnOff_true">true</value>
+ <value tokenid="ooxml:ST_OnOff_false">false</value>
+ <value tokenid="ooxml:ST_OnOff_0">0</value>
+ <value tokenid="ooxml:ST_OnOff_1">1</value>
+ </resource>
+ <resource name="ST_PathShadeType" resource="List">
+ <value tokenid="ooxml:ST_PathShadeType_shape">shape</value>
+ <value tokenid="ooxml:ST_PathShadeType_circle">circle</value>
+ <value tokenid="ooxml:ST_PathShadeType_rect">rect</value>
+ </resource>
+ <resource name="ST_PresetLineDashVal" resource="List">
+ <value tokenid="ooxml:ST_PresetLineDashVal_solid">solid</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_dot">dot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDot">sysDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_dash">dash</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDash">sysDash</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_lgDash">lgDash</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_dashDot">dashDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDashDot">sysDashDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_lgDashDot">lgDashDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_lgDashDotDot">lgDashDotDot</value>
+ <value tokenid="ooxml:ST_PresetLineDashVal_sysDashDotDot">sysDashDotDot</value>
+ </resource>
+ <resource name="ST_PresetCameraType" resource="List">
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueTopLeft">legacyObliqueTopLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueTop">legacyObliqueTop</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueTopRight">legacyObliqueTopRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueLeft">legacyObliqueLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueFront">legacyObliqueFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueRight">legacyObliqueRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueBottomLeft">legacyObliqueBottomLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueBottom">legacyObliqueBottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyObliqueBottomRight">legacyObliqueBottomRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveTopLeft">legacyPerspectiveTopLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveTop">legacyPerspectiveTop</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveTopRight">legacyPerspectiveTopRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveLeft">legacyPerspectiveLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveFront">legacyPerspectiveFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveRight">legacyPerspectiveRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveBottomLeft">legacyPerspectiveBottomLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveBottom">legacyPerspectiveBottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_legacyPerspectiveBottomRight">legacyPerspectiveBottomRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_orthographicFront">orthographicFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricTopUp">isometricTopUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricTopDown">isometricTopDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricBottomUp">isometricBottomUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricBottomDown">isometricBottomDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricLeftUp">isometricLeftUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricLeftDown">isometricLeftDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricRightUp">isometricRightUp</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricRightDown">isometricRightDown</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis1Left">isometricOffAxis1Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis1Right">isometricOffAxis1Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis1Top">isometricOffAxis1Top</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis2Left">isometricOffAxis2Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis2Right">isometricOffAxis2Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis2Top">isometricOffAxis2Top</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis3Left">isometricOffAxis3Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis3Right">isometricOffAxis3Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis3Bottom">isometricOffAxis3Bottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis4Left">isometricOffAxis4Left</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis4Right">isometricOffAxis4Right</value>
+ <value tokenid="ooxml:ST_PresetCameraType_isometricOffAxis4Bottom">isometricOffAxis4Bottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueTopLeft">obliqueTopLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueTop">obliqueTop</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueTopRight">obliqueTopRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueLeft">obliqueLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueRight">obliqueRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueBottomLeft">obliqueBottomLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueBottom">obliqueBottom</value>
+ <value tokenid="ooxml:ST_PresetCameraType_obliqueBottomRight">obliqueBottomRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveFront">perspectiveFront</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveLeft">perspectiveLeft</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveRight">perspectiveRight</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveAbove">perspectiveAbove</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveBelow">perspectiveBelow</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveAboveLeftFacing">perspectiveAboveLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveAboveRightFacing">perspectiveAboveRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveContrastingLeftFacing">perspectiveContrastingLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveContrastingRightFacing">perspectiveContrastingRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicLeftFacing">perspectiveHeroicLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicRightFacing">perspectiveHeroicRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicExtremeLeftFacing">perspectiveHeroicExtremeLeftFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveHeroicExtremeRightFacing">perspectiveHeroicExtremeRightFacing</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveRelaxed">perspectiveRelaxed</value>
+ <value tokenid="ooxml:ST_PresetCameraType_perspectiveRelaxedModerately">perspectiveRelaxedModerately</value>
+ </resource>
+ <resource name="ST_LightRigType" resource="List">
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat1">legacyFlat1</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat2">legacyFlat2</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat3">legacyFlat3</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyFlat4">legacyFlat4</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal1">legacyNormal1</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal2">legacyNormal2</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal3">legacyNormal3</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyNormal4">legacyNormal4</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh1">legacyHarsh1</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh2">legacyHarsh2</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh3">legacyHarsh3</value>
+ <value tokenid="ooxml:ST_LightRigType_legacyHarsh4">legacyHarsh4</value>
+ <value tokenid="ooxml:ST_LightRigType_threePt">threePt</value>
+ <value tokenid="ooxml:ST_LightRigType_balanced">balanced</value>
+ <value tokenid="ooxml:ST_LightRigType_soft">soft</value>
+ <value tokenid="ooxml:ST_LightRigType_harsh">harsh</value>
+ <value tokenid="ooxml:ST_LightRigType_flood">flood</value>
+ <value tokenid="ooxml:ST_LightRigType_contrasting">contrasting</value>
+ <value tokenid="ooxml:ST_LightRigType_morning">morning</value>
+ <value tokenid="ooxml:ST_LightRigType_sunrise">sunrise</value>
+ <value tokenid="ooxml:ST_LightRigType_sunset">sunset</value>
+ <value tokenid="ooxml:ST_LightRigType_chilly">chilly</value>
+ <value tokenid="ooxml:ST_LightRigType_freezing">freezing</value>
+ <value tokenid="ooxml:ST_LightRigType_flat">flat</value>
+ <value tokenid="ooxml:ST_LightRigType_twoPt">twoPt</value>
+ <value tokenid="ooxml:ST_LightRigType_glow">glow</value>
+ <value tokenid="ooxml:ST_LightRigType_brightRoom">brightRoom</value>
+ </resource>
+ <resource name="ST_LightRigDirection" resource="List">
+ <value tokenid="ooxml:ST_LightRigDirection_tl">tl</value>
+ <value tokenid="ooxml:ST_LightRigDirection_t">t</value>
+ <value tokenid="ooxml:ST_LightRigDirection_tr">tr</value>
+ <value tokenid="ooxml:ST_LightRigDirection_l">l</value>
+ <value tokenid="ooxml:ST_LightRigDirection_r">r</value>
+ <value tokenid="ooxml:ST_LightRigDirection_bl">bl</value>
+ <value tokenid="ooxml:ST_LightRigDirection_b">b</value>
+ <value tokenid="ooxml:ST_LightRigDirection_br">br</value>
+ </resource>
+ <resource name="ST_BevelPresetType" resource="List">
+ <value tokenid="ooxml:ST_BevelPresetType_relaxedInset">relaxedInset</value>
+ <value tokenid="ooxml:ST_BevelPresetType_circle">circle</value>
+ <value tokenid="ooxml:ST_BevelPresetType_slope">slope</value>
+ <value tokenid="ooxml:ST_BevelPresetType_cross">cross</value>
+ <value tokenid="ooxml:ST_BevelPresetType_angle">angle</value>
+ <value tokenid="ooxml:ST_BevelPresetType_softRound">softRound</value>
+ <value tokenid="ooxml:ST_BevelPresetType_convex">convex</value>
+ <value tokenid="ooxml:ST_BevelPresetType_coolSlant">coolSlant</value>
+ <value tokenid="ooxml:ST_BevelPresetType_divot">divot</value>
+ <value tokenid="ooxml:ST_BevelPresetType_riblet">riblet</value>
+ <value tokenid="ooxml:ST_BevelPresetType_hardEdge">hardEdge</value>
+ <value tokenid="ooxml:ST_BevelPresetType_artDeco">artDeco</value>
+ </resource>
+ <resource name="ST_PresetMaterialType" resource="List">
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyMatte">legacyMatte</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyPlastic">legacyPlastic</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyMetal">legacyMetal</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_legacyWireframe">legacyWireframe</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_matte">matte</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_plastic">plastic</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_metal">metal</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_warmMatte">warmMatte</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_translucentPowder">translucentPowder</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_powder">powder</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_dkEdge">dkEdge</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_softEdge">softEdge</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_clear">clear</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_flat">flat</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_softmetal">softmetal</value>
+ <value tokenid="ooxml:ST_PresetMaterialType_none">none</value>
+ </resource>
+ <resource name="ST_Ligatures" resource="List">
+ <value tokenid="ooxml:ST_Ligatures_none">none</value>
+ <value tokenid="ooxml:ST_Ligatures_standard">standard</value>
+ <value tokenid="ooxml:ST_Ligatures_contextual">contextual</value>
+ <value tokenid="ooxml:ST_Ligatures_historical">historical</value>
+ <value tokenid="ooxml:ST_Ligatures_discretional">discretional</value>
+ <value tokenid="ooxml:ST_Ligatures_standardContextual">standardContextual</value>
+ <value tokenid="ooxml:ST_Ligatures_standardHistorical">standardHistorical</value>
+ <value tokenid="ooxml:ST_Ligatures_contextualHistorical">contextualHistorical</value>
+ <value tokenid="ooxml:ST_Ligatures_standardDiscretional">standardDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_contextualDiscretional">contextualDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_historicalDiscretional">historicalDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_standardContextualHistorical">standardContextualHistorical</value>
+ <value tokenid="ooxml:ST_Ligatures_standardContextualDiscretional">standardContextualDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_standardHistoricalDiscretional">standardHistoricalDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_contextualHistoricalDiscretional">contextualHistoricalDiscretional</value>
+ <value tokenid="ooxml:ST_Ligatures_all">all</value>
+ </resource>
+ <resource name="ST_NumForm" resource="List">
+ <value tokenid="ooxml:ST_NumForm_default">default</value>
+ <value tokenid="ooxml:ST_NumForm_lining">lining</value>
+ <value tokenid="ooxml:ST_NumForm_oldStyle">oldStyle</value>
+ </resource>
+ <resource name="ST_NumSpacing" resource="List">
+ <value tokenid="ooxml:ST_NumSpacing_default">default</value>
+ <value tokenid="ooxml:ST_NumSpacing_proportional">proportional</value>
+ <value tokenid="ooxml:ST_NumSpacing_tabular">tabular</value>
+ </resource>
+
+ <resource name="ST_PositiveCoordinate" resource="Integer"/>
+ <resource name="ST_HexColorRGB" resource="Hex"/>
+ <resource name="ST_PositivePercentage" resource="Integer"/>
+ <resource name="ST_PositiveFixedPercentage" resource="Integer"/>
+ <resource name="ST_Percentage" resource="Integer"/>
+ <resource name="ST_PositiveFixedAngle" resource="Integer"/>
+ <resource name="ST_FixedAngle" resource="Integer"/>
+ <resource name="ST_LineWidth" resource="Integer"/>
+ <resource name="ST_UnsignedDecimalNumber" resource="Integer"/>
+
+ <!-- Groups Resource Definitions -->
+ <resource name="EG_ColorTransform" resource="Properties">
+ <element name="tint" tokenid="ooxml:EG_ColorTransform_tint"/>
+ <element name="shade" tokenid="ooxml:EG_ColorTransform_shade"/>
+ <element name="alpha" tokenid="ooxml:EG_ColorTransform_alpha"/>
+ <element name="hueMod" tokenid="ooxml:EG_ColorTransform_hueMod"/>
+ <element name="sat" tokenid="ooxml:EG_ColorTransform_sat"/>
+ <element name="satOff" tokenid="ooxml:EG_ColorTransform_satOff"/>
+ <element name="satMod" tokenid="ooxml:EG_ColorTransform_satMod"/>
+ <element name="lum" tokenid="ooxml:EG_ColorTransform_lum"/>
+ <element name="lumOff" tokenid="ooxml:EG_ColorTransform_lumOff"/>
+ <element name="lumMod" tokenid="ooxml:EG_ColorTransform_lumMod"/>
+ </resource>
+ <resource name="EG_ColorChoice" resource="Properties">
+ <element name="srgbClr" tokenid="ooxml:EG_ColorChoice_srgbClr"/>
+ <element name="schemeClr" tokenid="ooxml:EG_ColorChoice_schemeClr"/>
+ </resource>
+ <resource name="EG_FillProperties" resource="Properties">
+ <element name="noFill" tokenid="ooxml:EG_FillProperties_noFill"/>
+ <element name="solidFill" tokenid="ooxml:EG_FillProperties_solidFill"/>
+ <element name="gradFill" tokenid="ooxml:EG_FillProperties_gradFill"/>
+ </resource>
+ <resource name="EG_ShadeProperties" resource="Properties">
+ <element name="lin" tokenid="ooxml:EG_ShadeProperties_lin"/>
+ <element name="path" tokenid="ooxml:EG_ShadeProperties_path"/>
+ </resource>
+ <resource name="EG_LineDashProperties" resource="Properties">
+ <element name="prstDash" tokenid="ooxml:EG_LineDashProperties_prstDash"/>
+ </resource>
+ <resource name="EG_LineJoinProperties" resource="Properties">
+ <element name="round" tokenid="ooxml:EG_LineJoinProperties_round"/>
+ <element name="bevel" tokenid="ooxml:EG_LineJoinProperties_bevel"/>
+ <element name="miter" tokenid="ooxml:EG_LineJoinProperties_miter"/>
+ </resource>
+
+ <!-- Complex Types Resource Definitions -->
+ <resource name="CT_Glow" resource="Properties">
+ <attribute name="rad" tokenid="ooxml:CT_Glow_rad"/>
+ </resource>
+ <resource name="CT_SRgbColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SRgbColor_val"/>
+ </resource>
+ <resource name="CT_SchemeColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SchemeColor_val"/>
+ </resource>
+ <resource name="CT_PositiveFixedPercentage" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PositiveFixedPercentage_val"/>
+ </resource>
+ <resource name="CT_PositivePercentage" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PositivePercentage_val"/>
+ </resource>
+ <resource name="CT_Percentage" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Percentage_val"/>
+ </resource>
+ <resource name="CT_Empty" resource="Properties"/>
+ <resource name="CT_SolidColorFillProperties" resource="Properties"/>
+ <resource name="CT_GradientFillProperties" resource="Properties">
+ <element name="gsLst" tokenid="ooxml:CT_GradientFillProperties_gsLst"/>
+ </resource>
+ <resource name="CT_GradientStopList" resource="Properties">
+ <element name="gs" tokenid="ooxml:CT_GradientStopList_gs"/>
+ </resource>
+ <resource name="CT_GradientStop" resource="Properties">
+ <attribute name="pos" tokenid="ooxml:CT_GradientStop_pos"/>
+ </resource>
+ <resource name="CT_LinearShadeProperties" resource="Properties">
+ <attribute name="ang" tokenid="ooxml:CT_LinearShadeProperties_ang"/>
+ <attribute name="scaled" tokenid="ooxml:CT_LinearShadeProperties_scaled"/>
+ </resource>
+ <resource name="CT_PathShadeProperties" resource="Properties">
+ <element name="fillToRect" tokenid="ooxml:CT_PathShadeProperties_fillToRect"/>
+ <attribute name="path" tokenid="ooxml:CT_PathShadeProperties_path"/>
+ </resource>
+ <resource name="CT_RelativeRect" resource="Properties">
+ <attribute name="l" tokenid="ooxml:CT_RelativeRect_l"/>
+ <attribute name="t" tokenid="ooxml:CT_RelativeRect_t"/>
+ <attribute name="r" tokenid="ooxml:CT_RelativeRect_r"/>
+ <attribute name="b" tokenid="ooxml:CT_RelativeRect_b"/>
+ </resource>
+ <resource name="CT_PresetLineDashProperties" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_PresetLineDashProperties_val"/>
+ </resource>
+ <resource name="CT_LineJoinMiterProperties" resource="Properties">
+ <attribute name="lim" tokenid="ooxml:CT_LineJoinMiterProperties_lim"/>
+ </resource>
+ <resource name="CT_Camera" resource="Properties">
+ <attribute name="prst" tokenid="ooxml:CT_Camera_prst"/>
+ </resource>
+ <resource name="CT_LightRig" resource="Properties">
+ <element name="rot" tokenid="ooxml:CT_LightRig_rot"/>
+ <attribute name="rig" tokenid="ooxml:CT_LightRig_rig"/>
+ <attribute name="dir" tokenid="ooxml:CT_LightRig_dir"/>
+ </resource>
+ <resource name="CT_SphereCoords" resource="Properties">
+ <attribute name="lat" tokenid="ooxml:CT_SphereCoords_lat"/>
+ <attribute name="lon" tokenid="ooxml:CT_SphereCoords_lon"/>
+ <attribute name="rev" tokenid="ooxml:CT_SphereCoords_rev"/>
+ </resource>
+ <resource name="CT_Bevel" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_Bevel_w"/>
+ <attribute name="h" tokenid="ooxml:CT_Bevel_h"/>
+ <attribute name="prst" tokenid="ooxml:CT_Bevel_prst"/>
+ </resource>
+ <resource name="CT_Color" resource="Properties"/>
+ <resource name="CT_StyleSet" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_StyleSet_id"/>
+ <attribute name="val" tokenid="ooxml:CT_StyleSet_val"/>
+ </resource>
+ <resource name="CT_OnOff" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OnOff_val" action="setValue"/>
+ <action name="start" action="setDefaultBooleanValue"/>
+ </resource>
+
+ <!-- Main element content -->
+ <resource name="CT_Shadow" resource="Properties">
+ <attribute name="blurRad" tokenid="ooxml:CT_Shadow_blurRad"/>
+ <attribute name="dist" tokenid="ooxml:CT_Shadow_dist"/>
+ <attribute name="dir" tokenid="ooxml:CT_Shadow_dir"/>
+ <attribute name="sx" tokenid="ooxml:CT_Shadow_sx"/>
+ <attribute name="sy" tokenid="ooxml:CT_Shadow_sy"/>
+ <attribute name="kx" tokenid="ooxml:CT_Shadow_kx"/>
+ <attribute name="ky" tokenid="ooxml:CT_Shadow_ky"/>
+ <attribute name="algn" tokenid="ooxml:CT_Shadow_algn"/>
+ </resource>
+ <resource name="CT_Reflection" resource="Properties">
+ <attribute name="blurRad" tokenid="ooxml:CT_Reflection_blurRad"/>
+ <attribute name="stA" tokenid="ooxml:CT_Reflection_stA"/>
+ <attribute name="stPos" tokenid="ooxml:CT_Reflection_stPos"/>
+ <attribute name="endA" tokenid="ooxml:CT_Reflection_endA"/>
+ <attribute name="endPos" tokenid="ooxml:CT_Reflection_endPos"/>
+ <attribute name="dist" tokenid="ooxml:CT_Reflection_dist"/>
+ <attribute name="dir" tokenid="ooxml:CT_Reflection_dir"/>
+ <attribute name="fadeDir" tokenid="ooxml:CT_Reflection_fadeDir"/>
+ <attribute name="sx" tokenid="ooxml:CT_Reflection_sx"/>
+ <attribute name="sy" tokenid="ooxml:CT_Reflection_sy"/>
+ <attribute name="kx" tokenid="ooxml:CT_Reflection_kx"/>
+ <attribute name="ky" tokenid="ooxml:CT_Reflection_ky"/>
+ <attribute name="algn" tokenid="ooxml:CT_Reflection_algn"/>
+ </resource>
+ <resource name="CT_TextOutlineEffect" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_TextOutlineEffect_w"/>
+ <attribute name="cap" tokenid="ooxml:CT_TextOutlineEffect_cap"/>
+ <attribute name="cmpd" tokenid="ooxml:CT_TextOutlineEffect_cmpd"/>
+ <attribute name="algn" tokenid="ooxml:CT_TextOutlineEffect_algn"/>
+ </resource>
+ <resource name="CT_FillTextEffect" resource="Properties"/>
+ <resource name="CT_Scene3D" resource="Properties">
+ <element name="camera" tokenid="ooxml:CT_Scene3D_camera"/>
+ <element name="lightRig" tokenid="ooxml:CT_Scene3D_lightRig"/>
+ </resource>
+ <resource name="CT_Props3D" resource="Properties">
+ <element name="bevelT" tokenid="ooxml:CT_Props3D_bevelT"/>
+ <element name="bevelB" tokenid="ooxml:CT_Props3D_bevelB"/>
+ <element name="extrusionClr" tokenid="ooxml:CT_Props3D_extrusionClr"/>
+ <element name="contourClr" tokenid="ooxml:CT_Props3D_contourClr"/>
+ <attribute name="extrusionH" tokenid="ooxml:CT_Props3D_extrusionH"/>
+ <attribute name="contourW" tokenid="ooxml:CT_Props3D_contourW"/>
+ <attribute name="prstMaterial" tokenid="ooxml:CT_Props3D_prstMaterial"/>
+ </resource>
+ <resource name="CT_Ligatures" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Ligatures_val"/>
+ </resource>
+ <resource name="CT_NumForm" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_NumForm_val"/>
+ </resource>
+ <resource name="CT_NumSpacing" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_NumSpacing_val"/>
+ </resource>
+ <resource name="CT_StylisticSets" resource="Properties">
+ <attribute name="styleSet" tokenid="ooxml:CT_StylisticSets_styleSet"/>
+ </resource>
+
+ <resource name="glow" resource="Properties">
+ <element name="glow" tokenid="ooxml:glow_glow"/>
+ </resource>
+ <resource name="shadow" resource="Properties">
+ <element name="shadow" tokenid="ooxml:shadow_shadow"/>
+ </resource>
+ <resource name="reflection" resource="Properties">
+ <element name="reflection" tokenid="ooxml:reflection_reflection"/>
+ </resource>
+ <resource name="textOutline" resource="Properties">
+ <element name="textOutline" tokenid="ooxml:textOutline_textOutline"/>
+ </resource>
+ <resource name="textFill" resource="Properties">
+ <element name="textFill" tokenid="ooxml:textFill_textFill"/>
+ </resource>
+ <resource name="scene3d" resource="Properties">
+ <element name="scene3d" tokenid="ooxml:scene3d_scene3d"/>
+ </resource>
+ <resource name="props3d" resource="Properties">
+ <element name="props3d" tokenid="ooxml:props3d_props3d"/>
+ </resource>
+ <resource name="ligatures" resource="Properties">
+ <element name="ligatures" tokenid="ooxml:ligatures_ligatures"/>
+ </resource>
+ <resource name="numForm" resource="Properties">
+ <element name="numForm" tokenid="ooxml:numForm_numForm"/>
+ </resource>
+ <resource name="numSpacing" resource="Properties">
+ <element name="numSpacing" tokenid="ooxml:numSpacing_numSpacing"/>
+ </resource>
+ <resource name="stylisticSets" resource="Properties">
+ <element name="stylisticSets" tokenid="ooxml:stylisticSets_stylisticSets"/>
+ </resource>
+ <resource name="cntxtAlts" resource="Properties">
+ <element name="cntxtAlts" tokenid="ooxml:cntxtAlts_cntxtAlts"/>
+ </resource>
+ </namespace>
+ <namespace name="w15">
+ <start name="commentsEx"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/word/2012/wordml" attributeFormDefault="qualified">
+ <define name="commentsEx">
+ <element name="commentsEx">
+ <ref name="CT_CommentsEx"/>
+ </element>
+ </define>
+ <define name="CT_CommentsEx">
+ <element name="commentEx">
+ <ref name="CT_CommentEx"/>
+ </element>
+ </define>
+ <define name="CT_CommentEx">
+ <attribute name="paraId">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ <attribute name="paraIdParent">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ <attribute name="done">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_LongHexNumber">
+ <data type="hexBinary"/>
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <value>true</value>
+ <value>false</value>
+ <value>0</value>
+ <value>1</value>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="CT_CommentsEx" resource="Stream">
+ <element name="commentEx" tokenid="ooxml:CT_CommentsEx_commentEx"/>
+ </resource>
+ <resource name="CT_CommentEx" resource="CommentEx">
+ <attribute name="paraId" tokenid="ooxml:CT_CommentEx_paraId" action="att_paraId"/>
+ <attribute name="paraIdParent" tokenid="ooxml:CT_CommentEx_paraIdParent" action="att_paraIdParent"/>
+ <attribute name="done" tokenid="ooxml:CT_CommentEx_done" action="att_done"/>
+ </resource>
+ <resource name="ST_LongHexNumber" resource="String"/>
+ <resource name="ST_OnOff" resource="Boolean"/>
+ </namespace>
+ <namespace name="a14">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.microsoft.com/office/drawing/2010/main">
+ <!-- Simple types -->
+ <define name="ST_ArtisticEffectParam10">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ArtisticEffectParam100">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ArtisticEffectParam4">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ArtisticEffectParam6">
+ <data type="integer"/>
+ </define>
+ <define name="ST_ColorTemperature">
+ <data type="integer"/>
+ </define>
+ <define name="ST_SaturationAmount">
+ <data type="integer"/>
+ </define>
+
+ <!-- Complex types for effects -->
+ <define name="CT_PictureEffectBlur">
+ <attribute name="visible">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectCement">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="crackSpacing">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectChalkSketch">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam4"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectCrisscrossEtching">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam4"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectCutout">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="numberOfShades">
+ <ref name="ST_ArtisticEffectParam6"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectFilmGrain">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="grainSize">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectGlass">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="scaling">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectGlowDiffused">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="intensity">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectGlowEdges">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="smoothness">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectLightScreen">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="gridSize">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectLineDrawing">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pencilSize">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectMarker">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="size">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectMosiaicBubbles">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPaintStrokes">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="intensity">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPaintBrush">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="brushSize">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPastelsSmooth">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="scaling">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPencilGrayscale">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pencilSize">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPencilSketch">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="pressure">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPhotocopy">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="detail">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectPlasticWrap">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="smoothness">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectTexturizer">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="scaling">
+ <ref name="ST_ArtisticEffectParam100"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectWatercolorSponge">
+ <attribute name="trans">
+ <ref name="ST_PositiveFixedPercentage"/>
+ </attribute>
+ <attribute name="brushSize">
+ <ref name="ST_ArtisticEffectParam10"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectBrightnessContrast">
+ <attribute name="bright">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ <attribute name="contrast">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectColorTemperature">
+ <attribute name="colorTemp">
+ <ref name="ST_ColorTemperature"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectSaturation">
+ <attribute name="sat">
+ <ref name="ST_SaturationAmount"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureEffectSharpenSoften">
+ <attribute name="amount">
+ <ref name="ST_FixedPercentage"/>
+ </attribute>
+ </define>
+
+ <!-- Complex types for containers -->
+ <define name="CT_PictureEffect">
+ <choice>
+ <element name="artisticBlur">
+ <ref name="CT_PictureEffectBlur"/>
+ </element>
+ <element name="artisticCement">
+ <ref name="CT_PictureEffectCement"/>
+ </element>
+ <element name="artisticChalkSketch">
+ <ref name="CT_PictureEffectChalkSketch"/>
+ </element>
+ <element name="artisticCrisscrossEtching">
+ <ref name="CT_PictureEffectCrisscrossEtching"/>
+ </element>
+ <element name="artisticCutout">
+ <ref name="CT_PictureEffectCutout"/>
+ </element>
+ <element name="artisticFilmGrain">
+ <ref name="CT_PictureEffectFilmGrain"/>
+ </element>
+ <element name="artisticGlass">
+ <ref name="CT_PictureEffectGlass"/>
+ </element>
+ <element name="artisticGlowDiffused">
+ <ref name="CT_PictureEffectGlowDiffused"/>
+ </element>
+ <element name="artisticGlowEdges">
+ <ref name="CT_PictureEffectGlowEdges"/>
+ </element>
+ <element name="artisticLightScreen">
+ <ref name="CT_PictureEffectLightScreen"/>
+ </element>
+ <element name="artisticLineDrawing">
+ <ref name="CT_PictureEffectLineDrawing"/>
+ </element>
+ <element name="artisticMarker">
+ <ref name="CT_PictureEffectMarker"/>
+ </element>
+ <element name="artisticMosiaicBubbles">
+ <ref name="CT_PictureEffectMosiaicBubbles"/>
+ </element>
+ <element name="artisticPaintStrokes">
+ <ref name="CT_PictureEffectPaintStrokes"/>
+ </element>
+ <element name="artisticPaintBrush">
+ <ref name="CT_PictureEffectPaintBrush"/>
+ </element>
+ <element name="artisticPastelsSmooth">
+ <ref name="CT_PictureEffectPastelsSmooth"/>
+ </element>
+ <element name="artisticPencilGrayscale">
+ <ref name="CT_PictureEffectPencilGrayscale"/>
+ </element>
+ <element name="artisticPencilSketch">
+ <ref name="CT_PictureEffectPencilSketch"/>
+ </element>
+ <element name="artisticPhotocopy">
+ <ref name="CT_PictureEffectPhotocopy"/>
+ </element>
+ <element name="artisticPlasticWrap">
+ <ref name="CT_PictureEffectPlasticWrap"/>
+ </element>
+ <element name="artisticTexturizer">
+ <ref name="CT_PictureEffectTexturizer"/>
+ </element>
+ <element name="artisticWatercolorSponge">
+ <ref name="CT_PictureEffectWatercolorSponge"/>
+ </element>
+ <element name="brightnessContrast">
+ <ref name="CT_PictureEffectBrightnessContrast"/>
+ </element>
+ <element name="colorTemperature">
+ <ref name="CT_PictureEffectColorTemperature"/>
+ </element>
+ <element name="saturation">
+ <ref name="CT_PictureEffectSaturation"/>
+ </element>
+ <element name="sharpenSoften">
+ <ref name="CT_PictureEffectSharpenSoften"/>
+ </element>
+ </choice>
+ <attribute name="visible">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_PictureLayer">
+ <element name="imgEffect">
+ <ref name="CT_PictureEffect"/>
+ </element>
+ <attribute name="r:embed">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Photo">
+ <element name="imgLayer">
+ <ref name="CT_PictureLayer"/>
+ </element>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="dml-shapeGeometry">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/main">
+ <define name="ST_ShapeType">
+ <choice>
+ <!-- Line Shape -->
+ <value>line</value>
+ <!-- Line Inverse Shape -->
+ <value>lineInv</value>
+ <!-- Triangle Shape -->
+ <value>triangle</value>
+ <!-- Right Triangle Shape -->
+ <value>rtTriangle</value>
+ <!-- Rectangle Shape -->
+ <value>rect</value>
+ <!-- Diamond Shape -->
+ <value>diamond</value>
+ <!-- Parallelogram Shape -->
+ <value>parallelogram</value>
+ <!-- Trapezoid Shape -->
+ <value>trapezoid</value>
+ <!-- Non-Isosceles Trapezoid Shape -->
+ <value>nonIsoscelesTrapezoid</value>
+ <!-- Pentagon Shape -->
+ <value>pentagon</value>
+ <!-- Hexagon Shape -->
+ <value>hexagon</value>
+ <!-- Heptagon Shape -->
+ <value>heptagon</value>
+ <!-- Octagon Shape -->
+ <value>octagon</value>
+ <!-- Decagon Shape -->
+ <value>decagon</value>
+ <!-- Dodecagon Shape -->
+ <value>dodecagon</value>
+ <!-- Four Pointed Star Shape -->
+ <value>star4</value>
+ <!-- Five Pointed Star Shape -->
+ <value>star5</value>
+ <!-- Six Pointed Star Shape -->
+ <value>star6</value>
+ <!-- Seven Pointed Star Shape -->
+ <value>star7</value>
+ <!-- Eight Pointed Star Shape -->
+ <value>star8</value>
+ <!-- Ten Pointed Star Shape -->
+ <value>star10</value>
+ <!-- Twelve Pointed Star Shape -->
+ <value>star12</value>
+ <!-- Sixteen Pointed Star Shape -->
+ <value>star16</value>
+ <!-- Twenty Four Pointed Star Shape -->
+ <value>star24</value>
+ <!-- Thirty Two Pointed Star Shape -->
+ <value>star32</value>
+ <!-- Round Corner Rectangle Shape -->
+ <value>roundRect</value>
+ <!-- One Round Corner Rectangle Shape -->
+ <value>round1Rect</value>
+ <!-- Two Same-side Round Corner Rectangle Shape -->
+ <value>round2SameRect</value>
+ <!-- Two Diagonal Round Corner Rectangle Shape -->
+ <value>round2DiagRect</value>
+ <!-- One Snip One Round Corner Rectangle Shape -->
+ <value>snipRoundRect</value>
+ <!-- One Snip Corner Rectangle Shape -->
+ <value>snip1Rect</value>
+ <!-- Two Same-side Snip Corner Rectangle Shape -->
+ <value>snip2SameRect</value>
+ <!-- Two Diagonal Snip Corner Rectangle Shape -->
+ <value>snip2DiagRect</value>
+ <!-- Plaque Shape -->
+ <value>plaque</value>
+ <!-- Ellipse Shape -->
+ <value>ellipse</value>
+ <!-- Teardrop Shape -->
+ <value>teardrop</value>
+ <!-- Home Plate Shape -->
+ <value>homePlate</value>
+ <!-- Chevron Shape -->
+ <value>chevron</value>
+ <!-- Pie Wedge Shape -->
+ <value>pieWedge</value>
+ <!-- Pie Shape -->
+ <value>pie</value>
+ <!-- Block Arc Shape -->
+ <value>blockArc</value>
+ <!-- Donut Shape -->
+ <value>donut</value>
+ <!-- No Smoking Shape -->
+ <value>noSmoking</value>
+ <!-- Right Arrow Shape -->
+ <value>rightArrow</value>
+ <!-- Left Arrow Shape -->
+ <value>leftArrow</value>
+ <!-- Up Arrow Shape -->
+ <value>upArrow</value>
+ <!-- Down Arrow Shape -->
+ <value>downArrow</value>
+ <!-- Striped Right Arrow Shape -->
+ <value>stripedRightArrow</value>
+ <!-- Notched Right Arrow Shape -->
+ <value>notchedRightArrow</value>
+ <!-- Bent Up Arrow Shape -->
+ <value>bentUpArrow</value>
+ <!-- Left Right Arrow Shape -->
+ <value>leftRightArrow</value>
+ <!-- Up Down Arrow Shape -->
+ <value>upDownArrow</value>
+ <!-- Left Up Arrow Shape -->
+ <value>leftUpArrow</value>
+ <!-- Left Right Up Arrow Shape -->
+ <value>leftRightUpArrow</value>
+ <!-- Quad-Arrow Shape -->
+ <value>quadArrow</value>
+ <!-- Callout Left Arrow Shape -->
+ <value>leftArrowCallout</value>
+ <!-- Callout Right Arrow Shape -->
+ <value>rightArrowCallout</value>
+ <!-- Callout Up Arrow Shape -->
+ <value>upArrowCallout</value>
+ <!-- Callout Down Arrow Shape -->
+ <value>downArrowCallout</value>
+ <!-- Callout Left Right Arrow Shape -->
+ <value>leftRightArrowCallout</value>
+ <!-- Callout Up Down Arrow Shape -->
+ <value>upDownArrowCallout</value>
+ <!-- Callout Quad-Arrow Shape -->
+ <value>quadArrowCallout</value>
+ <!-- Bent Arrow Shape -->
+ <value>bentArrow</value>
+ <!-- U-Turn Arrow Shape -->
+ <value>uturnArrow</value>
+ <!-- Circular Arrow Shape -->
+ <value>circularArrow</value>
+ <!-- Left Circular Arrow Shape -->
+ <value>leftCircularArrow</value>
+ <!-- Left Right Circular Arrow Shape -->
+ <value>leftRightCircularArrow</value>
+ <!-- Curved Right Arrow Shape -->
+ <value>curvedRightArrow</value>
+ <!-- Curved Left Arrow Shape -->
+ <value>curvedLeftArrow</value>
+ <!-- Curved Up Arrow Shape -->
+ <value>curvedUpArrow</value>
+ <!-- Curved Down Arrow Shape -->
+ <value>curvedDownArrow</value>
+ <!-- Swoosh Arrow Shape -->
+ <value>swooshArrow</value>
+ <!-- Cube Shape -->
+ <value>cube</value>
+ <!-- Can Shape -->
+ <value>can</value>
+ <!-- Lightning Bolt Shape -->
+ <value>lightningBolt</value>
+ <!-- Heart Shape -->
+ <value>heart</value>
+ <!-- Sun Shape -->
+ <value>sun</value>
+ <!-- Moon Shape -->
+ <value>moon</value>
+ <!-- Smiley Face Shape -->
+ <value>smileyFace</value>
+ <!-- Irregular Seal 1 Shape -->
+ <value>irregularSeal1</value>
+ <!-- Irregular Seal 2 Shape -->
+ <value>irregularSeal2</value>
+ <!-- Folded Corner Shape -->
+ <value>foldedCorner</value>
+ <!-- Bevel Shape -->
+ <value>bevel</value>
+ <!-- Frame Shape -->
+ <value>frame</value>
+ <!-- Half Frame Shape -->
+ <value>halfFrame</value>
+ <!-- Corner Shape -->
+ <value>corner</value>
+ <!-- Diagonal Stripe Shape -->
+ <value>diagStripe</value>
+ <!-- Chord Shape -->
+ <value>chord</value>
+ <!-- Curved Arc Shape -->
+ <value>arc</value>
+ <!-- Left Bracket Shape -->
+ <value>leftBracket</value>
+ <!-- Right Bracket Shape -->
+ <value>rightBracket</value>
+ <!-- Left Brace Shape -->
+ <value>leftBrace</value>
+ <!-- Right Brace Shape -->
+ <value>rightBrace</value>
+ <!-- Bracket Pair Shape -->
+ <value>bracketPair</value>
+ <!-- Brace Pair Shape -->
+ <value>bracePair</value>
+ <!-- Straight Connector 1 Shape -->
+ <value>straightConnector1</value>
+ <!-- Bent Connector 2 Shape -->
+ <value>bentConnector2</value>
+ <!-- Bent Connector 3 Shape -->
+ <value>bentConnector3</value>
+ <!-- Bent Connector 4 Shape -->
+ <value>bentConnector4</value>
+ <!-- Bent Connector 5 Shape -->
+ <value>bentConnector5</value>
+ <!-- Curved Connector 2 Shape -->
+ <value>curvedConnector2</value>
+ <!-- Curved Connector 3 Shape -->
+ <value>curvedConnector3</value>
+ <!-- Curved Connector 4 Shape -->
+ <value>curvedConnector4</value>
+ <!-- Curved Connector 5 Shape -->
+ <value>curvedConnector5</value>
+ <!-- Callout 1 Shape -->
+ <value>callout1</value>
+ <!-- Callout 2 Shape -->
+ <value>callout2</value>
+ <!-- Callout 3 Shape -->
+ <value>callout3</value>
+ <!-- Callout 1 Shape -->
+ <value>accentCallout1</value>
+ <!-- Callout 2 Shape -->
+ <value>accentCallout2</value>
+ <!-- Callout 3 Shape -->
+ <value>accentCallout3</value>
+ <!-- Callout 1 with Border Shape -->
+ <value>borderCallout1</value>
+ <!-- Callout 2 with Border Shape -->
+ <value>borderCallout2</value>
+ <!-- Callout 3 with Border Shape -->
+ <value>borderCallout3</value>
+ <!-- Callout 1 with Border and Accent Shape -->
+ <value>accentBorderCallout1</value>
+ <!-- Callout 2 with Border and Accent Shape -->
+ <value>accentBorderCallout2</value>
+ <!-- Callout 3 with Border and Accent Shape -->
+ <value>accentBorderCallout3</value>
+ <!-- Callout Wedge Rectangle Shape -->
+ <value>wedgeRectCallout</value>
+ <!-- Callout Wedge Round Rectangle Shape -->
+ <value>wedgeRoundRectCallout</value>
+ <!-- Callout Wedge Ellipse Shape -->
+ <value>wedgeEllipseCallout</value>
+ <!-- Callout Cloud Shape -->
+ <value>cloudCallout</value>
+ <!-- Cloud Shape -->
+ <value>cloud</value>
+ <!-- Ribbon Shape -->
+ <value>ribbon</value>
+ <!-- Ribbon 2 Shape -->
+ <value>ribbon2</value>
+ <!-- Ellipse Ribbon Shape -->
+ <value>ellipseRibbon</value>
+ <!-- Ellipse Ribbon 2 Shape -->
+ <value>ellipseRibbon2</value>
+ <!-- Left Right Ribbon Shape -->
+ <value>leftRightRibbon</value>
+ <!-- Vertical Scroll Shape -->
+ <value>verticalScroll</value>
+ <!-- Horizontal Scroll Shape -->
+ <value>horizontalScroll</value>
+ <!-- Wave Shape -->
+ <value>wave</value>
+ <!-- Double Wave Shape -->
+ <value>doubleWave</value>
+ <!-- Plus Shape -->
+ <value>plus</value>
+ <!-- Process Flow Shape -->
+ <value>flowChartProcess</value>
+ <!-- Decision Flow Shape -->
+ <value>flowChartDecision</value>
+ <!-- Input Output Flow Shape -->
+ <value>flowChartInputOutput</value>
+ <!-- Predefined Process Flow Shape -->
+ <value>flowChartPredefinedProcess</value>
+ <!-- Internal Storage Flow Shape -->
+ <value>flowChartInternalStorage</value>
+ <!-- Document Flow Shape -->
+ <value>flowChartDocument</value>
+ <!-- Multi-Document Flow Shape -->
+ <value>flowChartMultidocument</value>
+ <!-- Terminator Flow Shape -->
+ <value>flowChartTerminator</value>
+ <!-- Preparation Flow Shape -->
+ <value>flowChartPreparation</value>
+ <!-- Manual Input Flow Shape -->
+ <value>flowChartManualInput</value>
+ <!-- Manual Operation Flow Shape -->
+ <value>flowChartManualOperation</value>
+ <!-- Connector Flow Shape -->
+ <value>flowChartConnector</value>
+ <!-- Punched Card Flow Shape -->
+ <value>flowChartPunchedCard</value>
+ <!-- Punched Tape Flow Shape -->
+ <value>flowChartPunchedTape</value>
+ <!-- Summing Junction Flow Shape -->
+ <value>flowChartSummingJunction</value>
+ <!-- Or Flow Shape -->
+ <value>flowChartOr</value>
+ <!-- Collate Flow Shape -->
+ <value>flowChartCollate</value>
+ <!-- Sort Flow Shape -->
+ <value>flowChartSort</value>
+ <!-- Extract Flow Shape -->
+ <value>flowChartExtract</value>
+ <!-- Merge Flow Shape -->
+ <value>flowChartMerge</value>
+ <!-- Offline Storage Flow Shape -->
+ <value>flowChartOfflineStorage</value>
+ <!-- Online Storage Flow Shape -->
+ <value>flowChartOnlineStorage</value>
+ <!-- Magnetic Tape Flow Shape -->
+ <value>flowChartMagneticTape</value>
+ <!-- Magnetic Disk Flow Shape -->
+ <value>flowChartMagneticDisk</value>
+ <!-- Magnetic Drum Flow Shape -->
+ <value>flowChartMagneticDrum</value>
+ <!-- Display Flow Shape -->
+ <value>flowChartDisplay</value>
+ <!-- Delay Flow Shape -->
+ <value>flowChartDelay</value>
+ <!-- Alternate Process Flow Shape -->
+ <value>flowChartAlternateProcess</value>
+ <!-- Off-Page Connector Flow Shape -->
+ <value>flowChartOffpageConnector</value>
+ <!-- Blank Button Shape -->
+ <value>actionButtonBlank</value>
+ <!-- Home Button Shape -->
+ <value>actionButtonHome</value>
+ <!-- Help Button Shape -->
+ <value>actionButtonHelp</value>
+ <!-- Information Button Shape -->
+ <value>actionButtonInformation</value>
+ <!-- Forward or Next Button Shape -->
+ <value>actionButtonForwardNext</value>
+ <!-- Back or Previous Button Shape -->
+ <value>actionButtonBackPrevious</value>
+ <!-- End Button Shape -->
+ <value>actionButtonEnd</value>
+ <!-- Beginning Button Shape -->
+ <value>actionButtonBeginning</value>
+ <!-- Return Button Shape -->
+ <value>actionButtonReturn</value>
+ <!-- Document Button Shape -->
+ <value>actionButtonDocument</value>
+ <!-- Sound Button Shape -->
+ <value>actionButtonSound</value>
+ <!-- Movie Button Shape -->
+ <value>actionButtonMovie</value>
+ <!-- Gear 6 Shape -->
+ <value>gear6</value>
+ <!-- Gear 9 Shape -->
+ <value>gear9</value>
+ <!-- Funnel Shape -->
+ <value>funnel</value>
+ <!-- Plus Math Shape -->
+ <value>mathPlus</value>
+ <!-- Minus Math Shape -->
+ <value>mathMinus</value>
+ <!-- Multiply Math Shape -->
+ <value>mathMultiply</value>
+ <!-- Divide Math Shape -->
+ <value>mathDivide</value>
+ <!-- Equal Math Shape -->
+ <value>mathEqual</value>
+ <!-- Not Equal Math Shape -->
+ <value>mathNotEqual</value>
+ <!-- Corner Tabs Shape -->
+ <value>cornerTabs</value>
+ <!-- Square Tabs Shape -->
+ <value>squareTabs</value>
+ <!-- Plaque Tabs Shape -->
+ <value>plaqueTabs</value>
+ <!-- Chart X Shape -->
+ <value>chartX</value>
+ <!-- Chart Star Shape -->
+ <value>chartStar</value>
+ <!-- Chart Plus Shape -->
+ <value>chartPlus</value>
+ </choice>
+ </define>
+ <define name="ST_TextShapeType">
+ <choice>
+ <!-- No Text Shape -->
+ <value>textNoShape</value>
+ <!-- Plain Text Shape -->
+ <value>textPlain</value>
+ <!-- Stop Sign Text Shape -->
+ <value>textStop</value>
+ <!-- Triangle Text Shape -->
+ <value>textTriangle</value>
+ <!-- Inverted Triangle Text Shape -->
+ <value>textTriangleInverted</value>
+ <!-- Chevron Text Shape -->
+ <value>textChevron</value>
+ <!-- Inverted Chevron Text Shape -->
+ <value>textChevronInverted</value>
+ <!-- Inside Ring Text Shape -->
+ <value>textRingInside</value>
+ <!-- Outside Ring Text Shape -->
+ <value>textRingOutside</value>
+ <!-- Upward Arch Text Shape -->
+ <value>textArchUp</value>
+ <!-- Downward Arch Text Shape -->
+ <value>textArchDown</value>
+ <!-- Circle Text Shape -->
+ <value>textCircle</value>
+ <!-- Button Text Shape -->
+ <value>textButton</value>
+ <!-- Upward Pour Arch Text Shape -->
+ <value>textArchUpPour</value>
+ <!-- Downward Pour Arch Text Shape -->
+ <value>textArchDownPour</value>
+ <!-- Circle Pour Text Shape -->
+ <value>textCirclePour</value>
+ <!-- Button Pour Text Shape -->
+ <value>textButtonPour</value>
+ <!-- Upward Curve Text Shape -->
+ <value>textCurveUp</value>
+ <!-- Downward Curve Text Shape -->
+ <value>textCurveDown</value>
+ <!-- Upward Can Text Shape -->
+ <value>textCanUp</value>
+ <!-- Downward Can Text Shape -->
+ <value>textCanDown</value>
+ <!-- Wave 1 Text Shape -->
+ <value>textWave1</value>
+ <!-- Wave 2 Text Shape -->
+ <value>textWave2</value>
+ <!-- Double Wave 1 Text Shape -->
+ <value>textDoubleWave1</value>
+ <!-- Wave 4 Text Shape -->
+ <value>textWave4</value>
+ <!-- Inflate Text Shape -->
+ <value>textInflate</value>
+ <!-- Deflate Text Shape -->
+ <value>textDeflate</value>
+ <!-- Bottom Inflate Text Shape -->
+ <value>textInflateBottom</value>
+ <!-- Bottom Deflate Text Shape -->
+ <value>textDeflateBottom</value>
+ <!-- Top Inflate Text Shape -->
+ <value>textInflateTop</value>
+ <!-- Top Deflate Text Shape -->
+ <value>textDeflateTop</value>
+ <!-- Deflate-Inflate Text Shape -->
+ <value>textDeflateInflate</value>
+ <!-- Deflate-Inflate-Deflate Text Shape -->
+ <value>textDeflateInflateDeflate</value>
+ <!-- Right Fade Text Shape -->
+ <value>textFadeRight</value>
+ <!-- Left Fade Text Shape -->
+ <value>textFadeLeft</value>
+ <!-- Upward Fade Text Shape -->
+ <value>textFadeUp</value>
+ <!-- Downward Fade Text Shape -->
+ <value>textFadeDown</value>
+ <!-- Upward Slant Text Shape -->
+ <value>textSlantUp</value>
+ <!-- Downward Slant Text Shape -->
+ <value>textSlantDown</value>
+ <!-- Upward Cascade Text Shape -->
+ <value>textCascadeUp</value>
+ <!-- Downward Cascade Text Shape -->
+ <value>textCascadeDown</value>
+ </choice>
+ </define>
+ <define name="ST_GeomGuideName">
+ <data type="token"/>
+ </define>
+ <define name="ST_GeomGuideFormula">
+ <data type="string"/>
+ </define>
+ <define name="CT_GeomGuide">
+ <attribute name="name">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="fmla">
+ <ref name="ST_GeomGuideFormula"/>
+ </attribute>
+ </define>
+ <define name="CT_GeomGuideList">
+ <element name="gd">
+ <ref name="CT_GeomGuide"/>
+ </element>
+ </define>
+ <define name="ST_AdjCoordinate">
+ <choice>
+ <ref name="ST_Coordinate"/>
+ <ref name="ST_GeomGuideName"/>
+ </choice>
+ </define>
+ <!-- Union -->
+ <define name="ST_AdjAngle">
+ <choice>
+ <ref name="ST_Angle"/>
+ <ref name="ST_GeomGuideName"/>
+ </choice>
+ </define>
+ <!-- Union -->
+ <define name="CT_AdjPoint2D">
+ <attribute name="x">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="y">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_GeomRect">
+ <attribute name="l">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_XYAdjustHandle">
+ <element name="pos">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ <attribute name="gdRefX">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minX">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxX">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="gdRefY">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minY">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxY">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_PolarAdjustHandle">
+ <element name="pos">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ <attribute name="gdRefR">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="gdRefAng">
+ <ref name="ST_GeomGuideName"/>
+ </attribute>
+ <attribute name="minAng">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="maxAng">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ </define>
+ <define name="CT_ConnectionSite">
+ <element name="pos">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ <attribute name="ang">
+ <ref name="ST_AdjAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_AdjustHandleList">
+ <choice>
+ <element name="ahXY">
+ <ref name="CT_XYAdjustHandle"/>
+ </element>
+ <element name="ahPolar">
+ <ref name="CT_PolarAdjustHandle"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_ConnectionSiteList">
+ <element name="cxn">
+ <ref name="CT_ConnectionSite"/>
+ </element>
+ </define>
+ <define name="CT_Connection">
+ <attribute name="id">
+ <ref name="ST_DrawingElementId"/>
+ </attribute>
+ <attribute name="idx">
+ <data type="unsignedInt"/>
+ </attribute>
+ </define>
+ <define name="CT_Path2DMoveTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DLineTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DArcTo">
+ <attribute name="wR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="hR">
+ <ref name="ST_AdjCoordinate"/>
+ </attribute>
+ <attribute name="stAng">
+ <ref name="ST_AdjAngle"/>
+ </attribute>
+ <attribute name="swAng">
+ <ref name="ST_AdjAngle"/>
+ </attribute>
+ </define>
+ <define name="CT_Path2DQuadBezierTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DCubicBezierTo">
+ <element name="pt">
+ <ref name="CT_AdjPoint2D"/>
+ </element>
+ </define>
+ <define name="CT_Path2DClose">
+ </define>
+ <define name="ST_PathFillMode">
+ <choice>
+ <!-- No Path Fill -->
+ <value>none</value>
+ <!-- Normal Path Fill -->
+ <value>norm</value>
+ <!-- Lighten Path Fill -->
+ <value>lighten</value>
+ <!-- Lighten Path Fill Less -->
+ <value>lightenLess</value>
+ <!-- Darken Path Fill -->
+ <value>darken</value>
+ <!-- Darken Path Fill Less -->
+ <value>darkenLess</value>
+ </choice>
+ </define>
+ <define name="CT_Path2D">
+ <choice>
+ <element name="close">
+ <ref name="CT_Path2DClose"/>
+ </element>
+ <element name="moveTo">
+ <ref name="CT_Path2DMoveTo"/>
+ </element>
+ <element name="lnTo">
+ <ref name="CT_Path2DLineTo"/>
+ </element>
+ <element name="arcTo">
+ <ref name="CT_Path2DArcTo"/>
+ </element>
+ <element name="quadBezTo">
+ <ref name="CT_Path2DQuadBezierTo"/>
+ </element>
+ <element name="cubicBezTo">
+ <ref name="CT_Path2DCubicBezierTo"/>
+ </element>
+ </choice>
+ <attribute name="w">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="h">
+ <ref name="ST_PositiveCoordinate"/>
+ </attribute>
+ <attribute name="fill">
+ <ref name="ST_PathFillMode"/>
+ </attribute>
+ <attribute name="stroke">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="extrusionOk">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_Path2DList">
+ <element name="path">
+ <ref name="CT_Path2D"/>
+ </element>
+ </define>
+ <define name="CT_PresetGeometry2D">
+ <element name="avLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <attribute name="prst">
+ <ref name="ST_ShapeType"/>
+ </attribute>
+ </define>
+ <define name="CT_PresetTextShape">
+ <element name="avLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <attribute name="prst">
+ <ref name="ST_TextShapeType"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomGeometry2D">
+ <element name="avLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <element name="gdLst">
+ <ref name="CT_GeomGuideList"/>
+ </element>
+ <element name="ahLst">
+ <ref name="CT_AdjustHandleList"/>
+ </element>
+ <element name="cxnLst">
+ <ref name="CT_ConnectionSiteList"/>
+ </element>
+ <element name="rect">
+ <ref name="CT_GeomRect"/>
+ </element>
+ <element name="pathLst">
+ <ref name="CT_Path2DList"/>
+ </element>
+ </define>
+ <define name="EG_Geometry">
+ <choice>
+ <element name="custGeom">
+ <ref name="CT_CustomGeometry2D"/>
+ </element>
+ <element name="prstGeom">
+ <ref name="CT_PresetGeometry2D"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_TextGeometry">
+ <choice>
+ <element name="custGeom">
+ <ref name="CT_CustomGeometry2D"/>
+ </element>
+ <element name="prstTxWarp">
+ <ref name="CT_PresetTextShape"/>
+ </element>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="ST_ShapeType" resource="List">
+ <value tokenid="ooxml:Value_ST_ShapeType_line">line</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_lineInv">lineInv</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_triangle">triangle</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rtTriangle">rtTriangle</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rect">rect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_diamond">diamond</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_parallelogram">parallelogram</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_trapezoid">trapezoid</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_nonIsoscelesTrapezoid">nonIsoscelesTrapezoid</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_pentagon">pentagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_hexagon">hexagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_heptagon">heptagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_octagon">octagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_decagon">decagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_dodecagon">dodecagon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star4">star4</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star5">star5</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star6">star6</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star7">star7</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star8">star8</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star10">star10</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star12">star12</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star16">star16</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star24">star24</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_star32">star32</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_roundRect">roundRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_round1Rect">round1Rect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_round2SameRect">round2SameRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_round2DiagRect">round2DiagRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snipRoundRect">snipRoundRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snip1Rect">snip1Rect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snip2SameRect">snip2SameRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_snip2DiagRect">snip2DiagRect</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_plaque">plaque</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ellipse">ellipse</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_teardrop">teardrop</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_homePlate">homePlate</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chevron">chevron</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_pieWedge">pieWedge</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_pie">pie</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_blockArc">blockArc</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_donut">donut</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_noSmoking">noSmoking</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightArrow">rightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftArrow">leftArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upArrow">upArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_downArrow">downArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_stripedRightArrow">stripedRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_notchedRightArrow">notchedRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentUpArrow">bentUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightArrow">leftRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upDownArrow">upDownArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftUpArrow">leftUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightUpArrow">leftRightUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_quadArrow">quadArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftArrowCallout">leftArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightArrowCallout">rightArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upArrowCallout">upArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_downArrowCallout">downArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightArrowCallout">leftRightArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_upDownArrowCallout">upDownArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_quadArrowCallout">quadArrowCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentArrow">bentArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_uturnArrow">uturnArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_circularArrow">circularArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftCircularArrow">leftCircularArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightCircularArrow">leftRightCircularArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedRightArrow">curvedRightArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedLeftArrow">curvedLeftArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedUpArrow">curvedUpArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedDownArrow">curvedDownArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_swooshArrow">swooshArrow</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cube">cube</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_can">can</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_lightningBolt">lightningBolt</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_heart">heart</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_sun">sun</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_moon">moon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_smileyFace">smileyFace</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_irregularSeal1">irregularSeal1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_irregularSeal2">irregularSeal2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_foldedCorner">foldedCorner</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bevel">bevel</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_frame">frame</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_halfFrame">halfFrame</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_corner">corner</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_diagStripe">diagStripe</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chord">chord</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_arc">arc</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftBracket">leftBracket</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightBracket">rightBracket</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftBrace">leftBrace</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_rightBrace">rightBrace</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bracketPair">bracketPair</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bracePair">bracePair</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_straightConnector1">straightConnector1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector2">bentConnector2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector3">bentConnector3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector4">bentConnector4</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_bentConnector5">bentConnector5</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector2">curvedConnector2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector3">curvedConnector3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector4">curvedConnector4</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_curvedConnector5">curvedConnector5</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_callout1">callout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_callout2">callout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_callout3">callout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentCallout1">accentCallout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentCallout2">accentCallout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentCallout3">accentCallout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_borderCallout1">borderCallout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_borderCallout2">borderCallout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_borderCallout3">borderCallout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentBorderCallout1">accentBorderCallout1</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentBorderCallout2">accentBorderCallout2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_accentBorderCallout3">accentBorderCallout3</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wedgeRectCallout">wedgeRectCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wedgeRoundRectCallout">wedgeRoundRectCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wedgeEllipseCallout">wedgeEllipseCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cloudCallout">cloudCallout</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cloud">cloud</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ribbon">ribbon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ribbon2">ribbon2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ellipseRibbon">ellipseRibbon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_ellipseRibbon2">ellipseRibbon2</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_leftRightRibbon">leftRightRibbon</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_verticalScroll">verticalScroll</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_horizontalScroll">horizontalScroll</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_wave">wave</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_doubleWave">doubleWave</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_plus">plus</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartProcess">flowChartProcess</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDecision">flowChartDecision</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartInputOutput">flowChartInputOutput</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPredefinedProcess">flowChartPredefinedProcess</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartInternalStorage">flowChartInternalStorage</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDocument">flowChartDocument</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMultidocument">flowChartMultidocument</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartTerminator">flowChartTerminator</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPreparation">flowChartPreparation</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartManualInput">flowChartManualInput</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartManualOperation">flowChartManualOperation</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartConnector">flowChartConnector</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPunchedCard">flowChartPunchedCard</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartPunchedTape">flowChartPunchedTape</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartSummingJunction">flowChartSummingJunction</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOr">flowChartOr</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartCollate">flowChartCollate</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartSort">flowChartSort</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartExtract">flowChartExtract</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMerge">flowChartMerge</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOfflineStorage">flowChartOfflineStorage</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOnlineStorage">flowChartOnlineStorage</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMagneticTape">flowChartMagneticTape</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMagneticDisk">flowChartMagneticDisk</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartMagneticDrum">flowChartMagneticDrum</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDisplay">flowChartDisplay</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartDelay">flowChartDelay</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartAlternateProcess">flowChartAlternateProcess</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_flowChartOffpageConnector">flowChartOffpageConnector</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonBlank">actionButtonBlank</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonHome">actionButtonHome</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonHelp">actionButtonHelp</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonInformation">actionButtonInformation</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonForwardNext">actionButtonForwardNext</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonBackPrevious">actionButtonBackPrevious</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonEnd">actionButtonEnd</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonBeginning">actionButtonBeginning</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonReturn">actionButtonReturn</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonDocument">actionButtonDocument</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonSound">actionButtonSound</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_actionButtonMovie">actionButtonMovie</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_gear6">gear6</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_gear9">gear9</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_funnel">funnel</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathPlus">mathPlus</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathMinus">mathMinus</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathMultiply">mathMultiply</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathDivide">mathDivide</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathEqual">mathEqual</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_mathNotEqual">mathNotEqual</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_cornerTabs">cornerTabs</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_squareTabs">squareTabs</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_plaqueTabs">plaqueTabs</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chartX">chartX</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chartStar">chartStar</value>
+ <value tokenid="ooxml:Value_ST_ShapeType_chartPlus">chartPlus</value>
+ </resource>
+ <resource name="ST_TextShapeType" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textNoShape">textNoShape</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textPlain">textPlain</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textStop">textStop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textTriangle">textTriangle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textTriangleInverted">textTriangleInverted</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textChevron">textChevron</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textChevronInverted">textChevronInverted</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textRingInside">textRingInside</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textRingOutside">textRingOutside</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchUp">textArchUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchDown">textArchDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCircle">textCircle</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textButton">textButton</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchUpPour">textArchUpPour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textArchDownPour">textArchDownPour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCirclePour">textCirclePour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textButtonPour">textButtonPour</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCurveUp">textCurveUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCurveDown">textCurveDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCanUp">textCanUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCanDown">textCanDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textWave1">textWave1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textWave2">textWave2</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDoubleWave1">textDoubleWave1</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textWave4">textWave4</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textInflate">textInflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflate">textDeflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textInflateBottom">textInflateBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateBottom">textDeflateBottom</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textInflateTop">textInflateTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateTop">textDeflateTop</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateInflate">textDeflateInflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textDeflateInflateDeflate">textDeflateInflateDeflate</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeRight">textFadeRight</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeLeft">textFadeLeft</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeUp">textFadeUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textFadeDown">textFadeDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textSlantUp">textSlantUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textSlantDown">textSlantDown</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCascadeUp">textCascadeUp</value>
+ <value tokenid="ooxml:Value_drawingml_ST_TextShapeType_textCascadeDown">textCascadeDown</value>
+ </resource>
+ <resource name="ST_GeomGuideName" resource="String"/>
+ <resource name="ST_GeomGuideFormula" resource="String"/>
+ <resource name="CT_GeomGuideList" resource="Properties">
+ <element name="gd" tokenid="ooxml:CT_GeomGuideList_gd"/>
+ </resource>
+ <resource name="ST_PathFillMode" resource="List">
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_none">none</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_norm">norm</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_lighten">lighten</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_lightenLess">lightenLess</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_darken">darken</value>
+ <value tokenid="ooxml:Value_drawingml_ST_PathFillMode_darkenLess">darkenLess</value>
+ </resource>
+ <resource name="CT_PresetGeometry2D" resource="Properties">
+ <element name="avLst" tokenid="ooxml:CT_PresetGeometry2D_avLst"/>
+ <attribute name="prst" tokenid="ooxml:CT_PresetGeometry2D_prst"/>
+ </resource>
+ <resource name="CT_CustomGeometry2D" resource="Properties">
+ <element name="avLst" tokenid="ooxml:CT_CustomGeometry2D_avLst"/>
+ <element name="gdLst" tokenid="ooxml:CT_CustomGeometry2D_gdLst"/>
+ <element name="ahLst" tokenid="ooxml:CT_CustomGeometry2D_ahLst"/>
+ <element name="cxnLst" tokenid="ooxml:CT_CustomGeometry2D_cxnLst"/>
+ <element name="rect" tokenid="ooxml:CT_CustomGeometry2D_rect"/>
+ <element name="pathLst" tokenid="ooxml:CT_CustomGeometry2D_pathLst"/>
+ </resource>
+ <resource name="EG_Geometry" resource="Properties">
+ <element name="custGeom" tokenid="ooxml:EG_Geometry_custGeom"/>
+ <element name="prstGeom" tokenid="ooxml:EG_Geometry_prstGeom"/>
+ </resource>
+ </namespace>
+ <namespace name="dml-wordprocessingDrawing">
+ <start name="inline"/>
+ <start name="anchor"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
+ <include href="dml-graphicalObject"/>
+ <include href="dml-documentProperties"/>
+ <!-- start = inline | anchor -->
+ <define name="ST_Coordinate">
+ <data type="long"/>
+ </define>
+ <define name="CT_EffectExtent">
+ <attribute name="l">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="t">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="r">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ <attribute name="b">
+ <ref name="ST_Coordinate"/>
+ </attribute>
+ </define>
+ <define name="ST_WrapDistance">
+ <data type="unsignedInt"/>
+ </define>
+ <define name="ST_EditId">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_Inline">
+ <element name="extent">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <element name="docPr">
+ <ref name="CT_NonVisualDrawingProps"/>
+ </element>
+ <element name="cNvGraphicFramePr">
+ <ref name="CT_NonVisualGraphicFrameProperties"/>
+ </element>
+ <element name="a:graphic">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelH">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelV">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="wp14:anchorId">
+ <ref name="ST_EditId"/>
+ </attribute>
+ </define>
+ <define name="ST_WrapText">
+ <choice>
+ <!-- Both Sides -->
+ <value>bothSides</value>
+ <!-- Left Side Only -->
+ <value>left</value>
+ <!-- Right Side Only -->
+ <value>right</value>
+ <!-- Largest Side Only -->
+ <value>largest</value>
+ </choice>
+ </define>
+ <define name="CT_WrapPath">
+ <element name="start">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="lineTo">
+ <ref name="CT_Point2D"/>
+ </element>
+ <attribute name="edited">
+ <data type="boolean"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapNone">
+ </define>
+ <define name="CT_WrapSquare">
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <attribute name="wrapText">
+ <ref name="ST_WrapText"/>
+ </attribute>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapTight">
+ <element name="wrapPolygon">
+ <ref name="CT_WrapPath"/>
+ </element>
+ <attribute name="wrapText">
+ <ref name="ST_WrapText"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapThrough">
+ <element name="wrapPolygon">
+ <ref name="CT_WrapPath"/>
+ </element>
+ <attribute name="wrapText">
+ <ref name="ST_WrapText"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="CT_WrapTopBottom">
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ </define>
+ <define name="EG_WrapType">
+ <choice>
+ <element name="wrapNone">
+ <ref name="CT_WrapNone"/>
+ </element>
+ <element name="wrapSquare">
+ <ref name="CT_WrapSquare"/>
+ </element>
+ <element name="wrapTight">
+ <ref name="CT_WrapTight"/>
+ </element>
+ <element name="wrapThrough">
+ <ref name="CT_WrapThrough"/>
+ </element>
+ <element name="wrapTopAndBottom">
+ <ref name="CT_WrapTopBottom"/>
+ </element>
+ </choice>
+ </define>
+ <define name="ST_PositionOffset">
+ <data type="int"/>
+ </define>
+ <define name="ST_AlignH">
+ <choice>
+ <!-- Left Alignment -->
+ <value>left</value>
+ <!-- Right Alignment -->
+ <value>right</value>
+ <!-- Center Alignment -->
+ <value>center</value>
+ <!-- Inside -->
+ <value>inside</value>
+ <!-- Outside -->
+ <value>outside</value>
+ </choice>
+ </define>
+ <define name="ST_RelFromH">
+ <choice>
+ <!-- Page Margin -->
+ <value>margin</value>
+ <!-- Page Edge -->
+ <value>page</value>
+ <!-- Column -->
+ <value>column</value>
+ <!-- Character -->
+ <value>character</value>
+ <!-- Left Margin -->
+ <value>leftMargin</value>
+ <!-- Right Margin -->
+ <value>rightMargin</value>
+ <!-- Inside Margin -->
+ <value>insideMargin</value>
+ <!-- Outside Margin -->
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="CT_PosH">
+ <choice>
+ <element name="align">
+ <ref name="ST_AlignH"/>
+ </element>
+ <element name="posOffset">
+ <ref name="ST_PositionOffset"/>
+ </element>
+ </choice>
+ <attribute name="relativeFrom">
+ <ref name="ST_RelFromH"/>
+ </attribute>
+ </define>
+ <define name="ST_AlignV">
+ <choice>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Bottom -->
+ <value>bottom</value>
+ <!-- Center Alignment -->
+ <value>center</value>
+ <!-- Inside -->
+ <value>inside</value>
+ <!-- Outside -->
+ <value>outside</value>
+ </choice>
+ </define>
+ <define name="ST_RelFromV">
+ <choice>
+ <!-- Page Margin -->
+ <value>margin</value>
+ <!-- Page Edge -->
+ <value>page</value>
+ <!-- Paragraph -->
+ <value>paragraph</value>
+ <!-- Line -->
+ <value>line</value>
+ <!-- Top Margin -->
+ <value>topMargin</value>
+ <!-- Bottom Margin -->
+ <value>bottomMargin</value>
+ <!-- Inside Margin -->
+ <value>insideMargin</value>
+ <!-- Outside Margin -->
+ <value>outsideMargin</value>
+ </choice>
+ </define>
+ <define name="CT_PosV">
+ <choice>
+ <element name="align">
+ <ref name="ST_AlignV"/>
+ </element>
+ <element name="posOffset">
+ <ref name="ST_PositionOffset"/>
+ </element>
+ </choice>
+ <attribute name="relativeFrom">
+ <ref name="ST_RelFromV"/>
+ </attribute>
+ </define>
+ <define name="CT_Anchor">
+ <element name="simplePos">
+ <ref name="CT_Point2D"/>
+ </element>
+ <element name="positionH">
+ <ref name="CT_PosH"/>
+ </element>
+ <element name="positionV">
+ <ref name="CT_PosV"/>
+ </element>
+ <element name="extent">
+ <ref name="CT_PositiveSize2D"/>
+ </element>
+ <element name="effectExtent">
+ <ref name="CT_EffectExtent"/>
+ </element>
+ <ref name="EG_WrapType"/>
+ <element name="docPr">
+ <ref name="CT_NonVisualDrawingProps"/>
+ </element>
+ <element name="cNvGraphicFramePr">
+ <ref name="CT_NonVisualGraphicFrameProperties"/>
+ </element>
+ <element name="a:graphic">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelH">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="wp14:sizeRelV">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <attribute name="distT">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distB">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distL">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="distR">
+ <ref name="ST_WrapDistance"/>
+ </attribute>
+ <attribute name="simplePos">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="relativeHeight">
+ <data type="unsignedInt"/>
+ </attribute>
+ <attribute name="behindDoc">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="locked">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="layoutInCell">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="hidden">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="allowOverlap">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="wp14:anchorId">
+ <ref name="ST_EditId"/>
+ </attribute>
+ </define>
+ <define name="inline">
+ <element name="inline">
+ <ref name="CT_Inline"/>
+ </element>
+ </define>
+ <define name="anchor">
+ <element name="anchor">
+ <ref name="CT_Anchor"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_Coordinate" resource="Integer"/>
+ <resource name="CT_EffectExtent" resource="Properties">
+ <attribute name="l" tokenid="ooxml:CT_EffectExtent_l"/>
+ <attribute name="t" tokenid="ooxml:CT_EffectExtent_t"/>
+ <attribute name="r" tokenid="ooxml:CT_EffectExtent_r"/>
+ <attribute name="b" tokenid="ooxml:CT_EffectExtent_b"/>
+ </resource>
+ <resource name="ST_WrapDistance" resource="Integer"/>
+ <resource name="CT_Inline" resource="Properties">
+ <element name="extent" tokenid="ooxml:CT_Inline_extent"/>
+ <element name="effectExtent" tokenid="ooxml:CT_Inline_effectExtent"/>
+ <element name="docPr" tokenid="ooxml:CT_Inline_docPr"/>
+ <element name="cNvGraphicFramePr" tokenid="ooxml:CT_Inline_cNvGraphicFramePr"/>
+ <element name="a:graphic" tokenid="ooxml:CT_Inline_a_graphic"/>
+ <element name="wp14:sizeRelH" tokenid="ooxml:CT_Inline_wp14_sizeRelH"/>
+ <element name="wp14:sizeRelV" tokenid="ooxml:CT_Inline_wp14_sizeRelV"/>
+ <attribute name="distT" tokenid="ooxml:CT_Inline_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_Inline_distB"/>
+ <attribute name="distL" tokenid="ooxml:CT_Inline_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_Inline_distR"/>
+ <attribute name="wp14:anchorId" tokenid="ooxml:CT_Inline_wp14_anchorId"/>
+ </resource>
+ <resource name="ST_WrapText" resource="List">
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_bothSides">bothSides</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_left">left</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_right">right</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_WrapText_largest">largest</value>
+ </resource>
+ <resource name="CT_WrapPath" resource="Properties">
+ <element name="start" tokenid="ooxml:CT_WrapPath_start"/>
+ <element name="lineTo" tokenid="ooxml:CT_WrapPath_lineTo"/>
+ <attribute name="edited" tokenid="ooxml:CT_WrapPath_edited"/>
+ </resource>
+ <resource name="CT_WrapNone" resource="Properties"/>
+ <resource name="CT_WrapSquare" resource="Properties">
+ <element name="effectExtent" tokenid="ooxml:CT_WrapSquare_effectExtent"/>
+ <attribute name="wrapText" tokenid="ooxml:CT_WrapSquare_wrapText"/>
+ <attribute name="distT" tokenid="ooxml:CT_WrapSquare_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_WrapSquare_distB"/>
+ <attribute name="distL" tokenid="ooxml:CT_WrapSquare_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_WrapSquare_distR"/>
+ </resource>
+ <resource name="CT_WrapTight" resource="Properties">
+ <element name="wrapPolygon" tokenid="ooxml:CT_WrapTight_wrapPolygon"/>
+ <attribute name="wrapText" tokenid="ooxml:CT_WrapTight_wrapText"/>
+ <attribute name="distL" tokenid="ooxml:CT_WrapTight_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_WrapTight_distR"/>
+ </resource>
+ <resource name="CT_WrapThrough" resource="Properties">
+ <element name="wrapPolygon" tokenid="ooxml:CT_WrapThrough_wrapPolygon"/>
+ <attribute name="wrapText" tokenid="ooxml:CT_WrapThrough_wrapText"/>
+ <attribute name="distL" tokenid="ooxml:CT_WrapThrough_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_WrapThrough_distR"/>
+ </resource>
+ <resource name="CT_WrapTopBottom" resource="Properties">
+ <element name="effectExtent" tokenid="ooxml:CT_WrapTopBottom_effectExtent"/>
+ <attribute name="distT" tokenid="ooxml:CT_WrapTopBottom_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_WrapTopBottom_distB"/>
+ </resource>
+ <resource name="EG_WrapType" resource="Properties">
+ <element name="wrapNone" tokenid="ooxml:EG_WrapType_wrapNone"/>
+ <element name="wrapSquare" tokenid="ooxml:EG_WrapType_wrapSquare"/>
+ <element name="wrapTight" tokenid="ooxml:EG_WrapType_wrapTight"/>
+ <element name="wrapThrough" tokenid="ooxml:EG_WrapType_wrapThrough"/>
+ <element name="wrapTopAndBottom" tokenid="ooxml:EG_WrapType_wrapTopAndBottom"/>
+ </resource>
+ <resource name="ST_PositionOffset" resource="Value">
+ <action name="characters" action="positionOffset"/>
+ </resource>
+ <resource name="ST_AlignH" resource="Value">
+ <action name="characters" action="alignH"/>
+ </resource>
+ <resource name="ST_RelFromH" resource="List">
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_margin">margin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_page">page</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_column">column</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_character">character</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_leftMargin">leftMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_rightMargin">rightMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromH_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="CT_PosH" resource="Properties">
+ <element name="align" tokenid="ooxml:CT_PosH_align"/>
+ <element name="posOffset" tokenid="ooxml:CT_PosH_posOffset"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_PosH_relativeFrom"/>
+ </resource>
+ <resource name="ST_AlignV" resource="Value">
+ <action name="characters" action="alignV"/>
+ </resource>
+ <resource name="ST_RelFromV" resource="List">
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_margin">margin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_page">page</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_paragraph">paragraph</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_line">line</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_topMargin">topMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_bottomMargin">bottomMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_insideMargin">insideMargin</value>
+ <value tokenid="ooxml:Value_wordprocessingDrawing_ST_RelFromV_outsideMargin">outsideMargin</value>
+ </resource>
+ <resource name="CT_PosV" resource="Properties">
+ <element name="align" tokenid="ooxml:CT_PosV_align"/>
+ <element name="posOffset" tokenid="ooxml:CT_PosV_posOffset"/>
+ <attribute name="relativeFrom" tokenid="ooxml:CT_PosV_relativeFrom"/>
+ </resource>
+ <resource name="ST_EditId" resource="Hex"/>
+ <resource name="CT_Anchor" resource="Properties">
+ <element name="simplePos" tokenid="ooxml:CT_Anchor_simplePos_elem"/>
+ <element name="positionH" tokenid="ooxml:CT_Anchor_positionH"/>
+ <element name="positionV" tokenid="ooxml:CT_Anchor_positionV"/>
+ <element name="extent" tokenid="ooxml:CT_Anchor_extent"/>
+ <element name="effectExtent" tokenid="ooxml:CT_Anchor_effectExtent"/>
+ <element name="docPr" tokenid="ooxml:CT_Anchor_docPr"/>
+ <element name="cNvGraphicFramePr" tokenid="ooxml:CT_Anchor_cNvGraphicFramePr"/>
+ <element name="a:graphic" tokenid="ooxml:CT_Anchor_a_graphic"/>
+ <element name="wp14:sizeRelV" tokenid="ooxml:CT_Anchor_wp14_sizeRelV"/>
+ <attribute name="distT" tokenid="ooxml:CT_Anchor_distT"/>
+ <attribute name="distB" tokenid="ooxml:CT_Anchor_distB"/>
+ <attribute name="distL" tokenid="ooxml:CT_Anchor_distL"/>
+ <attribute name="distR" tokenid="ooxml:CT_Anchor_distR"/>
+ <attribute name="simplePos" tokenid="ooxml:CT_Anchor_simplePos_attr"/>
+ <attribute name="relativeHeight" tokenid="ooxml:CT_Anchor_relativeHeight"/>
+ <attribute name="behindDoc" tokenid="ooxml:CT_Anchor_behindDoc"/>
+ <attribute name="locked" tokenid="ooxml:CT_Anchor_locked"/>
+ <attribute name="layoutInCell" tokenid="ooxml:CT_Anchor_layoutInCell"/>
+ <attribute name="hidden" tokenid="ooxml:CT_Anchor_hidden"/>
+ <attribute name="allowOverlap" tokenid="ooxml:CT_Anchor_allowOverlap"/>
+ <attribute name="wp14:anchorId" tokenid="ooxml:CT_Anchor_wp14_anchorId"/>
+ </resource>
+ <resource name="inline" resource="Properties">
+ <element name="inline" tokenid="ooxml:inline_inline"/>
+ </resource>
+ <resource name="anchor" resource="Properties">
+ <element name="anchor" tokenid="ooxml:anchor_anchor"/>
+ </resource>
+ </namespace>
+ <namespace name="sml-customXmlMappings">
+ <start name="schemaLibrary"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
+ <!-- ISO RELAX NG Schema -->
+ <!-- start = schemaLibrary -->
+ <define name="CT_Schema">
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="manifestLocation">
+ <data type="string"/>
+ </attribute>
+ <attribute name="schemaLocation">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SchemaLibrary">
+ <element name="schema">
+ <ref name="CT_Schema"/>
+ </element>
+ </define>
+ <define name="schemaLibrary">
+ <element name="schemaLibrary">
+ <ref name="CT_SchemaLibrary"/>
+ </element>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="shared-math">
+ <start name="oMathPara"/>
+ <start name="oMath"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/officeDocument/2006/math" attributeFormDefault="qualified">
+ <include href="wml"/>
+ <!-- start = mathPr | oMathPara | oMath -->
+ <define name="ST_Integer255">
+ <data type="integer"/>
+ </define>
+ <define name="CT_Integer255">
+ <attribute name="val">
+ <ref name="ST_Integer255"/>
+ </attribute>
+ </define>
+ <define name="ST_Integer2">
+ <data type="integer"/>
+ </define>
+ <define name="CT_Integer2">
+ <attribute name="val">
+ <ref name="ST_Integer2"/>
+ </attribute>
+ </define>
+ <define name="ST_SpacingRule">
+ <data type="integer"/>
+ </define>
+ <define name="CT_SpacingRule">
+ <attribute name="val">
+ <ref name="ST_SpacingRule"/>
+ </attribute>
+ </define>
+ <define name="ST_UnSignedInteger">
+ <data type="unsignedInt"/>
+ </define>
+ <define name="CT_UnSignedInteger">
+ <attribute name="val">
+ <ref name="ST_UnSignedInteger"/>
+ </attribute>
+ </define>
+ <define name="ST_Char">
+ <data type="string"/>
+ </define>
+ <define name="CT_Char">
+ <attribute name="val">
+ <ref name="ST_Char"/>
+ </attribute>
+ </define>
+ <define name="ST_OnOff">
+ <choice>
+ <!-- On -->
+ <value>on</value>
+ <!-- Off -->
+ <value>off</value>
+ </choice>
+ </define>
+ <define name="CT_OnOff">
+ <attribute name="val">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="ST_String">
+ <data type="string"/>
+ </define>
+ <define name="CT_String">
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="ST_XAlign">
+ <choice>
+ <!-- Left Justification -->
+ <value>left</value>
+ <!-- Center -->
+ <value>center</value>
+ <!-- Right -->
+ <value>right</value>
+ </choice>
+ </define>
+ <define name="CT_XAlign">
+ <attribute name="val">
+ <ref name="ST_XAlign"/>
+ </attribute>
+ </define>
+ <define name="ST_YAlign">
+ <choice>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Center (Function) -->
+ <value>center</value>
+ <!-- Bottom Alignment -->
+ <value>bot</value>
+ </choice>
+ </define>
+ <define name="CT_YAlign">
+ <attribute name="val">
+ <ref name="ST_YAlign"/>
+ </attribute>
+ </define>
+ <define name="ST_Shp">
+ <choice>
+ <!-- Centered (Delimiters) -->
+ <value>centered</value>
+ <!-- Match -->
+ <value>match</value>
+ </choice>
+ </define>
+ <define name="CT_Shp">
+ <attribute name="val">
+ <ref name="ST_Shp"/>
+ </attribute>
+ </define>
+ <define name="ST_FType">
+ <choice>
+ <!-- Bar Fraction -->
+ <value>bar</value>
+ <!-- Skewed -->
+ <value>skw</value>
+ <!-- Linear Fraction -->
+ <value>lin</value>
+ <!-- No-Bar Fraction (Stack) -->
+ <value>noBar</value>
+ </choice>
+ </define>
+ <define name="CT_FType">
+ <attribute name="val">
+ <ref name="ST_FType"/>
+ </attribute>
+ </define>
+ <define name="ST_LimLoc">
+ <choice>
+ <!-- Under-Over location -->
+ <value>undOvr</value>
+ <!-- Subscript-Superscript location -->
+ <value>subSup</value>
+ </choice>
+ </define>
+ <define name="CT_LimLoc">
+ <attribute name="val">
+ <ref name="ST_LimLoc"/>
+ </attribute>
+ </define>
+ <define name="ST_TopBot">
+ <choice>
+ <!-- Top -->
+ <value>top</value>
+ <!-- Bottom Alignment -->
+ <value>bot</value>
+ </choice>
+ </define>
+ <define name="CT_TopBot">
+ <attribute name="val">
+ <ref name="ST_TopBot"/>
+ </attribute>
+ </define>
+ <define name="ST_Script">
+ <choice>
+ <!-- Roman -->
+ <value>roman</value>
+ <!-- Script -->
+ <value>script</value>
+ <!-- Fraktur -->
+ <value>fraktur</value>
+ <!-- double-struck -->
+ <value>double-struck</value>
+ <!-- Sans-Serif -->
+ <value>sans-serif</value>
+ <!-- Monospace -->
+ <value>monospace</value>
+ </choice>
+ </define>
+ <define name="CT_Script">
+ <attribute name="val">
+ <ref name="ST_Script"/>
+ </attribute>
+ </define>
+ <define name="ST_Style">
+ <choice>
+ <!-- Plain -->
+ <value>p</value>
+ <!-- Bold -->
+ <value>b</value>
+ <!-- Italic -->
+ <value>i</value>
+ <!-- Bold-Italic -->
+ <value>bi</value>
+ </choice>
+ </define>
+ <define name="CT_Style">
+ <attribute name="val">
+ <ref name="ST_Style"/>
+ </attribute>
+ </define>
+ <define name="CT_ManualBreak">
+ <attribute name="alnAt">
+ <ref name="ST_Integer255"/>
+ </attribute>
+ </define>
+ <define name="EG_ScriptStyle">
+ <element name="scr">
+ <ref name="CT_Script"/>
+ </element>
+ <element name="sty">
+ <ref name="CT_Style"/>
+ </element>
+ </define>
+ <define name="CT_RPR">
+ <element name="lit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <choice>
+ <element name="nor">
+ <ref name="CT_OnOff"/>
+ </element>
+ <ref name="EG_ScriptStyle"/>
+ </choice>
+ <element name="brk">
+ <ref name="CT_ManualBreak"/>
+ </element>
+ <element name="aln">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_Text">
+ <ref name="ST_String"/>
+ <attribute name="xml:space">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_R">
+ <element name="rPr">
+ <ref name="CT_RPR"/>
+ </element>
+ <ref name="EG_RPr"/>
+ <choice>
+ <ref name="EG_RunInnerContent"/>
+ <element name="t">
+ <ref name="CT_Text"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_CtrlPr">
+ <ref name="EG_RPrMath"/>
+ </define>
+ <define name="CT_AccPr">
+ <element name="chr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Acc">
+ <element name="accPr">
+ <ref name="CT_AccPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_BarPr">
+ <element name="pos">
+ <ref name="CT_TopBot"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Bar">
+ <element name="barPr">
+ <ref name="CT_BarPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_BoxPr">
+ <element name="opEmu">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noBreak">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="diff">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="brk">
+ <ref name="CT_ManualBreak"/>
+ </element>
+ <element name="aln">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Box">
+ <element name="boxPr">
+ <ref name="CT_BoxPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_BorderBoxPr">
+ <element name="hideTop">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideBot">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideLeft">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideRight">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeH">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeV">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeBLTR">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strikeTLBR">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_BorderBox">
+ <element name="borderBoxPr">
+ <ref name="CT_BorderBoxPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_DPr">
+ <element name="begChr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="sepChr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="endChr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="grow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="shp">
+ <ref name="CT_Shp"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_D">
+ <element name="dPr">
+ <ref name="CT_DPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_EqArrPr">
+ <element name="baseJc">
+ <ref name="CT_YAlign"/>
+ </element>
+ <element name="maxDist">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="objDist">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rSpRule">
+ <ref name="CT_SpacingRule"/>
+ </element>
+ <element name="rSp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_EqArr">
+ <element name="eqArrPr">
+ <ref name="CT_EqArrPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_FPr">
+ <element name="type">
+ <ref name="CT_FType"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_F">
+ <element name="fPr">
+ <ref name="CT_FPr"/>
+ </element>
+ <element name="num">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="den">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_FuncPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Func">
+ <element name="funcPr">
+ <ref name="CT_FuncPr"/>
+ </element>
+ <element name="fName">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_GroupChrPr">
+ <element name="chr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="pos">
+ <ref name="CT_TopBot"/>
+ </element>
+ <element name="vertJc">
+ <ref name="CT_TopBot"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_GroupChr">
+ <element name="groupChrPr">
+ <ref name="CT_GroupChrPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_LimLowPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_LimLow">
+ <element name="limLowPr">
+ <ref name="CT_LimLowPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="lim">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_LimUppPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_LimUpp">
+ <element name="limUppPr">
+ <ref name="CT_LimUppPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="lim">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_MCPr">
+ <element name="count">
+ <ref name="CT_Integer255"/>
+ </element>
+ <element name="mcJc">
+ <ref name="CT_XAlign"/>
+ </element>
+ </define>
+ <define name="CT_MC">
+ <element name="mcPr">
+ <ref name="CT_MCPr"/>
+ </element>
+ </define>
+ <define name="CT_MCS">
+ <element name="mc">
+ <ref name="CT_MC"/>
+ </element>
+ </define>
+ <define name="CT_MPr">
+ <element name="baseJc">
+ <ref name="CT_YAlign"/>
+ </element>
+ <element name="plcHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rSpRule">
+ <ref name="CT_SpacingRule"/>
+ </element>
+ <element name="cGpRule">
+ <ref name="CT_SpacingRule"/>
+ </element>
+ <element name="rSp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="cSp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="cGp">
+ <ref name="CT_UnSignedInteger"/>
+ </element>
+ <element name="mcs">
+ <ref name="CT_MCS"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_MR">
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_M">
+ <element name="mPr">
+ <ref name="CT_MPr"/>
+ </element>
+ <element name="mr">
+ <ref name="CT_MR"/>
+ </element>
+ </define>
+ <define name="CT_NaryPr">
+ <element name="chr">
+ <ref name="CT_Char"/>
+ </element>
+ <element name="limLoc">
+ <ref name="CT_LimLoc"/>
+ </element>
+ <element name="grow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="subHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="supHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Nary">
+ <element name="naryPr">
+ <ref name="CT_NaryPr"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_PhantPr">
+ <element name="show">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="zeroWid">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="zeroAsc">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="zeroDesc">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="transp">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Phant">
+ <element name="phantPr">
+ <ref name="CT_PhantPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_RadPr">
+ <element name="degHide">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_Rad">
+ <element name="radPr">
+ <ref name="CT_RadPr"/>
+ </element>
+ <element name="deg">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SPrePr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SPre">
+ <element name="sPrePr">
+ <ref name="CT_SPrePr"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SSubPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SSub">
+ <element name="sSubPr">
+ <ref name="CT_SSubPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SSubSupPr">
+ <element name="alnScr">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SSubSup">
+ <element name="sSubSupPr">
+ <ref name="CT_SSubSupPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sub">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="CT_SSupPr">
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="CT_SSup">
+ <element name="sSupPr">
+ <ref name="CT_SSupPr"/>
+ </element>
+ <element name="e">
+ <ref name="CT_OMathArg"/>
+ </element>
+ <element name="sup">
+ <ref name="CT_OMathArg"/>
+ </element>
+ </define>
+ <define name="EG_OMathMathElements">
+ <choice>
+ <element name="acc">
+ <ref name="CT_Acc"/>
+ </element>
+ <element name="bar">
+ <ref name="CT_Bar"/>
+ </element>
+ <element name="box">
+ <ref name="CT_Box"/>
+ </element>
+ <element name="borderBox">
+ <ref name="CT_BorderBox"/>
+ </element>
+ <element name="d">
+ <ref name="CT_D"/>
+ </element>
+ <element name="eqArr">
+ <ref name="CT_EqArr"/>
+ </element>
+ <element name="f">
+ <ref name="CT_F"/>
+ </element>
+ <element name="func">
+ <ref name="CT_Func"/>
+ </element>
+ <element name="groupChr">
+ <ref name="CT_GroupChr"/>
+ </element>
+ <element name="limLow">
+ <ref name="CT_LimLow"/>
+ </element>
+ <element name="limUpp">
+ <ref name="CT_LimUpp"/>
+ </element>
+ <element name="m">
+ <ref name="CT_M"/>
+ </element>
+ <element name="nary">
+ <ref name="CT_Nary"/>
+ </element>
+ <element name="phant">
+ <ref name="CT_Phant"/>
+ </element>
+ <element name="rad">
+ <ref name="CT_Rad"/>
+ </element>
+ <element name="sPre">
+ <ref name="CT_SPre"/>
+ </element>
+ <element name="sSub">
+ <ref name="CT_SSub"/>
+ </element>
+ <element name="sSubSup">
+ <ref name="CT_SSubSup"/>
+ </element>
+ <element name="sSup">
+ <ref name="CT_SSup"/>
+ </element>
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_OMathElements">
+ <choice>
+ <ref name="EG_OMathMathElements"/>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_OMathArgPr">
+ <element name="argSz">
+ <ref name="CT_Integer2"/>
+ </element>
+ </define>
+ <define name="CT_OMathArg">
+ <element name="argPr">
+ <ref name="CT_OMathArgPr"/>
+ </element>
+ <ref name="EG_OMathElements"/>
+ <element name="ctrlPr">
+ <ref name="CT_CtrlPr"/>
+ </element>
+ </define>
+ <define name="ST_Jc">
+ <choice>
+ <!-- Align To Leading Edge -->
+ <value>start</value>
+ <!-- Align To Trailing Edge -->
+ <value>end</value>
+ <!-- Left Justification (ecma) -->
+ <value>left</value>
+ <!-- Right (ecma) -->
+ <value>right</value>
+ <!-- Center (Equation) -->
+ <value>center</value>
+ <!-- Centered as Group (Equations) -->
+ <value>centerGroup</value>
+ </choice>
+ </define>
+ <define name="CT_OMathJc">
+ <attribute name="val">
+ <ref name="ST_Jc"/>
+ </attribute>
+ </define>
+ <define name="CT_OMathParaPr">
+ <element name="jc">
+ <ref name="CT_OMathJc"/>
+ </element>
+ </define>
+ <define name="ST_TwipsMeasure">
+ <data type="unsignedInt"/>
+ </define>
+ <define name="CT_TwipsMeasure">
+ <attribute name="val">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="ST_BreakBin">
+ <choice>
+ <!-- Before -->
+ <value>before</value>
+ <!-- After -->
+ <value>after</value>
+ <!-- Repeat -->
+ <value>repeat</value>
+ </choice>
+ </define>
+ <define name="CT_BreakBin">
+ <attribute name="val">
+ <ref name="ST_BreakBin"/>
+ </attribute>
+ </define>
+ <define name="ST_BreakBinSub">
+ <choice>
+ <!-- Minus Minus -->
+ <value>--</value>
+ <!-- Minus Plus -->
+ <value>-+</value>
+ <!-- Plus Minus -->
+ <value>+-</value>
+ </choice>
+ </define>
+ <define name="CT_BreakBinSub">
+ <attribute name="val">
+ <ref name="ST_BreakBinSub"/>
+ </attribute>
+ </define>
+ <define name="CT_MathPr">
+ <element name="mathFont">
+ <ref name="CT_String"/>
+ </element>
+ <element name="brkBin">
+ <ref name="CT_BreakBin"/>
+ </element>
+ <element name="brkBinSub">
+ <ref name="CT_BreakBinSub"/>
+ </element>
+ <element name="smallFrac">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dispDef">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="lMargin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="rMargin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="defJc">
+ <ref name="CT_OMathJc"/>
+ </element>
+ <element name="preSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="postSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="interSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="intraSp">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <choice>
+ <element name="wrapIndent">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="wrapRight">
+ <ref name="CT_OnOff"/>
+ </element>
+ </choice>
+ <element name="intLim">
+ <ref name="CT_LimLoc"/>
+ </element>
+ <element name="naryLim">
+ <ref name="CT_LimLoc"/>
+ </element>
+ </define>
+ <define name="mathPr">
+ <element name="mathPr">
+ <ref name="CT_MathPr"/>
+ </element>
+ </define>
+ <define name="CT_OMathPara">
+ <element name="oMathParaPr">
+ <ref name="CT_OMathParaPr"/>
+ </element>
+ <element name="oMath">
+ <ref name="CT_OMath"/>
+ </element>
+ </define>
+ <define name="CT_OMath">
+ <ref name="EG_OMathElements"/>
+ </define>
+ <define name="oMathPara">
+ <element name="oMathPara">
+ <ref name="CT_OMathPara"/>
+ </element>
+ </define>
+ <define name="oMath">
+ <element name="oMath">
+ <ref name="CT_OMath"/>
+ </element>
+ </define>
+ <define name="oMathParaPr">
+ <element name="oMathParaPr">
+ <ref name="CT_OMathParaPr"/>
+ </element>
+ </define>
+ </grammar>
+ <resource name="ST_Integer255" resource="Integer"/>
+ <resource name="CT_Integer255" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Integer255_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_Integer2" resource="Integer"/>
+ <resource name="CT_Integer2" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Integer2_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_SpacingRule" resource="Integer"/>
+ <resource name="CT_SpacingRule" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SpacingRule_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_UnSignedInteger" resource="Integer"/>
+ <resource name="CT_UnSignedInteger" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_UnSignedInteger_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_Char" resource="String"/>
+ <resource name="CT_Char" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Char_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_OnOff" resource="List">
+ <value tokenid="ooxml:Value_math_ST_OnOff_on">on</value>
+ <value tokenid="ooxml:Value_math_ST_OnOff_off">off</value>
+ </resource>
+ <resource name="CT_OnOff" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OnOff_val" action="setValue"/>
+ <action name="start" action="setDefaultBooleanValue"/>
+ </resource>
+ <resource name="ST_String" resource="String"/>
+ <resource name="CT_String" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_String_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_XAlign" resource="List">
+ <value tokenid="ooxml:Value_math_ST_XAlign_left">left</value>
+ <value tokenid="ooxml:Value_math_ST_XAlign_center">center</value>
+ <value tokenid="ooxml:Value_math_ST_XAlign_right">right</value>
+ </resource>
+ <resource name="CT_XAlign" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_XAlign_val" action="setValue"/>
+ </resource>
+ <resource name="ST_YAlign" resource="List">
+ <value tokenid="ooxml:Value_math_ST_YAlign_top">top</value>
+ <value tokenid="ooxml:Value_math_ST_YAlign_center">center</value>
+ <value tokenid="ooxml:Value_math_ST_YAlign_bot">bot</value>
+ </resource>
+ <resource name="CT_YAlign" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_YAlign_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Shp" resource="List">
+ <value tokenid="ooxml:Value_math_ST_Shp_centered">centered</value>
+ <value tokenid="ooxml:Value_math_ST_Shp_match">match</value>
+ </resource>
+ <resource name="CT_Shp" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Shp_val" action="setValue"/>
+ </resource>
+ <resource name="ST_FType" resource="List">
+ <value tokenid="ooxml:Value_math_ST_FType_bar">bar</value>
+ <value tokenid="ooxml:Value_math_ST_FType_skw">skw</value>
+ <value tokenid="ooxml:Value_math_ST_FType_lin">lin</value>
+ <value tokenid="ooxml:Value_math_ST_FType_noBar">noBar</value>
+ </resource>
+ <resource name="CT_FType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FType_val" action="setValue"/>
+ </resource>
+ <resource name="ST_LimLoc" resource="List">
+ <value tokenid="ooxml:Value_math_ST_LimLoc_undOvr">undOvr</value>
+ <value tokenid="ooxml:Value_math_ST_LimLoc_subSup">subSup</value>
+ </resource>
+ <resource name="CT_LimLoc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_LimLoc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_TopBot" resource="List">
+ <value tokenid="ooxml:Value_math_ST_TopBot_top">top</value>
+ <value tokenid="ooxml:Value_math_ST_TopBot_bot">bot</value>
+ </resource>
+ <resource name="CT_TopBot" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TopBot_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Script" resource="List">
+ <value tokenid="ooxml:Value_math_ST_Script_roman">roman</value>
+ <value tokenid="ooxml:Value_math_ST_Script_script">script</value>
+ <value tokenid="ooxml:Value_math_ST_Script_fraktur">fraktur</value>
+ <value tokenid="ooxml:Value_math_ST_Script_doublemstruck">double-struck</value>
+ <value tokenid="ooxml:Value_math_ST_Script_sansmserif">sans-serif</value>
+ <value tokenid="ooxml:Value_math_ST_Script_monospace">monospace</value>
+ </resource>
+ <resource name="CT_Script" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Script_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Style" resource="List">
+ <value tokenid="ooxml:Value_ST_Style_b">b</value>
+ <value tokenid="ooxml:Value_ST_Style_bi">bi</value>
+ <value tokenid="ooxml:Value_ST_Style_i">i</value>
+ <value tokenid="ooxml:Value_ST_Style_p">p</value>
+ </resource>
+ <resource name="CT_Style" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Style_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Jc" resource="String">
+ <value tokenid="ooxml:Value_math_ST_Jc_start">left</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_end">right</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_left">left</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_right">right</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_center">center</value>
+ <value tokenid="ooxml:Value_math_ST_Jc_centerGroup">centerGroup</value>
+ </resource>
+ <resource name="CT_OMathJc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OMathJc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_TwipsMeasure" resource="TwipsMeasure_asSigned"/>
+ <resource name="CT_TwipsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TwipsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_BreakBin" resource="List">
+ <value tokenid="ooxml:Value_math_ST_BreakBin_before">before</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBin_after">after</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBin_repeat">repeat</value>
+ </resource>
+ <resource name="CT_BreakBin" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_BreakBin_val" action="setValue"/>
+ </resource>
+ <resource name="ST_BreakBinSub" resource="List">
+ <value tokenid="ooxml:Value_math_ST_BreakBinSub_mm">--</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBinSub_mp">-+</value>
+ <value tokenid="ooxml:Value_math_ST_BreakBinSub_pm">+-</value>
+ </resource>
+ <resource name="CT_BreakBinSub" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_BreakBinSub_val" action="setValue"/>
+ </resource>
+ </namespace>
+ <namespace name="shared-relationshipReference">
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
+ <!-- ISO RELAX NG Schema -->
+ <define name="id">
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="embed">
+ <attribute name="embed">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="link">
+ <attribute name="link"/>
+ </define>
+ <define name="dm">
+ <attribute name="dm"/>
+ </define>
+ <define name="lo">
+ <attribute name="lo"/>
+ </define>
+ <define name="qs">
+ <attribute name="qs"/>
+ </define>
+ <define name="cs">
+ <attribute name="cs"/>
+ </define>
+ <define name="blip">
+ <attribute name="blip"/>
+ </define>
+ <define name="pict">
+ <attribute name="pict"/>
+ </define>
+ <define name="href">
+ <attribute name="href">
+ <data type="string"/>
+ </attribute>
+ </define>
+ </grammar>
+ </namespace>
+ <namespace name="dml-chartDrawing">
+ <start name="pic"/>
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" ns="http://schemas.openxmlformats.org/drawingml/2006/picture">
+ <include href="dml-shapeProperties"/>
+ <include href="dml-documentProperties"/>
+ <!-- start = pic -->
+ <define name="CT_PictureNonVisual">
+ <element name="cNvPr">
+ <ref name="CT_NonVisualDrawingProps"/>
+ </element>
+ <element name="cNvPicPr">
+ <ref name="CT_NonVisualPictureProperties"/>
+ </element>
+ </define>
+ <define name="CT_Picture">
+ <element name="nvPicPr">
+ <ref name="CT_PictureNonVisual"/>
+ </element>
+ <element name="blipFill">
+ <ref name="CT_BlipFillProperties"/>
+ </element>
+ <element name="spPr">
+ <ref name="CT_ShapeProperties"/>
+ </element>
+ </define>
+ <define name="pic">
+ <element name="pic">
+ <ref name="CT_Picture"/>
+ </element>
+ </define>
+ <define name="CT_RelIds">
+ <attribute name="r:dm">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:lo">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:qs">
+ <data type="string"/>
+ </attribute>
+ <attribute name="r:cs">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="relIds">
+ <element name="dgm:relIds">
+ <ref name="CT_RelIds"/>
+ </element>
+ </define>
+ <define name="CT_GvmlGroupShape">
+ <element name="nvGrpSpPr">
+ <ref name="CT_NonVisualGroupDrawingShapeProps"/>
+ </element>
+ <element name="grpSpPr">
+ <ref name="CT_GroupShapeProperties"/>
+ </element>
+ </define>
+ <define name="lockedCanvas">
+ <element name="lc:lockedCanvas">
+ <ref name="CT_GvmlGroupShape"/>
+ </element>
+ </define>
+ <define name="CT_Chart">
+ <attribute name="r:id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="chart">
+ <element name="c:chart">
+ <ref name="CT_Chart"/>
+ </element>
+ </define>
+ <define name="CT_WordprocessingShape">
+ <element name="cNvSpPr">
+ <ref name="CT_NonVisualDrawingShapeProps"/>
+ </element>
+ <element name="spPr">
+ <ref name="CT_ShapeProperties"/>
+ </element>
+ </define>
+ <define name="wsp">
+ <element name="wps:wsp">
+ <ref name="CT_WordprocessingShape"/>
+ </element>
+ </define>
+ <define name="CT_WordprocessingGroup">
+ <element name="cNvGrpSpPr">
+ <ref name="CT_NonVisualGroupDrawingShapeProps"/>
+ </element>
+ <element name="grpSpPr">
+ <ref name="CT_WordprocessingGroup"/>
+ </element>
+ </define>
+ <define name="wgp">
+ <element name="wpg:wgp">
+ <ref name="CT_WordprocessingGroup"/>
+ </element>
+ </define>
+ <define name="CT_BackgroundFormatting">
+ <ref name="EG_FillProperties"/>
+ <ref name="EG_EffectProperties"/>
+ </define>
+ <define name="CT_WholeE2oFormatting">
+ <element name="ln">
+ <ref name="CT_LineProperties"/>
+ </element>
+ <ref name="EG_EffectProperties"/>
+ </define>
+ <define name="CT_WordprocessingCanvas">
+ <element name="wpc:bg">
+ <ref name="CT_BackgroundFormatting"/>
+ </element>
+ <element name="wpc:whole">
+ <ref name="CT_WholeE2oFormatting"/>
+ </element>
+ <choice>
+ <ref name="wsp"/>
+ <ref name="pic"/>
+ <!-- ToDo w14:contentPart missing -->
+ <ref name="wgp"/>
+ <!-- ToDo graphicFrame missing -->
+ </choice>
+ <!-- ToDo extLst missing -->
+ </define>
+ <define name="wpc">
+ <element name="wpc:wpc">
+ <ref name="CT_WordprocessingCanvas"/>
+ </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>
+ <resource name="CT_WholeE2oFormatting" resource="Properties">
+ <element name="a:ln" tokenid="ooxml:CT_WholeE2oFormatting_ln"/>
+ </resource>
+ <resource name="CT_WordprocessingCanvas" resource="Shape">
+ <element name="wpc:bg" tokenid="ooxml:CT_WordprocessingCanvas_bg"/>
+ <element name="wpc:whole" tokenid="ooxml:CT_WordprocessingCanvas_whole"/>
+ <element name="wps:wsp" tokenid="ooxml:CT_WordprocessingCanvas_wsp"/>
+ <element name="pic" tokenid="ooxml:CT_WordprocessingCanvas_pic"/>
+ <element name="wpg:wgp" tokenid="ooxml:CT_WordprocessingCanvas_wgp"/>
+ </resource>
+ <resource name="wpc" resource="Shape">
+ <element name="wpc:wpc" tokenid="ooxml:wpc_wpc"/>
+ </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">
+ <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_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">
+ <ref name="ST_ThemeColor"/>
+ </attribute>
+ <attribute name="themeTint">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="themeShade">
+ <ref name="ST_UcharHexNumber"/>
+ </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_instrText">
+ <ref name="ST_String"/>
+ <attribute name="xml:space">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_delText">
+ <ref name="ST_String"/>
+ <attribute name="xml:space">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_delInstrText">
+ <ref name="ST_String"/>
+ <attribute name="xml:space">
+ <data type="string"/>
+ </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_delText"/>
+ </element>
+ <element name="instrText">
+ <ref name="CT_instrText"/>
+ </element>
+ <element name="delInstrText">
+ <ref name="CT_delInstrText"/>
+ </element>
+ <element name="noBreakHyphen">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="softHyphen">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="dayShort">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="monthShort">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="yearShort">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="dayLong">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="monthLong">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="yearLong">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="annotationRef">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="footnoteRef">
+ <ref name="CT_FtnEdnRefChar"/>
+ </element>
+ <element name="endnoteRef">
+ <ref name="CT_FtnEdnRefChar"/>
+ </element>
+ <element name="separator">
+ <ref name="CT_FtnEdnSep"/>
+ </element>
+ <element name="continuationSeparator">
+ <ref name="CT_FtnEdnCont"/>
+ </element>
+ <element name="sym">
+ <ref name="CT_Sym"/>
+ </element>
+ <element name="pgNum">
+ <ref name="CT_PgNum"/>
+ </element>
+ <element name="cr">
+ <ref name="CT_Cr"/>
+ </element>
+ <element name="tab">
+ <ref name="CT_Tab"/>
+ </element>
+ <element name="object">
+ <ref name="CT_Object"/>
+ </element>
+ <element name="pict">
+ <ref name="CT_Picture"/>
+ </element>
+ <element name="fldChar">
+ <ref name="CT_FldChar"/>
+ </element>
+ <element name="ruby">
+ <ref name="CT_Ruby"/>
+ </element>
+ <element name="footnoteReference">
+ <ref name="CT_FtnEdnRef"/>
+ </element>
+ <element name="endnoteReference">
+ <ref name="CT_FtnEdnRef"/>
+ </element>
+ <element name="commentReference">
+ <ref name="CT_CommentRef"/>
+ </element>
+ <element name="drawing">
+ <ref name="CT_Drawing"/>
+ </element>
+ <element name="ptab">
+ <ref name="CT_PTab"/>
+ </element>
+ <element name="lastRenderedPageBreak">
+ <ref name="CT_Empty"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_R">
+ <ref name="EG_RPr"/>
+ <ref name="EG_RunInnerContent"/>
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_Hint">
+ <choice>
+ <!-- High ANSI Font -->
+ <value>default</value>
+ <!-- East Asian Font -->
+ <value>eastAsia</value>
+ <!-- Complex Script Font -->
+ <value>cs</value>
+ </choice>
+ </define>
+ <define name="ST_Theme">
+ <choice>
+ <!-- Major East Asian Theme Font -->
+ <value>majorEastAsia</value>
+ <!-- Major Complex Script Theme Font -->
+ <value>majorBidi</value>
+ <!-- Major ASCII Theme Font -->
+ <value>majorAscii</value>
+ <!-- Major High ANSI Theme Font -->
+ <value>majorHAnsi</value>
+ <!-- Minor East Asian Theme Font -->
+ <value>minorEastAsia</value>
+ <!-- Minor Complex Script Theme Font -->
+ <value>minorBidi</value>
+ <!-- Minor ASCII Theme Font -->
+ <value>minorAscii</value>
+ <!-- Minor High ANSI Theme Font -->
+ <value>minorHAnsi</value>
+ </choice>
+ </define>
+ <define name="CT_Fonts">
+ <attribute name="hint">
+ <ref name="ST_Hint"/>
+ </attribute>
+ <attribute name="ascii">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="hAnsi">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="eastAsia">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="cs">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="asciiTheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ <attribute name="hAnsiTheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ <attribute name="eastAsiaTheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ <attribute name="cstheme">
+ <ref name="ST_Theme"/>
+ </attribute>
+ </define>
+ <define name="EG_RPrBase">
+ <element name="rStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="rFonts">
+ <ref name="CT_Fonts"/>
+ </element>
+ <element name="b">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bCs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="i">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="iCs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="caps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="smallCaps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strike">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dstrike">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="outline">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="shadow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="emboss">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="imprint">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noProof">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="snapToGrid">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="vanish">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="webHidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="color">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="spacing">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="w">
+ <ref name="CT_TextScale"/>
+ </element>
+ <element name="kern">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="position">
+ <ref name="CT_SignedHpsMeasure"/>
+ </element>
+ <element name="sz">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="szCs">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="highlight">
+ <ref name="CT_Highlight"/>
+ </element>
+ <element name="u">
+ <ref name="CT_Underline"/>
+ </element>
+ <element name="effect">
+ <ref name="CT_TextEffect"/>
+ </element>
+ <element name="bdr">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="fitText">
+ <ref name="CT_FitText"/>
+ </element>
+ <element name="vertAlign">
+ <ref name="CT_VerticalAlignRun"/>
+ </element>
+ <element name="rtl">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="cs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="em">
+ <ref name="CT_Em"/>
+ </element>
+ <element name="lang">
+ <ref name="CT_Language"/>
+ </element>
+ <element name="eastAsianLayout">
+ <ref name="CT_EastAsianLayout"/>
+ </element>
+ <element name="specVanish">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="oMath">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="w14:glow">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:shadow">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:reflection">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:textOutline">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:textFill">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:scene3d">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:props3d">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:ligatures">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:numForm">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:numSpacing">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:stylisticSets">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <element name="w14:cntxtAlts">
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </define>
+ <define name="EG_RPrContent">
+ <ref name="EG_RPrBase"/>
+ <element name="rPrChange">
+ <ref name="CT_RPrChange"/>
+ </element>
+ </define>
+ <define name="CT_RPr">
+ <ref name="EG_RPrContent"/>
+ </define>
+ <define name="EG_RPr">
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ </define>
+ <define name="EG_RPrMath">
+ <choice>
+ <ref name="EG_RPr"/>
+ <element name="ins">
+ <ref name="CT_RPrChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_RPrChange"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_RPrOriginal">
+ <ref name="EG_RPrBase"/>
+ </define>
+ <define name="CT_ParaRPrOriginal">
+ <ref name="EG_ParaRPrTrackChanges"/>
+ <ref name="EG_RPrBase"/>
+ </define>
+ <define name="CT_ParaRPr">
+ <ref name="EG_ParaRPrTrackChanges"/>
+ <ref name="EG_RPrBase"/>
+ <element name="rPrChange">
+ <ref name="CT_ParaRPrChange"/>
+ </element>
+ </define>
+ <define name="CT_ParaTrackChange">
+ <ref name="CT_TrackChange"/>
+ </define>
+ <define name="EG_ParaRPrTrackChanges">
+ <element name="ins">
+ <ref name="CT_ParaTrackChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_ParaTrackChange"/>
+ </element>
+ <element name="moveFrom">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="moveTo">
+ <ref name="CT_TrackChange"/>
+ </element>
+ </define>
+ <define name="CT_AltChunk">
+ <element name="altChunkPr">
+ <ref name="CT_AltChunkPr"/>
+ </element>
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_AltChunkPr">
+ <element name="matchSrc">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="ST_RubyAlign">
+ <choice>
+ <value>center</value>
+ <value>distributeLetter</value>
+ <value>distributeSpace</value>
+ <value>left</value>
+ <value>right</value>
+ <value>rightVertical</value>
+ </choice>
+ </define>
+ <define name="CT_RubyAlign">
+ <attribute name="val">
+ <ref name="ST_RubyAlign"/>
+ </attribute>
+ </define>
+ <define name="CT_RubyPr">
+ <element name="rubyAlign">
+ <ref name="CT_RubyAlign"/>
+ </element>
+ <element name="hps">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="hpsRaise">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="hpsBaseText">
+ <ref name="CT_HpsMeasure"/>
+ </element>
+ <element name="lid">
+ <ref name="CT_Lang"/>
+ </element>
+ <element name="dirty">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="EG_RubyContent">
+ <choice>
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_RubyContent">
+ <ref name="EG_RubyContent"/>
+ </define>
+ <define name="CT_Ruby">
+ <element name="rubyPr">
+ <ref name="CT_RubyPr"/>
+ </element>
+ <element name="rt">
+ <ref name="CT_RubyContent"/>
+ </element>
+ <element name="rubyBase">
+ <ref name="CT_RubyContent"/>
+ </element>
+ </define>
+ <define name="CT_Lock">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtListItem">
+ <attribute name="displayText">
+ <data type="string"/>
+ </attribute>
+ <attribute name="value">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtDateMappingType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CalendarType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtDate">
+ <element name="dateFormat">
+ <ref name="CT_String"/>
+ </element>
+ <element name="lid">
+ <ref name="CT_Lang"/>
+ </element>
+ <element name="storeMappedDataAs">
+ <ref name="CT_SdtDateMappingType"/>
+ </element>
+ <element name="calendar">
+ <ref name="CT_CalendarType"/>
+ </element>
+ <attribute name="fullDate">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtDocPart">
+ <element name="docPartGallery">
+ <ref name="CT_String"/>
+ </element>
+ <element name="docPartCategory">
+ <ref name="CT_String"/>
+ </element>
+ <element name="docPartUnique">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_SdtDropDownList">
+ <element name="listItem">
+ <ref name="CT_SdtListItem"/>
+ </element>
+ <attribute name="lastValue">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPlaceholderDocPart">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPlaceholder">
+ <element name="docPart">
+ <ref name="CT_SdtPlaceholderDocPart"/>
+ </element>
+ </define>
+ <define name="CT_SdtText">
+ <attribute name="multiLine">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DataBinding">
+ <attribute name="prefixMappings">
+ <data type="string"/>
+ </attribute>
+ <attribute name="xpath">
+ <data type="string"/>
+ </attribute>
+ <attribute name="storeItemID">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtColor">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtAppearance">
+ <attribute name="w15:val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SdtPr">
+ <choice>
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ <element name="alias">
+ <ref name="CT_String"/>
+ </element>
+ <element name="lock">
+ <ref name="CT_Lock"/>
+ </element>
+ <element name="placeholder">
+ <ref name="CT_SdtPlaceholder"/>
+ </element>
+ <element name="showingPlcHdr">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dataBinding">
+ <ref name="CT_DataBinding"/>
+ </element>
+ <element name="temporary">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="id">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tabIndex">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tag">
+ <ref name="CT_String"/>
+ </element>
+ <element name="equation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="comboBox">
+ <ref name="CT_SdtDropDownList"/>
+ </element>
+ <element name="w14:checkbox">
+ <ref name="CT_SdtCheckbox"/>
+ </element>
+ <element name="date">
+ <ref name="CT_SdtDate"/>
+ </element>
+ <element name="docPartObj">
+ <ref name="CT_SdtDocPart"/>
+ </element>
+ <element name="docPartList">
+ <ref name="CT_SdtDocPart"/>
+ </element>
+ <element name="dropDownList">
+ <ref name="CT_SdtDropDownList"/>
+ </element>
+ <element name="picture">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="richText">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="text">
+ <ref name="CT_SdtText"/>
+ </element>
+ <element name="citation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="group">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bibliography">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="w15:color">
+ <ref name="CT_SdtColor"/>
+ </element>
+ <element name="w15:appearance">
+ <ref name="CT_SdtAppearance"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_SdtEndPr">
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ </define>
+ <define name="EG_ContentRunContent">
+ <choice>
+ <element name="customXml">
+ <ref name="CT_CustomXmlRun"/>
+ </element>
+ <element name="smartTag">
+ <ref name="CT_SmartTagRun"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtRun"/>
+ </element>
+ <element name="dir">
+ <ref name="CT_DirContentRun"/>
+ </element>
+ <element name="r">
+ <ref name="CT_R"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_DirContentRun">
+ <ref name="EG_PContent"/>
+ <attribute name="val">
+ <ref name="ST_Direction"/>
+ </attribute>
+ </define>
+ <define name="ST_Direction">
+ <choice>
+ <value>ltr</value>
+ <value>rtl</value>
+ </choice>
+ </define>
+ <define name="CT_SdtContentRun">
+ <ref name="EG_PContent"/>
+ </define>
+ <define name="EG_ContentBlockContent">
+ <choice>
+ <element name="customXml">
+ <ref name="CT_CustomXmlBlock"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtBlock"/>
+ </element>
+ <element name="p">
+ <ref name="CT_P"/>
+ </element>
+ <element name="tbl">
+ <ref name="CT_Tbl"/>
+ </element>
+ <!-- tdf#108714 : allow <w:br> at block level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <element name="br">
+ <ref name="CT_Br_OutOfOrder"/>
+ </element>
+ <!-- end tdf#108714 -->
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_SdtContentBlock">
+ <ref name="EG_ContentBlockContent"/>
+ </define>
+ <define name="EG_ContentRowContent">
+ <choice>
+ <element name="tr">
+ <ref name="CT_Row"/>
+ </element>
+ <element name="customXml">
+ <ref name="CT_CustomXmlRow"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtRow"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_SdtContentRow">
+ <ref name="EG_ContentRowContent"/>
+ </define>
+ <define name="EG_ContentCellContent">
+ <choice>
+ <element name="tc">
+ <ref name="CT_Tc"/>
+ </element>
+ <element name="customXml">
+ <ref name="CT_CustomXmlCell"/>
+ </element>
+ <element name="sdt">
+ <ref name="CT_SdtCell"/>
+ </element>
+ <ref name="EG_RunLevelElts"/>
+ </choice>
+ </define>
+ <define name="CT_SdtContentCell">
+ <ref name="EG_ContentCellContent"/>
+ </define>
+ <define name="CT_SdtBlock">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentBlock"/>
+ </element>
+ </define>
+ <define name="CT_SdtRun">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentRun"/>
+ </element>
+ </define>
+ <define name="CT_SdtCell">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentCell"/>
+ </element>
+ </define>
+ <define name="CT_SdtRow">
+ <element name="sdtPr">
+ <ref name="CT_SdtPr"/>
+ </element>
+ <element name="sdtEndPr">
+ <ref name="CT_SdtEndPr"/>
+ </element>
+ <element name="sdtContent">
+ <ref name="CT_SdtContentRow"/>
+ </element>
+ </define>
+ <define name="CT_Attr">
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlRun">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SmartTagRun">
+ <element name="smartTagPr">
+ <ref name="CT_SmartTagPr"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlBlock">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_ContentBlockContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlPr">
+ <element name="placeholder">
+ <ref name="CT_String"/>
+ </element>
+ <element name="attr">
+ <ref name="CT_Attr"/>
+ </element>
+ </define>
+ <define name="CT_CustomXmlRow">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_ContentRowContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_CustomXmlCell">
+ <element name="customXmlPr">
+ <ref name="CT_CustomXmlPr"/>
+ </element>
+ <ref name="EG_ContentCellContent"/>
+ <attribute name="uri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="element">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SmartTagPr">
+ <element name="attr">
+ <ref name="CT_Attr"/>
+ </element>
+ </define>
+ <define name="EG_PContent">
+ <choice>
+ <ref name="EG_ContentRunContent"/>
+ <element name="fldSimple">
+ <ref name="CT_SimpleField"/>
+ </element>
+ <element name="hyperlink">
+ <ref name="CT_Hyperlink"/>
+ </element>
+ <element name="subDoc">
+ <ref name="CT_Rel"/>
+ </element>
+ </choice>
+ </define>
+ <!-- [MS-DOCX] sect. 2.2.4 "p and tr Extensions" -->
+ <!-- Should rather be in w14 namespace, but I don't see how to reference things from there -->
+ <define name="AG_Parids">
+ <attribute name="w14:paraId">
+ <data type="string"/>
+ </attribute>
+ <!-- Not yet used
+ <attribute name="textId">
+ <ref name="ST_LongHexNumber"/>
+ </attribute>
+ -->
+ </define>
+ <define name="CT_P">
+ <element name="pPr">
+ <ref name="CT_PPr"/>
+ </element>
+ <ref name="EG_PContent"/>
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidP">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidRDefault">
+ <data type="string"/>
+ </attribute>
+ <ref name="AG_Parids"/>
+ <!-- tdf#108714 : allow <w:br> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <element name="br">
+ <ref name="CT_Br_OutOfOrder"/>
+ </element>
+ <!-- end tdf#108714 -->
+ <!-- tdf#111550 : allow <w:tbl> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <element name="tbl">
+ <ref name="CT_P_Tbl"/>
+ </element>
+ </define>
+ <define name="ST_TblWidth">
+ <choice>
+ <!-- No Width -->
+ <value>nil</value>
+ <!-- Width in Fiftieths of a Percent -->
+ <value>pct</value>
+ <!-- Width in Twentieths of a Point -->
+ <value>dxa</value>
+ <!-- Automatically Determined Width -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="ST_MeasurementOrPercent">
+ <data type="string"/>
+ </define>
+ <define name="CT_Height">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hRule">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_TblWidth">
+ <attribute name="w">
+ <ref name="ST_MeasurementOrPercent"/>
+ </attribute>
+ <attribute name="type">
+ <ref name="ST_TblWidth"/>
+ </attribute>
+ </define>
+ <define name="CT_TblGridCol">
+ <attribute name="w">
+ <ref name="ST_TwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="CT_TblGridBase">
+ <element name="gridCol">
+ <ref name="CT_TblGridCol"/>
+ </element>
+ </define>
+ <define name="CT_TblGrid">
+ <ref name="CT_TblGridBase"/>
+ <element name="tblGridChange">
+ <ref name="CT_TblGridChange"/>
+ </element>
+ </define>
+ <define name="CT_TcBorders">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="start">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="end">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideH">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideV">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="tl2br">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="tr2bl">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_TcMar">
+ <element name="top">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="start">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="left">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="right">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="end">
+ <ref name="CT_TblWidth"/>
+ </element>
+ </define>
+ <define name="ST_Merge">
+ <choice>
+ <!-- Continue Merged Region -->
+ <value>continue</value>
+ <!-- Start/Restart Merged Region -->
+ <value>restart</value>
+ </choice>
+ </define>
+ <define name="CT_VMerge">
+ <attribute name="val">
+ <ref name="ST_Merge"/>
+ </attribute>
+ </define>
+ <define name="CT_HMerge">
+ <attribute name="val">
+ <ref name="ST_Merge"/>
+ </attribute>
+ </define>
+ <define name="CT_TcPrBase">
+ <element name="cnfStyle">
+ <ref name="CT_Cnf"/>
+ </element>
+ <element name="tcW">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="gridSpan">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="hMerge">
+ <ref name="CT_HMerge"/>
+ </element>
+ <element name="vMerge">
+ <ref name="CT_VMerge"/>
+ </element>
+ <element name="tcBorders">
+ <ref name="CT_TcBorders"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="noWrap">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="tcMar">
+ <ref name="CT_TcMar"/>
+ </element>
+ <element name="textDirection">
+ <ref name="CT_TextDirection"/>
+ </element>
+ <element name="tcFitText">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="vAlign">
+ <ref name="CT_VerticalJc"/>
+ </element>
+ <element name="hideMark">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_TcPr">
+ <ref name="CT_TcPrInner"/>
+ <element name="tcPrChange">
+ <ref name="CT_TcPrChange"/>
+ </element>
+ </define>
+ <define name="CT_TcPrInner">
+ <ref name="CT_TcPrBase"/>
+ <ref name="EG_CellMarkupElements"/>
+ </define>
+ <define name="CT_Tc">
+ <element name="tcPr">
+ <ref name="CT_TcPr"/>
+ </element>
+ <ref name="EG_BlockLevelElts"/>
+ </define>
+ <define name="ST_Cnf">
+ <data type="string"/>
+ </define>
+ <define name="CT_Cnf">
+ <attribute name="val">
+ <ref name="ST_Cnf"/>
+ </attribute>
+ <attribute name="firstRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="oddVBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="evenVBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="oddHBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="evenHBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstRowFirstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstRowLastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRowFirstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRowLastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_TrPrBase">
+ <choice>
+ <element name="cnfStyle">
+ <ref name="CT_Cnf"/>
+ </element>
+ <element name="divId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="gridBefore">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="gridAfter">
+ <ref name="CT_TrPrBaseGridAfter"/>
+ </element>
+ <element name="wBefore">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="wAfter">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="cantSplit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="trHeight">
+ <ref name="CT_Height"/>
+ </element>
+ <element name="tblHeader">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="tblCellSpacing">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="hidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_TrPrBaseGridAfter">
+ <attribute name="val">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_TrPr">
+ <ref name="CT_TrPrBase"/>
+ <element name="ins">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_TrackChange"/>
+ </element>
+ <element name="trPrChange">
+ <ref name="CT_TrPrChange"/>
+ </element>
+ </define>
+ <define name="CT_Row">
+ <element name="tblPrEx">
+ <ref name="CT_TblPrEx"/>
+ </element>
+ <element name="trPr">
+ <ref name="CT_TrPr"/>
+ </element>
+ <ref name="EG_ContentCellContent"/>
+ <attribute name="rsidRPr">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidR">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidDel">
+ <data type="string"/>
+ </attribute>
+ <attribute name="rsidTr">
+ <data type="string"/>
+ </attribute>
+ <ref name="AG_Parids"/>
+ </define>
+ <define name="ST_TblLayout">
+ <choice>
+ <!-- Fixed Width Table Layout -->
+ <value>fixed</value>
+ <!-- AutoFit Table Layout -->
+ <value>autofit</value>
+ </choice>
+ </define>
+ <define name="CT_TblLayoutType">
+ <attribute name="type">
+ <ref name="ST_TblLayout"/>
+ </attribute>
+ </define>
+ <define name="ST_TblOverlap">
+ <choice>
+ <!-- Floating Table Cannot Overlap -->
+ <value>never</value>
+ <!-- Floating Table Can Overlap -->
+ <value>overlap</value>
+ </choice>
+ </define>
+ <define name="CT_TblOverlap">
+ <attribute name="val">
+ <ref name="ST_TblOverlap"/>
+ </attribute>
+ </define>
+ <define name="CT_TblPPr">
+ <attribute name="leftFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="rightFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="topFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="bottomFromText">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="vertAnchor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="horzAnchor">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tblpXSpec">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tblpX">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ <attribute name="tblpYSpec">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tblpY">
+ <ref name="ST_SignedTwipsMeasure"/>
+ </attribute>
+ </define>
+ <define name="CT_TblCellMar">
+ <element name="top">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="start">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="left">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="right">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="end">
+ <ref name="CT_TblWidth"/>
+ </element>
+ </define>
+ <define name="CT_TblBorders">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="start">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="end">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideH">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="insideV">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_TblPrBase">
+ <element name="tblStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="tblpPr">
+ <ref name="CT_TblPPr"/>
+ </element>
+ <element name="tblOverlap">
+ <ref name="CT_TblOverlap"/>
+ </element>
+ <element name="bidiVisual">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="tblStyleRowBandSize">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tblStyleColBandSize">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="tblW">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="tblCellSpacing">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblInd">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblBorders">
+ <ref name="CT_TblBorders"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="tblLayout">
+ <ref name="CT_TblLayoutType"/>
+ </element>
+ <element name="tblCellMar">
+ <ref name="CT_TblCellMar"/>
+ </element>
+ <element name="tblLook">
+ <ref name="CT_TblLook"/>
+ </element>
+ <element name="tblCaption">
+ <ref name="CT_String"/>
+ </element>
+ <element name="tblDescription">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_TblPr">
+ <ref name="CT_TblPrBase"/>
+ <element name="tblPrChange">
+ <ref name="CT_TblPrChange"/>
+ </element>
+ </define>
+ <define name="CT_TblPrExBase">
+ <element name="tblW">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="jc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="tblCellSpacing">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblInd">
+ <ref name="CT_TblWidth"/>
+ </element>
+ <element name="tblBorders">
+ <ref name="CT_TblBorders"/>
+ </element>
+ <element name="shd">
+ <ref name="CT_Shd"/>
+ </element>
+ <element name="tblLayout">
+ <ref name="CT_TblLayoutType"/>
+ </element>
+ <element name="tblCellMar">
+ <ref name="CT_TblCellMar"/>
+ </element>
+ <element name="tblLook">
+ <ref name="CT_TblLook"/>
+ </element>
+ <element name="tblCaption">
+ <ref name="CT_String"/>
+ </element>
+ <element name="tblDescription">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_TblPrEx">
+ <ref name="CT_TblPrExBase"/>
+ <element name="tblPrExChange">
+ <ref name="CT_TblPrExChange"/>
+ </element>
+ </define>
+ <define name="CT_Tbl">
+ <ref name="EG_RangeMarkupElements"/>
+ <element name="tblPr">
+ <ref name="CT_TblPr"/>
+ </element>
+ <element name="tblGrid">
+ <ref name="CT_TblGrid"/>
+ </element>
+ <ref name="EG_ContentRowContent"/>
+ </define>
+ <!-- tdf#111550 : Special element - copy of usual CT_Tbl, but only used as direct child of CT_P -->
+ <define name="CT_P_Tbl">
+ <ref name="EG_RangeMarkupElements"/>
+ <element name="tblPr">
+ <ref name="CT_TblPr"/>
+ </element>
+ <element name="tblGrid">
+ <ref name="CT_TblGrid"/>
+ </element>
+ <ref name="EG_ContentRowContent"/>
+ </define>
+ <define name="CT_TblLook">
+ <attribute name="firstRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastRow">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="firstColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="lastColumn">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="noHBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="noVBand">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_ShortHexNumber"/>
+ </attribute>
+ </define>
+ <define name="ST_FtnPos">
+ <choice>
+ <!-- Footnotes Positioned at Page Bottom -->
+ <value>pageBottom</value>
+ <!-- Footnotes Positioned Beneath Text -->
+ <value>beneathText</value>
+ <!-- Footnotes Positioned At End of Section -->
+ <value>sectEnd</value>
+ <!-- Footnotes Positioned At End of Document -->
+ <value>docEnd</value>
+ </choice>
+ </define>
+ <define name="CT_FtnPos">
+ <attribute name="val">
+ <ref name="ST_FtnPos"/>
+ </attribute>
+ </define>
+ <define name="ST_EdnPos">
+ <choice>
+ <!-- Endnotes Positioned at End of Section -->
+ <value>sectEnd</value>
+ <!-- Endnotes Positioned at End of Document -->
+ <value>docEnd</value>
+ </choice>
+ </define>
+ <define name="CT_EdnPos">
+ <attribute name="val">
+ <ref name="ST_EdnPos"/>
+ </attribute>
+ </define>
+ <define name="CT_NumFmt">
+ <attribute name="format">
+ <data type="string"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_NumberFormat"/>
+ </attribute>
+ </define>
+ <define name="ST_RestartNumber">
+ <choice>
+ <!-- Continue Numbering From Previous Section -->
+ <value>continuous</value>
+ <!-- Restart Numbering For Each Section -->
+ <value>eachSect</value>
+ <!-- Restart Numbering On Each Page -->
+ <value>eachPage</value>
+ </choice>
+ </define>
+ <define name="CT_NumRestart">
+ <attribute name="val">
+ <ref name="ST_RestartNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdnRef">
+ <attribute name="customMarkFollows">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdnSepRef">
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FtnEdn">
+ <ref name="EG_BlockLevelElts"/>
+ <attribute name="type">
+ <ref name="ST_FtnEdn"/>
+ </attribute>
+ <attribute name="id">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_CommentRef">
+ <ref name="CT_Markup"/>
+ </define>
+ <define name="EG_FtnEdnNumProps">
+ <element name="numStart">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="numRestart">
+ <ref name="CT_NumRestart"/>
+ </element>
+ </define>
+ <define name="CT_FtnProps">
+ <element name="pos">
+ <ref name="CT_FtnPos"/>
+ </element>
+ <element name="numFmt">
+ <ref name="CT_NumFmt"/>
+ </element>
+ <ref name="EG_FtnEdnNumProps"/>
+ </define>
+ <define name="CT_EdnProps">
+ <element name="pos">
+ <ref name="CT_EdnPos"/>
+ </element>
+ <element name="numFmt">
+ <ref name="CT_NumFmt"/>
+ </element>
+ <ref name="EG_FtnEdnNumProps"/>
+ </define>
+ <define name="CT_FtnDocProps">
+ <ref name="CT_FtnProps"/>
+ <element name="footnote">
+ <ref name="CT_FtnEdnSepRef"/>
+ </element>
+ </define>
+ <define name="CT_EdnDocProps">
+ <ref name="CT_EdnProps"/>
+ <element name="endnote">
+ <ref name="CT_FtnEdnSepRef"/>
+ </element>
+ </define>
+ <define name="CT_RecipientData">
+ <element name="active">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="column">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="uniqueTag">
+ <data type="base64Binary"/>
+ </element>
+ </define>
+ <define name="CT_Recipients">
+ <element name="recipientData">
+ <ref name="CT_RecipientData"/>
+ </element>
+ </define>
+ <define name="recipients">
+ <element name="recipients">
+ <ref name="CT_Recipients"/>
+ </element>
+ </define>
+ <define name="CT_OdsoFieldMapData">
+ <element name="type">
+ <ref name="CT_MailMergeOdsoFMDFieldType"/>
+ </element>
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="mappedName">
+ <ref name="CT_String"/>
+ </element>
+ <element name="column">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="lid">
+ <ref name="CT_Lang"/>
+ </element>
+ <element name="dynamicAddress">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_MailMergeSourceType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Odso">
+ <element name="udl">
+ <ref name="CT_String"/>
+ </element>
+ <element name="table">
+ <ref name="CT_String"/>
+ </element>
+ <element name="src">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="colDelim">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="type">
+ <ref name="CT_MailMergeSourceType"/>
+ </element>
+ <element name="fHdr">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="fieldMapData">
+ <ref name="CT_OdsoFieldMapData"/>
+ </element>
+ <element name="recipientData">
+ <ref name="CT_Rel"/>
+ </element>
+ </define>
+ <define name="CT_MailMerge">
+ <element name="mainDocumentType">
+ <ref name="CT_MailMergeDocType"/>
+ </element>
+ <element name="linkToQuery">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="dataType">
+ <ref name="CT_MailMergeDataType"/>
+ </element>
+ <element name="connectString">
+ <ref name="CT_String"/>
+ </element>
+ <element name="query">
+ <ref name="CT_String"/>
+ </element>
+ <element name="dataSource">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="headerSource">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="doNotSuppressBlankLines">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="destination">
+ <ref name="CT_MailMergeDest"/>
+ </element>
+ <element name="addressFieldName">
+ <ref name="CT_String"/>
+ </element>
+ <element name="mailSubject">
+ <ref name="CT_String"/>
+ </element>
+ <element name="mailAsAttachment">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="viewMergedData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="activeRecord">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="checkErrors">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="odso">
+ <ref name="CT_Odso"/>
+ </element>
+ </define>
+ <define name="CT_TargetScreenSz">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Compat">
+ <element name="useSingleBorderforContiguousCells">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wpJustification">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noTabHangInd">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noLeading">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="spaceForUL">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noColumnBalance">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="balanceSingleByteDoubleByteWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noExtraLineSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotLeaveBackslashAlone">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ulTrailSpace">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotExpandShiftReturn">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="spacingInWholePoints">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="lineWrapLikeWord6">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printBodyTextBeforeHeader">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printColBlack">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wpSpaceWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="showBreaksInFrames">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="subFontBySize">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressBottomSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressTopSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressSpacingAtTopOfPage">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressTopSpacingWP">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suppressSpBfAfterPgBrk">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="swapBordersFacingPages">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="convMailMergeEsc">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="truncateFontHeightsLikeWP6">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="mwSmallCaps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="usePrinterMetrics">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSuppressParagraphBorders">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="wrapTrailSpaces">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="footnoteLayoutLikeWW8">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="shapeLayoutLikeWW8">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alignTablesRowByRow">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="forgetLastTabAlignment">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="adjustLineHeightInTable">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="autoSpaceLikeWord95">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noSpaceRaiseLower">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseHTMLParagraphAutoSpacing">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="layoutRawTableWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="layoutTableRowsApart">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useWord97LineBreakRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotBreakWrappedTables">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSnapToGridInCell">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="selectFldWithFirstOrLastChar">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="applyBreakingRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotWrapTextWithPunct">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseEastAsianBreakRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useWord2002TableStyleRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="growAutofit">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useFELayout">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useNormalStyleForList">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseIndentAsNumberingTabStop">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useAltKinsokuLineBreakRules">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="allowSpaceOfSameStyleInTable">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSuppressIndentation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotAutofitConstrainedTables">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="autofitToFirstFixedWidthCell">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="underlineTabInNumList">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="displayHangulFixedWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="splitPgBreakAndParaMark">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotVertAlignCellWithSp">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotBreakConstrainedForcedTable">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotVertAlignInTxbx">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useAnsiKerningPairs">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="cachedColBalance">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="compatSetting">
+ <ref name="CT_CompatSetting"/>
+ </element>
+ </define>
+ <define name="CT_CompatSetting">
+ <attribute name="name">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="uri">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="val">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_DocVar">
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocVars">
+ <element name="docVar">
+ <ref name="CT_DocVar"/>
+ </element>
+ </define>
+ <define name="CT_DocRsids">
+ <element name="rsidRoot">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="rsid">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ </define>
+ <define name="CT_CharacterSpacing">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_SaveThroughXslt">
+ <attribute name="r:id">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="solutionID">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_RPrDefault">
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ </define>
+ <define name="CT_PPrDefault">
+ <element name="pPr">
+ <ref name="CT_PPr"/>
+ </element>
+ </define>
+ <define name="CT_DocDefaults">
+ <element name="rPrDefault">
+ <ref name="CT_RPrDefault"/>
+ </element>
+ <element name="pPrDefault">
+ <ref name="CT_PPrDefault"/>
+ </element>
+ </define>
+ <define name="ST_ColorSchemeIndex">
+ <choice>
+ <!-- Dark 1 Theme Color Reference -->
+ <value>dark1</value>
+ <!-- Light 1 Theme Color Reference -->
+ <value>light1</value>
+ <!-- Dark 2 Theme Color Reference -->
+ <value>dark2</value>
+ <!-- Light 2 Theme Color Reference -->
+ <value>light2</value>
+ <!-- Accent 1 Theme Color Reference -->
+ <value>accent1</value>
+ <!-- Accent 2 Theme Color Reference -->
+ <value>accent2</value>
+ <!-- Accent 3 Theme Color Reference -->
+ <value>accent3</value>
+ <!-- Accent4 Theme Color Reference -->
+ <value>accent4</value>
+ <!-- Accent5 Theme Color Reference -->
+ <value>accent5</value>
+ <!-- Accent 6 Theme Color Reference -->
+ <value>accent6</value>
+ <!-- Hyperlink Theme Color Reference -->
+ <value>hyperlink</value>
+ <!-- Followed Hyperlink Theme Color Reference -->
+ <value>followedHyperlink</value>
+ </choice>
+ </define>
+ <define name="CT_ColorSchemeMapping">
+ <attribute name="bg1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="t1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="bg2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="t2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent1">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent2">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent3">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent4">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent5">
+ <data type="string"/>
+ </attribute>
+ <attribute name="accent6">
+ <data type="string"/>
+ </attribute>
+ <attribute name="hyperlink">
+ <data type="string"/>
+ </attribute>
+ <attribute name="followedHyperlink">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_ReadingModeInkLockDown">
+ <attribute name="actualPg">
+ <data type="string"/>
+ </attribute>
+ <attribute name="w">
+ <data type="string"/>
+ </attribute>
+ <attribute name="h">
+ <data type="string"/>
+ </attribute>
+ <attribute name="fontSz">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_WriteProtection">
+ <attribute name="recommended">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <ref name="AG_Password"/>
+ </define>
+ <define name="CT_Settings">
+ <element name="writeProtection">
+ <ref name="CT_WriteProtection"/>
+ </element>
+ <element name="view">
+ <ref name="CT_View"/>
+ </element>
+ <element name="zoom">
+ <ref name="CT_Zoom"/>
+ </element>
+ <element name="linkStyles">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="removePersonalInformation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="removeDateAndTime">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotDisplayPageBoundaries">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="displayBackgroundShape">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printPostScriptOverText">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printFractionalCharacterWidth">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="printFormsData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="embedTrueTypeFonts">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="embedSystemFonts">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveSubsetFonts">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveFormsData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="mirrorMargins">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alignBordersAndEdges">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bordersDoNotSurroundHeader">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bordersDoNotSurroundFooter">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="gutterAtTop">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideSpellingErrors">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hideGrammaticalErrors">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="activeWritingStyle">
+ <ref name="CT_WritingStyle"/>
+ </element>
+ <element name="proofState">
+ <ref name="CT_Proof"/>
+ </element>
+ <element name="formsDesign">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="attachedTemplate">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="linkStyles">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="stylePaneFormatFilter">
+ <ref name="CT_ShortHexNumber"/>
+ </element>
+ <element name="stylePaneSortMethod">
+ <ref name="CT_ShortHexNumber"/>
+ </element>
+ <element name="documentType">
+ <ref name="CT_DocType"/>
+ </element>
+ <element name="mailMerge">
+ <ref name="CT_MailMerge"/>
+ </element>
+ <element name="revisionView">
+ <ref name="CT_TrackChangesView"/>
+ </element>
+ <element name="trackRevisions">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotTrackMoves">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotTrackFormatting">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="documentProtection">
+ <ref name="CT_DocProtect"/>
+ </element>
+ <element name="autoFormatOverride">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="styleLockTheme">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="styleLockQFSet">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="defaultTabStop">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="autoHyphenation">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="consecutiveHyphenLimit">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="hyphenationZone">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="doNotHyphenateCaps">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="showEnvelope">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="summaryLength">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="clickAndTypeStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="defaultTableStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="evenAndOddHeaders">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bookFoldRevPrinting">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bookFoldPrinting">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bookFoldPrintingSheets">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="drawingGridHorizontalSpacing">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="drawingGridVerticalSpacing">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="displayHorizontalDrawingGridEvery">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="displayVerticalDrawingGridEvery">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="doNotUseMarginsForDrawingGridOrigin">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="drawingGridHorizontalOrigin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="drawingGridVerticalOrigin">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="doNotShadeFormData">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noPunctuationKerning">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="characterSpacingControl">
+ <ref name="CT_CharacterSpacing"/>
+ </element>
+ <element name="printTwoOnOne">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="strictFirstAndLastChars">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="noLineBreaksAfter">
+ <ref name="CT_Kinsoku"/>
+ </element>
+ <element name="noLineBreaksBefore">
+ <ref name="CT_Kinsoku"/>
+ </element>
+ <element name="savePreviewPicture">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotValidateAgainstSchema">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveInvalidXml">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="ignoreMixedContent">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alwaysShowPlaceholderText">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotDemarcateInvalidXml">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveXmlDataOnly">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="useXSLTWhenSaving">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="saveThroughXslt">
+ <ref name="CT_SaveThroughXslt"/>
+ </element>
+ <element name="showXMLTags">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="alwaysMergeEmptyNamespace">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="updateFields">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hdrShapeDefaults">
+ <ref name="CT_ShapeDefaults"/>
+ </element>
+ <element name="footnotePr">
+ <ref name="CT_FtnDocProps"/>
+ </element>
+ <element name="endnotePr">
+ <ref name="CT_EdnDocProps"/>
+ </element>
+ <element name="compat">
+ <ref name="CT_Compat"/>
+ </element>
+ <element name="docVars">
+ <ref name="CT_DocVars"/>
+ </element>
+ <element name="rsids">
+ <ref name="CT_DocRsids"/>
+ </element>
+ <ref name="mathPr"/>
+ <element name="uiCompat97To2003">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="attachedSchema">
+ <ref name="CT_String"/>
+ </element>
+ <element name="themeFontLang">
+ <ref name="CT_Language"/>
+ </element>
+ <element name="clrSchemeMapping">
+ <ref name="CT_ColorSchemeMapping"/>
+ </element>
+ <element name="doNotIncludeSubdocsInStats">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotAutoCompressPictures">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="forceUpgrade">
+ <ref name="CT_Empty"/>
+ </element>
+ <element name="captions">
+ <ref name="CT_Captions"/>
+ </element>
+ <element name="readModeInkLockDown">
+ <ref name="CT_ReadingModeInkLockDown"/>
+ </element>
+ <element name="smartTagType">
+ <ref name="CT_SmartTagType"/>
+ </element>
+ <ref name="schemaLibrary"/>
+ <element name="shapeDefaults">
+ <ref name="CT_ShapeDefaults"/>
+ </element>
+ <element name="doNotEmbedSmartTags">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="decimalSymbol">
+ <ref name="CT_String"/>
+ </element>
+ <element name="listSeparator">
+ <ref name="CT_String"/>
+ </element>
+ </define>
+ <define name="CT_WebSettings">
+ <element name="frameset">
+ <ref name="CT_Frameset"/>
+ </element>
+ <element name="divs">
+ <ref name="CT_Divs"/>
+ </element>
+ <element name="encoding">
+ <ref name="CT_String"/>
+ </element>
+ <element name="optimizeForBrowser">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="relyOnVML">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="allowPNG">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotRelyOnCSS">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotSaveAsSingleFile">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotOrganizeInFolder">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="doNotUseLongFileNames">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="pixelsPerInch">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="targetScreenSz">
+ <ref name="CT_TargetScreenSz"/>
+ </element>
+ <element name="saveSmartTagsAsXml">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_FrameScrollbar">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Frame">
+ <element name="sz">
+ <ref name="CT_String"/>
+ </element>
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="sourceFileName">
+ <ref name="CT_Rel"/>
+ </element>
+ <element name="marW">
+ <ref name="CT_PixelsMeasure"/>
+ </element>
+ <element name="marH">
+ <ref name="CT_PixelsMeasure"/>
+ </element>
+ <element name="scrollbar">
+ <ref name="CT_FrameScrollbar"/>
+ </element>
+ <element name="noResizeAllowed">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="linkedToFile">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_FrameLayout">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FramesetSplitbar">
+ <element name="w">
+ <ref name="CT_TwipsMeasure"/>
+ </element>
+ <element name="color">
+ <ref name="CT_Color"/>
+ </element>
+ <element name="noBorder">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="flatBorders">
+ <ref name="CT_OnOff"/>
+ </element>
+ </define>
+ <define name="CT_Frameset">
+ <element name="sz">
+ <ref name="CT_String"/>
+ </element>
+ <element name="framesetSplitbar">
+ <ref name="CT_FramesetSplitbar"/>
+ </element>
+ <element name="frameLayout">
+ <ref name="CT_FrameLayout"/>
+ </element>
+ <choice>
+ <element name="frameset">
+ <ref name="CT_Frameset"/>
+ </element>
+ <element name="frame">
+ <ref name="CT_Frame"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_NumPicBullet">
+ <element name="pict">
+ <ref name="CT_Picture"/>
+ </element>
+ <attribute name="numPicBulletId">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LevelSuffix">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LevelText">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="null">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LvlLegacy">
+ <attribute name="legacy">
+ <data type="string"/>
+ </attribute>
+ <attribute name="legacySpace">
+ <data type="string"/>
+ </attribute>
+ <attribute name="legacyIndent">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Lvl">
+ <element name="start">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="numFmt">
+ <ref name="CT_NumFmt"/>
+ </element>
+ <element name="lvlRestart">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="pStyle">
+ <ref name="CT_String"/>
+ </element>
+ <element name="isLgl">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="suff">
+ <ref name="CT_LevelSuffix"/>
+ </element>
+ <element name="lvlText">
+ <ref name="CT_LevelText"/>
+ </element>
+ <element name="lvlPicBulletId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="legacy">
+ <ref name="CT_LvlLegacy"/>
+ </element>
+ <element name="lvlJc">
+ <ref name="CT_Jc"/>
+ </element>
+ <element name="pPr">
+ <ref name="CT_PPr"/>
+ </element>
+ <element name="rPr">
+ <ref name="CT_RPr"/>
+ </element>
+ <attribute name="ilvl">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tplc">
+ <data type="string"/>
+ </attribute>
+ <attribute name="tentative">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_MultiLevelType">
+ <choice>
+ <!-- Single Level Numbering Definition -->
+ <value>singleLevel</value>
+ <!-- Multilevel Numbering Definition -->
+ <value>multilevel</value>
+ <!-- Hybrid Multilevel Numbering Definition -->
+ <value>hybridMultilevel</value>
+ </choice>
+ </define>
+ <define name="CT_MultiLevelType">
+ <attribute name="val">
+ <ref name="ST_MultiLevelType"/>
+ </attribute>
+ </define>
+ <define name="CT_AbstractNum">
+ <element name="nsid">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="multiLevelType">
+ <ref name="CT_MultiLevelType"/>
+ </element>
+ <element name="tmpl">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="styleLink">
+ <ref name="CT_String"/>
+ </element>
+ <element name="numStyleLink">
+ <ref name="CT_String"/>
+ </element>
+ <element name="lvl">
+ <ref name="CT_Lvl"/>
+ </element>
+ <attribute name="abstractNumId">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_NumLvl">
+ <element name="startOverride">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="lvl">
+ <ref name="CT_Lvl"/>
+ </element>
+ <attribute name="ilvl">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Num">
+ <element name="abstractNumId">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="lvlOverride">
+ <ref name="CT_NumLvl"/>
+ </element>
+ <attribute name="numId">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Numbering">
+ <element name="numPicBullet">
+ <ref name="CT_NumPicBullet"/>
+ </element>
+ <element name="abstractNum">
+ <ref name="CT_AbstractNum"/>
+ </element>
+ <element name="num">
+ <ref name="CT_Num"/>
+ </element>
+ <element name="numIdMacAtCleanup">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ </define>
+ <define name="ST_TblStyleOverrideType">
+ <choice>
+ <!-- Whole table formatting -->
+ <value>wholeTable</value>
+ <!-- First Row Conditional Formatting -->
+ <value>firstRow</value>
+ <!-- Last table row formatting -->
+ <value>lastRow</value>
+ <!-- First Column Conditional Formatting -->
+ <value>firstCol</value>
+ <!-- Last table column formatting -->
+ <value>lastCol</value>
+ <!-- Banded Column Conditional Formatting -->
+ <value>band1Vert</value>
+ <!-- Even Column Stripe Conditional Formatting -->
+ <value>band2Vert</value>
+ <!-- Banded Row Conditional Formatting -->
+ <value>band1Horz</value>
+ <!-- Even Row Stripe Conditional Formatting -->
+ <value>band2Horz</value>
+ <!-- Top right table cell formatting -->
+ <value>neCell</value>
+ <!-- Top left table cell formatting -->
+ <value>nwCell</value>
+ <!-- Bottom right table cell formatting -->
+ <value>seCell</value>
+ <!-- Bottom left table cell formatting -->
+ <value>swCell</value>
+ </choice>
+ </define>
+ <define name="CT_Style_tblStylePr">
+ <element name="pPr">
+ <ref name="CT_PPrBase"/>
+ </element>
+ <element name="rPr">
+ <ref name="EG_RPrBase"/>
+ </element>
+ <element name="tblPr">
+ <ref name="CT_TblPrBase"/>
+ </element>
+ <element name="trPr">
+ <ref name="CT_TrPrBase"/>
+ </element>
+ <element name="tcPr">
+ <ref name="CT_TcPrBase"/>
+ </element>
+ <attribute name="type">
+ <ref name="ST_TblStyleOverrideType"/>
+ </attribute>
+ </define>
+ <define name="CT_Style_TblPr">
+ <ref name="CT_TblPrBase"/>
+ </define>
+ <define name="CT_Style_TrPr">
+ <ref name="CT_TrPrBase"/>
+ </define>
+ <define name="CT_Style_TcPr">
+ <ref name="CT_TcPrBase"/>
+ </define>
+ <define name="ST_StyleType">
+ <choice>
+ <!-- Paragraph Style -->
+ <value>paragraph</value>
+ <!-- Character Style -->
+ <value>character</value>
+ <!-- Table Style -->
+ <value>table</value>
+ <!-- Numbering Style -->
+ <value>numbering</value>
+ </choice>
+ </define>
+ <define name="CT_Style">
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="aliases">
+ <ref name="CT_String"/>
+ </element>
+ <element name="basedOn">
+ <ref name="CT_String"/>
+ </element>
+ <element name="next">
+ <ref name="CT_String"/>
+ </element>
+ <element name="link">
+ <ref name="CT_String"/>
+ </element>
+ <element name="autoRedefine">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="hidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="uiPriority">
+ <ref name="CT_DecimalNumber"/>
+ </element>
+ <element name="semiHidden">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="unhideWhenUsed">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="qFormat">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="locked">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="personal">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="personalCompose">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="personalReply">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="rsid">
+ <ref name="CT_LongHexNumber"/>
+ </element>
+ <element name="pPr">
+ <ref name="CT_PPrBase"/>
+ </element>
+ <element name="rPr">
+ <ref name="EG_RPrBase"/>
+ </element>
+ <element name="tblPr">
+ <ref name="CT_TblPrBase"/>
+ </element>
+ <element name="trPr">
+ <ref name="CT_TrPrBase"/>
+ </element>
+ <element name="tcPr">
+ <ref name="CT_TcPrBase"/>
+ </element>
+ <element name="tblStylePr">
+ <ref name="CT_Style_tblStylePr"/>
+ </element>
+ <attribute name="type">
+ <ref name="ST_StyleType"/>
+ </attribute>
+ <attribute name="styleId">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="default">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="customStyle">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ </define>
+ <define name="CT_LsdException">
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="locked">
+ <data type="string"/>
+ </attribute>
+ <attribute name="uiPriority">
+ <data type="string"/>
+ </attribute>
+ <attribute name="semiHidden">
+ <data type="string"/>
+ </attribute>
+ <attribute name="unhideWhenUsed">
+ <data type="string"/>
+ </attribute>
+ <attribute name="qFormat">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_LatentStyles">
+ <element name="lsdException">
+ <ref name="CT_LsdException"/>
+ </element>
+ <attribute name="defLockedState">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defUIPriority">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defSemiHidden">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defUnhideWhenUsed">
+ <data type="string"/>
+ </attribute>
+ <attribute name="defQFormat">
+ <data type="string"/>
+ </attribute>
+ <attribute name="count">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Styles">
+ <element name="docDefaults">
+ <ref name="CT_DocDefaults"/>
+ </element>
+ <element name="latentStyles">
+ <ref name="CT_LatentStyles"/>
+ </element>
+ <element name="style">
+ <ref name="CT_Style"/>
+ </element>
+ </define>
+ <define name="ST_Panose">
+ <data type="hexBinary"/>
+ </define>
+ <define name="CT_Panose">
+ <attribute name="val">
+ <ref name="ST_Panose"/>
+ </attribute>
+ </define>
+ <define name="ST_FontFamily">
+ <choice>
+ <!-- Novelty Font -->
+ <value>decorative</value>
+ <!-- Monospace Font -->
+ <value>modern</value>
+ <!-- Proportional Font With Serifs -->
+ <value>roman</value>
+ <!-- Script Font -->
+ <value>script</value>
+ <!-- Proportional Font Without Serifs -->
+ <value>swiss</value>
+ <!-- No Font Family -->
+ <value>auto</value>
+ </choice>
+ </define>
+ <define name="CT_FontFamily">
+ <attribute name="val">
+ <ref name="ST_FontFamily"/>
+ </attribute>
+ </define>
+ <define name="ST_Pitch">
+ <choice>
+ <!-- Fixed Width -->
+ <value>fixed</value>
+ <!-- Proportional Width -->
+ <value>variable</value>
+ <!-- Default -->
+ <value>default</value>
+ </choice>
+ </define>
+ <define name="CT_Pitch">
+ <attribute name="val">
+ <ref name="ST_Pitch"/>
+ </attribute>
+ </define>
+ <define name="CT_FontSig">
+ <attribute name="usb0">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="usb1">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="usb2">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="usb3">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="csb0">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="csb1">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ </define>
+ <define name="CT_FontRel">
+ <ref name="CT_Rel"/>
+ <attribute name="fontKey">
+ <data type="string"/>
+ </attribute>
+ <attribute name="subsetted">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Font">
+ <element name="altName">
+ <ref name="CT_String"/>
+ </element>
+ <element name="panose1">
+ <ref name="CT_Panose"/>
+ </element>
+ <element name="charset">
+ <ref name="CT_Charset"/>
+ </element>
+ <element name="characterSet">
+ <ref name="CT_String"/>
+ </element>
+ <element name="family">
+ <ref name="CT_FontFamily"/>
+ </element>
+ <element name="notTrueType">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="pitch">
+ <ref name="CT_Pitch"/>
+ </element>
+ <element name="sig">
+ <ref name="CT_FontSig"/>
+ </element>
+ <element name="embedRegular">
+ <ref name="CT_FontRel"/>
+ </element>
+ <element name="embedBold">
+ <ref name="CT_FontRel"/>
+ </element>
+ <element name="embedItalic">
+ <ref name="CT_FontRel"/>
+ </element>
+ <element name="embedBoldItalic">
+ <ref name="CT_FontRel"/>
+ </element>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_FontsList">
+ <element name="font">
+ <ref name="CT_Font"/>
+ </element>
+ </define>
+ <define name="CT_Charset">
+ <attribute name="val">
+ <ref name="ST_UcharHexNumber"/>
+ </attribute>
+ <attribute name="characterSet">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_DivBdr">
+ <element name="top">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="left">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="bottom">
+ <ref name="CT_Border"/>
+ </element>
+ <element name="right">
+ <ref name="CT_Border"/>
+ </element>
+ </define>
+ <define name="CT_Div">
+ <element name="blockQuote">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="bodyDiv">
+ <ref name="CT_OnOff"/>
+ </element>
+ <element name="marLeft">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="marRight">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="marTop">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="marBottom">
+ <ref name="CT_SignedTwipsMeasure"/>
+ </element>
+ <element name="divBdr">
+ <ref name="CT_DivBdr"/>
+ </element>
+ <element name="divsChild">
+ <ref name="CT_Divs"/>
+ </element>
+ <attribute name="id">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_Divs">
+ <element name="div">
+ <ref name="CT_Div"/>
+ </element>
+ </define>
+ <define name="CT_TxbxContent">
+ <ref name="EG_BlockLevelElts"/>
+ </define>
+ <define name="txbxContent">
+ <element name="txbxContent">
+ <ref name="CT_TxbxContent"/>
+ </element>
+ </define>
+ <define name="EG_MathContent">
+ <choice>
+ <ref name="oMathPara"/>
+ <ref name="oMath"/>
+ </choice>
+ </define>
+ <define name="EG_BlockLevelChunkElts">
+ <ref name="EG_ContentBlockContent"/>
+ </define>
+ <define name="EG_BlockLevelElts">
+ <choice>
+ <ref name="EG_BlockLevelChunkElts"/>
+ <element name="altChunk">
+ <ref name="CT_AltChunk"/>
+ </element>
+ </choice>
+ </define>
+ <define name="EG_RunLevelElts">
+ <choice>
+ <element name="proofErr">
+ <ref name="CT_ProofErr"/>
+ </element>
+ <ref name="EG_RangeMarkupElements"/>
+ <element name="ins">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <element name="del">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <element name="moveFrom">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <element name="moveTo">
+ <ref name="CT_RunTrackChange"/>
+ </element>
+ <ref name="EG_MathContent"/>
+ </choice>
+ </define>
+ <define name="CT_Body">
+ <ref name="EG_BlockLevelElts"/>
+ <element name="sectPr">
+ <ref name="CT_finalSectPr"/>
+ </element>
+ </define>
+ <define name="CT_ShapeDefaults">
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ </define>
+ <define name="CT_Comments">
+ <element name="comment">
+ <ref name="CT_Comment"/>
+ </element>
+ </define>
+ <define name="comments">
+ <element name="comments">
+ <ref name="CT_Comments"/>
+ </element>
+ </define>
+ <define name="CT_Footnotes">
+ <element name="footnote">
+ <ref name="CT_FtnEdn"/>
+ </element>
+ </define>
+ <define name="footnotes">
+ <element name="footnotes">
+ <ref name="CT_Footnotes"/>
+ </element>
+ </define>
+ <define name="CT_Endnotes">
+ <element name="endnote">
+ <ref name="CT_FtnEdn"/>
+ </element>
+ </define>
+ <define name="endnotes">
+ <element name="endnotes">
+ <ref name="CT_Endnotes"/>
+ </element>
+ </define>
+ <define name="hdr">
+ <element name="hdr">
+ <ref name="CT_HdrFtr"/>
+ </element>
+ </define>
+ <define name="ftr">
+ <element name="ftr">
+ <ref name="CT_HdrFtr"/>
+ </element>
+ </define>
+ <define name="CT_SmartTagType">
+ <attribute name="namespaceuri">
+ <data type="string"/>
+ </attribute>
+ <attribute name="name">
+ <data type="string"/>
+ </attribute>
+ <attribute name="url">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="ST_ThemeColor">
+ <choice>
+ <!-- Dark 1 Theme Color -->
+ <value>dark1</value>
+ <!-- Light 1 Theme Color -->
+ <value>light1</value>
+ <!-- Dark 2 Theme Color -->
+ <value>dark2</value>
+ <!-- Light 2 Theme Color -->
+ <value>light2</value>
+ <!-- Accent 1 Theme Color -->
+ <value>accent1</value>
+ <!-- Accent 2 Theme Color -->
+ <value>accent2</value>
+ <!-- Accent 3 Theme Color -->
+ <value>accent3</value>
+ <!-- Accent 4 Theme Color -->
+ <value>accent4</value>
+ <!-- Accent 5 Theme Color -->
+ <value>accent5</value>
+ <!-- Accent 6 Theme Color -->
+ <value>accent6</value>
+ <!-- Hyperlink Theme Color -->
+ <value>hyperlink</value>
+ <!-- Followed Hyperlink Theme Color -->
+ <value>followedHyperlink</value>
+ <!-- No Theme Color -->
+ <value>none</value>
+ <!-- Background 1 Theme Color -->
+ <value>background1</value>
+ <!-- Text 1 Theme Color -->
+ <value>text1</value>
+ <!-- Background 2 Theme Color -->
+ <value>background2</value>
+ <!-- Text 2 Theme Color -->
+ <value>text2</value>
+ </choice>
+ </define>
+ <define name="CT_DocPartBehavior">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartBehaviors">
+ <element name="behavior">
+ <ref name="CT_DocPartBehavior"/>
+ </element>
+ </define>
+ <define name="CT_DocPartType">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartTypes">
+ <element name="type">
+ <ref name="CT_DocPartType"/>
+ </element>
+ <attribute name="all">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartGallery">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartCategory">
+ <element name="name">
+ <ref name="CT_String"/>
+ </element>
+ <element name="gallery">
+ <ref name="CT_DocPartGallery"/>
+ </element>
+ </define>
+ <define name="CT_DocPartName">
+ <attribute name="val">
+ <data type="string"/>
+ </attribute>
+ <attribute name="decorated">
+ <data type="string"/>
+ </attribute>
+ </define>
+ <define name="CT_DocPartPr">
+ <choice>
+ <element name="name">
+ <ref name="CT_DocPartName"/>
+ </element>
+ <element name="style">
+ <ref name="CT_String"/>
+ </element>
+ <element name="category">
+ <ref name="CT_DocPartCategory"/>
+ </element>
+ <element name="types">
+ <ref name="CT_DocPartTypes"/>
+ </element>
+ <element name="behaviors">
+ <ref name="CT_DocPartBehaviors"/>
+ </element>
+ <element name="description">
+ <ref name="CT_String"/>
+ </element>
+ <element name="guid">
+ <ref name="CT_Guid"/>
+ </element>
+ </choice>
+ </define>
+ <define name="CT_DocPart">
+ <element name="docPartPr">
+ <ref name="CT_DocPartPr"/>
+ </element>
+ <element name="docPartBody">
+ <ref name="CT_Body"/>
+ </element>
+ </define>
+ <define name="CT_DocParts">
+ <element name="docPart">
+ <ref name="CT_DocPart"/>
+ </element>
+ </define>
+ <define name="settings">
+ <element name="settings">
+ <ref name="CT_Settings"/>
+ </element>
+ </define>
+ <define name="webSettings">
+ <element name="webSettings">
+ <ref name="CT_WebSettings"/>
+ </element>
+ </define>
+ <define name="fonts">
+ <element name="fonts">
+ <ref name="CT_FontsList"/>
+ </element>
+ </define>
+ <define name="numbering">
+ <element name="numbering">
+ <ref name="CT_Numbering"/>
+ </element>
+ </define>
+ <define name="styles">
+ <element name="styles">
+ <ref name="CT_Styles"/>
+ </element>
+ </define>
+ <define name="ST_CaptionPos">
+ <choice>
+ <!-- Position Caption Above Object -->
+ <value>above</value>
+ <!-- Position Caption Below Object -->
+ <value>below</value>
+ <!-- Position Caption Left Of Object -->
+ <value>left</value>
+ <!-- Position Caption Right Of Object -->
+ <value>right</value>
+ </choice>
+ </define>
+ <define name="CT_Caption">
+ <attribute name="name">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="pos">
+ <ref name="ST_CaptionPos"/>
+ </attribute>
+ <attribute name="chapNum">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="heading">
+ <ref name="ST_DecimalNumber"/>
+ </attribute>
+ <attribute name="noLabel">
+ <ref name="ST_OnOff"/>
+ </attribute>
+ <attribute name="numFmt">
+ <ref name="ST_NumberFormat"/>
+ </attribute>
+ <attribute name="sep">
+ <ref name="ST_ChapterSep"/>
+ </attribute>
+ </define>
+ <define name="CT_AutoCaption">
+ <attribute name="name">
+ <ref name="ST_String"/>
+ </attribute>
+ <attribute name="caption">
+ <ref name="ST_String"/>
+ </attribute>
+ </define>
+ <define name="CT_AutoCaptions">
+ <element name="autoCaption">
+ <ref name="CT_AutoCaption"/>
+ </element>
+ </define>
+ <define name="CT_Captions">
+ <element name="caption">
+ <ref name="CT_Caption"/>
+ </element>
+ <element name="autoCaptions">
+ <ref name="CT_AutoCaptions"/>
+ </element>
+ </define>
+ <define name="CT_DocumentBase">
+ <element name="background">
+ <ref name="CT_Background"/>
+ </element>
+ </define>
+ <define name="CT_Document">
+ <ref name="CT_DocumentBase"/>
+ <element name="body">
+ <ref name="CT_Body"/>
+ </element>
+ </define>
+ <define name="CT_GlossaryDocument">
+ <ref name="CT_DocumentBase"/>
+ <element name="docParts">
+ <ref name="CT_DocParts"/>
+ </element>
+ </define>
+ <define name="document">
+ <element name="document">
+ <ref name="CT_Document"/>
+ </element>
+ </define>
+ <define name="glossaryDocument">
+ <element name="glossaryDocument">
+ <ref name="CT_GlossaryDocument"/>
+ </element>
+ </define>
+ <define name="BUILT_IN_ANY_TYPE">
+ <choice>
+ <element>
+ <ref name="BUILT_IN_ANY_TYPE"/>
+ </element>
+ <data type="string"/>
+ </choice>
+ </define>
+ </grammar>
+ <resource name="CT_Empty" resource="Stream">
+ <action name="end" tokenid="ooxml:EG_RunInnerContent_noBreakHyphen" action="noBreakHyphen"/>
+ <action name="end" tokenid="ooxml:EG_RunInnerContent_softHyphen" action="softHyphen"/>
+ <action name="end" tokenid="ooxml:EG_RunInnerContent_cr" action="cr"/>
+ </resource>
+ <resource name="ST_OnOff" resource="Boolean"/>
+ <resource name="CT_OnOff" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_OnOff_val" action="setValue"/>
+ <action name="start" action="setDefaultBooleanValue"/>
+ </resource>
+ <resource name="ST_LongHexNumber" resource="Hex"/>
+ <resource name="CT_LongHexNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_LongHexNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="ST_ShortHexNumber" resource="Hex"/>
+ <resource name="CT_ShortHexNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_ShortHexNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="ST_UcharHexNumber" resource="Hex"/>
+ <resource name="CT_UcharHexNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_UcharHexNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="ST_DecimalNumber" resource="Integer"/>
+ <resource name="CT_DecimalNumber" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DecimalNumber_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_UnsignedDecimalNumber" resource="Integer"/>
+<!--
+ Historically, LO has treated TwipsMeasure as signed,
+ i.e. that negative numbers are allowed and treated as negative,
+ so that is the default handling.
+-->
+ <resource name="ST_TwipsMeasure" resource="TwipsMeasure_asSigned"/>
+ <resource name="ST_TwipsMeasure_asSigned" resource="TwipsMeasure_asSigned"/>
+ <resource name="ST_TwipsMeasure_asZero" resource="TwipsMeasure_asZero"/>
+ <resource name="CT_TwipsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TwipsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_SignedTwipsMeasure" resource="TwipsMeasure_asSigned"/>
+ <resource name="CT_SignedTwipsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SignedTwipsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_PixelsMeasure" resource="Integer"/>
+ <resource name="CT_PixelsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_PixelsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_HpsMeasure" resource="HpsMeasure"/>
+ <resource name="CT_HpsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_HpsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_SignedHpsMeasure" resource="Integer"/>
+ <resource name="CT_SignedHpsMeasure" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SignedHpsMeasure_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_MeasurementOrPercent" resource="MeasurementOrPercent"/>
+ <resource name="ST_DateTime" resource="String"/>
+ <resource name="CT_MacroName" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MacroName_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_EighthPointMeasure" resource="Integer"/>
+ <resource name="ST_PointMeasure" resource="Integer"/>
+ <resource name="ST_String" resource="String"/>
+ <resource name="CT_String" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_String_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_TextScale" resource="Integer"/>
+ <resource name="CT_TextScale" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextScale_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="ST_HighlightColor" resource="List">
+ <value tokenid="ooxml:Value_ST_HighlightColor_black">black</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_blue">blue</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_cyan">cyan</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_green">green</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_magenta">magenta</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_red">red</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_yellow">yellow</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_white">white</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkBlue">darkBlue</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkCyan">darkCyan</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkGreen">darkGreen</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkMagenta">darkMagenta</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkRed">darkRed</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkYellow">darkYellow</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_darkGray">darkGray</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_lightGray">lightGray</value>
+ <value tokenid="ooxml:Value_ST_HighlightColor_none">none</value>
+ </resource>
+ <resource name="CT_Highlight" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Highlight_val" action="setValue"/>
+ </resource>
+ <resource name="ST_HexColorAuto" resource="List">
+ <value tokenid="ooxml:Value_ST_HexColorAuto_auto">auto</value>
+ </resource>
+ <resource name="ST_HexColorRGB" resource="Hex"/>
+ <resource name="ST_HexColor" resource="HexColor"/>
+ <resource name="CT_Color" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Color_val"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Color_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Color_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Color_themeShade"/>
+ </resource>
+ <resource name="ST_LangCode" resource="Hex"/>
+ <resource name="ST_Lang" resource="String"/>
+ <resource name="CT_Lang" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Lang_val" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="CT_Guid" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Guid_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="ST_Underline" resource="List">
+ <value tokenid="ooxml:Value_ST_Underline_single">single</value>
+ <value tokenid="ooxml:Value_ST_Underline_words">words</value>
+ <value tokenid="ooxml:Value_ST_Underline_double">double</value>
+ <value tokenid="ooxml:Value_ST_Underline_thick">thick</value>
+ <value tokenid="ooxml:Value_ST_Underline_dotted">dotted</value>
+ <value tokenid="ooxml:Value_ST_Underline_dottedHeavy">dottedHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dash">dash</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashedHeavy">dashedHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashLong">dashLong</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashLongHeavy">dashLongHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dotDash">dotDash</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashDotHeavy">dashDotHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_dotDotDash">dotDotDash</value>
+ <value tokenid="ooxml:Value_ST_Underline_dashDotDotHeavy">dashDotDotHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_wave">wave</value>
+ <value tokenid="ooxml:Value_ST_Underline_wavyHeavy">wavyHeavy</value>
+ <value tokenid="ooxml:Value_ST_Underline_wavyDouble">wavyDouble</value>
+ <value tokenid="ooxml:Value_ST_Underline_none">none</value>
+ </resource>
+ <resource name="CT_Underline" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Underline_val"/>
+ <attribute name="color" tokenid="ooxml:CT_Underline_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Underline_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Underline_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Underline_themeShade"/>
+ </resource>
+ <resource name="ST_TextEffect" resource="List">
+ <value tokenid="ooxml:Value_ST_TextEffect_none">none</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_lights">lights</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_blinkBackground">blinkBackground</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_sparkle">sparkle</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_antsBlack">antsBlack</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_antsRed">antsRed</value>
+ <value tokenid="ooxml:Value_ST_TextEffect_shimmer">shimmer</value>
+ </resource>
+ <resource name="CT_TextEffect" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextEffect_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Border" resource="List">
+ <value tokenid="ooxml:Value_ST_Border_nil">nil</value>
+ <value tokenid="ooxml:Value_ST_Border_none">none</value>
+ <value tokenid="ooxml:Value_ST_Border_single">single</value>
+ <value tokenid="ooxml:Value_ST_Border_thick">thick</value>
+ <value tokenid="ooxml:Value_ST_Border_double">double</value>
+ <value tokenid="ooxml:Value_ST_Border_dotted">dotted</value>
+ <value tokenid="ooxml:Value_ST_Border_dashed">dashed</value>
+ <value tokenid="ooxml:Value_ST_Border_dotDash">dotDash</value>
+ <value tokenid="ooxml:Value_ST_Border_dotDotDash">dotDotDash</value>
+ <value tokenid="ooxml:Value_ST_Border_triple">triple</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickSmallGap">thinThickSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thickThinSmallGap">thickThinSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickThinSmallGap">thinThickThinSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickMediumGap">thinThickMediumGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thickThinMediumGap">thickThinMediumGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickThinMediumGap">thinThickThinMediumGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickLargeGap">thinThickLargeGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thickThinLargeGap">thickThinLargeGap</value>
+ <value tokenid="ooxml:Value_ST_Border_thinThickThinLargeGap">thinThickThinLargeGap</value>
+ <value tokenid="ooxml:Value_ST_Border_wave">wave</value>
+ <value tokenid="ooxml:Value_ST_Border_doubleWave">doubleWave</value>
+ <value tokenid="ooxml:Value_ST_Border_dashSmallGap">dashSmallGap</value>
+ <value tokenid="ooxml:Value_ST_Border_dashDotStroked">dashDotStroked</value>
+ <value tokenid="ooxml:Value_ST_Border_threeDEmboss">threeDEmboss</value>
+ <value tokenid="ooxml:Value_ST_Border_threeDEngrave">threeDEngrave</value>
+ <value tokenid="ooxml:Value_ST_Border_outset">outset</value>
+ <value tokenid="ooxml:Value_ST_Border_inset">inset</value>
+ <value tokenid="ooxml:Value_ST_Border_apples">apples</value>
+ <value tokenid="ooxml:Value_ST_Border_archedScallops">archedScallops</value>
+ <value tokenid="ooxml:Value_ST_Border_babyPacifier">babyPacifier</value>
+ <value tokenid="ooxml:Value_ST_Border_babyRattle">babyRattle</value>
+ <value tokenid="ooxml:Value_ST_Border_balloons3Colors">balloons3Colors</value>
+ <value tokenid="ooxml:Value_ST_Border_balloonsHotAir">balloonsHotAir</value>
+ <value tokenid="ooxml:Value_ST_Border_basicBlackDashes">basicBlackDashes</value>
+ <value tokenid="ooxml:Value_ST_Border_basicBlackDots">basicBlackDots</value>
+ <value tokenid="ooxml:Value_ST_Border_basicBlackSquares">basicBlackSquares</value>
+ <value tokenid="ooxml:Value_ST_Border_basicThinLines">basicThinLines</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWhiteDashes">basicWhiteDashes</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWhiteDots">basicWhiteDots</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWhiteSquares">basicWhiteSquares</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWideInline">basicWideInline</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWideMidline">basicWideMidline</value>
+ <value tokenid="ooxml:Value_ST_Border_basicWideOutline">basicWideOutline</value>
+ <value tokenid="ooxml:Value_ST_Border_bats">bats</value>
+ <value tokenid="ooxml:Value_ST_Border_birds">birds</value>
+ <value tokenid="ooxml:Value_ST_Border_birdsFlight">birdsFlight</value>
+ <value tokenid="ooxml:Value_ST_Border_cabins">cabins</value>
+ <value tokenid="ooxml:Value_ST_Border_cakeSlice">cakeSlice</value>
+ <value tokenid="ooxml:Value_ST_Border_candyCorn">candyCorn</value>
+ <value tokenid="ooxml:Value_ST_Border_celticKnotwork">celticKnotwork</value>
+ <value tokenid="ooxml:Value_ST_Border_certificateBanner">certificateBanner</value>
+ <value tokenid="ooxml:Value_ST_Border_chainLink">chainLink</value>
+ <value tokenid="ooxml:Value_ST_Border_champagneBottle">champagneBottle</value>
+ <value tokenid="ooxml:Value_ST_Border_checkedBarBlack">checkedBarBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_checkedBarColor">checkedBarColor</value>
+ <value tokenid="ooxml:Value_ST_Border_checkered">checkered</value>
+ <value tokenid="ooxml:Value_ST_Border_christmasTree">christmasTree</value>
+ <value tokenid="ooxml:Value_ST_Border_circlesLines">circlesLines</value>
+ <value tokenid="ooxml:Value_ST_Border_circlesRectangles">circlesRectangles</value>
+ <value tokenid="ooxml:Value_ST_Border_classicalWave">classicalWave</value>
+ <value tokenid="ooxml:Value_ST_Border_clocks">clocks</value>
+ <value tokenid="ooxml:Value_ST_Border_compass">compass</value>
+ <value tokenid="ooxml:Value_ST_Border_confetti">confetti</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiGrays">confettiGrays</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiOutline">confettiOutline</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiStreamers">confettiStreamers</value>
+ <value tokenid="ooxml:Value_ST_Border_confettiWhite">confettiWhite</value>
+ <value tokenid="ooxml:Value_ST_Border_cornerTriangles">cornerTriangles</value>
+ <value tokenid="ooxml:Value_ST_Border_couponCutoutDashes">couponCutoutDashes</value>
+ <value tokenid="ooxml:Value_ST_Border_couponCutoutDots">couponCutoutDots</value>
+ <value tokenid="ooxml:Value_ST_Border_crazyMaze">crazyMaze</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesButterfly">creaturesButterfly</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesFish">creaturesFish</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesInsects">creaturesInsects</value>
+ <value tokenid="ooxml:Value_ST_Border_creaturesLadyBug">creaturesLadyBug</value>
+ <value tokenid="ooxml:Value_ST_Border_crossStitch">crossStitch</value>
+ <value tokenid="ooxml:Value_ST_Border_cup">cup</value>
+ <value tokenid="ooxml:Value_ST_Border_decoArch">decoArch</value>
+ <value tokenid="ooxml:Value_ST_Border_decoArchColor">decoArchColor</value>
+ <value tokenid="ooxml:Value_ST_Border_decoBlocks">decoBlocks</value>
+ <value tokenid="ooxml:Value_ST_Border_diamondsGray">diamondsGray</value>
+ <value tokenid="ooxml:Value_ST_Border_doubleD">doubleD</value>
+ <value tokenid="ooxml:Value_ST_Border_doubleDiamonds">doubleDiamonds</value>
+ <value tokenid="ooxml:Value_ST_Border_earth1">earth1</value>
+ <value tokenid="ooxml:Value_ST_Border_earth2">earth2</value>
+ <value tokenid="ooxml:Value_ST_Border_eclipsingSquares1">eclipsingSquares1</value>
+ <value tokenid="ooxml:Value_ST_Border_eclipsingSquares2">eclipsingSquares2</value>
+ <value tokenid="ooxml:Value_ST_Border_eggsBlack">eggsBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_fans">fans</value>
+ <value tokenid="ooxml:Value_ST_Border_film">film</value>
+ <value tokenid="ooxml:Value_ST_Border_firecrackers">firecrackers</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersBlockPrint">flowersBlockPrint</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersDaisies">flowersDaisies</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersModern1">flowersModern1</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersModern2">flowersModern2</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersPansy">flowersPansy</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersRedRose">flowersRedRose</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersRoses">flowersRoses</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersTeacup">flowersTeacup</value>
+ <value tokenid="ooxml:Value_ST_Border_flowersTiny">flowersTiny</value>
+ <value tokenid="ooxml:Value_ST_Border_gems">gems</value>
+ <value tokenid="ooxml:Value_ST_Border_gingerbreadMan">gingerbreadMan</value>
+ <value tokenid="ooxml:Value_ST_Border_gradient">gradient</value>
+ <value tokenid="ooxml:Value_ST_Border_handmade1">handmade1</value>
+ <value tokenid="ooxml:Value_ST_Border_handmade2">handmade2</value>
+ <value tokenid="ooxml:Value_ST_Border_heartBalloon">heartBalloon</value>
+ <value tokenid="ooxml:Value_ST_Border_heartGray">heartGray</value>
+ <value tokenid="ooxml:Value_ST_Border_hearts">hearts</value>
+ <value tokenid="ooxml:Value_ST_Border_heebieJeebies">heebieJeebies</value>
+ <value tokenid="ooxml:Value_ST_Border_holly">holly</value>
+ <value tokenid="ooxml:Value_ST_Border_houseFunky">houseFunky</value>
+ <value tokenid="ooxml:Value_ST_Border_hypnotic">hypnotic</value>
+ <value tokenid="ooxml:Value_ST_Border_iceCreamCones">iceCreamCones</value>
+ <value tokenid="ooxml:Value_ST_Border_lightBulb">lightBulb</value>
+ <value tokenid="ooxml:Value_ST_Border_lightning1">lightning1</value>
+ <value tokenid="ooxml:Value_ST_Border_lightning2">lightning2</value>
+ <value tokenid="ooxml:Value_ST_Border_mapPins">mapPins</value>
+ <value tokenid="ooxml:Value_ST_Border_mapleLeaf">mapleLeaf</value>
+ <value tokenid="ooxml:Value_ST_Border_mapleMuffins">mapleMuffins</value>
+ <value tokenid="ooxml:Value_ST_Border_marquee">marquee</value>
+ <value tokenid="ooxml:Value_ST_Border_marqueeToothed">marqueeToothed</value>
+ <value tokenid="ooxml:Value_ST_Border_moons">moons</value>
+ <value tokenid="ooxml:Value_ST_Border_mosaic">mosaic</value>
+ <value tokenid="ooxml:Value_ST_Border_musicNotes">musicNotes</value>
+ <value tokenid="ooxml:Value_ST_Border_northwest">northwest</value>
+ <value tokenid="ooxml:Value_ST_Border_ovals">ovals</value>
+ <value tokenid="ooxml:Value_ST_Border_packages">packages</value>
+ <value tokenid="ooxml:Value_ST_Border_palmsBlack">palmsBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_palmsColor">palmsColor</value>
+ <value tokenid="ooxml:Value_ST_Border_paperClips">paperClips</value>
+ <value tokenid="ooxml:Value_ST_Border_papyrus">papyrus</value>
+ <value tokenid="ooxml:Value_ST_Border_partyFavor">partyFavor</value>
+ <value tokenid="ooxml:Value_ST_Border_partyGlass">partyGlass</value>
+ <value tokenid="ooxml:Value_ST_Border_pencils">pencils</value>
+ <value tokenid="ooxml:Value_ST_Border_people">people</value>
+ <value tokenid="ooxml:Value_ST_Border_peopleWaving">peopleWaving</value>
+ <value tokenid="ooxml:Value_ST_Border_peopleHats">peopleHats</value>
+ <value tokenid="ooxml:Value_ST_Border_poinsettias">poinsettias</value>
+ <value tokenid="ooxml:Value_ST_Border_postageStamp">postageStamp</value>
+ <value tokenid="ooxml:Value_ST_Border_pumpkin1">pumpkin1</value>
+ <value tokenid="ooxml:Value_ST_Border_pushPinNote2">pushPinNote2</value>
+ <value tokenid="ooxml:Value_ST_Border_pushPinNote1">pushPinNote1</value>
+ <value tokenid="ooxml:Value_ST_Border_pyramids">pyramids</value>
+ <value tokenid="ooxml:Value_ST_Border_pyramidsAbove">pyramidsAbove</value>
+ <value tokenid="ooxml:Value_ST_Border_quadrants">quadrants</value>
+ <value tokenid="ooxml:Value_ST_Border_rings">rings</value>
+ <value tokenid="ooxml:Value_ST_Border_safari">safari</value>
+ <value tokenid="ooxml:Value_ST_Border_sawtooth">sawtooth</value>
+ <value tokenid="ooxml:Value_ST_Border_sawtoothGray">sawtoothGray</value>
+ <value tokenid="ooxml:Value_ST_Border_scaredCat">scaredCat</value>
+ <value tokenid="ooxml:Value_ST_Border_seattle">seattle</value>
+ <value tokenid="ooxml:Value_ST_Border_shadowedSquares">shadowedSquares</value>
+ <value tokenid="ooxml:Value_ST_Border_sharksTeeth">sharksTeeth</value>
+ <value tokenid="ooxml:Value_ST_Border_shorebirdTracks">shorebirdTracks</value>
+ <value tokenid="ooxml:Value_ST_Border_skyrocket">skyrocket</value>
+ <value tokenid="ooxml:Value_ST_Border_snowflakeFancy">snowflakeFancy</value>
+ <value tokenid="ooxml:Value_ST_Border_snowflakes">snowflakes</value>
+ <value tokenid="ooxml:Value_ST_Border_sombrero">sombrero</value>
+ <value tokenid="ooxml:Value_ST_Border_southwest">southwest</value>
+ <value tokenid="ooxml:Value_ST_Border_stars">stars</value>
+ <value tokenid="ooxml:Value_ST_Border_starsTop">starsTop</value>
+ <value tokenid="ooxml:Value_ST_Border_stars3d">stars3d</value>
+ <value tokenid="ooxml:Value_ST_Border_starsBlack">starsBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_starsShadowed">starsShadowed</value>
+ <value tokenid="ooxml:Value_ST_Border_sun">sun</value>
+ <value tokenid="ooxml:Value_ST_Border_swirligig">swirligig</value>
+ <value tokenid="ooxml:Value_ST_Border_tornPaper">tornPaper</value>
+ <value tokenid="ooxml:Value_ST_Border_tornPaperBlack">tornPaperBlack</value>
+ <value tokenid="ooxml:Value_ST_Border_trees">trees</value>
+ <value tokenid="ooxml:Value_ST_Border_triangleParty">triangleParty</value>
+ <value tokenid="ooxml:Value_ST_Border_triangles">triangles</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal1">tribal1</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal2">tribal2</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal3">tribal3</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal4">tribal4</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal5">tribal5</value>
+ <value tokenid="ooxml:Value_ST_Border_tribal6">tribal6</value>
+ <value tokenid="ooxml:Value_ST_Border_twistedLines1">twistedLines1</value>
+ <value tokenid="ooxml:Value_ST_Border_twistedLines2">twistedLines2</value>
+ <value tokenid="ooxml:Value_ST_Border_vine">vine</value>
+ <value tokenid="ooxml:Value_ST_Border_waveline">waveline</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingAngles">weavingAngles</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingBraid">weavingBraid</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingRibbon">weavingRibbon</value>
+ <value tokenid="ooxml:Value_ST_Border_weavingStrips">weavingStrips</value>
+ <value tokenid="ooxml:Value_ST_Border_whiteFlowers">whiteFlowers</value>
+ <value tokenid="ooxml:Value_ST_Border_woodwork">woodwork</value>
+ <value tokenid="ooxml:Value_ST_Border_xIllusions">xIllusions</value>
+ <value tokenid="ooxml:Value_ST_Border_zanyTriangles">zanyTriangles</value>
+ <value tokenid="ooxml:Value_ST_Border_zigZag">zigZag</value>
+ <value tokenid="ooxml:Value_ST_Border_zigZagStitch">zigZagStitch</value>
+ </resource>
+ <resource name="CT_Border" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Border_val"/>
+ <attribute name="color" tokenid="ooxml:CT_Border_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Border_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Border_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Border_themeShade"/>
+ <attribute name="sz" tokenid="ooxml:CT_Border_sz"/>
+ <attribute name="space" tokenid="ooxml:CT_Border_space"/>
+ <attribute name="shadow" tokenid="ooxml:CT_Border_shadow"/>
+ <attribute name="frame" tokenid="ooxml:CT_Border_frame"/>
+ </resource>
+ <!-- This DOCX values will be mapped to match the 'DOC' values that are defined here: -->
+ <!-- http://msdn.microsoft.com/en-us/library/dd945712(v=office.12).aspx -->
+ <resource name="ST_Shd" resource="List">
+ <value tokenid="ooxml:Value_ST_Shd_clear">clear</value>
+ <value tokenid="ooxml:Value_ST_Shd_solid">solid</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct5">pct5</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct10">pct10</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct20">pct20</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct25">pct25</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct30">pct30</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct40">pct40</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct50">pct50</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct60">pct60</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct70">pct70</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct75">pct75</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct80">pct80</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct90">pct90</value>
+ <value tokenid="ooxml:Value_ST_Shd_horzStripe">horzStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_vertStripe">vertStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_reverseDiagStripe">reverseDiagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_diagStripe">diagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_horzCross">horzCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_diagCross">diagCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinHorzStripe">thinHorzStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinVertStripe">thinVertStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinReverseDiagStripe">thinReverseDiagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinDiagStripe">thinDiagStripe</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinHorzCross">thinHorzCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_thinDiagCross">thinDiagCross</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct12">pct12</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct15">pct15</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct35">pct35</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct37">pct37</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct45">pct45</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct55">pct55</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct62">pct62</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct65">pct65</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct85">pct85</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct87">pct87</value>
+ <value tokenid="ooxml:Value_ST_Shd_pct95">pct95</value>
+ <value tokenid="ooxml:Value_ST_Shd_nil">nil</value>
+ </resource>
+ <resource name="CT_Shd" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Shd_val"/>
+ <attribute name="color" tokenid="ooxml:CT_Shd_color"/>
+ <attribute name="themeColor" tokenid="ooxml:CT_Shd_themeColor"/>
+ <attribute name="themeTint" tokenid="ooxml:CT_Shd_themeTint"/>
+ <attribute name="themeShade" tokenid="ooxml:CT_Shd_themeShade"/>
+ <attribute name="fill" tokenid="ooxml:CT_Shd_fill"/>
+ <attribute name="themeFill" tokenid="ooxml:CT_Shd_themeFill"/>
+ <attribute name="themeFillTint" tokenid="ooxml:CT_Shd_themeFillTint"/>
+ <attribute name="themeFillShade" tokenid="ooxml:CT_Shd_themeFillShade"/>
+ </resource>
+ <resource name="CT_VerticalAlignRun" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_VerticalAlignRun_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FitText" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_FitText_val"/>
+ <attribute name="id" tokenid="ooxml:CT_FitText_id"/>
+ </resource>
+ <resource name="ST_Em" resource="List">
+ <value tokenid="ooxml:Value_ST_Em_none">none</value>
+ <value tokenid="ooxml:Value_ST_Em_dot">dot</value>
+ <value tokenid="ooxml:Value_ST_Em_comma">comma</value>
+ <value tokenid="ooxml:Value_ST_Em_circle">circle</value>
+ <value tokenid="ooxml:Value_ST_Em_underDot">underDot</value>
+ </resource>
+ <resource name="CT_Em" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Em_val" action="setValue"/>
+ </resource>
+ <resource name="CT_Language" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Language_val"/>
+ <attribute name="eastAsia" tokenid="ooxml:CT_Language_eastAsia"/>
+ <attribute name="bidi" tokenid="ooxml:CT_Language_bidi"/>
+ </resource>
+ <resource name="ST_CombineBrackets" resource="List">
+ <value tokenid="ooxml:Value_ST_CombineBrackets_none">none</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_round">round</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_square">square</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_angle">angle</value>
+ <value tokenid="ooxml:Value_ST_CombineBrackets_curly">curly</value>
+ </resource>
+ <resource name="CT_EastAsianLayout" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_EastAsianLayout_id"/>
+ <attribute name="combine" tokenid="ooxml:CT_EastAsianLayout_combine"/>
+ <attribute name="combineBrackets" tokenid="ooxml:CT_EastAsianLayout_combineBrackets"/>
+ <attribute name="vert" tokenid="ooxml:CT_EastAsianLayout_vert"/>
+ <attribute name="vertCompress" tokenid="ooxml:CT_EastAsianLayout_vertCompress"/>
+ </resource>
+ <resource name="ST_XAlign" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_XAlign_left">left</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_center">center</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_right">right</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_inside">inside</value>
+ <value tokenid="ooxml:Value_doc_ST_XAlign_outside">outside</value>
+ </resource>
+ <resource name="ST_YAlign" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_YAlign_inline">inline</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_top">top</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_center">center</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_bottom">bottom</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_inside">inside</value>
+ <value tokenid="ooxml:Value_doc_ST_YAlign_outside">outside</value>
+ </resource>
+ <resource name="ST_HeightRule" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_HeightRule_auto">auto</value>
+ <value tokenid="ooxml:Value_doc_ST_HeightRule_exact">exact</value>
+ <value tokenid="ooxml:Value_doc_ST_HeightRule_atLeast">atLeast</value>
+ </resource>
+ <resource name="ST_Wrap" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_Wrap_auto">auto</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_notBeside">notBeside</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_around">around</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_tight">tight</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_through">through</value>
+ <value tokenid="ooxml:Value_doc_ST_Wrap_none">none</value>
+ </resource>
+ <resource name="ST_VAnchor" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_VAnchor_text">text</value>
+ <value tokenid="ooxml:Value_doc_ST_VAnchor_margin">margin</value>
+ <value tokenid="ooxml:Value_doc_ST_VAnchor_page">page</value>
+ </resource>
+ <resource name="ST_HAnchor" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_HAnchor_text">text</value>
+ <value tokenid="ooxml:Value_doc_ST_HAnchor_margin">margin</value>
+ <value tokenid="ooxml:Value_doc_ST_HAnchor_page">page</value>
+ </resource>
+ <resource name="ST_DropCap" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DropCap_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_DropCap_drop">drop</value>
+ <value tokenid="ooxml:Value_doc_ST_DropCap_margin">margin</value>
+ </resource>
+ <resource name="CT_FramePr" resource="Properties">
+ <attribute name="dropCap" tokenid="ooxml:CT_FramePr_dropCap"/>
+ <attribute name="lines" tokenid="ooxml:CT_FramePr_lines"/>
+ <attribute name="w" tokenid="ooxml:CT_FramePr_w"/>
+ <attribute name="h" tokenid="ooxml:CT_FramePr_h"/>
+ <attribute name="vSpace" tokenid="ooxml:CT_FramePr_vSpace"/>
+ <attribute name="hSpace" tokenid="ooxml:CT_FramePr_hSpace"/>
+ <attribute name="wrap" tokenid="ooxml:CT_FramePr_wrap"/>
+ <attribute name="hAnchor" tokenid="ooxml:CT_FramePr_hAnchor"/>
+ <attribute name="vAnchor" tokenid="ooxml:CT_FramePr_vAnchor"/>
+ <attribute name="x" tokenid="ooxml:CT_FramePr_x"/>
+ <attribute name="xAlign" tokenid="ooxml:CT_FramePr_xAlign"/>
+ <attribute name="y" tokenid="ooxml:CT_FramePr_y"/>
+ <attribute name="yAlign" tokenid="ooxml:CT_FramePr_yAlign"/>
+ <attribute name="hRule" tokenid="ooxml:CT_FramePr_hRule"/>
+ <attribute name="anchorLock" tokenid="ooxml:CT_FramePr_anchorLock"/>
+ </resource>
+ <resource name="ST_TabJc" resource="List">
+ <value tokenid="ooxml:Value_ST_TabJc_clear">clear</value>
+ <value tokenid="ooxml:Value_ST_TabJc_start">start</value>
+ <value tokenid="ooxml:Value_ST_TabJc_left">left</value>
+ <value tokenid="ooxml:Value_ST_TabJc_center">center</value>
+ <value tokenid="ooxml:Value_ST_TabJc_end">end</value>
+ <value tokenid="ooxml:Value_ST_TabJc_right">right</value>
+ <value tokenid="ooxml:Value_ST_TabJc_decimal">decimal</value>
+ <value tokenid="ooxml:Value_ST_TabJc_bar">bar</value>
+ <value tokenid="ooxml:Value_ST_TabJc_num">num</value>
+ </resource>
+ <resource name="ST_TabTlc" resource="List">
+ <value tokenid="ooxml:Value_ST_TabTlc_none">none</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_dot">dot</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_hyphen">hyphen</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_underscore">underscore</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_heavy">heavy</value>
+ <value tokenid="ooxml:Value_ST_TabTlc_middleDot">middleDot</value>
+ </resource>
+ <resource name="CT_TabStop" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_TabStop_val"/>
+ <attribute name="leader" tokenid="ooxml:CT_TabStop_leader"/>
+ <attribute name="pos" tokenid="ooxml:CT_TabStop_pos"/>
+ </resource>
+ <resource name="ST_LineSpacingRule" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_LineSpacingRule_auto">auto</value>
+ <value tokenid="ooxml:Value_doc_ST_LineSpacingRule_exact">exact</value>
+ <value tokenid="ooxml:Value_doc_ST_LineSpacingRule_atLeast">atLeast</value>
+ </resource>
+ <resource name="CT_Spacing" resource="Properties">
+ <attribute name="before" tokenid="ooxml:CT_Spacing_before"/>
+ <attribute name="beforeLines" tokenid="ooxml:CT_Spacing_beforeLines"/>
+ <attribute name="beforeAutospacing" tokenid="ooxml:CT_Spacing_beforeAutospacing"/>
+ <attribute name="after" tokenid="ooxml:CT_Spacing_after"/>
+ <attribute name="afterLines" tokenid="ooxml:CT_Spacing_afterLines"/>
+ <attribute name="afterAutospacing" tokenid="ooxml:CT_Spacing_afterAutospacing"/>
+ <attribute name="line" tokenid="ooxml:CT_Spacing_line"/>
+ <attribute name="lineRule" tokenid="ooxml:CT_Spacing_lineRule"/>
+ </resource>
+ <resource name="CT_Ind" resource="Properties">
+ <attribute name="end" tokenid="ooxml:CT_Ind_end"/>
+ <attribute name="endChars" tokenid="ooxml:CT_Ind_endChars"/>
+ <attribute name="start" tokenid="ooxml:CT_Ind_start"/>
+ <attribute name="startChars" tokenid="ooxml:CT_Ind_startChars"/>
+ <attribute name="hanging" tokenid="ooxml:CT_Ind_hanging"/>
+ <attribute name="hangingChars" tokenid="ooxml:CT_Ind_hangingChars"/>
+ <attribute name="firstLine" tokenid="ooxml:CT_Ind_firstLine"/>
+ <attribute name="firstLineChars" tokenid="ooxml:CT_Ind_firstLineChars"/>
+ <!-- ECMA 1st version -->
+ <attribute name="left" tokenid="ooxml:CT_Ind_left"/>
+ <attribute name="leftChars" tokenid="ooxml:CT_Ind_leftChars"/>
+ <attribute name="right" tokenid="ooxml:CT_Ind_right"/>
+ <attribute name="rightChars" tokenid="ooxml:CT_Ind_rightChars"/>
+ </resource>
+ <resource name="ST_Jc" resource="List">
+ <value tokenid="ooxml:Value_ST_Jc_left">left</value>
+ <value tokenid="ooxml:Value_ST_Jc_right">right</value>
+ <value tokenid="ooxml:Value_ST_Jc_start">start</value>
+ <value tokenid="ooxml:Value_ST_Jc_center">center</value>
+ <value tokenid="ooxml:Value_ST_Jc_end">end</value>
+ <value tokenid="ooxml:Value_ST_Jc_both">both</value>
+ <value tokenid="ooxml:Value_ST_Jc_mediumKashida">mediumKashida</value>
+ <value tokenid="ooxml:Value_ST_Jc_distribute">distribute</value>
+ <value tokenid="ooxml:Value_ST_Jc_numTab">numTab</value>
+ <value tokenid="ooxml:Value_ST_Jc_highKashida">highKashida</value>
+ <value tokenid="ooxml:Value_ST_Jc_lowKashida">lowKashida</value>
+ <value tokenid="ooxml:Value_ST_Jc_thaiDistribute">thaiDistribute</value>
+ </resource>
+ <resource name="CT_Jc" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Jc_val" action="setValue"/>
+ </resource>
+ <resource name="ST_View" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_View_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_View_print">print</value>
+ <value tokenid="ooxml:Value_doc_ST_View_outline">outline</value>
+ <value tokenid="ooxml:Value_doc_ST_View_masterPages">masterPages</value>
+ <value tokenid="ooxml:Value_doc_ST_View_normal">normal</value>
+ <value tokenid="ooxml:Value_doc_ST_View_web">web</value>
+ </resource>
+ <resource name="CT_View" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_View_val"/>
+ </resource>
+ <resource name="ST_Zoom" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_Zoom_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_Zoom_fullPage">fullPage</value>
+ <value tokenid="ooxml:Value_doc_ST_Zoom_bestFit">bestFit</value>
+ <value tokenid="ooxml:Value_doc_ST_Zoom_textFit">textFit</value>
+ </resource>
+ <resource name="ST_Percentage" resource="Integer"/>
+ <resource name="CT_Zoom" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Zoom_val"/>
+ <attribute name="percent" tokenid="ooxml:CT_Zoom_percent"/>
+ </resource>
+ <resource name="CT_WritingStyle" resource="Properties">
+ <attribute name="lang" tokenid="ooxml:CT_WritingStyle_lang"/>
+ <attribute name="vendorID" tokenid="ooxml:CT_WritingStyle_vendorID"/>
+ <attribute name="dllVersion" tokenid="ooxml:CT_WritingStyle_dllVersion"/>
+ <attribute name="nlCheck" tokenid="ooxml:CT_WritingStyle_nlCheck"/>
+ <attribute name="checkStyle" tokenid="ooxml:CT_WritingStyle_checkStyle"/>
+ <attribute name="appName" tokenid="ooxml:CT_WritingStyle_appName"/>
+ </resource>
+ <resource name="CT_Proof" resource="Properties">
+ <attribute name="spelling" tokenid="ooxml:CT_Proof_spelling"/>
+ <attribute name="grammar" tokenid="ooxml:CT_Proof_grammar"/>
+ </resource>
+ <resource name="ST_DocType" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DocType_notSpecified">notSpecified</value>
+ <value tokenid="ooxml:Value_doc_ST_DocType_letter">letter</value>
+ <value tokenid="ooxml:Value_doc_ST_DocType_eMail">eMail</value>
+ </resource>
+ <resource name="CT_DocType" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_DocType_val"/>
+ </resource>
+ <resource name="ST_DocProtect" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_none">none</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_readOnly">readOnly</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_comments">comments</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_trackedChanges">trackedChanges</value>
+ <value tokenid="ooxml:Value_doc_ST_DocProtect_forms">forms</value>
+ </resource>
+ <resource name="ST_CryptProv" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_CryptProv_rsaAES">rsaAES</value>
+ <value tokenid="ooxml:Value_doc_ST_CryptProv_rsaFull">rsaFull</value>
+ </resource>
+ <resource name="ST_AlgClass" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_AlgClass_hash">hash</value>
+ </resource>
+ <resource name="ST_AlgType" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_AlgType_typeAny">typeAny</value>
+ </resource>
+ <resource name="AG_Password" resource="Properties">
+ <attribute name="cryptProviderType" tokenid="ooxml:AG_Password_cryptProviderType"/>
+ <attribute name="cryptAlgorithmClass" tokenid="ooxml:AG_Password_cryptAlgorithmClass"/>
+ <attribute name="cryptAlgorithmType" tokenid="ooxml:AG_Password_cryptAlgorithmType"/>
+ <attribute name="cryptAlgorithmSid" tokenid="ooxml:AG_Password_cryptAlgorithmSid"/>
+ <attribute name="cryptSpinCount" tokenid="ooxml:AG_Password_cryptSpinCount"/>
+ <attribute name="cryptProvider" tokenid="ooxml:AG_Password_cryptProvider"/>
+ <attribute name="algIdExt" tokenid="ooxml:AG_Password_algIdExt"/>
+ <attribute name="algIdExtSource" tokenid="ooxml:AG_Password_algIdExtSource"/>
+ <attribute name="cryptProviderTypeExt" tokenid="ooxml:AG_Password_cryptProviderTypeExt"/>
+ <attribute name="cryptProviderTypeExtSource" tokenid="ooxml:AG_Password_cryptProviderTypeExtSource"/>
+ <attribute name="hash" tokenid="ooxml:AG_Password_hash"/>
+ <attribute name="salt" tokenid="ooxml:AG_Password_salt"/>
+ </resource>
+ <resource name="CT_DocProtect" resource="Properties">
+ <attribute name="edit" tokenid="ooxml:CT_DocProtect_edit"/>
+ <attribute name="formatting" tokenid="ooxml:CT_DocProtect_formatting"/>
+ <attribute name="enforcement" tokenid="ooxml:CT_DocProtect_enforcement"/>
+ </resource>
+ <resource name="CT_MailMergeDocType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeDocType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMergeDataType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeDataType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMergeDest" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeDest_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMergeOdsoFMDFieldType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeOdsoFMDFieldType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_TrackChangesView" resource="Properties">
+ <attribute name="markup" tokenid="ooxml:CT_TrackChangesView_markup"/>
+ <attribute name="comments" tokenid="ooxml:CT_TrackChangesView_comments"/>
+ <attribute name="insDel" tokenid="ooxml:CT_TrackChangesView_insDel"/>
+ <attribute name="formatting" tokenid="ooxml:CT_TrackChangesView_formatting"/>
+ <attribute name="inkAnnotations" tokenid="ooxml:CT_TrackChangesView_inkAnnotations"/>
+ </resource>
+ <resource name="CT_Kinsoku" resource="Properties">
+ <attribute name="lang" tokenid="ooxml:CT_Kinsoku_lang"/>
+ <attribute name="val" tokenid="ooxml:CT_Kinsoku_val"/>
+ </resource>
+ <resource name="ST_TextDirection" resource="List">
+ <value tokenid="ooxml:Value_ST_TextDirection_lrTb">lrTb</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_tbRl">tbRl</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_btLr">btLr</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_lrTbV">lrTbV</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_tbRlV">tbRlV</value>
+ <value tokenid="ooxml:Value_ST_TextDirection_tbLrV">tbLrV</value>
+ </resource>
+ <resource name="CT_TextDirection" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextDirection_val" action="setValue"/>
+ </resource>
+ <resource name="ST_TextAlignment" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_top">top</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_center">center</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_baseline">baseline</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_bottom">bottom</value>
+ <value tokenid="ooxml:Value_doc_ST_TextAlignment_auto">auto</value>
+ </resource>
+ <resource name="CT_TextAlignment" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextAlignment_val" action="setValue"/>
+ </resource>
+ <resource name="ST_DisplacedByCustomXml" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_DisplacedByCustomXml_next">next</value>
+ <value tokenid="ooxml:Value_doc_ST_DisplacedByCustomXml_prev">prev</value>
+ </resource>
+ <resource name="ST_AnnotationVMerge" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_AnnotationVMerge_cont">cont</value>
+ <value tokenid="ooxml:Value_doc_ST_AnnotationVMerge_rest">rest</value>
+ </resource>
+ <resource name="CT_Markup" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_Markup_id"/>
+ </resource>
+ <resource name="CT_TrackChange" resource="Properties">
+ <attribute name="author" tokenid="ooxml:CT_TrackChange_author"/>
+ <attribute name="date" tokenid="ooxml:CT_TrackChange_date"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart" action="clearProps"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd" action="clearProps"/>
+ </resource>
+ <resource name="CT_CellMergeTrackChange" resource="Properties">
+ <attribute name="vMerge" tokenid="ooxml:CT_CellMergeTrackChange_vMerge"/>
+ <attribute name="vMergeOrig" tokenid="ooxml:CT_CellMergeTrackChange_vMergeOrig"/>
+ </resource>
+ <resource name="CT_TrackChangeRange" resource="Properties">
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_TrackChangeRange_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_MarkupRange" resource="Properties">
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_MarkupRange_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_MarkupRangeBookmark" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_MarkupRangeBookmark_id"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd"/>
+ </resource>
+ <resource name="CT_PermStart" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_PermStart_id"/>
+ <attribute name="colFirst" tokenid="ooxml:CT_PermStart_colFirst"/>
+ <attribute name="colLast" tokenid="ooxml:CT_PermStart_colLast"/>
+ <attribute name="ed" tokenid="ooxml:CT_PermStart_ed"/>
+ <attribute name="edGrp" tokenid="ooxml:CT_PermStart_edGrp"/>
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermStart_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_PermEnd" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_PermEnd_id"/>
+ <attribute name="displacedByCustomXml" tokenid="ooxml:CT_PermEnd_displacedByCustomXml"/>
+ </resource>
+ <resource name="CT_MarkupRangeCommentStart" resource="Properties">
+ <attribute name="id" tokenid="ooxml:EG_RangeMarkupElements_commentRangeStart"/>
+ </resource>
+ <resource name="CT_MarkupRangeCommentEnd" resource="Properties">
+ <attribute name="id" tokenid="ooxml:EG_RangeMarkupElements_commentRangeEnd"/>
+ </resource>
+ <resource name="CT_BookmarkRange" resource="Properties">
+ <attribute name="colFirst" tokenid="ooxml:CT_BookmarkRange_colFirst"/>
+ <attribute name="colLast" tokenid="ooxml:CT_BookmarkRange_colLast"/>
+ </resource>
+ <resource name="CT_Bookmark" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_Bookmark_name"/>
+ </resource>
+ <resource name="CT_MoveBookmark" resource="Properties">
+ <attribute name="author" tokenid="ooxml:CT_MoveBookmark_author"/>
+ <attribute name="date" tokenid="ooxml:CT_MoveBookmark_date"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/>
+ <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/>
+ </resource>
+ <resource name="CT_Comment" resource="XNote">
+ <attribute name="id" action="checkId"/>
+ <attribute name="initials" tokenid="ooxml:CT_Comment_initials"/>
+ </resource>
+ <resource name="CT_TrackChangeNumbering" resource="Properties">
+ <attribute name="original" tokenid="ooxml:CT_TrackChangeNumbering_original"/>
+ </resource>
+ <resource name="CT_TblPrExChange" resource="Properties">
+ <element name="tblPrEx" tokenid="ooxml:CT_TblPrExChange_tblPrEx"/>
+ </resource>
+ <resource name="CT_TcPrChange" resource="Properties">
+ <element name="tcPr" tokenid="ooxml:CT_TcPrChange_tcPr"/>
+ </resource>
+ <resource name="CT_TrPrChange" resource="Properties">
+ <element name="trPr" tokenid="ooxml:CT_TrPrChange_trPr"/>
+ </resource>
+ <resource name="CT_TblGridChange" resource="Properties">
+ <element name="tblGrid" tokenid="ooxml:CT_TblGridChange_tblGrid"/>
+ </resource>
+ <resource name="CT_TblPrChange" resource="Properties">
+ <element name="tblPr" tokenid="ooxml:CT_TblPrChange_tblPr"/>
+ </resource>
+ <resource name="CT_SectPrChange" resource="Properties">
+ <element name="sectPr" tokenid="ooxml:CT_SectPrChange_sectPr"/>
+ </resource>
+ <resource name="CT_PPrChange" resource="Properties">
+ <element name="pPr" tokenid="ooxml:CT_PPrChange_pPr"/>
+ </resource>
+ <resource name="CT_RPrChange" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_RPrChange_rPr"/>
+ </resource>
+ <resource name="CT_ParaRPrChange" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_ParaRPrChange_rPr"/>
+ </resource>
+ <resource name="CT_RunTrackChange" resource="Stream">
+ <action name="start" action="tokenproperty"/>
+ <action name="start" action="sendPropertiesWithId" sendtokenid="ooxml:trackchange"/>
+ <action name="start" action="clearProps"/>
+ <action name="end" action="tokenproperty"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:endtrackchange"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="EG_RangeMarkupElements" resource="Properties">
+ <element name="bookmarkStart" tokenid="ooxml:EG_RangeMarkupElements_bookmarkStart"/>
+ <element name="bookmarkEnd" tokenid="ooxml:EG_RangeMarkupElements_bookmarkEnd"/>
+ <element name="permStart" tokenid="ooxml:EG_RangeMarkupElements_PermStart"/>
+ <element name="permEnd" tokenid="ooxml:EG_RangeMarkupElements_PermEnd"/>
+ <element name="moveFromRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/>
+ <element name="moveFromRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/>
+ <element name="moveToRangeStart" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/>
+ <element name="moveToRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd"/>
+ <element name="commentRangeStart" tokenid="ooxml:EG_RangeMarkupElements_commentRangeStart"/>
+ <element name="commentRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_commentRangeEnd"/>
+ <element name="customXmlInsRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeStart"/>
+ <element name="customXmlInsRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlInsRangeEnd"/>
+ <element name="customXmlDelRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeStart"/>
+ <element name="customXmlDelRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlDelRangeEnd"/>
+ <element name="customXmlMoveFromRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeStart"/>
+ <element name="customXmlMoveFromRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveFromRangeEnd"/>
+ <element name="customXmlMoveToRangeStart" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeStart"/>
+ <element name="customXmlMoveToRangeEnd" tokenid="ooxml:EG_RangeMarkupElements_customXmlMoveToRangeEnd"/>
+ </resource>
+ <resource name="CT_NumPr" resource="Properties">
+ <element name="ilvl" tokenid="ooxml:CT_NumPr_ilvl"/>
+ <element name="numId" tokenid="ooxml:CT_NumPr_numId"/>
+ <element name="numberingChange" tokenid="ooxml:CT_NumPr_numberingChange"/>
+ <element name="ins" tokenid="ooxml:CT_NumPr_ins"/>
+ </resource>
+ <resource name="CT_PBdr" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_PBdr_top"/>
+ <element name="left" tokenid="ooxml:CT_PBdr_left"/>
+ <element name="bottom" tokenid="ooxml:CT_PBdr_bottom"/>
+ <element name="right" tokenid="ooxml:CT_PBdr_right"/>
+ <element name="between" tokenid="ooxml:CT_PBdr_between"/>
+ <element name="bar" tokenid="ooxml:CT_PBdr_bar"/>
+ </resource>
+ <resource name="CT_Tabs" resource="Properties">
+ <element name="tab" tokenid="ooxml:CT_Tabs_tab"/>
+ </resource>
+ <resource name="CT_TextboxTightWrap" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TextboxTightWrap_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_PPrBase" resource="Properties">
+ <element name="pStyle" tokenid="ooxml:CT_PPrBase_pStyle"/>
+ <element name="keepNext" tokenid="ooxml:CT_PPrBase_keepNext"/>
+ <element name="keepLines" tokenid="ooxml:CT_PPrBase_keepLines"/>
+ <element name="pageBreakBefore" tokenid="ooxml:CT_PPrBase_pageBreakBefore"/>
+ <element name="framePr" tokenid="ooxml:CT_PPrBase_framePr"/>
+ <element name="widowControl" tokenid="ooxml:CT_PPrBase_widowControl"/>
+ <element name="numPr" tokenid="ooxml:CT_PPrBase_numPr"/>
+ <element name="suppressLineNumbers" tokenid="ooxml:CT_PPrBase_suppressLineNumbers"/>
+ <element name="pBdr" tokenid="ooxml:CT_PrBase_pBdr"/>
+ <element name="shd" tokenid="ooxml:CT_PrBase_shd"/>
+ <element name="tabs" tokenid="ooxml:CT_PPrBase_tabs"/>
+ <element name="suppressAutoHyphens" tokenid="ooxml:CT_PPrBase_suppressAutoHyphens"/>
+ <element name="kinsoku" tokenid="ooxml:CT_PPrBase_kinsoku"/>
+ <element name="wordWrap" tokenid="ooxml:CT_PPrBase_wordWrap"/>
+ <element name="overflowPunct" tokenid="ooxml:CT_PPrBase_overflowPunct"/>
+ <element name="topLinePunct" tokenid="ooxml:CT_PPrBase_topLinePunct"/>
+ <element name="autoSpaceDE" tokenid="ooxml:CT_PPrBase_autoSpaceDE"/>
+ <element name="autoSpaceDN" tokenid="ooxml:CT_PPrBase_autoSpaceDN"/>
+ <element name="bidi" tokenid="ooxml:CT_PPrBase_bidi"/>
+ <element name="adjustRightInd" tokenid="ooxml:CT_PPrBase_adjustRightInd"/>
+ <element name="snapToGrid" tokenid="ooxml:CT_PPrBase_snapToGrid"/>
+ <element name="spacing" tokenid="ooxml:CT_PPrBase_spacing"/>
+ <element name="ind" tokenid="ooxml:CT_PPrBase_ind"/>
+ <element name="contextualSpacing" tokenid="ooxml:CT_PPrBase_contextualSpacing"/>
+ <element name="mirrorIndents" tokenid="ooxml:CT_PPrBase_mirrorIndents"/>
+ <element name="suppressOverlap" tokenid="ooxml:CT_PPrBase_suppressOverlap"/>
+ <element name="jc" tokenid="ooxml:CT_PPrBase_jc"/>
+ <element name="textDirection" tokenid="ooxml:CT_PPrBase_textDirection"/>
+ <element name="textAlignment" tokenid="ooxml:CT_PPrBase_textAlignment"/>
+ <element name="textboxTightWrap" tokenid="ooxml:CT_PPrBase_textboxTightWrap"/>
+ <element name="outlineLvl" tokenid="ooxml:CT_PPrBase_outlineLvl"/>
+ <element name="divId" tokenid="ooxml:CT_PPrBase_divId"/>
+ <element name="cnfStyle" tokenid="ooxml:CT_PPrBase_cnfStyle"/>
+ </resource>
+ <resource name="CT_PPr" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_PPr_rPr"/>
+ <element name="sectPr" tokenid="ooxml:CT_PPr_sectPr"/>
+ <element name="pPrChange" tokenid="ooxml:CT_PPr_pPrChange"/>
+ </resource>
+ <resource name="CT_Background" resource="Shape">
+ <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"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:background_background"/>
+ </resource>
+ <resource name="CT_Rel" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_Rel_id"/>
+ </resource>
+ <resource name="CT_PictureBase" resource="Properties"/>
+ <resource name="CT_Object" resource="Shape">
+ <attribute name="dxaOrig" tokenid="ooxml:CT_Object_dxaOrig"/>
+ <attribute name="dyaOrig" tokenid="ooxml:CT_Object_dyaOrig"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:object"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_Picture" resource="Shape">
+ <element name="movie" tokenid="ooxml:CT_Picture_movie"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:object"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_Drawing" resource="Properties">
+ <action name="end" action="handlePicture"/>
+ </resource>
+ <resource name="CT_SimpleField" resource="Stream">
+ <element name="fldData" tokenid="ooxml:CT_SimpleField_fldData"/>
+ <attribute name="instr" tokenid="ooxml:CT_SimpleField_instr"/>
+ <attribute name="fldLock" tokenid="ooxml:CT_SimpleField_fldLock"/>
+ <attribute name="dirty" tokenid="ooxml:CT_SimpleField_dirty"/>
+ <action name="start" action="fieldstart"/>
+ <action name="start" action="startCharacterGroup"/>
+ <action name="start" action="printproperty" sendtokenid="ooxml:CT_SimpleField_instr"/>
+ <action name="start" action="endCharacterGroup"/>
+ <action name="start" action="fieldlock_simple"/>
+ <action name="start" action="fieldsep"/>
+ <action name="end" action="fieldend"/>
+ </resource>
+ <resource name="ST_FldCharType" resource="List">
+ <value tokenid="ooxml:Value_ST_FldCharType_begin">begin</value>
+ <value tokenid="ooxml:Value_ST_FldCharType_separate">separate</value>
+ <value tokenid="ooxml:Value_ST_FldCharType_end">end</value>
+ </resource>
+ <resource name="ST_InfoTextType" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_InfoTextType_text">text</value>
+ <value tokenid="ooxml:Value_doc_ST_InfoTextType_autoText">autoText</value>
+ </resource>
+ <resource name="ST_FFName" resource="String"/>
+ <resource name="CT_FFTextType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FFTextType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FFName" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FFName_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FldChar" resource="Stream">
+ <element name="fldData" tokenid="ooxml:CT_FldChar_fldData"/>
+ <element name="ffData" tokenid="ooxml:CT_FldChar_ffData"/>
+ <element name="numberingChange" tokenid="ooxml:CT_FldChar_numberingChange"/>
+ <attribute name="fldCharType" tokenid="ooxml:CT_FldChar_fldCharType"/>
+ <attribute name="fldLock" tokenid="ooxml:CT_FldChar_fldLock"/>
+ <attribute name="dirty" tokenid="ooxml:CT_FldChar_dirty"/>
+ <action name="start" action="fieldstart">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_begin"/>
+ </action>
+ <action name="start" action="fieldsep">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_separate"/>
+ </action>
+ <action name="start" action="fieldend">
+ <cond tokenid="ooxml:CT_FldChar_fldCharType" value="ooxml:Value_ST_FldCharType_end"/>
+ </action>
+ <action name="start" action="fieldlock"/>
+ </resource>
+ <resource name="CT_Hyperlink" resource="Stream">
+ <attribute name="tgtFrame" tokenid="ooxml:CT_Hyperlink_tgtFrame"/>
+ <attribute name="tooltip" tokenid="ooxml:CT_Hyperlink_tooltip"/>
+ <attribute name="docLocation" tokenid="ooxml:CT_Hyperlink_docLocation"/>
+ <attribute name="history" tokenid="ooxml:CT_Hyperlink_history"/>
+ <attribute name="anchor" tokenid="ooxml:CT_Hyperlink_anchor"/>
+ <attribute name="r:id" tokenid="ooxml:CT_Hyperlink_r_id"/>
+ <action name="start" action="fieldstart"/>
+ <action name="start" action="handleHyperlink"/>
+ <action name="start" action="fieldsep"/>
+ <action name="end" action="fieldend"/>
+ </resource>
+ <resource name="CT_FLDData" resource="Stream">
+ <action name="characters" action="ignore"/>
+ </resource>
+ <resource name="CT_FFData" resource="Properties">
+ <element name="name" tokenid="ooxml:CT_FFData_name"/>
+ <element name="enabled" tokenid="ooxml:CT_FFData_enabled"/>
+ <element name="calcOnExit" tokenid="ooxml:CT_FFData_calcOnExit"/>
+ <element name="entryMacro" tokenid="ooxml:CT_FFData_entryMacro"/>
+ <element name="exitMacro" tokenid="ooxml:CT_FFData_exitMacro"/>
+ <element name="helpText" tokenid="ooxml:CT_FFData_helpText"/>
+ <element name="statusText" tokenid="ooxml:CT_FFData_statusText"/>
+ <element name="checkBox" tokenid="ooxml:CT_FFData_checkBox"/>
+ <element name="ddList" tokenid="ooxml:CT_FFData_ddList"/>
+ <element name="textInput" tokenid="ooxml:CT_FFData_textInput"/>
+ <action name="end" action="sendPropertiesWithId" sendtokenid="ooxml:ffdata"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_FFHelpText" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_FFHelpText_type"/>
+ <attribute name="val" tokenid="ooxml:CT_FFHelpText_val"/>
+ </resource>
+ <resource name="CT_FFStatusText" resource="Properties">
+ <attribute name="type" tokenid="ooxml:CT_FFStatusText_type"/>
+ <attribute name="val" tokenid="ooxml:CT_FFStatusText_val"/>
+ </resource>
+ <resource name="CT_FFCheckBox" resource="Properties">
+ <element name="size" tokenid="ooxml:CT_FFCheckBox_size"/>
+ <element name="sizeAuto" tokenid="ooxml:CT_FFCheckBox_sizeAuto"/>
+ <element name="default" tokenid="ooxml:CT_FFCheckBox_default"/>
+ <element name="checked" tokenid="ooxml:CT_FFCheckBox_checked"/>
+ </resource>
+ <resource name="CT_FFDDList" resource="Properties">
+ <element name="result" tokenid="ooxml:CT_FFDDList_result"/>
+ <element name="default" tokenid="ooxml:CT_FFDDList_default"/>
+ <element name="listEntry" tokenid="ooxml:CT_FFDDList_listEntry"/>
+ </resource>
+ <resource name="CT_FFTextInput" resource="Properties">
+ <element name="type" tokenid="ooxml:CT_FFTextInput_type"/>
+ <element name="default" tokenid="ooxml:CT_FFTextInput_default"/>
+ <element name="maxLength" tokenid="ooxml:CT_FFTextInput_maxLength"/>
+ <element name="format" tokenid="ooxml:CT_FFTextInput_format"/>
+ </resource>
+ <resource name="ST_SectionMark" resource="List">
+ <value tokenid="ooxml:Value_ST_SectionMark_continuous">continuous</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_nextColumn">nextColumn</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_nextPage">nextPage</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_evenPage">evenPage</value>
+ <value tokenid="ooxml:Value_ST_SectionMark_oddPage">oddPage</value>
+ </resource>
+ <resource name="CT_SectType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SectType_val" action="setValue"/>
+ </resource>
+ <resource name="ST_NumberFormat" resource="List">
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimal">decimal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_upperRoman">upperRoman</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_lowerRoman">lowerRoman</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_upperLetter">upperLetter</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_lowerLetter">lowerLetter</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ordinal">ordinal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_cardinalText">cardinalText</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ordinalText">ordinalText</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hex">hex</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chicago">chicago</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographDigital">ideographDigital</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_japaneseCounting">japaneseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_aiueo">aiueo</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_iroha">iroha</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalFullWidth">decimalFullWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalHalfWidth">decimalHalfWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_japaneseLegal">japaneseLegal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_japaneseDigitalTenThousand">japaneseDigitalTenThousand</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedCircle">decimalEnclosedCircle</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalFullWidth2">decimalFullWidth2</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_aiueoFullWidth">aiueoFullWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_irohaFullWidth">irohaFullWidth</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalZero">decimalZero</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_bullet">bullet</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ganada">ganada</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chosung">chosung</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedFullstop">decimalEnclosedFullstop</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedParen">decimalEnclosedParen</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_decimalEnclosedCircleChinese">decimalEnclosedCircleChinese</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographEnclosedCircle">ideographEnclosedCircle</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographTraditional">ideographTraditional</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographZodiac">ideographZodiac</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographZodiacTraditional">ideographZodiacTraditional</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_taiwaneseCounting">taiwaneseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_ideographLegalTraditional">ideographLegalTraditional</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_taiwaneseCountingThousand">taiwaneseCountingThousand</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_taiwaneseDigital">taiwaneseDigital</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chineseCounting">chineseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chineseLegalSimplified">chineseLegalSimplified</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_chineseCountingThousand">chineseCountingThousand</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanDigital">koreanDigital</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanCounting">koreanCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanLegal">koreanLegal</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_koreanDigital2">koreanDigital2</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_vietnameseCounting">vietnameseCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_russianLower">russianLower</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_russianUpper">russianUpper</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_none">none</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_numberInDash">numberInDash</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hebrew1">hebrew1</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hebrew2">hebrew2</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_arabicAlpha">arabicAlpha</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_arabicAbjad">arabicAbjad</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiVowels">hindiVowels</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiConsonants">hindiConsonants</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiNumbers">hindiNumbers</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_hindiCounting">hindiCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_thaiLetters">thaiLetters</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_thaiNumbers">thaiNumbers</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_thaiCounting">thaiCounting</value>
+ <value tokenid="ooxml:Value_ST_NumberFormat_custom">custom</value>
+ </resource>
+ <resource name="ST_PageOrientation" resource="List">
+ <value tokenid="ooxml:Value_ST_PageOrientation_portrait">portrait</value>
+ <value tokenid="ooxml:Value_ST_PageOrientation_landscape">landscape</value>
+ </resource>
+ <resource name="CT_PageSz" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_PageSz_w"/>
+ <attribute name="h" tokenid="ooxml:CT_PageSz_h"/>
+ <attribute name="orient" tokenid="ooxml:CT_PageSz_orient"/>
+ <attribute name="code" tokenid="ooxml:CT_PageSz_code"/>
+ </resource>
+ <resource name="CT_PageMar" resource="Properties">
+ <attribute name="top" tokenid="ooxml:CT_PageMar_top"/>
+ <attribute name="right" tokenid="ooxml:CT_PageMar_right"/>
+ <attribute name="bottom" tokenid="ooxml:CT_PageMar_bottom"/>
+ <attribute name="left" tokenid="ooxml:CT_PageMar_left"/>
+ <attribute name="header" tokenid="ooxml:CT_PageMar_header"/>
+ <attribute name="footer" tokenid="ooxml:CT_PageMar_footer"/>
+ <attribute name="gutter" tokenid="ooxml:CT_PageMar_gutter"/>
+ </resource>
+ <resource name="CT_PaperSource" resource="Properties">
+ <attribute name="first" tokenid="ooxml:CT_PaperSource_first"/>
+ <attribute name="other" tokenid="ooxml:CT_PaperSource_other"/>
+ </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_instrText" resource="Stream">
+ <attribute name="xml:space" tokenid="ooxml:CT_Text_space"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RunInnerContent_instrText" sendtokenid="ooxml:EG_RunInnerContent_instrText"/>
+ <action name="characters" action="text"/>
+ </resource>
+ <resource name="CT_delText" resource="Stream">
+ <attribute name="xml:space" tokenid="ooxml:CT_Text_space"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RunInnerContent_delText" sendtokenid="ooxml:EG_RunInnerContent_delText"/>
+ <action name="characters" action="text"/>
+ </resource>
+ <resource name="CT_delInstrText" resource="Stream">
+ <attribute name="xml:space" tokenid="ooxml:CT_Text_space"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RunInnerContent_delInstrText" sendtokenid="ooxml:EG_RunInnerContent_delInstrText"/>
+ <action name="characters" action="text"/>
+ </resource>
+ <resource name="CT_FtnEdnRefChar" resource="Stream">
+ <action name="end" action="ftnednref"/>
+ </resource>
+ <resource name="CT_FtnEdnSep" resource="Stream">
+ <action name="end" action="ftnednsep"/>
+ </resource>
+ <resource name="CT_FtnEdnCont" resource="Stream">
+ <action name="end" action="ftnedncont"/>
+ </resource>
+ <resource name="CT_PgNum" resource="Stream">
+ <action name="end" action="pgNum"/>
+ </resource>
+ <resource name="CT_Cr" resource="Properties">
+ <action name="end" action="handleBreak"/>
+ </resource>
+ <resource name="CT_Tab" resource="Stream">
+ <action name="end" action="tab"/>
+ </resource>
+ <resource name="EG_RunInnerContent" resource="Stream">
+ <element name="br" tokenid="ooxml:EG_RunInnerContent_br"/>
+ <element name="t" tokenid="ooxml:EG_RunInnerContent_t"/>
+ <element name="delText" tokenid="ooxml:EG_RunInnerContent_delText"/>
+ <element name="instrText" tokenid="ooxml:EG_RunInnerContent_instrText"/>
+ <element name="delInstrText" tokenid="ooxml:EG_RunInnerContent_delInstrText"/>
+ <element name="noBreakHyphen" tokenid="ooxml:EG_RunInnerContent_noBreakHyphen"/>
+ <element name="softHyphen" tokenid="ooxml:EG_RunInnerContent_softHyphen"/>
+ <element name="dayShort" tokenid="ooxml:EG_RunInnerContent_dayShort"/>
+ <element name="monthShort" tokenid="ooxml:EG_RunInnerContent_monthShort"/>
+ <element name="yearShort" tokenid="ooxml:EG_RunInnerContent_yearShort"/>
+ <element name="dayLong" tokenid="ooxml:EG_RunInnerContent_dayLong"/>
+ <element name="monthLong" tokenid="ooxml:EG_RunInnerContent_monthLong"/>
+ <element name="yearLong" tokenid="ooxml:EG_RunInnerContent_yearLong"/>
+ <element name="annotationRef" tokenid="ooxml:EG_RunInnerContent_annotationRef"/>
+ <element name="footnoteRef" tokenid="ooxml:EG_RunInnerContent_footnoteRef"/>
+ <element name="endnoteRef" tokenid="ooxml:EG_RunInnerContent_endnoteRef"/>
+ <element name="separator" tokenid="ooxml:EG_RunInnerContent_separator"/>
+ <element name="continuationSeparator" tokenid="ooxml:EG_RunInnerContent_continuationSeparator"/>
+ <element name="sym" tokenid="ooxml:EG_RunInnerContent_sym"/>
+ <element name="pgNum" tokenid="ooxml:EG_RunInnerContent_pgNum"/>
+ <element name="cr" tokenid="ooxml:EG_RunInnerContent_cr"/>
+ <element name="tab" tokenid="ooxml:EG_RunInnerContent_tab"/>
+ <element name="object" tokenid="ooxml:EG_RunInnerContent_object"/>
+ <element name="pict" tokenid="ooxml:EG_RunInnerContent_pict"/>
+ <element name="fldChar" tokenid="ooxml:EG_RunInnerContent_fldChar"/>
+ <element name="ruby" tokenid="ooxml:EG_RunInnerContent_ruby"/>
+ <element name="footnoteReference" tokenid="ooxml:EG_RunInnerContent_footnoteReference"/>
+ <element name="endnoteReference" tokenid="ooxml:EG_RunInnerContent_endnoteReference"/>
+ <element name="commentReference" tokenid="ooxml:EG_RunInnerContent_commentReference"/>
+ <element name="drawing" tokenid="ooxml:EG_RunInnerContent_drawing"/>
+ <element name="ptab" tokenid="ooxml:EG_RunInnerContent_ptab"/>
+ <element name="lastRenderedPageBreak" tokenid="ooxml:EG_RunInnerContent_lastRenderedPageBreak"/>
+ </resource>
+ <resource name="CT_R" resource="Stream">
+ <action name="start" action="startCharacterGroup"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RubyContent_r" sendtokenid="ooxml:EG_RubyContent_r"/>
+ </resource>
+ <resource name="ST_Hint" resource="List">
+ <value tokenid="ooxml:Value_ST_Hint_default">default</value>
+ <value tokenid="ooxml:Value_ST_Hint_eastAsia">eastAsia</value>
+ <value tokenid="ooxml:Value_ST_Hint_cs">cs</value>
+ </resource>
+ <resource name="ST_Theme" resource="List">
+ <value tokenid="ooxml:Value_ST_Theme_majorEastAsia">majorEastAsia</value>
+ <value tokenid="ooxml:Value_ST_Theme_majorBidi">majorBidi</value>
+ <value tokenid="ooxml:Value_ST_Theme_majorAscii">majorAscii</value>
+ <value tokenid="ooxml:Value_ST_Theme_majorHAnsi">majorHAnsi</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorEastAsia">minorEastAsia</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorBidi">minorBidi</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorAscii">minorAscii</value>
+ <value tokenid="ooxml:Value_ST_Theme_minorHAnsi">minorHAnsi</value>
+ </resource>
+ <resource name="CT_Fonts" resource="Properties">
+ <attribute name="hint" tokenid="ooxml:CT_Fonts_hint"/>
+ <attribute name="ascii" tokenid="ooxml:CT_Fonts_ascii"/>
+ <attribute name="hAnsi" tokenid="ooxml:CT_Fonts_hAnsi"/>
+ <attribute name="eastAsia" tokenid="ooxml:CT_Fonts_eastAsia"/>
+ <attribute name="cs" tokenid="ooxml:CT_Fonts_cs"/>
+ <attribute name="asciiTheme" tokenid="ooxml:CT_Fonts_asciiTheme"/>
+ <attribute name="hAnsiTheme" tokenid="ooxml:CT_Fonts_hAnsiTheme"/>
+ <attribute name="eastAsiaTheme" tokenid="ooxml:CT_Fonts_eastAsiaTheme"/>
+ <attribute name="cstheme" tokenid="ooxml:CT_Fonts_cstheme"/>
+ </resource>
+ <resource name="EG_RPrBase" resource="Properties">
+ <element name="rStyle" tokenid="ooxml:EG_RPrBase_rStyle"/>
+ <element name="rFonts" tokenid="ooxml:EG_RPrBase_rFonts"/>
+ <element name="b" tokenid="ooxml:EG_RPrBase_b"/>
+ <element name="bCs" tokenid="ooxml:EG_RPrBase_bCs"/>
+ <element name="i" tokenid="ooxml:EG_RPrBase_i"/>
+ <element name="iCs" tokenid="ooxml:EG_RPrBase_iCs"/>
+ <element name="caps" tokenid="ooxml:EG_RPrBase_caps"/>
+ <element name="smallCaps" tokenid="ooxml:EG_RPrBase_smallCaps"/>
+ <element name="strike" tokenid="ooxml:EG_RPrBase_strike"/>
+ <element name="dstrike" tokenid="ooxml:EG_RPrBase_dstrike"/>
+ <element name="outline" tokenid="ooxml:EG_RPrBase_outline"/>
+ <element name="shadow" tokenid="ooxml:EG_RPrBase_shadow"/>
+ <element name="emboss" tokenid="ooxml:EG_RPrBase_emboss"/>
+ <element name="imprint" tokenid="ooxml:EG_RPrBase_imprint"/>
+ <element name="noProof" tokenid="ooxml:EG_RPrBase_noProof"/>
+ <element name="snapToGrid" tokenid="ooxml:EG_RPrBase_snapToGrid"/>
+ <element name="vanish" tokenid="ooxml:EG_RPrBase_vanish"/>
+ <element name="webHidden" tokenid="ooxml:EG_RPrBase_webHidden"/>
+ <element name="color" tokenid="ooxml:EG_RPrBase_color"/>
+ <element name="spacing" tokenid="ooxml:EG_RPrBase_spacing"/>
+ <element name="w" tokenid="ooxml:EG_RPrBase_w"/>
+ <element name="kern" tokenid="ooxml:EG_RPrBase_kern"/>
+ <element name="position" tokenid="ooxml:EG_RPrBase_position"/>
+ <element name="sz" tokenid="ooxml:EG_RPrBase_sz"/>
+ <element name="szCs" tokenid="ooxml:EG_RPrBase_szCs"/>
+ <element name="highlight" tokenid="ooxml:EG_RPrBase_highlight"/>
+ <element name="u" tokenid="ooxml:EG_RPrBase_u"/>
+ <element name="effect" tokenid="ooxml:EG_RPrBase_effect"/>
+ <element name="bdr" tokenid="ooxml:EG_RPrBase_bdr"/>
+ <element name="shd" tokenid="ooxml:EG_RPrBase_shd"/>
+ <element name="fitText" tokenid="ooxml:EG_RPrBase_fitText"/>
+ <element name="vertAlign" tokenid="ooxml:EG_RPrBase_vertAlign"/>
+ <element name="rtl" tokenid="ooxml:EG_RPrBase_rtl"/>
+ <element name="cs" tokenid="ooxml:EG_RPrBase_cs"/>
+ <element name="em" tokenid="ooxml:EG_RPrBase_em"/>
+ <element name="lang" tokenid="ooxml:EG_RPrBase_lang"/>
+ <element name="eastAsianLayout" tokenid="ooxml:EG_RPrBase_eastAsianLayout"/>
+ <element name="specVanish" tokenid="ooxml:EG_RPrBase_specVanish"/>
+ <element name="oMath" tokenid="ooxml:EG_RPrBase_oMath"/>
+ <element name="w14:glow" tokenid="ooxml:EG_RPrBase_w14_glow"/>
+ <element name="w14:shadow" tokenid="ooxml:EG_RPrBase_w14_shadow"/>
+ <element name="w14:reflection" tokenid="ooxml:EG_RPrBase_w14_reflection"/>
+ <element name="w14:textOutline" tokenid="ooxml:EG_RPrBase_w14_textOutline"/>
+ <element name="w14:textFill" tokenid="ooxml:EG_RPrBase_w14_textFill"/>
+ <element name="w14:scene3d" tokenid="ooxml:EG_RPrBase_w14_scene3d"/>
+ <element name="w14:props3d" tokenid="ooxml:EG_RPrBase_w14_props3d"/>
+ <element name="w14:ligatures" tokenid="ooxml:EG_RPrBase_w14_ligatures"/>
+ <element name="w14:numForm" tokenid="ooxml:EG_RPrBase_w14_numForm"/>
+ <element name="w14:numSpacing" tokenid="ooxml:EG_RPrBase_w14_numSpacing"/>
+ <element name="w14:stylisticSets" tokenid="ooxml:EG_RPrBase_w14_stylisticSets"/>
+ <element name="w14:cntxtAlts" tokenid="ooxml:EG_RPrBase_w14_cntxtAlts"/>
+ </resource>
+ <resource name="EG_RPrContent" resource="Properties">
+ <element name="rPrChange" tokenid="ooxml:EG_RPrContent_rPrChange"/>
+ </resource>
+ <resource name="CT_RPr" resource="Properties">
+ </resource>
+ <resource name="CT_RPrOriginal" resource="Properties"/>
+ <resource name="CT_ParaRPrOriginal" resource="Properties"/>
+ <resource name="CT_ParaRPr" resource="Properties">
+ <element name="ins" tokenid="ooxml:CT_ParaRPr_ins"/>
+ <element name="del" tokenid="ooxml:CT_ParaRPr_del"/>
+ <element name="moveFrom" tokenid="ooxml:CT_ParaRPr_moveFrom"/>
+ <element name="moveTo" tokenid="ooxml:CT_ParaRPr_moveTo"/>
+ <element name="rPrChange" tokenid="ooxml:CT_ParaRPr_rPrChange"/>
+ </resource>
+ <resource name="CT_ParaTrackChange" resource="Properties">
+ <action name="start" action="tokenproperty"/>
+ <action name="start" action="sendPropertiesWithId" sendtokenid="ooxml:paratrackchange"/>
+ <action name="start" action="clearProps"/>
+ </resource>
+ <resource name="CT_AltChunk" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_AltChunk"/>
+ <action name="start" action="handleAltChunk"/>
+ </resource>
+ <resource name="ST_RubyAlign" resource="List">
+ <value tokenid="ooxml:Value_ST_RubyAlign_center">center</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_distributeLetter">distributeLetter</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_distributeSpace">distributeSpace</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_left">left</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_right">right</value>
+ <value tokenid="ooxml:Value_ST_RubyAlign_rightVertical">rightVertical</value>
+ </resource>
+ <resource name="CT_RubyAlign" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_RubyAlign_val" action="setValue"/>
+ </resource>
+ <resource name="CT_RubyPr" resource="Properties">
+ <element name="rubyAlign" tokenid="ooxml:CT_RubyPr_rubyAlign"/>
+ <element name="hps" tokenid="ooxml:CT_RubyPr_hps"/>
+ <element name="hpsRaise" tokenid="ooxml:CT_RubyPr_hpsRaise"/>
+ <element name="hpsBaseText" tokenid="ooxml:CT_RubyPr_hpsBaseText"/>
+ <element name="lid" tokenid="ooxml:CT_RubyPr_lid"/>
+ <element name="dirty" tokenid="ooxml:CT_RubyPr_dirty"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:CT_RubyPr" sendtokenid="ooxml:CT_RubyPr"/>
+ </resource>
+ <resource name="CT_Ruby" resource="Stream">
+ <element name="rubyPr" tokenid="ooxml:CT_RubyPr"/>
+ <element name="rt" tokenid="ooxml:CT_Ruby_rt"/>
+ <element name="rubyBase" tokenid="ooxml:CT_Ruby_rubyBase"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:EG_RunInnerContent_ruby" sendtokenid="ooxml:EG_RunInnerContent_ruby"/>
+ </resource>
+ <resource name="CT_RubyContent" resource="Stream">
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:CT_Ruby_rt" sendtokenid="ooxml:CT_Ruby_rt"/>
+ <action name="start" action="sendPropertiesWithId" tokenid="ooxml:CT_Ruby_rubyBase" sendtokenid="ooxml:CT_Ruby_rubyBase"/>
+ </resource>
+ <resource name="EG_RubyContent" resource="Stream">
+ <element name="r" tokenid="ooxml:EG_RubyContent_r"/>
+ </resource>
+ <resource name="CT_Lock" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Lock_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SdtDateMappingType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_SdtDateMappingType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_CalendarType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_CalendarType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SdtText" resource="Properties">
+ <attribute name="multiLine" tokenid="ooxml:CT_SdtText_multiLine"/>
+ </resource>
+ <resource name="CT_SdtPlaceholder" resource="Properties">
+ <attribute name="docPart" tokenid="ooxml:CT_SdtPlaceholder_docPart"/>
+ </resource>
+ <resource name="CT_DataBinding" resource="Properties">
+ <attribute name="prefixMappings" tokenid="ooxml:CT_DataBinding_prefixMappings"/>
+ <attribute name="xpath" tokenid="ooxml:CT_DataBinding_xpath"/>
+ <attribute name="storeItemID" tokenid="ooxml:CT_DataBinding_storeItemID"/>
+ </resource>
+ <resource name="CT_SdtColor" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SdtColor_val"/>
+ </resource>
+ <resource name="CT_SdtAppearance" resource="Properties">
+ <attribute name="w15:val" tokenid="ooxml:CT_SdtAppearance_val"/>
+ </resource>
+ <resource name="CT_SdtPr" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_SdtPr_rPr"/>
+ <element name="alias" tokenid="ooxml:CT_SdtPr_alias"/>
+ <element name="lock" tokenid="ooxml:CT_SdtPr_lock"/>
+ <element name="placeholder" tokenid="ooxml:CT_SdtPr_placeholder"/>
+ <element name="showingPlcHdr" tokenid="ooxml:CT_SdtPr_showingPlcHdr"/>
+ <element name="dataBinding" tokenid="ooxml:CT_SdtPr_dataBinding"/>
+ <element name="temporary" tokenid="ooxml:CT_SdtPr_temporary"/>
+ <element name="id" tokenid="ooxml:CT_SdtPr_id"/>
+ <element name="tabIndex" tokenid="ooxml:CT_SdtPr_tabIndex"/>
+ <element name="tag" tokenid="ooxml:CT_SdtPr_tag"/>
+ <element name="equation" tokenid="ooxml:CT_SdtPr_equation"/>
+ <element name="comboBox" tokenid="ooxml:CT_SdtPr_comboBox"/>
+ <element name="w14:checkbox" tokenid="ooxml:CT_SdtPr_checkbox"/>
+ <element name="date" tokenid="ooxml:CT_SdtPr_date"/>
+ <element name="docPartObj" tokenid="ooxml:CT_SdtPr_docPartObj"/>
+ <element name="docPartList" tokenid="ooxml:CT_SdtPr_docPartList"/>
+ <element name="dropDownList" tokenid="ooxml:CT_SdtPr_dropDownList"/>
+ <element name="picture" tokenid="ooxml:CT_SdtPr_picture"/>
+ <element name="richText" tokenid="ooxml:CT_SdtPr_richText"/>
+ <element name="text" tokenid="ooxml:CT_SdtPr_text"/>
+ <element name="citation" tokenid="ooxml:CT_SdtPr_citation"/>
+ <element name="group" tokenid="ooxml:CT_SdtPr_group"/>
+ <element name="bibliography" tokenid="ooxml:CT_SdtPr_bibliography"/>
+ <element name="w15:color" tokenid="ooxml:CT_SdtPr_color"/>
+ <element name="w15:appearance" tokenid="ooxml:CT_SdtPr_appearance"/>
+ </resource>
+ <resource name="CT_SdtEndPr" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_SdtEndPr_rPr"/>
+ </resource>
+ <resource name="CT_DirContentRun" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DirContentRun_val" action="setValue"/>
+ <action name="start" action="pushBiDiEmbedLevel"/>
+ <action name="end" action="popBiDiEmbedLevel"/>
+ </resource>
+ <resource name="ST_Direction" resource="List">
+ <value tokenid="ooxml:Value_ST_Direction_ltr">ltr</value>
+ <value tokenid="ooxml:Value_ST_Direction_rtl">rtl</value>
+ </resource>
+ <resource name="CT_SdtContentRun" resource="Stream"/>
+ <resource name="CT_SdtContentBlock" resource="Stream"/>
+ <resource name="CT_SdtContentRow" resource="Stream"/>
+ <resource name="CT_SdtContentCell" resource="Stream">
+ <action name="start" action="startSdt"/>
+ <action name="end" action="endSdt"/>
+ </resource>
+ <resource name="CT_SdtBlock" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtBlock_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtBlock_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtBlock_sdtContent"/>
+ <element name="sdtEndContent" tokenid="ooxml:CT_SdtBlock_sdtEndContent"/>
+ <action name="start" action="startSdt"/>
+ <action name="end" action="endSdt"/>
+ </resource>
+ <resource name="CT_SdtRun" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtRun_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtRun_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtRun_sdtContent"/>
+ <element name="sdtEndContent" tokenid="ooxml:CT_SdtRun_sdtEndContent"/>
+ <action name="start" action="startSdtRun"/>
+ <action name="end" action="endSdtRun"/>
+ </resource>
+ <resource name="CT_SdtCell" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtCell_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtCell_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtCell_sdtContent"/>
+ </resource>
+ <resource name="CT_SdtRow" resource="Stream">
+ <element name="sdtPr" tokenid="ooxml:CT_SdtRow_sdtPr"/>
+ <element name="sdtEndPr" tokenid="ooxml:CT_SdtRow_sdtEndPr"/>
+ <element name="sdtContent" tokenid="ooxml:CT_SdtRow_sdtContent"/>
+ </resource>
+ <resource name="CT_SdtDropDownList" resource="Properties">
+ <element name="listItem" tokenid="ooxml:CT_SdtDropDownList_listItem"/>
+ </resource>
+ <resource name="CT_SdtDate" resource="Properties">
+ <attribute name="fullDate" tokenid="ooxml:CT_SdtDate_fullDate"/>
+ <element name="dateFormat" tokenid="ooxml:CT_SdtDate_dateFormat"/>
+ <element name="lid" tokenid="ooxml:CT_SdtDate_lid"/>
+ <element name="storeMappedDataAs" tokenid="ooxml:CT_SdtDate_storeMappedDataAs"/>
+ <element name="calendar" tokenid="ooxml:CT_SdtDate_calendar"/>
+ </resource>
+ <resource name="CT_SdtDocPart" resource="Properties">
+ <element name="docPartGallery" tokenid="ooxml:CT_SdtDocPart_docPartGallery"/>
+ <element name="docPartCategory" tokenid="ooxml:CT_SdtDocPart_docPartCategory"/>
+ <element name="docPartUnique" tokenid="ooxml:CT_SdtDocPart_docPartUnique"/>
+ </resource>
+ <resource name="CT_SdtListItem" resource="Properties">
+ <attribute name="displayText" tokenid="ooxml:CT_SdtListItem_displayText"/>
+ <attribute name="value" tokenid="ooxml:CT_SdtListItem_value"/>
+ </resource>
+ <resource name="CT_SdtPlaceholderDocPart" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_SdtPlaceholder_docPart_val"/>
+ </resource>
+ <resource name="CT_Attr" resource="Properties">
+ <attribute name="uri" tokenid="ooxml:CT_Attr_uri"/>
+ <attribute name="name" tokenid="ooxml:CT_Attr_name"/>
+ <attribute name="val" tokenid="ooxml:CT_Attr_val"/>
+ </resource>
+ <resource name="CT_CustomXmlRun" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlRun_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlRun_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlRun_element"/>
+ </resource>
+ <resource name="CT_CustomXmlBlock" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlBlock_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlBlock_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlBlock_element"/>
+ </resource>
+ <resource name="CT_CustomXmlCell" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlCell_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlCell_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlCell_element"/>
+ </resource>
+ <resource name="CT_CustomXmlRow" resource="Properties">
+ <element name="customXmlPr" tokenid="ooxml:CT_CustomXmlRow_customXmlPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_CustomXmlRow_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_CustomXmlRow_element"/>
+ </resource>
+ <resource name="CT_SmartTagRun" resource="Properties">
+ <element name="smartTagPr" tokenid="ooxml:CT_SmartTagRun_smartTagPr"/>
+ <attribute name="uri" tokenid="ooxml:CT_SmartTagRun_uri"/>
+ <attribute name="element" tokenid="ooxml:CT_SmartTagRun_element"/>
+ </resource>
+ <resource name="CT_SmartTagPr" resource="Properties">
+ <element name="attr" tokenid="ooxml:CT_SmartTagPr_attr"/>
+ </resource>
+ <resource name="EG_PContent" resource="Properties">
+ <element name="fldSimple" tokenid="ooxml:EG_PContent_fldSimple"/>
+ <element name="hyperlink" tokenid="ooxml:EG_PContent_hyperlink"/>
+ <element name="subDoc" tokenid="ooxml:EG_PContent_subDoc"/>
+ </resource>
+ <resource name="CT_P" resource="Stream">
+ <attribute name="w14:paraId" tokenid="ooxml:AG_Parids_paraId"/>
+ <action name="start" action="handleLastParagraphInSection"/>
+ <action name="start" action="startParagraphGroup"/>
+ <action name="start" action="setHandle"/>
+ <action name="start" action="sendTableDepth"/>
+ <action name="end" action="endOfParagraph"/>
+ </resource>
+ <resource name="ST_TblWidth" resource="List">
+ <value tokenid="ooxml:Value_ST_TblWidth_nil">nil</value>
+ <value tokenid="ooxml:Value_ST_TblWidth_pct">pct</value>
+ <value tokenid="ooxml:Value_ST_TblWidth_dxa">dxa</value>
+ <value tokenid="ooxml:Value_ST_TblWidth_auto">auto</value>
+ </resource>
+ <resource name="CT_Height" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Height_val"/>
+ <attribute name="hRule" tokenid="ooxml:CT_Height_hRule"/>
+ </resource>
+ <resource name="CT_TblWidth" resource="Properties">
+ <attribute name="w" tokenid="ooxml:CT_TblWidth_w"/>
+ <attribute name="type" tokenid="ooxml:CT_TblWidth_type"/>
+ </resource>
+ <resource name="CT_TblPPr" resource="Properties">
+ <attribute name="vertAnchor" tokenid="ooxml:CT_TblPPr_vertAnchor"/>
+ <attribute name="tblpYSpec" tokenid="ooxml:CT_TblPPr_tblpYSpec"/>
+ <attribute name="horzAnchor" tokenid="ooxml:CT_TblPPr_horzAnchor"/>
+ <attribute name="tblpXSpec" tokenid="ooxml:CT_TblPPr_tblpXSpec"/>
+ <attribute name="tblpY" tokenid="ooxml:CT_TblPPr_tblpY"/>
+ <attribute name="tblpX" tokenid="ooxml:CT_TblPPr_tblpX"/>
+ <attribute name="leftFromText" tokenid="ooxml:CT_TblPPr_leftFromText"/>
+ <attribute name="rightFromText" tokenid="ooxml:CT_TblPPr_rightFromText"/>
+ <attribute name="topFromText" tokenid="ooxml:CT_TblPPr_topFromText"/>
+ <attribute name="bottomFromText" tokenid="ooxml:CT_TblPPr_bottomFromText"/>
+ </resource>
+ <resource name="CT_TblGridCol" resource="Value">
+ <attribute name="w" tokenid="ooxml:CT_TblGridCol_w" action="setValue"/>
+ <action name="start" action="setDefaultIntegerValue"/>
+ </resource>
+ <resource name="CT_TblGridBase" resource="Properties">
+ <element name="gridCol" tokenid="ooxml:CT_TblGridBase_gridCol"/>
+ </resource>
+ <resource name="CT_TblGrid" resource="Properties">
+ <element name="tblGridChange" tokenid="ooxml:CT_TblGrid_tblGridChange"/>
+ <action name="end" action="propagateTableProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_TcBorders" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TcBorders_top"/>
+ <element name="start" tokenid="ooxml:CT_TcBorders_start"/>
+ <element name="left" tokenid="ooxml:CT_TcBorders_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TcBorders_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TcBorders_end"/>
+ <element name="right" tokenid="ooxml:CT_TcBorders_right"/>
+ <element name="insideH" tokenid="ooxml:CT_TcBorders_insideH"/>
+ <element name="insideV" tokenid="ooxml:CT_TcBorders_insideV"/>
+ <element name="tl2br" tokenid="ooxml:CT_TcBorders_tl2br"/>
+ <element name="tr2bl" tokenid="ooxml:CT_TcBorders_tr2bl"/>
+ </resource>
+ <resource name="CT_TcMar" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TcMar_top"/>
+ <element name="start" tokenid="ooxml:CT_TcMar_start"/>
+ <element name="left" tokenid="ooxml:CT_TcMar_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TcMar_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TcMar_end"/>
+ <element name="right" tokenid="ooxml:CT_TcMar_right"/>
+ </resource>
+ <resource name="ST_Merge" resource="List">
+ <value tokenid="ooxml:Value_ST_Merge_continue">continue</value>
+ <value tokenid="ooxml:Value_ST_Merge_restart">restart</value>
+ </resource>
+ <resource name="CT_VMerge" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_VMerge_val" action="setValue"/>
+ </resource>
+ <resource name="CT_HMerge" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_HMerge_val" action="setValue"/>
+ </resource>
+ <resource name="CT_TcPrBase" resource="Properties">
+ <element name="cnfStyle" tokenid="ooxml:CT_TcPrBase_cnfStyle"/>
+ <element name="tcW" tokenid="ooxml:CT_TcPrBase_tcW"/>
+ <element name="gridSpan" tokenid="ooxml:CT_TcPrBase_gridSpan"/>
+ <element name="hMerge" tokenid="ooxml:CT_TcPrBase_hMerge"/>
+ <element name="vMerge" tokenid="ooxml:CT_TcPrBase_vMerge"/>
+ <element name="tcBorders" tokenid="ooxml:CT_TcPrBase_tcBorders"/>
+ <element name="shd" tokenid="ooxml:CT_TcPrBase_shd"/>
+ <element name="noWrap" tokenid="ooxml:CT_TcPrBase_noWrap"/>
+ <element name="tcMar" tokenid="ooxml:CT_TcPrBase_tcMar"/>
+ <element name="textDirection" tokenid="ooxml:CT_TcPrBase_textDirection"/>
+ <element name="tcFitText" tokenid="ooxml:CT_TcPrBase_tcFitText"/>
+ <element name="vAlign" tokenid="ooxml:CT_TcPrBase_vAlign"/>
+ <element name="hideMark" tokenid="ooxml:CT_TcPrBase_hideMark"/>
+ <element name="cellDel" tokenid="ooxml:CT_TcPrBase_cellDel"/>
+ <element name="cellIns" tokenid="ooxml:CT_TcPrBase_cellIns"/>
+ <element name="cellMerge" tokenid="ooxml:CT_TcPrBase_cellMerge"/>
+ </resource>
+ <resource name="CT_TcPr" resource="Properties">
+ <element name="tcPrChange" tokenid="ooxml:CT_TcPr_tcPrChange"/>
+ <action name="end" action="propagateCellProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_TcPrInner" resource="Properties"/>
+ <resource name="CT_Tc" resource="TextTableCell">
+ <action name="start" action="startCell"/>
+ <action name="end" action="endCell"/>
+ <action name="end" action="sendCellProperties"/>
+ <action name="end" action="endParagraphGroup"/>
+ </resource>
+ <resource name="ST_Cnf" resource="String"/>
+ <resource name="CT_Cnf" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Cnf_val"/>
+ <attribute name="firstRow" tokenid="ooxml:CT_Cnf_firstRow"/>
+ <attribute name="lastRow" tokenid="ooxml:CT_Cnf_lastRow"/>
+ <attribute name="firstColumn" tokenid="ooxml:CT_Cnf_firstColumn"/>
+ <attribute name="lastColumn" tokenid="ooxml:CT_Cnf_lastColumn"/>
+ <attribute name="oddVBand" tokenid="ooxml:CT_Cnf_oddVBand"/>
+ <attribute name="evenVBand" tokenid="ooxml:CT_Cnf_evenVBand"/>
+ <attribute name="oddHBand" tokenid="ooxml:CT_Cnf_oddHBand"/>
+ <attribute name="evenHBand" tokenid="ooxml:CT_Cnf_evenHBand"/>
+ <attribute name="firstRowFirstColumn" tokenid="ooxml:CT_Cnf_firstRowFirstColumn"/>
+ <attribute name="firstRowLastColumn" tokenid="ooxml:CT_Cnf_firstRowLastColumn"/>
+ <attribute name="lastRowFirstColumn" tokenid="ooxml:CT_Cnf_lastRowFirstColumn"/>
+ <attribute name="lastRowLastColumn" tokenid="ooxml:CT_Cnf_lastRowLastColumn"/>
+ </resource>
+ <resource name="CT_TrPrBase" resource="Properties">
+ <element name="cnfStyle" tokenid="ooxml:CT_TrPrBase_cnfStyle"/>
+ <element name="divId" tokenid="ooxml:CT_TrPrBase_divId"/>
+ <element name="gridBefore" tokenid="ooxml:CT_TrPrBase_gridBefore"/>
+ <element name="gridAfter" tokenid="ooxml:CT_TrPrBase_gridAfter"/>
+ <element name="wBefore" tokenid="ooxml:CT_TrPrBase_wBefore"/>
+ <element name="wAfter" tokenid="ooxml:CT_TrPrBase_wAfter"/>
+ <element name="cantSplit" tokenid="ooxml:CT_TrPrBase_cantSplit"/>
+ <element name="trHeight" tokenid="ooxml:CT_TrPrBase_trHeight"/>
+ <element name="tblHeader" tokenid="ooxml:CT_TrPrBase_tblHeader"/>
+ <element name="tblCellSpacing" tokenid="ooxml:CT_TrPrBase_tblCellSpacing"/>
+ <element name="jc" tokenid="ooxml:CT_TrPrBase_jc"/>
+ <element name="hidden" tokenid="ooxml:CT_TrPrBase_hidden"/>
+ </resource>
+ <resource name="CT_TrPrBaseGridAfter" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TrPrBase_gridAfter" action="setValue"/>
+ <action name="end" action="handleGridAfter"/>
+ </resource>
+ <resource name="CT_TrPr" resource="Properties">
+ <element name="ins" tokenid="ooxml:CT_TrPr_ins"/>
+ <element name="del" tokenid="ooxml:CT_TrPr_del"/>
+ <element name="trPrChange" tokenid="ooxml:CT_TrPr_trPrChange"/>
+ <action name="end" action="propagateRowProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_Row" resource="TextTableRow">
+ <action name="start" action="startRow"/>
+ <action name="end" action="sendRowProperties"/>
+ <action name="end" action="sendTableProperties"/>
+ <action name="end" action="endRow"/>
+ </resource>
+ <resource name="ST_TblLayout" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_TblLayout_fixed">fixed</value>
+ <value tokenid="ooxml:Value_doc_ST_TblLayout_autofit">autofit</value>
+ </resource>
+ <resource name="CT_TblLayoutType" resource="Value">
+ <attribute name="type" tokenid="ooxml:CT_TblLayoutType_type" action="setValue"/>
+ </resource>
+ <resource name="ST_TblOverlap" resource="List">
+ <value tokenid="ooxml:Value_ST_TblOverlap_never">never</value>
+ <value tokenid="ooxml:Value_ST_TblOverlap_overlap">overlap</value>
+ </resource>
+ <resource name="CT_TblOverlap" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TblOverlap_val" action="setValue"/>
+ </resource>
+ <resource name="CT_TblCellMar" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TblCellMar_top"/>
+ <element name="start" tokenid="ooxml:CT_TblCellMar_start"/>
+ <element name="left" tokenid="ooxml:CT_TblCellMar_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TblCellMar_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TblCellMar_end"/>
+ <element name="right" tokenid="ooxml:CT_TblCellMar_right"/>
+ </resource>
+ <resource name="CT_TblBorders" resource="Properties">
+ <element name="top" tokenid="ooxml:CT_TblBorders_top"/>
+ <element name="start" tokenid="ooxml:CT_TblBorders_start"/>
+ <element name="left" tokenid="ooxml:CT_TblBorders_left"/>
+ <element name="bottom" tokenid="ooxml:CT_TblBorders_bottom"/>
+ <element name="end" tokenid="ooxml:CT_TblBorders_end"/>
+ <element name="right" tokenid="ooxml:CT_TblBorders_right"/>
+ <element name="insideH" tokenid="ooxml:CT_TblBorders_insideH"/>
+ <element name="insideV" tokenid="ooxml:CT_TblBorders_insideV"/>
+ </resource>
+ <resource name="CT_TblPrBase" resource="Properties">
+ <element name="tblStyle" tokenid="ooxml:CT_TblPrBase_tblStyle"/>
+ <element name="tblpPr" tokenid="ooxml:CT_TblPrBase_tblpPr"/>
+ <element name="tblOverlap" tokenid="ooxml:CT_TblPrBase_tblOverlap"/>
+ <element name="bidiVisual" tokenid="ooxml:CT_TblPrBase_bidiVisual"/>
+ <element name="tblStyleRowBandSize" tokenid="ooxml:CT_TblPrBase_tblStyleRowBandSize"/>
+ <element name="tblStyleColBandSize" tokenid="ooxml:CT_TblPrBase_tblStyleColBandSize"/>
+ <element name="tblW" tokenid="ooxml:CT_TblPrBase_tblW"/>
+ <element name="jc" tokenid="ooxml:CT_TblPrBase_jc"/>
+ <element name="tblCellSpacing" tokenid="ooxml:CT_TblPrBase_tblCellSpacing"/>
+ <element name="tblInd" tokenid="ooxml:CT_TblPrBase_tblInd"/>
+ <element name="tblBorders" tokenid="ooxml:CT_TblPrBase_tblBorders"/>
+ <element name="shd" tokenid="ooxml:CT_TblPrBase_shd"/>
+ <element name="tblLayout" tokenid="ooxml:CT_TblPrBase_tblLayout"/>
+ <element name="tblCellMar" tokenid="ooxml:CT_TblPrBase_tblCellMar"/>
+ <element name="tblLook" tokenid="ooxml:CT_TblPrBase_tblLook"/>
+ <element name="tblCaption" tokenid="ooxml:CT_TblPrBase_tblCaption"/>
+ <element name="tblDescription" tokenid="ooxml:CT_TblPrBase_tblDescription"/>
+ </resource>
+ <resource name="CT_TblPr" resource="Properties">
+ <element name="tblPrChange" tokenid="ooxml:CT_TblPr_tblPrChange"/>
+ <action name="end" action="propagateTableProperties"/>
+ <action name="end" action="clearProps"/>
+ </resource>
+ <resource name="CT_TblPrEx" resource="Properties">
+ <element name="tblPrExChange" tokenid="ooxml:CT_TblPrEx_tblPrExChange"/>
+ <element name="tblBorders" tokenid="ooxml:CT_TblPrEx_tblBorders"/>
+ </resource>
+ <resource name="CT_Tbl" resource="TextTable"/>
+ <!-- tdf#111550 : allow <w:tbl> at paragraph level (despite this is illegal according to ECMA-376-1:2016) - bug-to-bug compatibility with Word -->
+ <resource name="CT_P_Tbl" resource="TextTable">
+ <action name="start" action="start_P_Tbl"/>
+ </resource>
+ <resource name="CT_TblLook" resource="Properties">
+ <attribute name="firstRow" tokenid="ooxml:CT_TblLook_firstRow"/>
+ <attribute name="lastRow" tokenid="ooxml:CT_TblLook_lastRow"/>
+ <attribute name="firstColumn" tokenid="ooxml:CT_TblLook_firstColumn"/>
+ <attribute name="lastColumn" tokenid="ooxml:CT_TblLook_lastColumn"/>
+ <attribute name="noHBand" tokenid="ooxml:CT_TblLook_noHBand"/>
+ <attribute name="noVBand" tokenid="ooxml:CT_TblLook_noVBand"/>
+ <attribute name="val" tokenid="ooxml:CT_TblLook_val"/>
+ </resource>
+ <resource name="ST_FtnPos" resource="List">
+ <value tokenid="ooxml:Value_ST_FtnPos_pageBottom">pageBottom</value>
+ <value tokenid="ooxml:Value_ST_FtnPos_beneathText">beneathText</value>
+ <value tokenid="ooxml:Value_ST_FtnPos_sectEnd">sectEnd</value>
+ <value tokenid="ooxml:Value_ST_FtnPos_docEnd">docEnd</value>
+ </resource>
+ <resource name="CT_FtnPos" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FtnPos_val" action="setValue"/>
+ </resource>
+ <resource name="ST_EdnPos" resource="List">
+ <value tokenid="ooxml:Value_ST_EdnPos_sectEnd">sectEnd</value>
+ <value tokenid="ooxml:Value_ST_EdnPos_docEnd">docEnd</value>
+ </resource>
+ <resource name="CT_EdnPos" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_EdnPos_val" action="setValue"/>
+ </resource>
+ <resource name="CT_NumFmt" resource="Properties">
+ <attribute name="format" tokenid="ooxml:CT_NumFmt_format"/>
+ <attribute name="val" tokenid="ooxml:CT_NumFmt_val"/>
+ </resource>
+ <resource name="ST_RestartNumber" resource="List">
+ <value tokenid="ooxml:Value_ST_RestartNumber_continuous">continuous</value>
+ <value tokenid="ooxml:Value_ST_RestartNumber_eachSect">eachSect</value>
+ <value tokenid="ooxml:Value_ST_RestartNumber_eachPage">eachPage</value>
+ </resource>
+ <resource name="CT_NumRestart" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_NumRestart_val" action="setValue"/>
+ </resource>
+ <resource name="CT_FtnEdnRef" resource="Properties">
+ <attribute name="customMarkFollows" tokenid="ooxml:CT_FtnEdnRef_customMarkFollows"/>
+ <attribute name="id" tokenid="ooxml:CT_FtnEdnRef_id" action="setXNoteId"/>
+ <action name="end" action="handleXNotes"/>
+ </resource>
+ <resource name="CT_FtnEdnSepRef" resource="Properties">
+ <attribute name="id" tokenid="ooxml:CT_FtnEdnSepRef_id"/>
+ </resource>
+ <resource name="CT_FtnEdn" resource="XNote">
+ <attribute name="type" tokenid="ooxml:CT_FtnEdn_type" action="checkType"/>
+ <attribute name="id" tokenid="ooxml:CT_FtnEdn_id" action="checkId"/>
+ <action name="start" action="propagateCharacterProperties"/>
+ <action name="end" action="endSectionGroup"/>
+ </resource>
+ <resource name="CT_CommentRef" resource="Properties">
+ <action name="end" action="handleComment"/>
+ </resource>
+ <resource name="EG_FtnEdnNumProps" resource="Properties">
+ <element name="numStart" tokenid="ooxml:EG_FtnEdnNumProps_numStart"/>
+ <element name="numRestart" tokenid="ooxml:EG_FtnEdnNumProps_numRestart"/>
+ </resource>
+ <resource name="CT_FtnProps" resource="Properties">
+ <element name="pos" tokenid="ooxml:CT_FtnProps_pos"/>
+ <element name="numFmt" tokenid="ooxml:CT_FtnProps_numFmt"/>
+ </resource>
+ <resource name="CT_EdnProps" resource="Properties">
+ <element name="pos" tokenid="ooxml:CT_EdnProps_pos"/>
+ <element name="numFmt" tokenid="ooxml:CT_EdnProps_numFmt"/>
+ </resource>
+ <resource name="CT_FtnDocProps" resource="Properties">
+ <element name="footnote" tokenid="ooxml:CT_FtnDocProps_footnote"/>
+ </resource>
+ <resource name="CT_EdnDocProps" resource="Properties">
+ <element name="endnote" tokenid="ooxml:CT_EdnDocProps_endnote"/>
+ </resource>
+ <resource name="CT_MailMergeSourceType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MailMergeSourceType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_MailMerge" resource="Properties">
+ <element name="mainDocumentType" tokenid="ooxml:CT_MailMerge_mainDocumentType"/>
+ <element name="linkToQuery" tokenid="ooxml:CT_MailMerge_linkToQuery"/>
+ <element name="dataType" tokenid="ooxml:CT_MailMerge_dataType"/>
+ <element name="connectString" tokenid="ooxml:CT_MailMerge_connectString"/>
+ <element name="query" tokenid="ooxml:CT_MailMerge_query"/>
+ <element name="dataSource" tokenid="ooxml:CT_MailMerge_dataSource"/>
+ <element name="headerSource" tokenid="ooxml:CT_MailMerge_headerSource"/>
+ <element name="doNotSuppressBlankLines" tokenid="ooxml:CT_MailMerge_doNotSuppressBlankLines"/>
+ <element name="destination" tokenid="ooxml:CT_MailMerge_destination"/>
+ <element name="addressFieldName" tokenid="ooxml:CT_MailMerge_addressFieldName"/>
+ <element name="mailSubject" tokenid="ooxml:CT_MailMerge_mailSubject"/>
+ <element name="mailAsAttachment" tokenid="ooxml:CT_MailMerge_mailAsAttachment"/>
+ <element name="viewMergedData" tokenid="ooxml:CT_MailMerge_viewMergedData"/>
+ <element name="activeRecord" tokenid="ooxml:CT_MailMerge_activeRecord"/>
+ <element name="checkErrors" tokenid="ooxml:CT_MailMerge_checkErrors"/>
+ <element name="odso" tokenid="ooxml:CT_MailMerge_odso"/>
+ </resource>
+ <resource name="CT_TargetScreenSz" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_TargetScreenSz_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_Compat" resource="Properties">
+ <element name="useSingleBorderforContiguousCells" tokenid="ooxml:CT_Compat_useSingleBorderforContiguousCells"/>
+ <element name="wpJustification" tokenid="ooxml:CT_Compat_wpJustification"/>
+ <element name="noTabHangInd" tokenid="ooxml:CT_Compat_noTabHangInd"/>
+ <element name="noLeading" tokenid="ooxml:CT_Compat_noLeading"/>
+ <element name="spaceForUL" tokenid="ooxml:CT_Compat_spaceForUL"/>
+ <element name="noColumnBalance" tokenid="ooxml:CT_Compat_noColumnBalance"/>
+ <element name="balanceSingleByteDoubleByteWidth" tokenid="ooxml:CT_Compat_balanceSingleByteDoubleByteWidth"/>
+ <element name="noExtraLineSpacing" tokenid="ooxml:CT_Compat_noExtraLineSpacing"/>
+ <element name="doNotLeaveBackslashAlone" tokenid="ooxml:CT_Compat_doNotLeaveBackslashAlone"/>
+ <element name="ulTrailSpace" tokenid="ooxml:CT_Compat_ulTrailSpace"/>
+ <element name="doNotExpandShiftReturn" tokenid="ooxml:CT_Compat_doNotExpandShiftReturn"/>
+ <element name="spacingInWholePoints" tokenid="ooxml:CT_Compat_spacingInWholePoints"/>
+ <element name="lineWrapLikeWord6" tokenid="ooxml:CT_Compat_lineWrapLikeWord6"/>
+ <element name="printBodyTextBeforeHeader" tokenid="ooxml:CT_Compat_printBodyTextBeforeHeader"/>
+ <element name="printColBlack" tokenid="ooxml:CT_Compat_printColBlack"/>
+ <element name="wpSpaceWidth" tokenid="ooxml:CT_Compat_wpSpaceWidth"/>
+ <element name="showBreaksInFrames" tokenid="ooxml:CT_Compat_showBreaksInFrames"/>
+ <element name="subFontBySize" tokenid="ooxml:CT_Compat_subFontBySize"/>
+ <element name="suppressBottomSpacing" tokenid="ooxml:CT_Compat_suppressBottomSpacing"/>
+ <element name="suppressTopSpacing" tokenid="ooxml:CT_Compat_suppressTopSpacing"/>
+ <element name="suppressSpacingAtTopOfPage" tokenid="ooxml:CT_Compat_suppressSpacingAtTopOfPage"/>
+ <element name="suppressTopSpacingWP" tokenid="ooxml:CT_Compat_suppressTopSpacingWP"/>
+ <element name="suppressSpBfAfterPgBrk" tokenid="ooxml:CT_Compat_suppressSpBfAfterPgBrk"/>
+ <element name="swapBordersFacingPages" tokenid="ooxml:CT_Compat_swapBordersFacingPages"/>
+ <element name="convMailMergeEsc" tokenid="ooxml:CT_Compat_convMailMergeEsc"/>
+ <element name="truncateFontHeightsLikeWP6" tokenid="ooxml:CT_Compat_truncateFontHeightsLikeWP6"/>
+ <element name="mwSmallCaps" tokenid="ooxml:CT_Compat_mwSmallCaps"/>
+ <element name="usePrinterMetrics" tokenid="ooxml:CT_Compat_usePrinterMetrics"/>
+ <element name="doNotSuppressParagraphBorders" tokenid="ooxml:CT_Compat_doNotSuppressParagraphBorders"/>
+ <element name="wrapTrailSpaces" tokenid="ooxml:CT_Compat_wrapTrailSpaces"/>
+ <element name="footnoteLayoutLikeWW8" tokenid="ooxml:CT_Compat_footnoteLayoutLikeWW8"/>
+ <element name="shapeLayoutLikeWW8" tokenid="ooxml:CT_Compat_shapeLayoutLikeWW8"/>
+ <element name="alignTablesRowByRow" tokenid="ooxml:CT_Compat_alignTablesRowByRow"/>
+ <element name="forgetLastTabAlignment" tokenid="ooxml:CT_Compat_forgetLastTabAlignment"/>
+ <element name="adjustLineHeightInTable" tokenid="ooxml:CT_Compat_adjustLineHeightInTable"/>
+ <element name="autoSpaceLikeWord95" tokenid="ooxml:CT_Compat_autoSpaceLikeWord95"/>
+ <element name="noSpaceRaiseLower" tokenid="ooxml:CT_Compat_noSpaceRaiseLower"/>
+ <element name="doNotUseHTMLParagraphAutoSpacing" tokenid="ooxml:CT_Compat_doNotUseHTMLParagraphAutoSpacing"/>
+ <element name="layoutRawTableWidth" tokenid="ooxml:CT_Compat_layoutRawTableWidth"/>
+ <element name="layoutTableRowsApart" tokenid="ooxml:CT_Compat_layoutTableRowsApart"/>
+ <element name="useWord97LineBreakRules" tokenid="ooxml:CT_Compat_useWord97LineBreakRules"/>
+ <element name="doNotBreakWrappedTables" tokenid="ooxml:CT_Compat_doNotBreakWrappedTables"/>
+ <element name="doNotSnapToGridInCell" tokenid="ooxml:CT_Compat_doNotSnapToGridInCell"/>
+ <element name="selectFldWithFirstOrLastChar" tokenid="ooxml:CT_Compat_selectFldWithFirstOrLastChar"/>
+ <element name="applyBreakingRules" tokenid="ooxml:CT_Compat_applyBreakingRules"/>
+ <element name="doNotWrapTextWithPunct" tokenid="ooxml:CT_Compat_doNotWrapTextWithPunct"/>
+ <element name="doNotUseEastAsianBreakRules" tokenid="ooxml:CT_Compat_doNotUseEastAsianBreakRules"/>
+ <element name="useWord2002TableStyleRules" tokenid="ooxml:CT_Compat_useWord2002TableStyleRules"/>
+ <element name="growAutofit" tokenid="ooxml:CT_Compat_growAutofit"/>
+ <element name="useFELayout" tokenid="ooxml:CT_Compat_useFELayout"/>
+ <element name="useNormalStyleForList" tokenid="ooxml:CT_Compat_useNormalStyleForList"/>
+ <element name="doNotUseIndentAsNumberingTabStop" tokenid="ooxml:CT_Compat_doNotUseIndentAsNumberingTabStop"/>
+ <element name="useAltKinsokuLineBreakRules" tokenid="ooxml:CT_Compat_useAltKinsokuLineBreakRules"/>
+ <element name="allowSpaceOfSameStyleInTable" tokenid="ooxml:CT_Compat_allowSpaceOfSameStyleInTable"/>
+ <element name="doNotSuppressIndentation" tokenid="ooxml:CT_Compat_doNotSuppressIndentation"/>
+ <element name="doNotAutofitConstrainedTables" tokenid="ooxml:CT_Compat_doNotAutofitConstrainedTables"/>
+ <element name="autofitToFirstFixedWidthCell" tokenid="ooxml:CT_Compat_autofitToFirstFixedWidthCell"/>
+ <element name="underlineTabInNumList" tokenid="ooxml:CT_Compat_underlineTabInNumList"/>
+ <element name="displayHangulFixedWidth" tokenid="ooxml:CT_Compat_displayHangulFixedWidth"/>
+ <element name="splitPgBreakAndParaMark" tokenid="ooxml:CT_Compat_splitPgBreakAndParaMark"/>
+ <element name="doNotVertAlignCellWithSp" tokenid="ooxml:CT_Compat_doNotVertAlignCellWithSp"/>
+ <element name="doNotBreakConstrainedForcedTable" tokenid="ooxml:CT_Compat_doNotBreakConstrainedForcedTable"/>
+ <element name="doNotVertAlignInTxbx" tokenid="ooxml:CT_Compat_doNotVertAlignInTxbx"/>
+ <element name="useAnsiKerningPairs" tokenid="ooxml:CT_Compat_useAnsiKerningPairs"/>
+ <element name="cachedColBalance" tokenid="ooxml:CT_Compat_cachedColBalance"/>
+ <element name="compatSetting" tokenid="ooxml:CT_Compat_compatSetting"/>
+ </resource>
+ <resource name="CT_CompatSetting" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_CompatSetting_name"/>
+ <attribute name="uri" tokenid="ooxml:CT_CompatSetting_uri"/>
+ <attribute name="val" tokenid="ooxml:CT_CompatSetting_val"/>
+ </resource>
+ <resource name="CT_DocVars" resource="Properties">
+ <element name="docVar" tokenid="ooxml:CT_DocVar"/>
+ </resource>
+ <resource name="CT_DocVar" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_DocVar_name"/>
+ <attribute name="val" tokenid="ooxml:CT_DocVar_val"/>
+ </resource>
+ <resource name="CT_DocRsids" resource="Properties">
+ <element name="rsidRoot" tokenid="ooxml:CT_DocRsids_rsidRoot"/>
+ <element name="rsid" tokenid="ooxml:CT_DocRsids_rsid"/>
+ </resource>
+ <resource name="CT_CharacterSpacing" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_CharacterSpacing_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_SaveThroughXslt" resource="Properties">
+ <attribute name="r:id" tokenid="ooxml:CT_SaveThroughXslt_r_id"/>
+ <attribute name="solutionID" tokenid="ooxml:CT_SaveThroughXslt_solutionID"/>
+ </resource>
+ <resource name="CT_RPrDefault" resource="Properties">
+ <element name="rPr" tokenid="ooxml:CT_RPrDefault_rPr"/>
+ </resource>
+ <resource name="CT_PPrDefault" resource="Properties">
+ <element name="pPr" tokenid="ooxml:CT_PPrDefault_pPr"/>
+ </resource>
+ <resource name="CT_DocDefaults" resource="Properties">
+ <element name="pPrDefault" tokenid="ooxml:CT_DocDefaults_pPrDefault"/>
+ <element name="rPrDefault" tokenid="ooxml:CT_DocDefaults_rPrDefault"/>
+ </resource>
+ <resource name="CT_LatentStyles" resource="Properties">
+ <attribute name="defLockedState" tokenid="ooxml:CT_LatentStyles_defLockedState"/>
+ <attribute name="defUIPriority" tokenid="ooxml:CT_LatentStyles_defUIPriority"/>
+ <attribute name="defSemiHidden" tokenid="ooxml:CT_LatentStyles_defSemiHidden"/>
+ <attribute name="defUnhideWhenUsed" tokenid="ooxml:CT_LatentStyles_defUnhideWhenUsed"/>
+ <attribute name="defQFormat" tokenid="ooxml:CT_LatentStyles_defQFormat"/>
+ <attribute name="count" tokenid="ooxml:CT_LatentStyles_count"/>
+ <element name="lsdException" tokenid="ooxml:CT_LatentStyles_lsdException"/>
+ </resource>
+ <resource name="CT_LsdException" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_LsdException_name"/>
+ <attribute name="locked" tokenid="ooxml:CT_LsdException_locked"/>
+ <attribute name="uiPriority" tokenid="ooxml:CT_LsdException_uiPriority"/>
+ <attribute name="semiHidden" tokenid="ooxml:CT_LsdException_semiHidden"/>
+ <attribute name="unhideWhenUsed" tokenid="ooxml:CT_LsdException_unhideWhenUsed"/>
+ <attribute name="qFormat" tokenid="ooxml:CT_LsdException_qFormat"/>
+ </resource>
+ <resource name="ST_ColorSchemeIndex" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_dark1">dark1</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_light1">light1</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_dark2">dark2</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_light2">light2</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent1">accent1</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent2">accent2</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent3">accent3</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent4">accent4</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent5">accent5</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_accent6">accent6</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_hyperlink">hyperlink</value>
+ <value tokenid="ooxml:Value_doc_ST_ColorSchemeIndex_followedHyperlink">followedHyperlink</value>
+ </resource>
+ <resource name="CT_ReadingModeInkLockDown" resource="Properties">
+ <attribute name="actualPg" tokenid="ooxml:CT_ReadingModeInkLockDown_actualPg"/>
+ <attribute name="w" tokenid="ooxml:CT_ReadingModeInkLockDown_w"/>
+ <attribute name="h" tokenid="ooxml:CT_ReadingModeInkLockDown_h"/>
+ <attribute name="fontSz" tokenid="ooxml:CT_ReadingModeInkLockDown_fontSz"/>
+ </resource>
+ <resource name="CT_WriteProtection" resource="Properties">
+ <attribute name="recommended" tokenid="ooxml:CT_WriteProtection_recommended"/>
+ </resource>
+ <resource name="CT_Settings" resource="PropertyTable" tokenid="ooxml:SETTINGS">
+ <element name="writeProtection" tokenid="ooxml:CT_Settings_writeProtection"/>
+ <element name="view" tokenid="ooxml:CT_Settings_view"/>
+ <element name="zoom" tokenid="ooxml:CT_Settings_zoom"/>
+ <element name="removePersonalInformation" tokenid="ooxml:CT_Settings_removePersonalInformation"/>
+ <element name="removeDateAndTime" tokenid="ooxml:CT_Settings_removeDateAndTime"/>
+ <element name="doNotDisplayPageBoundaries" tokenid="ooxml:CT_Settings_doNotDisplayPageBoundaries"/>
+ <element name="displayBackgroundShape" tokenid="ooxml:CT_Settings_displayBackgroundShape"/>
+ <element name="printPostScriptOverText" tokenid="ooxml:CT_Settings_printPostScriptOverText"/>
+ <element name="printFractionalCharacterWidth" tokenid="ooxml:CT_Settings_printFractionalCharacterWidth"/>
+ <element name="printFormsData" tokenid="ooxml:CT_Settings_printFormsData"/>
+ <element name="embedTrueTypeFonts" tokenid="ooxml:CT_Settings_embedTrueTypeFonts"/>
+ <element name="embedSystemFonts" tokenid="ooxml:CT_Settings_embedSystemFonts"/>
+ <element name="saveSubsetFonts" tokenid="ooxml:CT_Settings_saveSubsetFonts"/>
+ <element name="saveFormsData" tokenid="ooxml:CT_Settings_saveFormsData"/>
+ <element name="mirrorMargins" tokenid="ooxml:CT_Settings_mirrorMargins"/>
+ <element name="alignBordersAndEdges" tokenid="ooxml:CT_Settings_alignBordersAndEdges"/>
+ <element name="bordersDoNotSurroundHeader" tokenid="ooxml:CT_Settings_bordersDoNotSurroundHeader"/>
+ <element name="bordersDoNotSurroundFooter" tokenid="ooxml:CT_Settings_bordersDoNotSurroundFooter"/>
+ <element name="gutterAtTop" tokenid="ooxml:CT_Settings_gutterAtTop"/>
+ <element name="hideSpellingErrors" tokenid="ooxml:CT_Settings_hideSpellingErrors"/>
+ <element name="hideGrammaticalErrors" tokenid="ooxml:CT_Settings_hideGrammaticalErrors"/>
+ <element name="activeWritingStyle" tokenid="ooxml:CT_Settings_activeWritingStyle"/>
+ <element name="proofState" tokenid="ooxml:CT_Settings_proofState"/>
+ <element name="formsDesign" tokenid="ooxml:CT_Settings_formsDesign"/>
+ <element name="attachedTemplate" tokenid="ooxml:CT_Settings_attachedTemplate"/>
+ <element name="linkStyles" tokenid="ooxml:CT_Settings_linkStyles"/>
+ <element name="stylePaneFormatFilter" tokenid="ooxml:CT_Settings_stylePaneFormatFilter"/>
+ <element name="stylePaneSortMethod" tokenid="ooxml:CT_Settings_stylePaneSortMethod"/>
+ <element name="documentType" tokenid="ooxml:CT_Settings_documentType"/>
+ <element name="mailMerge" tokenid="ooxml:CT_Settings_mailMerge"/>
+ <element name="revisionView" tokenid="ooxml:CT_Settings_revisionView"/>
+ <element name="trackRevisions" tokenid="ooxml:CT_Settings_trackRevisions"/>
+ <element name="doNotTrackMoves" tokenid="ooxml:CT_Settings_doNotTrackMoves"/>
+ <element name="doNotTrackFormatting" tokenid="ooxml:CT_Settings_doNotTrackFormatting"/>
+ <element name="documentProtection" tokenid="ooxml:CT_Settings_documentProtection"/>
+ <element name="autoFormatOverride" tokenid="ooxml:CT_Settings_autoFormatOverride"/>
+ <element name="styleLockTheme" tokenid="ooxml:CT_Settings_styleLockTheme"/>
+ <element name="styleLockQFSet" tokenid="ooxml:CT_Settings_styleLockQFSet"/>
+ <element name="defaultTabStop" tokenid="ooxml:CT_Settings_defaultTabStop"/>
+ <element name="autoHyphenation" tokenid="ooxml:CT_Settings_autoHyphenation"/>
+ <element name="consecutiveHyphenLimit" tokenid="ooxml:CT_Settings_consecutiveHyphenLimit"/>
+ <element name="hyphenationZone" tokenid="ooxml:CT_Settings_hyphenationZone"/>
+ <element name="doNotHyphenateCaps" tokenid="ooxml:CT_Settings_doNotHyphenateCaps"/>
+ <element name="showEnvelope" tokenid="ooxml:CT_Settings_showEnvelope"/>
+ <element name="summaryLength" tokenid="ooxml:CT_Settings_summaryLength"/>
+ <element name="clickAndTypeStyle" tokenid="ooxml:CT_Settings_clickAndTypeStyle"/>
+ <element name="defaultTableStyle" tokenid="ooxml:CT_Settings_defaultTableStyle"/>
+ <element name="evenAndOddHeaders" tokenid="ooxml:CT_Settings_evenAndOddHeaders"/>
+ <element name="bookFoldRevPrinting" tokenid="ooxml:CT_Settings_bookFoldRevPrinting"/>
+ <element name="bookFoldPrinting" tokenid="ooxml:CT_Settings_bookFoldPrinting"/>
+ <element name="bookFoldPrintingSheets" tokenid="ooxml:CT_Settings_bookFoldPrintingSheets"/>
+ <element name="drawingGridHorizontalSpacing" tokenid="ooxml:CT_Settings_drawingGridHorizontalSpacing"/>
+ <element name="drawingGridVerticalSpacing" tokenid="ooxml:CT_Settings_drawingGridVerticalSpacing"/>
+ <element name="displayHorizontalDrawingGridEvery" tokenid="ooxml:CT_Settings_displayHorizontalDrawingGridEvery"/>
+ <element name="displayVerticalDrawingGridEvery" tokenid="ooxml:CT_Settings_displayVerticalDrawingGridEvery"/>
+ <element name="doNotUseMarginsForDrawingGridOrigin" tokenid="ooxml:CT_Settings_doNotUseMarginsForDrawingGridOrigin"/>
+ <element name="drawingGridHorizontalOrigin" tokenid="ooxml:CT_Settings_drawingGridHorizontalOrigin"/>
+ <element name="drawingGridVerticalOrigin" tokenid="ooxml:CT_Settings_drawingGridVerticalOrigin"/>
+ <element name="doNotShadeFormData" tokenid="ooxml:CT_Settings_doNotShadeFormData"/>
+ <element name="noPunctuationKerning" tokenid="ooxml:CT_Settings_noPunctuationKerning"/>
+ <element name="characterSpacingControl" tokenid="ooxml:CT_Settings_characterSpacingControl"/>
+ <element name="printTwoOnOne" tokenid="ooxml:CT_Settings_printTwoOnOne"/>
+ <element name="strictFirstAndLastChars" tokenid="ooxml:CT_Settings_strictFirstAndLastChars"/>
+ <element name="noLineBreaksAfter" tokenid="ooxml:CT_Settings_noLineBreaksAfter"/>
+ <element name="noLineBreaksBefore" tokenid="ooxml:CT_Settings_noLineBreaksBefore"/>
+ <element name="savePreviewPicture" tokenid="ooxml:CT_Settings_savePreviewPicture"/>
+ <element name="doNotValidateAgainstSchema" tokenid="ooxml:CT_Settings_doNotValidateAgainstSchema"/>
+ <element name="saveInvalidXml" tokenid="ooxml:CT_Settings_saveInvalidXml"/>
+ <element name="ignoreMixedContent" tokenid="ooxml:CT_Settings_ignoreMixedContent"/>
+ <element name="alwaysShowPlaceholderText" tokenid="ooxml:CT_Settings_alwaysShowPlaceholderText"/>
+ <element name="doNotDemarcateInvalidXml" tokenid="ooxml:CT_Settings_doNotDemarcateInvalidXml"/>
+ <element name="saveXmlDataOnly" tokenid="ooxml:CT_Settings_saveXmlDataOnly"/>
+ <element name="useXSLTWhenSaving" tokenid="ooxml:CT_Settings_useXSLTWhenSaving"/>
+ <element name="saveThroughXslt" tokenid="ooxml:CT_Settings_saveThroughXslt"/>
+ <element name="showXMLTags" tokenid="ooxml:CT_Settings_showXMLTags"/>
+ <element name="alwaysMergeEmptyNamespace" tokenid="ooxml:CT_Settings_alwaysMergeEmptyNamespace"/>
+ <element name="updateFields" tokenid="ooxml:CT_Settings_updateFields"/>
+ <element name="hdrShapeDefaults" tokenid="ooxml:CT_Settings_hdrShapeDefaults"/>
+ <element name="footnotePr" tokenid="ooxml:CT_Settings_footnotePr"/>
+ <element name="endnotePr" tokenid="ooxml:CT_Settings_endnotePr"/>
+ <element name="compat" tokenid="ooxml:CT_Settings_compat"/>
+ <element name="docVars" tokenid="ooxml:CT_Settings_docVars"/>
+ <element name="rsids" tokenid="ooxml:CT_Settings_rsids"/>
+ <element name="uiCompat97To2003" tokenid="ooxml:CT_Settings_uiCompat97To2003"/>
+ <element name="attachedSchema" tokenid="ooxml:CT_Settings_attachedSchema"/>
+ <element name="themeFontLang" tokenid="ooxml:CT_Settings_themeFontLang"/>
+ <element name="clrSchemeMapping" tokenid="ooxml:CT_Settings_clrSchemeMapping"/>
+ <element name="doNotIncludeSubdocsInStats" tokenid="ooxml:CT_Settings_doNotIncludeSubdocsInStats"/>
+ <element name="doNotAutoCompressPictures" tokenid="ooxml:CT_Settings_doNotAutoCompressPictures"/>
+ <element name="forceUpgrade" tokenid="ooxml:CT_Settings_forceUpgrade"/>
+ <element name="captions" tokenid="ooxml:CT_Settings_captions"/>
+ <element name="readModeInkLockDown" tokenid="ooxml:CT_Settings_readModeInkLockDown"/>
+ <element name="smartTagType" tokenid="ooxml:CT_Settings_smartTagType"/>
+ <element name="shapeDefaults" tokenid="ooxml:CT_Settings_shapeDefaults"/>
+ <element name="doNotEmbedSmartTags" tokenid="ooxml:CT_Settings_doNotEmbedSmartTags"/>
+ <element name="decimalSymbol" tokenid="ooxml:CT_Settings_decimalSymbol"/>
+ <element name="listSeparator" tokenid="ooxml:CT_Settings_listSeparator"/>
+ </resource>
+ <resource name="CT_FrameScrollbar" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FrameScrollbar_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_FrameLayout" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FrameLayout_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_LevelSuffix" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_LevelSuffix_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_LevelText" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_LevelText_val"/>
+ <attribute name="null" tokenid="ooxml:CT_LevelText_null"/>
+ </resource>
+ <resource name="CT_LvlLegacy" resource="Properties">
+ <attribute name="legacy" tokenid="ooxml:CT_LvlLegacy_legacy"/>
+ <attribute name="legacySpace" tokenid="ooxml:CT_LvlLegacy_legacySpace"/>
+ <attribute name="legacyIndent" tokenid="ooxml:CT_LvlLegacy_legacyIndent"/>
+ </resource>
+ <resource name="CT_Lvl" resource="Properties">
+ <element name="start" tokenid="ooxml:CT_Lvl_start"/>
+ <element name="numFmt" tokenid="ooxml:CT_Lvl_numFmt"/>
+ <element name="lvlRestart" tokenid="ooxml:CT_Lvl_lvlRestart"/>
+ <element name="pStyle" tokenid="ooxml:CT_Lvl_pStyle"/>
+ <element name="isLgl" tokenid="ooxml:CT_Lvl_isLgl"/>
+ <element name="suff" tokenid="ooxml:CT_Lvl_suff"/>
+ <element name="lvlText" tokenid="ooxml:CT_Lvl_lvlText"/>
+ <element name="lvlPicBulletId" tokenid="ooxml:CT_Lvl_lvlPicBulletId"/>
+ <element name="legacy" tokenid="ooxml:CT_Lvl_legacy"/>
+ <element name="lvlJc" tokenid="ooxml:CT_Lvl_lvlJc"/>
+ <element name="pPr" tokenid="ooxml:CT_Lvl_pPr"/>
+ <element name="rPr" tokenid="ooxml:CT_Lvl_rPr"/>
+ <attribute name="ilvl" tokenid="ooxml:CT_Lvl_ilvl"/>
+ <attribute name="tplc" tokenid="ooxml:CT_Lvl_tplc"/>
+ <attribute name="tentative" tokenid="ooxml:CT_Lvl_tentative"/>
+ </resource>
+ <resource name="ST_MultiLevelType" resource="List">
+ <value tokenid="ooxml:Value_ST_MultiLevelType_singleLevel">singleLevel</value>
+ <value tokenid="ooxml:Value_ST_MultiLevelType_multilevel">multilevel</value>
+ <value tokenid="ooxml:Value_ST_MultiLevelType_hybridMultilevel">hybridMultilevel</value>
+ </resource>
+ <resource name="CT_MultiLevelType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_MultiLevelType_val" action="setValue"/>
+ </resource>
+ <resource name="CT_NumPicBullet" resource="Properties">
+ <element name="pict" tokenid="ooxml:CT_NumPicBullet_pict"/>
+ <attribute name="numPicBulletId" tokenid="ooxml:CT_NumPicBullet_numPicBulletId"/>
+ </resource>
+ <resource name="CT_AbstractNum" resource="Properties">
+ <element name="nsid" tokenid="ooxml:CT_AbstractNum_nsid"/>
+ <element name="multiLevelType" tokenid="ooxml:CT_AbstractNum_multiLevelType"/>
+ <element name="tmpl" tokenid="ooxml:CT_AbstractNum_tmpl"/>
+ <element name="name" tokenid="ooxml:CT_AbstractNum_name"/>
+ <element name="styleLink" tokenid="ooxml:CT_AbstractNum_styleLink"/>
+ <element name="numStyleLink" tokenid="ooxml:CT_AbstractNum_numStyleLink"/>
+ <element name="lvl" tokenid="ooxml:CT_AbstractNum_lvl"/>
+ <attribute name="abstractNumId" tokenid="ooxml:CT_AbstractNum_abstractNumId"/>
+ </resource>
+ <resource name="CT_NumLvl" resource="Properties">
+ <element name="startOverride" tokenid="ooxml:CT_NumLvl_startOverride"/>
+ <element name="lvl" tokenid="ooxml:CT_NumLvl_lvl"/>
+ <attribute name="ilvl" tokenid="ooxml:CT_NumLvl_ilvl"/>
+ </resource>
+ <resource name="CT_Num" resource="Properties">
+ <element name="abstractNumId" tokenid="ooxml:CT_Num_abstractNumId"/>
+ <element name="lvlOverride" tokenid="ooxml:CT_Num_lvlOverride"/>
+ <attribute name="numId" tokenid="ooxml:CT_Num_numId"/>
+ </resource>
+ <resource name="CT_Numbering" resource="PropertyTable" tokenid="ooxml:NUMBERING">
+ <element name="numPicBullet" tokenid="ooxml:CT_Numbering_numPicBullet"/>
+ <element name="abstractNum" tokenid="ooxml:CT_Numbering_abstractNum"/>
+ <element name="num" tokenid="ooxml:CT_Numbering_num"/>
+ <element name="numIdMacAtCleanup" tokenid="ooxml:CT_Numbering_numIdMacAtCleanup"/>
+ </resource>
+ <resource name="ST_TblStyleOverrideType" resource="List">
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_wholeTable">wholeTable</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_firstRow">firstRow</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_lastRow">lastRow</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_firstCol">firstCol</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_lastCol">lastCol</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band1Vert">band1Vert</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band2Vert">band2Vert</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band1Horz">band1Horz</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_band2Horz">band2Horz</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_neCell">neCell</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_nwCell">nwCell</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_seCell">seCell</value>
+ <value tokenid="ooxml:Value_ST_TblStyleOverrideType_swCell">swCell</value>
+ </resource>
+ <resource name="CT_Style_tblStylePr" resource="Properties">
+ <element name="pPr" tokenid="ooxml:CT_PPrBase"/>
+ <element name="rPr" tokenid="ooxml:EG_RPrBase"/>
+ <element name="tblPr" tokenid="ooxml:CT_TblPrBase"/>
+ <element name="trPr" tokenid="ooxml:CT_TrPrBase"/>
+ <element name="tcPr" tokenid="ooxml:CT_TcPrBase"/>
+ <attribute name="type" tokenid="ooxml:CT_TblStyleOverrideType"/>
+ </resource>
+ <resource name="ST_StyleType" resource="List">
+ <value tokenid="ooxml:Value_ST_StyleType_paragraph">paragraph</value>
+ <value tokenid="ooxml:Value_ST_StyleType_character">character</value>
+ <value tokenid="ooxml:Value_ST_StyleType_table">table</value>
+ <value tokenid="ooxml:Value_ST_StyleType_numbering">numbering</value>
+ </resource>
+ <resource name="CT_Style" resource="Properties">
+ <element name="name" tokenid="ooxml:CT_Style_name"/>
+ <element name="aliases" tokenid="ooxml:CT_Style_aliases"/>
+ <element name="basedOn" tokenid="ooxml:CT_Style_basedOn"/>
+ <element name="next" tokenid="ooxml:CT_Style_next"/>
+ <element name="link" tokenid="ooxml:CT_Style_link"/>
+ <element name="autoRedefine" tokenid="ooxml:CT_Style_autoRedefine"/>
+ <element name="hidden" tokenid="ooxml:CT_Style_hidden"/>
+ <element name="uiPriority" tokenid="ooxml:CT_Style_uiPriority"/>
+ <element name="semiHidden" tokenid="ooxml:CT_Style_semiHidden"/>
+ <element name="unhideWhenUsed" tokenid="ooxml:CT_Style_unhideWhenUsed"/>
+ <element name="qFormat" tokenid="ooxml:CT_Style_qFormat"/>
+ <element name="locked" tokenid="ooxml:CT_Style_locked"/>
+ <element name="personal" tokenid="ooxml:CT_Style_personal"/>
+ <element name="personalCompose" tokenid="ooxml:CT_Style_personalCompose"/>
+ <element name="personalReply" tokenid="ooxml:CT_Style_personalReply"/>
+ <element name="rsid" tokenid="ooxml:CT_Style_rsid"/>
+ <element name="pPr" tokenid="ooxml:CT_Style_pPr"/>
+ <element name="rPr" tokenid="ooxml:CT_Style_rPr"/>
+ <element name="tblPr" tokenid="ooxml:CT_Style_tblPr"/>
+ <element name="trPr" tokenid="ooxml:CT_Style_trPr"/>
+ <element name="tcPr" tokenid="ooxml:CT_Style_tcPr"/>
+ <element name="tblStylePr" tokenid="ooxml:CT_Style_tblStylePr"/>
+ <attribute name="type" tokenid="ooxml:CT_Style_type"/>
+ <attribute name="styleId" tokenid="ooxml:CT_Style_styleId"/>
+ <attribute name="default" tokenid="ooxml:CT_Style_default"/>
+ <attribute name="customStyle" tokenid="ooxml:CT_Style_customStyle"/>
+ </resource>
+ <resource name="CT_Styles" resource="Table" tokenid="ooxml:STYLESHEET"/>
+ <resource name="ST_Panose" resource="Hex"/>
+ <resource name="CT_Panose" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_Panose_val" action="setValue"/>
+ <action name="start" action="setDefaultHexValue"/>
+ </resource>
+ <resource name="CT_Charset" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Charset_val"/>
+ <attribute name="characterSet" tokenid="ooxml:CT_Charset_characterSet"/>
+ </resource>
+ <resource name="ST_FontFamily" resource="List">
+ <value tokenid="ooxml:Value_ST_FontFamily_decorative">decorative</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_modern">modern</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_roman">roman</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_script">script</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_swiss">swiss</value>
+ <value tokenid="ooxml:Value_ST_FontFamily_auto">auto</value>
+ </resource>
+ <resource name="CT_FontFamily" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_FontFamily_val" action="setValue"/>
+ </resource>
+ <resource name="ST_Pitch" resource="List">
+ <value tokenid="ooxml:Value_ST_Pitch_fixed">fixed</value>
+ <value tokenid="ooxml:Value_ST_Pitch_variable">variable</value>
+ <value tokenid="ooxml:Value_ST_Pitch_default">default</value>
+ </resource>
+ <resource name="CT_Pitch" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_Pitch_val"/>
+ </resource>
+ <resource name="CT_FontSig" resource="Properties">
+ <attribute name="usb0" tokenid="ooxml:CT_FontSig_usb0"/>
+ <attribute name="usb1" tokenid="ooxml:CT_FontSig_usb1"/>
+ <attribute name="usb2" tokenid="ooxml:CT_FontSig_usb2"/>
+ <attribute name="usb3" tokenid="ooxml:CT_FontSig_usb3"/>
+ <attribute name="csb0" tokenid="ooxml:CT_FontSig_csb0"/>
+ <attribute name="csb1" tokenid="ooxml:CT_FontSig_csb1"/>
+ </resource>
+ <resource name="CT_FontRel" resource="Properties">
+ <attribute name="fontKey" tokenid="ooxml:CT_FontRel_fontKey"/>
+ <attribute name="subsetted" tokenid="ooxml:CT_FontRel_subsetted"/>
+ <action name="start" action="handleFontRel"/>
+ </resource>
+ <resource name="CT_Font" resource="Properties">
+ <element name="altName" tokenid="ooxml:CT_Font_altName"/>
+ <element name="panose1" tokenid="ooxml:CT_Font_panose1"/>
+ <element name="charset" tokenid="ooxml:CT_Font_charset"/>
+ <element name="characterSet" tokenid="ooxml:CT_Font_characterSet"/>
+ <element name="family" tokenid="ooxml:CT_Font_family"/>
+ <element name="notTrueType" tokenid="ooxml:CT_Font_notTrueType"/>
+ <element name="pitch" tokenid="ooxml:CT_Font_pitch"/>
+ <element name="sig" tokenid="ooxml:CT_Font_sig"/>
+ <element name="embedRegular" tokenid="ooxml:CT_Font_embedRegular"/>
+ <element name="embedBold" tokenid="ooxml:CT_Font_embedBold"/>
+ <element name="embedItalic" tokenid="ooxml:CT_Font_embedItalic"/>
+ <element name="embedBoldItalic" tokenid="ooxml:CT_Font_embedBoldItalic"/>
+ <attribute name="name" tokenid="ooxml:CT_Font_name"/>
+ </resource>
+ <resource name="CT_FontsList" resource="Table" tokenid="ooxml:FONTTABLE"/>
+ <resource name="EG_BlockLevelElts" resource="Properties">
+ <attribute name="name" tokenid="ooxml:EG_BlockLevelElts_altChunk"/>
+ </resource>
+ <resource name="EG_RunLevelElts" resource="Stream">
+ <element name="proofErr" tokenid="ooxml:EG_RunLevelElts_proofErr"/>
+ <element name="permStart" tokenid="ooxml:EG_RunLevelElts_permStart"/>
+ <element name="permEnd" tokenid="ooxml:EG_RunLevelElts_permEnd"/>
+ <element name="ins" tokenid="ooxml:EG_RunLevelElts_ins"/>
+ <element name="del" tokenid="ooxml:EG_RunLevelElts_del"/>
+ <element name="moveFrom" tokenid="ooxml:EG_RunLevelElts_moveFrom"/>
+ <element name="moveTo" tokenid="ooxml:EG_RunLevelElts_moveTo"/>
+ </resource>
+ <resource name="CT_Body" resource="Stream">
+ <action name="start" action="startSectionGroup"/>
+ <!--
+ <action name="start" action="footnoteSeparator"/>
+ <action name="start" action="footnoteCont"/>
+ <action name="start" action="endnoteSeparator"/>
+ <action name="start" action="endnoteCont"/>
+ -->
+ <action name="end" action="endCharacterGroup"/>
+ <action name="end" action="endParagraphGroup"/>
+ <action name="end" action="setLastSectionGroup"/>
+ <action name="end" action="endSectionGroup"/>
+ </resource>
+ <resource name="CT_ShapeDefaults" resource="Properties">
+ <element name="v:fill" tokenid="ooxml:CT_ShapeDefaults_v_fill"/>
+ <element name="v:stroke" tokenid="ooxml:CT_ShapeDefaults_v_stroke"/>
+ <element name="v:textbox" tokenid="ooxml:CT_ShapeDefaults_v_textbox"/>
+ <element name="v:shadow" tokenid="ooxml:CT_ShapeDefaults_v_shadow"/>
+ <element name="colormru" tokenid="ooxml:CT_ShapeDefaults_colormru"/>
+ <element name="colormenu" tokenid="ooxml:CT_ShapeDefaults_colormenu"/>
+ <attribute name="spidmax" tokenid="ooxml:CT_ShapeDefaults_spidmax"/>
+ <attribute name="style" tokenid="ooxml:CT_ShapeDefaults_style"/>
+ <attribute name="fill" tokenid="ooxml:CT_ShapeDefaults_fill"/>
+ <attribute name="fillcolor" tokenid="ooxml:CT_ShapeDefaults_fillcolor"/>
+ <attribute name="stroke" tokenid="ooxml:CT_ShapeDefaults_stroke"/>
+ <attribute name="strokecolor" tokenid="ooxml:CT_ShapeDefaults_strokecolor"/>
+ <attribute name="allowincell" tokenid="ooxml:CT_ShapeDefaults_allowincell"/>
+ </resource>
+ <resource name="CT_Comments" resource="Stream">
+ <action name="start" action="startSectionGroup"/>
+ <action name="end" action="endSectionGroup"/>
+ </resource>
+ <resource name="CT_Footnotes" resource="Stream"/>
+ <resource name="footnotes" resource="Stream"/>
+ <resource name="CT_Endnotes" resource="Stream"/>
+ <resource name="endnotes" resource="Stream"/>
+ <resource name="CT_SmartTagType" resource="Properties">
+ <attribute name="namespaceuri" tokenid="ooxml:CT_SmartTagType_namespaceuri"/>
+ <attribute name="name" tokenid="ooxml:CT_SmartTagType_name"/>
+ <attribute name="url" tokenid="ooxml:CT_SmartTagType_url"/>
+ </resource>
+ <resource name="ST_ThemeColor" resource="List">
+ <value tokenid="ooxml:Value_St_ThemeColor_dark1">dark1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_light1">light1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_dark2">dark2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_light2">light2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent1">accent1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent2">accent2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent3">accent3</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent4">accent4</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent5">accent5</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_accent6">accent6</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_hyperlink">hyperlink</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_followedHyperlink">followedHyperlink</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_none">none</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_background1">background1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_text1">text1</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_background2">background2</value>
+ <value tokenid="ooxml:Value_St_ThemeColor_text2">text2</value>
+ </resource>
+ <resource name="CT_DocPartBehavior" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DocPartBehavior_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_DocPartType" resource="Value">
+ <attribute name="val" tokenid="ooxml:CT_DocPartType_val" action="setValue"/>
+ <action name="start" action="setDefaultStringValue"/>
+ </resource>
+ <resource name="CT_DocPartGallery" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_DocPartGallery_val"/>
+ </resource>
+ <resource name="CT_DocPartName" resource="Properties">
+ <attribute name="val" tokenid="ooxml:CT_DocPartName_val"/>
+ <attribute name="decorated" tokenid="ooxml:CT_DocPartName_decorated"/>
+ </resource>
+ <resource name="settings" resource="Stream">
+ <element name="settings" tokenid="ooxml:settings_settings"/>
+ </resource>
+ <resource name="fonts" resource="Stream">
+ <element name="fonts" tokenid="ooxml:FONTTABLE"/>
+ </resource>
+ <resource name="numbering" resource="Stream">
+ <element name="numbering" tokenid="ooxml:NUMBERING"/>
+ </resource>
+ <resource name="styles" resource="Stream">
+ <element name="styles" tokenid="ooxml:STYLESHEET"/>
+ </resource>
+ <resource name="ST_CaptionPos" resource="List">
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_above">above</value>
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_below">below</value>
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_left">left</value>
+ <value tokenid="ooxml:Value_doc_ST_CaptionPos_right">right</value>
+ </resource>
+ <resource name="CT_Caption" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_Caption_name"/>
+ <attribute name="pos" tokenid="ooxml:CT_Caption_pos"/>
+ <attribute name="chapNum" tokenid="ooxml:CT_Caption_chapNum"/>
+ <attribute name="heading" tokenid="ooxml:CT_Caption_heading"/>
+ <attribute name="noLabel" tokenid="ooxml:CT_Caption_noLabel"/>
+ <attribute name="numFmt" tokenid="ooxml:CT_Caption_numFmt"/>
+ <attribute name="sep" tokenid="ooxml:CT_Caption_sep"/>
+ </resource>
+ <resource name="CT_AutoCaption" resource="Properties">
+ <attribute name="name" tokenid="ooxml:CT_AutoCaption_name"/>
+ <attribute name="caption" tokenid="ooxml:CT_AutoCaption_caption"/>
+ </resource>
+ <resource name="CT_AutoCaptions" resource="Properties">
+ <element name="autoCaption" tokenid="ooxml:CT_AutoCaptions_autoCaption"/>
+ </resource>
+ <resource name="CT_Captions" resource="Properties">
+ <element name="caption" tokenid="ooxml:CT_Captions_caption"/>
+ <element name="autoCaptions" tokenid="ooxml:CT_Captions_autoCaptions"/>
+ </resource>
+ <resource name="CT_DocumentBase" resource="Properties">
+ <element name="background" tokenid="ooxml:CT_DocumentBase_background"/>
+ </resource>
+ <resource name="CT_Document" resource="Stream"/>
+ <resource name="CT_GlossaryDocument" resource="Stream"/>
+ <resource name="CT_DocParts" resource="Stream"/>
+ <resource name="CT_DocPart" resource="Stream">
+ <action name="start" action="startGlossaryEntry"/>
+ <action name="end" action="endGlossaryEntry"/>
+ </resource>
+ <resource name="CT_DocPartPr" resource="Properties">
+ <action name="start" action="startSectionGroup"/>
+ <element name="name" tokenid="ooxml:CT_DocPartPr_name"/>
+ <element name="category" tokenid="ooxml:CT_DocPartPr_category"/>
+ </resource>
+ <resource name="CT_DocPartCategory" resource="Properties">
+ <element name="gallery" tokenid="ooxml:CT_DocPartCategory_gallery"/>
+ </resource>
+ <resource name="document" resource="Stream"/>
+ <resource name="glossaryDocument" resource="Stream"/>
+ <resource name="CT_TxbxContent" resource="Stream">
+ <action name="start" action="startTxbxContent"/>
+ <action name="end" action="endTxbxContent"/>
+ </resource>
+ <resource name="CT_OMath" resource="Math"/>
+ <resource name="CT_OMathPara" resource="Stream"/>
+ <resource name="CT_OMathParaPr" resource="Properties"/>
+ <resource name="CT_OMathJc" resource="Value"/>
+ </namespace>
+</model>
+<!-- vim: shiftwidth=2 softtabstop=2 expandtab:
+-->
diff --git a/sw/source/writerfilter/ooxml/modelpreprocess.py b/sw/source/writerfilter/ooxml/modelpreprocess.py
new file mode 100644
index 000000000000..d6ef4c175430
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/ooxml/qnametostr.py b/sw/source/writerfilter/ooxml/qnametostr.py
new file mode 100644
index 000000000000..e09a98570111
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/ooxml/resourceids.py b/sw/source/writerfilter/ooxml/resourceids.py
new file mode 100644
index 000000000000..70325c9d376b
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/ooxml/tox.ini b/sw/source/writerfilter/ooxml/tox.ini
new file mode 100644
index 000000000000..c1781905c427
--- /dev/null
+++ b/sw/source/writerfilter/ooxml/tox.ini
@@ -0,0 +1,2 @@
+[pycodestyle]
+ignore = E501
diff --git a/sw/source/writerfilter/rtftok/README b/sw/source/writerfilter/rtftok/README
new file mode 100644
index 000000000000..a23b40ece4fb
--- /dev/null
+++ b/sw/source/writerfilter/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' sw/source/writerfilter/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/sw/source/writerfilter/rtftok/rtfcharsets.cxx b/sw/source/writerfilter/rtftok/rtfcharsets.cxx
new file mode 100644
index 000000000000..1b71bbb9951c
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfcharsets.cxx
@@ -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/.
+ */
+
+#include "rtfcharsets.hxx"
+
+#include <iterator>
+
+#include <rtl/textenc.h>
+
+namespace writerfilter::rtftok
+{
+// See RTF spec v1.9.1, page 19
+RTFEncoding const aRTFEncodings[] = {
+ // charset codepage Windows / Mac name
+ { 0, 1252 }, // ANSI
+ { 1, 0 }, // Default
+ { 2, 42 }, // Symbol
+ { 77, 10000 }, // Mac Roman
+ { 78, 10001 }, // Mac Shift Jis
+ { 79, 10003 }, // Mac Hangul
+ { 80, 10008 }, // Mac GB2312
+ { 81, 10002 }, // Mac Big5
+ { 83, 10005 }, // Mac Herbrew
+ { 84, 10004 }, // Mac Arabic
+ { 85, 10006 }, // Mac Greek
+ { 86, 10081 }, // Mac Turkish
+ { 87, 10021 }, // Mac Thai
+ { 88, 10029 }, // Mac East Europe
+ { 89, 10007 }, // Mac Russian
+ { 128, 932 }, // Shift JIS
+ { 129, 949 }, // Hangul
+ { 130, 1361 }, // Johab
+ { 134, 936 }, // GB2312
+ { 136, 950 }, // Big5
+ { 161, 1253 }, // Greek
+ { 162, 1254 }, // Turkish
+ { 163, 1258 }, // Vietnamese
+ { 177, 1255 }, // Herbrew
+ { 178, 1256 }, // Arabic
+ { 186, 1257 }, // Baltic
+ { 204, 1251 }, // Russian
+ { 222, 874 }, // Thai
+ { 238, 1250 }, // Eastern European
+ { 254, 437 }, // PC 437
+ { 255, 850 }, // OEM
+};
+
+int nRTFEncodings = std::size(aRTFEncodings);
+
+RTFFontNameSuffix const aRTFFontNameSuffixes[] = {
+ { "Baltic", RTL_TEXTENCODING_MS_1257 }, { "CE", RTL_TEXTENCODING_MS_1250 },
+ { "Cyr", RTL_TEXTENCODING_MS_1251 }, { "Greek", RTL_TEXTENCODING_MS_1253 },
+ { "Tur", RTL_TEXTENCODING_MS_1254 }, { "(Hebrew)", RTL_TEXTENCODING_MS_1255 },
+ { "(Arabic)", RTL_TEXTENCODING_MS_1256 }, { "(Vietnamese)", RTL_TEXTENCODING_MS_1258 },
+ { "", RTL_TEXTENCODING_DONTKNOW } // End of array
+};
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfcharsets.hxx b/sw/source/writerfilter/rtftok/rtfcharsets.hxx
new file mode 100644
index 000000000000..826dea271f6b
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfcharsets.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+/// RTF legacy charsets
+struct RTFEncoding
+{
+ int charset;
+ int codepage;
+};
+extern RTFEncoding const aRTFEncodings[];
+extern int nRTFEncodings;
+
+/// Font name can contain special suffixes used
+/// to determine encoding for given font table entry
+/// For example "Arial CE" is "Arial" with CP1250 encoding
+/// List of these suffixes is not official and detected in a empirical
+/// way thus may be inexact and incomplete.
+struct RTFFontNameSuffix
+{
+ const char* suffix;
+ int codepage;
+};
+extern RTFFontNameSuffix const aRTFFontNameSuffixes[];
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfcontrolwords.cxx b/sw/source/writerfilter/rtftok/rtfcontrolwords.cxx
new file mode 100644
index 000000000000..8b035b37bbe2
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfcontrolwords.cxx
@@ -0,0 +1,1900 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfcontrolwords.hxx"
+#include <oox/token/namespaces.hxx>
+
+namespace writerfilter::rtftok
+{
+RTFSymbol const aRTFControlWords[] = {
+ // sKeyword nControlType nIndex
+ { "'", RTFControlType::SYMBOL, RTFKeyword::HEXCHAR, 0 },
+ { "-", RTFControlType::SYMBOL, RTFKeyword::OPTHYPH, 0 },
+ { "*", RTFControlType::SYMBOL, RTFKeyword::IGNORE, 0 },
+ { ":", RTFControlType::SYMBOL, RTFKeyword::SUBENTRY, 0 },
+ { "\\", RTFControlType::SYMBOL, RTFKeyword::BACKSLASH, 0 },
+ { "\n", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "\r", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "\r\n", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "_", RTFControlType::SYMBOL, RTFKeyword::NOBRKHYPH, 0 },
+ { "{", RTFControlType::SYMBOL, RTFKeyword::LBRACE, 0 },
+ { "|", RTFControlType::SYMBOL, RTFKeyword::FORMULA, 0 },
+ { "}", RTFControlType::SYMBOL, RTFKeyword::RBRACE, 0 },
+ { "~", RTFControlType::SYMBOL, RTFKeyword::NOBREAK, 0 },
+ { "ab", RTFControlType::TOGGLE, RTFKeyword::AB, 1 },
+ { "absh", RTFControlType::VALUE, RTFKeyword::ABSH, 0 },
+ { "abslock", RTFControlType::FLAG, RTFKeyword::ABSLOCK, 0 },
+ { "absnoovrlp", RTFControlType::TOGGLE, RTFKeyword::ABSNOOVRLP, 1 },
+ { "absw", RTFControlType::VALUE, RTFKeyword::ABSW, 0 },
+ { "acaps", RTFControlType::TOGGLE, RTFKeyword::ACAPS, 1 },
+ { "acccircle", RTFControlType::TOGGLE, RTFKeyword::ACCCIRCLE, 1 },
+ { "acccomma", RTFControlType::TOGGLE, RTFKeyword::ACCCOMMA, 1 },
+ { "accdot", RTFControlType::TOGGLE, RTFKeyword::ACCDOT, 1 },
+ { "accnone", RTFControlType::TOGGLE, RTFKeyword::ACCNONE, 1 },
+ { "accunderdot", RTFControlType::TOGGLE, RTFKeyword::ACCUNDERDOT, 1 },
+ { "acf", RTFControlType::VALUE, RTFKeyword::ACF, 0 },
+ { "adeff", RTFControlType::VALUE, RTFKeyword::ADEFF, 0 },
+ { "additive", RTFControlType::FLAG, RTFKeyword::ADDITIVE, 0 },
+ { "adeflang", RTFControlType::VALUE, RTFKeyword::ADEFLANG, 0 },
+ { "adjustright", RTFControlType::FLAG, RTFKeyword::ADJUSTRIGHT, 0 },
+ { "adn", RTFControlType::VALUE, RTFKeyword::ADN, 6 },
+ { "aenddoc", RTFControlType::FLAG, RTFKeyword::AENDDOC, 0 },
+ { "aendnotes", RTFControlType::FLAG, RTFKeyword::AENDNOTES, 0 },
+ { "aexpnd", RTFControlType::VALUE, RTFKeyword::AEXPND, 0 },
+ { "af", RTFControlType::VALUE, RTFKeyword::AF, 0 },
+ { "afelev", RTFControlType::FLAG, RTFKeyword::AFELEV, 0 },
+ { "afs", RTFControlType::VALUE, RTFKeyword::AFS, 24 },
+ { "aftnbj", RTFControlType::FLAG, RTFKeyword::AFTNBJ, 0 },
+ { "aftncn", RTFControlType::DESTINATION, RTFKeyword::AFTNCN, 0 },
+ { "aftnnalc", RTFControlType::FLAG, RTFKeyword::AFTNNALC, 0 },
+ { "aftnnar", RTFControlType::FLAG, RTFKeyword::AFTNNAR, 0 },
+ { "aftnnauc", RTFControlType::FLAG, RTFKeyword::AFTNNAUC, 0 },
+ { "aftnnchi", RTFControlType::FLAG, RTFKeyword::AFTNNCHI, 0 },
+ { "aftnnchosung", RTFControlType::FLAG, RTFKeyword::AFTNNCHOSUNG, 0 },
+ { "aftnncnum", RTFControlType::FLAG, RTFKeyword::AFTNNCNUM, 0 },
+ { "aftnndbar", RTFControlType::FLAG, RTFKeyword::AFTNNDBAR, 0 },
+ { "aftnndbnum", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUM, 0 },
+ { "aftnndbnumd", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMD, 0 },
+ { "aftnndbnumk", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMK, 0 },
+ { "aftnndbnumt", RTFControlType::FLAG, RTFKeyword::AFTNNDBNUMT, 0 },
+ { "aftnnganada", RTFControlType::FLAG, RTFKeyword::AFTNNGANADA, 0 },
+ { "aftnngbnum", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUM, 0 },
+ { "aftnngbnumd", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUMD, 0 },
+ { "aftnngbnumk", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUMK, 0 },
+ { "aftnngbnuml", RTFControlType::FLAG, RTFKeyword::AFTNNGBNUML, 0 },
+ { "aftnnrlc", RTFControlType::FLAG, RTFKeyword::AFTNNRLC, 0 },
+ { "aftnnruc", RTFControlType::FLAG, RTFKeyword::AFTNNRUC, 0 },
+ { "aftnnzodiac", RTFControlType::FLAG, RTFKeyword::AFTNNZODIAC, 0 },
+ { "aftnnzodiacd", RTFControlType::FLAG, RTFKeyword::AFTNNZODIACD, 0 },
+ { "aftnnzodiacl", RTFControlType::FLAG, RTFKeyword::AFTNNZODIACL, 0 },
+ { "aftnrestart", RTFControlType::FLAG, RTFKeyword::AFTNRESTART, 0 },
+ { "aftnrstcont", RTFControlType::FLAG, RTFKeyword::AFTNRSTCONT, 0 },
+ { "aftnsep", RTFControlType::DESTINATION, RTFKeyword::AFTNSEP, 0 },
+ { "aftnsepc", RTFControlType::DESTINATION, RTFKeyword::AFTNSEPC, 0 },
+ { "aftnstart", RTFControlType::VALUE, RTFKeyword::AFTNSTART, 1 },
+ { "aftntj", RTFControlType::FLAG, RTFKeyword::AFTNTJ, 0 },
+ { "ai", RTFControlType::TOGGLE, RTFKeyword::AI, 1 },
+ { "alang", RTFControlType::VALUE, RTFKeyword::ALANG, 0 },
+ { "allowfieldendsel", RTFControlType::FLAG, RTFKeyword::ALLOWFIELDENDSEL, 0 },
+ { "allprot", RTFControlType::FLAG, RTFKeyword::ALLPROT, 0 },
+ { "alntblind", RTFControlType::FLAG, RTFKeyword::ALNTBLIND, 0 },
+ { "alt", RTFControlType::FLAG, RTFKeyword::ALT, 0 },
+ { "animtext", RTFControlType::VALUE, RTFKeyword::ANIMTEXT, 0 },
+ { "annotation", RTFControlType::DESTINATION, RTFKeyword::ANNOTATION, 0 },
+ { "annotprot", RTFControlType::FLAG, RTFKeyword::ANNOTPROT, 0 },
+ { "ansi", RTFControlType::FLAG, RTFKeyword::ANSI, 0 },
+ { "ansicpg", RTFControlType::VALUE, RTFKeyword::ANSICPG, 0 },
+ { "aoutl", RTFControlType::TOGGLE, RTFKeyword::AOUTL, 1 },
+ { "ApplyBrkRules", RTFControlType::FLAG, RTFKeyword::APPLYBRKRULES, 0 },
+ { "ascaps", RTFControlType::TOGGLE, RTFKeyword::ASCAPS, 1 },
+ { "ashad", RTFControlType::TOGGLE, RTFKeyword::ASHAD, 1 },
+ { "asianbrkrule", RTFControlType::FLAG, RTFKeyword::ASIANBRKRULE, 0 },
+ { "aspalpha", RTFControlType::TOGGLE, RTFKeyword::ASPALPHA, 1 },
+ { "aspnum", RTFControlType::TOGGLE, RTFKeyword::ASPNUM, 1 },
+ { "astrike", RTFControlType::TOGGLE, RTFKeyword::ASTRIKE, 1 },
+ { "atnauthor", RTFControlType::DESTINATION, RTFKeyword::ATNAUTHOR, 0 },
+ { "atndate", RTFControlType::DESTINATION, RTFKeyword::ATNDATE, 0 },
+ { "atnicn", RTFControlType::DESTINATION, RTFKeyword::ATNICN, 0 },
+ { "atnid", RTFControlType::DESTINATION, RTFKeyword::ATNID, 0 },
+ { "atnparent", RTFControlType::DESTINATION, RTFKeyword::ATNPARENT, 0 },
+ { "atnref", RTFControlType::DESTINATION, RTFKeyword::ATNREF, 0 },
+ { "atntime", RTFControlType::DESTINATION, RTFKeyword::ATNTIME, 0 },
+ { "atrfend", RTFControlType::DESTINATION, RTFKeyword::ATRFEND, 0 },
+ { "atrfstart", RTFControlType::DESTINATION, RTFKeyword::ATRFSTART, 0 },
+ { "aul", RTFControlType::TOGGLE, RTFKeyword::AUL, 1 },
+ { "auld", RTFControlType::TOGGLE, RTFKeyword::AULD, 1 },
+ { "auldb", RTFControlType::TOGGLE, RTFKeyword::AULDB, 1 },
+ { "aulnone", RTFControlType::TOGGLE, RTFKeyword::AULNONE, 1 },
+ { "aulw", RTFControlType::TOGGLE, RTFKeyword::AULW, 1 },
+ { "aup", RTFControlType::VALUE, RTFKeyword::AUP, 6 },
+ { "author", RTFControlType::DESTINATION, RTFKeyword::AUTHOR, 0 },
+ { "autofmtoverride", RTFControlType::FLAG, RTFKeyword::AUTOFMTOVERRIDE, 0 },
+ { "b", RTFControlType::TOGGLE, RTFKeyword::B, 1 },
+ { "background", RTFControlType::DESTINATION, RTFKeyword::BACKGROUND, 0 },
+ { "bdbfhdr", RTFControlType::FLAG, RTFKeyword::BDBFHDR, 0 },
+ { "bdrrlswsix", RTFControlType::FLAG, RTFKeyword::BDRRLSWSIX, 0 },
+ { "bgbdiag", RTFControlType::FLAG, RTFKeyword::BGBDIAG, 0 },
+ { "bgcross", RTFControlType::FLAG, RTFKeyword::BGCROSS, 0 },
+ { "bgdcross", RTFControlType::FLAG, RTFKeyword::BGDCROSS, 0 },
+ { "bgdkbdiag", RTFControlType::FLAG, RTFKeyword::BGDKBDIAG, 0 },
+ { "bgdkcross", RTFControlType::FLAG, RTFKeyword::BGDKCROSS, 0 },
+ { "bgdkdcross", RTFControlType::FLAG, RTFKeyword::BGDKDCROSS, 0 },
+ { "bgdkfdiag", RTFControlType::FLAG, RTFKeyword::BGDKFDIAG, 0 },
+ { "bgdkhoriz", RTFControlType::FLAG, RTFKeyword::BGDKHORIZ, 0 },
+ { "bgdkvert", RTFControlType::FLAG, RTFKeyword::BGDKVERT, 0 },
+ { "bgfdiag", RTFControlType::FLAG, RTFKeyword::BGFDIAG, 0 },
+ { "bghoriz", RTFControlType::FLAG, RTFKeyword::BGHORIZ, 0 },
+ { "bgvert", RTFControlType::FLAG, RTFKeyword::BGVERT, 0 },
+ { "bin", RTFControlType::VALUE, RTFKeyword::BIN, 0 },
+ { "binfsxn", RTFControlType::VALUE, RTFKeyword::BINFSXN, 0 },
+ { "binsxn", RTFControlType::VALUE, RTFKeyword::BINSXN, 0 },
+ { "bkmkcolf", RTFControlType::VALUE, RTFKeyword::BKMKCOLF, 0 },
+ { "bkmkcoll", RTFControlType::VALUE, RTFKeyword::BKMKCOLL, 0 },
+ { "bkmkend", RTFControlType::DESTINATION, RTFKeyword::BKMKEND, 0 },
+ { "bkmkpub", RTFControlType::FLAG, RTFKeyword::BKMKPUB, 0 },
+ { "bkmkstart", RTFControlType::DESTINATION, RTFKeyword::BKMKSTART, 0 },
+ { "bliptag", RTFControlType::VALUE, RTFKeyword::BLIPTAG, 0 },
+ { "blipuid", RTFControlType::DESTINATION, RTFKeyword::BLIPUID, 0 },
+ { "blipupi", RTFControlType::VALUE, RTFKeyword::BLIPUPI, 0 },
+ { "blue", RTFControlType::VALUE, RTFKeyword::BLUE, 0 },
+ { "bookfold", RTFControlType::FLAG, RTFKeyword::BOOKFOLD, 0 },
+ { "bookfoldrev", RTFControlType::FLAG, RTFKeyword::BOOKFOLDREV, 0 },
+ { "bookfoldsheets", RTFControlType::VALUE, RTFKeyword::BOOKFOLDSHEETS, 0 },
+ { "box", RTFControlType::FLAG, RTFKeyword::BOX, 0 },
+ { "brdrart", RTFControlType::VALUE, RTFKeyword::BRDRART, 0 },
+ { "brdrb", RTFControlType::FLAG, RTFKeyword::BRDRB, 0 },
+ { "brdrbar", RTFControlType::FLAG, RTFKeyword::BRDRBAR, 0 },
+ { "brdrbtw", RTFControlType::FLAG, RTFKeyword::BRDRBTW, 0 },
+ { "brdrcf", RTFControlType::VALUE, RTFKeyword::BRDRCF, 0 },
+ { "brdrdash", RTFControlType::FLAG, RTFKeyword::BRDRDASH, 0 },
+ { "brdrdashd", RTFControlType::FLAG, RTFKeyword::BRDRDASHD, 0 },
+ { "brdrdashdd", RTFControlType::FLAG, RTFKeyword::BRDRDASHDD, 0 },
+ { "brdrdashdotstr", RTFControlType::FLAG, RTFKeyword::BRDRDASHDOTSTR, 0 },
+ { "brdrdashsm", RTFControlType::FLAG, RTFKeyword::BRDRDASHSM, 0 },
+ { "brdrdb", RTFControlType::FLAG, RTFKeyword::BRDRDB, 0 },
+ { "brdrdot", RTFControlType::FLAG, RTFKeyword::BRDRDOT, 0 },
+ { "brdremboss", RTFControlType::FLAG, RTFKeyword::BRDREMBOSS, 0 },
+ { "brdrengrave", RTFControlType::FLAG, RTFKeyword::BRDRENGRAVE, 0 },
+ { "brdrframe", RTFControlType::FLAG, RTFKeyword::BRDRFRAME, 0 },
+ { "brdrhair", RTFControlType::FLAG, RTFKeyword::BRDRHAIR, 0 },
+ { "brdrinset", RTFControlType::FLAG, RTFKeyword::BRDRINSET, 0 },
+ { "brdrl", RTFControlType::FLAG, RTFKeyword::BRDRL, 0 },
+ { "brdrnil", RTFControlType::FLAG, RTFKeyword::BRDRNIL, 0 },
+ { "brdrnone", RTFControlType::FLAG, RTFKeyword::BRDRNONE, 0 },
+ { "brdroutset", RTFControlType::FLAG, RTFKeyword::BRDROUTSET, 0 },
+ { "brdrr", RTFControlType::FLAG, RTFKeyword::BRDRR, 0 },
+ { "brdrs", RTFControlType::FLAG, RTFKeyword::BRDRS, 0 },
+ { "brdrsh", RTFControlType::FLAG, RTFKeyword::BRDRSH, 0 },
+ { "brdrt", RTFControlType::FLAG, RTFKeyword::BRDRT, 0 },
+ { "brdrtbl", RTFControlType::FLAG, RTFKeyword::BRDRTBL, 0 },
+ { "brdrth", RTFControlType::FLAG, RTFKeyword::BRDRTH, 0 },
+ { "brdrthtnlg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNLG, 0 },
+ { "brdrthtnmg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNMG, 0 },
+ { "brdrthtnsg", RTFControlType::FLAG, RTFKeyword::BRDRTHTNSG, 0 },
+ { "brdrtnthlg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHLG, 0 },
+ { "brdrtnthmg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHMG, 0 },
+ { "brdrtnthsg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHSG, 0 },
+ { "brdrtnthtnlg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNLG, 0 },
+ { "brdrtnthtnmg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNMG, 0 },
+ { "brdrtnthtnsg", RTFControlType::FLAG, RTFKeyword::BRDRTNTHTNSG, 0 },
+ { "brdrtriple", RTFControlType::FLAG, RTFKeyword::BRDRTRIPLE, 0 },
+ { "brdrw", RTFControlType::VALUE, RTFKeyword::BRDRW, 0 },
+ { "brdrwavy", RTFControlType::FLAG, RTFKeyword::BRDRWAVY, 0 },
+ { "brdrwavydb", RTFControlType::FLAG, RTFKeyword::BRDRWAVYDB, 0 },
+ { "brkfrm", RTFControlType::FLAG, RTFKeyword::BRKFRM, 0 },
+ { "brsp", RTFControlType::VALUE, RTFKeyword::BRSP, 0 },
+ { "bullet", RTFControlType::SYMBOL, RTFKeyword::BULLET, 0 },
+ { "buptim", RTFControlType::DESTINATION, RTFKeyword::BUPTIM, 0 },
+ { "bxe", RTFControlType::FLAG, RTFKeyword::BXE, 0 },
+ { "caccentfive", RTFControlType::FLAG, RTFKeyword::CACCENTFIVE, 0 },
+ { "caccentfour", RTFControlType::FLAG, RTFKeyword::CACCENTFOUR, 0 },
+ { "caccentone", RTFControlType::FLAG, RTFKeyword::CACCENTONE, 0 },
+ { "caccentsix", RTFControlType::FLAG, RTFKeyword::CACCENTSIX, 0 },
+ { "caccentthree", RTFControlType::FLAG, RTFKeyword::CACCENTTHREE, 0 },
+ { "caccenttwo", RTFControlType::FLAG, RTFKeyword::CACCENTTWO, 0 },
+ { "cachedcolbal", RTFControlType::FLAG, RTFKeyword::CACHEDCOLBAL, 0 },
+ { "caps", RTFControlType::TOGGLE, RTFKeyword::CAPS, 1 },
+ { "category", RTFControlType::DESTINATION, RTFKeyword::CATEGORY, 0 },
+ { "cb", RTFControlType::VALUE, RTFKeyword::CB, 0 },
+ { "cbackgroundone", RTFControlType::FLAG, RTFKeyword::CBACKGROUNDONE, 0 },
+ { "cbackgroundtwo", RTFControlType::FLAG, RTFKeyword::CBACKGROUNDTWO, 0 },
+ { "cbpat", RTFControlType::VALUE, RTFKeyword::CBPAT, 0 },
+ { "cchs", RTFControlType::VALUE, RTFKeyword::CCHS, 0 },
+ { "cell", RTFControlType::SYMBOL, RTFKeyword::CELL, 0 },
+ { "cellx", RTFControlType::VALUE, RTFKeyword::CELLX, 0 },
+ { "cf", RTFControlType::VALUE, RTFKeyword::CF, 0 },
+ { "cfollowedhyperlink", RTFControlType::FLAG, RTFKeyword::CFOLLOWEDHYPERLINK, 0 },
+ { "cfpat", RTFControlType::VALUE, RTFKeyword::CFPAT, 0 },
+ { "cgrid", RTFControlType::VALUE, RTFKeyword::CGRID, 0 },
+ { "charrsid", RTFControlType::VALUE, RTFKeyword::CHARRSID, 0 },
+ { "charscalex", RTFControlType::VALUE, RTFKeyword::CHARSCALEX, 100 },
+ { "chatn", RTFControlType::SYMBOL, RTFKeyword::CHATN, 0 },
+ { "chbgbdiag", RTFControlType::FLAG, RTFKeyword::CHBGBDIAG, 0 },
+ { "chbgcross", RTFControlType::FLAG, RTFKeyword::CHBGCROSS, 0 },
+ { "chbgdcross", RTFControlType::FLAG, RTFKeyword::CHBGDCROSS, 0 },
+ { "chbgdkbdiag", RTFControlType::FLAG, RTFKeyword::CHBGDKBDIAG, 0 },
+ { "chbgdkcross", RTFControlType::FLAG, RTFKeyword::CHBGDKCROSS, 0 },
+ { "chbgdkdcross", RTFControlType::FLAG, RTFKeyword::CHBGDKDCROSS, 0 },
+ { "chbgdkfdiag", RTFControlType::FLAG, RTFKeyword::CHBGDKFDIAG, 0 },
+ { "chbgdkhoriz", RTFControlType::FLAG, RTFKeyword::CHBGDKHORIZ, 0 },
+ { "chbgdkvert", RTFControlType::FLAG, RTFKeyword::CHBGDKVERT, 0 },
+ { "chbgfdiag", RTFControlType::FLAG, RTFKeyword::CHBGFDIAG, 0 },
+ { "chbghoriz", RTFControlType::FLAG, RTFKeyword::CHBGHORIZ, 0 },
+ { "chbgvert", RTFControlType::FLAG, RTFKeyword::CHBGVERT, 0 },
+ { "chbrdr", RTFControlType::FLAG, RTFKeyword::CHBRDR, 0 },
+ { "chcbpat", RTFControlType::VALUE, RTFKeyword::CHCBPAT, 0 },
+ { "chcfpat", RTFControlType::VALUE, RTFKeyword::CHCFPAT, 0 },
+ { "chdate", RTFControlType::SYMBOL, RTFKeyword::CHDATE, 0 },
+ { "chdpa", RTFControlType::SYMBOL, RTFKeyword::CHDPA, 0 },
+ { "chdpl", RTFControlType::SYMBOL, RTFKeyword::CHDPL, 0 },
+ { "chftn", RTFControlType::SYMBOL, RTFKeyword::CHFTN, 0 },
+ { "chftnsep", RTFControlType::SYMBOL, RTFKeyword::CHFTNSEP, 0 },
+ { "chftnsepc", RTFControlType::SYMBOL, RTFKeyword::CHFTNSEPC, 0 },
+ { "chpgn", RTFControlType::SYMBOL, RTFKeyword::CHPGN, 0 },
+ { "chhres", RTFControlType::VALUE, RTFKeyword::CHHRES, 0 },
+ { "chshdng", RTFControlType::VALUE, RTFKeyword::CHSHDNG, 0 },
+ { "chtime", RTFControlType::SYMBOL, RTFKeyword::CHTIME, 0 },
+ { "chyperlink", RTFControlType::FLAG, RTFKeyword::CHYPERLINK, 0 },
+ { "clbgbdiag", RTFControlType::FLAG, RTFKeyword::CLBGBDIAG, 0 },
+ { "clbgcross", RTFControlType::FLAG, RTFKeyword::CLBGCROSS, 0 },
+ { "clbgdcross", RTFControlType::FLAG, RTFKeyword::CLBGDCROSS, 0 },
+ { "clbgdkbdiag", RTFControlType::FLAG, RTFKeyword::CLBGDKBDIAG, 0 },
+ { "clbgdkcross", RTFControlType::FLAG, RTFKeyword::CLBGDKCROSS, 0 },
+ { "clbgdkdcross", RTFControlType::FLAG, RTFKeyword::CLBGDKDCROSS, 0 },
+ { "clbgdkfdiag", RTFControlType::FLAG, RTFKeyword::CLBGDKFDIAG, 0 },
+ { "clbgdkhor", RTFControlType::FLAG, RTFKeyword::CLBGDKHOR, 0 },
+ { "clbgdkvert", RTFControlType::FLAG, RTFKeyword::CLBGDKVERT, 0 },
+ { "clbgfdiag", RTFControlType::FLAG, RTFKeyword::CLBGFDIAG, 0 },
+ { "clbghoriz", RTFControlType::FLAG, RTFKeyword::CLBGHORIZ, 0 },
+ { "clbgvert", RTFControlType::FLAG, RTFKeyword::CLBGVERT, 0 },
+ { "clbrdrb", RTFControlType::FLAG, RTFKeyword::CLBRDRB, 0 },
+ { "clbrdrl", RTFControlType::FLAG, RTFKeyword::CLBRDRL, 0 },
+ { "clbrdrr", RTFControlType::FLAG, RTFKeyword::CLBRDRR, 0 },
+ { "clbrdrt", RTFControlType::FLAG, RTFKeyword::CLBRDRT, 0 },
+ { "clcbpat", RTFControlType::VALUE, RTFKeyword::CLCBPAT, 0 },
+ { "clcbpatraw", RTFControlType::VALUE, RTFKeyword::CLCBPATRAW, 0 },
+ { "clcfpat", RTFControlType::VALUE, RTFKeyword::CLCFPAT, 0 },
+ { "clcfpatraw", RTFControlType::VALUE, RTFKeyword::CLCFPATRAW, 0 },
+ { "cldel", RTFControlType::FLAG, RTFKeyword::CLDEL, 0 },
+ { "cldelauth", RTFControlType::VALUE, RTFKeyword::CLDELAUTH, 0 },
+ { "cldeldttm", RTFControlType::VALUE, RTFKeyword::CLDELDTTM, 0 },
+ { "cldgll", RTFControlType::FLAG, RTFKeyword::CLDGLL, 0 },
+ { "cldglu", RTFControlType::FLAG, RTFKeyword::CLDGLU, 0 },
+ { "clFitText", RTFControlType::FLAG, RTFKeyword::CLFITTEXT, 0 },
+ { "clftsWidth", RTFControlType::VALUE, RTFKeyword::CLFTSWIDTH, 0 },
+ { "clhidemark", RTFControlType::FLAG, RTFKeyword::CLHIDEMARK, 0 },
+ { "clins", RTFControlType::FLAG, RTFKeyword::CLINS, 0 },
+ { "clinsauth", RTFControlType::VALUE, RTFKeyword::CLINSAUTH, 0 },
+ { "clinsdttm", RTFControlType::VALUE, RTFKeyword::CLINSDTTM, 0 },
+ { "clmgf", RTFControlType::FLAG, RTFKeyword::CLMGF, 0 },
+ { "clmrg", RTFControlType::FLAG, RTFKeyword::CLMRG, 0 },
+ { "clmrgd", RTFControlType::FLAG, RTFKeyword::CLMRGD, 0 },
+ { "clmrgdauth", RTFControlType::VALUE, RTFKeyword::CLMRGDAUTH, 0 },
+ { "clmrgddttm", RTFControlType::VALUE, RTFKeyword::CLMRGDDTTM, 0 },
+ { "clmrgdr", RTFControlType::FLAG, RTFKeyword::CLMRGDR, 0 },
+ { "clNoWrap", RTFControlType::FLAG, RTFKeyword::CLNOWRAP, 0 },
+ { "clpadb", RTFControlType::VALUE, RTFKeyword::CLPADB, 0 },
+ { "clpadfb", RTFControlType::VALUE, RTFKeyword::CLPADFB, 0 },
+ { "clpadfl", RTFControlType::VALUE, RTFKeyword::CLPADFL, 0 },
+ { "clpadfr", RTFControlType::VALUE, RTFKeyword::CLPADFR, 0 },
+ { "clpadft", RTFControlType::VALUE, RTFKeyword::CLPADFT, 0 },
+ { "clpadl", RTFControlType::VALUE, RTFKeyword::CLPADL, 0 },
+ { "clpadr", RTFControlType::VALUE, RTFKeyword::CLPADR, 0 },
+ { "clpadt", RTFControlType::VALUE, RTFKeyword::CLPADT, 0 },
+ { "clspb", RTFControlType::VALUE, RTFKeyword::CLSPB, 0 },
+ { "clspfb", RTFControlType::VALUE, RTFKeyword::CLSPFB, 0 },
+ { "clspfl", RTFControlType::VALUE, RTFKeyword::CLSPFL, 0 },
+ { "clspfr", RTFControlType::VALUE, RTFKeyword::CLSPFR, 0 },
+ { "clspft", RTFControlType::VALUE, RTFKeyword::CLSPFT, 0 },
+ { "clspl", RTFControlType::VALUE, RTFKeyword::CLSPL, 0 },
+ { "clspr", RTFControlType::VALUE, RTFKeyword::CLSPR, 0 },
+ { "clspt", RTFControlType::VALUE, RTFKeyword::CLSPT, 0 },
+ { "clshdng", RTFControlType::VALUE, RTFKeyword::CLSHDNG, 0 },
+ { "clshdngraw", RTFControlType::VALUE, RTFKeyword::CLSHDNGRAW, 0 },
+ { "clshdrawnil", RTFControlType::FLAG, RTFKeyword::CLSHDRAWNIL, 0 },
+ { "clsplit", RTFControlType::FLAG, RTFKeyword::CLSPLIT, 0 },
+ { "clsplitr", RTFControlType::FLAG, RTFKeyword::CLSPLITR, 0 },
+ { "cltxbtlr", RTFControlType::FLAG, RTFKeyword::CLTXBTLR, 0 },
+ { "cltxlrtb", RTFControlType::FLAG, RTFKeyword::CLTXLRTB, 0 },
+ { "cltxlrtbv", RTFControlType::FLAG, RTFKeyword::CLTXLRTBV, 0 },
+ { "cltxtbrl", RTFControlType::FLAG, RTFKeyword::CLTXTBRL, 0 },
+ { "cltxtbrlv", RTFControlType::FLAG, RTFKeyword::CLTXTBRLV, 0 },
+ { "clvertalb", RTFControlType::FLAG, RTFKeyword::CLVERTALB, 0 },
+ { "clvertalc", RTFControlType::FLAG, RTFKeyword::CLVERTALC, 0 },
+ { "clvertalt", RTFControlType::FLAG, RTFKeyword::CLVERTALT, 0 },
+ { "clvmgf", RTFControlType::FLAG, RTFKeyword::CLVMGF, 0 },
+ { "clvmrg", RTFControlType::FLAG, RTFKeyword::CLVMRG, 0 },
+ { "clwWidth", RTFControlType::VALUE, RTFKeyword::CLWWIDTH, 0 },
+ { "cmaindarkone", RTFControlType::FLAG, RTFKeyword::CMAINDARKONE, 0 },
+ { "cmaindarktwo", RTFControlType::FLAG, RTFKeyword::CMAINDARKTWO, 0 },
+ { "cmainlightone", RTFControlType::FLAG, RTFKeyword::CMAINLIGHTONE, 0 },
+ { "cmainlighttwo", RTFControlType::FLAG, RTFKeyword::CMAINLIGHTTWO, 0 },
+ { "collapsed", RTFControlType::FLAG, RTFKeyword::COLLAPSED, 0 },
+ { "colno", RTFControlType::VALUE, RTFKeyword::COLNO, 0 },
+ { "colorschememapping", RTFControlType::DESTINATION, RTFKeyword::COLORSCHEMEMAPPING, 0 },
+ { "colortbl", RTFControlType::DESTINATION, RTFKeyword::COLORTBL, 0 },
+ { "cols", RTFControlType::VALUE, RTFKeyword::COLS, 1 },
+ { "colsr", RTFControlType::VALUE, RTFKeyword::COLSR, 0 },
+ { "colsx", RTFControlType::VALUE, RTFKeyword::COLSX, 720 },
+ { "column", RTFControlType::SYMBOL, RTFKeyword::COLUMN, 0 },
+ { "colw", RTFControlType::VALUE, RTFKeyword::COLW, 0 },
+ { "comment", RTFControlType::DESTINATION, RTFKeyword::COMMENT, 0 },
+ { "company", RTFControlType::DESTINATION, RTFKeyword::COMPANY, 0 },
+ { "contextualspace", RTFControlType::FLAG, RTFKeyword::CONTEXTUALSPACE, 0 },
+ { "cpg", RTFControlType::VALUE, RTFKeyword::CPG, 0 },
+ { "crauth", RTFControlType::VALUE, RTFKeyword::CRAUTH, 0 },
+ { "crdate", RTFControlType::VALUE, RTFKeyword::CRDATE, 0 },
+ { "creatim", RTFControlType::DESTINATION, RTFKeyword::CREATIM, 0 },
+ { "cs", RTFControlType::VALUE, RTFKeyword::CS, 0 },
+ { "cshade", RTFControlType::VALUE, RTFKeyword::CSHADE, 0 },
+ { "ctextone", RTFControlType::FLAG, RTFKeyword::CTEXTONE, 0 },
+ { "ctexttwo", RTFControlType::FLAG, RTFKeyword::CTEXTTWO, 0 },
+ { "ctint", RTFControlType::VALUE, RTFKeyword::CTINT, 0 },
+ { "ctrl", RTFControlType::FLAG, RTFKeyword::CTRL, 0 },
+ { "cts", RTFControlType::VALUE, RTFKeyword::CTS, 0 },
+ { "cufi", RTFControlType::VALUE, RTFKeyword::CUFI, 0 },
+ { "culi", RTFControlType::VALUE, RTFKeyword::CULI, 0 },
+ { "curi", RTFControlType::VALUE, RTFKeyword::CURI, 0 },
+ { "cvmme", RTFControlType::FLAG, RTFKeyword::CVMME, 0 },
+ { "datafield", RTFControlType::DESTINATION, RTFKeyword::DATAFIELD, 0 },
+ { "datastore", RTFControlType::DESTINATION, RTFKeyword::DATASTORE, 0 },
+ { "date", RTFControlType::FLAG, RTFKeyword::DATE, 0 },
+ { "dbch", RTFControlType::FLAG, RTFKeyword::DBCH, 0 },
+ { "defchp", RTFControlType::DESTINATION, RTFKeyword::DEFCHP, 0 },
+ { "deff", RTFControlType::VALUE, RTFKeyword::DEFF, 0 },
+ { "defformat", RTFControlType::FLAG, RTFKeyword::DEFFORMAT, 0 },
+ { "deflang", RTFControlType::VALUE, RTFKeyword::DEFLANG, 0 },
+ { "deflangfe", RTFControlType::VALUE, RTFKeyword::DEFLANGFE, 0 },
+ { "defpap", RTFControlType::DESTINATION, RTFKeyword::DEFPAP, 0 },
+ { "defshp", RTFControlType::FLAG, RTFKeyword::DEFSHP, 0 },
+ { "deftab", RTFControlType::VALUE, RTFKeyword::DEFTAB, 720 },
+ { "deleted", RTFControlType::TOGGLE, RTFKeyword::DELETED, 1 },
+ { "delrsid", RTFControlType::VALUE, RTFKeyword::DELRSID, 0 },
+ { "dfrauth", RTFControlType::VALUE, RTFKeyword::DFRAUTH, 0 },
+ { "dfrdate", RTFControlType::VALUE, RTFKeyword::DFRDATE, 0 },
+ { "dfrmtxtx", RTFControlType::VALUE, RTFKeyword::DFRMTXTX, 0 },
+ { "dfrmtxty", RTFControlType::VALUE, RTFKeyword::DFRMTXTY, 0 },
+ { "dfrstart", RTFControlType::VALUE, RTFKeyword::DFRSTART, 0 },
+ { "dfrstop", RTFControlType::VALUE, RTFKeyword::DFRSTOP, 0 },
+ { "dfrxst", RTFControlType::VALUE, RTFKeyword::DFRXST, 0 },
+ { "dghorigin", RTFControlType::VALUE, RTFKeyword::DGHORIGIN, 1701 },
+ { "dghshow", RTFControlType::VALUE, RTFKeyword::DGHSHOW, 3 },
+ { "dghspace", RTFControlType::VALUE, RTFKeyword::DGHSPACE, 120 },
+ { "dgmargin", RTFControlType::FLAG, RTFKeyword::DGMARGIN, 0 },
+ { "dgsnap", RTFControlType::FLAG, RTFKeyword::DGSNAP, 0 },
+ { "dgvorigin", RTFControlType::VALUE, RTFKeyword::DGVORIGIN, 1984 },
+ { "dgvshow", RTFControlType::VALUE, RTFKeyword::DGVSHOW, 0 },
+ { "dgvspace", RTFControlType::VALUE, RTFKeyword::DGVSPACE, 120 },
+ { "dibitmap", RTFControlType::VALUE, RTFKeyword::DIBITMAP, 0 },
+ { "disabled", RTFControlType::TOGGLE, RTFKeyword::DISABLED, 1 },
+ { "dn", RTFControlType::VALUE, RTFKeyword::DN, 6 },
+ { "dntblnsbdb", RTFControlType::FLAG, RTFKeyword::DNTBLNSBDB, 0 },
+ { "do", RTFControlType::DESTINATION, RTFKeyword::DO, 0 },
+ { "dobxcolumn", RTFControlType::FLAG, RTFKeyword::DOBXCOLUMN, 0 },
+ { "dobxmargin", RTFControlType::FLAG, RTFKeyword::DOBXMARGIN, 0 },
+ { "dobxpage", RTFControlType::FLAG, RTFKeyword::DOBXPAGE, 0 },
+ { "dobymargin", RTFControlType::FLAG, RTFKeyword::DOBYMARGIN, 0 },
+ { "dobypage", RTFControlType::FLAG, RTFKeyword::DOBYPAGE, 0 },
+ { "dobypara", RTFControlType::FLAG, RTFKeyword::DOBYPARA, 0 },
+ { "doccomm", RTFControlType::DESTINATION, RTFKeyword::DOCCOMM, 0 },
+ { "doctemp", RTFControlType::FLAG, RTFKeyword::DOCTEMP, 0 },
+ { "doctype", RTFControlType::VALUE, RTFKeyword::DOCTYPE, 0 },
+ { "docvar", RTFControlType::DESTINATION, RTFKeyword::DOCVAR, 0 },
+ { "dodhgt", RTFControlType::VALUE, RTFKeyword::DODHGT, 0 },
+ { "dolock", RTFControlType::FLAG, RTFKeyword::DOLOCK, 0 },
+ { "donotembedlingdata", RTFControlType::VALUE, RTFKeyword::DONOTEMBEDLINGDATA, 0 },
+ { "donotembedsysfont", RTFControlType::VALUE, RTFKeyword::DONOTEMBEDSYSFONT, 0 },
+ { "donotshowcomments", RTFControlType::FLAG, RTFKeyword::DONOTSHOWCOMMENTS, 0 },
+ { "donotshowinsdel", RTFControlType::FLAG, RTFKeyword::DONOTSHOWINSDEL, 0 },
+ { "donotshowmarkup", RTFControlType::FLAG, RTFKeyword::DONOTSHOWMARKUP, 0 },
+ { "donotshowprops", RTFControlType::FLAG, RTFKeyword::DONOTSHOWPROPS, 0 },
+ { "dpaendhol", RTFControlType::FLAG, RTFKeyword::DPAENDHOL, 0 },
+ { "dpaendl", RTFControlType::VALUE, RTFKeyword::DPAENDL, 0 },
+ { "dpaendsol", RTFControlType::FLAG, RTFKeyword::DPAENDSOL, 0 },
+ { "dpaendw", RTFControlType::VALUE, RTFKeyword::DPAENDW, 0 },
+ { "dparc", RTFControlType::FLAG, RTFKeyword::DPARC, 0 },
+ { "dparcflipx", RTFControlType::FLAG, RTFKeyword::DPARCFLIPX, 0 },
+ { "dparcflipy", RTFControlType::FLAG, RTFKeyword::DPARCFLIPY, 0 },
+ { "dpastarthol", RTFControlType::FLAG, RTFKeyword::DPASTARTHOL, 0 },
+ { "dpastartl", RTFControlType::VALUE, RTFKeyword::DPASTARTL, 0 },
+ { "dpastartsol", RTFControlType::FLAG, RTFKeyword::DPASTARTSOL, 0 },
+ { "dpastartw", RTFControlType::VALUE, RTFKeyword::DPASTARTW, 0 },
+ { "dpcallout", RTFControlType::FLAG, RTFKeyword::DPCALLOUT, 0 },
+ { "dpcoa", RTFControlType::VALUE, RTFKeyword::DPCOA, 0 },
+ { "dpcoaccent", RTFControlType::FLAG, RTFKeyword::DPCOACCENT, 0 },
+ { "dpcobestfit", RTFControlType::FLAG, RTFKeyword::DPCOBESTFIT, 0 },
+ { "dpcoborder", RTFControlType::FLAG, RTFKeyword::DPCOBORDER, 0 },
+ { "dpcodabs", RTFControlType::FLAG, RTFKeyword::DPCODABS, 0 },
+ { "dpcodbottom", RTFControlType::FLAG, RTFKeyword::DPCODBOTTOM, 0 },
+ { "dpcodcenter", RTFControlType::FLAG, RTFKeyword::DPCODCENTER, 0 },
+ { "dpcodescent", RTFControlType::VALUE, RTFKeyword::DPCODESCENT, 0 },
+ { "dpcodtop", RTFControlType::FLAG, RTFKeyword::DPCODTOP, 0 },
+ { "dpcolength", RTFControlType::VALUE, RTFKeyword::DPCOLENGTH, 0 },
+ { "dpcominusx", RTFControlType::FLAG, RTFKeyword::DPCOMINUSX, 0 },
+ { "dpcominusy", RTFControlType::FLAG, RTFKeyword::DPCOMINUSY, 0 },
+ { "dpcooffset", RTFControlType::VALUE, RTFKeyword::DPCOOFFSET, 0 },
+ { "dpcosmarta", RTFControlType::FLAG, RTFKeyword::DPCOSMARTA, 0 },
+ { "dpcotdouble", RTFControlType::FLAG, RTFKeyword::DPCOTDOUBLE, 0 },
+ { "dpcotright", RTFControlType::FLAG, RTFKeyword::DPCOTRIGHT, 0 },
+ { "dpcotsingle", RTFControlType::FLAG, RTFKeyword::DPCOTSINGLE, 0 },
+ { "dpcottriple", RTFControlType::FLAG, RTFKeyword::DPCOTTRIPLE, 0 },
+ { "dpcount", RTFControlType::VALUE, RTFKeyword::DPCOUNT, 0 },
+ { "dpellipse", RTFControlType::FLAG, RTFKeyword::DPELLIPSE, 0 },
+ { "dpendgroup", RTFControlType::FLAG, RTFKeyword::DPENDGROUP, 0 },
+ { "dpfillbgcb", RTFControlType::VALUE, RTFKeyword::DPFILLBGCB, 0 },
+ { "dpfillbgcg", RTFControlType::VALUE, RTFKeyword::DPFILLBGCG, 0 },
+ { "dpfillbgcr", RTFControlType::VALUE, RTFKeyword::DPFILLBGCR, 0 },
+ { "dpfillbggray", RTFControlType::VALUE, RTFKeyword::DPFILLBGGRAY, 0 },
+ { "dpfillbgpal", RTFControlType::FLAG, RTFKeyword::DPFILLBGPAL, 0 },
+ { "dpfillfgcb", RTFControlType::VALUE, RTFKeyword::DPFILLFGCB, 0 },
+ { "dpfillfgcg", RTFControlType::VALUE, RTFKeyword::DPFILLFGCG, 0 },
+ { "dpfillfgcr", RTFControlType::VALUE, RTFKeyword::DPFILLFGCR, 0 },
+ { "dpfillfggray", RTFControlType::VALUE, RTFKeyword::DPFILLFGGRAY, 0 },
+ { "dpfillfgpal", RTFControlType::FLAG, RTFKeyword::DPFILLFGPAL, 0 },
+ { "dpfillpat", RTFControlType::VALUE, RTFKeyword::DPFILLPAT, 0 },
+ { "dpgroup", RTFControlType::FLAG, RTFKeyword::DPGROUP, 0 },
+ { "dpline", RTFControlType::FLAG, RTFKeyword::DPLINE, 0 },
+ { "dplinecob", RTFControlType::VALUE, RTFKeyword::DPLINECOB, 0 },
+ { "dplinecog", RTFControlType::VALUE, RTFKeyword::DPLINECOG, 0 },
+ { "dplinecor", RTFControlType::VALUE, RTFKeyword::DPLINECOR, 0 },
+ { "dplinedado", RTFControlType::FLAG, RTFKeyword::DPLINEDADO, 0 },
+ { "dplinedadodo", RTFControlType::FLAG, RTFKeyword::DPLINEDADODO, 0 },
+ { "dplinedash", RTFControlType::FLAG, RTFKeyword::DPLINEDASH, 0 },
+ { "dplinedot", RTFControlType::FLAG, RTFKeyword::DPLINEDOT, 0 },
+ { "dplinegray", RTFControlType::VALUE, RTFKeyword::DPLINEGRAY, 0 },
+ { "dplinehollow", RTFControlType::FLAG, RTFKeyword::DPLINEHOLLOW, 0 },
+ { "dplinepal", RTFControlType::FLAG, RTFKeyword::DPLINEPAL, 0 },
+ { "dplinesolid", RTFControlType::FLAG, RTFKeyword::DPLINESOLID, 0 },
+ { "dplinew", RTFControlType::VALUE, RTFKeyword::DPLINEW, 0 },
+ { "dppolycount", RTFControlType::VALUE, RTFKeyword::DPPOLYCOUNT, 0 },
+ { "dppolygon", RTFControlType::FLAG, RTFKeyword::DPPOLYGON, 0 },
+ { "dppolyline", RTFControlType::FLAG, RTFKeyword::DPPOLYLINE, 0 },
+ { "dpptx", RTFControlType::VALUE, RTFKeyword::DPPTX, 0 },
+ { "dppty", RTFControlType::VALUE, RTFKeyword::DPPTY, 0 },
+ { "dprect", RTFControlType::FLAG, RTFKeyword::DPRECT, 0 },
+ { "dproundr", RTFControlType::FLAG, RTFKeyword::DPROUNDR, 0 },
+ { "dpshadow", RTFControlType::FLAG, RTFKeyword::DPSHADOW, 0 },
+ { "dpshadx", RTFControlType::VALUE, RTFKeyword::DPSHADX, 0 },
+ { "dpshady", RTFControlType::VALUE, RTFKeyword::DPSHADY, 0 },
+ { "dptxbtlr", RTFControlType::FLAG, RTFKeyword::DPTXBTLR, 0 },
+ { "dptxbx", RTFControlType::FLAG, RTFKeyword::DPTXBX, 0 },
+ { "dptxbxmar", RTFControlType::VALUE, RTFKeyword::DPTXBXMAR, 0 },
+ { "dptxbxtext", RTFControlType::DESTINATION, RTFKeyword::DPTXBXTEXT, 0 },
+ { "dptxlrtb", RTFControlType::FLAG, RTFKeyword::DPTXLRTB, 0 },
+ { "dptxlrtbv", RTFControlType::FLAG, RTFKeyword::DPTXLRTBV, 0 },
+ { "dptxtbrl", RTFControlType::FLAG, RTFKeyword::DPTXTBRL, 0 },
+ { "dptxtbrlv", RTFControlType::FLAG, RTFKeyword::DPTXTBRLV, 0 },
+ { "dpx", RTFControlType::VALUE, RTFKeyword::DPX, 0 },
+ { "dpxsize", RTFControlType::VALUE, RTFKeyword::DPXSIZE, 0 },
+ { "dpy", RTFControlType::VALUE, RTFKeyword::DPY, 0 },
+ { "dpysize", RTFControlType::VALUE, RTFKeyword::DPYSIZE, 0 },
+ { "dropcapli", RTFControlType::VALUE, RTFKeyword::DROPCAPLI, 0 },
+ { "dropcapt", RTFControlType::VALUE, RTFKeyword::DROPCAPT, 0 },
+ { "ds", RTFControlType::VALUE, RTFKeyword::DS, 0 },
+ { "dxfrtext", RTFControlType::VALUE, RTFKeyword::DXFRTEXT, 0 },
+ { "dy", RTFControlType::VALUE, RTFKeyword::DY, 0 },
+ { "ebcend", RTFControlType::DESTINATION, RTFKeyword::EBCEND, 0 },
+ { "ebcstart", RTFControlType::DESTINATION, RTFKeyword::EBCSTART, 0 },
+ { "edmins", RTFControlType::VALUE, RTFKeyword::EDMINS, 0 },
+ { "embo", RTFControlType::TOGGLE, RTFKeyword::EMBO, 1 },
+ { "emdash", RTFControlType::SYMBOL, RTFKeyword::EMDASH, 0 },
+ { "emfblip", RTFControlType::FLAG, RTFKeyword::EMFBLIP, 0 },
+ { "emspace", RTFControlType::SYMBOL, RTFKeyword::EMSPACE, 0 },
+ { "endash", RTFControlType::SYMBOL, RTFKeyword::ENDASH, 0 },
+ { "enddoc", RTFControlType::FLAG, RTFKeyword::ENDDOC, 0 },
+ { "endnhere", RTFControlType::FLAG, RTFKeyword::ENDNHERE, 0 },
+ { "endnotes", RTFControlType::FLAG, RTFKeyword::ENDNOTES, 0 },
+ { "enforceprot", RTFControlType::VALUE, RTFKeyword::ENFORCEPROT, 0 },
+ { "enspace", RTFControlType::SYMBOL, RTFKeyword::ENSPACE, 0 },
+ { "expnd", RTFControlType::VALUE, RTFKeyword::EXPND, 0 },
+ { "expndtw", RTFControlType::VALUE, RTFKeyword::EXPNDTW, 0 },
+ { "expshrtn", RTFControlType::FLAG, RTFKeyword::EXPSHRTN, 0 },
+ { "f", RTFControlType::VALUE, RTFKeyword::F, 0 },
+ { "faauto", RTFControlType::FLAG, RTFKeyword::FAAUTO, 0 },
+ { "facenter", RTFControlType::FLAG, RTFKeyword::FACENTER, 0 },
+ { "facingp", RTFControlType::TOGGLE, RTFKeyword::FACINGP, 1 },
+ { "factoidname", RTFControlType::DESTINATION, RTFKeyword::FACTOIDNAME, 0 },
+ { "fafixed", RTFControlType::FLAG, RTFKeyword::FAFIXED, 0 },
+ { "fahang", RTFControlType::FLAG, RTFKeyword::FAHANG, 0 },
+ { "falt", RTFControlType::DESTINATION, RTFKeyword::FALT, 0 },
+ { "faroman", RTFControlType::FLAG, RTFKeyword::FAROMAN, 0 },
+ { "favar", RTFControlType::FLAG, RTFKeyword::FAVAR, 0 },
+ { "fbias", RTFControlType::VALUE, RTFKeyword::FBIAS, 0 },
+ { "fbidi", RTFControlType::FLAG, RTFKeyword::FBIDI, 0 },
+ { "fbidis", RTFControlType::FLAG, RTFKeyword::FBIDIS, 0 },
+ { "fbimajor", RTFControlType::FLAG, RTFKeyword::FBIMAJOR, 0 },
+ { "fbiminor", RTFControlType::FLAG, RTFKeyword::FBIMINOR, 0 },
+ { "fchars", RTFControlType::DESTINATION, RTFKeyword::FCHARS, 0 },
+ { "fcharset", RTFControlType::VALUE, RTFKeyword::FCHARSET, 0 },
+ { "fcs", RTFControlType::VALUE, RTFKeyword::FCS, 0 },
+ { "fdbmajor", RTFControlType::FLAG, RTFKeyword::FDBMAJOR, 0 },
+ { "fdbminor", RTFControlType::FLAG, RTFKeyword::FDBMINOR, 0 },
+ { "fdecor", RTFControlType::FLAG, RTFKeyword::FDECOR, 0 },
+ { "felnbrelev", RTFControlType::FLAG, RTFKeyword::FELNBRELEV, 0 },
+ { "fet", RTFControlType::VALUE, RTFKeyword::FET, 0 },
+ { "fetch", RTFControlType::FLAG, RTFKeyword::FETCH, 0 },
+ { "ffdefres", RTFControlType::VALUE, RTFKeyword::FFDEFRES, 0 },
+ { "ffdeftext", RTFControlType::DESTINATION, RTFKeyword::FFDEFTEXT, 0 },
+ { "ffentrymcr", RTFControlType::DESTINATION, RTFKeyword::FFENTRYMCR, 0 },
+ { "ffexitmcr", RTFControlType::DESTINATION, RTFKeyword::FFEXITMCR, 0 },
+ { "ffformat", RTFControlType::DESTINATION, RTFKeyword::FFFORMAT, 0 },
+ { "ffhaslistbox", RTFControlType::VALUE, RTFKeyword::FFHASLISTBOX, 0 },
+ { "ffhelptext", RTFControlType::DESTINATION, RTFKeyword::FFHELPTEXT, 0 },
+ { "ffhps", RTFControlType::VALUE, RTFKeyword::FFHPS, 0 },
+ { "ffl", RTFControlType::DESTINATION, RTFKeyword::FFL, 0 },
+ { "ffmaxlen", RTFControlType::VALUE, RTFKeyword::FFMAXLEN, 0 },
+ { "ffname", RTFControlType::DESTINATION, RTFKeyword::FFNAME, 0 },
+ { "ffownhelp", RTFControlType::VALUE, RTFKeyword::FFOWNHELP, 0 },
+ { "ffownstat", RTFControlType::VALUE, RTFKeyword::FFOWNSTAT, 0 },
+ { "ffprot", RTFControlType::VALUE, RTFKeyword::FFPROT, 0 },
+ { "ffrecalc", RTFControlType::VALUE, RTFKeyword::FFRECALC, 0 },
+ { "ffres", RTFControlType::VALUE, RTFKeyword::FFRES, 0 },
+ { "ffsize", RTFControlType::VALUE, RTFKeyword::FFSIZE, 0 },
+ { "ffstattext", RTFControlType::DESTINATION, RTFKeyword::FFSTATTEXT, 0 },
+ { "fftype", RTFControlType::VALUE, RTFKeyword::FFTYPE, 0 },
+ { "fftypetxt", RTFControlType::VALUE, RTFKeyword::FFTYPETXT, 0 },
+ { "fhimajor", RTFControlType::FLAG, RTFKeyword::FHIMAJOR, 0 },
+ { "fhiminor", RTFControlType::FLAG, RTFKeyword::FHIMINOR, 0 },
+ { "fi", RTFControlType::VALUE, RTFKeyword::FI, 0 },
+ { "fid", RTFControlType::VALUE, RTFKeyword::FID, 0 },
+ { "field", RTFControlType::DESTINATION, RTFKeyword::FIELD, 0 },
+ { "file", RTFControlType::DESTINATION, RTFKeyword::FILE, 0 },
+ { "filetbl", RTFControlType::DESTINATION, RTFKeyword::FILETBL, 0 },
+ { "fittext", RTFControlType::VALUE, RTFKeyword::FITTEXT, 0 },
+ { "fjgothic", RTFControlType::FLAG, RTFKeyword::FJGOTHIC, 0 },
+ { "fjminchou", RTFControlType::FLAG, RTFKeyword::FJMINCHOU, 0 },
+ { "fldalt", RTFControlType::FLAG, RTFKeyword::FLDALT, 0 },
+ { "flddirty", RTFControlType::FLAG, RTFKeyword::FLDDIRTY, 0 },
+ { "fldedit", RTFControlType::FLAG, RTFKeyword::FLDEDIT, 0 },
+ { "fldinst", RTFControlType::DESTINATION, RTFKeyword::FLDINST, 0 },
+ { "fldlock", RTFControlType::FLAG, RTFKeyword::FLDLOCK, 0 },
+ { "fldpriv", RTFControlType::FLAG, RTFKeyword::FLDPRIV, 0 },
+ { "fldrslt", RTFControlType::DESTINATION, RTFKeyword::FLDRSLT, 0 },
+ { "fldtype", RTFControlType::DESTINATION, RTFKeyword::FLDTYPE, 0 },
+ { "flomajor", RTFControlType::FLAG, RTFKeyword::FLOMAJOR, 0 },
+ { "flominor", RTFControlType::FLAG, RTFKeyword::FLOMINOR, 0 },
+ { "fmodern", RTFControlType::FLAG, RTFKeyword::FMODERN, 0 },
+ { "fn", RTFControlType::VALUE, RTFKeyword::FN, 0 },
+ { "fname", RTFControlType::DESTINATION, RTFKeyword::FNAME, 0 },
+ { "fnetwork", RTFControlType::FLAG, RTFKeyword::FNETWORK, 0 },
+ { "fnil", RTFControlType::FLAG, RTFKeyword::FNIL, 0 },
+ { "fnonfilesys", RTFControlType::FLAG, RTFKeyword::FNONFILESYS, 0 },
+ { "fontemb", RTFControlType::DESTINATION, RTFKeyword::FONTEMB, 0 },
+ { "fontfile", RTFControlType::DESTINATION, RTFKeyword::FONTFILE, 0 },
+ { "fonttbl", RTFControlType::DESTINATION, RTFKeyword::FONTTBL, 0 },
+ { "footer", RTFControlType::DESTINATION, RTFKeyword::FOOTER, 0 },
+ { "footerf", RTFControlType::DESTINATION, RTFKeyword::FOOTERF, 0 },
+ { "footerl", RTFControlType::DESTINATION, RTFKeyword::FOOTERL, 0 },
+ { "footerr", RTFControlType::DESTINATION, RTFKeyword::FOOTERR, 0 },
+ { "footery", RTFControlType::VALUE, RTFKeyword::FOOTERY, 720 },
+ { "footnote", RTFControlType::DESTINATION, RTFKeyword::FOOTNOTE, 0 },
+ { "forceupgrade", RTFControlType::FLAG, RTFKeyword::FORCEUPGRADE, 0 },
+ { "formdisp", RTFControlType::FLAG, RTFKeyword::FORMDISP, 0 },
+ { "formfield", RTFControlType::DESTINATION, RTFKeyword::FORMFIELD, 0 },
+ { "formprot", RTFControlType::FLAG, RTFKeyword::FORMPROT, 0 },
+ { "formshade", RTFControlType::FLAG, RTFKeyword::FORMSHADE, 0 },
+ { "fosnum", RTFControlType::VALUE, RTFKeyword::FOSNUM, 0 },
+ { "fprq", RTFControlType::VALUE, RTFKeyword::FPRQ, 0 },
+ { "fracwidth", RTFControlType::FLAG, RTFKeyword::FRACWIDTH, 0 },
+ { "frelative", RTFControlType::VALUE, RTFKeyword::FRELATIVE, 0 },
+ { "frmtxbtlr", RTFControlType::FLAG, RTFKeyword::FRMTXBTLR, 0 },
+ { "frmtxlrtb", RTFControlType::FLAG, RTFKeyword::FRMTXLRTB, 0 },
+ { "frmtxlrtbv", RTFControlType::FLAG, RTFKeyword::FRMTXLRTBV, 0 },
+ { "frmtxtbrl", RTFControlType::FLAG, RTFKeyword::FRMTXTBRL, 0 },
+ { "frmtxtbrlv", RTFControlType::FLAG, RTFKeyword::FRMTXTBRLV, 0 },
+ { "froman", RTFControlType::FLAG, RTFKeyword::FROMAN, 0 },
+ { "fromhtml", RTFControlType::VALUE, RTFKeyword::FROMHTML, 0 },
+ { "fromtext", RTFControlType::FLAG, RTFKeyword::FROMTEXT, 0 },
+ { "fs", RTFControlType::VALUE, RTFKeyword::FS, 24 },
+ { "fscript", RTFControlType::FLAG, RTFKeyword::FSCRIPT, 0 },
+ { "fswiss", RTFControlType::FLAG, RTFKeyword::FSWISS, 0 },
+ { "ftech", RTFControlType::FLAG, RTFKeyword::FTECH, 0 },
+ { "ftnalt", RTFControlType::FLAG, RTFKeyword::FTNALT, 0 },
+ { "ftnbj", RTFControlType::FLAG, RTFKeyword::FTNBJ, 0 },
+ { "ftncn", RTFControlType::DESTINATION, RTFKeyword::FTNCN, 0 },
+ { "ftnil", RTFControlType::FLAG, RTFKeyword::FTNIL, 0 },
+ { "ftnlytwnine", RTFControlType::FLAG, RTFKeyword::FTNLYTWNINE, 0 },
+ { "ftnnalc", RTFControlType::FLAG, RTFKeyword::FTNNALC, 0 },
+ { "ftnnar", RTFControlType::FLAG, RTFKeyword::FTNNAR, 0 },
+ { "ftnnauc", RTFControlType::FLAG, RTFKeyword::FTNNAUC, 0 },
+ { "ftnnchi", RTFControlType::FLAG, RTFKeyword::FTNNCHI, 0 },
+ { "ftnnchosung", RTFControlType::FLAG, RTFKeyword::FTNNCHOSUNG, 0 },
+ { "ftnncnum", RTFControlType::FLAG, RTFKeyword::FTNNCNUM, 0 },
+ { "ftnndbar", RTFControlType::FLAG, RTFKeyword::FTNNDBAR, 0 },
+ { "ftnndbnum", RTFControlType::FLAG, RTFKeyword::FTNNDBNUM, 0 },
+ { "ftnndbnumd", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMD, 0 },
+ { "ftnndbnumk", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMK, 0 },
+ { "ftnndbnumt", RTFControlType::FLAG, RTFKeyword::FTNNDBNUMT, 0 },
+ { "ftnnganada", RTFControlType::FLAG, RTFKeyword::FTNNGANADA, 0 },
+ { "ftnngbnum", RTFControlType::FLAG, RTFKeyword::FTNNGBNUM, 0 },
+ { "ftnngbnumd", RTFControlType::FLAG, RTFKeyword::FTNNGBNUMD, 0 },
+ { "ftnngbnumk", RTFControlType::FLAG, RTFKeyword::FTNNGBNUMK, 0 },
+ { "ftnngbnuml", RTFControlType::FLAG, RTFKeyword::FTNNGBNUML, 0 },
+ { "ftnnrlc", RTFControlType::FLAG, RTFKeyword::FTNNRLC, 0 },
+ { "ftnnruc", RTFControlType::FLAG, RTFKeyword::FTNNRUC, 0 },
+ { "ftnnzodiac", RTFControlType::FLAG, RTFKeyword::FTNNZODIAC, 0 },
+ { "ftnnzodiacd", RTFControlType::FLAG, RTFKeyword::FTNNZODIACD, 0 },
+ { "ftnnzodiacl", RTFControlType::FLAG, RTFKeyword::FTNNZODIACL, 0 },
+ { "ftnrestart", RTFControlType::FLAG, RTFKeyword::FTNRESTART, 0 },
+ { "ftnrstcont", RTFControlType::FLAG, RTFKeyword::FTNRSTCONT, 0 },
+ { "ftnrstpg", RTFControlType::FLAG, RTFKeyword::FTNRSTPG, 0 },
+ { "ftnsep", RTFControlType::DESTINATION, RTFKeyword::FTNSEP, 0 },
+ { "ftnsepc", RTFControlType::DESTINATION, RTFKeyword::FTNSEPC, 0 },
+ { "ftnstart", RTFControlType::VALUE, RTFKeyword::FTNSTART, 1 },
+ { "ftntj", RTFControlType::FLAG, RTFKeyword::FTNTJ, 0 },
+ { "fttruetype", RTFControlType::FLAG, RTFKeyword::FTTRUETYPE, 0 },
+ { "fvaliddos", RTFControlType::FLAG, RTFKeyword::FVALIDDOS, 0 },
+ { "fvalidhpfs", RTFControlType::FLAG, RTFKeyword::FVALIDHPFS, 0 },
+ { "fvalidmac", RTFControlType::FLAG, RTFKeyword::FVALIDMAC, 0 },
+ { "fvalidntfs", RTFControlType::FLAG, RTFKeyword::FVALIDNTFS, 0 },
+ { "g", RTFControlType::DESTINATION, RTFKeyword::G, 0 },
+ { "gcw", RTFControlType::VALUE, RTFKeyword::GCW, 0 },
+ { "generator", RTFControlType::DESTINATION, RTFKeyword::GENERATOR, 0 },
+ { "green", RTFControlType::VALUE, RTFKeyword::GREEN, 0 },
+ { "grfdocevents", RTFControlType::VALUE, RTFKeyword::GRFDOCEVENTS, 0 },
+ { "gridtbl", RTFControlType::DESTINATION, RTFKeyword::GRIDTBL, 0 },
+ { "gutter", RTFControlType::VALUE, RTFKeyword::GUTTER, 0 },
+ { "gutterprl", RTFControlType::FLAG, RTFKeyword::GUTTERPRL, 0 },
+ { "guttersxn", RTFControlType::VALUE, RTFKeyword::GUTTERSXN, 0 },
+ { "header", RTFControlType::DESTINATION, RTFKeyword::HEADER, 0 },
+ { "headerf", RTFControlType::DESTINATION, RTFKeyword::HEADERF, 0 },
+ { "headerl", RTFControlType::DESTINATION, RTFKeyword::HEADERL, 0 },
+ { "headerr", RTFControlType::DESTINATION, RTFKeyword::HEADERR, 0 },
+ { "headery", RTFControlType::VALUE, RTFKeyword::HEADERY, 720 },
+ { "hich", RTFControlType::FLAG, RTFKeyword::HICH, 0 },
+ { "highlight", RTFControlType::VALUE, RTFKeyword::HIGHLIGHT, 0 },
+ { "hl", RTFControlType::DESTINATION, RTFKeyword::HL, 0 },
+ { "hlfr", RTFControlType::DESTINATION, RTFKeyword::HLFR, 0 },
+ { "hlinkbase", RTFControlType::DESTINATION, RTFKeyword::HLINKBASE, 0 },
+ { "hlloc", RTFControlType::DESTINATION, RTFKeyword::HLLOC, 0 },
+ { "hlsrc", RTFControlType::DESTINATION, RTFKeyword::HLSRC, 0 },
+ { "horzdoc", RTFControlType::FLAG, RTFKeyword::HORZDOC, 0 },
+ { "horzsect", RTFControlType::FLAG, RTFKeyword::HORZSECT, 0 },
+ { "horzvert", RTFControlType::VALUE, RTFKeyword::HORZVERT, 0 },
+ { "hr", RTFControlType::VALUE, RTFKeyword::HR, 0 },
+ { "hres", RTFControlType::VALUE, RTFKeyword::HRES, 0 },
+ { "hrule", RTFControlType::FLAG, RTFKeyword::HRULE, 0 },
+ { "hsv", RTFControlType::DESTINATION, RTFKeyword::HSV, 0 },
+ { "htmautsp", RTFControlType::FLAG, RTFKeyword::HTMAUTSP, 0 },
+ { "htmlbase", RTFControlType::FLAG, RTFKeyword::HTMLBASE, 0 },
+ { "htmlrtf", RTFControlType::TOGGLE, RTFKeyword::HTMLRTF, 1 },
+ { "htmltag", RTFControlType::DESTINATION, RTFKeyword::HTMLTAG, 0 },
+ { "hwelev", RTFControlType::FLAG, RTFKeyword::HWELEV, 0 },
+ { "hyphauto", RTFControlType::TOGGLE, RTFKeyword::HYPHAUTO, 1 },
+ { "hyphcaps", RTFControlType::TOGGLE, RTFKeyword::HYPHCAPS, 1 },
+ { "hyphconsec", RTFControlType::VALUE, RTFKeyword::HYPHCONSEC, 0 },
+ { "hyphhotz", RTFControlType::VALUE, RTFKeyword::HYPHHOTZ, 0 },
+ { "hyphpar", RTFControlType::TOGGLE, RTFKeyword::HYPHPAR, 1 },
+ { "i", RTFControlType::TOGGLE, RTFKeyword::I, 1 },
+ { "id", RTFControlType::VALUE, RTFKeyword::ID, 0 },
+ { "ignoremixedcontent", RTFControlType::VALUE, RTFKeyword::IGNOREMIXEDCONTENT, 0 },
+ { "ilfomacatclnup", RTFControlType::VALUE, RTFKeyword::ILFOMACATCLNUP, 0 },
+ { "ilvl", RTFControlType::VALUE, RTFKeyword::ILVL, 0 },
+ { "impr", RTFControlType::TOGGLE, RTFKeyword::IMPR, 1 },
+ { "indmirror", RTFControlType::FLAG, RTFKeyword::INDMIRROR, 0 },
+ { "indrlsweleven", RTFControlType::FLAG, RTFKeyword::INDRLSWELEVEN, 0 },
+ { "info", RTFControlType::DESTINATION, RTFKeyword::INFO, 0 },
+ { "insrsid", RTFControlType::VALUE, RTFKeyword::INSRSID, 0 },
+ { "intbl", RTFControlType::FLAG, RTFKeyword::INTBL, 0 },
+ { "ipgp", RTFControlType::VALUE, RTFKeyword::IPGP, 0 },
+ { "irowband", RTFControlType::VALUE, RTFKeyword::IROWBAND, 0 },
+ { "irow", RTFControlType::VALUE, RTFKeyword::IROW, 0 },
+ { "itap", RTFControlType::VALUE, RTFKeyword::ITAP, 1 },
+ { "ixe", RTFControlType::FLAG, RTFKeyword::IXE, 0 },
+ { "jcompress", RTFControlType::FLAG, RTFKeyword::JCOMPRESS, 0 },
+ { "jexpand", RTFControlType::FLAG, RTFKeyword::JEXPAND, 0 },
+ { "jis", RTFControlType::FLAG, RTFKeyword::JIS, 0 },
+ { "jpegblip", RTFControlType::FLAG, RTFKeyword::JPEGBLIP, 0 },
+ { "jsksu", RTFControlType::FLAG, RTFKeyword::JSKSU, 0 },
+ { "keep", RTFControlType::FLAG, RTFKeyword::KEEP, 0 },
+ { "keepn", RTFControlType::FLAG, RTFKeyword::KEEPN, 0 },
+ { "kerning", RTFControlType::VALUE, RTFKeyword::KERNING, 0 },
+ { "keycode", RTFControlType::DESTINATION, RTFKeyword::KEYCODE, 0 },
+ { "keywords", RTFControlType::DESTINATION, RTFKeyword::KEYWORDS, 0 },
+ { "krnprsnet", RTFControlType::FLAG, RTFKeyword::KRNPRSNET, 0 },
+ { "ksulang", RTFControlType::VALUE, RTFKeyword::KSULANG, 0 },
+ { "jclisttab", RTFControlType::FLAG, RTFKeyword::JCLISTTAB, 0 },
+ { "landscape", RTFControlType::FLAG, RTFKeyword::LANDSCAPE, 0 },
+ { "lang", RTFControlType::VALUE, RTFKeyword::LANG, 0 },
+ { "langfe", RTFControlType::VALUE, RTFKeyword::LANGFE, 0 },
+ { "langfenp", RTFControlType::VALUE, RTFKeyword::LANGFENP, 0 },
+ { "langnp", RTFControlType::VALUE, RTFKeyword::LANGNP, 0 },
+ { "lastrow", RTFControlType::FLAG, RTFKeyword::LASTROW, 0 },
+ { "latentstyles", RTFControlType::DESTINATION, RTFKeyword::LATENTSTYLES, 0 },
+ { "lbr", RTFControlType::VALUE, RTFKeyword::LBR, 0 },
+ { "lchars", RTFControlType::DESTINATION, RTFKeyword::LCHARS, 0 },
+ { "ldblquote", RTFControlType::SYMBOL, RTFKeyword::LDBLQUOTE, 0 },
+ { "level", RTFControlType::VALUE, RTFKeyword::LEVEL, 0 },
+ { "levelfollow", RTFControlType::VALUE, RTFKeyword::LEVELFOLLOW, 0 },
+ { "levelindent", RTFControlType::VALUE, RTFKeyword::LEVELINDENT, 0 },
+ { "leveljc", RTFControlType::VALUE, RTFKeyword::LEVELJC, 0 },
+ { "leveljcn", RTFControlType::VALUE, RTFKeyword::LEVELJCN, 0 },
+ { "levellegal", RTFControlType::VALUE, RTFKeyword::LEVELLEGAL, 1 },
+ { "levelnfc", RTFControlType::VALUE, RTFKeyword::LEVELNFC, 0 },
+ { "levelnfcn", RTFControlType::VALUE, RTFKeyword::LEVELNFCN, 0 },
+ { "levelnorestart", RTFControlType::VALUE, RTFKeyword::LEVELNORESTART, 0 },
+ { "levelnumbers", RTFControlType::DESTINATION, RTFKeyword::LEVELNUMBERS, 0 },
+ { "levelold", RTFControlType::VALUE, RTFKeyword::LEVELOLD, 0 },
+ { "levelpicture", RTFControlType::VALUE, RTFKeyword::LEVELPICTURE, 0 },
+ { "levelpicturenosize", RTFControlType::FLAG, RTFKeyword::LEVELPICTURENOSIZE, 0 },
+ { "levelprev", RTFControlType::VALUE, RTFKeyword::LEVELPREV, 0 },
+ { "levelprevspace", RTFControlType::VALUE, RTFKeyword::LEVELPREVSPACE, 0 },
+ { "levelspace", RTFControlType::VALUE, RTFKeyword::LEVELSPACE, 0 },
+ { "levelstartat", RTFControlType::VALUE, RTFKeyword::LEVELSTARTAT, 0 },
+ { "leveltemplateid", RTFControlType::VALUE, RTFKeyword::LEVELTEMPLATEID, 0 },
+ { "leveltext", RTFControlType::DESTINATION, RTFKeyword::LEVELTEXT, 0 },
+ { "lfolevel", RTFControlType::DESTINATION, RTFKeyword::LFOLEVEL, 0 },
+ { "li", RTFControlType::VALUE, RTFKeyword::LI, 0 },
+ { "line", RTFControlType::SYMBOL, RTFKeyword::LINE, 0 },
+ { "linebetcol", RTFControlType::FLAG, RTFKeyword::LINEBETCOL, 0 },
+ { "linecont", RTFControlType::FLAG, RTFKeyword::LINECONT, 0 },
+ { "linemod", RTFControlType::VALUE, RTFKeyword::LINEMOD, 1 },
+ { "lineppage", RTFControlType::FLAG, RTFKeyword::LINEPPAGE, 0 },
+ { "linerestart", RTFControlType::FLAG, RTFKeyword::LINERESTART, 0 },
+ { "linestart", RTFControlType::VALUE, RTFKeyword::LINESTART, 1 },
+ { "linestarts", RTFControlType::VALUE, RTFKeyword::LINESTARTS, 1 },
+ { "linex", RTFControlType::VALUE, RTFKeyword::LINEX, 360 },
+ { "linkself", RTFControlType::FLAG, RTFKeyword::LINKSELF, 0 },
+ { "linkstyles", RTFControlType::FLAG, RTFKeyword::LINKSTYLES, 0 },
+ { "linkval", RTFControlType::DESTINATION, RTFKeyword::LINKVAL, 0 },
+ { "lin", RTFControlType::VALUE, RTFKeyword::LIN, 0 },
+ { "lisa", RTFControlType::VALUE, RTFKeyword::LISA, 0 },
+ { "lisb", RTFControlType::VALUE, RTFKeyword::LISB, 0 },
+ { "list", RTFControlType::DESTINATION, RTFKeyword::LIST, 0 },
+ { "listhybrid", RTFControlType::FLAG, RTFKeyword::LISTHYBRID, 0 },
+ { "listid", RTFControlType::VALUE, RTFKeyword::LISTID, 0 },
+ { "listlevel", RTFControlType::DESTINATION, RTFKeyword::LISTLEVEL, 0 },
+ { "listname", RTFControlType::DESTINATION, RTFKeyword::LISTNAME, 0 },
+ { "listoverride", RTFControlType::DESTINATION, RTFKeyword::LISTOVERRIDE, 0 },
+ { "listoverridecount", RTFControlType::VALUE, RTFKeyword::LISTOVERRIDECOUNT, 0 },
+ { "listoverrideformat", RTFControlType::VALUE, RTFKeyword::LISTOVERRIDEFORMAT, 0 },
+ { "listoverridestartat", RTFControlType::FLAG, RTFKeyword::LISTOVERRIDESTARTAT, 0 },
+ { "listoverridetable", RTFControlType::DESTINATION, RTFKeyword::LISTOVERRIDETABLE, 0 },
+ { "listpicture", RTFControlType::DESTINATION, RTFKeyword::LISTPICTURE, 0 },
+ { "listrestarthdn", RTFControlType::VALUE, RTFKeyword::LISTRESTARTHDN, 0 },
+ { "listsimple", RTFControlType::VALUE, RTFKeyword::LISTSIMPLE, 0 },
+ { "liststyleid", RTFControlType::VALUE, RTFKeyword::LISTSTYLEID, 0 },
+ { "liststylename", RTFControlType::DESTINATION, RTFKeyword::LISTSTYLENAME, 0 },
+ { "listtable", RTFControlType::DESTINATION, RTFKeyword::LISTTABLE, 0 },
+ { "listtemplateid", RTFControlType::VALUE, RTFKeyword::LISTTEMPLATEID, 0 },
+ { "listtext", RTFControlType::DESTINATION, RTFKeyword::LISTTEXT, 0 },
+ { "lnbrkrule", RTFControlType::FLAG, RTFKeyword::LNBRKRULE, 0 },
+ { "lndscpsxn", RTFControlType::FLAG, RTFKeyword::LNDSCPSXN, 0 },
+ { "lnongrid", RTFControlType::FLAG, RTFKeyword::LNONGRID, 0 },
+ { "loch", RTFControlType::FLAG, RTFKeyword::LOCH, 0 },
+ { "lquote", RTFControlType::SYMBOL, RTFKeyword::LQUOTE, 0 },
+ { "ls", RTFControlType::VALUE, RTFKeyword::LS, 0 },
+ { "lsdlocked", RTFControlType::VALUE, RTFKeyword::LSDLOCKED, 0 },
+ { "lsdlockeddef", RTFControlType::VALUE, RTFKeyword::LSDLOCKEDDEF, 0 },
+ { "lsdlockedexcept", RTFControlType::DESTINATION, RTFKeyword::LSDLOCKEDEXCEPT, 0 },
+ { "lsdpriority", RTFControlType::VALUE, RTFKeyword::LSDPRIORITY, 0 },
+ { "lsdprioritydef", RTFControlType::VALUE, RTFKeyword::LSDPRIORITYDEF, 0 },
+ { "lsdqformat", RTFControlType::VALUE, RTFKeyword::LSDQFORMAT, 0 },
+ { "lsdqformatdef", RTFControlType::VALUE, RTFKeyword::LSDQFORMATDEF, 0 },
+ { "lsdsemihidden", RTFControlType::VALUE, RTFKeyword::LSDSEMIHIDDEN, 0 },
+ { "lsdsemihiddendef", RTFControlType::VALUE, RTFKeyword::LSDSEMIHIDDENDEF, 0 },
+ { "lsdstimax", RTFControlType::VALUE, RTFKeyword::LSDSTIMAX, 0 },
+ { "lsdunhideused", RTFControlType::VALUE, RTFKeyword::LSDUNHIDEUSED, 0 },
+ { "lsdunhideuseddef", RTFControlType::VALUE, RTFKeyword::LSDUNHIDEUSEDDEF, 0 },
+ { "ltrch", RTFControlType::FLAG, RTFKeyword::LTRCH, 0 },
+ { "ltrdoc", RTFControlType::FLAG, RTFKeyword::LTRDOC, 0 },
+ { "ltrmark", RTFControlType::SYMBOL, RTFKeyword::LTRMARK, 0 },
+ { "ltrpar", RTFControlType::FLAG, RTFKeyword::LTRPAR, 0 },
+ { "ltrrow", RTFControlType::FLAG, RTFKeyword::LTRROW, 0 },
+ { "ltrsect", RTFControlType::FLAG, RTFKeyword::LTRSECT, 0 },
+ { "lvltentative", RTFControlType::FLAG, RTFKeyword::LVLTENTATIVE, 0 },
+ { "lytcalctblwd", RTFControlType::FLAG, RTFKeyword::LYTCALCTBLWD, 0 },
+ { "lytexcttp", RTFControlType::FLAG, RTFKeyword::LYTEXCTTP, 0 },
+ { "lytprtmet", RTFControlType::FLAG, RTFKeyword::LYTPRTMET, 0 },
+ { "lyttblrtgr", RTFControlType::FLAG, RTFKeyword::LYTTBLRTGR, 0 },
+ { "mac", RTFControlType::FLAG, RTFKeyword::MAC, 0 },
+ { "macc", RTFControlType::DESTINATION, RTFKeyword::MACC, 0 },
+ { "maccPr", RTFControlType::DESTINATION, RTFKeyword::MACCPR, 0 },
+ { "macpict", RTFControlType::FLAG, RTFKeyword::MACPICT, 0 },
+ { "mailmerge", RTFControlType::DESTINATION, RTFKeyword::MAILMERGE, 0 },
+ { "makebackup", RTFControlType::FLAG, RTFKeyword::MAKEBACKUP, 0 },
+ { "maln", RTFControlType::DESTINATION, RTFKeyword::MALN, 0 },
+ { "malnScr", RTFControlType::DESTINATION, RTFKeyword::MALNSCR, 0 },
+ { "manager", RTFControlType::DESTINATION, RTFKeyword::MANAGER, 0 },
+ { "margb", RTFControlType::VALUE, RTFKeyword::MARGB, 1440 },
+ { "margbsxn", RTFControlType::VALUE, RTFKeyword::MARGBSXN, 0 },
+ { "margl", RTFControlType::VALUE, RTFKeyword::MARGL, 1800 },
+ { "marglsxn", RTFControlType::VALUE, RTFKeyword::MARGLSXN, 0 },
+ { "margmirror", RTFControlType::FLAG, RTFKeyword::MARGMIRROR, 0 },
+ { "margmirsxn", RTFControlType::FLAG, RTFKeyword::MARGMIRSXN, 0 },
+ { "margPr", RTFControlType::DESTINATION, RTFKeyword::MARGPR, 0 },
+ { "margr", RTFControlType::VALUE, RTFKeyword::MARGR, 1800 },
+ { "margrsxn", RTFControlType::VALUE, RTFKeyword::MARGRSXN, 0 },
+ { "margSz", RTFControlType::VALUE, RTFKeyword::MARGSZ, 0 },
+ { "margt", RTFControlType::VALUE, RTFKeyword::MARGT, 1440 },
+ { "margtsxn", RTFControlType::VALUE, RTFKeyword::MARGTSXN, 0 },
+ { "mbar", RTFControlType::DESTINATION, RTFKeyword::MBAR, 0 },
+ { "mbarPr", RTFControlType::DESTINATION, RTFKeyword::MBARPR, 0 },
+ { "mbaseJc", RTFControlType::DESTINATION, RTFKeyword::MBASEJC, 0 },
+ { "mbegChr", RTFControlType::DESTINATION, RTFKeyword::MBEGCHR, 0 },
+ { "mborderBox", RTFControlType::DESTINATION, RTFKeyword::MBORDERBOX, 0 },
+ { "mborderBoxPr", RTFControlType::DESTINATION, RTFKeyword::MBORDERBOXPR, 0 },
+ { "mbox", RTFControlType::DESTINATION, RTFKeyword::MBOX, 0 },
+ { "mboxPr", RTFControlType::DESTINATION, RTFKeyword::MBOXPR, 0 },
+ { "mbrk", RTFControlType::VALUE, RTFKeyword::MBRK, 0 },
+ { "mbrkBin", RTFControlType::VALUE, RTFKeyword::MBRKBIN, 0 },
+ { "mbrkBinSub", RTFControlType::VALUE, RTFKeyword::MBRKBINSUB, 0 },
+ { "mcGp", RTFControlType::VALUE, RTFKeyword::MCGP, 0 },
+ { "mcGpRule", RTFControlType::VALUE, RTFKeyword::MCGPRULE, 0 },
+ { "mchr", RTFControlType::DESTINATION, RTFKeyword::MCHR, 0 },
+ { "mcount", RTFControlType::DESTINATION, RTFKeyword::MCOUNT, 0 },
+ { "mcSp", RTFControlType::VALUE, RTFKeyword::MCSP, 0 },
+ { "mctrlPr", RTFControlType::DESTINATION, RTFKeyword::MCTRLPR, 0 },
+ { "md", RTFControlType::DESTINATION, RTFKeyword::MD, 0 },
+ { "mdefJc", RTFControlType::VALUE, RTFKeyword::MDEFJC, 0 },
+ { "mdeg", RTFControlType::DESTINATION, RTFKeyword::MDEG, 0 },
+ { "mdegHide", RTFControlType::DESTINATION, RTFKeyword::MDEGHIDE, 0 },
+ { "mden", RTFControlType::DESTINATION, RTFKeyword::MDEN, 0 },
+ { "mdiff", RTFControlType::DESTINATION, RTFKeyword::MDIFF, 0 },
+ { "mdiffSty", RTFControlType::VALUE, RTFKeyword::MDIFFSTY, 0 },
+ { "mdispdef", RTFControlType::VALUE, RTFKeyword::MDISPDEF, 1 },
+ { "mdPr", RTFControlType::DESTINATION, RTFKeyword::MDPR, 0 },
+ { "me", RTFControlType::DESTINATION, RTFKeyword::ME, 0 },
+ { "mendChr", RTFControlType::DESTINATION, RTFKeyword::MENDCHR, 0 },
+ { "meqArr", RTFControlType::DESTINATION, RTFKeyword::MEQARR, 0 },
+ { "meqArrPr", RTFControlType::DESTINATION, RTFKeyword::MEQARRPR, 0 },
+ { "mf", RTFControlType::DESTINATION, RTFKeyword::MF, 0 },
+ { "mfName", RTFControlType::DESTINATION, RTFKeyword::MFNAME, 0 },
+ { "mfPr", RTFControlType::DESTINATION, RTFKeyword::MFPR, 0 },
+ { "mfunc", RTFControlType::DESTINATION, RTFKeyword::MFUNC, 0 },
+ { "mfuncPr", RTFControlType::DESTINATION, RTFKeyword::MFUNCPR, 0 },
+ { "mgroupChr", RTFControlType::DESTINATION, RTFKeyword::MGROUPCHR, 0 },
+ { "mgroupChrPr", RTFControlType::DESTINATION, RTFKeyword::MGROUPCHRPR, 0 },
+ { "mgrow", RTFControlType::DESTINATION, RTFKeyword::MGROW, 0 },
+ { "mhideBot", RTFControlType::DESTINATION, RTFKeyword::MHIDEBOT, 0 },
+ { "mhideLeft", RTFControlType::DESTINATION, RTFKeyword::MHIDELEFT, 0 },
+ { "mhideRight", RTFControlType::DESTINATION, RTFKeyword::MHIDERIGHT, 0 },
+ { "mhideTop", RTFControlType::DESTINATION, RTFKeyword::MHIDETOP, 0 },
+ { "mhtmltag", RTFControlType::DESTINATION, RTFKeyword::MHTMLTAG, 0 },
+ { "min", RTFControlType::VALUE, RTFKeyword::MIN, 0 },
+ { "minterSp", RTFControlType::VALUE, RTFKeyword::MINTERSP, 0 },
+ { "mintLim", RTFControlType::VALUE, RTFKeyword::MINTLIM, 0 },
+ { "mintraSp", RTFControlType::VALUE, RTFKeyword::MINTRASP, 0 },
+ { "mjc", RTFControlType::VALUE, RTFKeyword::MJC, 0 },
+ { "mlim", RTFControlType::DESTINATION, RTFKeyword::MLIM, 0 },
+ { "mlimloc", RTFControlType::DESTINATION, RTFKeyword::MLIMLOC, 0 },
+ { "mlimLoc", RTFControlType::DESTINATION, RTFKeyword::MLIMLOC, 0 },
+ { "mlimlow", RTFControlType::DESTINATION, RTFKeyword::MLIMLOW, 0 },
+ { "mlimLow", RTFControlType::DESTINATION, RTFKeyword::MLIMLOW, 0 },
+ { "mlimlowPr", RTFControlType::DESTINATION, RTFKeyword::MLIMLOWPR, 0 },
+ { "mlimLowPr", RTFControlType::DESTINATION, RTFKeyword::MLIMLOWPR, 0 },
+ { "mlimupp", RTFControlType::DESTINATION, RTFKeyword::MLIMUPP, 0 },
+ { "mlimUpp", RTFControlType::DESTINATION, RTFKeyword::MLIMUPP, 0 },
+ { "mlimuppPr", RTFControlType::DESTINATION, RTFKeyword::MLIMUPPPR, 0 },
+ { "mlimUppPr", RTFControlType::DESTINATION, RTFKeyword::MLIMUPPPR, 0 },
+ { "mlit", RTFControlType::FLAG, RTFKeyword::MLIT, 0 },
+ { "mlMargin", RTFControlType::VALUE, RTFKeyword::MLMARGIN, 0 },
+ { "mm", RTFControlType::DESTINATION, RTFKeyword::MM, 0 },
+ { "mmaddfieldname", RTFControlType::DESTINATION, RTFKeyword::MMADDFIELDNAME, 0 },
+ { "mmath", RTFControlType::DESTINATION, RTFKeyword::MMATH, 0 },
+ { "mmathFont", RTFControlType::VALUE, RTFKeyword::MMATHFONT, 0 },
+ { "mmathPict", RTFControlType::DESTINATION, RTFKeyword::MMATHPICT, 0 },
+ { "mmathPr", RTFControlType::DESTINATION, RTFKeyword::MMATHPR, 0 },
+ { "mmattach", RTFControlType::FLAG, RTFKeyword::MMATTACH, 0 },
+ { "mmaxdist", RTFControlType::DESTINATION, RTFKeyword::MMAXDIST, 0 },
+ { "mmblanklines", RTFControlType::FLAG, RTFKeyword::MMBLANKLINES, 0 },
+ { "mmc", RTFControlType::DESTINATION, RTFKeyword::MMC, 0 },
+ { "mmcJc", RTFControlType::DESTINATION, RTFKeyword::MMCJC, 0 },
+ { "mmconnectstr", RTFControlType::DESTINATION, RTFKeyword::MMCONNECTSTR, 0 },
+ { "mmconnectstrdata", RTFControlType::DESTINATION, RTFKeyword::MMCONNECTSTRDATA, 0 },
+ { "mmcPr", RTFControlType::DESTINATION, RTFKeyword::MMCPR, 0 },
+ { "mmcs", RTFControlType::DESTINATION, RTFKeyword::MMCS, 0 },
+ { "mmdatasource", RTFControlType::DESTINATION, RTFKeyword::MMDATASOURCE, 0 },
+ { "mmdatatypeaccess", RTFControlType::FLAG, RTFKeyword::MMDATATYPEACCESS, 0 },
+ { "mmdatatypeexcel", RTFControlType::FLAG, RTFKeyword::MMDATATYPEEXCEL, 0 },
+ { "mmdatatypefile", RTFControlType::FLAG, RTFKeyword::MMDATATYPEFILE, 0 },
+ { "mmdatatypeodbc", RTFControlType::FLAG, RTFKeyword::MMDATATYPEODBC, 0 },
+ { "mmdatatypeodso", RTFControlType::FLAG, RTFKeyword::MMDATATYPEODSO, 0 },
+ { "mmdatatypeqt", RTFControlType::FLAG, RTFKeyword::MMDATATYPEQT, 0 },
+ { "mmdefaultsql", RTFControlType::FLAG, RTFKeyword::MMDEFAULTSQL, 0 },
+ { "mmdestemail", RTFControlType::FLAG, RTFKeyword::MMDESTEMAIL, 0 },
+ { "mmdestfax", RTFControlType::FLAG, RTFKeyword::MMDESTFAX, 0 },
+ { "mmdestnewdoc", RTFControlType::FLAG, RTFKeyword::MMDESTNEWDOC, 0 },
+ { "mmdestprinter", RTFControlType::FLAG, RTFKeyword::MMDESTPRINTER, 0 },
+ { "mmerrors", RTFControlType::VALUE, RTFKeyword::MMERRORS, 0 },
+ { "mmfttypeaddress", RTFControlType::FLAG, RTFKeyword::MMFTTYPEADDRESS, 0 },
+ { "mmfttypebarcode", RTFControlType::FLAG, RTFKeyword::MMFTTYPEBARCODE, 0 },
+ { "mmfttypedbcolumn", RTFControlType::FLAG, RTFKeyword::MMFTTYPEDBCOLUMN, 0 },
+ { "mmfttypemapped", RTFControlType::FLAG, RTFKeyword::MMFTTYPEMAPPED, 0 },
+ { "mmfttypenull", RTFControlType::FLAG, RTFKeyword::MMFTTYPENULL, 0 },
+ { "mmfttypesalutation", RTFControlType::FLAG, RTFKeyword::MMFTTYPESALUTATION, 0 },
+ { "mmheadersource", RTFControlType::DESTINATION, RTFKeyword::MMHEADERSOURCE, 0 },
+ { "mmjdsotype", RTFControlType::VALUE, RTFKeyword::MMJDSOTYPE, 0 },
+ { "mmlinktoquery", RTFControlType::FLAG, RTFKeyword::MMLINKTOQUERY, 0 },
+ { "mmmailsubject", RTFControlType::DESTINATION, RTFKeyword::MMMAILSUBJECT, 0 },
+ { "mmmaintypecatalog", RTFControlType::FLAG, RTFKeyword::MMMAINTYPECATALOG, 0 },
+ { "mmmaintypeemail", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEEMAIL, 0 },
+ { "mmmaintypeenvelopes", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEENVELOPES, 0 },
+ { "mmmaintypefax", RTFControlType::FLAG, RTFKeyword::MMMAINTYPEFAX, 0 },
+ { "mmmaintypelabels", RTFControlType::FLAG, RTFKeyword::MMMAINTYPELABELS, 0 },
+ { "mmmaintypeletters", RTFControlType::FLAG, RTFKeyword::MMMAINTYPELETTERS, 0 },
+ { "mmodso", RTFControlType::DESTINATION, RTFKeyword::MMODSO, 0 },
+ { "mmodsoactive", RTFControlType::VALUE, RTFKeyword::MMODSOACTIVE, 0 },
+ { "mmodsocoldelim", RTFControlType::VALUE, RTFKeyword::MMODSOCOLDELIM, 0 },
+ { "mmodsocolumn", RTFControlType::VALUE, RTFKeyword::MMODSOCOLUMN, 0 },
+ { "mmodsodynaddr", RTFControlType::VALUE, RTFKeyword::MMODSODYNADDR, 0 },
+ { "mmodsofhdr", RTFControlType::VALUE, RTFKeyword::MMODSOFHDR, 0 },
+ { "mmodsofilter", RTFControlType::DESTINATION, RTFKeyword::MMODSOFILTER, 0 },
+ { "mmodsofldmpdata", RTFControlType::DESTINATION, RTFKeyword::MMODSOFLDMPDATA, 0 },
+ { "mmodsofmcolumn", RTFControlType::VALUE, RTFKeyword::MMODSOFMCOLUMN, 0 },
+ { "mmodsohash", RTFControlType::VALUE, RTFKeyword::MMODSOHASH, 0 },
+ { "mmodsolid", RTFControlType::VALUE, RTFKeyword::MMODSOLID, 0 },
+ { "mmodsomappedname", RTFControlType::DESTINATION, RTFKeyword::MMODSOMAPPEDNAME, 0 },
+ { "mmodsoname", RTFControlType::DESTINATION, RTFKeyword::MMODSONAME, 0 },
+ { "mmodsorecipdata", RTFControlType::DESTINATION, RTFKeyword::MMODSORECIPDATA, 0 },
+ { "mmodsosort", RTFControlType::DESTINATION, RTFKeyword::MMODSOSORT, 0 },
+ { "mmodsosrc", RTFControlType::DESTINATION, RTFKeyword::MMODSOSRC, 0 },
+ { "mmodsotable", RTFControlType::DESTINATION, RTFKeyword::MMODSOTABLE, 0 },
+ { "mmodsoudl", RTFControlType::DESTINATION, RTFKeyword::MMODSOUDL, 0 },
+ { "mmodsoudldata", RTFControlType::DESTINATION, RTFKeyword::MMODSOUDLDATA, 0 },
+ { "mmodsouniquetag", RTFControlType::DESTINATION, RTFKeyword::MMODSOUNIQUETAG, 0 },
+ { "mmPr", RTFControlType::DESTINATION, RTFKeyword::MMPR, 0 },
+ { "mmquery", RTFControlType::DESTINATION, RTFKeyword::MMQUERY, 0 },
+ { "mmr", RTFControlType::DESTINATION, RTFKeyword::MMR, 0 },
+ { "mmreccur", RTFControlType::VALUE, RTFKeyword::MMRECCUR, 0 },
+ { "mmshowdata", RTFControlType::FLAG, RTFKeyword::MMSHOWDATA, 0 },
+ { "mnary", RTFControlType::DESTINATION, RTFKeyword::MNARY, 0 },
+ { "mnaryLim", RTFControlType::VALUE, RTFKeyword::MNARYLIM, 0 },
+ { "mnaryPr", RTFControlType::DESTINATION, RTFKeyword::MNARYPR, 0 },
+ { "mnoBreak", RTFControlType::DESTINATION, RTFKeyword::MNOBREAK, 0 },
+ { "mnor", RTFControlType::FLAG, RTFKeyword::MNOR, 0 },
+ { "mnum", RTFControlType::DESTINATION, RTFKeyword::MNUM, 0 },
+ { "mo", RTFControlType::VALUE, RTFKeyword::MO, 0 },
+ { "mobjDist", RTFControlType::DESTINATION, RTFKeyword::MOBJDIST, 0 },
+ { "moMath", RTFControlType::DESTINATION, RTFKeyword::MOMATH, 0 },
+ { "moMathPara", RTFControlType::DESTINATION, RTFKeyword::MOMATHPARA, 0 },
+ { "moMathParaPr", RTFControlType::DESTINATION, RTFKeyword::MOMATHPARAPR, 0 },
+ { "mopEmu", RTFControlType::DESTINATION, RTFKeyword::MOPEMU, 0 },
+ { "mphant", RTFControlType::DESTINATION, RTFKeyword::MPHANT, 0 },
+ { "mphantPr", RTFControlType::DESTINATION, RTFKeyword::MPHANTPR, 0 },
+ { "mplcHide", RTFControlType::DESTINATION, RTFKeyword::MPLCHIDE, 0 },
+ { "mpos", RTFControlType::DESTINATION, RTFKeyword::MPOS, 0 },
+ { "mpostSp", RTFControlType::VALUE, RTFKeyword::MPOSTSP, 0 },
+ { "mpreSp", RTFControlType::VALUE, RTFKeyword::MPRESP, 0 },
+ { "mr", RTFControlType::DESTINATION, RTFKeyword::MR, 0 },
+ { "mrad", RTFControlType::DESTINATION, RTFKeyword::MRAD, 0 },
+ { "mradPr", RTFControlType::DESTINATION, RTFKeyword::MRADPR, 0 },
+ { "mrMargin", RTFControlType::VALUE, RTFKeyword::MRMARGIN, 0 },
+ { "mrPr", RTFControlType::DESTINATION, RTFKeyword::MRPR, 0 },
+ { "mrSp", RTFControlType::VALUE, RTFKeyword::MRSP, 0 },
+ { "mrSpRule", RTFControlType::VALUE, RTFKeyword::MRSPRULE, 0 },
+ { "mscr", RTFControlType::VALUE, RTFKeyword::MSCR, 0 },
+ { "msepChr", RTFControlType::DESTINATION, RTFKeyword::MSEPCHR, 0 },
+ { "mshow", RTFControlType::DESTINATION, RTFKeyword::MSHOW, 0 },
+ { "mshp", RTFControlType::DESTINATION, RTFKeyword::MSHP, 0 },
+ { "msmallFrac", RTFControlType::VALUE, RTFKeyword::MSMALLFRAC, 0 },
+ { "msmcap", RTFControlType::FLAG, RTFKeyword::MSMCAP, 0 },
+ { "msPre", RTFControlType::DESTINATION, RTFKeyword::MSPRE, 0 },
+ { "msPrePr", RTFControlType::DESTINATION, RTFKeyword::MSPREPR, 0 },
+ { "msSub", RTFControlType::DESTINATION, RTFKeyword::MSSUB, 0 },
+ { "msSubPr", RTFControlType::DESTINATION, RTFKeyword::MSSUBPR, 0 },
+ { "msSubSup", RTFControlType::DESTINATION, RTFKeyword::MSSUBSUP, 0 },
+ { "msSubSupPr", RTFControlType::DESTINATION, RTFKeyword::MSSUBSUPPR, 0 },
+ { "msSup", RTFControlType::DESTINATION, RTFKeyword::MSSUP, 0 },
+ { "msSupPr", RTFControlType::DESTINATION, RTFKeyword::MSSUPPR, 0 },
+ { "mstrikeBLTR", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEBLTR, 0 },
+ { "mstrikeH", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEH, 0 },
+ { "mstrikeTLBR", RTFControlType::DESTINATION, RTFKeyword::MSTRIKETLBR, 0 },
+ { "mstrikeV", RTFControlType::DESTINATION, RTFKeyword::MSTRIKEV, 0 },
+ { "msty", RTFControlType::VALUE, RTFKeyword::MSTY, 0 },
+ { "msub", RTFControlType::DESTINATION, RTFKeyword::MSUB, 0 },
+ { "msubHide", RTFControlType::DESTINATION, RTFKeyword::MSUBHIDE, 0 },
+ { "msup", RTFControlType::DESTINATION, RTFKeyword::MSUP, 0 },
+ { "msupHide", RTFControlType::DESTINATION, RTFKeyword::MSUPHIDE, 0 },
+ { "mtransp", RTFControlType::DESTINATION, RTFKeyword::MTRANSP, 0 },
+ { "mtype", RTFControlType::DESTINATION, RTFKeyword::MTYPE, 0 },
+ { "muser", RTFControlType::FLAG, RTFKeyword::MUSER, 0 },
+ { "mvauth", RTFControlType::VALUE, RTFKeyword::MVAUTH, 0 },
+ { "mvdate", RTFControlType::VALUE, RTFKeyword::MVDATE, 0 },
+ { "mvertJc", RTFControlType::DESTINATION, RTFKeyword::MVERTJC, 0 },
+ { "mvf", RTFControlType::FLAG, RTFKeyword::MVF, 0 },
+ { "mvfmf", RTFControlType::DESTINATION, RTFKeyword::MVFMF, 0 },
+ { "mvfml", RTFControlType::DESTINATION, RTFKeyword::MVFML, 0 },
+ { "mvt", RTFControlType::FLAG, RTFKeyword::MVT, 0 },
+ { "mvtof", RTFControlType::DESTINATION, RTFKeyword::MVTOF, 0 },
+ { "mvtol", RTFControlType::DESTINATION, RTFKeyword::MVTOL, 0 },
+ { "mwrapIndent", RTFControlType::VALUE, RTFKeyword::MWRAPINDENT, 1440 },
+ { "mwrapRight", RTFControlType::VALUE, RTFKeyword::MWRAPRIGHT, 0 },
+ { "mzeroAsc", RTFControlType::DESTINATION, RTFKeyword::MZEROASC, 0 },
+ { "mzeroDesc", RTFControlType::DESTINATION, RTFKeyword::MZERODESC, 0 },
+ { "mzeroWid", RTFControlType::DESTINATION, RTFKeyword::MZEROWID, 0 },
+ { "nestcell", RTFControlType::SYMBOL, RTFKeyword::NESTCELL, 0 },
+ { "nestrow", RTFControlType::SYMBOL, RTFKeyword::NESTROW, 0 },
+ { "nesttableprops", RTFControlType::DESTINATION, RTFKeyword::NESTTABLEPROPS, 0 },
+ { "newtblstyruls", RTFControlType::FLAG, RTFKeyword::NEWTBLSTYRULS, 0 },
+ { "nextfile", RTFControlType::DESTINATION, RTFKeyword::NEXTFILE, 0 },
+ { "noafcnsttbl", RTFControlType::FLAG, RTFKeyword::NOAFCNSTTBL, 0 },
+ { "nobrkwrptbl", RTFControlType::FLAG, RTFKeyword::NOBRKWRPTBL, 0 },
+ { "nocolbal", RTFControlType::FLAG, RTFKeyword::NOCOLBAL, 0 },
+ { "nocompatoptions", RTFControlType::FLAG, RTFKeyword::NOCOMPATOPTIONS, 0 },
+ { "nocwrap", RTFControlType::FLAG, RTFKeyword::NOCWRAP, 0 },
+ { "nocxsptable", RTFControlType::FLAG, RTFKeyword::NOCXSPTABLE, 0 },
+ { "noextrasprl", RTFControlType::FLAG, RTFKeyword::NOEXTRASPRL, 0 },
+ { "nofchars", RTFControlType::VALUE, RTFKeyword::NOFCHARS, 0 },
+ { "nofcharsws", RTFControlType::VALUE, RTFKeyword::NOFCHARSWS, 0 },
+ { "nofeaturethrottle", RTFControlType::FLAG, RTFKeyword::NOFEATURETHROTTLE, 0 },
+ { "nofpages", RTFControlType::VALUE, RTFKeyword::NOFPAGES, 0 },
+ { "nofwords", RTFControlType::VALUE, RTFKeyword::NOFWORDS, 0 },
+ { "nogrowautofit", RTFControlType::FLAG, RTFKeyword::NOGROWAUTOFIT, 0 },
+ { "noindnmbrts", RTFControlType::FLAG, RTFKeyword::NOINDNMBRTS, 0 },
+ { "nojkernpunct", RTFControlType::FLAG, RTFKeyword::NOJKERNPUNCT, 0 },
+ { "nolead", RTFControlType::FLAG, RTFKeyword::NOLEAD, 0 },
+ { "noline", RTFControlType::FLAG, RTFKeyword::NOLINE, 0 },
+ { "nolnhtadjtbl", RTFControlType::FLAG, RTFKeyword::NOLNHTADJTBL, 0 },
+ { "nonesttables", RTFControlType::DESTINATION, RTFKeyword::NONESTTABLES, 0 },
+ { "nonshppict", RTFControlType::FLAG, RTFKeyword::NONSHPPICT, 0 },
+ { "nooverflow", RTFControlType::FLAG, RTFKeyword::NOOVERFLOW, 0 },
+ { "noproof", RTFControlType::FLAG, RTFKeyword::NOPROOF, 0 },
+ { "noqfpromote", RTFControlType::FLAG, RTFKeyword::NOQFPROMOTE, 0 },
+ { "nosectexpand", RTFControlType::FLAG, RTFKeyword::NOSECTEXPAND, 0 },
+ { "nosnaplinegrid", RTFControlType::FLAG, RTFKeyword::NOSNAPLINEGRID, 0 },
+ { "nospaceforul", RTFControlType::FLAG, RTFKeyword::NOSPACEFORUL, 0 },
+ { "nosupersub", RTFControlType::FLAG, RTFKeyword::NOSUPERSUB, 0 },
+ { "notabind", RTFControlType::FLAG, RTFKeyword::NOTABIND, 0 },
+ { "notbrkcnstfrctbl", RTFControlType::FLAG, RTFKeyword::NOTBRKCNSTFRCTBL, 0 },
+ { "notcvasp", RTFControlType::FLAG, RTFKeyword::NOTCVASP, 0 },
+ { "notvatxbx", RTFControlType::FLAG, RTFKeyword::NOTVATXBX, 0 },
+ { "nouicompat", RTFControlType::FLAG, RTFKeyword::NOUICOMPAT, 0 },
+ { "noultrlspc", RTFControlType::FLAG, RTFKeyword::NOULTRLSPC, 0 },
+ { "nowidctlpar", RTFControlType::FLAG, RTFKeyword::NOWIDCTLPAR, 0 },
+ { "nowrap", RTFControlType::FLAG, RTFKeyword::NOWRAP, 0 },
+ { "nowwrap", RTFControlType::FLAG, RTFKeyword::NOWWRAP, 0 },
+ { "noxlattoyen", RTFControlType::FLAG, RTFKeyword::NOXLATTOYEN, 0 },
+ { "objalias", RTFControlType::DESTINATION, RTFKeyword::OBJALIAS, 0 },
+ { "objalign", RTFControlType::VALUE, RTFKeyword::OBJALIGN, 0 },
+ { "objattph", RTFControlType::FLAG, RTFKeyword::OBJATTPH, 0 },
+ { "objautlink", RTFControlType::FLAG, RTFKeyword::OBJAUTLINK, 0 },
+ { "objclass", RTFControlType::DESTINATION, RTFKeyword::OBJCLASS, 0 },
+ { "objcropb", RTFControlType::VALUE, RTFKeyword::OBJCROPB, 0 },
+ { "objcropl", RTFControlType::VALUE, RTFKeyword::OBJCROPL, 0 },
+ { "objcropr", RTFControlType::VALUE, RTFKeyword::OBJCROPR, 0 },
+ { "objcropt", RTFControlType::VALUE, RTFKeyword::OBJCROPT, 0 },
+ { "objdata", RTFControlType::DESTINATION, RTFKeyword::OBJDATA, 0 },
+ { "object", RTFControlType::DESTINATION, RTFKeyword::OBJECT, 0 },
+ { "objemb", RTFControlType::FLAG, RTFKeyword::OBJEMB, 0 },
+ { "objh", RTFControlType::VALUE, RTFKeyword::OBJH, 0 },
+ { "objhtml", RTFControlType::FLAG, RTFKeyword::OBJHTML, 0 },
+ { "objicemb", RTFControlType::FLAG, RTFKeyword::OBJICEMB, 0 },
+ { "objlink", RTFControlType::FLAG, RTFKeyword::OBJLINK, 0 },
+ { "objlock", RTFControlType::FLAG, RTFKeyword::OBJLOCK, 0 },
+ { "objname", RTFControlType::DESTINATION, RTFKeyword::OBJNAME, 0 },
+ { "objocx", RTFControlType::FLAG, RTFKeyword::OBJOCX, 0 },
+ { "objpub", RTFControlType::FLAG, RTFKeyword::OBJPUB, 0 },
+ { "objscalex", RTFControlType::VALUE, RTFKeyword::OBJSCALEX, 0 },
+ { "objscaley", RTFControlType::VALUE, RTFKeyword::OBJSCALEY, 0 },
+ { "objsect", RTFControlType::DESTINATION, RTFKeyword::OBJSECT, 0 },
+ { "objsetsize", RTFControlType::FLAG, RTFKeyword::OBJSETSIZE, 0 },
+ { "objsub", RTFControlType::FLAG, RTFKeyword::OBJSUB, 0 },
+ { "objtime", RTFControlType::DESTINATION, RTFKeyword::OBJTIME, 0 },
+ { "objtransy", RTFControlType::VALUE, RTFKeyword::OBJTRANSY, 0 },
+ { "objupdate", RTFControlType::FLAG, RTFKeyword::OBJUPDATE, 0 },
+ { "objw", RTFControlType::VALUE, RTFKeyword::OBJW, 0 },
+ { "ogutter", RTFControlType::VALUE, RTFKeyword::OGUTTER, 0 },
+ { "oldas", RTFControlType::FLAG, RTFKeyword::OLDAS, 0 },
+ { "oldcprops", RTFControlType::DESTINATION, RTFKeyword::OLDCPROPS, 0 },
+ { "oldlinewrap", RTFControlType::FLAG, RTFKeyword::OLDLINEWRAP, 0 },
+ { "oldpprops", RTFControlType::DESTINATION, RTFKeyword::OLDPPROPS, 0 },
+ { "oldsprops", RTFControlType::DESTINATION, RTFKeyword::OLDSPROPS, 0 },
+ { "oldtprops", RTFControlType::DESTINATION, RTFKeyword::OLDTPROPS, 0 },
+ { "oleclsid", RTFControlType::DESTINATION, RTFKeyword::OLECLSID, 0 },
+ { "operator", RTFControlType::DESTINATION, RTFKeyword::OPERATOR, 0 },
+ { "otblrul", RTFControlType::FLAG, RTFKeyword::OTBLRUL, 0 },
+ { "outl", RTFControlType::TOGGLE, RTFKeyword::OUTL, 1 },
+ { "outlinelevel", RTFControlType::VALUE, RTFKeyword::OUTLINELEVEL, 0 },
+ { "overlay", RTFControlType::FLAG, RTFKeyword::OVERLAY, 0 },
+ { "page", RTFControlType::SYMBOL, RTFKeyword::PAGE, 0 },
+ { "pagebb", RTFControlType::FLAG, RTFKeyword::PAGEBB, 0 },
+ { "panose", RTFControlType::DESTINATION, RTFKeyword::PANOSE, 0 },
+ { "paperh", RTFControlType::VALUE, RTFKeyword::PAPERH, 15840 },
+ { "paperw", RTFControlType::VALUE, RTFKeyword::PAPERW, 12240 },
+ { "par", RTFControlType::SYMBOL, RTFKeyword::PAR, 0 },
+ { "pararsid", RTFControlType::VALUE, RTFKeyword::PARARSID, 0 },
+ { "pard", RTFControlType::FLAG, RTFKeyword::PARD, 0 },
+ { "password", RTFControlType::DESTINATION, RTFKeyword::PASSWORD, 0 },
+ { "passwordhash", RTFControlType::DESTINATION, RTFKeyword::PASSWORDHASH, 0 },
+ { "pc", RTFControlType::FLAG, RTFKeyword::PC, 0 },
+ { "pca", RTFControlType::FLAG, RTFKeyword::PCA, 0 },
+ { "pgbrdrb", RTFControlType::FLAG, RTFKeyword::PGBRDRB, 0 },
+ { "pgbrdrfoot", RTFControlType::FLAG, RTFKeyword::PGBRDRFOOT, 0 },
+ { "pgbrdrhead", RTFControlType::FLAG, RTFKeyword::PGBRDRHEAD, 0 },
+ { "pgbrdrl", RTFControlType::FLAG, RTFKeyword::PGBRDRL, 0 },
+ { "pgbrdropt", RTFControlType::VALUE, RTFKeyword::PGBRDROPT, 0 },
+ { "pgbrdrr", RTFControlType::FLAG, RTFKeyword::PGBRDRR, 0 },
+ { "pgbrdrsnap", RTFControlType::FLAG, RTFKeyword::PGBRDRSNAP, 0 },
+ { "pgbrdrt", RTFControlType::FLAG, RTFKeyword::PGBRDRT, 0 },
+ { "pghsxn", RTFControlType::VALUE, RTFKeyword::PGHSXN, 0 },
+ { "pgnbidia", RTFControlType::FLAG, RTFKeyword::PGNBIDIA, 0 },
+ { "pgnbidib", RTFControlType::FLAG, RTFKeyword::PGNBIDIB, 0 },
+ { "pgnchosung", RTFControlType::FLAG, RTFKeyword::PGNCHOSUNG, 0 },
+ { "pgncnum", RTFControlType::FLAG, RTFKeyword::PGNCNUM, 0 },
+ { "pgncont", RTFControlType::FLAG, RTFKeyword::PGNCONT, 0 },
+ { "pgndbnum", RTFControlType::FLAG, RTFKeyword::PGNDBNUM, 0 },
+ { "pgndbnumd", RTFControlType::FLAG, RTFKeyword::PGNDBNUMD, 0 },
+ { "pgndbnumk", RTFControlType::FLAG, RTFKeyword::PGNDBNUMK, 0 },
+ { "pgndbnumt", RTFControlType::FLAG, RTFKeyword::PGNDBNUMT, 0 },
+ { "pgndec", RTFControlType::FLAG, RTFKeyword::PGNDEC, 0 },
+ { "pgndecd", RTFControlType::FLAG, RTFKeyword::PGNDECD, 0 },
+ { "pgnganada", RTFControlType::FLAG, RTFKeyword::PGNGANADA, 0 },
+ { "pgngbnum", RTFControlType::FLAG, RTFKeyword::PGNGBNUM, 0 },
+ { "pgngbnumd", RTFControlType::FLAG, RTFKeyword::PGNGBNUMD, 0 },
+ { "pgngbnumk", RTFControlType::FLAG, RTFKeyword::PGNGBNUMK, 0 },
+ { "pgngbnuml", RTFControlType::FLAG, RTFKeyword::PGNGBNUML, 0 },
+ { "pgnhindia", RTFControlType::FLAG, RTFKeyword::PGNHINDIA, 0 },
+ { "pgnhindib", RTFControlType::FLAG, RTFKeyword::PGNHINDIB, 0 },
+ { "pgnhindic", RTFControlType::FLAG, RTFKeyword::PGNHINDIC, 0 },
+ { "pgnhindid", RTFControlType::FLAG, RTFKeyword::PGNHINDID, 0 },
+ { "pgnhn", RTFControlType::VALUE, RTFKeyword::PGNHN, 0 },
+ { "pgnhnsc", RTFControlType::FLAG, RTFKeyword::PGNHNSC, 0 },
+ { "pgnhnsh", RTFControlType::FLAG, RTFKeyword::PGNHNSH, 0 },
+ { "pgnhnsm", RTFControlType::FLAG, RTFKeyword::PGNHNSM, 0 },
+ { "pgnhnsn", RTFControlType::FLAG, RTFKeyword::PGNHNSN, 0 },
+ { "pgnhnsp", RTFControlType::FLAG, RTFKeyword::PGNHNSP, 0 },
+ { "pgnid", RTFControlType::FLAG, RTFKeyword::PGNID, 0 },
+ { "pgnlcltr", RTFControlType::FLAG, RTFKeyword::PGNLCLTR, 0 },
+ { "pgnlcrm", RTFControlType::FLAG, RTFKeyword::PGNLCRM, 0 },
+ { "pgnrestart", RTFControlType::FLAG, RTFKeyword::PGNRESTART, 0 },
+ { "pgnstart", RTFControlType::VALUE, RTFKeyword::PGNSTART, 1 },
+ { "pgnstarts", RTFControlType::VALUE, RTFKeyword::PGNSTARTS, 1 },
+ { "pgnthaia", RTFControlType::FLAG, RTFKeyword::PGNTHAIA, 0 },
+ { "pgnthaib", RTFControlType::FLAG, RTFKeyword::PGNTHAIB, 0 },
+ { "pgnthaic", RTFControlType::FLAG, RTFKeyword::PGNTHAIC, 0 },
+ { "pgnucltr", RTFControlType::FLAG, RTFKeyword::PGNUCLTR, 0 },
+ { "pgnucrm", RTFControlType::FLAG, RTFKeyword::PGNUCRM, 0 },
+ { "pgnvieta", RTFControlType::FLAG, RTFKeyword::PGNVIETA, 0 },
+ { "pgnx", RTFControlType::VALUE, RTFKeyword::PGNX, 720 },
+ { "pgny", RTFControlType::VALUE, RTFKeyword::PGNY, 720 },
+ { "pgnzodiac", RTFControlType::FLAG, RTFKeyword::PGNZODIAC, 0 },
+ { "pgnzodiacd", RTFControlType::FLAG, RTFKeyword::PGNZODIACD, 0 },
+ { "pgnzodiacl", RTFControlType::FLAG, RTFKeyword::PGNZODIACL, 0 },
+ { "pgp", RTFControlType::DESTINATION, RTFKeyword::PGP, 0 },
+ { "pgptbl", RTFControlType::DESTINATION, RTFKeyword::PGPTBL, 0 },
+ { "pgwsxn", RTFControlType::VALUE, RTFKeyword::PGWSXN, 0 },
+ { "phcol", RTFControlType::FLAG, RTFKeyword::PHCOL, 0 },
+ { "phmrg", RTFControlType::FLAG, RTFKeyword::PHMRG, 0 },
+ { "phpg", RTFControlType::FLAG, RTFKeyword::PHPG, 0 },
+ { "picbmp", RTFControlType::FLAG, RTFKeyword::PICBMP, 0 },
+ { "picbpp", RTFControlType::VALUE, RTFKeyword::PICBPP, 0 },
+ { "piccropb", RTFControlType::VALUE, RTFKeyword::PICCROPB, 0 },
+ { "piccropl", RTFControlType::VALUE, RTFKeyword::PICCROPL, 0 },
+ { "piccropr", RTFControlType::VALUE, RTFKeyword::PICCROPR, 0 },
+ { "piccropt", RTFControlType::VALUE, RTFKeyword::PICCROPT, 0 },
+ { "pich", RTFControlType::VALUE, RTFKeyword::PICH, 0 },
+ { "pichgoal", RTFControlType::VALUE, RTFKeyword::PICHGOAL, 0 },
+ { "pichGoal", RTFControlType::VALUE, RTFKeyword::PICHGOAL, 0 },
+ { "picprop", RTFControlType::DESTINATION, RTFKeyword::PICPROP, 0 },
+ { "picscaled", RTFControlType::FLAG, RTFKeyword::PICSCALED, 0 },
+ { "picscalex", RTFControlType::VALUE, RTFKeyword::PICSCALEX, 100 },
+ { "picscaley", RTFControlType::VALUE, RTFKeyword::PICSCALEY, 100 },
+ { "pict", RTFControlType::DESTINATION, RTFKeyword::PICT, 0 },
+ { "picw", RTFControlType::VALUE, RTFKeyword::PICW, 0 },
+ { "picwgoal", RTFControlType::VALUE, RTFKeyword::PICWGOAL, 0 },
+ { "picwGoal", RTFControlType::VALUE, RTFKeyword::PICWGOAL, 0 },
+ { "pindtabqc", RTFControlType::FLAG, RTFKeyword::PINDTABQC, 0 },
+ { "pindtabql", RTFControlType::FLAG, RTFKeyword::PINDTABQL, 0 },
+ { "pindtabqr", RTFControlType::FLAG, RTFKeyword::PINDTABQR, 0 },
+ { "plain", RTFControlType::FLAG, RTFKeyword::PLAIN, 0 },
+ { "pmartabqc", RTFControlType::FLAG, RTFKeyword::PMARTABQC, 0 },
+ { "pmartabql", RTFControlType::FLAG, RTFKeyword::PMARTABQL, 0 },
+ { "pmartabqr", RTFControlType::FLAG, RTFKeyword::PMARTABQR, 0 },
+ { "pmmetafile", RTFControlType::VALUE, RTFKeyword::PMMETAFILE, 0 },
+ { "pn", RTFControlType::DESTINATION, RTFKeyword::PN, 0 },
+ { "pnacross", RTFControlType::FLAG, RTFKeyword::PNACROSS, 0 },
+ { "pnaiu", RTFControlType::FLAG, RTFKeyword::PNAIU, 0 },
+ { "pnaiud", RTFControlType::FLAG, RTFKeyword::PNAIUD, 0 },
+ { "pnaiueo", RTFControlType::FLAG, RTFKeyword::PNAIUEO, 0 },
+ { "pnaiueod", RTFControlType::FLAG, RTFKeyword::PNAIUEOD, 0 },
+ { "pnb", RTFControlType::TOGGLE, RTFKeyword::PNB, 1 },
+ { "pnbidia", RTFControlType::FLAG, RTFKeyword::PNBIDIA, 0 },
+ { "pnbidib", RTFControlType::FLAG, RTFKeyword::PNBIDIB, 0 },
+ { "pncaps", RTFControlType::TOGGLE, RTFKeyword::PNCAPS, 1 },
+ { "pncard", RTFControlType::FLAG, RTFKeyword::PNCARD, 0 },
+ { "pncf", RTFControlType::VALUE, RTFKeyword::PNCF, 0 },
+ { "pnchosung", RTFControlType::FLAG, RTFKeyword::PNCHOSUNG, 0 },
+ { "pncnum", RTFControlType::FLAG, RTFKeyword::PNCNUM, 0 },
+ { "pndbnum", RTFControlType::FLAG, RTFKeyword::PNDBNUM, 0 },
+ { "pndbnumd", RTFControlType::FLAG, RTFKeyword::PNDBNUMD, 0 },
+ { "pndbnumk", RTFControlType::FLAG, RTFKeyword::PNDBNUMK, 0 },
+ { "pndbnuml", RTFControlType::FLAG, RTFKeyword::PNDBNUML, 0 },
+ { "pndbnumt", RTFControlType::FLAG, RTFKeyword::PNDBNUMT, 0 },
+ { "pndec", RTFControlType::FLAG, RTFKeyword::PNDEC, 0 },
+ { "pndecd", RTFControlType::FLAG, RTFKeyword::PNDECD, 0 },
+ { "pnf", RTFControlType::VALUE, RTFKeyword::PNF, 0 },
+ { "pnfs", RTFControlType::VALUE, RTFKeyword::PNFS, 0 },
+ { "pnganada", RTFControlType::FLAG, RTFKeyword::PNGANADA, 0 },
+ { "pngblip", RTFControlType::FLAG, RTFKeyword::PNGBLIP, 0 },
+ { "pngbnum", RTFControlType::FLAG, RTFKeyword::PNGBNUM, 0 },
+ { "pngbnumd", RTFControlType::FLAG, RTFKeyword::PNGBNUMD, 0 },
+ { "pngbnumk", RTFControlType::FLAG, RTFKeyword::PNGBNUMK, 0 },
+ { "pngbnuml", RTFControlType::FLAG, RTFKeyword::PNGBNUML, 0 },
+ { "pnhang", RTFControlType::FLAG, RTFKeyword::PNHANG, 0 },
+ { "pni", RTFControlType::TOGGLE, RTFKeyword::PNI, 1 },
+ { "pnindent", RTFControlType::VALUE, RTFKeyword::PNINDENT, 0 },
+ { "pniroha", RTFControlType::FLAG, RTFKeyword::PNIROHA, 0 },
+ { "pnirohad", RTFControlType::FLAG, RTFKeyword::PNIROHAD, 0 },
+ { "pnlcltr", RTFControlType::FLAG, RTFKeyword::PNLCLTR, 0 },
+ { "pnlcrm", RTFControlType::FLAG, RTFKeyword::PNLCRM, 0 },
+ { "pnlvl", RTFControlType::VALUE, RTFKeyword::PNLVL, 0 },
+ { "pnlvlblt", RTFControlType::FLAG, RTFKeyword::PNLVLBLT, 0 },
+ { "pnlvlbody", RTFControlType::FLAG, RTFKeyword::PNLVLBODY, 0 },
+ { "pnlvlcont", RTFControlType::FLAG, RTFKeyword::PNLVLCONT, 0 },
+ { "pnnumonce", RTFControlType::FLAG, RTFKeyword::PNNUMONCE, 0 },
+ { "pnord", RTFControlType::FLAG, RTFKeyword::PNORD, 0 },
+ { "pnordt", RTFControlType::FLAG, RTFKeyword::PNORDT, 0 },
+ { "pnprev", RTFControlType::FLAG, RTFKeyword::PNPREV, 0 },
+ { "pnqc", RTFControlType::FLAG, RTFKeyword::PNQC, 0 },
+ { "pnql", RTFControlType::FLAG, RTFKeyword::PNQL, 0 },
+ { "pnqr", RTFControlType::FLAG, RTFKeyword::PNQR, 0 },
+ { "pnrauth", RTFControlType::VALUE, RTFKeyword::PNRAUTH, 0 },
+ { "pnrdate", RTFControlType::VALUE, RTFKeyword::PNRDATE, 0 },
+ { "pnrestart", RTFControlType::FLAG, RTFKeyword::PNRESTART, 0 },
+ { "pnrnfc", RTFControlType::VALUE, RTFKeyword::PNRNFC, 0 },
+ { "pnrnot", RTFControlType::FLAG, RTFKeyword::PNRNOT, 0 },
+ { "pnrpnbr", RTFControlType::VALUE, RTFKeyword::PNRPNBR, 0 },
+ { "pnrrgb", RTFControlType::VALUE, RTFKeyword::PNRRGB, 0 },
+ { "pnrstart", RTFControlType::VALUE, RTFKeyword::PNRSTART, 0 },
+ { "pnrstop", RTFControlType::VALUE, RTFKeyword::PNRSTOP, 0 },
+ { "pnrxst", RTFControlType::VALUE, RTFKeyword::PNRXST, 0 },
+ { "pnscaps", RTFControlType::TOGGLE, RTFKeyword::PNSCAPS, 1 },
+ { "pnseclvl", RTFControlType::DESTINATION, RTFKeyword::PNSECLVL, 0 },
+ { "pnsp", RTFControlType::VALUE, RTFKeyword::PNSP, 0 },
+ { "pnstart", RTFControlType::VALUE, RTFKeyword::PNSTART, 0 },
+ { "pnstrike", RTFControlType::TOGGLE, RTFKeyword::PNSTRIKE, 1 },
+ { "pntext", RTFControlType::DESTINATION, RTFKeyword::PNTEXT, 0 },
+ { "pntxta", RTFControlType::DESTINATION, RTFKeyword::PNTXTA, 0 },
+ { "pntxtb", RTFControlType::DESTINATION, RTFKeyword::PNTXTB, 0 },
+ { "pnucltr", RTFControlType::FLAG, RTFKeyword::PNUCLTR, 0 },
+ { "pnucrm", RTFControlType::FLAG, RTFKeyword::PNUCRM, 0 },
+ { "pnul", RTFControlType::TOGGLE, RTFKeyword::PNUL, 1 },
+ { "pnuld", RTFControlType::FLAG, RTFKeyword::PNULD, 0 },
+ { "pnuldash", RTFControlType::FLAG, RTFKeyword::PNULDASH, 0 },
+ { "pnuldashd", RTFControlType::FLAG, RTFKeyword::PNULDASHD, 0 },
+ { "pnuldashdd", RTFControlType::FLAG, RTFKeyword::PNULDASHDD, 0 },
+ { "pnuldb", RTFControlType::FLAG, RTFKeyword::PNULDB, 0 },
+ { "pnulhair", RTFControlType::FLAG, RTFKeyword::PNULHAIR, 0 },
+ { "pnulnone", RTFControlType::FLAG, RTFKeyword::PNULNONE, 0 },
+ { "pnulth", RTFControlType::FLAG, RTFKeyword::PNULTH, 0 },
+ { "pnulw", RTFControlType::FLAG, RTFKeyword::PNULW, 0 },
+ { "pnulwave", RTFControlType::FLAG, RTFKeyword::PNULWAVE, 0 },
+ { "pnzodiac", RTFControlType::FLAG, RTFKeyword::PNZODIAC, 0 },
+ { "pnzodiacd", RTFControlType::FLAG, RTFKeyword::PNZODIACD, 0 },
+ { "pnzodiacl", RTFControlType::FLAG, RTFKeyword::PNZODIACL, 0 },
+ { "posnegx", RTFControlType::VALUE, RTFKeyword::POSNEGX, 0 },
+ { "posnegy", RTFControlType::VALUE, RTFKeyword::POSNEGY, 0 },
+ { "posx", RTFControlType::VALUE, RTFKeyword::POSX, 0 },
+ { "posxc", RTFControlType::FLAG, RTFKeyword::POSXC, 0 },
+ { "posxi", RTFControlType::FLAG, RTFKeyword::POSXI, 0 },
+ { "posxl", RTFControlType::FLAG, RTFKeyword::POSXL, 0 },
+ { "posxo", RTFControlType::FLAG, RTFKeyword::POSXO, 0 },
+ { "posxr", RTFControlType::FLAG, RTFKeyword::POSXR, 0 },
+ { "posy", RTFControlType::VALUE, RTFKeyword::POSY, 0 },
+ { "posyb", RTFControlType::FLAG, RTFKeyword::POSYB, 0 },
+ { "posyc", RTFControlType::FLAG, RTFKeyword::POSYC, 0 },
+ { "posyil", RTFControlType::FLAG, RTFKeyword::POSYIL, 0 },
+ { "posyin", RTFControlType::FLAG, RTFKeyword::POSYIN, 0 },
+ { "posyout", RTFControlType::FLAG, RTFKeyword::POSYOUT, 0 },
+ { "posyt", RTFControlType::FLAG, RTFKeyword::POSYT, 0 },
+ { "prauth", RTFControlType::VALUE, RTFKeyword::PRAUTH, 0 },
+ { "prcolbl", RTFControlType::FLAG, RTFKeyword::PRCOLBL, 0 },
+ { "prdate", RTFControlType::VALUE, RTFKeyword::PRDATE, 0 },
+ { "printdata", RTFControlType::FLAG, RTFKeyword::PRINTDATA, 0 },
+ { "printim", RTFControlType::DESTINATION, RTFKeyword::PRINTIM, 0 },
+ { "private", RTFControlType::DESTINATION, RTFKeyword::PRIVATE, 0 },
+ { "propname", RTFControlType::DESTINATION, RTFKeyword::PROPNAME, 0 },
+ { "proptype", RTFControlType::VALUE, RTFKeyword::PROPTYPE, 0 },
+ { "protect", RTFControlType::TOGGLE, RTFKeyword::PROTECT, 1 },
+ { "protend", RTFControlType::DESTINATION, RTFKeyword::PROTEND, 0 },
+ { "protlevel", RTFControlType::VALUE, RTFKeyword::PROTLEVEL, 0 },
+ { "protstart", RTFControlType::DESTINATION, RTFKeyword::PROTSTART, 0 },
+ { "protusertbl", RTFControlType::DESTINATION, RTFKeyword::PROTUSERTBL, 0 },
+ { "psover", RTFControlType::FLAG, RTFKeyword::PSOVER, 0 },
+ { "psz", RTFControlType::VALUE, RTFKeyword::PSZ, 0 },
+ { "ptabldot", RTFControlType::FLAG, RTFKeyword::PTABLDOT, 0 },
+ { "ptablmdot", RTFControlType::FLAG, RTFKeyword::PTABLMDOT, 0 },
+ { "ptablminus", RTFControlType::FLAG, RTFKeyword::PTABLMINUS, 0 },
+ { "ptablnone", RTFControlType::FLAG, RTFKeyword::PTABLNONE, 0 },
+ { "ptabluscore", RTFControlType::FLAG, RTFKeyword::PTABLUSCORE, 0 },
+ { "pubauto", RTFControlType::FLAG, RTFKeyword::PUBAUTO, 0 },
+ { "pvmrg", RTFControlType::FLAG, RTFKeyword::PVMRG, 0 },
+ { "pvpara", RTFControlType::FLAG, RTFKeyword::PVPARA, 0 },
+ { "pvpg", RTFControlType::FLAG, RTFKeyword::PVPG, 0 },
+ { "pwd", RTFControlType::VALUE, RTFKeyword::PWD, 0 },
+ { "pxe", RTFControlType::DESTINATION, RTFKeyword::PXE, 0 },
+ { "qc", RTFControlType::FLAG, RTFKeyword::QC, 0 },
+ { "qd", RTFControlType::FLAG, RTFKeyword::QD, 0 },
+ { "qj", RTFControlType::FLAG, RTFKeyword::QJ, 0 },
+ { "qk", RTFControlType::VALUE, RTFKeyword::QK, 0 },
+ { "ql", RTFControlType::FLAG, RTFKeyword::QL, 0 },
+ { "qmspace", RTFControlType::SYMBOL, RTFKeyword::QMSPACE, 0 },
+ { "qr", RTFControlType::FLAG, RTFKeyword::QR, 0 },
+ { "qt", RTFControlType::FLAG, RTFKeyword::QT, 0 },
+ { "rawclbgdkbdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKBDIAG, 0 },
+ { "rawclbgbdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGBDIAG, 0 },
+ { "rawclbgcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGCROSS, 0 },
+ { "rawclbgdcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDCROSS, 0 },
+ { "rawclbgdkcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKCROSS, 0 },
+ { "rawclbgdkdcross", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKDCROSS, 0 },
+ { "rawclbgdkfdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKFDIAG, 0 },
+ { "rawclbgdkhor", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKHOR, 0 },
+ { "rawclbgdkvert", RTFControlType::FLAG, RTFKeyword::RAWCLBGDKVERT, 0 },
+ { "rawclbgfdiag", RTFControlType::FLAG, RTFKeyword::RAWCLBGFDIAG, 0 },
+ { "rawclbghoriz", RTFControlType::FLAG, RTFKeyword::RAWCLBGHORIZ, 0 },
+ { "rawclbgvert", RTFControlType::FLAG, RTFKeyword::RAWCLBGVERT, 0 },
+ { "rdblquote", RTFControlType::SYMBOL, RTFKeyword::RDBLQUOTE, 0 },
+ { "readonlyrecommended", RTFControlType::FLAG, RTFKeyword::READONLYRECOMMENDED, 0 },
+ { "readprot", RTFControlType::FLAG, RTFKeyword::READPROT, 0 },
+ { "red", RTFControlType::VALUE, RTFKeyword::RED, 0 },
+ { "relyonvml", RTFControlType::VALUE, RTFKeyword::RELYONVML, 0 },
+ { "remdttm", RTFControlType::FLAG, RTFKeyword::REMDTTM, 0 },
+ { "rempersonalinfo", RTFControlType::FLAG, RTFKeyword::REMPERSONALINFO, 0 },
+ { "result", RTFControlType::DESTINATION, RTFKeyword::RESULT, 0 },
+ { "revauth", RTFControlType::VALUE, RTFKeyword::REVAUTH, 0 },
+ { "revauthdel", RTFControlType::VALUE, RTFKeyword::REVAUTHDEL, 0 },
+ { "revbar", RTFControlType::VALUE, RTFKeyword::REVBAR, 3 },
+ { "revdttm", RTFControlType::VALUE, RTFKeyword::REVDTTM, 0 },
+ { "revdttmdel", RTFControlType::VALUE, RTFKeyword::REVDTTMDEL, 0 },
+ { "revised", RTFControlType::TOGGLE, RTFKeyword::REVISED, 1 },
+ { "revisions", RTFControlType::FLAG, RTFKeyword::REVISIONS, 0 },
+ { "revprop", RTFControlType::VALUE, RTFKeyword::REVPROP, 3 },
+ { "revprot", RTFControlType::FLAG, RTFKeyword::REVPROT, 0 },
+ { "revtbl", RTFControlType::DESTINATION, RTFKeyword::REVTBL, 0 },
+ { "revtim", RTFControlType::DESTINATION, RTFKeyword::REVTIM, 0 },
+ { "ri", RTFControlType::VALUE, RTFKeyword::RI, 0 },
+ { "rin", RTFControlType::VALUE, RTFKeyword::RIN, 0 },
+ { "row", RTFControlType::SYMBOL, RTFKeyword::ROW, 0 },
+ { "rquote", RTFControlType::SYMBOL, RTFKeyword::RQUOTE, 0 },
+ { "rsid", RTFControlType::VALUE, RTFKeyword::RSID, 0 },
+ { "rsidroot", RTFControlType::VALUE, RTFKeyword::RSIDROOT, 0 },
+ { "rsidtbl", RTFControlType::DESTINATION, RTFKeyword::RSIDTBL, 0 },
+ { "rsltbmp", RTFControlType::FLAG, RTFKeyword::RSLTBMP, 0 },
+ { "rslthtml", RTFControlType::FLAG, RTFKeyword::RSLTHTML, 0 },
+ { "rsltmerge", RTFControlType::FLAG, RTFKeyword::RSLTMERGE, 0 },
+ { "rsltpict", RTFControlType::FLAG, RTFKeyword::RSLTPICT, 0 },
+ { "rsltrtf", RTFControlType::FLAG, RTFKeyword::RSLTRTF, 0 },
+ { "rslttxt", RTFControlType::FLAG, RTFKeyword::RSLTTXT, 0 },
+ { "rtf", RTFControlType::DESTINATION, RTFKeyword::RTF, 0 },
+ { "rtlch", RTFControlType::FLAG, RTFKeyword::RTLCH, 0 },
+ { "rtldoc", RTFControlType::FLAG, RTFKeyword::RTLDOC, 0 },
+ { "rtlgutter", RTFControlType::FLAG, RTFKeyword::RTLGUTTER, 0 },
+ { "rtlmark", RTFControlType::SYMBOL, RTFKeyword::RTLMARK, 0 },
+ { "rtlpar", RTFControlType::FLAG, RTFKeyword::RTLPAR, 0 },
+ { "rtlrow", RTFControlType::FLAG, RTFKeyword::RTLROW, 0 },
+ { "rtlsect", RTFControlType::FLAG, RTFKeyword::RTLSECT, 0 },
+ { "rxe", RTFControlType::DESTINATION, RTFKeyword::RXE, 0 },
+ { "s", RTFControlType::VALUE, RTFKeyword::S, 0 },
+ { "sa", RTFControlType::VALUE, RTFKeyword::SA, 0 },
+ { "saauto", RTFControlType::TOGGLE, RTFKeyword::SAAUTO, 1 },
+ { "saftnnalc", RTFControlType::FLAG, RTFKeyword::SAFTNNALC, 0 },
+ { "saftnnar", RTFControlType::FLAG, RTFKeyword::SAFTNNAR, 0 },
+ { "saftnnauc", RTFControlType::FLAG, RTFKeyword::SAFTNNAUC, 0 },
+ { "saftnnchi", RTFControlType::FLAG, RTFKeyword::SAFTNNCHI, 0 },
+ { "saftnnchosung", RTFControlType::FLAG, RTFKeyword::SAFTNNCHOSUNG, 0 },
+ { "saftnncnum", RTFControlType::FLAG, RTFKeyword::SAFTNNCNUM, 0 },
+ { "saftnndbar", RTFControlType::FLAG, RTFKeyword::SAFTNNDBAR, 0 },
+ { "saftnndbnum", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUM, 0 },
+ { "saftnndbnumd", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMD, 0 },
+ { "saftnndbnumk", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMK, 0 },
+ { "saftnndbnumt", RTFControlType::FLAG, RTFKeyword::SAFTNNDBNUMT, 0 },
+ { "saftnnganada", RTFControlType::FLAG, RTFKeyword::SAFTNNGANADA, 0 },
+ { "saftnngbnum", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUM, 0 },
+ { "saftnngbnumd", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUMD, 0 },
+ { "saftnngbnumk", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUMK, 0 },
+ { "saftnngbnuml", RTFControlType::FLAG, RTFKeyword::SAFTNNGBNUML, 0 },
+ { "saftnnrlc", RTFControlType::FLAG, RTFKeyword::SAFTNNRLC, 0 },
+ { "saftnnruc", RTFControlType::FLAG, RTFKeyword::SAFTNNRUC, 0 },
+ { "saftnnzodiac", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIAC, 0 },
+ { "saftnnzodiacd", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIACD, 0 },
+ { "saftnnzodiacl", RTFControlType::FLAG, RTFKeyword::SAFTNNZODIACL, 0 },
+ { "saftnrestart", RTFControlType::FLAG, RTFKeyword::SAFTNRESTART, 0 },
+ { "saftnrstcont", RTFControlType::FLAG, RTFKeyword::SAFTNRSTCONT, 0 },
+ { "saftnstart", RTFControlType::VALUE, RTFKeyword::SAFTNSTART, 1 },
+ { "sautoupd", RTFControlType::FLAG, RTFKeyword::SAUTOUPD, 0 },
+ { "saveinvalidxml", RTFControlType::FLAG, RTFKeyword::SAVEINVALIDXML, 0 },
+ { "saveprevpict", RTFControlType::FLAG, RTFKeyword::SAVEPREVPICT, 0 },
+ { "sb", RTFControlType::VALUE, RTFKeyword::SB, 0 },
+ { "sbasedon", RTFControlType::VALUE, RTFKeyword::SBASEDON, 222 },
+ { "sbauto", RTFControlType::TOGGLE, RTFKeyword::SBAUTO, 1 },
+ { "sbkcol", RTFControlType::FLAG, RTFKeyword::SBKCOL, 0 },
+ { "sbkeven", RTFControlType::FLAG, RTFKeyword::SBKEVEN, 0 },
+ { "sbknone", RTFControlType::FLAG, RTFKeyword::SBKNONE, 0 },
+ { "sbkodd", RTFControlType::FLAG, RTFKeyword::SBKODD, 0 },
+ { "sbkpage", RTFControlType::FLAG, RTFKeyword::SBKPAGE, 0 },
+ { "sbys", RTFControlType::FLAG, RTFKeyword::SBYS, 0 },
+ { "scaps", RTFControlType::TOGGLE, RTFKeyword::SCAPS, 1 },
+ { "scompose", RTFControlType::FLAG, RTFKeyword::SCOMPOSE, 0 },
+ { "sec", RTFControlType::VALUE, RTFKeyword::SEC, 0 },
+ { "sect", RTFControlType::SYMBOL, RTFKeyword::SECT, 0 },
+ { "sectd", RTFControlType::FLAG, RTFKeyword::SECTD, 0 },
+ { "sectdefaultcl", RTFControlType::FLAG, RTFKeyword::SECTDEFAULTCL, 0 },
+ { "sectexpand", RTFControlType::VALUE, RTFKeyword::SECTEXPAND, 0 },
+ { "sectlinegrid", RTFControlType::VALUE, RTFKeyword::SECTLINEGRID, 0 },
+ { "sectnum", RTFControlType::SYMBOL, RTFKeyword::SECTNUM, 0 },
+ { "sectrsid", RTFControlType::VALUE, RTFKeyword::SECTRSID, 0 },
+ { "sectspecifycl", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYCL, 0 },
+ { "sectspecifygenN", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYGENN, 0 },
+ { "sectspecifyl", RTFControlType::FLAG, RTFKeyword::SECTSPECIFYL, 0 },
+ { "sectunlocked", RTFControlType::FLAG, RTFKeyword::SECTUNLOCKED, 0 },
+ { "sftnbj", RTFControlType::FLAG, RTFKeyword::SFTNBJ, 0 },
+ { "sftnnalc", RTFControlType::FLAG, RTFKeyword::SFTNNALC, 0 },
+ { "sftnnar", RTFControlType::FLAG, RTFKeyword::SFTNNAR, 0 },
+ { "sftnnauc", RTFControlType::FLAG, RTFKeyword::SFTNNAUC, 0 },
+ { "sftnnchi", RTFControlType::FLAG, RTFKeyword::SFTNNCHI, 0 },
+ { "sftnnchosung", RTFControlType::FLAG, RTFKeyword::SFTNNCHOSUNG, 0 },
+ { "sftnncnum", RTFControlType::FLAG, RTFKeyword::SFTNNCNUM, 0 },
+ { "sftnndbar", RTFControlType::FLAG, RTFKeyword::SFTNNDBAR, 0 },
+ { "sftnndbnum", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUM, 0 },
+ { "sftnndbnumd", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMD, 0 },
+ { "sftnndbnumk", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMK, 0 },
+ { "sftnndbnumt", RTFControlType::FLAG, RTFKeyword::SFTNNDBNUMT, 0 },
+ { "sftnnganada", RTFControlType::FLAG, RTFKeyword::SFTNNGANADA, 0 },
+ { "sftnngbnum", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUM, 0 },
+ { "sftnngbnumd", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUMD, 0 },
+ { "sftnngbnumk", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUMK, 0 },
+ { "sftnngbnuml", RTFControlType::FLAG, RTFKeyword::SFTNNGBNUML, 0 },
+ { "sftnnrlc", RTFControlType::FLAG, RTFKeyword::SFTNNRLC, 0 },
+ { "sftnnruc", RTFControlType::FLAG, RTFKeyword::SFTNNRUC, 0 },
+ { "sftnnzodiac", RTFControlType::FLAG, RTFKeyword::SFTNNZODIAC, 0 },
+ { "sftnnzodiacd", RTFControlType::FLAG, RTFKeyword::SFTNNZODIACD, 0 },
+ { "sftnnzodiacl", RTFControlType::FLAG, RTFKeyword::SFTNNZODIACL, 0 },
+ { "sftnrestart", RTFControlType::FLAG, RTFKeyword::SFTNRESTART, 0 },
+ { "sftnrstcont", RTFControlType::FLAG, RTFKeyword::SFTNRSTCONT, 0 },
+ { "sftnrstpg", RTFControlType::FLAG, RTFKeyword::SFTNRSTPG, 0 },
+ { "sftnstart", RTFControlType::VALUE, RTFKeyword::SFTNSTART, 1 },
+ { "sftntj", RTFControlType::FLAG, RTFKeyword::SFTNTJ, 0 },
+ { "shad", RTFControlType::TOGGLE, RTFKeyword::SHAD, 1 },
+ { "shading", RTFControlType::VALUE, RTFKeyword::SHADING, 0 },
+ { "shidden", RTFControlType::FLAG, RTFKeyword::SHIDDEN, 0 },
+ { "shift", RTFControlType::FLAG, RTFKeyword::SHIFT, 0 },
+ { "showplaceholdtext", RTFControlType::VALUE, RTFKeyword::SHOWPLACEHOLDTEXT, 0 },
+ { "showxmlerrors", RTFControlType::VALUE, RTFKeyword::SHOWXMLERRORS, 0 },
+ { "shp", RTFControlType::DESTINATION, RTFKeyword::SHP, 0 },
+ { "shpbottom", RTFControlType::VALUE, RTFKeyword::SHPBOTTOM, 0 },
+ { "shpbxcolumn", RTFControlType::FLAG, RTFKeyword::SHPBXCOLUMN, 0 },
+ { "shpbxignore", RTFControlType::FLAG, RTFKeyword::SHPBXIGNORE, 0 },
+ { "shpbxmargin", RTFControlType::FLAG, RTFKeyword::SHPBXMARGIN, 0 },
+ { "shpbxpage", RTFControlType::FLAG, RTFKeyword::SHPBXPAGE, 0 },
+ { "shpbyignore", RTFControlType::FLAG, RTFKeyword::SHPBYIGNORE, 0 },
+ { "shpbymargin", RTFControlType::FLAG, RTFKeyword::SHPBYMARGIN, 0 },
+ { "shpbypage", RTFControlType::FLAG, RTFKeyword::SHPBYPAGE, 0 },
+ { "shpbypara", RTFControlType::FLAG, RTFKeyword::SHPBYPARA, 0 },
+ { "shpfblwtxt", RTFControlType::VALUE, RTFKeyword::SHPFBLWTXT, 0 },
+ { "shpfhdr", RTFControlType::VALUE, RTFKeyword::SHPFHDR, 0 },
+ { "shpgrp", RTFControlType::DESTINATION, RTFKeyword::SHPGRP, 0 },
+ { "shpinst", RTFControlType::DESTINATION, RTFKeyword::SHPINST, 0 },
+ { "shpleft", RTFControlType::VALUE, RTFKeyword::SHPLEFT, 0 },
+ { "shplid", RTFControlType::VALUE, RTFKeyword::SHPLID, 0 },
+ { "shplockanchor", RTFControlType::FLAG, RTFKeyword::SHPLOCKANCHOR, 0 },
+ { "shppict", RTFControlType::DESTINATION, RTFKeyword::SHPPICT, 0 },
+ { "shpright", RTFControlType::VALUE, RTFKeyword::SHPRIGHT, 0 },
+ { "shprslt", RTFControlType::DESTINATION, RTFKeyword::SHPRSLT, 0 },
+ { "shptop", RTFControlType::VALUE, RTFKeyword::SHPTOP, 0 },
+ { "shptxt", RTFControlType::DESTINATION, RTFKeyword::SHPTXT, 0 },
+ { "shpwrk", RTFControlType::VALUE, RTFKeyword::SHPWRK, 0 },
+ { "shpwr", RTFControlType::VALUE, RTFKeyword::SHPWR, 0 },
+ { "shpz", RTFControlType::VALUE, RTFKeyword::SHPZ, 0 },
+ { "sl", RTFControlType::VALUE, RTFKeyword::SL, 0 },
+ { "slink", RTFControlType::VALUE, RTFKeyword::SLINK, 0 },
+ { "slmult", RTFControlType::VALUE, RTFKeyword::SLMULT, 0 },
+ { "slocked", RTFControlType::FLAG, RTFKeyword::SLOCKED, 0 },
+ { "sn", RTFControlType::DESTINATION, RTFKeyword::SN, 0 },
+ { "snaptogridincell", RTFControlType::FLAG, RTFKeyword::SNAPTOGRIDINCELL, 0 },
+ { "snext", RTFControlType::VALUE, RTFKeyword::SNEXT, 0 },
+ { "softcol", RTFControlType::FLAG, RTFKeyword::SOFTCOL, 0 },
+ { "softlheight", RTFControlType::VALUE, RTFKeyword::SOFTLHEIGHT, 0 },
+ { "softline", RTFControlType::FLAG, RTFKeyword::SOFTLINE, 0 },
+ { "softpage", RTFControlType::FLAG, RTFKeyword::SOFTPAGE, 0 },
+ { "sp", RTFControlType::DESTINATION, RTFKeyword::SP, 0 },
+ { "spersonal", RTFControlType::FLAG, RTFKeyword::SPERSONAL, 0 },
+ { "spltpgpar", RTFControlType::FLAG, RTFKeyword::SPLTPGPAR, 0 },
+ { "splytwnine", RTFControlType::FLAG, RTFKeyword::SPLYTWNINE, 0 },
+ { "spriority", RTFControlType::VALUE, RTFKeyword::SPRIORITY, 0 },
+ { "sprsbsp", RTFControlType::FLAG, RTFKeyword::SPRSBSP, 0 },
+ { "sprslnsp", RTFControlType::FLAG, RTFKeyword::SPRSLNSP, 0 },
+ { "sprsspbf", RTFControlType::FLAG, RTFKeyword::SPRSSPBF, 0 },
+ { "sprstsm", RTFControlType::FLAG, RTFKeyword::SPRSTSM, 0 },
+ { "sprstsp", RTFControlType::FLAG, RTFKeyword::SPRSTSP, 0 },
+ { "spv", RTFControlType::FLAG, RTFKeyword::SPV, 0 },
+ { "sqformat", RTFControlType::FLAG, RTFKeyword::SQFORMAT, 0 },
+ { "srauth", RTFControlType::VALUE, RTFKeyword::SRAUTH, 0 },
+ { "srdate", RTFControlType::VALUE, RTFKeyword::SRDATE, 0 },
+ { "sreply", RTFControlType::FLAG, RTFKeyword::SREPLY, 0 },
+ { "ssemihidden", RTFControlType::VALUE, RTFKeyword::SSEMIHIDDEN, 0 },
+ { "staticval", RTFControlType::DESTINATION, RTFKeyword::STATICVAL, 0 },
+ { "stextflow", RTFControlType::VALUE, RTFKeyword::STEXTFLOW, 0 },
+ { "strike", RTFControlType::TOGGLE, RTFKeyword::STRIKE, 1 },
+ { "striked", RTFControlType::TOGGLE, RTFKeyword::STRIKED, 1 },
+ { "stshfbi", RTFControlType::VALUE, RTFKeyword::STSHFBI, 0 },
+ { "stshfdbch", RTFControlType::VALUE, RTFKeyword::STSHFDBCH, 0 },
+ { "stshfhich", RTFControlType::VALUE, RTFKeyword::STSHFHICH, 0 },
+ { "stshfloch", RTFControlType::VALUE, RTFKeyword::STSHFLOCH, 0 },
+ { "stylelock", RTFControlType::FLAG, RTFKeyword::STYLELOCK, 0 },
+ { "stylelockbackcomp", RTFControlType::FLAG, RTFKeyword::STYLELOCKBACKCOMP, 0 },
+ { "stylelockenforced", RTFControlType::FLAG, RTFKeyword::STYLELOCKENFORCED, 0 },
+ { "stylelockqfset", RTFControlType::FLAG, RTFKeyword::STYLELOCKQFSET, 0 },
+ { "stylelocktheme", RTFControlType::FLAG, RTFKeyword::STYLELOCKTHEME, 0 },
+ { "stylesheet", RTFControlType::DESTINATION, RTFKeyword::STYLESHEET, 0 },
+ { "stylesortmethod", RTFControlType::VALUE, RTFKeyword::STYLESORTMETHOD, 1 },
+ { "styrsid", RTFControlType::VALUE, RTFKeyword::STYRSID, 0 },
+ { "sub", RTFControlType::FLAG, RTFKeyword::SUB, 0 },
+ { "subdocument", RTFControlType::VALUE, RTFKeyword::SUBDOCUMENT, 0 },
+ { "subfontbysize", RTFControlType::FLAG, RTFKeyword::SUBFONTBYSIZE, 0 },
+ { "subject", RTFControlType::DESTINATION, RTFKeyword::SUBJECT, 0 },
+ { "sunhideused", RTFControlType::VALUE, RTFKeyword::SUNHIDEUSED, 0 },
+ { "super", RTFControlType::FLAG, RTFKeyword::SUPER, 0 },
+ { "sv", RTFControlType::DESTINATION, RTFKeyword::SV, 0 },
+ { "svb", RTFControlType::DESTINATION, RTFKeyword::SVB, 0 },
+ { "swpbdr", RTFControlType::FLAG, RTFKeyword::SWPBDR, 0 },
+ { "tab", RTFControlType::SYMBOL, RTFKeyword::TAB, 0 },
+ { "tabsnoovrlp", RTFControlType::FLAG, RTFKeyword::TABSNOOVRLP, 0 },
+ { "taprtl", RTFControlType::FLAG, RTFKeyword::TAPRTL, 0 },
+ { "tb", RTFControlType::VALUE, RTFKeyword::TB, 0 },
+ { "tblind", RTFControlType::VALUE, RTFKeyword::TBLIND, 0 },
+ { "tblindtype", RTFControlType::VALUE, RTFKeyword::TBLINDTYPE, 0 },
+ { "tbllkbestfit", RTFControlType::FLAG, RTFKeyword::TBLLKBESTFIT, 0 },
+ { "tbllkborder", RTFControlType::FLAG, RTFKeyword::TBLLKBORDER, 0 },
+ { "tbllkcolor", RTFControlType::FLAG, RTFKeyword::TBLLKCOLOR, 0 },
+ { "tbllkfont", RTFControlType::FLAG, RTFKeyword::TBLLKFONT, 0 },
+ { "tbllkhdrcols", RTFControlType::FLAG, RTFKeyword::TBLLKHDRCOLS, 0 },
+ { "tbllkhdrrows", RTFControlType::FLAG, RTFKeyword::TBLLKHDRROWS, 0 },
+ { "tbllklastcol", RTFControlType::FLAG, RTFKeyword::TBLLKLASTCOL, 0 },
+ { "tbllklastrow", RTFControlType::FLAG, RTFKeyword::TBLLKLASTROW, 0 },
+ { "tbllknocolband", RTFControlType::FLAG, RTFKeyword::TBLLKNOCOLBAND, 0 },
+ { "tbllknorowband", RTFControlType::FLAG, RTFKeyword::TBLLKNOROWBAND, 0 },
+ { "tbllkshading", RTFControlType::FLAG, RTFKeyword::TBLLKSHADING, 0 },
+ { "tblrsid", RTFControlType::VALUE, RTFKeyword::TBLRSID, 0 },
+ { "tc", RTFControlType::DESTINATION, RTFKeyword::TC, 0 },
+ { "tcelld", RTFControlType::FLAG, RTFKeyword::TCELLD, 0 },
+ { "tcf", RTFControlType::VALUE, RTFKeyword::TCF, 67 },
+ { "tcl", RTFControlType::VALUE, RTFKeyword::TCL, 0 },
+ { "tcn", RTFControlType::FLAG, RTFKeyword::TCN, 0 },
+ { "tdfrmtxtBottom", RTFControlType::VALUE, RTFKeyword::TDFRMTXTBOTTOM, 0 },
+ { "tdfrmtxtLeft", RTFControlType::VALUE, RTFKeyword::TDFRMTXTLEFT, 0 },
+ { "tdfrmtxtRight", RTFControlType::VALUE, RTFKeyword::TDFRMTXTRIGHT, 0 },
+ { "tdfrmtxtTop", RTFControlType::VALUE, RTFKeyword::TDFRMTXTTOP, 0 },
+ { "template", RTFControlType::DESTINATION, RTFKeyword::TEMPLATE, 0 },
+ { "themedata", RTFControlType::DESTINATION, RTFKeyword::THEMEDATA, 0 },
+ { "themelang", RTFControlType::VALUE, RTFKeyword::THEMELANG, 0 },
+ { "themelangcs", RTFControlType::VALUE, RTFKeyword::THEMELANGCS, 0 },
+ { "themelangfe", RTFControlType::VALUE, RTFKeyword::THEMELANGFE, 0 },
+ { "time", RTFControlType::FLAG, RTFKeyword::TIME, 0 },
+ { "title", RTFControlType::DESTINATION, RTFKeyword::TITLE, 0 },
+ { "titlepg", RTFControlType::FLAG, RTFKeyword::TITLEPG, 0 },
+ { "tldot", RTFControlType::FLAG, RTFKeyword::TLDOT, 0 },
+ { "tleq", RTFControlType::FLAG, RTFKeyword::TLEQ, 0 },
+ { "tlhyph", RTFControlType::FLAG, RTFKeyword::TLHYPH, 0 },
+ { "tlmdot", RTFControlType::FLAG, RTFKeyword::TLMDOT, 0 },
+ { "tlth", RTFControlType::FLAG, RTFKeyword::TLTH, 0 },
+ { "tlul", RTFControlType::FLAG, RTFKeyword::TLUL, 0 },
+ { "toplinepunct", RTFControlType::FLAG, RTFKeyword::TOPLINEPUNCT, 0 },
+ { "tphcol", RTFControlType::FLAG, RTFKeyword::TPHCOL, 0 },
+ { "tphmrg", RTFControlType::FLAG, RTFKeyword::TPHMRG, 0 },
+ { "tphpg", RTFControlType::FLAG, RTFKeyword::TPHPG, 0 },
+ { "tposnegx", RTFControlType::VALUE, RTFKeyword::TPOSNEGX, 0 },
+ { "tposnegy", RTFControlType::VALUE, RTFKeyword::TPOSNEGY, 0 },
+ { "tposxc", RTFControlType::FLAG, RTFKeyword::TPOSXC, 0 },
+ { "tposxi", RTFControlType::FLAG, RTFKeyword::TPOSXI, 0 },
+ { "tposxl", RTFControlType::FLAG, RTFKeyword::TPOSXL, 0 },
+ { "tposx", RTFControlType::VALUE, RTFKeyword::TPOSX, 0 },
+ { "tposxo", RTFControlType::FLAG, RTFKeyword::TPOSXO, 0 },
+ { "tposxr", RTFControlType::FLAG, RTFKeyword::TPOSXR, 0 },
+ { "tposy", RTFControlType::VALUE, RTFKeyword::TPOSY, 0 },
+ { "tposyb", RTFControlType::FLAG, RTFKeyword::TPOSYB, 0 },
+ { "tposyc", RTFControlType::FLAG, RTFKeyword::TPOSYC, 0 },
+ { "tposyil", RTFControlType::FLAG, RTFKeyword::TPOSYIL, 0 },
+ { "tposyin", RTFControlType::FLAG, RTFKeyword::TPOSYIN, 0 },
+ { "tposyout", RTFControlType::FLAG, RTFKeyword::TPOSYOUT, 0 },
+ { "tposyt", RTFControlType::FLAG, RTFKeyword::TPOSYT, 0 },
+ { "tpvmrg", RTFControlType::FLAG, RTFKeyword::TPVMRG, 0 },
+ { "tpvpara", RTFControlType::FLAG, RTFKeyword::TPVPARA, 0 },
+ { "tpvpg", RTFControlType::FLAG, RTFKeyword::TPVPG, 0 },
+ { "tqc", RTFControlType::FLAG, RTFKeyword::TQC, 0 },
+ { "tqdec", RTFControlType::FLAG, RTFKeyword::TQDEC, 0 },
+ { "tqr", RTFControlType::FLAG, RTFKeyword::TQR, 0 },
+ { "trackformatting", RTFControlType::VALUE, RTFKeyword::TRACKFORMATTING, 0 },
+ { "trackmoves", RTFControlType::VALUE, RTFKeyword::TRACKMOVES, 0 },
+ { "transmf", RTFControlType::FLAG, RTFKeyword::TRANSMF, 0 },
+ { "trauth", RTFControlType::VALUE, RTFKeyword::TRAUTH, 0 },
+ { "trautofit", RTFControlType::TOGGLE, RTFKeyword::TRAUTOFIT, 1 },
+ { "trbgbdiag", RTFControlType::FLAG, RTFKeyword::TRBGBDIAG, 0 },
+ { "trbgcross", RTFControlType::FLAG, RTFKeyword::TRBGCROSS, 0 },
+ { "trbgdcross", RTFControlType::FLAG, RTFKeyword::TRBGDCROSS, 0 },
+ { "trbgdkbdiag", RTFControlType::FLAG, RTFKeyword::TRBGDKBDIAG, 0 },
+ { "trbgdkcross", RTFControlType::FLAG, RTFKeyword::TRBGDKCROSS, 0 },
+ { "trbgdkdcross", RTFControlType::FLAG, RTFKeyword::TRBGDKDCROSS, 0 },
+ { "trbgdkfdiag", RTFControlType::FLAG, RTFKeyword::TRBGDKFDIAG, 0 },
+ { "trbgdkhor", RTFControlType::FLAG, RTFKeyword::TRBGDKHOR, 0 },
+ { "trbgdkvert", RTFControlType::FLAG, RTFKeyword::TRBGDKVERT, 0 },
+ { "trbgfdiag", RTFControlType::FLAG, RTFKeyword::TRBGFDIAG, 0 },
+ { "trbghoriz", RTFControlType::FLAG, RTFKeyword::TRBGHORIZ, 0 },
+ { "trbgvert", RTFControlType::FLAG, RTFKeyword::TRBGVERT, 0 },
+ { "trbrdrb", RTFControlType::FLAG, RTFKeyword::TRBRDRB, 0 },
+ { "trbrdrh", RTFControlType::FLAG, RTFKeyword::TRBRDRH, 0 },
+ { "trbrdrl", RTFControlType::FLAG, RTFKeyword::TRBRDRL, 0 },
+ { "trbrdrr", RTFControlType::FLAG, RTFKeyword::TRBRDRR, 0 },
+ { "trbrdrt", RTFControlType::FLAG, RTFKeyword::TRBRDRT, 0 },
+ { "trbrdrv", RTFControlType::FLAG, RTFKeyword::TRBRDRV, 0 },
+ { "trcbpat", RTFControlType::VALUE, RTFKeyword::TRCBPAT, 0 },
+ { "trcfpat", RTFControlType::VALUE, RTFKeyword::TRCFPAT, 0 },
+ { "trdate", RTFControlType::VALUE, RTFKeyword::TRDATE, 0 },
+ { "trftsWidthA", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTHA, 0 },
+ { "trftsWidthB", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTHB, 0 },
+ { "trftsWidth", RTFControlType::VALUE, RTFKeyword::TRFTSWIDTH, 0 },
+ { "trgaph", RTFControlType::VALUE, RTFKeyword::TRGAPH, 0 },
+ { "trhdr", RTFControlType::FLAG, RTFKeyword::TRHDR, 0 },
+ { "trkeep", RTFControlType::FLAG, RTFKeyword::TRKEEP, 0 },
+ { "trkeepfollow", RTFControlType::FLAG, RTFKeyword::TRKEEPFOLLOW, 0 },
+ { "trleft", RTFControlType::VALUE, RTFKeyword::TRLEFT, 0 },
+ { "trowd", RTFControlType::FLAG, RTFKeyword::TROWD, 0 },
+ { "trpaddb", RTFControlType::VALUE, RTFKeyword::TRPADDB, 0 },
+ { "trpaddfb", RTFControlType::VALUE, RTFKeyword::TRPADDFB, 0 },
+ { "trpaddfl", RTFControlType::VALUE, RTFKeyword::TRPADDFL, 0 },
+ { "trpaddfr", RTFControlType::VALUE, RTFKeyword::TRPADDFR, 0 },
+ { "trpaddft", RTFControlType::VALUE, RTFKeyword::TRPADDFT, 0 },
+ { "trpaddl", RTFControlType::VALUE, RTFKeyword::TRPADDL, 0 },
+ { "trpaddr", RTFControlType::VALUE, RTFKeyword::TRPADDR, 0 },
+ { "trpaddt", RTFControlType::VALUE, RTFKeyword::TRPADDT, 0 },
+ { "trpadob", RTFControlType::VALUE, RTFKeyword::TRPADOB, 0 },
+ { "trpadofb", RTFControlType::VALUE, RTFKeyword::TRPADOFB, 0 },
+ { "trpadofl", RTFControlType::VALUE, RTFKeyword::TRPADOFL, 0 },
+ { "trpadofr", RTFControlType::VALUE, RTFKeyword::TRPADOFR, 0 },
+ { "trpadoft", RTFControlType::VALUE, RTFKeyword::TRPADOFT, 0 },
+ { "trpadol", RTFControlType::VALUE, RTFKeyword::TRPADOL, 0 },
+ { "trpador", RTFControlType::VALUE, RTFKeyword::TRPADOR, 0 },
+ { "trpadot", RTFControlType::VALUE, RTFKeyword::TRPADOT, 0 },
+ { "trpat", RTFControlType::VALUE, RTFKeyword::TRPAT, 0 },
+ { "trqc", RTFControlType::FLAG, RTFKeyword::TRQC, 0 },
+ { "trql", RTFControlType::FLAG, RTFKeyword::TRQL, 0 },
+ { "trqr", RTFControlType::FLAG, RTFKeyword::TRQR, 0 },
+ { "trrh", RTFControlType::VALUE, RTFKeyword::TRRH, 0 },
+ { "trshdng", RTFControlType::VALUE, RTFKeyword::TRSHDNG, 0 },
+ { "trspdb", RTFControlType::VALUE, RTFKeyword::TRSPDB, 0 },
+ { "trspdfb", RTFControlType::VALUE, RTFKeyword::TRSPDFB, 0 },
+ { "trspdfl", RTFControlType::VALUE, RTFKeyword::TRSPDFL, 0 },
+ { "trspdfr", RTFControlType::VALUE, RTFKeyword::TRSPDFR, 0 },
+ { "trspdft", RTFControlType::VALUE, RTFKeyword::TRSPDFT, 0 },
+ { "trspdl", RTFControlType::VALUE, RTFKeyword::TRSPDL, 0 },
+ { "trspdr", RTFControlType::VALUE, RTFKeyword::TRSPDR, 0 },
+ { "trspdt", RTFControlType::VALUE, RTFKeyword::TRSPDT, 0 },
+ { "trspob", RTFControlType::VALUE, RTFKeyword::TRSPOB, 0 },
+ { "trspofb", RTFControlType::VALUE, RTFKeyword::TRSPOFB, 0 },
+ { "trspofl", RTFControlType::VALUE, RTFKeyword::TRSPOFL, 0 },
+ { "trspofr", RTFControlType::VALUE, RTFKeyword::TRSPOFR, 0 },
+ { "trspoft", RTFControlType::VALUE, RTFKeyword::TRSPOFT, 0 },
+ { "trspol", RTFControlType::VALUE, RTFKeyword::TRSPOL, 0 },
+ { "trspor", RTFControlType::VALUE, RTFKeyword::TRSPOR, 0 },
+ { "trspot", RTFControlType::VALUE, RTFKeyword::TRSPOT, 0 },
+ { "truncatefontheight", RTFControlType::FLAG, RTFKeyword::TRUNCATEFONTHEIGHT, 0 },
+ { "truncex", RTFControlType::FLAG, RTFKeyword::TRUNCEX, 0 },
+ { "trwWidthA", RTFControlType::VALUE, RTFKeyword::TRWWIDTHA, 0 },
+ { "trwWidthB", RTFControlType::VALUE, RTFKeyword::TRWWIDTHB, 0 },
+ { "trwWidth", RTFControlType::VALUE, RTFKeyword::TRWWIDTH, 0 },
+ { "ts", RTFControlType::VALUE, RTFKeyword::TS, 0 },
+ { "tsbgbdiag", RTFControlType::FLAG, RTFKeyword::TSBGBDIAG, 0 },
+ { "tsbgcross", RTFControlType::FLAG, RTFKeyword::TSBGCROSS, 0 },
+ { "tsbgdcross", RTFControlType::FLAG, RTFKeyword::TSBGDCROSS, 0 },
+ { "tsbgdkbdiag", RTFControlType::FLAG, RTFKeyword::TSBGDKBDIAG, 0 },
+ { "tsbgdkcross", RTFControlType::FLAG, RTFKeyword::TSBGDKCROSS, 0 },
+ { "tsbgdkdcross", RTFControlType::FLAG, RTFKeyword::TSBGDKDCROSS, 0 },
+ { "tsbgdkfdiag", RTFControlType::FLAG, RTFKeyword::TSBGDKFDIAG, 0 },
+ { "tsbgdkhor", RTFControlType::FLAG, RTFKeyword::TSBGDKHOR, 0 },
+ { "tsbgdkvert", RTFControlType::FLAG, RTFKeyword::TSBGDKVERT, 0 },
+ { "tsbgfdiag", RTFControlType::FLAG, RTFKeyword::TSBGFDIAG, 0 },
+ { "tsbghoriz", RTFControlType::FLAG, RTFKeyword::TSBGHORIZ, 0 },
+ { "tsbgvert", RTFControlType::FLAG, RTFKeyword::TSBGVERT, 0 },
+ { "tsbrdrb", RTFControlType::FLAG, RTFKeyword::TSBRDRB, 0 },
+ { "tsbrdrdgl", RTFControlType::FLAG, RTFKeyword::TSBRDRDGL, 0 },
+ { "tsbrdrdgr", RTFControlType::FLAG, RTFKeyword::TSBRDRDGR, 0 },
+ { "tsbrdrh", RTFControlType::FLAG, RTFKeyword::TSBRDRH, 0 },
+ { "tsbrdrl", RTFControlType::FLAG, RTFKeyword::TSBRDRL, 0 },
+ { "tsbrdrr", RTFControlType::FLAG, RTFKeyword::TSBRDRR, 0 },
+ { "tsbrdrt", RTFControlType::FLAG, RTFKeyword::TSBRDRT, 0 },
+ { "tsbrdrv", RTFControlType::FLAG, RTFKeyword::TSBRDRV, 0 },
+ { "tscbandhorzeven", RTFControlType::FLAG, RTFKeyword::TSCBANDHORZEVEN, 0 },
+ { "tscbandhorzodd", RTFControlType::FLAG, RTFKeyword::TSCBANDHORZODD, 0 },
+ { "tscbandsh", RTFControlType::VALUE, RTFKeyword::TSCBANDSH, 0 },
+ { "tscbandsv", RTFControlType::VALUE, RTFKeyword::TSCBANDSV, 0 },
+ { "tscbandverteven", RTFControlType::FLAG, RTFKeyword::TSCBANDVERTEVEN, 0 },
+ { "tscbandvertodd", RTFControlType::FLAG, RTFKeyword::TSCBANDVERTODD, 0 },
+ { "tscellcbpat", RTFControlType::VALUE, RTFKeyword::TSCELLCBPAT, 0 },
+ { "tscellcfpat", RTFControlType::VALUE, RTFKeyword::TSCELLCFPAT, 0 },
+ { "tscellpaddb", RTFControlType::VALUE, RTFKeyword::TSCELLPADDB, 0 },
+ { "tscellpaddfb", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFB, 0 },
+ { "tscellpaddfl", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFL, 0 },
+ { "tscellpaddfr", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFR, 0 },
+ { "tscellpaddft", RTFControlType::VALUE, RTFKeyword::TSCELLPADDFT, 0 },
+ { "tscellpaddl", RTFControlType::VALUE, RTFKeyword::TSCELLPADDL, 0 },
+ { "tscellpaddr", RTFControlType::VALUE, RTFKeyword::TSCELLPADDR, 0 },
+ { "tscellpaddt", RTFControlType::VALUE, RTFKeyword::TSCELLPADDT, 0 },
+ { "tscellpct", RTFControlType::VALUE, RTFKeyword::TSCELLPCT, 0 },
+ { "tscellwidth", RTFControlType::VALUE, RTFKeyword::TSCELLWIDTH, 0 },
+ { "tscellwidthfts", RTFControlType::VALUE, RTFKeyword::TSCELLWIDTHFTS, 0 },
+ { "tscfirstcol", RTFControlType::FLAG, RTFKeyword::TSCFIRSTCOL, 0 },
+ { "tscfirstrow", RTFControlType::FLAG, RTFKeyword::TSCFIRSTROW, 0 },
+ { "tsclastcol", RTFControlType::FLAG, RTFKeyword::TSCLASTCOL, 0 },
+ { "tsclastrow", RTFControlType::FLAG, RTFKeyword::TSCLASTROW, 0 },
+ { "tscnecell", RTFControlType::FLAG, RTFKeyword::TSCNECELL, 0 },
+ { "tscnwcell", RTFControlType::FLAG, RTFKeyword::TSCNWCELL, 0 },
+ { "tscsecell", RTFControlType::FLAG, RTFKeyword::TSCSECELL, 0 },
+ { "tscswcell", RTFControlType::FLAG, RTFKeyword::TSCSWCELL, 0 },
+ { "tsd", RTFControlType::FLAG, RTFKeyword::TSD, 0 },
+ { "tsnowrap", RTFControlType::FLAG, RTFKeyword::TSNOWRAP, 0 },
+ { "tsrowd", RTFControlType::FLAG, RTFKeyword::TSROWD, 0 },
+ { "tsvertalb", RTFControlType::FLAG, RTFKeyword::TSVERTALB, 0 },
+ { "tsvertalc", RTFControlType::FLAG, RTFKeyword::TSVERTALC, 0 },
+ { "tsvertalt", RTFControlType::FLAG, RTFKeyword::TSVERTALT, 0 },
+ { "twoinone", RTFControlType::VALUE, RTFKeyword::TWOINONE, 0 },
+ { "twoonone", RTFControlType::FLAG, RTFKeyword::TWOONONE, 0 },
+ { "tx", RTFControlType::VALUE, RTFKeyword::TX, 0 },
+ { "txbxtwalways", RTFControlType::FLAG, RTFKeyword::TXBXTWALWAYS, 0 },
+ { "txbxtwfirst", RTFControlType::FLAG, RTFKeyword::TXBXTWFIRST, 0 },
+ { "txbxtwfirstlast", RTFControlType::FLAG, RTFKeyword::TXBXTWFIRSTLAST, 0 },
+ { "txbxtwlast", RTFControlType::FLAG, RTFKeyword::TXBXTWLAST, 0 },
+ { "txbxtwno", RTFControlType::FLAG, RTFKeyword::TXBXTWNO, 0 },
+ { "txe", RTFControlType::DESTINATION, RTFKeyword::TXE, 0 },
+ { "u", RTFControlType::VALUE, RTFKeyword::U, 0 },
+ { "uc", RTFControlType::VALUE, RTFKeyword::UC, 1 },
+ { "ud", RTFControlType::DESTINATION, RTFKeyword::UD, 0 },
+ { "ul", RTFControlType::TOGGLE, RTFKeyword::UL, 1 },
+ { "ulc", RTFControlType::VALUE, RTFKeyword::ULC, 0 },
+ { "uld", RTFControlType::FLAG, RTFKeyword::ULD, 0 },
+ { "uldash", RTFControlType::TOGGLE, RTFKeyword::ULDASH, 1 },
+ { "uldashd", RTFControlType::TOGGLE, RTFKeyword::ULDASHD, 1 },
+ { "uldashdd", RTFControlType::TOGGLE, RTFKeyword::ULDASHDD, 1 },
+ { "uldb", RTFControlType::TOGGLE, RTFKeyword::ULDB, 1 },
+ { "ulhair", RTFControlType::TOGGLE, RTFKeyword::ULHAIR, 1 },
+ { "ulhwave", RTFControlType::TOGGLE, RTFKeyword::ULHWAVE, 1 },
+ { "ulldash", RTFControlType::TOGGLE, RTFKeyword::ULLDASH, 1 },
+ { "ulnone", RTFControlType::FLAG, RTFKeyword::ULNONE, 0 },
+ { "ulth", RTFControlType::TOGGLE, RTFKeyword::ULTH, 1 },
+ { "ulthd", RTFControlType::TOGGLE, RTFKeyword::ULTHD, 1 },
+ { "ulthdash", RTFControlType::TOGGLE, RTFKeyword::ULTHDASH, 1 },
+ { "ulthdashd", RTFControlType::TOGGLE, RTFKeyword::ULTHDASHD, 1 },
+ { "ulthdashdd", RTFControlType::TOGGLE, RTFKeyword::ULTHDASHDD, 1 },
+ { "ulthldash", RTFControlType::TOGGLE, RTFKeyword::ULTHLDASH, 1 },
+ { "ululdbwave", RTFControlType::TOGGLE, RTFKeyword::ULULDBWAVE, 1 },
+ { "ulw", RTFControlType::FLAG, RTFKeyword::ULW, 0 },
+ { "ulwave", RTFControlType::TOGGLE, RTFKeyword::ULWAVE, 1 },
+ { "up", RTFControlType::VALUE, RTFKeyword::UP, 6 },
+ { "upr", RTFControlType::DESTINATION, RTFKeyword::UPR, 0 },
+ { "urtf", RTFControlType::VALUE, RTFKeyword::URTF, 0 },
+ { "useltbaln", RTFControlType::FLAG, RTFKeyword::USELTBALN, 0 },
+ { "usenormstyforlist", RTFControlType::FLAG, RTFKeyword::USENORMSTYFORLIST, 0 },
+ { "userprops", RTFControlType::DESTINATION, RTFKeyword::USERPROPS, 0 },
+ { "usexform", RTFControlType::FLAG, RTFKeyword::USEXFORM, 0 },
+ { "utinl", RTFControlType::FLAG, RTFKeyword::UTINL, 0 },
+ { "v", RTFControlType::TOGGLE, RTFKeyword::V, 1 },
+ { "validatexml", RTFControlType::VALUE, RTFKeyword::VALIDATEXML, 0 },
+ { "vern", RTFControlType::VALUE, RTFKeyword::VERN, 0 },
+ { "version", RTFControlType::VALUE, RTFKeyword::VERSION, 0 },
+ { "vertal", RTFControlType::FLAG, RTFKeyword::VERTAL, 0 },
+ { "vertalb", RTFControlType::FLAG, RTFKeyword::VERTALB, 0 },
+ { "vertalc", RTFControlType::FLAG, RTFKeyword::VERTALC, 0 },
+ { "vertalj", RTFControlType::FLAG, RTFKeyword::VERTALJ, 0 },
+ { "vertalt", RTFControlType::FLAG, RTFKeyword::VERTALT, 0 },
+ { "vertdoc", RTFControlType::FLAG, RTFKeyword::VERTDOC, 0 },
+ { "vertsect", RTFControlType::FLAG, RTFKeyword::VERTSECT, 0 },
+ { "viewbksp", RTFControlType::VALUE, RTFKeyword::VIEWBKSP, 0 },
+ { "viewkind", RTFControlType::VALUE, RTFKeyword::VIEWKIND, 0 },
+ { "viewnobound", RTFControlType::FLAG, RTFKeyword::VIEWNOBOUND, 0 },
+ { "viewscale", RTFControlType::VALUE, RTFKeyword::VIEWSCALE, 100 },
+ { "viewzk", RTFControlType::VALUE, RTFKeyword::VIEWZK, 0 },
+ { "wbitmap", RTFControlType::VALUE, RTFKeyword::WBITMAP, 0 },
+ { "wbmbitspixel", RTFControlType::VALUE, RTFKeyword::WBMBITSPIXEL, 1 },
+ { "wbmplanes", RTFControlType::VALUE, RTFKeyword::WBMPLANES, 0 },
+ { "wbmwidthbyte", RTFControlType::VALUE, RTFKeyword::WBMWIDTHBYTE, 0 },
+ { "webhidden", RTFControlType::FLAG, RTFKeyword::WEBHIDDEN, 0 },
+ { "wgrffmtfilter", RTFControlType::DESTINATION, RTFKeyword::WGRFFMTFILTER, 0 },
+ { "widctlpar", RTFControlType::FLAG, RTFKeyword::WIDCTLPAR, 0 },
+ { "widowctrl", RTFControlType::FLAG, RTFKeyword::WIDOWCTRL, 0 },
+ { "windowcaption", RTFControlType::DESTINATION, RTFKeyword::WINDOWCAPTION, 0 },
+ { "wmetafile", RTFControlType::VALUE, RTFKeyword::WMETAFILE, 1 },
+ { "wpeqn", RTFControlType::FLAG, RTFKeyword::WPEQN, 0 },
+ { "wpjst", RTFControlType::FLAG, RTFKeyword::WPJST, 0 },
+ { "wpsp", RTFControlType::FLAG, RTFKeyword::WPSP, 0 },
+ { "wraparound", RTFControlType::FLAG, RTFKeyword::WRAPAROUND, 0 },
+ { "wrapdefault", RTFControlType::FLAG, RTFKeyword::WRAPDEFAULT, 0 },
+ { "wrapthrough", RTFControlType::FLAG, RTFKeyword::WRAPTHROUGH, 0 },
+ { "wraptight", RTFControlType::FLAG, RTFKeyword::WRAPTIGHT, 0 },
+ { "wraptrsp", RTFControlType::FLAG, RTFKeyword::WRAPTRSP, 0 },
+ { "writereservation", RTFControlType::DESTINATION, RTFKeyword::WRITERESERVATION, 0 },
+ { "writereservhash", RTFControlType::DESTINATION, RTFKeyword::WRITERESERVHASH, 0 },
+ { "wrppunct", RTFControlType::FLAG, RTFKeyword::WRPPUNCT, 0 },
+ { "xe", RTFControlType::DESTINATION, RTFKeyword::XE, 0 },
+ { "xef", RTFControlType::VALUE, RTFKeyword::XEF, 0 },
+ { "xform", RTFControlType::DESTINATION, RTFKeyword::XFORM, 0 },
+ { "xmlattr", RTFControlType::FLAG, RTFKeyword::XMLATTR, 0 },
+ { "xmlattrname", RTFControlType::DESTINATION, RTFKeyword::XMLATTRNAME, 0 },
+ { "xmlattrns", RTFControlType::VALUE, RTFKeyword::XMLATTRNS, 0 },
+ { "xmlattrvalue", RTFControlType::DESTINATION, RTFKeyword::XMLATTRVALUE, 0 },
+ { "xmlclose", RTFControlType::DESTINATION, RTFKeyword::XMLCLOSE, 0 },
+ { "xmlname", RTFControlType::DESTINATION, RTFKeyword::XMLNAME, 0 },
+ { "xmlns", RTFControlType::VALUE, RTFKeyword::XMLNS, 0 },
+ { "xmlnstbl", RTFControlType::DESTINATION, RTFKeyword::XMLNSTBL, 0 },
+ { "xmlopen", RTFControlType::DESTINATION, RTFKeyword::XMLOPEN, 0 },
+ { "xmlsdttcell", RTFControlType::FLAG, RTFKeyword::XMLSDTTCELL, 0 },
+ { "xmlsdttpara", RTFControlType::FLAG, RTFKeyword::XMLSDTTPARA, 0 },
+ { "xmlsdttregular", RTFControlType::FLAG, RTFKeyword::XMLSDTTREGULAR, 0 },
+ { "xmlsdttrow", RTFControlType::FLAG, RTFKeyword::XMLSDTTROW, 0 },
+ { "xmlsdttunknown", RTFControlType::FLAG, RTFKeyword::XMLSDTTUNKNOWN, 0 },
+ { "yr", RTFControlType::VALUE, RTFKeyword::YR, 0 },
+ { "yts", RTFControlType::VALUE, RTFKeyword::YTS, 0 },
+ { "yxe", RTFControlType::FLAG, RTFKeyword::YXE, 0 },
+ { "zwbo", RTFControlType::SYMBOL, RTFKeyword::ZWBO, 0 },
+ { "zwj", RTFControlType::SYMBOL, RTFKeyword::ZWJ, 0 },
+ { "zwnbo", RTFControlType::SYMBOL, RTFKeyword::ZWNBO, 0 },
+ { "zwnj", RTFControlType::SYMBOL, RTFKeyword::ZWNJ, 0 },
+ { "flymaincnt", RTFControlType::DESTINATION, RTFKeyword::FLYMAINCNT, 0 },
+ { "flyvert", RTFControlType::VALUE, RTFKeyword::FLYVERT, 0 },
+ { "flyhorz", RTFControlType::VALUE, RTFKeyword::FLYHORZ, 0 },
+ { "flyanchor", RTFControlType::VALUE, RTFKeyword::FLYANCHOR, 0 },
+};
+const int nRTFControlWords = SAL_N_ELEMENTS(aRTFControlWords);
+
+RTFMathSymbol const aRTFMathControlWords[] = {
+ // eKeyword nToken eDestination
+ { RTFKeyword::MOMATH, M_TOKEN(oMath), Destination::MOMATH },
+ { RTFKeyword::MF, M_TOKEN(f), Destination::MF },
+ { RTFKeyword::MFPR, M_TOKEN(fPr), Destination::MFPR },
+ { RTFKeyword::MCTRLPR, M_TOKEN(ctrlPr), Destination::MCTRLPR },
+ { RTFKeyword::MNUM, M_TOKEN(num), Destination::MNUM },
+ { RTFKeyword::MDEN, M_TOKEN(den), Destination::MDEN },
+ { RTFKeyword::MACC, M_TOKEN(acc), Destination::MACC },
+ { RTFKeyword::MACCPR, M_TOKEN(accPr), Destination::MACCPR },
+ { RTFKeyword::MBAR, M_TOKEN(bar), Destination::MBAR },
+ { RTFKeyword::MBARPR, M_TOKEN(barPr), Destination::MBARPR },
+ { RTFKeyword::ME, M_TOKEN(e), Destination::ME },
+ { RTFKeyword::MD, M_TOKEN(d), Destination::MD },
+ { RTFKeyword::MDPR, M_TOKEN(dPr), Destination::MDPR },
+ { RTFKeyword::MFUNC, M_TOKEN(func), Destination::MFUNC },
+ { RTFKeyword::MFUNCPR, M_TOKEN(funcPr), Destination::MFUNCPR },
+ { RTFKeyword::MFNAME, M_TOKEN(fName), Destination::MFNAME },
+ { RTFKeyword::MLIMLOW, M_TOKEN(limLow), Destination::MLIMLOW },
+ { RTFKeyword::MLIMLOWPR, M_TOKEN(limLowPr), Destination::MLIMLOWPR },
+ { RTFKeyword::MLIM, M_TOKEN(lim), Destination::MLIM },
+ { RTFKeyword::MM, M_TOKEN(m), Destination::MM },
+ { RTFKeyword::MMPR, M_TOKEN(mPr), Destination::MMPR },
+ { RTFKeyword::MMR, M_TOKEN(mr), Destination::MMR },
+ { RTFKeyword::MNARY, M_TOKEN(nary), Destination::MNARY },
+ { RTFKeyword::MNARYPR, M_TOKEN(naryPr), Destination::MNARYPR },
+ { RTFKeyword::MSUB, M_TOKEN(sub), Destination::MSUB },
+ { RTFKeyword::MSUP, M_TOKEN(sup), Destination::MSUP },
+ { RTFKeyword::MLIMUPP, M_TOKEN(limUpp), Destination::MLIMUPP },
+ { RTFKeyword::MLIMUPPPR, M_TOKEN(limUppPr), Destination::MLIMUPPPR },
+ { RTFKeyword::MGROUPCHR, M_TOKEN(groupChr), Destination::MGROUPCHR },
+ { RTFKeyword::MGROUPCHRPR, M_TOKEN(groupChrPr), Destination::MGROUPCHRPR },
+ { RTFKeyword::MBORDERBOX, M_TOKEN(borderBox), Destination::MBORDERBOX },
+ { RTFKeyword::MBORDERBOXPR, M_TOKEN(borderBoxPr), Destination::MBORDERBOXPR },
+ { RTFKeyword::MRAD, M_TOKEN(rad), Destination::MRAD },
+ { RTFKeyword::MRADPR, M_TOKEN(radPr), Destination::MRADPR },
+ { RTFKeyword::MDEG, M_TOKEN(deg), Destination::MDEG },
+ { RTFKeyword::MSSUB, M_TOKEN(sSub), Destination::MSSUB },
+ { RTFKeyword::MSSUBPR, M_TOKEN(sSubPr), Destination::MSSUBPR },
+ { RTFKeyword::MSSUP, M_TOKEN(sSup), Destination::MSSUP },
+ { RTFKeyword::MSSUPPR, M_TOKEN(sSupPr), Destination::MSSUPPR },
+ { RTFKeyword::MSSUBSUP, M_TOKEN(sSubSup), Destination::MSSUBSUP },
+ { RTFKeyword::MSSUBSUPPR, M_TOKEN(sSubSupPr), Destination::MSSUBSUPPR },
+ { RTFKeyword::MSPRE, M_TOKEN(sPre), Destination::MSPRE },
+ { RTFKeyword::MSPREPR, M_TOKEN(sPrePr), Destination::MSPREPR },
+ { RTFKeyword::MBOX, M_TOKEN(box), Destination::MBOX },
+ { RTFKeyword::MEQARR, M_TOKEN(eqArr), Destination::MEQARR },
+};
+const int nRTFMathControlWords = SAL_N_ELEMENTS(aRTFMathControlWords);
+
+bool RTFMathSymbol::operator<(const RTFMathSymbol& rOther) const
+{
+ return m_eKeyword < rOther.m_eKeyword;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfcontrolwords.hxx b/sw/source/writerfilter/rtftok/rtfcontrolwords.hxx
new file mode 100644
index 000000000000..c1480ffb0231
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfcontrolwords.hxx
@@ -0,0 +1,2049 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+/**
+ * An RTF destination state is the last open destination control word.
+ *
+ * Note that this is not a 1:1 mapping between destination control
+ * words, e.g. RTF_PICT gets mapped to Destination::PICT or
+ * Destination::SHAPEPROPERTYVALUEPICT.
+ */
+enum class Destination
+{
+ NORMAL,
+ SKIP,
+ FONTTABLE,
+ FONTENTRY,
+ COLORTABLE,
+ STYLESHEET,
+ STYLEENTRY,
+ FIELD,
+ FIELDINSTRUCTION,
+ FIELDRESULT,
+ LISTTABLE,
+ LISTPICTURE,
+ LISTENTRY,
+ LISTNAME,
+ LISTOVERRIDETABLE,
+ LISTOVERRIDEENTRY,
+ LISTLEVEL,
+ LEVELTEXT,
+ LEVELNUMBERS,
+ SHPPICT,
+ PICT,
+ PICPROP,
+ SHAPEPROPERTY,
+ SHAPEPROPERTYNAME,
+ SHAPEPROPERTYVALUE,
+ SHAPE,
+ SHAPEINSTRUCTION,
+ SHAPEPROPERTYVALUEPICT,
+ NESTEDTABLEPROPERTIES,
+ FOOTNOTE,
+ BOOKMARKSTART,
+ BOOKMARKEND,
+ REVISIONTABLE,
+ REVISIONENTRY,
+ SHAPETEXT,
+ FORMFIELD,
+ FORMFIELDNAME,
+ FORMFIELDLIST,
+ DATAFIELD,
+ INFO,
+ CREATIONTIME,
+ REVISIONTIME,
+ PRINTTIME,
+ AUTHOR,
+ KEYWORDS,
+ OPERATOR,
+ COMPANY,
+ COMMENT,
+ OBJECT,
+ OBJDATA,
+ OBJCLASS,
+ RESULT,
+ ANNOTATIONDATE,
+ ANNOTATIONAUTHOR,
+ ANNOTATIONREFERENCE,
+ FALT,
+ FLYMAINCONTENT,
+ DRAWINGOBJECT,
+ PARAGRAPHNUMBERING,
+ PARAGRAPHNUMBERING_TEXTBEFORE,
+ PARAGRAPHNUMBERING_TEXTAFTER,
+ TITLE,
+ SUBJECT,
+ DOCCOMM,
+ ATNID,
+ ANNOTATIONREFERENCESTART,
+ ANNOTATIONREFERENCEEND,
+ MOMATH,
+ MR,
+ MF,
+ MFPR,
+ MCTRLPR,
+ MNUM,
+ MDEN,
+ MACC,
+ MACCPR,
+ MCHR,
+ MPOS,
+ MVERTJC,
+ MSTRIKEH,
+ MDEGHIDE,
+ ME,
+ MBAR,
+ MBARPR,
+ MD,
+ MDPR,
+ MBEGCHR,
+ MSEPCHR,
+ MENDCHR,
+ MFUNC,
+ MFUNCPR,
+ MFNAME,
+ MLIMLOW,
+ MLIMLOWPR,
+ MLIM,
+ MM,
+ MMPR,
+ MMR,
+ MNARY,
+ MNARYPR,
+ MSUB,
+ MSUP,
+ MSUBHIDE,
+ MSUPHIDE,
+ MLIMUPP,
+ MLIMUPPPR,
+ MGROUPCHR,
+ MGROUPCHRPR,
+ MBORDERBOX,
+ MBORDERBOXPR,
+ MRAD,
+ MRADPR,
+ MDEG,
+ MSSUB,
+ MSSUBPR,
+ MSSUP,
+ MSSUPPR,
+ MSSUBSUP,
+ MSSUBSUPPR,
+ MSPRE,
+ MSPREPR,
+ MTYPE,
+ MGROW,
+ MBOX,
+ MEQARR,
+ UPR,
+ LFOLEVEL,
+ BACKGROUND,
+ SHAPEGROUP,
+ FOOTNOTESEPARATOR,
+ INDEXENTRY,
+ TOCENTRY,
+ USERPROPS,
+ PROPNAME,
+ STATICVAL,
+ GENERATOR,
+ DOCVAR,
+};
+
+enum class RTFKeyword
+{
+ invalid = -1,
+ HEXCHAR,
+ OPTHYPH,
+ IGNORE,
+ SUBENTRY,
+ BACKSLASH,
+ NOBRKHYPH,
+ LBRACE,
+ FORMULA,
+ RBRACE,
+ NOBREAK,
+ AB,
+ ABSH,
+ ABSLOCK,
+ ABSNOOVRLP,
+ ABSW,
+ ACAPS,
+ ACCCIRCLE,
+ ACCCOMMA,
+ ACCDOT,
+ ACCNONE,
+ ACCUNDERDOT,
+ ACF,
+ ADEFF,
+ ADDITIVE,
+ ADEFLANG,
+ ADJUSTRIGHT,
+ ADN,
+ AENDDOC,
+ AENDNOTES,
+ AEXPND,
+ AF,
+ AFELEV,
+ AFS,
+ AFTNBJ,
+ AFTNCN,
+ AFTNNALC,
+ AFTNNAR,
+ AFTNNAUC,
+ AFTNNCHI,
+ AFTNNCHOSUNG,
+ AFTNNCNUM,
+ AFTNNDBAR,
+ AFTNNDBNUM,
+ AFTNNDBNUMD,
+ AFTNNDBNUMK,
+ AFTNNDBNUMT,
+ AFTNNGANADA,
+ AFTNNGBNUM,
+ AFTNNGBNUMD,
+ AFTNNGBNUMK,
+ AFTNNGBNUML,
+ AFTNNRLC,
+ AFTNNRUC,
+ AFTNNZODIAC,
+ AFTNNZODIACD,
+ AFTNNZODIACL,
+ AFTNRESTART,
+ AFTNRSTCONT,
+ AFTNSEP,
+ AFTNSEPC,
+ AFTNSTART,
+ AFTNTJ,
+ AI,
+ ALANG,
+ ALLOWFIELDENDSEL,
+ ALLPROT,
+ ALNTBLIND,
+ ALT,
+ ANIMTEXT,
+ ANNOTATION,
+ ANNOTPROT,
+ ANSI,
+ ANSICPG,
+ AOUTL,
+ APPLYBRKRULES,
+ ASCAPS,
+ ASHAD,
+ ASIANBRKRULE,
+ ASPALPHA,
+ ASPNUM,
+ ASTRIKE,
+ ATNAUTHOR,
+ ATNDATE,
+ ATNICN,
+ ATNID,
+ ATNPARENT,
+ ATNREF,
+ ATNTIME,
+ ATRFEND,
+ ATRFSTART,
+ AUL,
+ AULD,
+ AULDB,
+ AULNONE,
+ AULW,
+ AUP,
+ AUTHOR,
+ AUTOFMTOVERRIDE,
+ B,
+ BACKGROUND,
+ BDBFHDR,
+ BDRRLSWSIX,
+ BGBDIAG,
+ BGCROSS,
+ BGDCROSS,
+ BGDKBDIAG,
+ BGDKCROSS,
+ BGDKDCROSS,
+ BGDKFDIAG,
+ BGDKHORIZ,
+ BGDKVERT,
+ BGFDIAG,
+ BGHORIZ,
+ BGVERT,
+ BIN,
+ BINFSXN,
+ BINSXN,
+ BKMKCOLF,
+ BKMKCOLL,
+ BKMKEND,
+ BKMKPUB,
+ BKMKSTART,
+ BLIPTAG,
+ BLIPUID,
+ BLIPUPI,
+ BLUE,
+ BOOKFOLD,
+ BOOKFOLDREV,
+ BOOKFOLDSHEETS,
+ BOX,
+ BRDRART,
+ BRDRB,
+ BRDRBAR,
+ BRDRBTW,
+ BRDRCF,
+ BRDRDASH,
+ BRDRDASHD,
+ BRDRDASHDD,
+ BRDRDASHDOTSTR,
+ BRDRDASHSM,
+ BRDRDB,
+ BRDRDOT,
+ BRDREMBOSS,
+ BRDRENGRAVE,
+ BRDRFRAME,
+ BRDRHAIR,
+ BRDRINSET,
+ BRDRL,
+ BRDRNIL,
+ BRDRNONE,
+ BRDROUTSET,
+ BRDRR,
+ BRDRS,
+ BRDRSH,
+ BRDRT,
+ BRDRTBL,
+ BRDRTH,
+ BRDRTHTNLG,
+ BRDRTHTNMG,
+ BRDRTHTNSG,
+ BRDRTNTHLG,
+ BRDRTNTHMG,
+ BRDRTNTHSG,
+ BRDRTNTHTNLG,
+ BRDRTNTHTNMG,
+ BRDRTNTHTNSG,
+ BRDRTRIPLE,
+ BRDRW,
+ BRDRWAVY,
+ BRDRWAVYDB,
+ BRKFRM,
+ BRSP,
+ BULLET,
+ BUPTIM,
+ BXE,
+ CACCENTFIVE,
+ CACCENTFOUR,
+ CACCENTONE,
+ CACCENTSIX,
+ CACCENTTHREE,
+ CACCENTTWO,
+ CACHEDCOLBAL,
+ CAPS,
+ CATEGORY,
+ CB,
+ CBACKGROUNDONE,
+ CBACKGROUNDTWO,
+ CBPAT,
+ CCHS,
+ CELL,
+ CELLX,
+ CF,
+ CFOLLOWEDHYPERLINK,
+ CFPAT,
+ CGRID,
+ CHARRSID,
+ CHARSCALEX,
+ CHATN,
+ CHBGBDIAG,
+ CHBGCROSS,
+ CHBGDCROSS,
+ CHBGDKBDIAG,
+ CHBGDKCROSS,
+ CHBGDKDCROSS,
+ CHBGDKFDIAG,
+ CHBGDKHORIZ,
+ CHBGDKVERT,
+ CHBGFDIAG,
+ CHBGHORIZ,
+ CHBGVERT,
+ CHBRDR,
+ CHCBPAT,
+ CHCFPAT,
+ CHDATE,
+ CHDPA,
+ CHDPL,
+ CHFTN,
+ CHFTNSEP,
+ CHFTNSEPC,
+ CHPGN,
+ CHHRES,
+ CHSHDNG,
+ CHTIME,
+ CHYPERLINK,
+ CLBGBDIAG,
+ CLBGCROSS,
+ CLBGDCROSS,
+ CLBGDKBDIAG,
+ CLBGDKCROSS,
+ CLBGDKDCROSS,
+ CLBGDKFDIAG,
+ CLBGDKHOR,
+ CLBGDKVERT,
+ CLBGFDIAG,
+ CLBGHORIZ,
+ CLBGVERT,
+ CLBRDRB,
+ CLBRDRL,
+ CLBRDRR,
+ CLBRDRT,
+ CLCBPAT,
+ CLCBPATRAW,
+ CLCFPAT,
+ CLCFPATRAW,
+ CLDEL,
+ CLDELAUTH,
+ CLDELDTTM,
+ CLDGLL,
+ CLDGLU,
+ CLFITTEXT,
+ CLFTSWIDTH,
+ CLHIDEMARK,
+ CLINS,
+ CLINSAUTH,
+ CLINSDTTM,
+ CLMGF,
+ CLMRG,
+ CLMRGD,
+ CLMRGDAUTH,
+ CLMRGDDTTM,
+ CLMRGDR,
+ CLNOWRAP,
+ CLPADB,
+ CLPADFB,
+ CLPADFL,
+ CLPADFR,
+ CLPADFT,
+ CLPADL,
+ CLPADR,
+ CLPADT,
+ CLSPB,
+ CLSPFB,
+ CLSPFL,
+ CLSPFR,
+ CLSPFT,
+ CLSPL,
+ CLSPR,
+ CLSPT,
+ CLSHDNG,
+ CLSHDNGRAW,
+ CLSHDRAWNIL,
+ CLSPLIT,
+ CLSPLITR,
+ CLTXBTLR,
+ CLTXLRTB,
+ CLTXLRTBV,
+ CLTXTBRL,
+ CLTXTBRLV,
+ CLVERTALB,
+ CLVERTALC,
+ CLVERTALT,
+ CLVMGF,
+ CLVMRG,
+ CLWWIDTH,
+ CMAINDARKONE,
+ CMAINDARKTWO,
+ CMAINLIGHTONE,
+ CMAINLIGHTTWO,
+ COLLAPSED,
+ COLNO,
+ COLORSCHEMEMAPPING,
+ COLORTBL,
+ COLS,
+ COLSR,
+ COLSX,
+ COLUMN,
+ COLW,
+ COMMENT,
+ COMPANY,
+ CONTEXTUALSPACE,
+ CPG,
+ CRAUTH,
+ CRDATE,
+ CREATIM,
+ CS,
+ CSHADE,
+ CTEXTONE,
+ CTEXTTWO,
+ CTINT,
+ CTRL,
+ CTS,
+ CUFI,
+ CULI,
+ CURI,
+ CVMME,
+ DATAFIELD,
+ DATASTORE,
+ DATE,
+ DBCH,
+ DEFCHP,
+ DEFF,
+ DEFFORMAT,
+ DEFLANG,
+ DEFLANGFE,
+ DEFPAP,
+ DEFSHP,
+ DEFTAB,
+ DELETED,
+ DELRSID,
+ DFRAUTH,
+ DFRDATE,
+ DFRMTXTX,
+ DFRMTXTY,
+ DFRSTART,
+ DFRSTOP,
+ DFRXST,
+ DGHORIGIN,
+ DGHSHOW,
+ DGHSPACE,
+ DGMARGIN,
+ DGSNAP,
+ DGVORIGIN,
+ DGVSHOW,
+ DGVSPACE,
+ DIBITMAP,
+ DISABLED,
+ DN,
+ DNTBLNSBDB,
+ DO,
+ DOBXCOLUMN,
+ DOBXMARGIN,
+ DOBXPAGE,
+ DOBYMARGIN,
+ DOBYPAGE,
+ DOBYPARA,
+ DOCCOMM,
+ DOCTEMP,
+ DOCTYPE,
+ DOCVAR,
+ DODHGT,
+ DOLOCK,
+ DONOTEMBEDLINGDATA,
+ DONOTEMBEDSYSFONT,
+ DONOTSHOWCOMMENTS,
+ DONOTSHOWINSDEL,
+ DONOTSHOWMARKUP,
+ DONOTSHOWPROPS,
+ DPAENDHOL,
+ DPAENDL,
+ DPAENDSOL,
+ DPAENDW,
+ DPARC,
+ DPARCFLIPX,
+ DPARCFLIPY,
+ DPASTARTHOL,
+ DPASTARTL,
+ DPASTARTSOL,
+ DPASTARTW,
+ DPCALLOUT,
+ DPCOA,
+ DPCOACCENT,
+ DPCOBESTFIT,
+ DPCOBORDER,
+ DPCODABS,
+ DPCODBOTTOM,
+ DPCODCENTER,
+ DPCODESCENT,
+ DPCODTOP,
+ DPCOLENGTH,
+ DPCOMINUSX,
+ DPCOMINUSY,
+ DPCOOFFSET,
+ DPCOSMARTA,
+ DPCOTDOUBLE,
+ DPCOTRIGHT,
+ DPCOTSINGLE,
+ DPCOTTRIPLE,
+ DPCOUNT,
+ DPELLIPSE,
+ DPENDGROUP,
+ DPFILLBGCB,
+ DPFILLBGCG,
+ DPFILLBGCR,
+ DPFILLBGGRAY,
+ DPFILLBGPAL,
+ DPFILLFGCB,
+ DPFILLFGCG,
+ DPFILLFGCR,
+ DPFILLFGGRAY,
+ DPFILLFGPAL,
+ DPFILLPAT,
+ DPGROUP,
+ DPLINE,
+ DPLINECOB,
+ DPLINECOG,
+ DPLINECOR,
+ DPLINEDADO,
+ DPLINEDADODO,
+ DPLINEDASH,
+ DPLINEDOT,
+ DPLINEGRAY,
+ DPLINEHOLLOW,
+ DPLINEPAL,
+ DPLINESOLID,
+ DPLINEW,
+ DPPOLYCOUNT,
+ DPPOLYGON,
+ DPPOLYLINE,
+ DPPTX,
+ DPPTY,
+ DPRECT,
+ DPROUNDR,
+ DPSHADOW,
+ DPSHADX,
+ DPSHADY,
+ DPTXBTLR,
+ DPTXBX,
+ DPTXBXMAR,
+ DPTXBXTEXT,
+ DPTXLRTB,
+ DPTXLRTBV,
+ DPTXTBRL,
+ DPTXTBRLV,
+ DPX,
+ DPXSIZE,
+ DPY,
+ DPYSIZE,
+ DROPCAPLI,
+ DROPCAPT,
+ DS,
+ DXFRTEXT,
+ DY,
+ EBCEND,
+ EBCSTART,
+ EDMINS,
+ EMBO,
+ EMDASH,
+ EMFBLIP,
+ EMSPACE,
+ ENDASH,
+ ENDDOC,
+ ENDNHERE,
+ ENDNOTES,
+ ENFORCEPROT,
+ ENSPACE,
+ EXPND,
+ EXPNDTW,
+ EXPSHRTN,
+ F,
+ FAAUTO,
+ FACENTER,
+ FACINGP,
+ FACTOIDNAME,
+ FAFIXED,
+ FAHANG,
+ FALT,
+ FAROMAN,
+ FAVAR,
+ FBIAS,
+ FBIDI,
+ FBIDIS,
+ FBIMAJOR,
+ FBIMINOR,
+ FCHARS,
+ FCHARSET,
+ FCS,
+ FDBMAJOR,
+ FDBMINOR,
+ FDECOR,
+ FELNBRELEV,
+ FET,
+ FETCH,
+ FFDEFRES,
+ FFDEFTEXT,
+ FFENTRYMCR,
+ FFEXITMCR,
+ FFFORMAT,
+ FFHASLISTBOX,
+ FFHELPTEXT,
+ FFHPS,
+ FFL,
+ FFMAXLEN,
+ FFNAME,
+ FFOWNHELP,
+ FFOWNSTAT,
+ FFPROT,
+ FFRECALC,
+ FFRES,
+ FFSIZE,
+ FFSTATTEXT,
+ FFTYPE,
+ FFTYPETXT,
+ FHIMAJOR,
+ FHIMINOR,
+ FI,
+ FID,
+ FIELD,
+ FILE,
+ FILETBL,
+ FITTEXT,
+ FJGOTHIC,
+ FJMINCHOU,
+ FLDALT,
+ FLDDIRTY,
+ FLDEDIT,
+ FLDINST,
+ FLDLOCK,
+ FLDPRIV,
+ FLDRSLT,
+ FLDTYPE,
+ FLOMAJOR,
+ FLOMINOR,
+ FMODERN,
+ FN,
+ FNAME,
+ FNETWORK,
+ FNIL,
+ FNONFILESYS,
+ FONTEMB,
+ FONTFILE,
+ FONTTBL,
+ FOOTER,
+ FOOTERF,
+ FOOTERL,
+ FOOTERR,
+ FOOTERY,
+ FOOTNOTE,
+ FORCEUPGRADE,
+ FORMDISP,
+ FORMFIELD,
+ FORMPROT,
+ FORMSHADE,
+ FOSNUM,
+ FPRQ,
+ FRACWIDTH,
+ FRELATIVE,
+ FRMTXBTLR,
+ FRMTXLRTB,
+ FRMTXLRTBV,
+ FRMTXTBRL,
+ FRMTXTBRLV,
+ FROMAN,
+ FROMHTML,
+ FROMTEXT,
+ FS,
+ FSCRIPT,
+ FSWISS,
+ FTECH,
+ FTNALT,
+ FTNBJ,
+ FTNCN,
+ FTNIL,
+ FTNLYTWNINE,
+ FTNNALC,
+ FTNNAR,
+ FTNNAUC,
+ FTNNCHI,
+ FTNNCHOSUNG,
+ FTNNCNUM,
+ FTNNDBAR,
+ FTNNDBNUM,
+ FTNNDBNUMD,
+ FTNNDBNUMK,
+ FTNNDBNUMT,
+ FTNNGANADA,
+ FTNNGBNUM,
+ FTNNGBNUMD,
+ FTNNGBNUMK,
+ FTNNGBNUML,
+ FTNNRLC,
+ FTNNRUC,
+ FTNNZODIAC,
+ FTNNZODIACD,
+ FTNNZODIACL,
+ FTNRESTART,
+ FTNRSTCONT,
+ FTNRSTPG,
+ FTNSEP,
+ FTNSEPC,
+ FTNSTART,
+ FTNTJ,
+ FTTRUETYPE,
+ FVALIDDOS,
+ FVALIDHPFS,
+ FVALIDMAC,
+ FVALIDNTFS,
+ G,
+ GCW,
+ GENERATOR,
+ GREEN,
+ GRFDOCEVENTS,
+ GRIDTBL,
+ GUTTER,
+ GUTTERPRL,
+ GUTTERSXN,
+ HEADER,
+ HEADERF,
+ HEADERL,
+ HEADERR,
+ HEADERY,
+ HICH,
+ HIGHLIGHT,
+ HL,
+ HLFR,
+ HLINKBASE,
+ HLLOC,
+ HLSRC,
+ HORZDOC,
+ HORZSECT,
+ HORZVERT,
+ HR,
+ HRES,
+ HRULE,
+ HSV,
+ HTMAUTSP,
+ HTMLBASE,
+ HTMLRTF,
+ HTMLTAG,
+ HWELEV,
+ HYPHAUTO,
+ HYPHCAPS,
+ HYPHCONSEC,
+ HYPHHOTZ,
+ HYPHPAR,
+ I,
+ ID,
+ IGNOREMIXEDCONTENT,
+ ILFOMACATCLNUP,
+ ILVL,
+ IMPR,
+ INDMIRROR,
+ INDRLSWELEVEN,
+ INFO,
+ INSRSID,
+ INTBL,
+ IPGP,
+ IROWBAND,
+ IROW,
+ ITAP,
+ IXE,
+ JCOMPRESS,
+ JEXPAND,
+ JIS,
+ JPEGBLIP,
+ JSKSU,
+ KEEP,
+ KEEPN,
+ KERNING,
+ KEYCODE,
+ KEYWORDS,
+ KRNPRSNET,
+ KSULANG,
+ JCLISTTAB,
+ LANDSCAPE,
+ LANG,
+ LANGFE,
+ LANGFENP,
+ LANGNP,
+ LASTROW,
+ LATENTSTYLES,
+ LBR,
+ LCHARS,
+ LDBLQUOTE,
+ LEVEL,
+ LEVELFOLLOW,
+ LEVELINDENT,
+ LEVELJC,
+ LEVELJCN,
+ LEVELLEGAL,
+ LEVELNFC,
+ LEVELNFCN,
+ LEVELNORESTART,
+ LEVELNUMBERS,
+ LEVELOLD,
+ LEVELPICTURE,
+ LEVELPICTURENOSIZE,
+ LEVELPREV,
+ LEVELPREVSPACE,
+ LEVELSPACE,
+ LEVELSTARTAT,
+ LEVELTEMPLATEID,
+ LEVELTEXT,
+ LFOLEVEL,
+ LI,
+ LINE,
+ LINEBETCOL,
+ LINECONT,
+ LINEMOD,
+ LINEPPAGE,
+ LINERESTART,
+ LINESTART,
+ LINESTARTS,
+ LINEX,
+ LINKSELF,
+ LINKSTYLES,
+ LINKVAL,
+ LIN,
+ LISA,
+ LISB,
+ LIST,
+ LISTHYBRID,
+ LISTID,
+ LISTLEVEL,
+ LISTNAME,
+ LISTOVERRIDE,
+ LISTOVERRIDECOUNT,
+ LISTOVERRIDEFORMAT,
+ LISTOVERRIDESTARTAT,
+ LISTOVERRIDETABLE,
+ LISTPICTURE,
+ LISTRESTARTHDN,
+ LISTSIMPLE,
+ LISTSTYLEID,
+ LISTSTYLENAME,
+ LISTTABLE,
+ LISTTEMPLATEID,
+ LISTTEXT,
+ LNBRKRULE,
+ LNDSCPSXN,
+ LNONGRID,
+ LOCH,
+ LQUOTE,
+ LS,
+ LSDLOCKED,
+ LSDLOCKEDDEF,
+ LSDLOCKEDEXCEPT,
+ LSDPRIORITY,
+ LSDPRIORITYDEF,
+ LSDQFORMAT,
+ LSDQFORMATDEF,
+ LSDSEMIHIDDEN,
+ LSDSEMIHIDDENDEF,
+ LSDSTIMAX,
+ LSDUNHIDEUSED,
+ LSDUNHIDEUSEDDEF,
+ LTRCH,
+ LTRDOC,
+ LTRMARK,
+ LTRPAR,
+ LTRROW,
+ LTRSECT,
+ LVLTENTATIVE,
+ LYTCALCTBLWD,
+ LYTEXCTTP,
+ LYTPRTMET,
+ LYTTBLRTGR,
+ MAC,
+ MACC,
+ MACCPR,
+ MACPICT,
+ MAILMERGE,
+ MAKEBACKUP,
+ MALN,
+ MALNSCR,
+ MANAGER,
+ MARGB,
+ MARGBSXN,
+ MARGL,
+ MARGLSXN,
+ MARGMIRROR,
+ MARGMIRSXN,
+ MARGPR,
+ MARGR,
+ MARGRSXN,
+ MARGSZ,
+ MARGT,
+ MARGTSXN,
+ MBAR,
+ MBARPR,
+ MBASEJC,
+ MBEGCHR,
+ MBORDERBOX,
+ MBORDERBOXPR,
+ MBOX,
+ MBOXPR,
+ MBRK,
+ MBRKBIN,
+ MBRKBINSUB,
+ MCGP,
+ MCGPRULE,
+ MCHR,
+ MCOUNT,
+ MCSP,
+ MCTRLPR,
+ MD,
+ MDEFJC,
+ MDEG,
+ MDEGHIDE,
+ MDEN,
+ MDIFF,
+ MDIFFSTY,
+ MDISPDEF,
+ MDPR,
+ ME,
+ MENDCHR,
+ MEQARR,
+ MEQARRPR,
+ MF,
+ MFNAME,
+ MFPR,
+ MFUNC,
+ MFUNCPR,
+ MGROUPCHR,
+ MGROUPCHRPR,
+ MGROW,
+ MHIDEBOT,
+ MHIDELEFT,
+ MHIDERIGHT,
+ MHIDETOP,
+ MHTMLTAG,
+ MIN,
+ MINTERSP,
+ MINTLIM,
+ MINTRASP,
+ MJC,
+ MLIM,
+ MLIMLOC,
+ MLIMLOW,
+ MLIMLOWPR,
+ MLIMUPP,
+ MLIMUPPPR,
+ MLIT,
+ MLMARGIN,
+ MM,
+ MMADDFIELDNAME,
+ MMATH,
+ MMATHFONT,
+ MMATHPICT,
+ MMATHPR,
+ MMATTACH,
+ MMAXDIST,
+ MMBLANKLINES,
+ MMC,
+ MMCJC,
+ MMCONNECTSTR,
+ MMCONNECTSTRDATA,
+ MMCPR,
+ MMCS,
+ MMDATASOURCE,
+ MMDATATYPEACCESS,
+ MMDATATYPEEXCEL,
+ MMDATATYPEFILE,
+ MMDATATYPEODBC,
+ MMDATATYPEODSO,
+ MMDATATYPEQT,
+ MMDEFAULTSQL,
+ MMDESTEMAIL,
+ MMDESTFAX,
+ MMDESTNEWDOC,
+ MMDESTPRINTER,
+ MMERRORS,
+ MMFTTYPEADDRESS,
+ MMFTTYPEBARCODE,
+ MMFTTYPEDBCOLUMN,
+ MMFTTYPEMAPPED,
+ MMFTTYPENULL,
+ MMFTTYPESALUTATION,
+ MMHEADERSOURCE,
+ MMJDSOTYPE,
+ MMLINKTOQUERY,
+ MMMAILSUBJECT,
+ MMMAINTYPECATALOG,
+ MMMAINTYPEEMAIL,
+ MMMAINTYPEENVELOPES,
+ MMMAINTYPEFAX,
+ MMMAINTYPELABELS,
+ MMMAINTYPELETTERS,
+ MMODSO,
+ MMODSOACTIVE,
+ MMODSOCOLDELIM,
+ MMODSOCOLUMN,
+ MMODSODYNADDR,
+ MMODSOFHDR,
+ MMODSOFILTER,
+ MMODSOFLDMPDATA,
+ MMODSOFMCOLUMN,
+ MMODSOHASH,
+ MMODSOLID,
+ MMODSOMAPPEDNAME,
+ MMODSONAME,
+ MMODSORECIPDATA,
+ MMODSOSORT,
+ MMODSOSRC,
+ MMODSOTABLE,
+ MMODSOUDL,
+ MMODSOUDLDATA,
+ MMODSOUNIQUETAG,
+ MMPR,
+ MMQUERY,
+ MMR,
+ MMRECCUR,
+ MMSHOWDATA,
+ MNARY,
+ MNARYLIM,
+ MNARYPR,
+ MNOBREAK,
+ MNOR,
+ MNUM,
+ MO,
+ MOBJDIST,
+ MOMATH,
+ MOMATHPARA,
+ MOMATHPARAPR,
+ MOPEMU,
+ MPHANT,
+ MPHANTPR,
+ MPLCHIDE,
+ MPOS,
+ MPOSTSP,
+ MPRESP,
+ MR,
+ MRAD,
+ MRADPR,
+ MRMARGIN,
+ MRPR,
+ MRSP,
+ MRSPRULE,
+ MSCR,
+ MSEPCHR,
+ MSHOW,
+ MSHP,
+ MSMALLFRAC,
+ MSMCAP,
+ MSPRE,
+ MSPREPR,
+ MSSUB,
+ MSSUBPR,
+ MSSUBSUP,
+ MSSUBSUPPR,
+ MSSUP,
+ MSSUPPR,
+ MSTRIKEBLTR,
+ MSTRIKEH,
+ MSTRIKETLBR,
+ MSTRIKEV,
+ MSTY,
+ MSUB,
+ MSUBHIDE,
+ MSUP,
+ MSUPHIDE,
+ MTRANSP,
+ MTYPE,
+ MUSER,
+ MVAUTH,
+ MVDATE,
+ MVERTJC,
+ MVF,
+ MVFMF,
+ MVFML,
+ MVT,
+ MVTOF,
+ MVTOL,
+ MWRAPINDENT,
+ MWRAPRIGHT,
+ MZEROASC,
+ MZERODESC,
+ MZEROWID,
+ NESTCELL,
+ NESTROW,
+ NESTTABLEPROPS,
+ NEWTBLSTYRULS,
+ NEXTFILE,
+ NOAFCNSTTBL,
+ NOBRKWRPTBL,
+ NOCOLBAL,
+ NOCOMPATOPTIONS,
+ NOCWRAP,
+ NOCXSPTABLE,
+ NOEXTRASPRL,
+ NOFCHARS,
+ NOFCHARSWS,
+ NOFEATURETHROTTLE,
+ NOFPAGES,
+ NOFWORDS,
+ NOGROWAUTOFIT,
+ NOINDNMBRTS,
+ NOJKERNPUNCT,
+ NOLEAD,
+ NOLINE,
+ NOLNHTADJTBL,
+ NONESTTABLES,
+ NONSHPPICT,
+ NOOVERFLOW,
+ NOPROOF,
+ NOQFPROMOTE,
+ NOSECTEXPAND,
+ NOSNAPLINEGRID,
+ NOSPACEFORUL,
+ NOSUPERSUB,
+ NOTABIND,
+ NOTBRKCNSTFRCTBL,
+ NOTCVASP,
+ NOTVATXBX,
+ NOUICOMPAT,
+ NOULTRLSPC,
+ NOWIDCTLPAR,
+ NOWRAP,
+ NOWWRAP,
+ NOXLATTOYEN,
+ OBJALIAS,
+ OBJALIGN,
+ OBJATTPH,
+ OBJAUTLINK,
+ OBJCLASS,
+ OBJCROPB,
+ OBJCROPL,
+ OBJCROPR,
+ OBJCROPT,
+ OBJDATA,
+ OBJECT,
+ OBJEMB,
+ OBJH,
+ OBJHTML,
+ OBJICEMB,
+ OBJLINK,
+ OBJLOCK,
+ OBJNAME,
+ OBJOCX,
+ OBJPUB,
+ OBJSCALEX,
+ OBJSCALEY,
+ OBJSECT,
+ OBJSETSIZE,
+ OBJSUB,
+ OBJTIME,
+ OBJTRANSY,
+ OBJUPDATE,
+ OBJW,
+ OGUTTER,
+ OLDAS,
+ OLDCPROPS,
+ OLDLINEWRAP,
+ OLDPPROPS,
+ OLDSPROPS,
+ OLDTPROPS,
+ OLECLSID,
+ OPERATOR,
+ OTBLRUL,
+ OUTL,
+ OUTLINELEVEL,
+ OVERLAY,
+ PAGE,
+ PAGEBB,
+ PANOSE,
+ PAPERH,
+ PAPERW,
+ PAR,
+ PARARSID,
+ PARD,
+ PASSWORD,
+ PASSWORDHASH,
+ PC,
+ PCA,
+ PGBRDRB,
+ PGBRDRFOOT,
+ PGBRDRHEAD,
+ PGBRDRL,
+ PGBRDROPT,
+ PGBRDRR,
+ PGBRDRSNAP,
+ PGBRDRT,
+ PGHSXN,
+ PGNBIDIA,
+ PGNBIDIB,
+ PGNCHOSUNG,
+ PGNCNUM,
+ PGNCONT,
+ PGNDBNUM,
+ PGNDBNUMD,
+ PGNDBNUMK,
+ PGNDBNUMT,
+ PGNDEC,
+ PGNDECD,
+ PGNGANADA,
+ PGNGBNUM,
+ PGNGBNUMD,
+ PGNGBNUMK,
+ PGNGBNUML,
+ PGNHINDIA,
+ PGNHINDIB,
+ PGNHINDIC,
+ PGNHINDID,
+ PGNHN,
+ PGNHNSC,
+ PGNHNSH,
+ PGNHNSM,
+ PGNHNSN,
+ PGNHNSP,
+ PGNID,
+ PGNLCLTR,
+ PGNLCRM,
+ PGNRESTART,
+ PGNSTART,
+ PGNSTARTS,
+ PGNTHAIA,
+ PGNTHAIB,
+ PGNTHAIC,
+ PGNUCLTR,
+ PGNUCRM,
+ PGNVIETA,
+ PGNX,
+ PGNY,
+ PGNZODIAC,
+ PGNZODIACD,
+ PGNZODIACL,
+ PGP,
+ PGPTBL,
+ PGWSXN,
+ PHCOL,
+ PHMRG,
+ PHPG,
+ PICBMP,
+ PICBPP,
+ PICCROPB,
+ PICCROPL,
+ PICCROPR,
+ PICCROPT,
+ PICH,
+ PICHGOAL,
+ PICPROP,
+ PICSCALED,
+ PICSCALEX,
+ PICSCALEY,
+ PICT,
+ PICW,
+ PICWGOAL,
+ PINDTABQC,
+ PINDTABQL,
+ PINDTABQR,
+ PLAIN,
+ PMARTABQC,
+ PMARTABQL,
+ PMARTABQR,
+ PMMETAFILE,
+ PN,
+ PNACROSS,
+ PNAIU,
+ PNAIUD,
+ PNAIUEO,
+ PNAIUEOD,
+ PNB,
+ PNBIDIA,
+ PNBIDIB,
+ PNCAPS,
+ PNCARD,
+ PNCF,
+ PNCHOSUNG,
+ PNCNUM,
+ PNDBNUM,
+ PNDBNUMD,
+ PNDBNUMK,
+ PNDBNUML,
+ PNDBNUMT,
+ PNDEC,
+ PNDECD,
+ PNF,
+ PNFS,
+ PNGANADA,
+ PNGBLIP,
+ PNGBNUM,
+ PNGBNUMD,
+ PNGBNUMK,
+ PNGBNUML,
+ PNHANG,
+ PNI,
+ PNINDENT,
+ PNIROHA,
+ PNIROHAD,
+ PNLCLTR,
+ PNLCRM,
+ PNLVL,
+ PNLVLBLT,
+ PNLVLBODY,
+ PNLVLCONT,
+ PNNUMONCE,
+ PNORD,
+ PNORDT,
+ PNPREV,
+ PNQC,
+ PNQL,
+ PNQR,
+ PNRAUTH,
+ PNRDATE,
+ PNRESTART,
+ PNRNFC,
+ PNRNOT,
+ PNRPNBR,
+ PNRRGB,
+ PNRSTART,
+ PNRSTOP,
+ PNRXST,
+ PNSCAPS,
+ PNSECLVL,
+ PNSP,
+ PNSTART,
+ PNSTRIKE,
+ PNTEXT,
+ PNTXTA,
+ PNTXTB,
+ PNUCLTR,
+ PNUCRM,
+ PNUL,
+ PNULD,
+ PNULDASH,
+ PNULDASHD,
+ PNULDASHDD,
+ PNULDB,
+ PNULHAIR,
+ PNULNONE,
+ PNULTH,
+ PNULW,
+ PNULWAVE,
+ PNZODIAC,
+ PNZODIACD,
+ PNZODIACL,
+ POSNEGX,
+ POSNEGY,
+ POSX,
+ POSXC,
+ POSXI,
+ POSXL,
+ POSXO,
+ POSXR,
+ POSY,
+ POSYB,
+ POSYC,
+ POSYIL,
+ POSYIN,
+ POSYOUT,
+ POSYT,
+ PRAUTH,
+ PRCOLBL,
+ PRDATE,
+ PRINTDATA,
+ PRINTIM,
+ PRIVATE,
+ PROPNAME,
+ PROPTYPE,
+ PROTECT,
+ PROTEND,
+ PROTLEVEL,
+ PROTSTART,
+ PROTUSERTBL,
+ PSOVER,
+ PSZ,
+ PTABLDOT,
+ PTABLMDOT,
+ PTABLMINUS,
+ PTABLNONE,
+ PTABLUSCORE,
+ PUBAUTO,
+ PVMRG,
+ PVPARA,
+ PVPG,
+ PWD,
+ PXE,
+ QC,
+ QD,
+ QJ,
+ QK,
+ QL,
+ QMSPACE,
+ QR,
+ QT,
+ RAWCLBGDKBDIAG,
+ RAWCLBGBDIAG,
+ RAWCLBGCROSS,
+ RAWCLBGDCROSS,
+ RAWCLBGDKCROSS,
+ RAWCLBGDKDCROSS,
+ RAWCLBGDKFDIAG,
+ RAWCLBGDKHOR,
+ RAWCLBGDKVERT,
+ RAWCLBGFDIAG,
+ RAWCLBGHORIZ,
+ RAWCLBGVERT,
+ RDBLQUOTE,
+ READONLYRECOMMENDED,
+ READPROT,
+ RED,
+ RELYONVML,
+ REMDTTM,
+ REMPERSONALINFO,
+ RESULT,
+ REVAUTH,
+ REVAUTHDEL,
+ REVBAR,
+ REVDTTM,
+ REVDTTMDEL,
+ REVISED,
+ REVISIONS,
+ REVPROP,
+ REVPROT,
+ REVTBL,
+ REVTIM,
+ RI,
+ RIN,
+ ROW,
+ RQUOTE,
+ RSID,
+ RSIDROOT,
+ RSIDTBL,
+ RSLTBMP,
+ RSLTHTML,
+ RSLTMERGE,
+ RSLTPICT,
+ RSLTRTF,
+ RSLTTXT,
+ RTF,
+ RTLCH,
+ RTLDOC,
+ RTLGUTTER,
+ RTLMARK,
+ RTLPAR,
+ RTLROW,
+ RTLSECT,
+ RXE,
+ S,
+ SA,
+ SAAUTO,
+ SAFTNNALC,
+ SAFTNNAR,
+ SAFTNNAUC,
+ SAFTNNCHI,
+ SAFTNNCHOSUNG,
+ SAFTNNCNUM,
+ SAFTNNDBAR,
+ SAFTNNDBNUM,
+ SAFTNNDBNUMD,
+ SAFTNNDBNUMK,
+ SAFTNNDBNUMT,
+ SAFTNNGANADA,
+ SAFTNNGBNUM,
+ SAFTNNGBNUMD,
+ SAFTNNGBNUMK,
+ SAFTNNGBNUML,
+ SAFTNNRLC,
+ SAFTNNRUC,
+ SAFTNNZODIAC,
+ SAFTNNZODIACD,
+ SAFTNNZODIACL,
+ SAFTNRESTART,
+ SAFTNRSTCONT,
+ SAFTNSTART,
+ SAUTOUPD,
+ SAVEINVALIDXML,
+ SAVEPREVPICT,
+ SB,
+ SBASEDON,
+ SBAUTO,
+ SBKCOL,
+ SBKEVEN,
+ SBKNONE,
+ SBKODD,
+ SBKPAGE,
+ SBYS,
+ SCAPS,
+ SCOMPOSE,
+ SEC,
+ SECT,
+ SECTD,
+ SECTDEFAULTCL,
+ SECTEXPAND,
+ SECTLINEGRID,
+ SECTNUM,
+ SECTRSID,
+ SECTSPECIFYCL,
+ SECTSPECIFYGENN,
+ SECTSPECIFYL,
+ SECTUNLOCKED,
+ SFTNBJ,
+ SFTNNALC,
+ SFTNNAR,
+ SFTNNAUC,
+ SFTNNCHI,
+ SFTNNCHOSUNG,
+ SFTNNCNUM,
+ SFTNNDBAR,
+ SFTNNDBNUM,
+ SFTNNDBNUMD,
+ SFTNNDBNUMK,
+ SFTNNDBNUMT,
+ SFTNNGANADA,
+ SFTNNGBNUM,
+ SFTNNGBNUMD,
+ SFTNNGBNUMK,
+ SFTNNGBNUML,
+ SFTNNRLC,
+ SFTNNRUC,
+ SFTNNZODIAC,
+ SFTNNZODIACD,
+ SFTNNZODIACL,
+ SFTNRESTART,
+ SFTNRSTCONT,
+ SFTNRSTPG,
+ SFTNSTART,
+ SFTNTJ,
+ SHAD,
+ SHADING,
+ SHIDDEN,
+ SHIFT,
+ SHOWPLACEHOLDTEXT,
+ SHOWXMLERRORS,
+ SHP,
+ SHPBOTTOM,
+ SHPBXCOLUMN,
+ SHPBXIGNORE,
+ SHPBXMARGIN,
+ SHPBXPAGE,
+ SHPBYIGNORE,
+ SHPBYMARGIN,
+ SHPBYPAGE,
+ SHPBYPARA,
+ SHPFBLWTXT,
+ SHPFHDR,
+ SHPGRP,
+ SHPINST,
+ SHPLEFT,
+ SHPLID,
+ SHPLOCKANCHOR,
+ SHPPICT,
+ SHPRIGHT,
+ SHPRSLT,
+ SHPTOP,
+ SHPTXT,
+ SHPWRK,
+ SHPWR,
+ SHPZ,
+ SL,
+ SLINK,
+ SLMULT,
+ SLOCKED,
+ SN,
+ SNAPTOGRIDINCELL,
+ SNEXT,
+ SOFTCOL,
+ SOFTLHEIGHT,
+ SOFTLINE,
+ SOFTPAGE,
+ SP,
+ SPERSONAL,
+ SPLTPGPAR,
+ SPLYTWNINE,
+ SPRIORITY,
+ SPRSBSP,
+ SPRSLNSP,
+ SPRSSPBF,
+ SPRSTSM,
+ SPRSTSP,
+ SPV,
+ SQFORMAT,
+ SRAUTH,
+ SRDATE,
+ SREPLY,
+ SSEMIHIDDEN,
+ STATICVAL,
+ STEXTFLOW,
+ STRIKE,
+ STRIKED,
+ STSHFBI,
+ STSHFDBCH,
+ STSHFHICH,
+ STSHFLOCH,
+ STYLELOCK,
+ STYLELOCKBACKCOMP,
+ STYLELOCKENFORCED,
+ STYLELOCKQFSET,
+ STYLELOCKTHEME,
+ STYLESHEET,
+ STYLESORTMETHOD,
+ STYRSID,
+ SUB,
+ SUBDOCUMENT,
+ SUBFONTBYSIZE,
+ SUBJECT,
+ SUNHIDEUSED,
+ SUPER,
+ SV,
+ SVB,
+ SWPBDR,
+ TAB,
+ TABSNOOVRLP,
+ TAPRTL,
+ TB,
+ TBLIND,
+ TBLINDTYPE,
+ TBLLKBESTFIT,
+ TBLLKBORDER,
+ TBLLKCOLOR,
+ TBLLKFONT,
+ TBLLKHDRCOLS,
+ TBLLKHDRROWS,
+ TBLLKLASTCOL,
+ TBLLKLASTROW,
+ TBLLKNOCOLBAND,
+ TBLLKNOROWBAND,
+ TBLLKSHADING,
+ TBLRSID,
+ TC,
+ TCELLD,
+ TCF,
+ TCL,
+ TCN,
+ TDFRMTXTBOTTOM,
+ TDFRMTXTLEFT,
+ TDFRMTXTRIGHT,
+ TDFRMTXTTOP,
+ TEMPLATE,
+ THEMEDATA,
+ THEMELANG,
+ THEMELANGCS,
+ THEMELANGFE,
+ TIME,
+ TITLE,
+ TITLEPG,
+ TLDOT,
+ TLEQ,
+ TLHYPH,
+ TLMDOT,
+ TLTH,
+ TLUL,
+ TOPLINEPUNCT,
+ TPHCOL,
+ TPHMRG,
+ TPHPG,
+ TPOSNEGX,
+ TPOSNEGY,
+ TPOSXC,
+ TPOSXI,
+ TPOSXL,
+ TPOSX,
+ TPOSXO,
+ TPOSXR,
+ TPOSY,
+ TPOSYB,
+ TPOSYC,
+ TPOSYIL,
+ TPOSYIN,
+ TPOSYOUT,
+ TPOSYT,
+ TPVMRG,
+ TPVPARA,
+ TPVPG,
+ TQC,
+ TQDEC,
+ TQR,
+ TRACKFORMATTING,
+ TRACKMOVES,
+ TRANSMF,
+ TRAUTH,
+ TRAUTOFIT,
+ TRBGBDIAG,
+ TRBGCROSS,
+ TRBGDCROSS,
+ TRBGDKBDIAG,
+ TRBGDKCROSS,
+ TRBGDKDCROSS,
+ TRBGDKFDIAG,
+ TRBGDKHOR,
+ TRBGDKVERT,
+ TRBGFDIAG,
+ TRBGHORIZ,
+ TRBGVERT,
+ TRBRDRB,
+ TRBRDRH,
+ TRBRDRL,
+ TRBRDRR,
+ TRBRDRT,
+ TRBRDRV,
+ TRCBPAT,
+ TRCFPAT,
+ TRDATE,
+ TRFTSWIDTHA,
+ TRFTSWIDTHB,
+ TRFTSWIDTH,
+ TRGAPH,
+ TRHDR,
+ TRKEEP,
+ TRKEEPFOLLOW,
+ TRLEFT,
+ TROWD,
+ TRPADDB,
+ TRPADDFB,
+ TRPADDFL,
+ TRPADDFR,
+ TRPADDFT,
+ TRPADDL,
+ TRPADDR,
+ TRPADDT,
+ TRPADOB,
+ TRPADOFB,
+ TRPADOFL,
+ TRPADOFR,
+ TRPADOFT,
+ TRPADOL,
+ TRPADOR,
+ TRPADOT,
+ TRPAT,
+ TRQC,
+ TRQL,
+ TRQR,
+ TRRH,
+ TRSHDNG,
+ TRSPDB,
+ TRSPDFB,
+ TRSPDFL,
+ TRSPDFR,
+ TRSPDFT,
+ TRSPDL,
+ TRSPDR,
+ TRSPDT,
+ TRSPOB,
+ TRSPOFB,
+ TRSPOFL,
+ TRSPOFR,
+ TRSPOFT,
+ TRSPOL,
+ TRSPOR,
+ TRSPOT,
+ TRUNCATEFONTHEIGHT,
+ TRUNCEX,
+ TRWWIDTHA,
+ TRWWIDTHB,
+ TRWWIDTH,
+ TS,
+ TSBGBDIAG,
+ TSBGCROSS,
+ TSBGDCROSS,
+ TSBGDKBDIAG,
+ TSBGDKCROSS,
+ TSBGDKDCROSS,
+ TSBGDKFDIAG,
+ TSBGDKHOR,
+ TSBGDKVERT,
+ TSBGFDIAG,
+ TSBGHORIZ,
+ TSBGVERT,
+ TSBRDRB,
+ TSBRDRDGL,
+ TSBRDRDGR,
+ TSBRDRH,
+ TSBRDRL,
+ TSBRDRR,
+ TSBRDRT,
+ TSBRDRV,
+ TSCBANDHORZEVEN,
+ TSCBANDHORZODD,
+ TSCBANDSH,
+ TSCBANDSV,
+ TSCBANDVERTEVEN,
+ TSCBANDVERTODD,
+ TSCELLCBPAT,
+ TSCELLCFPAT,
+ TSCELLPADDB,
+ TSCELLPADDFB,
+ TSCELLPADDFL,
+ TSCELLPADDFR,
+ TSCELLPADDFT,
+ TSCELLPADDL,
+ TSCELLPADDR,
+ TSCELLPADDT,
+ TSCELLPCT,
+ TSCELLWIDTH,
+ TSCELLWIDTHFTS,
+ TSCFIRSTCOL,
+ TSCFIRSTROW,
+ TSCLASTCOL,
+ TSCLASTROW,
+ TSCNECELL,
+ TSCNWCELL,
+ TSCSECELL,
+ TSCSWCELL,
+ TSD,
+ TSNOWRAP,
+ TSROWD,
+ TSVERTALB,
+ TSVERTALC,
+ TSVERTALT,
+ TWOINONE,
+ TWOONONE,
+ TX,
+ TXBXTWALWAYS,
+ TXBXTWFIRST,
+ TXBXTWFIRSTLAST,
+ TXBXTWLAST,
+ TXBXTWNO,
+ TXE,
+ U,
+ UC,
+ UD,
+ UL,
+ ULC,
+ ULD,
+ ULDASH,
+ ULDASHD,
+ ULDASHDD,
+ ULDB,
+ ULHAIR,
+ ULHWAVE,
+ ULLDASH,
+ ULNONE,
+ ULTH,
+ ULTHD,
+ ULTHDASH,
+ ULTHDASHD,
+ ULTHDASHDD,
+ ULTHLDASH,
+ ULULDBWAVE,
+ ULW,
+ ULWAVE,
+ UP,
+ UPR,
+ URTF,
+ USELTBALN,
+ USENORMSTYFORLIST,
+ USERPROPS,
+ USEXFORM,
+ UTINL,
+ V,
+ VALIDATEXML,
+ VERN,
+ VERSION,
+ VERTAL,
+ VERTALB,
+ VERTALC,
+ VERTALJ,
+ VERTALT,
+ VERTDOC,
+ VERTSECT,
+ VIEWBKSP,
+ VIEWKIND,
+ VIEWNOBOUND,
+ VIEWSCALE,
+ VIEWZK,
+ WBITMAP,
+ WBMBITSPIXEL,
+ WBMPLANES,
+ WBMWIDTHBYTE,
+ WEBHIDDEN,
+ WGRFFMTFILTER,
+ WIDCTLPAR,
+ WIDOWCTRL,
+ WINDOWCAPTION,
+ WMETAFILE,
+ WPEQN,
+ WPJST,
+ WPSP,
+ WRAPAROUND,
+ WRAPDEFAULT,
+ WRAPTHROUGH,
+ WRAPTIGHT,
+ WRAPTRSP,
+ WRITERESERVATION,
+ WRITERESERVHASH,
+ WRPPUNCT,
+ XE,
+ XEF,
+ XFORM,
+ XMLATTR,
+ XMLATTRNAME,
+ XMLATTRNS,
+ XMLATTRVALUE,
+ XMLCLOSE,
+ XMLNAME,
+ XMLNS,
+ XMLNSTBL,
+ XMLOPEN,
+ XMLSDTTCELL,
+ XMLSDTTPARA,
+ XMLSDTTREGULAR,
+ XMLSDTTROW,
+ XMLSDTTUNKNOWN,
+ YR,
+ YTS,
+ YXE,
+ ZWBO,
+ ZWJ,
+ ZWNBO,
+ ZWNJ,
+ FLYMAINCNT,
+ FLYVERT,
+ FLYHORZ,
+ FLYANCHOR
+};
+const char* keywordToString(RTFKeyword nKeyword);
+
+/// Types of an RTF Control Word
+enum class RTFControlType
+{
+ FLAG, // eg \sbknone takes no parameter
+ DESTINATION, // eg \fonttbl, if ignored, the whole group should be skipped
+ SYMBOL, // eg \tab
+ TOGGLE, // eg \b (between on and off)
+ VALUE // eg \fs (requires parameter)
+};
+
+/// Represents an RTF Control Word
+class RTFSymbol
+{
+ const char* m_sKeyword;
+ RTFControlType m_eControlType;
+ RTFKeyword m_nIndex;
+
+ int m_nDefValue; ///< Most of the control words default to 0.
+
+public:
+ RTFSymbol(const char* sKeyword, RTFControlType nControlType, RTFKeyword nIndex, int nDefValue)
+ : m_sKeyword(sKeyword)
+ , m_eControlType(nControlType)
+ , m_nIndex(nIndex)
+ , m_nDefValue(nDefValue)
+ {
+ }
+
+ const char* GetKeyword() const { return m_sKeyword; }
+
+ RTFControlType GetControlType() const { return m_eControlType; }
+
+ RTFKeyword GetIndex() const { return m_nIndex; }
+
+ int GetDefValue() const { return m_nDefValue; }
+};
+
+extern RTFSymbol const aRTFControlWords[];
+extern const int nRTFControlWords;
+
+/// Represents an RTF Math Control Word
+class RTFMathSymbol
+{
+ RTFKeyword m_eKeyword;
+ int m_nToken; ///< This is the OOXML token equivalent.
+ Destination m_eDestination;
+
+public:
+ RTFMathSymbol(RTFKeyword eKeyword, int nToken = 0,
+ Destination eDestination = Destination::NORMAL)
+ : m_eKeyword(eKeyword)
+ , m_nToken(nToken)
+ , m_eDestination(eDestination)
+ {
+ }
+
+ int GetToken() const { return m_nToken; }
+
+ Destination GetDestination() const { return m_eDestination; }
+
+ bool operator<(const RTFMathSymbol& rOther) const;
+};
+
+extern RTFMathSymbol const aRTFMathControlWords[];
+extern const int nRTFMathControlWords;
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfdispatchdestination.cxx b/sw/source/writerfilter/rtftok/rtfdispatchdestination.cxx
new file mode 100644
index 000000000000..8789c3f858a8
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfdispatchdestination.cxx
@@ -0,0 +1,684 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/document/DocumentProperties.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <filter/msfilter/escherex.hxx>
+#include <rtl/character.hxx>
+#include <tools/stream.hxx>
+#include <sal/log.hxx>
+
+#include <dmapper/DomainMapperFactory.hxx>
+#include <ooxml/resourceids.hxx>
+
+#include "rtflookahead.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfsdrimport.hxx"
+#include "rtfskipdestination.hxx"
+#include "rtftokenizer.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchDestination(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ // special case \upr: ignore everything except nested \ud
+ if (Destination::UPR == m_aStates.top().getDestination() && RTFKeyword::UD != nKeyword)
+ {
+ m_aStates.top().setDestination(Destination::SKIP);
+ aSkip.setParsed(false);
+ }
+ else
+ switch (nKeyword)
+ {
+ case RTFKeyword::RTF:
+ break;
+ case RTFKeyword::FONTTBL:
+ m_aStates.top().setDestination(Destination::FONTTABLE);
+ break;
+ case RTFKeyword::COLORTBL:
+ m_aStates.top().setDestination(Destination::COLORTABLE);
+ break;
+ case RTFKeyword::STYLESHEET:
+ m_aStates.top().setDestination(Destination::STYLESHEET);
+ break;
+ case RTFKeyword::FIELD:
+ m_aStates.top().setDestination(Destination::FIELD);
+ m_aStates.top().setFieldLocked(false);
+ break;
+ case RTFKeyword::DOCVAR:
+ m_aStates.top().setDestination(Destination::DOCVAR);
+ break;
+ case RTFKeyword::FLDINST:
+ {
+ // Look for the field type
+ sal_uInt64 const nPos = Strm().Tell();
+ OStringBuffer aBuf;
+ char ch = 0;
+ bool bFoundCode = false;
+ bool bInKeyword = false;
+ while (!bFoundCode && ch != '}')
+ {
+ Strm().ReadChar(ch);
+ if ('\\' == ch)
+ bInKeyword = true;
+ if (!bInKeyword && rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
+ aBuf.append(ch);
+ else if (bInKeyword && rtl::isAsciiWhiteSpace(static_cast<unsigned char>(ch)))
+ bInKeyword = false;
+ if (!aBuf.isEmpty()
+ && !rtl::isAsciiAlphanumeric(static_cast<unsigned char>(ch)))
+ bFoundCode = true;
+ }
+
+ if (std::string_view(aBuf) == "INCLUDEPICTURE")
+ {
+ // Extract the field argument of INCLUDEPICTURE: we handle that
+ // at a tokenizer level, as DOCX has no such field.
+ aBuf.append(ch);
+ while (true)
+ {
+ Strm().ReadChar(ch);
+ if (ch == '}')
+ break;
+ aBuf.append(ch);
+ }
+ OUString aFieldCommand = OStringToOUString(aBuf, RTL_TEXTENCODING_UTF8);
+ std::tuple<OUString, std::vector<OUString>, std::vector<OUString>> aResult
+ = writerfilter::dmapper::splitFieldCommand(aFieldCommand);
+ m_aPicturePath
+ = std::get<1>(aResult).empty() ? OUString() : std::get<1>(aResult).front();
+ }
+
+ Strm().Seek(nPos);
+
+ // Form data should be handled only for form fields if any
+ if (aBuf.toString().indexOf("FORM") != -1)
+ m_bFormField = true;
+
+ singleChar(cFieldStart);
+ m_aStates.top().setDestination(Destination::FIELDINSTRUCTION);
+ }
+ break;
+ case RTFKeyword::FLDRSLT:
+ m_aStates.top().setDestination(Destination::FIELDRESULT);
+ break;
+ case RTFKeyword::LISTTABLE:
+ m_aStates.top().setDestination(Destination::LISTTABLE);
+ break;
+ case RTFKeyword::LISTPICTURE:
+ m_aStates.top().setDestination(Destination::LISTPICTURE);
+ m_aStates.top().setInListpicture(true);
+ break;
+ case RTFKeyword::LIST:
+ m_aStates.top().setDestination(Destination::LISTENTRY);
+ break;
+ case RTFKeyword::LISTNAME:
+ m_aStates.top().setDestination(Destination::LISTNAME);
+ break;
+ case RTFKeyword::LFOLEVEL:
+ m_aStates.top().setDestination(Destination::LFOLEVEL);
+ m_aStates.top().getTableSprms().clear();
+ break;
+ case RTFKeyword::LISTOVERRIDETABLE:
+ m_aStates.top().setDestination(Destination::LISTOVERRIDETABLE);
+ break;
+ case RTFKeyword::LISTOVERRIDE:
+ m_aStates.top().setDestination(Destination::LISTOVERRIDEENTRY);
+ break;
+ case RTFKeyword::LISTLEVEL:
+ m_aStates.top().setDestination(Destination::LISTLEVEL);
+ ++m_nListLevel;
+ break;
+ case RTFKeyword::LEVELTEXT:
+ m_aStates.top().setDestination(Destination::LEVELTEXT);
+ break;
+ case RTFKeyword::LEVELNUMBERS:
+ m_aStates.top().setDestination(Destination::LEVELNUMBERS);
+ break;
+ case RTFKeyword::SHPPICT:
+ resetFrame();
+ m_aStates.top().setDestination(Destination::SHPPICT);
+ break;
+ case RTFKeyword::PICT:
+ if (m_aStates.top().getDestination() != Destination::SHAPEPROPERTYVALUE)
+ m_aStates.top().setDestination(Destination::PICT); // as character
+ else
+ m_aStates.top().setDestination(
+ Destination::SHAPEPROPERTYVALUEPICT); // anchored inside a shape
+ break;
+ case RTFKeyword::PICPROP:
+ m_aStates.top().setDestination(Destination::PICPROP);
+ break;
+ case RTFKeyword::SP:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTY);
+ break;
+ case RTFKeyword::SN:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTYNAME);
+ break;
+ case RTFKeyword::SV:
+ m_aStates.top().setDestination(Destination::SHAPEPROPERTYVALUE);
+ break;
+ case RTFKeyword::SHP:
+ m_bNeedCrOrig = m_bNeedCr;
+ m_aStates.top().setDestination(Destination::SHAPE);
+ m_aStates.top().setInShape(true);
+ break;
+ case RTFKeyword::SHPINST:
+ m_aStates.top().setDestination(Destination::SHAPEINSTRUCTION);
+ break;
+ case RTFKeyword::NESTTABLEPROPS:
+ // do not set any properties of outer table at nested table!
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+ m_aNestedTableCellsSprms.clear();
+ m_aNestedTableCellsAttributes.clear();
+ m_nNestedCells = 0;
+ m_aStates.top().setDestination(Destination::NESTEDTABLEPROPERTIES);
+ break;
+ case RTFKeyword::HEADER:
+ case RTFKeyword::FOOTER:
+ case RTFKeyword::HEADERL:
+ case RTFKeyword::HEADERR:
+ case RTFKeyword::HEADERF:
+ case RTFKeyword::FOOTERL:
+ case RTFKeyword::FOOTERR:
+ case RTFKeyword::FOOTERF:
+ if (!m_pSuperstream)
+ {
+ Id nId = 0;
+ std::size_t nPos = m_nGroupStartPos - 1;
+ switch (nKeyword)
+ {
+ case RTFKeyword::HEADER:
+ if (!m_hasRHeader)
+ {
+ nId = NS_ooxml::LN_headerr;
+ m_hasRHeader = true;
+ }
+ break;
+ case RTFKeyword::FOOTER:
+ if (!m_hasRFooter)
+ {
+ nId = NS_ooxml::LN_footerr;
+ m_hasRFooter = true;
+ }
+ break;
+ case RTFKeyword::HEADERL:
+ nId = NS_ooxml::LN_headerl;
+ break;
+ case RTFKeyword::HEADERR:
+ nId = NS_ooxml::LN_headerr;
+ break;
+ case RTFKeyword::HEADERF:
+ if (!m_hasFHeader)
+ {
+ nId = NS_ooxml::LN_headerf;
+ m_hasFHeader = true;
+ }
+ break;
+ case RTFKeyword::FOOTERL:
+ nId = NS_ooxml::LN_footerl;
+ break;
+ case RTFKeyword::FOOTERR:
+ nId = NS_ooxml::LN_footerr;
+ break;
+ case RTFKeyword::FOOTERF:
+ if (!m_hasFFooter)
+ {
+ nId = NS_ooxml::LN_footerf;
+ m_hasFFooter = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nId != 0)
+ m_nHeaderFooterPositions.push(std::make_pair(nId, nPos));
+
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ break;
+ case RTFKeyword::FOOTNOTE:
+ checkFirstRun();
+ if (!m_pSuperstream)
+ {
+ Id nId = NS_ooxml::LN_footnote;
+
+ // Check if this is an endnote.
+ OStringBuffer aBuf;
+ char ch;
+ sal_uInt64 const nCurrent = Strm().Tell();
+ for (int i = 0; i < 7; ++i)
+ {
+ Strm().ReadChar(ch);
+ aBuf.append(ch);
+ }
+ Strm().Seek(nCurrent);
+ OString aKeyword = aBuf.makeStringAndClear();
+ if (aKeyword == "\\ftnalt")
+ nId = NS_ooxml::LN_endnote;
+
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ m_aStates.top().setCurrentBuffer(nullptr);
+ bool bCustomMark = false;
+ OUString aCustomMark;
+ for (auto const& elem : m_aSuperBuffer)
+ {
+ if (std::get<0>(elem) == BUFFER_UTEXT)
+ {
+ aCustomMark = std::get<1>(elem)->getString();
+ bCustomMark = true;
+ }
+ }
+ m_aSuperBuffer.clear();
+ m_aStates.top().setDestination(Destination::FOOTNOTE);
+ Mapper().startCharacterGroup();
+ runProps();
+ if (!m_aStates.top().getCurrentBuffer())
+ resolveSubstream(m_nGroupStartPos - 1, nId, aCustomMark);
+ else
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
+ aAttributes.set(Id(1), new RTFValue(nId));
+ aAttributes.set(Id(2), new RTFValue(aCustomMark));
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
+ }
+ if (bCustomMark)
+ {
+ m_aStates.top().getCharacterAttributes().clear();
+ m_aStates.top().getCharacterSprms().clear();
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_FtnEdnRef_customMarkFollows, pValue);
+ text(aCustomMark);
+ }
+ Mapper().endCharacterGroup();
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ break;
+ case RTFKeyword::BKMKSTART:
+ m_aStates.top().setDestination(Destination::BOOKMARKSTART);
+ break;
+ case RTFKeyword::BKMKEND:
+ m_aStates.top().setDestination(Destination::BOOKMARKEND);
+ break;
+ case RTFKeyword::XE:
+ m_aStates.top().setDestination(Destination::INDEXENTRY);
+ break;
+ case RTFKeyword::TC:
+ case RTFKeyword::TCN:
+ m_aStates.top().setDestination(Destination::TOCENTRY);
+ break;
+ case RTFKeyword::REVTBL:
+ m_aStates.top().setDestination(Destination::REVISIONTABLE);
+ break;
+ case RTFKeyword::ANNOTATION:
+ if (!m_pSuperstream)
+ {
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ resolveSubstream(m_nGroupStartPos - 1, NS_ooxml::LN_annotation);
+ }
+ else
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(Id(0), new RTFValue(m_nGroupStartPos - 1));
+ aAttributes.set(Id(1), new RTFValue(NS_ooxml::LN_annotation));
+ aAttributes.set(Id(2), new RTFValue(OUString()));
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_RESOLVESUBSTREAM, new RTFValue(aAttributes), nullptr));
+ }
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ else
+ {
+ // If there is an author set, emit it now.
+ if (!m_aAuthor.isEmpty() || !m_aAuthorInitials.isEmpty())
+ {
+ RTFSprms aAttributes;
+ if (!m_aAuthor.isEmpty())
+ {
+ auto pValue = new RTFValue(m_aAuthor);
+ aAttributes.set(NS_ooxml::LN_CT_TrackChange_author, pValue);
+ }
+ if (!m_aAuthorInitials.isEmpty())
+ {
+ auto pValue = new RTFValue(m_aAuthorInitials);
+ aAttributes.set(NS_ooxml::LN_CT_Comment_initials, pValue);
+ }
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes));
+ Mapper().props(pProperties);
+ }
+ }
+ break;
+ case RTFKeyword::SHPTXT:
+ case RTFKeyword::DPTXBXTEXT:
+ {
+ bool bPictureFrame = false;
+ for (const auto& rProperty : m_aStates.top().getShape().getProperties())
+ {
+ if (rProperty.first == "shapeType"
+ && rProperty.second
+ == std::u16string_view(
+ OUString::number(ESCHER_ShpInst_PictureFrame)))
+ {
+ bPictureFrame = true;
+ break;
+ }
+ }
+ if (bPictureFrame)
+ // Skip text on picture frames.
+ m_aStates.top().setDestination(Destination::SKIP);
+ else
+ {
+ m_aStates.top().setDestination(Destination::SHAPETEXT);
+ checkFirstRun();
+ dispatchFlag(RTFKeyword::PARD);
+ m_bNeedPap = true;
+ if (nKeyword == RTFKeyword::SHPTXT)
+ {
+ if (!m_aStates.top().getCurrentBuffer())
+ m_pSdrImport->resolve(m_aStates.top().getShape(), false,
+ RTFSdrImport::SHAPE);
+ else
+ {
+ auto pValue = new RTFValue(m_aStates.top().getShape());
+ m_aStates.top().getCurrentBuffer()->push_back(
+ Buf_t(BUFFER_STARTSHAPE, pValue, nullptr));
+ }
+ }
+ }
+ }
+ break;
+ case RTFKeyword::FORMFIELD:
+ if (m_aStates.top().getDestination() == Destination::FIELDINSTRUCTION)
+ m_aStates.top().setDestination(Destination::FORMFIELD);
+ break;
+ case RTFKeyword::FFNAME:
+ m_aStates.top().setDestination(Destination::FORMFIELDNAME);
+ break;
+ case RTFKeyword::FFL:
+ m_aStates.top().setDestination(Destination::FORMFIELDLIST);
+ break;
+ case RTFKeyword::DATAFIELD:
+ m_aStates.top().setDestination(Destination::DATAFIELD);
+ break;
+ case RTFKeyword::INFO:
+ m_aStates.top().setDestination(Destination::INFO);
+ break;
+ case RTFKeyword::CREATIM:
+ m_aStates.top().setDestination(Destination::CREATIONTIME);
+ break;
+ case RTFKeyword::REVTIM:
+ m_aStates.top().setDestination(Destination::REVISIONTIME);
+ break;
+ case RTFKeyword::PRINTIM:
+ m_aStates.top().setDestination(Destination::PRINTTIME);
+ break;
+ case RTFKeyword::AUTHOR:
+ m_aStates.top().setDestination(Destination::AUTHOR);
+ break;
+ case RTFKeyword::KEYWORDS:
+ m_aStates.top().setDestination(Destination::KEYWORDS);
+ break;
+ case RTFKeyword::OPERATOR:
+ m_aStates.top().setDestination(Destination::OPERATOR);
+ break;
+ case RTFKeyword::COMPANY:
+ m_aStates.top().setDestination(Destination::COMPANY);
+ break;
+ case RTFKeyword::COMMENT:
+ m_aStates.top().setDestination(Destination::COMMENT);
+ break;
+ case RTFKeyword::OBJECT:
+ {
+ // beginning of an OLE Object
+ m_aStates.top().setDestination(Destination::OBJECT);
+
+ // check if the object is in a special container (e.g. a table)
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ // the object is in a table or another container.
+ // Don't try to treat it as an OLE object (fdo#53594).
+ // Use the \result (RTFKeyword::RESULT) element of the object instead,
+ // the result element contain picture representing the OLE Object.
+ m_bObject = true;
+ }
+ }
+ break;
+ case RTFKeyword::OBJDATA:
+ // check if the object is in a special container (e.g. a table)
+ if (m_aStates.top().getCurrentBuffer())
+ {
+ // the object is in a table or another container.
+ // Use the \result (RTFKeyword::RESULT) element of the object instead,
+ // of the \objdata.
+ m_aStates.top().setDestination(Destination::SKIP);
+ }
+ else
+ {
+ m_aStates.top().setDestination(Destination::OBJDATA);
+ }
+ break;
+ case RTFKeyword::OBJCLASS:
+ m_aStates.top().setDestination(Destination::OBJCLASS);
+ break;
+ case RTFKeyword::RESULT:
+ m_aStates.top().setDestination(Destination::RESULT);
+ break;
+ case RTFKeyword::ATNDATE:
+ m_aStates.top().setDestination(Destination::ANNOTATIONDATE);
+ break;
+ case RTFKeyword::ATNAUTHOR:
+ m_aStates.top().setDestination(Destination::ANNOTATIONAUTHOR);
+ break;
+ case RTFKeyword::ATNREF:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCE);
+ break;
+ case RTFKeyword::FALT:
+ m_aStates.top().setDestination(Destination::FALT);
+ break;
+ case RTFKeyword::FLYMAINCNT:
+ m_aStates.top().setDestination(Destination::FLYMAINCONTENT);
+ break;
+ case RTFKeyword::LISTTEXT:
+ // Should be ignored by any reader that understands Word 97 through Word 2007 numbering.
+ case RTFKeyword::NONESTTABLES:
+ // This destination should be ignored by readers that support nested tables.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::DO:
+ m_aStates.top().setDestination(Destination::DRAWINGOBJECT);
+ break;
+ case RTFKeyword::PN:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING);
+ break;
+ case RTFKeyword::PNTEXT:
+ // This destination should be ignored by readers that support paragraph numbering.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::PNTXTA:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTAFTER);
+ break;
+ case RTFKeyword::PNTXTB:
+ m_aStates.top().setDestination(Destination::PARAGRAPHNUMBERING_TEXTBEFORE);
+ break;
+ case RTFKeyword::TITLE:
+ m_aStates.top().setDestination(Destination::TITLE);
+ break;
+ case RTFKeyword::SUBJECT:
+ m_aStates.top().setDestination(Destination::SUBJECT);
+ break;
+ case RTFKeyword::DOCCOMM:
+ m_aStates.top().setDestination(Destination::DOCCOMM);
+ break;
+ case RTFKeyword::ATRFSTART:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCESTART);
+ break;
+ case RTFKeyword::ATRFEND:
+ m_aStates.top().setDestination(Destination::ANNOTATIONREFERENCEEND);
+ break;
+ case RTFKeyword::ATNID:
+ m_aStates.top().setDestination(Destination::ATNID);
+ break;
+ case RTFKeyword::MMATH:
+ case RTFKeyword::MOMATHPARA:
+ // Nothing to do here (just enter the destination) till RTFKeyword::MMATHPR is implemented.
+ break;
+ case RTFKeyword::MR:
+ m_aStates.top().setDestination(Destination::MR);
+ break;
+ case RTFKeyword::MCHR:
+ m_aStates.top().setDestination(Destination::MCHR);
+ break;
+ case RTFKeyword::MPOS:
+ m_aStates.top().setDestination(Destination::MPOS);
+ break;
+ case RTFKeyword::MVERTJC:
+ m_aStates.top().setDestination(Destination::MVERTJC);
+ break;
+ case RTFKeyword::MSTRIKEH:
+ m_aStates.top().setDestination(Destination::MSTRIKEH);
+ break;
+ case RTFKeyword::MDEGHIDE:
+ m_aStates.top().setDestination(Destination::MDEGHIDE);
+ break;
+ case RTFKeyword::MTYPE:
+ m_aStates.top().setDestination(Destination::MTYPE);
+ break;
+ case RTFKeyword::MGROW:
+ m_aStates.top().setDestination(Destination::MGROW);
+ break;
+ case RTFKeyword::MHIDETOP:
+ case RTFKeyword::MHIDEBOT:
+ case RTFKeyword::MHIDELEFT:
+ case RTFKeyword::MHIDERIGHT:
+ // SmOoxmlImport::handleBorderBox will ignore these anyway, so silently ignore for now.
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::MSUBHIDE:
+ m_aStates.top().setDestination(Destination::MSUBHIDE);
+ break;
+ case RTFKeyword::MSUPHIDE:
+ m_aStates.top().setDestination(Destination::MSUPHIDE);
+ break;
+ case RTFKeyword::MBEGCHR:
+ m_aStates.top().setDestination(Destination::MBEGCHR);
+ break;
+ case RTFKeyword::MSEPCHR:
+ m_aStates.top().setDestination(Destination::MSEPCHR);
+ break;
+ case RTFKeyword::MENDCHR:
+ m_aStates.top().setDestination(Destination::MENDCHR);
+ break;
+ case RTFKeyword::UPR:
+ m_aStates.top().setDestination(Destination::UPR);
+ break;
+ case RTFKeyword::UD:
+ // Anything inside \ud is just normal Unicode content.
+ m_aStates.top().setDestination(Destination::NORMAL);
+ break;
+ case RTFKeyword::BACKGROUND:
+ m_aStates.top().setDestination(Destination::BACKGROUND);
+ m_aStates.top().setInBackground(true);
+ break;
+ case RTFKeyword::SHPGRP:
+ {
+ RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
+ if (!aLookahead.hasTable())
+ {
+ uno::Reference<drawing::XShapes> xGroupShape(
+ m_xModelFactory->createInstance("com.sun.star.drawing.GroupShape"),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc,
+ uno::UNO_QUERY);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShape> xShape(xGroupShape, uno::UNO_QUERY);
+ // set default VertOrient before inserting
+ uno::Reference<beans::XPropertySet>(xShape, uno::UNO_QUERY_THROW)
+ ->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
+ xDrawSupplier->getDrawPage()->add(xShape);
+ }
+ m_pSdrImport->pushParent(xGroupShape);
+ m_aStates.top().setCreatedShapeGroup(true);
+ }
+ m_aStates.top().setDestination(Destination::SHAPEGROUP);
+ m_aStates.top().setInShapeGroup(true);
+ }
+ break;
+ case RTFKeyword::FTNSEP:
+ m_aStates.top().setDestination(Destination::FOOTNOTESEPARATOR);
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_FtnEdn_type,
+ new RTFValue(NS_ooxml::LN_Value_doc_ST_FtnEdn_separator));
+ break;
+ case RTFKeyword::USERPROPS:
+ // Container of all user-defined properties.
+ m_aStates.top().setDestination(Destination::USERPROPS);
+ if (m_xDocumentProperties.is())
+ // Create a custom document properties to be able to process them later all at once.
+ m_xDocumentProperties = document::DocumentProperties::create(m_xContext);
+ break;
+ case RTFKeyword::PROPNAME:
+ m_aStates.top().setDestination(Destination::PROPNAME);
+ break;
+ case RTFKeyword::STATICVAL:
+ m_aStates.top().setDestination(Destination::STATICVAL);
+ break;
+ case RTFKeyword::GENERATOR:
+ m_aStates.top().setDestination(Destination::GENERATOR);
+ break;
+ default:
+ {
+ // Check if it's a math token.
+ RTFMathSymbol aSymbol(nKeyword);
+ if (RTFTokenizer::lookupMathKeyword(aSymbol))
+ {
+ m_aMathBuffer.appendOpeningTag(aSymbol.GetToken());
+ m_aStates.top().setDestination(aSymbol.GetDestination());
+ return RTFError::OK;
+ }
+
+ SAL_INFO("writerfilter",
+ "TODO handle destination '" << keywordToString(nKeyword) << "'");
+ // Make sure we skip destinations (even without \*) till we don't handle them
+ m_aStates.top().setDestination(Destination::SKIP);
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+
+ // new destination => use new destination text
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+
+ return RTFError::OK;
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx b/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx
new file mode 100644
index 000000000000..753f1c3fbba9
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfdispatchflag.cxx
@@ -0,0 +1,1381 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <filter/msfilter/escherex.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+#include "rtfsdrimport.hxx"
+#include "rtfskipdestination.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+bool RTFDocumentImpl::dispatchFloatingTableFlag(RTFKeyword nKeyword)
+{
+ // Positioned Wrapped Tables
+ OUString aParam;
+ switch (nKeyword)
+ {
+ case RTFKeyword::TPVPARA:
+ aParam = "text";
+ break;
+ case RTFKeyword::TPVMRG:
+ aParam = "margin";
+ break;
+ case RTFKeyword::TPVPG:
+ aParam = "page";
+ break;
+ default:
+ break;
+ }
+ if (!aParam.isEmpty())
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_vertAnchor, new RTFValue(aParam));
+ return true;
+ }
+ switch (nKeyword)
+ {
+ case RTFKeyword::TPHCOL:
+ aParam = "text";
+ break;
+ case RTFKeyword::TPHMRG:
+ aParam = "margin";
+ break;
+ case RTFKeyword::TPHPG:
+ aParam = "page";
+ break;
+ default:
+ break;
+ }
+ if (!aParam.isEmpty())
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_horzAnchor, new RTFValue(aParam));
+ return true;
+ }
+ switch (nKeyword)
+ {
+ case RTFKeyword::TPOSYC:
+ aParam = "center";
+ break;
+ case RTFKeyword::TPOSYB:
+ aParam = "bottom";
+ break;
+ default:
+ break;
+ }
+ if (!aParam.isEmpty())
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_tblpYSpec, new RTFValue(aParam));
+ return true;
+ }
+ switch (nKeyword)
+ {
+ case RTFKeyword::TPOSXC:
+ aParam = "center";
+ break;
+ case RTFKeyword::TPOSXR:
+ aParam = "right";
+ break;
+ default:
+ break;
+ }
+ if (!aParam.isEmpty())
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_tblpXSpec, new RTFValue(aParam));
+ return true;
+ }
+
+ if (nKeyword == RTFKeyword::TABSNOOVRLP)
+ {
+ m_aStates.top().getTableRowSprms().set(
+ NS_ooxml::LN_CT_TblPrBase_tblOverlap,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblOverlap_never));
+ return true;
+ }
+
+ return false;
+}
+
+RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nParam = -1;
+ int nSprm = -1;
+
+ // Underline flags.
+ switch (nKeyword)
+ {
+ case RTFKeyword::ULD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotted;
+ break;
+ case RTFKeyword::ULW:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_words;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue = new RTFValue(nSprm);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Indentation
+ switch (nKeyword)
+ {
+ case RTFKeyword::QC:
+ nParam = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case RTFKeyword::QJ:
+ nParam = NS_ooxml::LN_Value_ST_Jc_both;
+ break;
+ case RTFKeyword::QL:
+ nParam = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case RTFKeyword::QR:
+ nParam = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ case RTFKeyword::QD:
+ nParam = NS_ooxml::LN_Value_ST_Jc_distribute;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_jc, pValue);
+ m_bNeedPap = true;
+ return RTFError::OK;
+ }
+
+ // Font Alignment
+ switch (nKeyword)
+ {
+ case RTFKeyword::FAFIXED:
+ case RTFKeyword::FAAUTO:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_auto;
+ break;
+ case RTFKeyword::FAHANG:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_top;
+ break;
+ case RTFKeyword::FACENTER:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_center;
+ break;
+ case RTFKeyword::FAROMAN:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_baseline;
+ break;
+ case RTFKeyword::FAVAR:
+ nParam = NS_ooxml::LN_Value_doc_ST_TextAlignment_bottom;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_textAlignment, pValue);
+ return RTFError::OK;
+ }
+
+ // Tab kind.
+ switch (nKeyword)
+ {
+ case RTFKeyword::TQR:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_right;
+ break;
+ case RTFKeyword::TQC:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_center;
+ break;
+ case RTFKeyword::TQDEC:
+ nParam = NS_ooxml::LN_Value_ST_TabJc_decimal;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Tab lead.
+ switch (nKeyword)
+ {
+ case RTFKeyword::TLDOT:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_dot;
+ break;
+ case RTFKeyword::TLMDOT:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_middleDot;
+ break;
+ case RTFKeyword::TLHYPH:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_hyphen;
+ break;
+ case RTFKeyword::TLUL:
+ case RTFKeyword::TLTH:
+ nParam = NS_ooxml::LN_Value_ST_TabTlc_underscore;
+ break;
+ case RTFKeyword::TLEQ:
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_leader, pValue);
+ return RTFError::OK;
+ }
+
+ // Border types
+ {
+ switch (nKeyword)
+ {
+ // brdrhair and brdrs are the same, brdrw will make a difference
+ // map to values in ooxml/model.xml resource ST_Border
+ case RTFKeyword::BRDRHAIR:
+ case RTFKeyword::BRDRS:
+ nParam = NS_ooxml::LN_Value_ST_Border_single;
+ break;
+ case RTFKeyword::BRDRDOT:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotted;
+ break;
+ case RTFKeyword::BRDRDASH:
+ nParam = NS_ooxml::LN_Value_ST_Border_dashed;
+ break;
+ case RTFKeyword::BRDRDB:
+ nParam = NS_ooxml::LN_Value_ST_Border_double;
+ break;
+ case RTFKeyword::BRDRTNTHSG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickSmallGap;
+ break;
+ case RTFKeyword::BRDRTNTHMG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickMediumGap;
+ break;
+ case RTFKeyword::BRDRTNTHLG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thinThickLargeGap;
+ break;
+ case RTFKeyword::BRDRTHTNSG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinSmallGap;
+ break;
+ case RTFKeyword::BRDRTHTNMG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinMediumGap;
+ break;
+ case RTFKeyword::BRDRTHTNLG:
+ nParam = NS_ooxml::LN_Value_ST_Border_thickThinLargeGap;
+ break;
+ case RTFKeyword::BRDREMBOSS:
+ nParam = NS_ooxml::LN_Value_ST_Border_threeDEmboss;
+ break;
+ case RTFKeyword::BRDRENGRAVE:
+ nParam = NS_ooxml::LN_Value_ST_Border_threeDEngrave;
+ break;
+ case RTFKeyword::BRDROUTSET:
+ nParam = NS_ooxml::LN_Value_ST_Border_outset;
+ break;
+ case RTFKeyword::BRDRINSET:
+ nParam = NS_ooxml::LN_Value_ST_Border_inset;
+ break;
+ case RTFKeyword::BRDRDASHSM:
+ nParam = NS_ooxml::LN_Value_ST_Border_dashSmallGap;
+ break;
+ case RTFKeyword::BRDRDASHD:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotDash;
+ break;
+ case RTFKeyword::BRDRDASHDD:
+ nParam = NS_ooxml::LN_Value_ST_Border_dotDotDash;
+ break;
+ case RTFKeyword::BRDRNONE:
+ nParam = NS_ooxml::LN_Value_ST_Border_none;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_val, pValue);
+ return RTFError::OK;
+ }
+ }
+
+ // Section breaks
+ switch (nKeyword)
+ {
+ case RTFKeyword::SBKNONE:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_continuous;
+ break;
+ case RTFKeyword::SBKCOL:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_nextColumn;
+ break;
+ case RTFKeyword::SBKPAGE:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
+ break;
+ case RTFKeyword::SBKEVEN:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_evenPage;
+ break;
+ case RTFKeyword::SBKODD:
+ nParam = NS_ooxml::LN_Value_ST_SectionMark_oddPage;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid)
+ {
+ m_nResetBreakOnSectBreak = nKeyword;
+ }
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pValue);
+ return RTFError::OK;
+ }
+
+ // Footnote numbering
+ switch (nKeyword)
+ {
+ case RTFKeyword::FTNNAR:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal;
+ break;
+ case RTFKeyword::FTNNALC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter;
+ break;
+ case RTFKeyword::FTNNAUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter;
+ break;
+ case RTFKeyword::FTNNRLC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman;
+ break;
+ case RTFKeyword::FTNNRUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman;
+ break;
+ case RTFKeyword::FTNNCHI:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pInner = new RTFValue(nParam);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumFmt_val, pInner);
+ auto pOuter = new RTFValue(aAttributes);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr, NS_ooxml::LN_CT_FtnProps_numFmt,
+ pOuter);
+ return RTFError::OK;
+ }
+
+ // Footnote restart type
+ switch (nKeyword)
+ {
+ case RTFKeyword::FTNRSTPG:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachPage;
+ break;
+ case RTFKeyword::FTNRESTART:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_eachSect;
+ break;
+ case RTFKeyword::FTNRSTCONT:
+ nParam = NS_ooxml::LN_Value_ST_RestartNumber_continuous;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue);
+ return RTFError::OK;
+ }
+
+ // Endnote numbering
+ switch (nKeyword)
+ {
+ case RTFKeyword::AFTNNAR:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_decimal;
+ break;
+ case RTFKeyword::AFTNNALC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter;
+ break;
+ case RTFKeyword::AFTNNAUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperLetter;
+ break;
+ case RTFKeyword::AFTNNRLC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman;
+ break;
+ case RTFKeyword::AFTNNRUC:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_upperRoman;
+ break;
+ case RTFKeyword::AFTNNCHI:
+ nParam = NS_ooxml::LN_Value_ST_NumberFormat_chicago;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pInner = new RTFValue(nParam);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumFmt_val, pInner);
+ auto pOuter = new RTFValue(aAttributes);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(), NS_ooxml::LN_EG_SectPrContents_endnotePr,
+ NS_ooxml::LN_CT_EdnProps_numFmt, pOuter);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRQL:
+ nParam = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case RTFKeyword::TRQC:
+ nParam = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case RTFKeyword::TRQR:
+ nParam = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_jc, pValue);
+ return RTFError::OK;
+ }
+
+ // Cell Text Flow
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLTXLRTB:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
+ break;
+ case RTFKeyword::CLTXTBRL:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
+ break;
+ case RTFKeyword::CLTXBTLR:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_btLr;
+ break;
+ case RTFKeyword::CLTXLRTBV:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_lrTbV;
+ break;
+ case RTFKeyword::CLTXTBRLV:
+ nParam = NS_ooxml::LN_Value_ST_TextDirection_tbRlV;
+ break;
+ default:
+ break;
+ }
+ if (nParam >= 0)
+ {
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_textDirection, pValue);
+ }
+
+ // Trivial paragraph flags
+ switch (nKeyword)
+ {
+ case RTFKeyword::KEEP:
+ if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
+ nParam = NS_ooxml::LN_CT_PPrBase_keepLines;
+ break;
+ case RTFKeyword::KEEPN:
+ nParam = NS_ooxml::LN_CT_PPrBase_keepNext;
+ break;
+ case RTFKeyword::INTBL:
+ {
+ m_aStates.top().setCurrentBuffer(&m_aTableBufferStack.back());
+ nParam = NS_ooxml::LN_inTbl;
+ }
+ break;
+ case RTFKeyword::PAGEBB:
+ // ignore a page break that is defined before the document content has even started
+ if (!m_bFirstRun)
+ 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;
+ }
+
+ if (dispatchFloatingTableFlag(nKeyword))
+ {
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::FNIL:
+ case RTFKeyword::FROMAN:
+ case RTFKeyword::FSWISS:
+ case RTFKeyword::FMODERN:
+ case RTFKeyword::FSCRIPT:
+ case RTFKeyword::FDECOR:
+ case RTFKeyword::FTECH:
+ case RTFKeyword::FBIDI:
+ // TODO ooxml:CT_Font_family seems to be ignored by the domain mapper
+ break;
+ case RTFKeyword::ANSI:
+ m_aStates.top().setCurrentEncoding(RTL_TEXTENCODING_MS_1252);
+ break;
+ case RTFKeyword::MAC:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_APPLE_ROMAN);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PC:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_437);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PCA:
+ m_aDefaultState.setCurrentEncoding(RTL_TEXTENCODING_IBM_850);
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::PLAIN:
+ {
+ m_aStates.top().getCharacterSprms() = getDefaultState().getCharacterSprms();
+ m_aStates.top().setCurrentEncoding(getEncoding(getFontIndex(m_nDefaultFontIndex)));
+ m_aStates.top().getCharacterAttributes() = getDefaultState().getCharacterAttributes();
+ m_aStates.top().setCurrentCharacterStyleIndex(-1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ }
+ break;
+ case RTFKeyword::PARD:
+ {
+ if (m_bHadPicture)
+ dispatchSymbol(RTFKeyword::PAR);
+ // \pard is allowed between \cell and \row, but in that case it should not reset the fact that we're inside a table.
+ // It should not reset the paragraph style, either, so remember the old paragraph style.
+ 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));
+ // 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.
+ // By default the style with index 0 is applied.
+ {
+ OUString const aName = getStyleName(0);
+ // But only in case it's not a character style.
+ if (!aName.isEmpty()
+ && getStyleType(0) != NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ new RTFValue(aName));
+ }
+ m_aStates.top().setCurrentStyleIndex(0);
+ }
+ // Need to send paragraph properties again, if there will be any.
+ m_bNeedPap = true;
+ break;
+ }
+ case RTFKeyword::SECTD:
+ {
+ m_aStates.top().getSectionSprms() = m_aDefaultState.getSectionSprms();
+ m_aStates.top().getSectionAttributes() = m_aDefaultState.getSectionAttributes();
+ }
+ break;
+ case RTFKeyword::TROWD:
+ {
+ // Back these up, in case later we still need this info.
+ backupTableRowProperties();
+ resetTableRowProperties();
+ // In case the table definition is in the middle of the row
+ // (invalid), make sure table definition is emitted.
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::WIDCTLPAR:
+ case RTFKeyword::NOWIDCTLPAR:
+ {
+ auto pValue = new RTFValue(int(nKeyword == RTFKeyword::WIDCTLPAR));
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_widowControl, pValue);
+ }
+ break;
+ case RTFKeyword::BOX:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(aAttributes);
+ for (int i = 0; i < 4; i++)
+ m_aStates.top().getParagraphSprms().set(getParagraphBorder(i), pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH_BOX);
+ }
+ break;
+ case RTFKeyword::LTRSECT:
+ case RTFKeyword::RTLSECT:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LTRSECT ? 0 : 1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
+ pValue);
+ }
+ break;
+ case RTFKeyword::LTRPAR:
+ case RTFKeyword::RTLPAR:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LTRPAR ? 0 : 1);
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_bidi, pValue);
+ }
+ break;
+ case RTFKeyword::LTRROW:
+ case RTFKeyword::RTLROW:
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ m_aStates.top().getTableRowSprms().set(
+ NS_ooxml::LN_CT_TblPrBase_bidiVisual,
+ new RTFValue(int(nKeyword == RTFKeyword::RTLROW)));
+ break;
+ case RTFKeyword::LTRCH:
+ // dmapper does not support this.
+ if (m_aStates.top().getRunType() == RTFParserState::RunType::RTLCH_LTRCH_1)
+ m_aStates.top().setRunType(RTFParserState::RunType::RTLCH_LTRCH_2);
+ else
+ m_aStates.top().setRunType(RTFParserState::RunType::LTRCH_RTLCH_1);
+ break;
+ case RTFKeyword::RTLCH:
+ if (m_aStates.top().getRunType() == RTFParserState::RunType::LTRCH_RTLCH_1)
+ m_aStates.top().setRunType(RTFParserState::RunType::LTRCH_RTLCH_2);
+ else
+ m_aStates.top().setRunType(RTFParserState::RunType::RTLCH_LTRCH_1);
+
+ if (m_aDefaultState.getCurrentEncoding() == RTL_TEXTENCODING_MS_1255)
+ m_aStates.top().setCurrentEncoding(m_aDefaultState.getCurrentEncoding());
+ break;
+ case RTFKeyword::ULNONE:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ }
+ break;
+ case RTFKeyword::NONSHPPICT:
+ case RTFKeyword::MMATHPICT: // Picture group used by readers not understanding \moMath group
+ m_aStates.top().setDestination(Destination::SKIP);
+ break;
+ case RTFKeyword::CLBRDRT:
+ case RTFKeyword::CLBRDRL:
+ case RTFKeyword::CLBRDRB:
+ case RTFKeyword::CLBRDRR:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLBRDRT:
+ nSprm = NS_ooxml::LN_CT_TcBorders_top;
+ break;
+ case RTFKeyword::CLBRDRL:
+ nSprm = NS_ooxml::LN_CT_TcBorders_left;
+ break;
+ case RTFKeyword::CLBRDRB:
+ nSprm = NS_ooxml::LN_CT_TcBorders_bottom;
+ break;
+ case RTFKeyword::CLBRDRR:
+ nSprm = NS_ooxml::LN_CT_TcBorders_right;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcBorders,
+ nSprm, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::CELL);
+ }
+ break;
+ case RTFKeyword::PGBRDRT:
+ case RTFKeyword::PGBRDRL:
+ case RTFKeyword::PGBRDRB:
+ case RTFKeyword::PGBRDRR:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::PGBRDRT:
+ nSprm = NS_ooxml::LN_CT_PageBorders_top;
+ break;
+ case RTFKeyword::PGBRDRL:
+ nSprm = NS_ooxml::LN_CT_PageBorders_left;
+ break;
+ case RTFKeyword::PGBRDRB:
+ nSprm = NS_ooxml::LN_CT_PageBorders_bottom;
+ break;
+ case RTFKeyword::PGBRDRR:
+ nSprm = NS_ooxml::LN_CT_PageBorders_right;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders, nSprm, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PAGE);
+ }
+ break;
+ case RTFKeyword::BRDRT:
+ case RTFKeyword::BRDRL:
+ case RTFKeyword::BRDRB:
+ case RTFKeyword::BRDRR:
+ case RTFKeyword::BRDRBTW:
+ {
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ switch (nKeyword)
+ {
+ case RTFKeyword::BRDRT:
+ nSprm = getParagraphBorder(0);
+ break;
+ case RTFKeyword::BRDRL:
+ nSprm = getParagraphBorder(1);
+ break;
+ case RTFKeyword::BRDRB:
+ nSprm = getParagraphBorder(2);
+ break;
+ case RTFKeyword::BRDRR:
+ nSprm = getParagraphBorder(3);
+ break;
+ case RTFKeyword::BRDRBTW:
+ nSprm = getParagraphBorder(4);
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nSprm,
+ pValue);
+ m_aStates.top().setBorderState(RTFBorderState::PARAGRAPH);
+ }
+ break;
+ case RTFKeyword::CHBRDR:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(aAttributes);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_bdr, pValue);
+ m_aStates.top().setBorderState(RTFBorderState::CHARACTER);
+ }
+ break;
+ case RTFKeyword::CLMGF:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLMRG:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_hMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVMGF:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_restart);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVMRG:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_Merge_continue);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vMerge, pValue);
+ }
+ break;
+ case RTFKeyword::CLVERTALT:
+ case RTFKeyword::CLVERTALC:
+ case RTFKeyword::CLVERTALB:
+ {
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLVERTALT:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_top;
+ break;
+ case RTFKeyword::CLVERTALC:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_center;
+ break;
+ case RTFKeyword::CLVERTALB:
+ nParam = NS_ooxml::LN_Value_ST_VerticalJc_bottom;
+ break;
+ default:
+ break;
+ }
+ auto pValue = new RTFValue(nParam);
+ m_aStates.top().getTableCellSprms().set(NS_ooxml::LN_CT_TcPrBase_vAlign, pValue);
+ }
+ break;
+ case RTFKeyword::TRKEEP:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TrPrBase_cantSplit, pValue);
+ }
+ break;
+ case RTFKeyword::SECTUNLOCKED:
+ {
+ auto pValue = new RTFValue(0);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_formProt, pValue);
+ }
+ break;
+ case RTFKeyword::PGNBIDIA:
+ case RTFKeyword::PGNBIDIB:
+ // These should be mapped to NS_ooxml::LN_EG_SectPrContents_pgNumType, but dmapper has no API for that at the moment.
+ break;
+ case RTFKeyword::LOCH:
+ m_aStates.top().setRunType(RTFParserState::RunType::LOCH);
+ break;
+ case RTFKeyword::HICH:
+ m_aStates.top().setRunType(RTFParserState::RunType::HICH);
+ break;
+ case RTFKeyword::DBCH:
+ m_aStates.top().setRunType(RTFParserState::RunType::DBCH);
+ break;
+ case RTFKeyword::TITLEPG:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_titlePg, pValue);
+ }
+ break;
+ case RTFKeyword::SUPER:
+ {
+ // Make sure character properties are not lost if the document
+ // starts with a footnote.
+ if (!isStyleSheetImport())
+ {
+ checkFirstRun();
+ checkNeedPap();
+ }
+
+ if (!m_aStates.top().getCurrentBuffer())
+ m_aStates.top().setCurrentBuffer(&m_aSuperBuffer);
+
+ auto pValue = new RTFValue("superscript");
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue);
+ }
+ break;
+ case RTFKeyword::SUB:
+ {
+ auto pValue = new RTFValue("subscript");
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_vertAlign, pValue);
+ }
+ break;
+ case RTFKeyword::NOSUPERSUB:
+ {
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ {
+ replayBuffer(m_aSuperBuffer, nullptr, nullptr);
+ m_aStates.top().setCurrentBuffer(nullptr);
+ }
+ m_aStates.top().getCharacterSprms().erase(NS_ooxml::LN_EG_RPrBase_vertAlign);
+ }
+ break;
+ case RTFKeyword::LINEPPAGE:
+ case RTFKeyword::LINECONT:
+ {
+ auto pValue = new RTFValue(nKeyword == RTFKeyword::LINEPPAGE
+ ? NS_ooxml::LN_Value_ST_LineNumberRestart_newPage
+ : NS_ooxml::LN_Value_ST_LineNumberRestart_continuous);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_restart, pValue);
+ }
+ break;
+ case RTFKeyword::AENDDOC:
+ // Noop, this is the default in Writer.
+ case RTFKeyword::AENDNOTES:
+ // Noop
+ case RTFKeyword::AFTNRSTCONT:
+ // Noop, this is the default in Writer.
+ case RTFKeyword::AFTNRESTART:
+ // Noop
+ case RTFKeyword::FTNBJ:
+ // Noop, this is the default in Writer.
+ break;
+ case RTFKeyword::ENDDOC:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_RestartNumber_eachSect);
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numRestart, pValue);
+ }
+ break;
+ case RTFKeyword::NOLINE:
+ eraseNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_distance);
+ break;
+ case RTFKeyword::FORMSHADE:
+ // Noop, this is the default in Writer.
+ break;
+ case RTFKeyword::PNGBLIP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::PNG;
+ break;
+ case RTFKeyword::JPEGBLIP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::JPEG;
+ break;
+ case RTFKeyword::POSYT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_top);
+ break;
+ case RTFKeyword::POSYB:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_bottom);
+ break;
+ case RTFKeyword::POSYC:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_center);
+ break;
+ case RTFKeyword::POSYIN:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_inside);
+ break;
+ case RTFKeyword::POSYOUT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_outside);
+ break;
+ case RTFKeyword::POSYIL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ NS_ooxml::LN_Value_doc_ST_YAlign_inline);
+ break;
+
+ case RTFKeyword::PHMRG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_margin);
+ break;
+ case RTFKeyword::PVMRG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_margin);
+ break;
+ case RTFKeyword::PHPG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_page);
+ break;
+ case RTFKeyword::PVPG:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_page);
+ break;
+ case RTFKeyword::PHCOL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ NS_ooxml::LN_Value_doc_ST_HAnchor_text);
+ break;
+ case RTFKeyword::PVPARA:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ NS_ooxml::LN_Value_doc_ST_VAnchor_text);
+ break;
+
+ case RTFKeyword::POSXC:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_center);
+ break;
+ case RTFKeyword::POSXI:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_inside);
+ break;
+ case RTFKeyword::POSXO:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_outside);
+ break;
+ case RTFKeyword::POSXL:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_left);
+ break;
+ case RTFKeyword::POSXR:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ NS_ooxml::LN_Value_doc_ST_XAlign_right);
+ break;
+
+ case RTFKeyword::DPLINE:
+ case RTFKeyword::DPRECT:
+ case RTFKeyword::DPELLIPSE:
+ case RTFKeyword::DPTXBX:
+ case RTFKeyword::DPPOLYLINE:
+ case RTFKeyword::DPPOLYGON:
+ {
+ sal_Int32 nType = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::DPLINE:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.LineShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPPOLYLINE:
+ {
+ // The reason this is not a simple CustomShape is that in the old syntax we have no ViewBox info.
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.PolyLineShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPPOLYGON:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.PolyPolygonShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPRECT:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.RectangleShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ break;
+ }
+ case RTFKeyword::DPELLIPSE:
+ nType = ESCHER_ShpInst_Ellipse;
+ break;
+ case RTFKeyword::DPTXBX:
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.text.TextFrame"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ std::vector<beans::PropertyValue> aDefaults
+ = RTFSdrImport::getTextFrameDefaults(false);
+ for (const auto& rDefault : aDefaults)
+ {
+ if (!findPropertyName(
+ m_aStates.top().getDrawingObject().getPendingProperties(),
+ rDefault.Name))
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(
+ rDefault);
+ }
+ checkFirstRun();
+ Mapper().startShape(m_aStates.top().getDrawingObject().getShape());
+ m_aStates.top().getDrawingObject().setHadShapeText(true);
+ }
+ break;
+ default:
+ break;
+ }
+ if (nType)
+ {
+ uno::Reference<drawing::XShape> xShape(
+ getModelFactory()->createInstance("com.sun.star.drawing.CustomShape"),
+ uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setShape(xShape);
+ }
+ uno::Reference<drawing::XDrawPageSupplier> xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xPropertySet(
+ m_aStates.top().getDrawingObject().getShape(), uno::UNO_QUERY);
+ m_aStates.top().getDrawingObject().setPropertySet(xPropertySet);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
+ if (xShapes.is() && nKeyword != RTFKeyword::DPTXBX)
+ {
+ // set default VertOrient before inserting
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ "VertOrient", uno::Any(text::VertOrientation::NONE));
+ xShapes->add(m_aStates.top().getDrawingObject().getShape());
+ }
+ }
+ if (nType)
+ {
+ uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(
+ m_aStates.top().getDrawingObject().getShape(), uno::UNO_QUERY);
+ xDefaulter->createCustomShapeDefaults(OUString::number(nType));
+ }
+ std::vector<beans::PropertyValue>& rPendingProperties
+ = m_aStates.top().getDrawingObject().getPendingProperties();
+ for (const auto& rPendingProperty : rPendingProperties)
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ rPendingProperty.Name, rPendingProperty.Value);
+ m_pSdrImport->resolveDhgt(m_aStates.top().getDrawingObject().getPropertySet(),
+ m_aStates.top().getDrawingObject().getDhgt(),
+ /*bOldStyle=*/true);
+ }
+ break;
+ case RTFKeyword::DOBXMARGIN:
+ case RTFKeyword::DOBYMARGIN:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name
+ = (nKeyword == RTFKeyword::DOBXMARGIN ? std::u16string_view(u"HoriOrientRelation")
+ : std::u16string_view(u"VertOrientRelation"));
+ aPropertyValue.Value <<= text::RelOrientation::PAGE_PRINT_AREA;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::DOBXPAGE:
+ case RTFKeyword::DOBYPAGE:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name
+ = (nKeyword == RTFKeyword::DOBXPAGE ? std::u16string_view(u"HoriOrientRelation")
+ : std::u16string_view(u"VertOrientRelation"));
+ aPropertyValue.Value <<= text::RelOrientation::PAGE_FRAME;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::DOBYPARA:
+ {
+ beans::PropertyValue aPropertyValue;
+ aPropertyValue.Name = "VertOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ m_aStates.top().getDrawingObject().getPendingProperties().push_back(aPropertyValue);
+ }
+ break;
+ case RTFKeyword::CONTEXTUALSPACE:
+ {
+ auto pValue = new RTFValue(1);
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_contextualSpacing,
+ pValue);
+ }
+ break;
+ case RTFKeyword::LINKSTYLES:
+ {
+ auto pValue = new RTFValue(1);
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_linkStyles, pValue);
+ }
+ break;
+ case RTFKeyword::PNLVLBODY:
+ {
+ auto pValue = new RTFValue(2);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid, pValue);
+ }
+ break;
+ case RTFKeyword::PNDEC:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_decimal);
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val, pValue);
+ }
+ break;
+ case RTFKeyword::PNLVLBLT:
+ {
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
+ new RTFValue(1));
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_bullet));
+ }
+ break;
+ case RTFKeyword::LANDSCAPE:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_PageOrientation_landscape);
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient,
+ pValue);
+ [[fallthrough]]; // set the default + current value
+ }
+ case RTFKeyword::LNDSCPSXN:
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_PageOrientation_landscape);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_orient,
+ pValue);
+ }
+ break;
+ case RTFKeyword::SHPBXPAGE:
+ m_aStates.top().getShape().setHoriOrientRelation(text::RelOrientation::PAGE_FRAME);
+ m_aStates.top().getShape().setHoriOrientRelationToken(
+ NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromH_page);
+ break;
+ case RTFKeyword::SHPBYPAGE:
+ m_aStates.top().getShape().setVertOrientRelation(text::RelOrientation::PAGE_FRAME);
+ m_aStates.top().getShape().setVertOrientRelationToken(
+ NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page);
+ break;
+ case RTFKeyword::DPLINEHOLLOW:
+ m_aStates.top().getDrawingObject().setFLine(0);
+ break;
+ case RTFKeyword::DPROUNDR:
+ if (m_aStates.top().getDrawingObject().getPropertySet().is())
+ // Seems this old syntax has no way to specify a custom radius, and this is the default
+ m_aStates.top().getDrawingObject().getPropertySet()->setPropertyValue(
+ "CornerRadius", uno::Any(sal_Int32(83)));
+ break;
+ case RTFKeyword::NOWRAP:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_notBeside);
+ break;
+ case RTFKeyword::OVERLAY:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_none);
+ break;
+ case RTFKeyword::WRAPAROUND:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_around);
+ break;
+ case RTFKeyword::WRAPTHROUGH:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_through);
+ break;
+ case RTFKeyword::WRAPTIGHT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_tight);
+ break;
+ case RTFKeyword::WRAPDEFAULT:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_wrap,
+ NS_ooxml::LN_Value_doc_ST_Wrap_auto);
+ break;
+ case RTFKeyword::MNOR:
+ m_bMathNor = true;
+ break;
+ case RTFKeyword::REVISIONS:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_trackRevisions, new RTFValue(1));
+ break;
+ case RTFKeyword::BRDRSH:
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_shadow, new RTFValue(1));
+ break;
+ case RTFKeyword::NOCOLBAL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_noColumnBalance, new RTFValue(1));
+ break;
+ case RTFKeyword::MARGMIRROR:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_mirrorMargins, new RTFValue(1));
+ break;
+ case RTFKeyword::SAUTOUPD:
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_autoRedefine,
+ new RTFValue(1));
+ break;
+ case RTFKeyword::WIDOWCTRL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_widowControl, new RTFValue(1));
+ break;
+ case RTFKeyword::LINEBETCOL:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_sep,
+ new RTFValue(1));
+ break;
+ case RTFKeyword::PGNRESTART:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_start, new RTFValue(1));
+ break;
+ case RTFKeyword::PGNUCLTR:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_upperLetter);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNLCLTR:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNUCRM:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_upperRoman);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNLCRM:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::PGNDEC:
+ {
+ auto pIntValue = new RTFValue(NS_ooxml::LN_Value_ST_NumberFormat_decimal);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgNumType,
+ NS_ooxml::LN_CT_PageNumber_fmt, pIntValue);
+ }
+ break;
+ case RTFKeyword::HTMAUTSP:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_doNotUseHTMLParagraphAutoSpacing,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::DNTBLNSBDB:
+ // tdf#128428 switch off longer space sequence
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::GUTTERPRL:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_gutterAtTop, new RTFValue(1));
+ break;
+ case RTFKeyword::RTLGUTTER:
+ {
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_rtlGutter,
+ new RTFValue(1));
+ }
+ break;
+ case RTFKeyword::FLDLOCK:
+ {
+ if (m_aStates.top().getDestination() == Destination::FIELD)
+ m_aStates.top().setFieldLocked(true);
+ }
+ break;
+ case RTFKeyword::NOBRKWRPTBL:
+ {
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_doNotBreakWrappedTables,
+ new RTFValue(0));
+ }
+ break;
+ case RTFKeyword::SPLTPGPAR:
+ {
+ // if flag is present, it is turned *off* - opposite to what spec says
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_splitPgBreakAndParaMark,
+ 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/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx b/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
new file mode 100644
index 000000000000..b40fd55dde9b
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfdispatchsymbol.cxx
@@ -0,0 +1,455 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <svl/lngmisc.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include <sal/log.hxx>
+
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword)
+{
+ setNeedSect(true);
+ if (nKeyword != RTFKeyword::HEXCHAR)
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ else
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
+ RTFSkipDestination aSkip(*this);
+
+ if (RTFKeyword::LINE == nKeyword)
+ {
+ // very special handling since text() will eat lone '\n'
+ singleChar('\n', /*bRunProps=*/true);
+ return RTFError::OK;
+ }
+ // Trivial symbols
+ sal_uInt8 cCh = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::TAB:
+ cCh = '\t';
+ break;
+ case RTFKeyword::BACKSLASH:
+ cCh = '\\';
+ break;
+ case RTFKeyword::LBRACE:
+ cCh = '{';
+ break;
+ case RTFKeyword::RBRACE:
+ cCh = '}';
+ break;
+ case RTFKeyword::EMDASH:
+ cCh = 151;
+ break;
+ case RTFKeyword::ENDASH:
+ cCh = 150;
+ break;
+ case RTFKeyword::BULLET:
+ cCh = 149;
+ break;
+ case RTFKeyword::LQUOTE:
+ cCh = 145;
+ break;
+ case RTFKeyword::RQUOTE:
+ cCh = 146;
+ break;
+ case RTFKeyword::LDBLQUOTE:
+ cCh = 147;
+ break;
+ case RTFKeyword::RDBLQUOTE:
+ cCh = 148;
+ break;
+ default:
+ break;
+ }
+ if (cCh > 0)
+ {
+ OUString aStr(OStringToOUString(OStringChar(char(cCh)), RTL_TEXTENCODING_MS_1252));
+ text(aStr);
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::IGNORE:
+ {
+ m_bSkipUnknown = true;
+ aSkip.setReset(false);
+ return RTFError::OK;
+ }
+ break;
+ case RTFKeyword::PAR:
+ {
+ if (m_aStates.top().getDestination() == Destination::FOOTNOTESEPARATOR)
+ break; // just ignore it - only thing we read in here is CHFTNSEP
+ checkFirstRun();
+ checkNeedPap();
+ runProps(); // tdf#152872 paragraph marker formatting
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ parBreak();
+ // Not in table? Reset max width.
+ if (m_nCellxMax)
+ {
+ // Was in table, but not anymore -> tblEnd.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblEnd, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+ m_nCellxMax = 0;
+ }
+ else if (m_aStates.top().getDestination() != Destination::SHAPETEXT)
+ {
+ RTFValue::Pointer_t pValue;
+ m_aStates.top().getCurrentBuffer()->push_back(Buf_t(BUFFER_PAR, pValue, nullptr));
+ }
+ // but don't emit properties yet, since they may change till the first text token arrives
+ m_bNeedPap = true;
+ if (!m_aStates.top().getFrame().hasProperties())
+ m_bNeedPar = false;
+ m_bNeedFinalPar = false;
+ }
+ break;
+ case RTFKeyword::SECT:
+ {
+ m_bHadSect = true;
+ if (m_bIgnoreNextContSectBreak || m_aStates.top().getFrame().hasProperties())
+ {
+ // testContSectionPageBreak: need \par now
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bIgnoreNextContSectBreak = false;
+ }
+ else
+ {
+ bool bPendingFloatingTable = false;
+ RTFValue::Pointer_t pTblpPr
+ = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblpPr);
+ if (pTblpPr)
+ {
+ // We have a pending floating table, provide an anchor for it still in this
+ // section.
+ bPendingFloatingTable = true;
+ }
+
+ if (m_bNeedCr || bPendingFloatingTable)
+ { // tdf#158586 don't dispatch \par here, it eats deferred page breaks
+ setNeedPar(true);
+ }
+
+ sectBreak();
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid)
+ {
+ // this should run on _second_ \sect after \page
+ dispatchFlag(m_nResetBreakOnSectBreak); // lazy reset
+ m_nResetBreakOnSectBreak = RTFKeyword::invalid;
+ m_bNeedSect = false; // dispatchSymbol set it
+ }
+ setNeedPar(true); // testFdo52052: need \par at end of document
+ // testNestedTable: but not m_bNeedCr, that creates a page break
+ }
+ }
+ break;
+ case RTFKeyword::NOBREAK:
+ {
+ OUString aStr(SVT_HARD_SPACE);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::NOBRKHYPH:
+ {
+ OUString aStr(SVT_HARD_HYPHEN);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::OPTHYPH:
+ {
+ OUString aStr(SVT_SOFT_HYPHEN);
+ text(aStr);
+ }
+ break;
+ case RTFKeyword::HEXCHAR:
+ m_aStates.top().setInternalState(RTFInternalState::HEX);
+ break;
+ case RTFKeyword::CELL:
+ case RTFKeyword::NESTCELL:
+ {
+ checkFirstRun();
+ if (m_bNeedPap)
+ {
+ // There were no runs in the cell, so we need to send paragraph and character properties here.
+ auto pPValue = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ bufferProperties(m_aTableBufferStack.back(), pPValue, nullptr);
+ auto pCValue = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+ bufferProperties(m_aTableBufferStack.back(), pCValue, nullptr);
+ }
+
+ RTFValue::Pointer_t pValue;
+ m_aTableBufferStack.back().emplace_back(Buf_t(BUFFER_CELLEND, pValue, nullptr));
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::NESTROW:
+ {
+ tools::SvRef<TableRowBuffer> const pBuffer(
+ new TableRowBuffer(m_aTableBufferStack.back(), m_aNestedTableCellsSprms,
+ m_aNestedTableCellsAttributes, m_nNestedCells));
+ prepareProperties(m_aStates.top(), pBuffer->GetParaProperties(),
+ pBuffer->GetFrameProperties(), pBuffer->GetRowProperties(),
+ m_nNestedCells, m_nNestedCurrentCellX - m_nNestedTRLeft);
+
+ if (m_aTableBufferStack.size() == 1 || !m_aStates.top().getCurrentBuffer())
+ {
+ throw io::WrongFormatException("mismatch between \\itap and number of \\nestrow",
+ nullptr);
+ }
+ assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
+ // note: there may be several states pointing to table buffer!
+ for (std::size_t i = 0; i < m_aStates.size(); ++i)
+ {
+ if (m_aStates[i].getCurrentBuffer() == &m_aTableBufferStack.back())
+ {
+ m_aStates[i].setCurrentBuffer(
+ &m_aTableBufferStack[m_aTableBufferStack.size() - 2]);
+ }
+ }
+ m_aTableBufferStack.pop_back();
+ m_aTableBufferStack.back().emplace_back(
+ Buf_t(BUFFER_NESTROW, RTFValue::Pointer_t(), pBuffer));
+
+ m_aNestedTableCellsSprms.clear();
+ m_aNestedTableCellsAttributes.clear();
+ m_nNestedCells = 0;
+ m_bNeedPap = true;
+ }
+ break;
+ case RTFKeyword::ROW:
+ {
+ if (m_aStates.top().getTableRowWidthAfter() > 0)
+ {
+ // Add fake cellx / cell, RTF equivalent of
+ // OOXMLFastContextHandlerTextTableRow::handleGridAfter().
+ auto pXValue = new RTFValue(m_aStates.top().getTableRowWidthAfter());
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ dispatchSymbol(RTFKeyword::CELL);
+
+ // Adjust total width, which is done in the \cellx handler for normal cells.
+ m_nTopLevelCurrentCellX += m_aStates.top().getTableRowWidthAfter();
+
+ m_aStates.top().setTableRowWidthAfter(0);
+ }
+
+ bool bRestored = false;
+ // Ending a row, but no cells defined?
+ // See if there was an invalid table row reset, so we can restore cell infos to help invalid documents.
+ if (!m_nTopLevelCurrentCellX && m_nBackupTopLevelCurrentCellX)
+ {
+ restoreTableRowProperties();
+ bRestored = true;
+ }
+
+ // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell
+ const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
+ if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY)
+ {
+ auto pXValueLast = m_aStates.top().getTableRowSprms().find(
+ NS_ooxml::LN_CT_TblGridBase_gridCol, false);
+ const int nXValueLast = pXValueLast ? pXValueLast->getInt() : 0;
+ auto pXValue = new RTFValue(nXValueLast + m_nCellxMax - m_nTopLevelCurrentCellX);
+ m_aStates.top().getTableRowSprms().eraseLast(NS_ooxml::LN_CT_TblGridBase_gridCol);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ m_nTopLevelCurrentCellX = m_nCellxMax;
+ }
+
+ if (m_nTopLevelCells)
+ {
+ // Make a backup before we start popping elements
+ m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms;
+ m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes;
+ m_nInheritingCells = m_nTopLevelCells;
+ }
+ else
+ {
+ // No table definition? Then inherit from the previous row
+ m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms;
+ m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes;
+ m_nTopLevelCells = m_nInheritingCells;
+ }
+
+ while (m_aTableBufferStack.size() > 1)
+ {
+ SAL_WARN("writerfilter.rtf", "dropping extra table buffer");
+ // note: there may be several states pointing to table buffer!
+ for (std::size_t i = 0; i < m_aStates.size(); ++i)
+ {
+ if (m_aStates[i].getCurrentBuffer() == &m_aTableBufferStack.back())
+ {
+ m_aStates[i].setCurrentBuffer(&m_aTableBufferStack.front());
+ }
+ }
+ m_aTableBufferStack.pop_back();
+ }
+
+ replayRowBuffer(m_aTableBufferStack.back(), m_aTopLevelTableCellsSprms,
+ m_aTopLevelTableCellsAttributes, m_nTopLevelCells);
+
+ // The scope of the table cell defaults is one row.
+ m_aDefaultState.getTableCellSprms().clear();
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+
+ writerfilter::Reference<Properties>::Pointer_t paraProperties;
+ writerfilter::Reference<Properties>::Pointer_t frameProperties;
+ writerfilter::Reference<Properties>::Pointer_t rowProperties;
+ prepareProperties(m_aStates.top(), paraProperties, frameProperties, rowProperties,
+ m_nTopLevelCells, m_nTopLevelCurrentCellX - m_nTopLevelTRLeft);
+ sendProperties(paraProperties, frameProperties, rowProperties);
+
+ m_bNeedPap = true;
+ m_bNeedFinalPar = true;
+ m_aTableBufferStack.back().clear();
+ m_nTopLevelCells = 0;
+
+ if (bRestored)
+ // We restored cell definitions, clear these now.
+ // This is necessary, as later cell definitions want to overwrite the restored ones.
+ resetTableRowProperties();
+ }
+ break;
+ case RTFKeyword::COLUMN:
+ {
+ bool bColumns = false; // If we have multiple columns
+ RTFValue::Pointer_t pCols
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_cols);
+ if (pCols)
+ {
+ RTFValue::Pointer_t pNum = pCols->getAttributes().find(NS_ooxml::LN_CT_Columns_num);
+ if (pNum && pNum->getInt() > 1)
+ bColumns = true;
+ }
+ checkFirstRun();
+ if (bColumns)
+ {
+ sal_uInt8 const sBreak[] = { 0xe };
+ Mapper().startCharacterGroup();
+ Mapper().text(sBreak, 1);
+ Mapper().endCharacterGroup();
+ }
+ else
+ dispatchSymbol(RTFKeyword::PAGE);
+ }
+ break;
+ case RTFKeyword::CHFTN:
+ {
+ if (m_aStates.top().getCurrentBuffer() == &m_aSuperBuffer)
+ // Stop buffering, there will be no custom mark for this footnote or endnote.
+ m_aStates.top().setCurrentBuffer(nullptr);
+ break;
+ }
+ case RTFKeyword::PAGE:
+ {
+ // Ignore page breaks inside tables.
+ if (m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back())
+ break;
+
+ // If we're inside a continuous section, we should send a section break, not a page one.
+ RTFValue::Pointer_t pBreak
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ // Unless we're on a title page.
+ RTFValue::Pointer_t pTitlePg
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_titlePg);
+ if (((pBreak
+ && pBreak->getInt()
+ == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous)
+ && m_bHadSect) // tdf#158983 before first \sect, ignore \sbknone!
+ || m_nResetBreakOnSectBreak == RTFKeyword::SBKNONE)
+ && !(pTitlePg && pTitlePg->getInt()))
+ {
+ if (m_bWasInFrame)
+ {
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bWasInFrame = false;
+ }
+ sectBreak();
+ // note: this will not affect the following section break
+ // but the one just pushed
+ dispatchFlag(RTFKeyword::SBKPAGE);
+ if (m_bNeedPar)
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bIgnoreNextContSectBreak = true;
+ // arrange to clean up the synthetic RTFKeyword::SBKPAGE
+ m_nResetBreakOnSectBreak = RTFKeyword::SBKNONE;
+ }
+ else
+ {
+ bool bFirstRun = m_bFirstRun;
+ checkFirstRun();
+ if (bFirstRun || m_bNeedCr)
+ {
+ // Only send the paragraph properties early if we'll create a new paragraph in a
+ // bit anyway.
+ checkNeedPap();
+ // flush previously deferred break - needed for testFdo49893_2
+ // which has consecutive \page with no text between
+ sal_Unicode const nothing[] = { 0 /*MSVC doesn't allow it to be empty*/ };
+ Mapper().utext(nothing, 0);
+ }
+ sal_uInt8 const sBreak[] = { 0xc };
+ Mapper().text(sBreak, 1);
+ // testFdo81892 don't do another \par break directly; because of
+ // GetSplitPgBreakAndParaMark() it does finishParagraph *twice*
+ m_bNeedCr = true;
+ }
+ }
+ break;
+ case RTFKeyword::CHPGN:
+ {
+ OUString aStr("PAGE");
+ singleChar(cFieldStart);
+ text(aStr);
+ singleChar(cFieldSep, true);
+ singleChar(cFieldEnd);
+ }
+ break;
+ case RTFKeyword::CHFTNSEP:
+ {
+ static const sal_Unicode uFtnEdnSep = 0x3;
+ Mapper().utext(&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/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx b/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
new file mode 100644
index 000000000000..1e7552dd71b1
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfdispatchvalue.cxx
@@ -0,0 +1,1909 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <comphelper/sequence.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <osl/thread.h>
+#include <sal/log.hxx>
+#include <rtl/tencinfo.h>
+#include <tools/UnitConversion.hxx>
+
+#include <ooxml/resourceids.hxx>
+
+#include "rtfcharsets.hxx"
+#include "rtffly.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+
+#include <unotools/defaultencoding.hxx>
+#include <unotools/wincodepage.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter
+{
+static int getNumberFormat(int nParam)
+{
+ static const int aMap[]
+ = { NS_ooxml::LN_Value_ST_NumberFormat_decimal,
+ NS_ooxml::LN_Value_ST_NumberFormat_upperRoman,
+ NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman,
+ NS_ooxml::LN_Value_ST_NumberFormat_upperLetter,
+ NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter,
+ NS_ooxml::LN_Value_ST_NumberFormat_ordinal,
+ NS_ooxml::LN_Value_ST_NumberFormat_cardinalText,
+ NS_ooxml::LN_Value_ST_NumberFormat_ordinalText,
+ NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
+ NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec.
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_aiueo,
+ NS_ooxml::LN_Value_ST_NumberFormat_iroha,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal,
+ NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2,
+ NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalZero,
+ NS_ooxml::LN_Value_ST_NumberFormat_bullet,
+ NS_ooxml::LN_Value_ST_NumberFormat_ganada,
+ NS_ooxml::LN_Value_ST_NumberFormat_chosung,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified,
+ NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand,
+ NS_ooxml::LN_Value_ST_NumberFormat_decimal,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal,
+ NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2,
+ NS_ooxml::LN_Value_ST_NumberFormat_hebrew1,
+ NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha,
+ NS_ooxml::LN_Value_ST_NumberFormat_hebrew2,
+ NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad };
+ const int nLen = SAL_N_ELEMENTS(aMap);
+ int nValue = 0;
+ if (nParam >= 0 && nParam < nLen)
+ nValue = aMap[nParam];
+ else // 255 and the other cases.
+ nValue = NS_ooxml::LN_Value_ST_NumberFormat_none;
+ return nValue;
+}
+
+namespace rtftok
+{
+bool RTFDocumentImpl::dispatchTableSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+ switch (nKeyword)
+ {
+ case RTFKeyword::LEVELJC:
+ {
+ nSprm = NS_ooxml::LN_CT_Lvl_lvlJc;
+ int nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_ST_Jc_left;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_ST_Jc_center;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_ST_Jc_right;
+ break;
+ }
+ pIntValue = new RTFValue(nValue);
+ break;
+ }
+ case RTFKeyword::LEVELSTARTAT:
+ nSprm = NS_ooxml::LN_CT_Lvl_start;
+ break;
+ case RTFKeyword::LEVELPICTURE:
+ nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId;
+ break;
+ case RTFKeyword::SBASEDON:
+ nSprm = NS_ooxml::LN_CT_Style_basedOn;
+ pIntValue = new RTFValue(getStyleName(nParam));
+ break;
+ case RTFKeyword::SNEXT:
+ nSprm = NS_ooxml::LN_CT_Style_next;
+ pIntValue = new RTFValue(getStyleName(nParam));
+ break;
+ case RTFKeyword::LEVELLEGAL:
+ nSprm = NS_ooxml::LN_CT_Lvl_isLgl;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ return true;
+ }
+ if (nKeyword == RTFKeyword::LEVELNFC)
+ {
+ pIntValue = new RTFValue(getNumberFormat(nParam));
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt,
+ NS_ooxml::LN_CT_NumFmt_val, pIntValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::FS:
+ case RTFKeyword::AFS:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_szCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_sz;
+ break;
+ }
+ break;
+ case RTFKeyword::EXPNDTW:
+ nSprm = NS_ooxml::LN_EG_RPrBase_spacing;
+ break;
+ case RTFKeyword::KERNING:
+ nSprm = NS_ooxml::LN_EG_RPrBase_kern;
+ break;
+ case RTFKeyword::CHARSCALEX:
+ nSprm = NS_ooxml::LN_EG_RPrBase_w;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pIntValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pIntValue);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::LANG:
+ case RTFKeyword::ALANG:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_CT_Language_bidi;
+ break;
+ case RTFParserState::RunType::DBCH:
+ nSprm = NS_ooxml::LN_CT_Language_eastAsia;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ default:
+ nSprm = NS_ooxml::LN_CT_Language_val;
+ break;
+ }
+ break;
+ case RTFKeyword::LANGFE: // this one is always CJK apparently
+ nSprm = NS_ooxml::LN_CT_Language_eastAsia;
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
+ auto pValue = new RTFValue(aTag.getBcp47());
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_lang, nSprm,
+ pValue);
+ // Language is a character property, but we should store it at a paragraph level as well for fields.
+ if (nKeyword == RTFKeyword::LANG && m_bNeedPap)
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_EG_RPrBase_lang,
+ nSprm, pValue);
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::ITAP:
+ nSprm = NS_ooxml::LN_tblDepth;
+ // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then
+ // use the default value (1), as Word apparently does
+ if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0))
+ {
+ nParam = 1;
+ pIntValue = new RTFValue(nParam);
+ }
+ break;
+ default:
+ break;
+ }
+ if (nSprm > 0)
+ {
+ m_aStates.top().getParagraphSprms().set(nSprm, pIntValue);
+ if (nKeyword == RTFKeyword::ITAP && nParam > 0)
+ {
+ while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam))
+ {
+ m_aTableBufferStack.emplace_back();
+ }
+ // Invalid tables may omit INTBL after ITAP
+ dispatchFlag(RTFKeyword::INTBL); // sets newly pushed buffer as current
+ assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchInfoValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::YR:
+ {
+ m_aStates.top().setYear(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::MO:
+ {
+ m_aStates.top().setMonth(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::DY:
+ {
+ m_aStates.top().setDay(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::HR:
+ {
+ m_aStates.top().setHour(nParam);
+ nSprm = 1;
+ }
+ break;
+ case RTFKeyword::MIN:
+ {
+ m_aStates.top().setMinute(nParam);
+ nSprm = 1;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return nSprm > 0;
+}
+
+bool RTFDocumentImpl::dispatchFrameValue(RTFKeyword nKeyword, int nParam)
+{
+ Id nId = 0;
+ switch (nKeyword)
+ {
+ case RTFKeyword::ABSW:
+ nId = NS_ooxml::LN_CT_FramePr_w;
+ break;
+ case RTFKeyword::ABSH:
+ nId = NS_ooxml::LN_CT_FramePr_h;
+ break;
+ case RTFKeyword::POSX:
+ {
+ nId = NS_ooxml::LN_CT_FramePr_x;
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0);
+ }
+ break;
+ case RTFKeyword::POSY:
+ {
+ nId = NS_ooxml::LN_CT_FramePr_y;
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_bNeedPap = true;
+ // Don't try to support text frames inside tables for now.
+ if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back())
+ m_aStates.top().getFrame().setSprm(nId, nParam);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam)
+{
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::CELLX:
+ {
+ int& rCurrentCellX(
+ (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ ? m_nNestedCurrentCellX
+ : m_nTopLevelCurrentCellX);
+ int nCellX = nParam - rCurrentCellX;
+
+ if (!nCellX && nParam > 0)
+ {
+ // If width of cell is 0, BUT there is a value for \cellxN use minimal
+ // possible width. But if \cellxN has no value leave 0 so autofit will
+ // try to resolve this.
+
+ // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells.
+ const int COL_DFLT_WIDTH = 41;
+ nCellX = COL_DFLT_WIDTH;
+ }
+
+ // If there is a negative left margin, then the first cellx is relative to that.
+ RTFValue::Pointer_t pTblInd
+ = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd);
+ if (rCurrentCellX == 0 && pTblInd)
+ {
+ RTFValue::Pointer_t pWidth
+ = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w);
+ if (pWidth && pWidth->getInt() < 0)
+ nCellX = -1 * (pWidth->getInt() - nParam);
+ }
+
+ rCurrentCellX = nParam;
+ auto pXValue = new RTFValue(nCellX);
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue,
+ RTFOverwrite::NO_APPEND);
+ if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ {
+ m_nNestedCells++;
+ // Push cell properties.
+ m_aNestedTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_aNestedTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ }
+ else
+ {
+ m_nTopLevelCells++;
+ // Push cell properties.
+ m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms());
+ m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes());
+ }
+
+ m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms();
+ m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes();
+ // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token
+ dispatchFlag(RTFKeyword::INTBL);
+ if (!m_nCellxMax)
+ {
+ // Wasn't in table, but now is -> tblStart.
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1));
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ }
+ m_nCellxMax = std::max(m_nCellxMax, nParam);
+ return true;
+ }
+ break;
+ case RTFKeyword::TRRH:
+ {
+ OUString hRule("auto");
+ if (nParam < 0)
+ {
+ tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam));
+ std::swap(pIntValue, pAbsValue);
+
+ hRule = "exact";
+ }
+ else if (nParam > 0)
+ hRule = "atLeast";
+
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val,
+ pIntValue);
+
+ auto pHRule = new RTFValue(hRule);
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_hRule,
+ pHRule);
+ return true;
+ }
+ break;
+ case RTFKeyword::TRLEFT:
+ case RTFKeyword::TBLIND:
+ {
+ // the value is in twips
+ 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);
+ 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));
+
+ if (nKeyword == RTFKeyword::TBLIND)
+ {
+ RTFValue::Pointer_t pCellMargin
+ = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblCellMar);
+ if (pCellMargin)
+ {
+ RTFValue::Pointer_t pMarginLeft
+ = pCellMargin->getSprms().find(NS_ooxml::LN_CT_TcMar_left);
+ if (pMarginLeft)
+ nParam -= pMarginLeft->getAttributes()
+ .find(NS_ooxml::LN_CT_TblWidth_w)
+ ->getInt();
+ }
+ rCurrentTRLeft = nParam;
+ }
+ else
+ rCurrentTRLeft = rCurrentCellX = nParam;
+
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd,
+ +NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ return true;
+ }
+ break;
+ case RTFKeyword::CLSHDNG:
+ {
+ int nValue = -1;
+
+ if (nParam < 1)
+ nValue = NS_ooxml::LN_Value_ST_Shd_clear;
+ else if (nParam < 750)
+ // Values in between 1 and 250 visually closer to 0% shading (white)
+ // But this will mean "no shading" while cell actually have some.
+ // So lets use minimal available value.
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct5;
+ else if (nParam < 1100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct10;
+ else if (nParam < 1350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct12;
+ else if (nParam < 1750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct15;
+ else if (nParam < 2250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct20;
+ else if (nParam < 2750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct25;
+ else if (nParam < 3250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct30;
+ else if (nParam < 3600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct35;
+ else if (nParam < 3850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct37;
+ else if (nParam < 4250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct40;
+ else if (nParam < 4750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct45;
+ else if (nParam < 5250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct50;
+ else if (nParam < 5750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct55;
+ else if (nParam < 6100)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct60;
+ else if (nParam < 6350)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct62;
+ else if (nParam < 6750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct65;
+ else if (nParam < 7250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct70;
+ else if (nParam < 7750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct75;
+ else if (nParam < 8250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct80;
+ else if (nParam < 8600)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct85;
+ else if (nParam < 8850)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct87;
+ else if (nParam < 9250)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct90;
+ else if (nParam < 9750)
+ nValue = NS_ooxml::LN_Value_ST_Shd_pct95;
+ else
+ // Solid fill
+ nValue = NS_ooxml::LN_Value_ST_Shd_solid;
+
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_val, new RTFValue(nValue));
+ return true;
+ }
+ break;
+ case RTFKeyword::CLPADB:
+ case RTFKeyword::CLPADL:
+ case RTFKeyword::CLPADR:
+ case RTFKeyword::CLPADT:
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ // Top and left is swapped, that's what Word does.
+ switch (nKeyword)
+ {
+ case RTFKeyword::CLPADB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::CLPADL:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ case RTFKeyword::CLPADR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::CLPADT:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ break;
+ case RTFKeyword::TRPADDFB:
+ case RTFKeyword::TRPADDFL:
+ case RTFKeyword::TRPADDFR:
+ case RTFKeyword::TRPADDFT:
+ {
+ RTFSprms aAttributes;
+ switch (nParam)
+ {
+ case 3:
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ break;
+ }
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRPADDFB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::TRPADDFL:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ case RTFKeyword::TRPADDFR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::TRPADDFT:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ default:
+ break;
+ }
+ putNestedAttribute(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar, nSprm,
+ new RTFValue(aAttributes));
+ // tdf#74795 also set on current cell, and as default for table cells
+ // (why isn't this done by domainmapper?)
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ putNestedAttribute(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ break;
+ case RTFKeyword::TRPADDB:
+ case RTFKeyword::TRPADDL:
+ case RTFKeyword::TRPADDR:
+ case RTFKeyword::TRPADDT:
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam));
+ switch (nKeyword)
+ {
+ case RTFKeyword::TRPADDB:
+ nSprm = NS_ooxml::LN_CT_TcMar_bottom;
+ break;
+ case RTFKeyword::TRPADDL:
+ nSprm = NS_ooxml::LN_CT_TcMar_left;
+ break;
+ case RTFKeyword::TRPADDR:
+ nSprm = NS_ooxml::LN_CT_TcMar_right;
+ break;
+ case RTFKeyword::TRPADDT:
+ nSprm = NS_ooxml::LN_CT_TcMar_top;
+ break;
+ default:
+ break;
+ }
+ putNestedSprm(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ nSprm, new RTFValue(aAttributes));
+ // tdf#74795 also set on current cell, and as default for table cells
+ // (why isn't this done by domainmapper?)
+ putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ putNestedSprm(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar,
+ nSprm, new RTFValue(aAttributes));
+ return true;
+ }
+ case RTFKeyword::TRGAPH:
+ // Half of the space between the cells of a table row: default left/right table cell margin.
+ if (nParam > 0)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_type,
+ new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa));
+ aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue);
+ // FIXME: this is wrong, it is half-gap, needs to be distinguished from margin! depending on TRPADDFL/TRPADDFR
+ putNestedSprm(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left,
+ new RTFValue(aAttributes));
+ putNestedSprm(m_aStates.top().getTableRowSprms(),
+ NS_ooxml::LN_CT_TblPrBase_tblCellMar,
+ NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes));
+ }
+ return true;
+ case RTFKeyword::TRFTSWIDTH:
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_type, pIntValue);
+ return true;
+ case RTFKeyword::TRWWIDTH:
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW,
+ NS_ooxml::LN_CT_TblWidth_w, pIntValue);
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/nKeyword != RTFKeyword::U, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nSprm = 0;
+ tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam));
+ // Trivial table sprms.
+ if (dispatchTableSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial character sprms.
+ if (dispatchCharacterSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial character attributes.
+ if (dispatchCharacterAttributeValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Trivial paragraph sprms.
+ if (dispatchParagraphSprmValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Info group.
+ if (dispatchInfoValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Frame size / position.
+ if (dispatchFrameValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Table-related values.
+ if (dispatchTableValue(nKeyword, nParam))
+ {
+ return RTFError::OK;
+ }
+
+ // Then check for the more complex ones.
+ switch (nKeyword)
+ {
+ case RTFKeyword::F:
+ case RTFKeyword::AF:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_CT_Fonts_cs;
+ break;
+ case RTFParserState::RunType::DBCH:
+ nSprm = NS_ooxml::LN_CT_Fonts_eastAsia;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ default:
+ nSprm = NS_ooxml::LN_CT_Fonts_ascii;
+ break;
+ }
+
+ if (m_aStates.top().getDestination() == Destination::FONTTABLE
+ || m_aStates.top().getDestination() == Destination::FONTENTRY)
+ {
+ // Some text in buffer? It is font name. So previous font definition is complete
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ m_aFontIndexes.push_back(nParam);
+ m_nCurrentFontIndex = getFontIndex(nParam);
+ }
+ else if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ RTFSprms aFontAttributes;
+ aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)]));
+ RTFSprms aRunPropsSprms;
+ aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes));
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_rPr,
+ new RTFValue(RTFSprms(), aRunPropsSprms),
+ RTFOverwrite::NO_APPEND);
+ }
+ else
+ {
+ m_nCurrentFontIndex = getFontIndex(nParam);
+ auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex));
+ putNestedAttribute(m_aStates.top().getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue);
+ if (nKeyword == RTFKeyword::F)
+ m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex));
+ }
+ break;
+ case RTFKeyword::RED:
+ m_aStates.top().getCurrentColor().SetRed(nParam);
+ break;
+ case RTFKeyword::GREEN:
+ m_aStates.top().getCurrentColor().SetGreen(nParam);
+ break;
+ case RTFKeyword::BLUE:
+ m_aStates.top().getCurrentColor().SetBlue(nParam);
+ break;
+ case RTFKeyword::FCHARSET:
+ {
+ // we always send text to the domain mapper in OUString, so no
+ // need to send encoding info
+ int i;
+ for (i = 0; i < nRTFEncodings; i++)
+ {
+ if (aRTFEncodings[i].charset == nParam)
+ break;
+ }
+ if (i == nRTFEncodings)
+ // not found
+ return RTFError::OK;
+
+ m_nCurrentEncoding
+ = aRTFEncodings[i].codepage == 0 // Default (CP_ACP)
+ ? osl_getThreadTextEncoding()
+ : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage);
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ break;
+ case RTFKeyword::ANSICPG:
+ case RTFKeyword::CPG:
+ {
+ rtl_TextEncoding nEncoding
+ = (nParam == 0)
+ ? utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding())
+ : rtl_getTextEncodingFromWindowsCodePage(nParam);
+ if (nKeyword == RTFKeyword::ANSICPG)
+ m_aDefaultState.setCurrentEncoding(nEncoding);
+ else
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(nEncoding);
+ }
+ break;
+ case RTFKeyword::CF:
+ {
+ RTFSprms aAttributes;
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_color,
+ new RTFValue(aAttributes));
+ }
+ break;
+ case RTFKeyword::S:
+ {
+ m_aStates.top().setCurrentStyleIndex(nParam);
+
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // paragraph style
+ }
+ else
+ {
+ OUString aName = getStyleName(nParam);
+ if (!aName.isEmpty())
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_pStyle,
+ new RTFValue(aName));
+ else
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle,
+ new RTFValue(aName));
+ }
+ }
+ }
+ break;
+ case RTFKeyword::CS:
+ m_aStates.top().setCurrentCharacterStyleIndex(nParam);
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // character style
+ }
+ else
+ {
+ OUString aName = getStyleName(nParam);
+ if (!aName.isEmpty())
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_rStyle,
+ new RTFValue(aName));
+ }
+ break;
+ case RTFKeyword::DS:
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ auto pValue = new RTFValue(0); // TODO no value in enum StyleType?
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // section style
+ }
+ break;
+ case RTFKeyword::TS:
+ if (m_aStates.top().getDestination() == Destination::STYLESHEET
+ || m_aStates.top().getDestination() == Destination::STYLEENTRY)
+ {
+ m_nCurrentStyleIndex = nParam;
+ // FIXME the correct value would be NS_ooxml::LN_Value_ST_StyleType_table but maybe table styles mess things up in dmapper, be cautious and disable them for now
+ auto pValue = new RTFValue(0);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type,
+ pValue); // table style
+ }
+ break;
+ case RTFKeyword::DEFF:
+ m_nDefaultFontIndex = nParam;
+ break;
+ case RTFKeyword::STSHFDBCH:
+ // tdf#123703 switch off longer space sequence except in the case of the fixed compatibility setting font id 31505
+ if (nParam != 31505)
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ case RTFKeyword::DEFLANG:
+ case RTFKeyword::ADEFLANG:
+ {
+ LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam))));
+ auto pValue = new RTFValue(aTag.getBcp47());
+ putNestedAttribute(m_aStates.top().getCharacterSprms(),
+ (nKeyword == RTFKeyword::DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang
+ : NS_ooxml::LN_CT_Language_bidi),
+ nSprm, pValue);
+ }
+ break;
+ case RTFKeyword::CHCBPAT:
+ {
+ auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::CLCBPAT:
+ case RTFKeyword::CLCBPATRAW:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::CBPAT:
+ if (nParam)
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_shd,
+ NS_ooxml::LN_CT_Shd_fill, pValue);
+ }
+ break;
+ case RTFKeyword::ULC:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ m_aStates.top().getCharacterSprms().set(0x6877, pValue);
+ }
+ break;
+ case RTFKeyword::HIGHLIGHT:
+ {
+ auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO));
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_highlight, pValue);
+ }
+ break;
+ case RTFKeyword::UP:
+ case RTFKeyword::DN:
+ {
+ auto pValue = new RTFValue(nParam * (nKeyword == RTFKeyword::UP ? 1 : -1));
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue);
+ }
+ break;
+ case RTFKeyword::HORZVERT:
+ {
+ auto pValue = new RTFValue(int(true));
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_vert,
+ pValue);
+ if (nParam)
+ // rotate fits to a single line
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue);
+ }
+ break;
+ case RTFKeyword::EXPND:
+ {
+ // Convert quarter-points to twentieths of a point
+ auto pValue = new RTFValue(nParam * 5);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_spacing, pValue);
+ }
+ break;
+ case RTFKeyword::TWOINONE:
+ {
+ auto pValue = new RTFValue(int(true));
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_combine,
+ pValue);
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_none;
+ break;
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_round;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_square;
+ break;
+ case 3:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle;
+ break;
+ case 4:
+ nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly;
+ break;
+ }
+ if (nId > 0)
+ m_aStates.top().getCharacterAttributes().set(
+ NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId));
+ }
+ break;
+ case RTFKeyword::SL:
+ {
+ // This is similar to RTFKeyword::ABSH, negative value means 'exact', positive means 'at least'.
+ tools::SvRef<RTFValue> pValue(
+ new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast));
+ if (nParam < 0)
+ {
+ pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact);
+ pIntValue = new RTFValue(-nParam);
+ }
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, pValue);
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_line, pIntValue);
+ }
+ break;
+ case RTFKeyword::SLMULT:
+ if (nParam > 0)
+ {
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
+ m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule,
+ pValue);
+ }
+ break;
+ case RTFKeyword::BRDRW:
+ {
+ // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0
+ if (nParam > 1)
+ nParam = nParam * 2 / 5;
+ auto pValue = new RTFValue(nParam);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue);
+ }
+ break;
+ case RTFKeyword::BRDRCF:
+ {
+ auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam)));
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue);
+ }
+ break;
+ case RTFKeyword::BRSP:
+ {
+ // dmapper expects it in points, we have it in twip
+ auto pValue = new RTFValue(nParam / 20);
+ putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue);
+ }
+ break;
+ case RTFKeyword::TX:
+ {
+ m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_pos, pIntValue);
+ auto pValue = new RTFValue(m_aStates.top().getTabAttributes());
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
+ NS_ooxml::LN_CT_Tabs_tab, pValue);
+ else
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_tabs,
+ NS_ooxml::LN_CT_Tabs_tab, pValue);
+ m_aStates.top().getTabAttributes().clear();
+ }
+ break;
+ case RTFKeyword::ILVL:
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_ilvl, pIntValue);
+ break;
+ case RTFKeyword::LISTTEMPLATEID:
+ // This one is not referenced anywhere, so it's pointless to store it at the moment.
+ break;
+ case RTFKeyword::LISTID:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTENTRY)
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_abstractNumId,
+ pIntValue);
+ else if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue);
+ m_aStates.top().setCurrentListIndex(nParam);
+ }
+ break;
+ case RTFKeyword::LS:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ {
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid,
+ pIntValue);
+ m_aStates.top().setCurrentListOverrideIndex(nParam);
+ }
+ else
+ {
+ // Insert at the start, so properties inherited from the list
+ // can be overridden by direct formatting. But still allow the
+ // case when old-style paragraph numbering is already
+ // tokenized.
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND);
+ }
+ }
+ break;
+ case RTFKeyword::UC:
+ if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16))
+ m_aStates.top().setUc(nParam);
+ break;
+ case RTFKeyword::U:
+ // sal_Unicode is unsigned 16-bit, RTF may represent that as a
+ // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The
+ // static_cast() will do the right thing.
+ if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_UINT16))
+ {
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
+ {
+ if (nParam != ';')
+ m_aStates.top().getLevelNumbers().push_back(sal_Int32(nParam));
+ else
+ // ';' in \u form is not considered valid.
+ m_aStates.top().setLevelNumbersValid(false);
+ }
+ else
+ m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam));
+ m_aStates.top().getCharsToSkip() = m_aStates.top().getUc();
+ }
+ break;
+ case RTFKeyword::LEVELFOLLOW:
+ {
+ OUString sValue;
+ switch (nParam)
+ {
+ case 0:
+ sValue = "tab";
+ break;
+ case 1:
+ sValue = "space";
+ break;
+ case 2:
+ sValue = "nothing";
+ break;
+ }
+ if (!sValue.isEmpty())
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue));
+ }
+ break;
+ case RTFKeyword::FPRQ:
+ {
+ sal_Int32 nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_default;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_fixed;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_ST_Pitch_variable;
+ break;
+ }
+ if (nValue)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue));
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Font_pitch,
+ new RTFValue(aAttributes));
+ }
+ }
+ break;
+ case RTFKeyword::LISTOVERRIDECOUNT:
+ // Ignore this for now, the exporter always emits it with a zero parameter.
+ break;
+ case RTFKeyword::PICSCALEX:
+ m_aStates.top().getPicture().nScaleX = nParam;
+ break;
+ case RTFKeyword::PICSCALEY:
+ m_aStates.top().getPicture().nScaleY = nParam;
+ break;
+ case RTFKeyword::PICW:
+ m_aStates.top().getPicture().nWidth = nParam;
+ break;
+ case RTFKeyword::PICH:
+ m_aStates.top().getPicture().nHeight = nParam;
+ break;
+ case RTFKeyword::PICWGOAL:
+ m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICHGOAL:
+ m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPL:
+ m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPR:
+ m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPT:
+ m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::PICCROPB:
+ m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam);
+ break;
+ case RTFKeyword::SHPWRK:
+ {
+ int nValue = 0;
+ switch (nParam)
+ {
+ case 0:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides;
+ break;
+ case 1:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left;
+ break;
+ case 2:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right;
+ break;
+ case 3:
+ nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest;
+ break;
+ default:
+ break;
+ }
+ auto pValue = new RTFValue(nValue);
+ RTFValue::Pointer_t pTight
+ = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_WrapType_wrapTight);
+ if (pTight)
+ pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue);
+ else
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_WrapSquare_wrapText,
+ pValue);
+ }
+ break;
+ case RTFKeyword::SHPWR:
+ {
+ switch (nParam)
+ {
+ case 1:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_NONE);
+ break;
+ case 2:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
+ break;
+ case 3:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapNone,
+ new RTFValue());
+ break;
+ case 4:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapTight,
+ new RTFValue());
+ break;
+ case 5:
+ m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH);
+ break;
+ }
+ }
+ break;
+ case RTFKeyword::COLS:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num,
+ pIntValue);
+ break;
+ case RTFKeyword::COLSX:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space,
+ pIntValue);
+ break;
+ case RTFKeyword::COLNO:
+ putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols,
+ NS_ooxml::LN_CT_Columns_col, pIntValue);
+ break;
+ case RTFKeyword::COLW:
+ case RTFKeyword::COLSR:
+ {
+ RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_cols);
+ rAttributes.set((nKeyword == RTFKeyword::COLW ? NS_ooxml::LN_CT_Column_w
+ : NS_ooxml::LN_CT_Column_space),
+ pIntValue);
+ }
+ break;
+ case RTFKeyword::PAPERH:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::PGHSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h,
+ pIntValue);
+ break;
+ case RTFKeyword::PAPERW:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::PGWSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w,
+ pIntValue);
+ break;
+ case RTFKeyword::BINFSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_paperSrc,
+ NS_ooxml::LN_CT_PaperSource_first, pIntValue);
+ break;
+ case RTFKeyword::BINSXN:
+ {
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_paperSrc,
+ NS_ooxml::LN_CT_PaperSource_other, pIntValue);
+ }
+ break;
+ case RTFKeyword::MARGL:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGLSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGR:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGRSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGT:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGTSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top,
+ pIntValue);
+ break;
+ case RTFKeyword::MARGB:
+ putNestedAttribute(m_aDefaultState.getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
+ pIntValue);
+ [[fallthrough]]; // set the default + current value
+ case RTFKeyword::MARGBSXN:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom,
+ pIntValue);
+ break;
+ case RTFKeyword::HEADERY:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header,
+ pIntValue);
+ break;
+ case RTFKeyword::FOOTERY:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer,
+ pIntValue);
+ break;
+ case RTFKeyword::GUTTER:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_gutter,
+ pIntValue);
+ break;
+ case RTFKeyword::DEFTAB:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue);
+ break;
+ case RTFKeyword::LINEMOD:
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_countBy, pIntValue);
+ break;
+ case RTFKeyword::LINEX:
+ if (nParam)
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_distance, pIntValue);
+ break;
+ case RTFKeyword::LINESTARTS:
+ {
+ // OOXML <w:lnNumType w:start="..."/> is 0-based, RTF is 1-based.
+ auto pStart = tools::make_ref<RTFValue>(nParam - 1);
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_lnNumType,
+ NS_ooxml::LN_CT_LineNumber_start, pStart);
+ }
+ break;
+ case RTFKeyword::REVAUTH:
+ case RTFKeyword::REVAUTHDEL:
+ {
+ auto pValue = new RTFValue(m_aAuthors[nParam]);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_CT_TrackChange_author, pValue);
+ }
+ break;
+ case RTFKeyword::REVDTTM:
+ case RTFKeyword::REVDTTMDEL:
+ {
+ OUString aStr(
+ OStringToOUString(DTTM22OString(nParam), m_aStates.top().getCurrentEncoding()));
+ auto pValue = new RTFValue(aStr);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_CT_TrackChange_date, pValue);
+ }
+ break;
+ case RTFKeyword::SHPLEFT:
+ m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPTOP:
+ m_aStates.top().getShape().setTop(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPRIGHT:
+ m_aStates.top().getShape().setRight(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPBOTTOM:
+ m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::SHPZ:
+ m_aStates.top().getShape().setZ(nParam);
+ break;
+ case RTFKeyword::FFTYPE:
+ switch (nParam)
+ {
+ case 0:
+ m_nFormFieldType = RTFFormFieldType::TEXT;
+ break;
+ case 1:
+ m_nFormFieldType = RTFFormFieldType::CHECKBOX;
+ break;
+ case 2:
+ m_nFormFieldType = RTFFormFieldType::LIST;
+ break;
+ default:
+ m_nFormFieldType = RTFFormFieldType::NONE;
+ break;
+ }
+ break;
+ case RTFKeyword::FFDEFRES:
+ if (m_nFormFieldType == RTFFormFieldType::CHECKBOX)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue);
+ else if (m_nFormFieldType == RTFFormFieldType::LIST)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue);
+ break;
+ case RTFKeyword::FFRES:
+ // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits.
+ if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue);
+ else if (m_nFormFieldType == RTFFormFieldType::LIST)
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue);
+ break;
+ case RTFKeyword::EDMINS:
+ if (m_xDocumentProperties.is())
+ {
+ // tdf#116851 some RTF may be malformed
+ if (nParam < 0)
+ nParam = -nParam;
+ m_xDocumentProperties->setEditingDuration(nParam);
+ }
+ break;
+ case RTFKeyword::NOFPAGES:
+ case RTFKeyword::NOFWORDS:
+ case RTFKeyword::NOFCHARS:
+ case RTFKeyword::NOFCHARSWS:
+ if (m_xDocumentProperties.is())
+ {
+ comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics();
+ OUString aName;
+ switch (nKeyword)
+ {
+ case RTFKeyword::NOFPAGES:
+ aName = "PageCount";
+ nParam = 99;
+ break;
+ case RTFKeyword::NOFWORDS:
+ aName = "WordCount";
+ break;
+ case RTFKeyword::NOFCHARS:
+ aName = "CharacterCount";
+ break;
+ case RTFKeyword::NOFCHARSWS:
+ aName = "NonWhitespaceCharacterCount";
+ break;
+ default:
+ break;
+ }
+ if (!aName.isEmpty())
+ {
+ aSeq[aName] <<= sal_Int32(nParam);
+ m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList());
+ }
+ }
+ break;
+ case RTFKeyword::VERSION:
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setEditingCycles(nParam);
+ break;
+ case RTFKeyword::VERN:
+ // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers.
+ break;
+ case RTFKeyword::FTNSTART:
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_footnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
+ break;
+ case RTFKeyword::AFTNSTART:
+ putNestedSprm(m_aDefaultState.getParagraphSprms(),
+ NS_ooxml::LN_EG_SectPrContents_endnotePr,
+ NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue);
+ break;
+ case RTFKeyword::DFRMTXTX:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
+ break;
+ case RTFKeyword::DFRMTXTY:
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
+ break;
+ case RTFKeyword::DXFRTEXT:
+ {
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam);
+ }
+ break;
+ case RTFKeyword::FLYVERT:
+ {
+ RTFVertOrient aVertOrient(nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign,
+ aVertOrient.GetAlign());
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor,
+ aVertOrient.GetAnchor());
+ }
+ break;
+ case RTFKeyword::FLYHORZ:
+ {
+ RTFHoriOrient aHoriOrient(nParam);
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign,
+ aHoriOrient.GetAlign());
+ m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor,
+ aHoriOrient.GetAnchor());
+ }
+ break;
+ case RTFKeyword::FLYANCHOR:
+ break;
+ case RTFKeyword::WMETAFILE:
+ m_aStates.top().getPicture().eWMetafile = nParam;
+ break;
+ case RTFKeyword::SB:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_before, pIntValue);
+ break;
+ case RTFKeyword::SA:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_after, pIntValue);
+ break;
+ case RTFKeyword::DPX:
+ m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPY:
+ m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPXSIZE:
+ m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::DPYSIZE:
+ m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam));
+ break;
+ case RTFKeyword::PNSTART:
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue);
+ break;
+ case RTFKeyword::PNF:
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]);
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue);
+ putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_rPr,
+ NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes));
+ }
+ break;
+ case RTFKeyword::VIEWSCALE:
+ m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue);
+ break;
+ case RTFKeyword::BIN:
+ {
+ m_aStates.top().setInternalState(RTFInternalState::BIN);
+ m_aStates.top().setBinaryToRead(nParam);
+ }
+ break;
+ case RTFKeyword::DPLINECOR:
+ m_aStates.top().getDrawingObject().setLineColorR(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPLINECOG:
+ m_aStates.top().getDrawingObject().setLineColorG(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPLINECOB:
+ m_aStates.top().getDrawingObject().setLineColorB(nParam);
+ m_aStates.top().getDrawingObject().setHasLineColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCR:
+ m_aStates.top().getDrawingObject().setFillColorR(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCG:
+ m_aStates.top().getDrawingObject().setFillColorG(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DPFILLBGCB:
+ m_aStates.top().getDrawingObject().setFillColorB(nParam);
+ m_aStates.top().getDrawingObject().setHasFillColor(true);
+ break;
+ case RTFKeyword::DODHGT:
+ m_aStates.top().getDrawingObject().setDhgt(nParam);
+ break;
+ case RTFKeyword::DPPOLYCOUNT:
+ if (nParam >= 0)
+ {
+ m_aStates.top().getDrawingObject().setPolyLineCount(nParam);
+ }
+ break;
+ case RTFKeyword::DPPTX:
+ {
+ RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
+
+ if (rDrawingObject.getPolyLinePoints().empty())
+ dispatchValue(RTFKeyword::DPPOLYCOUNT, 2);
+
+ rDrawingObject.getPolyLinePoints().emplace_back(convertTwipToMm100(nParam), 0);
+ }
+ break;
+ case RTFKeyword::DPPTY:
+ {
+ RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject();
+ if (!rDrawingObject.getPolyLinePoints().empty())
+ {
+ rDrawingObject.getPolyLinePoints().back().Y = convertTwipToMm100(nParam);
+ rDrawingObject.setPolyLineCount(rDrawingObject.getPolyLineCount() - 1);
+ if (rDrawingObject.getPolyLineCount() == 0 && rDrawingObject.getPropertySet().is())
+ {
+ uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence
+ = { comphelper::containerToSequence(rDrawingObject.getPolyLinePoints()) };
+ rDrawingObject.getPropertySet()->setPropertyValue(
+ "PolyPolygon", uno::Any(aPointSequenceSequence));
+ }
+ }
+ }
+ break;
+ case RTFKeyword::SHPFBLWTXT:
+ // Shape is below text -> send it to the background.
+ m_aStates.top().getShape().setInBackground(nParam != 0);
+ break;
+ case RTFKeyword::FI:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ if (m_aStates.top().getLevelNumbersValid())
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
+ else
+ m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam;
+ }
+ else
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, pIntValue);
+ break;
+ }
+ case RTFKeyword::LI:
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ if (m_aStates.top().getLevelNumbersValid())
+ putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_left, pIntValue);
+ }
+ else
+ {
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_left, pIntValue);
+ }
+ // It turns out \li should reset the \fi inherited from the stylesheet.
+ // So set the direct formatting to zero, if we don't have such direct formatting yet.
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0),
+ RTFOverwrite::NO_IGNORE);
+ }
+ break;
+ case RTFKeyword::RI:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_right, pIntValue);
+ break;
+ case RTFKeyword::LIN:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_start, pIntValue);
+ break;
+ case RTFKeyword::RIN:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind,
+ NS_ooxml::LN_CT_Ind_end, pIntValue);
+ break;
+ case RTFKeyword::OUTLINELEVEL:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue);
+ break;
+ case RTFKeyword::PROPTYPE:
+ {
+ switch (nParam)
+ {
+ case 3:
+ m_aStates.top().setPropType(cppu::UnoType<sal_Int32>::get());
+ break;
+ case 5:
+ m_aStates.top().setPropType(cppu::UnoType<double>::get());
+ break;
+ case 11:
+ m_aStates.top().setPropType(cppu::UnoType<bool>::get());
+ break;
+ case 30:
+ m_aStates.top().setPropType(cppu::UnoType<OUString>::get());
+ break;
+ case 64:
+ m_aStates.top().setPropType(cppu::UnoType<util::DateTime>::get());
+ break;
+ }
+ }
+ break;
+ case RTFKeyword::DIBITMAP:
+ m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP;
+ break;
+ case RTFKeyword::TRWWIDTHA:
+ m_aStates.top().setTableRowWidthAfter(nParam);
+ break;
+ case RTFKeyword::ANIMTEXT:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_TextEffect_none;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground;
+ break;
+ }
+
+ if (nId > 0)
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_effect,
+ new RTFValue(nId));
+ break;
+ }
+ case RTFKeyword::VIEWBKSP:
+ {
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue);
+ // Send this token immediately, if it only appears before the first
+ // run, it will be too late, we ignored the background shape already by then.
+ outputSettingsTable();
+ break;
+ }
+ case RTFKeyword::STEXTFLOW:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 0:
+ nId = NS_ooxml::LN_Value_ST_TextDirection_lrTb;
+ break;
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_TextDirection_tbRl;
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection,
+ new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::LBR:
+ {
+ Id nId = 0;
+ switch (nParam)
+ {
+ case 1:
+ nId = NS_ooxml::LN_Value_ST_BrClear_left;
+ break;
+ case 2:
+ nId = NS_ooxml::LN_Value_ST_BrClear_right;
+ break;
+ case 3:
+ nId = NS_ooxml::LN_Value_ST_BrClear_all;
+ break;
+ }
+
+ if (nId > 0)
+ {
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Br_clear,
+ new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::PGBRDROPT:
+ {
+ sal_Int16 nOffsetFrom = (nParam & 0xe0) >> 5;
+ bool bFromEdge = nOffsetFrom == 1;
+ if (bFromEdge)
+ {
+ Id nId = NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page;
+ putNestedAttribute(m_aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders,
+ NS_ooxml::LN_CT_PageBorders_offsetFrom, new RTFValue(nId));
+ }
+ }
+ break;
+ case RTFKeyword::TPOSY:
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_tblpY, new RTFValue(nParam));
+ }
+ break;
+ case RTFKeyword::TPOSX:
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_tblpX, new RTFValue(nParam));
+ }
+ break;
+ case RTFKeyword::TDFRMTXTLEFT:
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_leftFromText, new RTFValue(nParam));
+ }
+ break;
+ case RTFKeyword::TDFRMTXTRIGHT:
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_rightFromText, new RTFValue(nParam));
+ }
+ break;
+ case RTFKeyword::TDFRMTXTTOP:
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_topFromText, new RTFValue(nParam));
+ }
+ break;
+ case RTFKeyword::TDFRMTXTBOTTOM:
+ {
+ putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblpPr,
+ NS_ooxml::LN_CT_TblPPr_bottomFromText, new RTFValue(nParam));
+ }
+ 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/sw/source/writerfilter/rtftok/rtfdocumentfactory.cxx b/sw/source/writerfilter/rtftok/rtfdocumentfactory.cxx
new file mode 100644
index 000000000000..75b109b6842d
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx
new file mode 100644
index 000000000000..ab700ff0dc14
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfdocumentimpl.cxx
@@ -0,0 +1,4062 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfdocumentimpl.hxx"
+
+#include <algorithm>
+#include <memory>
+#include <string_view>
+
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XDependentTextField.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.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 <comphelper/diagnose_ex.hxx>
+#include <tools/globname.hxx>
+#include <tools/datetimeutils.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/embeddedobjectcontainer.hxx>
+#include <svl/lngmisc.hxx>
+#include <sfx2/classificationhelper.hxx>
+#include <oox/mathml/imexport.hxx>
+#include <ooxml/resourceids.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <rtl/uri.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <oox/helper/graphichelper.hxx>
+#include <vcl/wmfexternal.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include "rtfsdrimport.hxx"
+#include "rtfreferenceproperties.hxx"
+#include "rtfskipdestination.hxx"
+#include "rtftokenizer.hxx"
+#include "rtflookahead.hxx"
+#include "rtfcharsets.hxx"
+
+using namespace com::sun::star;
+
+namespace
+{
+/// Returns an util::DateTime from a 'YYYY. MM. DD.' string.
+util::DateTime getDateTimeFromUserProp(std::u16string_view rString)
+{
+ util::DateTime aRet;
+ size_t nLen = rString.size();
+ if (nLen >= 4)
+ {
+ aRet.Year = o3tl::toInt32(rString.substr(0, 4));
+
+ if (nLen >= 8 && o3tl::starts_with(rString.substr(4), u". "))
+ {
+ aRet.Month = o3tl::toInt32(rString.substr(6, 2));
+
+ if (nLen >= 12 && o3tl::starts_with(rString.substr(8), u". "))
+ aRet.Day = o3tl::toInt32(rString.substr(10, 2));
+ }
+ }
+ return aRet;
+}
+} // anonymous namespace
+
+namespace writerfilter::rtftok
+{
+Id getParagraphBorder(sal_uInt32 nIndex)
+{
+ static const Id aBorderIds[]
+ = { NS_ooxml::LN_CT_PBdr_top, NS_ooxml::LN_CT_PBdr_left, NS_ooxml::LN_CT_PBdr_bottom,
+ NS_ooxml::LN_CT_PBdr_right, NS_ooxml::LN_CT_PBdr_between };
+
+ return aBorderIds[nIndex];
+}
+
+void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite, bool bAttribute)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent, /*bFirst=*/true, /*bForWrite=*/true);
+ if (!pParent)
+ {
+ RTFSprms aAttributes;
+ if (nParent == NS_ooxml::LN_CT_TcPrBase_shd)
+ {
+ // RTF default is 'auto', see writerfilter::dmapper::CellColorHandler
+ aAttributes.set(NS_ooxml::LN_CT_Shd_color, new RTFValue(sal_uInt32(COL_AUTO)));
+ aAttributes.set(NS_ooxml::LN_CT_Shd_fill, new RTFValue(sal_uInt32(COL_AUTO)));
+ }
+ auto pParentValue = new RTFValue(aAttributes);
+ rSprms.set(nParent, pParentValue, eOverwrite);
+ pParent = pParentValue;
+ }
+ RTFSprms& rAttributes = (bAttribute ? pParent->getAttributes() : pParent->getSprms());
+ rAttributes.set(nId, pValue, eOverwrite);
+}
+
+void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite)
+{
+ putNestedAttribute(rSprms, nParent, nId, pValue, eOverwrite, false);
+}
+
+RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ return RTFValue::Pointer_t();
+ RTFSprms& rAttributes = pParent->getAttributes();
+ return rAttributes.find(nId);
+}
+
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ return RTFValue::Pointer_t();
+ RTFSprms& rInner = pParent->getSprms();
+ return rInner.find(nId);
+}
+
+bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId)
+{
+ RTFValue::Pointer_t pParent = rSprms.find(nParent);
+ if (!pParent)
+ // It doesn't even have a parent, we're done.
+ return false;
+ RTFSprms& rAttributes = pParent->getAttributes();
+ return rAttributes.erase(nId);
+}
+
+RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId)
+{
+ RTFValue::Pointer_t p = rSprms.find(nId);
+ if (p && !p->getSprms().empty())
+ return p->getSprms().back().second->getAttributes();
+
+ SAL_WARN("writerfilter.rtf", "trying to set property when no type is defined");
+ return rSprms;
+}
+
+void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue)
+{
+ RTFSprms* pAttributes = nullptr;
+ if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH_BOX)
+ for (int i = 0; i < 4; i++)
+ {
+ RTFValue::Pointer_t p = aStates.top().getParagraphSprms().find(getParagraphBorder(i));
+ if (p)
+ {
+ RTFSprms& rAttributes = p->getAttributes();
+ rAttributes.set(nId, pValue);
+ }
+ }
+ else if (aStates.top().getBorderState() == RTFBorderState::CHARACTER)
+ {
+ RTFValue::Pointer_t pPointer
+ = aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_RPrBase_bdr);
+ if (pPointer)
+ {
+ RTFSprms& rAttributes = pPointer->getAttributes();
+ rAttributes.set(nId, pValue);
+ }
+ }
+ // Attributes of the last border type
+ else if (aStates.top().getBorderState() == RTFBorderState::PARAGRAPH)
+ pAttributes
+ = &getLastAttributes(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr);
+ else if (aStates.top().getBorderState() == RTFBorderState::CELL)
+ pAttributes = &getLastAttributes(aStates.top().getTableCellSprms(),
+ NS_ooxml::LN_CT_TcPrBase_tcBorders);
+ else if (aStates.top().getBorderState() == RTFBorderState::PAGE)
+ pAttributes = &getLastAttributes(aStates.top().getSectionSprms(),
+ NS_ooxml::LN_EG_SectPrContents_pgBorders);
+ else if (aStates.top().getBorderState() == RTFBorderState::NONE)
+ {
+ // this is invalid, but Word apparently clears or overrides all paragraph borders now
+ for (int i = 0; i < 4; ++i)
+ {
+ auto const nBorder = getParagraphBorder(i);
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aAttributes.set(NS_ooxml::LN_CT_Border_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+ putNestedSprm(aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_pBdr, nBorder,
+ new RTFValue(aAttributes, aSprms), RTFOverwrite::YES);
+ }
+ }
+
+ if (pAttributes)
+ pAttributes->set(nId, pValue);
+}
+
+OString DTTM22OString(tools::Long nDTTM)
+{
+ return DateTimeToOString(msfilter::util::DTTM2DateTime(nDTTM));
+}
+
+static RTFSprms lcl_getBookmarkProperties(int nPos, const OUString& rString)
+{
+ RTFSprms aAttributes;
+ auto pPos = new RTFValue(nPos);
+ if (!rString.isEmpty())
+ {
+ // If present, this should be sent first.
+ auto pString = new RTFValue(rString);
+ aAttributes.set(NS_ooxml::LN_CT_Bookmark_name, pString);
+ }
+ aAttributes.set(NS_ooxml::LN_CT_MarkupRangeBookmark_id, pPos);
+ return aAttributes;
+}
+
+const char* keywordToString(RTFKeyword nKeyword)
+{
+ for (int i = 0; i < nRTFControlWords; i++)
+ {
+ if (nKeyword == aRTFControlWords[i].GetIndex())
+ return aRTFControlWords[i].GetKeyword();
+ }
+ return nullptr;
+}
+
+static util::DateTime lcl_getDateTime(RTFParserState const& aState)
+{
+ return { 0 /*100sec*/,
+ 0 /*sec*/,
+ aState.getMinute(),
+ aState.getHour(),
+ aState.getDay(),
+ aState.getMonth(),
+ static_cast<sal_Int16>(aState.getYear()),
+ false };
+}
+
+static void lcl_DestinationToMath(OUStringBuffer* pDestinationText,
+ oox::formulaimport::XmlStreamBuilder& rMathBuffer, bool& rMathNor)
+{
+ if (!pDestinationText)
+ return;
+ OUString aStr = pDestinationText->makeStringAndClear();
+ if (aStr.isEmpty())
+ return;
+ rMathBuffer.appendOpeningTag(M_TOKEN(r));
+ if (rMathNor)
+ {
+ rMathBuffer.appendOpeningTag(M_TOKEN(rPr));
+ // Same as M_TOKEN(lit)
+ rMathBuffer.appendOpeningTag(M_TOKEN(nor));
+ rMathBuffer.appendClosingTag(M_TOKEN(nor));
+ rMathBuffer.appendClosingTag(M_TOKEN(rPr));
+ rMathNor = false;
+ }
+ rMathBuffer.appendOpeningTag(M_TOKEN(t));
+ rMathBuffer.appendCharacters(aStr);
+ rMathBuffer.appendClosingTag(M_TOKEN(t));
+ rMathBuffer.appendClosingTag(M_TOKEN(r));
+}
+
+RTFDocumentImpl::RTFDocumentImpl(uno::Reference<uno::XComponentContext> const& xContext,
+ uno::Reference<io::XInputStream> const& xInputStream,
+ uno::Reference<lang::XComponent> const& xDstDoc,
+ uno::Reference<frame::XFrame> const& xFrame,
+ uno::Reference<task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor)
+ : m_xContext(xContext)
+ , m_xInputStream(xInputStream)
+ , m_xDstDoc(xDstDoc)
+ , m_xFrame(xFrame)
+ , m_xStatusIndicator(xStatusIndicator)
+ , m_pMapperStream(nullptr)
+ , m_aDefaultState(this)
+ , m_bSkipUnknown(false)
+ , m_bFirstRun(true)
+ , m_bFirstRunException(false)
+ , m_bNeedPap(true)
+ , m_bNeedCr(false)
+ , m_bNeedCrOrig(false)
+ , m_bNeedPar(true)
+ , m_bNeedFinalPar(false)
+ , m_nNestedCells(0)
+ , m_nTopLevelCells(0)
+ , m_nInheritingCells(0)
+ , m_nNestedTRLeft(0)
+ , m_nTopLevelTRLeft(0)
+ , m_nNestedCurrentCellX(0)
+ , m_nTopLevelCurrentCellX(0)
+ , m_nBackupTopLevelCurrentCellX(0)
+ , m_aTableBufferStack(1) // create top-level buffer already
+ , m_pSuperstream(nullptr)
+ , m_nStreamType(0)
+ , m_nGroupStartPos(0)
+ , m_nFormFieldType(RTFFormFieldType::NONE)
+ , m_bObject(false)
+ , m_nCurrentFontIndex(0)
+ , m_nCurrentEncoding(-1)
+ , m_nDefaultFontIndex(-1)
+ , m_pStyleTableEntries(new RTFReferenceTable::Entries_t)
+ , m_nCurrentStyleIndex(0)
+ , m_bFormField(false)
+ , m_bMathNor(false)
+ , m_bIgnoreNextContSectBreak(false)
+ , m_nResetBreakOnSectBreak(RTFKeyword::invalid)
+ , m_bNeedSect(false) // done by checkFirstRun
+ , m_bWasInFrame(false)
+ , m_bHadPicture(false)
+ , m_bHadSect(false)
+ , m_nCellxMax(0)
+ , m_nListPictureId(0)
+ , m_bIsNewDoc(!rMediaDescriptor.getUnpackedValueOrDefault("InsertMode", false))
+ , m_rMediaDescriptor(rMediaDescriptor)
+ , m_hasRHeader(false)
+ , m_hasFHeader(false)
+ , m_hasRFooter(false)
+ , m_hasFFooter(false)
+{
+ 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);
+
+ // unlike OOXML, this is enabled by default
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Compat_splitPgBreakAndParaMark, new RTFValue(1));
+}
+
+RTFDocumentImpl::~RTFDocumentImpl() = default;
+
+SvStream& RTFDocumentImpl::Strm() { return *m_pInStream; }
+
+void RTFDocumentImpl::setSuperstream(RTFDocumentImpl* pSuperstream)
+{
+ m_pSuperstream = pSuperstream;
+}
+
+bool RTFDocumentImpl::isSubstream() const { return m_pSuperstream != nullptr; }
+
+void RTFDocumentImpl::finishSubstream() { checkUnicode(/*bUnicode =*/true, /*bHex =*/true); }
+
+void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId)
+{
+ resolveSubstream(nPos, nId, OUString());
+}
+void RTFDocumentImpl::resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst)
+{
+ sal_uInt64 const nCurrent = Strm().Tell();
+ // Seek to header position, parse, then seek back.
+ auto pImpl = new RTFDocumentImpl(m_xContext, m_xInputStream, m_xDstDoc, m_xFrame,
+ m_xStatusIndicator, m_rMediaDescriptor);
+ pImpl->setSuperstream(this);
+ pImpl->m_nStreamType = nId;
+ pImpl->m_aIgnoreFirst = rIgnoreFirst;
+ if (!m_aAuthor.isEmpty())
+ {
+ pImpl->m_aAuthor = m_aAuthor;
+ m_aAuthor.clear();
+ }
+ if (!m_aAuthorInitials.isEmpty())
+ {
+ pImpl->m_aAuthorInitials = m_aAuthorInitials;
+ m_aAuthorInitials.clear();
+ }
+ pImpl->m_nDefaultFontIndex = m_nDefaultFontIndex;
+ pImpl->m_pStyleTableEntries = m_pStyleTableEntries;
+ pImpl->Strm().Seek(nPos);
+ SAL_INFO("writerfilter.rtf", "substream start");
+ Mapper().substream(nId, pImpl);
+ SAL_INFO("writerfilter.rtf", "substream end");
+ Strm().Seek(nCurrent);
+}
+
+void RTFDocumentImpl::outputSettingsTable()
+{
+ // tdf#136740: do not change target document settings when pasting
+ if (!m_bIsNewDoc || isSubstream())
+ return;
+ writerfilter::Reference<Properties>::Pointer_t pProp
+ = new RTFReferenceProperties(m_aSettingsTableAttributes, m_aSettingsTableSprms);
+ RTFReferenceTable::Entries_t aSettingsTableEntries;
+ aSettingsTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t pTable
+ = new RTFReferenceTable(std::move(aSettingsTableEntries));
+ Mapper().table(NS_ooxml::LN_settings_settings, pTable);
+}
+
+void RTFDocumentImpl::checkFirstRun()
+{
+ if (!m_bFirstRun)
+ return;
+
+ outputSettingsTable();
+ // start initial paragraph
+ m_bFirstRun = false;
+ assert(!m_bNeedSect || m_bFirstRunException);
+ setNeedSect(true); // first call that succeeds
+
+ // set the requested default font, if there are none for each state in stack
+ RTFValue::Pointer_t pFont
+ = getNestedAttribute(m_aDefaultState.getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pFont)
+ return;
+
+ for (size_t i = 0; i < m_aStates.size(); i++)
+ {
+ RTFValue::Pointer_t pCurrentFont
+ = getNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii);
+ if (!pCurrentFont)
+ putNestedAttribute(m_aStates[i].getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_rFonts,
+ NS_ooxml::LN_CT_Fonts_ascii, pFont);
+ }
+}
+
+void RTFDocumentImpl::setNeedPar(bool bNeedPar) { m_bNeedPar = bNeedPar; }
+
+void RTFDocumentImpl::setNeedSect(bool bNeedSect)
+{
+ if (!m_bNeedSect && bNeedSect && m_bFirstRun)
+ {
+ RTFLookahead aLookahead(Strm(), m_pTokenizer->getGroupStart());
+ if (aLookahead.hasTable() && aLookahead.hasColumns())
+ {
+ m_bFirstRunException = true;
+ }
+ }
+
+ // ignore setting before checkFirstRun - every keyword calls setNeedSect!
+ // except the case of a table in a multicolumn section
+ if (!m_bNeedSect && bNeedSect && (!m_bFirstRun || m_bFirstRunException))
+ {
+ if (!m_pSuperstream) // no sections in header/footer!
+ {
+ Mapper().startSectionGroup();
+ }
+ // set flag in substream too - otherwise multiple startParagraphGroup
+ m_bNeedSect = bNeedSect;
+ Mapper().startParagraphGroup();
+ setNeedPar(true);
+ }
+ else if (m_bNeedSect && !bNeedSect)
+ {
+ m_bNeedSect = bNeedSect;
+ }
+}
+
+/// Copy rProps to rStyleAttributes and rStyleSprms, but in case of nested sprms, copy their children as toplevel sprms/attributes.
+static void lcl_copyFlatten(RTFReferenceProperties& rProps, RTFSprms& rStyleAttributes,
+ RTFSprms& rStyleSprms)
+{
+ for (auto& rSprm : rProps.getSprms())
+ {
+ // createStyleProperties() puts properties to rPr, but here we need a flat list.
+ if (rSprm.first == NS_ooxml::LN_CT_Style_rPr)
+ {
+ // rPr can have both attributes and SPRMs, copy over both types.
+ RTFSprms& rRPrSprms = rSprm.second->getSprms();
+ for (const auto& rRPrSprm : rRPrSprms)
+ rStyleSprms.set(rRPrSprm.first, rRPrSprm.second);
+
+ RTFSprms& rRPrAttributes = rSprm.second->getAttributes();
+ for (const auto& rRPrAttribute : rRPrAttributes)
+ rStyleAttributes.set(rRPrAttribute.first, rRPrAttribute.second);
+ }
+ else
+ rStyleSprms.set(rSprm.first, rSprm.second);
+ }
+
+ RTFSprms& rAttributes = rProps.getAttributes();
+ for (const auto& rAttribute : rAttributes)
+ rStyleAttributes.set(rAttribute.first, rAttribute.second);
+}
+
+writerfilter::Reference<Properties>::Pointer_t
+RTFDocumentImpl::getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType)
+{
+ RTFSprms aSprms(rSprms);
+ RTFValue::Pointer_t pAbstractList;
+ int nAbstractListId = -1;
+ RTFValue::Pointer_t pNumId
+ = getNestedSprm(aSprms, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_numId);
+ if (pNumId)
+ {
+ // We have a numbering, look up the abstract list for property
+ // deduplication and duplication.
+ auto itNumId = m_aListOverrideTable.find(pNumId->getInt());
+ if (itNumId != m_aListOverrideTable.end())
+ {
+ nAbstractListId = itNumId->second;
+ auto itAbstract = m_aListTable.find(nAbstractListId);
+ if (itAbstract != m_aListTable.end())
+ pAbstractList = itAbstract->second;
+ }
+ }
+
+ if (pAbstractList)
+ {
+ auto it = m_aInvalidListTableFirstIndents.find(nAbstractListId);
+ if (it != m_aInvalidListTableFirstIndents.end())
+ aSprms.deduplicateList(it->second);
+ }
+
+ int nStyle = 0;
+ if (!m_aStates.empty())
+ nStyle = m_aStates.top().getCurrentStyleIndex();
+ auto it = m_pStyleTableEntries->find(nStyle);
+ if (it != m_pStyleTableEntries->end())
+ {
+ // cloneAndDeduplicate() wants to know about only a single "style", so
+ // let's merge paragraph and character style properties here.
+ auto itChar = m_pStyleTableEntries->end();
+ if (!m_aStates.empty())
+ {
+ int nCharStyle = m_aStates.top().getCurrentCharacterStyleIndex();
+ itChar = m_pStyleTableEntries->find(nCharStyle);
+ }
+
+ RTFSprms aStyleSprms;
+ RTFSprms aStyleAttributes;
+ // Ensure the paragraph style is a flat list.
+ // Take paragraph style into account for character properties as well,
+ // as paragraph style may contain character properties.
+ RTFReferenceProperties& rProps = *static_cast<RTFReferenceProperties*>(it->second.get());
+ lcl_copyFlatten(rProps, aStyleAttributes, aStyleSprms);
+
+ if (itChar != m_pStyleTableEntries->end())
+ {
+ // Found active character style, then update aStyleSprms/Attributes.
+ if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ RTFReferenceProperties& rCharProps
+ = *static_cast<RTFReferenceProperties*>(itChar->second.get());
+ lcl_copyFlatten(rCharProps, aStyleAttributes, aStyleSprms);
+ }
+ }
+
+ RTFSprms sprms(aSprms.cloneAndDeduplicate(aStyleSprms, nStyleType, true, &aSprms));
+ RTFSprms attributes(rAttributes.cloneAndDeduplicate(aStyleAttributes, nStyleType, true));
+ return new RTFReferenceProperties(std::move(attributes), std::move(sprms));
+ }
+
+ if (pAbstractList)
+ aSprms.duplicateList(pAbstractList);
+ writerfilter::Reference<Properties>::Pointer_t pRet
+ = new RTFReferenceProperties(rAttributes, std::move(aSprms));
+ return pRet;
+}
+
+void RTFDocumentImpl::checkNeedPap()
+{
+ if (!m_bNeedPap)
+ return;
+
+ m_bNeedPap = false; // reset early, so we can avoid recursion when calling ourselves
+
+ if (m_aStates.empty())
+ return;
+
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t const pParagraphProperties(getProperties(
+ m_aStates.top().getParagraphAttributes(), m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_Value_ST_StyleType_paragraph));
+
+ // Writer will ignore a page break before a text frame, so guard it with empty paragraphs
+ const bool bIsInFrame = m_aStates.top().getFrame().hasProperties();
+ bool hasBreakBeforeFrame
+ = bIsInFrame
+ && m_aStates.top().getParagraphSprms().find(NS_ooxml::LN_CT_PPrBase_pageBreakBefore);
+ if (hasBreakBeforeFrame)
+ {
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedPap = false;
+ }
+ Mapper().props(pParagraphProperties);
+ if (hasBreakBeforeFrame)
+ dispatchSymbol(RTFKeyword::PAR);
+
+ if (bIsInFrame)
+ {
+ 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,
+ NS_ooxml::LN_Value_ST_StyleType_character);
+ }
+
+ // 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_Unicode const sBreak[] = { 0x0d };
+ Mapper().utext(sBreak, 1);
+ m_bNeedCr = false;
+}
+
+void RTFDocumentImpl::tableBreak()
+{
+ checkFirstRun(); // ooo113308-1.rtf has a header at offset 151084 that doesn't startParagraphGroup() without this
+ 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
+ if (!m_bParAtEndOfSection)
+ {
+ Mapper().startParagraphGroup();
+ }
+}
+
+void RTFDocumentImpl::sectBreak(bool bFinal)
+{
+ SAL_INFO("writerfilter.rtf", __func__ << ": final? " << bFinal << ", needed? " << m_bNeedSect);
+ bool bNeedSect = m_bNeedSect;
+ RTFValue::Pointer_t pBreak
+ = m_aStates.top().getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ bool bContinuous = pBreak && pBreak->getInt() == NS_ooxml::LN_Value_ST_SectionMark_continuous;
+ // If there is no paragraph in this section, then insert a dummy one, as required by Writer,
+ // unless this is the end of the doc, we had nothing since the last section break and this is not a continuous one.
+ // Also, when pasting, it's fine to not have any paragraph inside the document at all.
+ if (m_bNeedPar && (!bFinal || m_bNeedSect || bContinuous) && !isSubstream() && m_bIsNewDoc)
+ {
+ m_bParAtEndOfSection = true;
+ dispatchSymbol(RTFKeyword::PAR);
+ }
+ // It's allowed to not have a non-table paragraph at the end of an RTF doc, add it now if required.
+ if (m_bNeedFinalPar && bFinal)
+ {
+ dispatchFlag(RTFKeyword::PARD);
+ m_bParAtEndOfSection = true;
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedSect = bNeedSect;
+ }
+ // testTdf148515, if RTF ends with \row, endParagraphGroup() must be called!
+ if (!m_bParAtEndOfSection || m_aStates.top().getCurrentBuffer())
+ {
+ Mapper().endParagraphGroup(); // < top para context dies with page break
+ }
+ m_bParAtEndOfSection = false;
+ // paragraph properties are *done* now - only section properties following
+
+ while (!m_nHeaderFooterPositions.empty())
+ {
+ std::pair<Id, std::size_t> aPair = m_nHeaderFooterPositions.front();
+ m_nHeaderFooterPositions.pop();
+ resolveSubstream(aPair.second, aPair.first);
+ }
+
+ // Normally a section break at the end of the doc is necessary. Unless the
+ // last control word in the document is a section break itself.
+ if (!bNeedSect || !m_bHadSect)
+ {
+ // In case the last section is a continuous one, we don't need to output a section break.
+ if (bFinal && bContinuous)
+ m_aStates.top().getSectionSprms().erase(NS_ooxml::LN_EG_SectPrContents_type);
+ }
+
+ // Section properties are a paragraph sprm.
+ auto pValue
+ = new RTFValue(m_aStates.top().getSectionAttributes(), m_aStates.top().getSectionSprms());
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_CT_PPr_sectPr, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+
+ if (bFinal && !m_pSuperstream)
+ // This is the end of the document, not just the end of e.g. a header.
+ // This makes sure that dmapper can set DontBalanceTextColumns=true for this section if necessary.
+ Mapper().markLastSectionGroup();
+
+ // The trick is that we send properties of the previous section right now, which will be exactly what dmapper expects.
+ Mapper().props(pProperties);
+
+ // 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;
+ auto it = m_aStyleNames.find(nIndex);
+ if (it != m_aStyleNames.end())
+ aRet = it->second;
+ return aRet;
+ }
+
+ return m_pSuperstream->getStyleName(nIndex);
+}
+
+Id RTFDocumentImpl::getStyleType(int nIndex)
+{
+ if (!m_pSuperstream)
+ {
+ Id nRet = 0;
+ auto it = m_aStyleTypes.find(nIndex);
+ if (it != m_aStyleTypes.end())
+ nRet = it->second;
+ 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.
+ auto& rDestinationTextBuffer = m_aStates.top().getDestinationText();
+ OString aStr = OUStringToOString(rDestinationTextBuffer, RTL_TEXTENCODING_ASCII_US);
+ rDestinationTextBuffer.setLength(0);
+ for (int i = 0; i < aStr.getLength(); ++i)
+ {
+ char ch = aStr[i];
+ if (ch != 0x0d && ch != 0x0a && ch != 0x20)
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return;
+ b += parsed;
+ count--;
+ if (!count)
+ {
+ aStream.WriteChar(static_cast<char>(b));
+ count = 2;
+ b = 0;
+ }
+ }
+ }
+ }
+ else
+ pStream = m_pBinaryData.get();
+
+ if (!pStream->Tell())
+ // No destination text? Then we'll get it later.
+ return;
+
+ SvMemoryStream aDIBStream;
+ if (m_aStates.top().getPicture().eStyle == RTFBmpStyle::DIBITMAP)
+ {
+ // Construct a BITMAPFILEHEADER structure before the real data.
+ SvStream& rBodyStream = *pStream;
+ aDIBStream.WriteChar('B');
+ aDIBStream.WriteChar('M');
+ // The size of the real data.
+ aDIBStream.WriteUInt32(rBodyStream.Tell());
+ // Reserved.
+ aDIBStream.WriteUInt32(0);
+ // The offset of the real data, i.e. the size of the header, including this number.
+ aDIBStream.WriteUInt32(14);
+ rBodyStream.Seek(0);
+ aDIBStream.WriteStream(rBodyStream);
+ pStream = &aDIBStream;
+ }
+
+ // Store, and get its URL.
+ pStream->Seek(0);
+ uno::Reference<io::XInputStream> xInputStream(new utl::OInputStreamWrapper(pStream));
+ WmfExternal aExtHeader;
+ aExtHeader.mapMode = m_aStates.top().getPicture().eWMetafile;
+ if (m_aStates.top().getPicture().nGoalWidth == 0
+ || m_aStates.top().getPicture().nGoalHeight == 0)
+ {
+ // Don't use the values provided by picw and pich if the desired size is provided.
+
+ aExtHeader.xExt = sal_uInt16(std::clamp<sal_Int32>(
+ m_aStates.top().getPicture().nWidth, 0,
+ SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
+ aExtHeader.yExt = sal_uInt16(std::clamp<sal_Int32>(
+ m_aStates.top().getPicture().nHeight, 0,
+ SAL_MAX_UINT16)); //TODO: better way to handle out-of-bounds values?
+ }
+ WmfExternal* pExtHeader = &aExtHeader;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(m_aStates.top().getDrawingObject().getShape(),
+ uno::UNO_QUERY);
+ if (xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ pExtHeader = nullptr;
+
+ uno::Reference<graphic::XGraphic> xGraphic
+ = m_pGraphicHelper->importGraphic(xInputStream, pExtHeader);
+
+ if (m_aStates.top().getPicture().eStyle != RTFBmpStyle::NONE)
+ {
+ // In case of PNG/JPEG, the real size is known, don't use the values
+ // provided by picw and pich.
+
+ Graphic aGraphic(xGraphic);
+ Size aSize(aGraphic.GetPrefSize());
+ MapMode aMap(MapUnit::Map100thMM);
+ if (aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMap);
+ else
+ aSize = OutputDevice::LogicToLogic(aSize, aGraphic.GetPrefMapMode(), aMap);
+ m_aStates.top().getPicture().nWidth = aSize.Width();
+ m_aStates.top().getPicture().nHeight = aSize.Height();
+ }
+
+ uno::Reference<drawing::XShape> xShape(rShape);
+ if (m_aStates.top().getInShape() && xShape.is())
+ {
+ awt::Size aSize = xShape->getSize();
+ if (aSize.Width || aSize.Height)
+ {
+ // resolvePict() is processing pib structure inside shape
+ // So if shape has dimensions we should use them instead of
+ // \picwN, \pichN, \picscalexN, \picscaleyN given with picture
+ m_aStates.top().getPicture().nGoalWidth = aSize.Width;
+ m_aStates.top().getPicture().nGoalHeight = aSize.Height;
+ m_aStates.top().getPicture().nScaleX = 100;
+ m_aStates.top().getPicture().nScaleY = 100;
+ }
+ }
+
+ // Wrap it in an XShape.
+ if (xShape.is())
+ {
+ uno::Reference<lang::XServiceInfo> xSI(xShape, uno::UNO_QUERY_THROW);
+ if (!xSI->supportsService("com.sun.star.drawing.GraphicObjectShape"))
+ {
+ // it's sometimes an error to get here - but it's possible to have
+ // a \pict inside the \shptxt of a \shp of shapeType 202 "TextBox"
+ // and in that case xShape is the text frame; we actually need a
+ // new GraphicObject then (example: fdo37691-1.rtf)
+ SAL_INFO("writerfilter.rtf",
+ "cannot set graphic on existing shape, creating a new GraphicObjectShape");
+ xShape.clear();
+ }
+ }
+ if (!xShape.is())
+ {
+ if (m_xModelFactory.is())
+ xShape.set(m_xModelFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"),
+ uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPageSupplier> const xDrawSupplier(m_xDstDoc, uno::UNO_QUERY);
+ if (xDrawSupplier.is())
+ {
+ uno::Reference<drawing::XShapes> xShapes = xDrawSupplier->getDrawPage();
+ if (xShapes.is())
+ xShapes->add(xShape);
+ }
+ }
+
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("Graphic", uno::Any(xGraphic));
+
+ // check if the picture is in an OLE object and if the \objdata element is used
+ // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
+ if (m_bObject)
+ {
+ // Set the object size
+ awt::Size aSize;
+ aSize.Width
+ = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
+ : m_aStates.top().getPicture().nWidth);
+ aSize.Height
+ = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
+ : m_aStates.top().getPicture().nHeight);
+ xShape->setSize(aSize);
+
+ // Replacement graphic is inline by default, see oox::vml::SimpleShape::implConvertAndInsert().
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+
+ auto pShapeValue = new RTFValue(xShape);
+ m_aObjectAttributes.set(NS_ooxml::LN_shape, pShapeValue);
+ return;
+ }
+
+ if (m_aStates.top().getInListpicture())
+ {
+ // Send the shape directly, no section is started, to additional properties will be ignored anyway.
+ Mapper().startShape(xShape);
+ Mapper().endShape();
+ return;
+ }
+
+ // Send it to the dmapper.
+ RTFSprms aSprms;
+ RTFSprms aAttributes;
+ // shape attribute
+ RTFSprms aPicAttributes;
+ if (m_aStates.top().getPicture().nCropT != 0 || m_aStates.top().getPicture().nCropB != 0
+ || m_aStates.top().getPicture().nCropL != 0 || m_aStates.top().getPicture().nCropR != 0)
+ {
+ text::GraphicCrop const crop{ m_aStates.top().getPicture().nCropT,
+ m_aStates.top().getPicture().nCropB,
+ m_aStates.top().getPicture().nCropL,
+ m_aStates.top().getPicture().nCropR };
+ auto const pCrop = new RTFValue(crop);
+ aPicAttributes.set(NS_ooxml::LN_CT_BlipFillProperties_srcRect, pCrop);
+ }
+ auto pShapeValue = new RTFValue(xShape);
+ aPicAttributes.set(NS_ooxml::LN_shape, pShapeValue);
+ // pic sprm
+ RTFSprms aGraphicDataAttributes;
+ RTFSprms aGraphicDataSprms;
+ auto pPicValue = new RTFValue(aPicAttributes);
+ aGraphicDataSprms.set(NS_ooxml::LN_pic_pic, pPicValue);
+ // graphicData sprm
+ RTFSprms aGraphicAttributes;
+ RTFSprms aGraphicSprms;
+ auto pGraphicDataValue = new RTFValue(aGraphicDataAttributes, aGraphicDataSprms);
+ aGraphicSprms.set(NS_ooxml::LN_CT_GraphicalObject_graphicData, pGraphicDataValue);
+ // graphic sprm
+ auto pGraphicValue = new RTFValue(aGraphicAttributes, aGraphicSprms);
+ // extent sprm
+ RTFSprms aExtentAttributes;
+ int nXExt = (m_aStates.top().getPicture().nGoalWidth ? m_aStates.top().getPicture().nGoalWidth
+ : m_aStates.top().getPicture().nWidth);
+ int nYExt = (m_aStates.top().getPicture().nGoalHeight ? m_aStates.top().getPicture().nGoalHeight
+ : m_aStates.top().getPicture().nHeight);
+ if (m_aStates.top().getPicture().nScaleX != 100)
+ nXExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleX)
+ * (nXExt
+ - (m_aStates.top().getPicture().nCropL + m_aStates.top().getPicture().nCropR)))
+ / 100L;
+ if (m_aStates.top().getPicture().nScaleY != 100)
+ nYExt = (static_cast<tools::Long>(m_aStates.top().getPicture().nScaleY)
+ * (nYExt
+ - (m_aStates.top().getPicture().nCropT + m_aStates.top().getPicture().nCropB)))
+ / 100L;
+ auto pXExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nXExt));
+ auto pYExtValue = new RTFValue(oox::drawingml::convertHmmToEmu(nYExt));
+ aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cx, pXExtValue);
+ aExtentAttributes.set(NS_ooxml::LN_CT_PositiveSize2D_cy, pYExtValue);
+ auto pExtentValue = new RTFValue(aExtentAttributes);
+ // docpr sprm
+ RTFSprms aDocprAttributes;
+ for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
+ if (rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_name
+ || rCharacterAttribute.first == NS_ooxml::LN_CT_NonVisualDrawingProps_descr)
+ aDocprAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
+ auto pDocprValue = new RTFValue(aDocprAttributes);
+ if (bInline)
+ {
+ RTFSprms aInlineAttributes;
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distT, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distB, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distL, new RTFValue(0));
+ aInlineAttributes.set(NS_ooxml::LN_CT_Inline_distR, new RTFValue(0));
+ RTFSprms aInlineSprms;
+ aInlineSprms.set(NS_ooxml::LN_CT_Inline_extent, pExtentValue);
+ aInlineSprms.set(NS_ooxml::LN_CT_Inline_docPr, pDocprValue);
+ aInlineSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
+ // inline sprm
+ auto pValue = new RTFValue(aInlineAttributes, aInlineSprms);
+ aSprms.set(NS_ooxml::LN_inline_inline, pValue);
+ }
+ else // anchored
+ {
+ // wrap sprm
+ RTFSprms aAnchorWrapAttributes;
+ m_aStates.top().getShape().getAnchorAttributes().set(
+ NS_ooxml::LN_CT_Anchor_behindDoc,
+ new RTFValue((m_aStates.top().getShape().getInBackground()) ? 1 : 0));
+ RTFSprms aAnchorSprms;
+ for (const auto& rCharacterAttribute : m_aStates.top().getCharacterAttributes())
+ {
+ if (rCharacterAttribute.first == NS_ooxml::LN_CT_WrapSquare_wrapText)
+ aAnchorWrapAttributes.set(rCharacterAttribute.first, rCharacterAttribute.second);
+ }
+ sal_Int32 nWrap = -1;
+ for (auto& rCharacterSprm : m_aStates.top().getCharacterSprms())
+ {
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapNone
+ || rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight)
+ {
+ nWrap = rCharacterSprm.first;
+
+ // If there is a wrap polygon prepared by RTFSdrImport, pick it up here.
+ if (rCharacterSprm.first == NS_ooxml::LN_EG_WrapType_wrapTight
+ && !m_aStates.top().getShape().getWrapPolygonSprms().empty())
+ rCharacterSprm.second->getSprms().set(
+ NS_ooxml::LN_CT_WrapTight_wrapPolygon,
+ new RTFValue(RTFSprms(), m_aStates.top().getShape().getWrapPolygonSprms()));
+
+ aAnchorSprms.set(rCharacterSprm.first, rCharacterSprm.second);
+ }
+ }
+
+ if (m_aStates.top().getShape().getWrapSprm().first != 0)
+ // Replay of a buffered shape, wrap sprm there has priority over
+ // character sprms of the current state.
+ aAnchorSprms.set(m_aStates.top().getShape().getWrapSprm().first,
+ m_aStates.top().getShape().getWrapSprm().second);
+
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_extent, pExtentValue);
+ if (!aAnchorWrapAttributes.empty() && nWrap == -1)
+ aAnchorSprms.set(NS_ooxml::LN_EG_WrapType_wrapSquare,
+ new RTFValue(aAnchorWrapAttributes));
+
+ // See OOXMLFastContextHandler::positionOffset(), we can't just put offset values in an RTFValue.
+ RTFSprms aPoshAttributes;
+ RTFSprms aPoshSprms;
+ if (m_aStates.top().getShape().getHoriOrientRelationToken() > 0)
+ aPoshAttributes.set(
+ NS_ooxml::LN_CT_PosH_relativeFrom,
+ new RTFValue(m_aStates.top().getShape().getHoriOrientRelationToken()));
+ if (m_aStates.top().getShape().getLeft() != 0)
+ {
+ Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
+ m_aStates.top().getShape().getLeft())),
+ /*bVertical=*/false);
+ aPoshSprms.set(NS_ooxml::LN_CT_PosH_posOffset, new RTFValue());
+ }
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionH,
+ new RTFValue(aPoshAttributes, aPoshSprms));
+
+ RTFSprms aPosvAttributes;
+ RTFSprms aPosvSprms;
+ if (m_aStates.top().getShape().getVertOrientRelationToken() > 0)
+ aPosvAttributes.set(
+ NS_ooxml::LN_CT_PosV_relativeFrom,
+ new RTFValue(m_aStates.top().getShape().getVertOrientRelationToken()));
+ if (m_aStates.top().getShape().getTop() != 0)
+ {
+ Mapper().positionOffset(OUString::number(oox::drawingml::convertHmmToEmu(
+ m_aStates.top().getShape().getTop())),
+ /*bVertical=*/true);
+ aPosvSprms.set(NS_ooxml::LN_CT_PosV_posOffset, new RTFValue());
+ }
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_positionV,
+ new RTFValue(aPosvAttributes, aPosvSprms));
+
+ aAnchorSprms.set(NS_ooxml::LN_CT_Anchor_docPr, pDocprValue);
+ aAnchorSprms.set(NS_ooxml::LN_graphic_graphic, pGraphicValue);
+ // anchor sprm
+ auto pValue = new RTFValue(m_aStates.top().getShape().getAnchorAttributes(), aAnchorSprms);
+ aSprms.set(NS_ooxml::LN_anchor_anchor, pValue);
+ }
+ checkFirstRun();
+
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms));
+ Mapper().props(pProperties);
+ // Make sure we don't lose these properties with a too early reset.
+ m_bHadPicture = true;
+ }
+ else
+ {
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue, nullptr);
+ }
+}
+
+RTFError RTFDocumentImpl::resolveChars(char ch)
+{
+ if (m_aStates.top().getInternalState() == RTFInternalState::BIN)
+ {
+ m_pBinaryData = std::make_shared<SvMemoryStream>();
+ m_pBinaryData->WriteChar(ch);
+ for (int i = 0; i < m_aStates.top().getBinaryToRead() - 1; ++i)
+ {
+ Strm().ReadChar(ch);
+ m_pBinaryData->WriteChar(ch);
+ }
+ m_aStates.top().setInternalState(RTFInternalState::NORMAL);
+ return RTFError::OK;
+ }
+
+ OStringBuffer aBuf(512);
+
+ bool bUnicodeChecked = false;
+ bool bSkipped = false;
+
+ while (!Strm().eof()
+ && (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ || (ch != '{' && ch != '}' && ch != '\\')))
+ {
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ || (ch != 0x0d && ch != 0x0a))
+ {
+ if (m_aStates.top().getCharsToSkip() == 0)
+ {
+ if (!bUnicodeChecked)
+ {
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/false);
+ bUnicodeChecked = true;
+ }
+ aBuf.append(ch);
+ }
+ else
+ {
+ bSkipped = true;
+ m_aStates.top().getCharsToSkip()--;
+ }
+ }
+
+ // read a single char if we're in hex mode
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX)
+ break;
+
+ if (RTL_TEXTENCODING_MS_932 == m_aStates.top().getCurrentEncoding())
+ {
+ unsigned char uch = ch;
+ if ((uch >= 0x80 && uch <= 0x9F) || uch >= 0xE0)
+ {
+ // read second byte of 2-byte Shift-JIS - may be \ { }
+ Strm().ReadChar(ch);
+ if (m_aStates.top().getCharsToSkip() == 0)
+ {
+ // fdo#79384: Word will reject Shift-JIS following \loch
+ // but apparently OOo could read and (worse) write such documents
+ SAL_INFO_IF(m_aStates.top().getRunType() != RTFParserState::RunType::DBCH,
+ "writerfilter.rtf", "invalid Shift-JIS without DBCH");
+ assert(bUnicodeChecked);
+ aBuf.append(ch);
+ }
+ else
+ {
+ assert(bSkipped);
+ // anybody who uses \ucN with Shift-JIS is insane
+ m_aStates.top().getCharsToSkip()--;
+ }
+ }
+ }
+
+ Strm().ReadChar(ch);
+ }
+ if (m_aStates.top().getInternalState() != RTFInternalState::HEX && !Strm().eof())
+ Strm().SeekRel(-1);
+
+ if (m_aStates.top().getInternalState() == RTFInternalState::HEX
+ && m_aStates.top().getDestination() != Destination::LEVELNUMBERS)
+ {
+ if (!bSkipped)
+ {
+ // note: apparently \'0d\'0a is interpreted as 2 breaks, not 1
+ if ((ch == '\r' || ch == '\n')
+ && m_aStates.top().getDestination() != Destination::DOCCOMM
+ && m_aStates.top().getDestination() != Destination::LEVELNUMBERS
+ && m_aStates.top().getDestination() != Destination::LEVELTEXT)
+ {
+ checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
+ dispatchSymbol(RTFKeyword::PAR);
+ }
+ else
+ {
+ m_aHexBuffer.append(ch);
+ }
+ }
+ return RTFError::OK;
+ }
+
+ if (m_aStates.top().getDestination() == Destination::SKIP)
+ return RTFError::OK;
+ OString aStr = aBuf.makeStringAndClear();
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS)
+ {
+ if (aStr.toChar() != ';')
+ m_aStates.top().getLevelNumbers().push_back(sal_Int32(ch));
+ return RTFError::OK;
+ }
+
+ SAL_INFO("writerfilter.rtf",
+ "RTFDocumentImpl::resolveChars: collected '"
+ << OStringToOUString(aStr, m_aStates.top().getCurrentEncoding()) << "'");
+
+ if (m_aStates.top().getDestination() == Destination::COLORTABLE)
+ {
+ // we hit a ';' at the end of each color entry
+ m_aColorTable.push_back(m_aStates.top().getCurrentColor().GetColor());
+ // set components back to zero
+ m_aStates.top().getCurrentColor() = RTFColorTableEntry();
+ }
+ else if (!aStr.isEmpty())
+ m_aHexBuffer.append(aStr);
+
+ checkUnicode(/*bUnicode =*/false, /*bHex =*/true);
+ return RTFError::OK;
+}
+
+void RTFDocumentImpl::singleChar(sal_uInt8 nValue, bool bRunProps)
+{
+ sal_uInt8 sValue[] = { nValue };
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+
+ if (!pCurrentBuffer)
+ {
+ Mapper().startCharacterGroup();
+ }
+ else
+ {
+ pCurrentBuffer->emplace_back(BUFFER_STARTRUN, nullptr, nullptr);
+ }
+
+ // Should we send run properties?
+ if (bRunProps)
+ runProps();
+
+ if (!pCurrentBuffer)
+ {
+ Mapper().text(sValue, 1);
+ Mapper().endCharacterGroup();
+ }
+ else
+ {
+ auto pValue = new RTFValue(*sValue);
+ pCurrentBuffer->emplace_back(BUFFER_TEXT, pValue, nullptr);
+ pCurrentBuffer->emplace_back(BUFFER_ENDRUN, nullptr, nullptr);
+ }
+}
+
+void RTFDocumentImpl::handleFontTableEntry()
+{
+ OUString aName = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ if (aName.isEmpty())
+ return;
+
+ if (aName.endsWith(";"))
+ {
+ aName = aName.copy(0, aName.getLength() - 1);
+ }
+
+ // Old documents can contain no encoding information in fontinfo,
+ // but there can be font name suffixes: Arial CE is not a special
+ // font, it is ordinal Arial, but with used cp 1250 encoding.
+ // Moreover these suffixes have priority over \cpgN and \fcharsetN
+ // in MS Word.
+ OUString aFontSuffix;
+ OUString aNameNoSuffix(aName);
+ sal_Int32 nLastSpace = aName.lastIndexOf(' ');
+ if (nLastSpace >= 0)
+ {
+ aFontSuffix = aName.copy(nLastSpace + 1);
+ aNameNoSuffix = aName.copy(0, nLastSpace);
+ sal_Int32 nEncoding = RTL_TEXTENCODING_DONTKNOW;
+ for (int i = 0; aRTFFontNameSuffixes[i].codepage != RTL_TEXTENCODING_DONTKNOW; i++)
+ {
+ if (aFontSuffix.equalsAscii(aRTFFontNameSuffixes[i].suffix))
+ {
+ nEncoding = aRTFFontNameSuffixes[i].codepage;
+ break;
+ }
+ }
+ if (nEncoding > RTL_TEXTENCODING_DONTKNOW)
+ {
+ m_nCurrentEncoding = nEncoding;
+ m_aStates.top().setCurrentEncoding(m_nCurrentEncoding);
+ }
+ else
+ {
+ // Unknown suffix: looks like it is just a part of font name, restore it
+ aNameNoSuffix = aName;
+ }
+ }
+
+ m_aFontNames[m_nCurrentFontIndex] = aNameNoSuffix;
+ if (m_nCurrentEncoding >= 0)
+ {
+ m_aFontEncodings[m_nCurrentFontIndex] = m_nCurrentEncoding;
+ m_nCurrentEncoding = -1;
+ }
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Font_name,
+ new RTFValue(aNameNoSuffix));
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+
+ //See fdo#47347 initial invalid font entry properties are inserted first,
+ //so when we attempt to insert the correct ones, there's already an
+ //entry in the map for them, so the new ones aren't inserted.
+ auto lb = m_aFontTableEntries.lower_bound(m_nCurrentFontIndex);
+ if (lb != m_aFontTableEntries.end()
+ && !(m_aFontTableEntries.key_comp()(m_nCurrentFontIndex, lb->first)))
+ lb->second = pProp;
+ else
+ m_aFontTableEntries.insert(lb, std::make_pair(m_nCurrentFontIndex, pProp));
+}
+
+void RTFDocumentImpl::text(OUString& rString)
+{
+ if (rString.getLength() == 1 && m_aStates.top().getDestination() != Destination::DOCCOMM)
+ {
+ // No cheating! Tokenizer ignores bare \r and \n, their hex \'0d / \'0a form doesn't count, either.
+ sal_Unicode ch = rString[0];
+ if (ch == 0x0d || ch == 0x0a)
+ return;
+ }
+
+ bool bRet = true;
+ switch (m_aStates.top().getDestination())
+ {
+ // Note: in stylesheet and revtbl groups are mandatory
+ case Destination::STYLEENTRY:
+ case Destination::LISTNAME:
+ case Destination::REVISIONENTRY:
+ {
+ // ; is the end of the entry
+ bool bEnd = false;
+ if (rString.endsWith(";"))
+ {
+ rString = rString.copy(0, rString.getLength() - 1);
+ bEnd = true;
+ }
+ m_aStates.top().appendDestinationText(rString);
+ if (bEnd)
+ {
+ // always clear, necessary in case of group-less fonttable
+ OUString const aName
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ switch (m_aStates.top().getDestination())
+ {
+ case Destination::STYLEENTRY:
+ {
+ RTFValue::Pointer_t pType
+ = m_aStates.top().getTableAttributes().find(NS_ooxml::LN_CT_Style_type);
+ if (pType)
+ {
+ // Word strips whitespace around style names.
+ m_aStyleNames[m_nCurrentStyleIndex] = aName.trim();
+ m_aStyleTypes[m_nCurrentStyleIndex] = pType->getInt();
+ auto pValue = new RTFValue(aName.trim());
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_styleId,
+ pValue);
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_name, pValue);
+
+ writerfilter::Reference<Properties>::Pointer_t const pProp(
+ createStyleProperties());
+ m_pStyleTableEntries->insert(
+ std::make_pair(m_nCurrentStyleIndex, pProp));
+ }
+ else
+ SAL_INFO("writerfilter.rtf", "no RTF style type defined, ignoring");
+ break;
+ }
+ case Destination::LISTNAME:
+ // TODO: what can be done with a list name?
+ break;
+ case Destination::REVISIONENTRY:
+ m_aAuthors[m_aAuthors.size()] = aName;
+ break;
+ default:
+ break;
+ }
+ resetAttributes();
+ resetSprms();
+ }
+ }
+ break;
+ case Destination::DOCVAR:
+ {
+ m_aStates.top().appendDocVar(rString);
+ }
+ break;
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
+ case Destination::LEVELTEXT:
+ case Destination::SHAPEPROPERTYNAME:
+ case Destination::SHAPEPROPERTYVALUE:
+ case Destination::BOOKMARKEND:
+ case Destination::PICT:
+ case Destination::SHAPEPROPERTYVALUEPICT:
+ case Destination::FORMFIELDNAME:
+ case Destination::FORMFIELDLIST:
+ case Destination::DATAFIELD:
+ case Destination::AUTHOR:
+ case Destination::KEYWORDS:
+ case Destination::OPERATOR:
+ case Destination::COMPANY:
+ case Destination::COMMENT:
+ case Destination::OBJDATA:
+ case Destination::OBJCLASS:
+ case Destination::ANNOTATIONDATE:
+ case Destination::ANNOTATIONAUTHOR:
+ case Destination::ANNOTATIONREFERENCE:
+ case Destination::FALT:
+ case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
+ case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
+ case Destination::TITLE:
+ case Destination::SUBJECT:
+ case Destination::DOCCOMM:
+ case Destination::ATNID:
+ case Destination::ANNOTATIONREFERENCESTART:
+ case Destination::ANNOTATIONREFERENCEEND:
+ case Destination::MR:
+ case Destination::MCHR:
+ case Destination::MPOS:
+ case Destination::MVERTJC:
+ case Destination::MSTRIKEH:
+ case Destination::MDEGHIDE:
+ case Destination::MBEGCHR:
+ case Destination::MSEPCHR:
+ case Destination::MENDCHR:
+ case Destination::MSUBHIDE:
+ case Destination::MSUPHIDE:
+ case Destination::MTYPE:
+ case Destination::MGROW:
+ case Destination::INDEXENTRY:
+ case Destination::TOCENTRY:
+ case Destination::PROPNAME:
+ case Destination::STATICVAL:
+ m_aStates.top().appendDestinationText(rString);
+ break;
+ case Destination::GENERATOR:
+ // don't enlarge space sequences, eg. it was saved in LibreOffice
+ if (!rString.startsWithIgnoreAsciiCase("Microsoft"))
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence,
+ new RTFValue(0));
+ break;
+ default:
+ bRet = false;
+ break;
+ }
+ if (bRet)
+ return;
+
+ if (!m_aIgnoreFirst.isEmpty() && m_aIgnoreFirst == rString)
+ {
+ m_aIgnoreFirst.clear();
+ return;
+ }
+
+ // Are we in the middle of the table definition? (No cell defs yet, but we already have some cell props.)
+ if (m_aStates.top().getTableCellSprms().find(NS_ooxml::LN_CT_TcPrBase_vAlign)
+ && m_nTopLevelCells == 0)
+ {
+ m_aTableBufferStack.back().emplace_back(BUFFER_UTEXT, new RTFValue(rString), nullptr);
+ return;
+ }
+
+ checkFirstRun();
+ checkNeedPap();
+
+ // Don't return earlier, a bookmark start has to be in a paragraph group.
+ if (m_aStates.top().getDestination() == Destination::BOOKMARKSTART)
+ {
+ m_aStates.top().appendDestinationText(rString);
+ return;
+ }
+
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+
+ if (!pCurrentBuffer && m_aStates.top().getDestination() != Destination::FOOTNOTE)
+ Mapper().startCharacterGroup();
+ else if (pCurrentBuffer)
+ {
+ RTFValue::Pointer_t pValue;
+ pCurrentBuffer->emplace_back(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(rString.getStr(), rString.getLength());
+ else
+ {
+ auto pValue = new RTFValue(rString);
+ pCurrentBuffer->emplace_back(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->emplace_back(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>& rCellsSprms,
+ ::std::deque<RTFSprms>& rCellsAttributes, int const nCells)
+{
+ for (int i = 0; i < nCells; ++i)
+ {
+ replayBuffer(rBuffer, &rCellsSprms.front(), &rCellsAttributes.front());
+ rCellsSprms.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(rCellsSprms.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 || std::get<0>(aTuple) == BUFFER_PROPS_CHAR)
+ {
+ // 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(),
+ std::get<0>(aTuple) == BUFFER_PROPS_CHAR ? NS_ooxml::LN_Value_ST_StyleType_character
+ : 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(aString.getStr(), aString.getLength());
+ }
+ else if (std::get<0>(aTuple) == BUFFER_ENDRUN)
+ Mapper().endCharacterGroup();
+ else if (std::get<0>(aTuple) == BUFFER_PAR)
+ parBreak();
+ else if (std::get<0>(aTuple) == BUFFER_STARTSHAPE)
+ m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), false, RTFSdrImport::SHAPE);
+ else if (std::get<0>(aTuple) == BUFFER_RESOLVESHAPE)
+ {
+ // Make sure there is no current buffer while replaying the shape,
+ // otherwise it gets re-buffered.
+ RTFBuffer_t* pCurrentBuffer = m_aStates.top().getCurrentBuffer();
+ m_aStates.top().setCurrentBuffer(nullptr);
+
+ // Set current shape during replay, needed by e.g. wrap in
+ // background.
+ RTFShape aShape = m_aStates.top().getShape();
+ m_aStates.top().getShape() = std::get<1>(aTuple)->getShape();
+
+ m_pSdrImport->resolve(std::get<1>(aTuple)->getShape(), true, RTFSdrImport::SHAPE);
+ m_aStates.top().getShape() = std::move(aShape);
+ m_aStates.top().setCurrentBuffer(pCurrentBuffer);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_ENDSHAPE)
+ m_pSdrImport->close();
+ else if (std::get<0>(aTuple) == BUFFER_RESOLVESUBSTREAM)
+ {
+ RTFSprms& rAttributes = std::get<1>(aTuple)->getAttributes();
+ std::size_t nPos = rAttributes.find(0)->getInt();
+ Id nId = rAttributes.find(1)->getInt();
+ OUString aCustomMark = rAttributes.find(2)->getString();
+ resolveSubstream(nPos, nId, aCustomMark);
+ }
+ else if (std::get<0>(aTuple) == BUFFER_PICTURE)
+ m_aStates.top().getPicture() = std::get<1>(aTuple)->getPicture();
+ else if (std::get<0>(aTuple) == BUFFER_SETSTYLE)
+ {
+ if (!m_aStates.empty())
+ m_aStates.top().setCurrentStyleIndex(std::get<1>(aTuple)->getInt());
+ }
+ else
+ assert(false);
+ }
+}
+
+bool findPropertyName(const std::vector<beans::PropertyValue>& rProperties, const OUString& rName)
+{
+ return std::any_of(
+ rProperties.begin(), rProperties.end(),
+ [&rName](const beans::PropertyValue& rProperty) { return rProperty.Name == rName; });
+}
+
+void RTFDocumentImpl::backupTableRowProperties()
+{
+ if (m_nTopLevelCurrentCellX)
+ {
+ m_aBackupTableRowSprms = m_aStates.top().getTableRowSprms();
+ m_aBackupTableRowAttributes = m_aStates.top().getTableRowAttributes();
+ m_nBackupTopLevelCurrentCellX = m_nTopLevelCurrentCellX;
+ }
+}
+
+void RTFDocumentImpl::restoreTableRowProperties()
+{
+ m_aStates.top().getTableRowSprms() = m_aBackupTableRowSprms;
+ m_aStates.top().getTableRowAttributes() = m_aBackupTableRowAttributes;
+ m_nTopLevelCurrentCellX = m_nBackupTopLevelCurrentCellX;
+}
+
+void RTFDocumentImpl::resetTableRowProperties()
+{
+ m_aStates.top().getTableRowSprms() = m_aDefaultState.getTableRowSprms();
+ m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, new RTFValue(-1),
+ RTFOverwrite::NO_APPEND);
+ m_aStates.top().getTableRowAttributes() = m_aDefaultState.getTableRowAttributes();
+ if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination())
+ {
+ m_nNestedTRLeft = 0;
+ m_nNestedCurrentCellX = 0;
+ }
+ else
+ {
+ m_nTopLevelTRLeft = 0;
+ m_nTopLevelCurrentCellX = 0;
+ }
+}
+
+RTFError RTFDocumentImpl::dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam)
+{
+ setNeedSect(true);
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFSkipDestination aSkip(*this);
+ int nSprm = -1;
+ tools::SvRef<RTFValue> pBoolValue(new RTFValue(int(!bParam || nParam != 0)));
+
+ // Underline toggles.
+ switch (nKeyword)
+ {
+ case RTFKeyword::UL:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_single;
+ break;
+ case RTFKeyword::ULDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dash;
+ break;
+ case RTFKeyword::ULDASHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotDash;
+ break;
+ case RTFKeyword::ULDASHDD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dotDotDash;
+ break;
+ case RTFKeyword::ULDB:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_double;
+ break;
+ case RTFKeyword::ULHWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wavyHeavy;
+ break;
+ case RTFKeyword::ULLDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashLong;
+ break;
+ case RTFKeyword::ULTH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_thick;
+ break;
+ case RTFKeyword::ULTHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dottedHeavy;
+ break;
+ case RTFKeyword::ULTHDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashedHeavy;
+ break;
+ case RTFKeyword::ULTHDASHD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotHeavy;
+ break;
+ case RTFKeyword::ULTHDASHDD:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashDotDotHeavy;
+ break;
+ case RTFKeyword::ULTHLDASH:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_dashLongHeavy;
+ break;
+ case RTFKeyword::ULULDBWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wavyDouble;
+ break;
+ case RTFKeyword::ULWAVE:
+ nSprm = NS_ooxml::LN_Value_ST_Underline_wave;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue
+ = new RTFValue((!bParam || nParam != 0) ? nSprm : NS_ooxml::LN_Value_ST_Underline_none);
+ m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Underline_val, pValue);
+ return RTFError::OK;
+ }
+
+ // Accent characters (over dot / over comma).
+ switch (nKeyword)
+ {
+ case RTFKeyword::ACCNONE:
+ nSprm = NS_ooxml::LN_Value_ST_Em_none;
+ break;
+ case RTFKeyword::ACCDOT:
+ nSprm = NS_ooxml::LN_Value_ST_Em_dot;
+ break;
+ case RTFKeyword::ACCCOMMA:
+ nSprm = NS_ooxml::LN_Value_ST_Em_comma;
+ break;
+ case RTFKeyword::ACCCIRCLE:
+ nSprm = NS_ooxml::LN_Value_ST_Em_circle;
+ break;
+ case RTFKeyword::ACCUNDERDOT:
+ nSprm = NS_ooxml::LN_Value_ST_Em_underDot;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ auto pValue = new RTFValue((!bParam || nParam != 0) ? nSprm : 0);
+ m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_em, pValue);
+ return RTFError::OK;
+ }
+
+ // Trivial character sprms.
+ switch (nKeyword)
+ {
+ case RTFKeyword::B:
+ case RTFKeyword::AB:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_bCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_b;
+ break;
+ }
+ break;
+ case RTFKeyword::I:
+ case RTFKeyword::AI:
+ switch (m_aStates.top().getRunType())
+ {
+ case RTFParserState::RunType::HICH:
+ case RTFParserState::RunType::RTLCH_LTRCH_1:
+ case RTFParserState::RunType::LTRCH_RTLCH_2:
+ nSprm = NS_ooxml::LN_EG_RPrBase_iCs;
+ break;
+ case RTFParserState::RunType::NONE:
+ case RTFParserState::RunType::LOCH:
+ case RTFParserState::RunType::LTRCH_RTLCH_1:
+ case RTFParserState::RunType::RTLCH_LTRCH_2:
+ case RTFParserState::RunType::DBCH:
+ default:
+ nSprm = NS_ooxml::LN_EG_RPrBase_i;
+ break;
+ }
+ break;
+ case RTFKeyword::OUTL:
+ nSprm = NS_ooxml::LN_EG_RPrBase_outline;
+ break;
+ case RTFKeyword::SHAD:
+ nSprm = NS_ooxml::LN_EG_RPrBase_shadow;
+ break;
+ case RTFKeyword::V:
+ nSprm = NS_ooxml::LN_EG_RPrBase_vanish;
+ break;
+ case RTFKeyword::STRIKE:
+ nSprm = NS_ooxml::LN_EG_RPrBase_strike;
+ break;
+ case RTFKeyword::STRIKED:
+ nSprm = NS_ooxml::LN_EG_RPrBase_dstrike;
+ break;
+ case RTFKeyword::SCAPS:
+ nSprm = NS_ooxml::LN_EG_RPrBase_smallCaps;
+ break;
+ case RTFKeyword::IMPR:
+ nSprm = NS_ooxml::LN_EG_RPrBase_imprint;
+ break;
+ case RTFKeyword::CAPS:
+ nSprm = NS_ooxml::LN_EG_RPrBase_caps;
+ break;
+ default:
+ break;
+ }
+ if (nSprm >= 0)
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ {
+ m_aStates.top().getTableSprms().set(nSprm, pBoolValue);
+ }
+ else
+ {
+ m_aStates.top().getCharacterSprms().set(nSprm, pBoolValue);
+ }
+ return RTFError::OK;
+ }
+
+ switch (nKeyword)
+ {
+ case RTFKeyword::ASPALPHA:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_autoSpaceDE,
+ pBoolValue);
+ break;
+ case RTFKeyword::DELETED:
+ case RTFKeyword::REVISED:
+ {
+ auto pValue
+ = new RTFValue(nKeyword == RTFKeyword::DELETED ? oox::XML_del : oox::XML_ins);
+ putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange,
+ NS_ooxml::LN_token, pValue);
+ }
+ break;
+ case RTFKeyword::SBAUTO:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_beforeAutospacing, pBoolValue);
+ break;
+ case RTFKeyword::SAAUTO:
+ putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing,
+ NS_ooxml::LN_CT_Spacing_afterAutospacing, pBoolValue);
+ break;
+ case RTFKeyword::FACINGP:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_evenAndOddHeaders, pBoolValue);
+ break;
+ case RTFKeyword::HYPHAUTO:
+ m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_autoHyphenation, pBoolValue);
+ break;
+ case RTFKeyword::HYPHPAR:
+ m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_suppressAutoHyphens,
+ new RTFValue(int(bParam && nParam == 0)));
+ break;
+ default:
+ {
+ SAL_INFO("writerfilter.rtf",
+ "TODO handle toggle '" << keywordToString(nKeyword) << "'");
+ aSkip.setParsed(false);
+ }
+ break;
+ }
+ return RTFError::OK;
+}
+
+RTFError RTFDocumentImpl::pushState()
+{
+ //SAL_INFO("writerfilter.rtf", __func__ << " before push: " << m_pTokenizer->getGroup());
+
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ m_nGroupStartPos = Strm().Tell();
+
+ if (m_aStates.empty())
+ m_aStates.push(m_aDefaultState);
+ else
+ {
+ // fdo#85812 group resets run type of _current_ and new state (but not RTL)
+ if (m_aStates.top().getRunType() != RTFParserState::RunType::LTRCH_RTLCH_2
+ && m_aStates.top().getRunType() != RTFParserState::RunType::RTLCH_LTRCH_2)
+ {
+ m_aStates.top().setRunType(RTFParserState::RunType::NONE);
+ }
+
+ if (m_aStates.top().getDestination() == Destination::MR)
+ lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
+ m_bMathNor);
+ m_aStates.push(m_aStates.top());
+ }
+ m_aStates.top().getDestinationText().setLength(0); // was copied: always reset!
+
+ m_pTokenizer->pushGroup();
+
+ switch (m_aStates.top().getDestination())
+ {
+ case Destination::FONTTABLE:
+ // this is a "faked" destination for the font entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::FONTENTRY);
+ break;
+ case Destination::STYLESHEET:
+ // this is a "faked" destination for the style sheet entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::STYLEENTRY);
+ {
+ // the *default* is \s0 i.e. paragraph style default
+ // this will be overwritten by \sN \csN \dsN \tsN
+ m_nCurrentStyleIndex = 0;
+ auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, pValue);
+ }
+ break;
+ case Destination::FIELDRESULT:
+ case Destination::SHAPETEXT:
+ case Destination::FORMFIELD:
+ //TODO: if this is pushed then the font encoding is used which results in a broken command string
+ // if it is not pushed to NORMAL then it is not restored in time.
+ case Destination::FIELDINSTRUCTION:
+ case Destination::PICT:
+ m_aStates.top().setDestination(Destination::NORMAL);
+ break;
+ case Destination::MNUM:
+ case Destination::MDEN:
+ case Destination::ME:
+ case Destination::MFNAME:
+ case Destination::MLIM:
+ case Destination::MSUB:
+ case Destination::MSUP:
+ case Destination::MDEG:
+ case Destination::MOMATH:
+ m_aStates.top().setDestination(Destination::MR);
+ break;
+ case Destination::REVISIONTABLE:
+ // this is a "faked" destination for the revision table entry
+ m_aStates.top().setCurrentDestinationText(&m_aStates.top().getDestinationText());
+ m_aStates.top().setDestination(Destination::REVISIONENTRY);
+ break;
+ default:
+ break;
+ }
+
+ // If this is true, then ooxml:endtrackchange will be generated. Make sure
+ // we don't generate more ooxml:endtrackchange than ooxml:trackchange: new
+ // state does not inherit this flag.
+ m_aStates.top().setStartedTrackchange(false);
+
+ return RTFError::OK;
+}
+
+writerfilter::Reference<Properties>::Pointer_t RTFDocumentImpl::createStyleProperties()
+{
+ int nBasedOn = 0;
+ RTFValue::Pointer_t pBasedOn
+ = m_aStates.top().getTableSprms().find(NS_ooxml::LN_CT_Style_basedOn);
+ if (pBasedOn)
+ nBasedOn = pBasedOn->getInt();
+ if (nBasedOn == 0)
+ {
+ // No parent style, then mimic what Word does: ignore attributes which
+ // would set a margin as formatting, but with a default value.
+ for (const auto& nId :
+ { NS_ooxml::LN_CT_Ind_firstLine, NS_ooxml::LN_CT_Ind_left, NS_ooxml::LN_CT_Ind_right,
+ NS_ooxml::LN_CT_Ind_start, NS_ooxml::LN_CT_Ind_end })
+ {
+ RTFValue::Pointer_t pValue = getNestedAttribute(m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_CT_PPrBase_ind, nId);
+ if (pValue && pValue->getInt() == 0)
+ eraseNestedAttribute(m_aStates.top().getParagraphSprms(),
+ NS_ooxml::LN_CT_PPrBase_ind, nId);
+ }
+ }
+
+ RTFValue::Pointer_t pParaProps = new RTFValue(m_aStates.top().getParagraphAttributes(),
+ m_aStates.top().getParagraphSprms());
+ RTFValue::Pointer_t pCharProps = new RTFValue(m_aStates.top().getCharacterAttributes(),
+ m_aStates.top().getCharacterSprms());
+
+ // resetSprms will clean up this modification
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_pPr, pParaProps);
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Style_rPr, pCharProps);
+
+ writerfilter::Reference<Properties>::Pointer_t pProps(new RTFReferenceProperties(
+ m_aStates.top().getTableAttributes(), m_aStates.top().getTableSprms()));
+ return pProps;
+}
+
+/** 2 different representations of the styles are needed:
+
+ 1) flat content, as read from the input file:
+ stored in m_pStyleTableEntries, used as reference input for
+ deduplication both here and for hard formatting in getProperties()
+
+ 2) real content, with proper override of sprms/attributes where it differs
+ from parent style; this is produced here and sent to domain mapper
+ */
+RTFReferenceTable::Entries_t RTFDocumentImpl::deduplicateStyleTable()
+{
+ RTFReferenceTable::Entries_t ret;
+ for (auto const& it : *m_pStyleTableEntries)
+ {
+ auto pStyle = it.second;
+ ret[it.first] = pStyle;
+ // ugly downcasts here, but can't easily replace the members with
+ // RTFReferenceProperties because dmapper wants SvRef<Properties> anyway
+ RTFValue::Pointer_t const pBasedOn(
+ static_cast<RTFReferenceProperties&>(*pStyle).getSprms().find(
+ NS_ooxml::LN_CT_Style_basedOn));
+ if (pBasedOn)
+ {
+ int const nBasedOn(pBasedOn->getInt());
+ // don't deduplicate yourself - especially a potential problem for the default style.
+ if (it.first == nBasedOn)
+ continue;
+
+ auto const itParent(m_pStyleTableEntries->find(nBasedOn)); // definition as read!
+ if (itParent != m_pStyleTableEntries->end())
+ {
+ auto const pStyleType(
+ static_cast<RTFReferenceProperties&>(*pStyle).getAttributes().find(
+ NS_ooxml::LN_CT_Style_type));
+ assert(pStyleType);
+ int const nStyleType(pStyleType->getInt());
+ RTFSprms sprms(
+ static_cast<RTFReferenceProperties&>(*pStyle).getSprms().cloneAndDeduplicate(
+ static_cast<RTFReferenceProperties&>(*itParent->second).getSprms(),
+ nStyleType));
+ RTFSprms attributes(
+ static_cast<RTFReferenceProperties&>(*pStyle)
+ .getAttributes()
+ .cloneAndDeduplicate(
+ static_cast<RTFReferenceProperties&>(*itParent->second).getAttributes(),
+ nStyleType));
+
+ ret[it.first] = new RTFReferenceProperties(std::move(attributes), std::move(sprms));
+ }
+ else
+ {
+ SAL_WARN("writerfilter.rtf", "parent style not found: " << nBasedOn);
+ }
+ }
+ }
+ assert(ret.size() == m_pStyleTableEntries->size());
+ return ret;
+}
+
+void RTFDocumentImpl::resetSprms()
+{
+ m_aStates.top().getTableSprms().clear();
+ m_aStates.top().getCharacterSprms().clear();
+ m_aStates.top().getParagraphSprms().clear();
+}
+
+void RTFDocumentImpl::resetAttributes()
+{
+ m_aStates.top().getTableAttributes().clear();
+ m_aStates.top().getCharacterAttributes().clear();
+ m_aStates.top().getParagraphAttributes().clear();
+}
+
+static bool lcl_containsProperty(const uno::Sequence<beans::Property>& rProperties,
+ std::u16string_view rName)
+{
+ return std::any_of(rProperties.begin(), rProperties.end(),
+ [&](const beans::Property& rProperty) { return rProperty.Name == rName; });
+}
+
+RTFError RTFDocumentImpl::beforePopState(RTFParserState& rState)
+{
+ switch (rState.getDestination())
+ {
+ //Note: in fonttbl there may or may not be groups, so process it as no groups
+ case Destination::FONTTABLE:
+ case Destination::FONTENTRY:
+ {
+ // Some text unhandled? Seems it is last font name
+ if (m_aStates.top().getCurrentDestinationText()->getLength())
+ handleFontTableEntry();
+
+ if (rState.getDestination() == Destination::FONTTABLE)
+ {
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(m_aFontTableEntries));
+ Mapper().table(NS_ooxml::LN_FONTTABLE, pTable);
+ if (m_nDefaultFontIndex >= 0)
+ {
+ auto pValue = new RTFValue(m_aFontNames[getFontIndex(m_nDefaultFontIndex)]);
+ putNestedAttribute(m_aDefaultState.getCharacterSprms(),
+ NS_ooxml::LN_EG_RPrBase_rFonts, NS_ooxml::LN_CT_Fonts_ascii,
+ pValue);
+ }
+ }
+ }
+ break;
+ case Destination::STYLESHEET:
+ {
+ RTFReferenceTable::Entries_t pStyleTableDeduplicated(deduplicateStyleTable());
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(pStyleTableDeduplicated)));
+ Mapper().table(NS_ooxml::LN_STYLESHEET, pTable);
+ }
+ break;
+ case Destination::LISTOVERRIDETABLE:
+ {
+ RTFSprms aListTableAttributes;
+ writerfilter::Reference<Properties>::Pointer_t pProp
+ = new RTFReferenceProperties(std::move(aListTableAttributes), m_aListTableSprms);
+ RTFReferenceTable::Entries_t aListTableEntries;
+ aListTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(aListTableEntries)));
+ Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
+ }
+ break;
+ case Destination::LISTENTRY:
+ for (const auto& rListLevelEntry : rState.getListLevelEntries())
+ rState.getTableSprms().set(rListLevelEntry.first, rListLevelEntry.second,
+ RTFOverwrite::NO_APPEND);
+ break;
+ case Destination::FIELDINSTRUCTION:
+ {
+ auto pValue = new RTFValue(m_aFormfieldAttributes, m_aFormfieldSprms);
+ RTFSprms aFFAttributes;
+ RTFSprms aFFSprms;
+ aFFSprms.set(NS_ooxml::LN_ffdata, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aFFAttributes), std::move(aFFSprms));
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto pFFValue = new RTFValue(aFFAttributes, aFFSprms);
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pFFValue, nullptr);
+ }
+ m_aFormfieldAttributes.clear();
+ m_aFormfieldSprms.clear();
+
+ if (m_aStates.top().isFieldLocked())
+ singleChar(cFieldLock);
+ singleChar(cFieldSep, true);
+ }
+ break;
+ case Destination::FIELDRESULT:
+ singleChar(cFieldEnd);
+
+ if (!m_aPicturePath.isEmpty())
+ {
+ // Read the picture into m_aStates.top().aDestinationText.
+ pushState();
+ dispatchDestination(RTFKeyword::PICT);
+ if (m_aPicturePath.endsWith(".png"))
+ dispatchFlag(RTFKeyword::PNGBLIP);
+ OUString aFileURL = m_rMediaDescriptor.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_URL, OUString());
+ OUString aPictureURL;
+ try
+ {
+ aPictureURL = rtl::Uri::convertRelToAbs(aFileURL, m_aPicturePath);
+ }
+ catch (const rtl::MalformedUriException& rException)
+ {
+ SAL_WARN("writerfilter.rtf",
+ "rtl::Uri::convertRelToAbs() failed: " << rException.getMessage());
+ }
+
+ if (!aPictureURL.isEmpty())
+ {
+ SvFileStream aStream(aPictureURL, StreamMode::READ);
+ if (aStream.IsOpen())
+ {
+ OUStringBuffer aBuf;
+ while (aStream.good())
+ {
+ unsigned char ch = 0;
+ aStream.ReadUChar(ch);
+ if (ch < 16)
+ aBuf.append("0");
+ aBuf.append(static_cast<sal_Int32>(ch), 16);
+ }
+ m_aStates.top().getDestinationText() = aBuf;
+ }
+ }
+ popState();
+ m_aPicturePath.clear();
+ }
+
+ break;
+ case Destination::LEVELTEXT:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+
+ // The first character is the length of the string (the rest should be ignored).
+ sal_Int32 nLength(aStr.toChar());
+ OUString aValue;
+ if (nLength < aStr.getLength())
+ aValue = aStr.copy(1, nLength);
+ else
+ aValue = aStr;
+ auto pValue = new RTFValue(aValue, true);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
+ }
+ break;
+ case Destination::LEVELNUMBERS:
+ {
+ bool bNestedLevelNumbers = false;
+ if (m_aStates.size() > 1)
+ // Current destination is levelnumbers and parent destination is levelnumbers as well.
+ bNestedLevelNumbers
+ = m_aStates[m_aStates.size() - 2].getDestination() == Destination::LEVELNUMBERS;
+ if (!bNestedLevelNumbers && rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText))
+ {
+ RTFSprms& rAttributes
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_lvlText)->getAttributes();
+ RTFValue::Pointer_t pValue = rAttributes.find(NS_ooxml::LN_CT_LevelText_val);
+ if (pValue && rState.getLevelNumbersValid())
+ {
+ OUString aOrig = pValue->getString();
+
+ OUStringBuffer aBuf(aOrig.getLength() * 2);
+ sal_Int32 nReplaces = 1;
+ for (int i = 0; i < aOrig.getLength(); i++)
+ {
+ if (std::find(rState.getLevelNumbers().begin(),
+ rState.getLevelNumbers().end(), i + 1)
+ != rState.getLevelNumbers().end())
+ {
+ aBuf.append('%');
+ // '1.1.1' -> '%1.%2.%3', but '1.' (with '2.' prefix omitted) is %2.
+ aBuf.append(sal_Int32(nReplaces++ + rState.getListLevelNum() + 1
+ - rState.getLevelNumbers().size()));
+ }
+ else
+ aBuf.append(aOrig[i]);
+ }
+
+ pValue->setString(aBuf.makeStringAndClear());
+ }
+ else if (pValue)
+ // Have a value, but levelnumbers is not valid -> ignore it.
+ pValue->setString(OUString());
+ }
+ break;
+ }
+ case Destination::SHAPEPROPERTYNAME:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ rState.getShape().getProperties().emplace_back(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear(), OUString());
+ break;
+ case Destination::SHAPEPROPERTYVALUE:
+ if (!rState.getShape().getProperties().empty())
+ {
+ rState.getShape().getProperties().back().second
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ if (m_aStates.top().getHadShapeText())
+ m_pSdrImport->append(rState.getShape().getProperties().back().first,
+ rState.getShape().getProperties().back().second);
+ else if (rState.getInShapeGroup() && !rState.getInShape()
+ && rState.getShape().getProperties().back().first == "rotation")
+ {
+ // Rotation should be applied on the groupshape itself, not on each shape.
+ rState.getShape().getGroupProperties().push_back(
+ rState.getShape().getProperties().back());
+ rState.getShape().getProperties().pop_back();
+ }
+ }
+ break;
+ case Destination::PICPROP:
+ case Destination::SHAPEINSTRUCTION:
+ if (m_aStates.size() > 1
+ && m_aStates[m_aStates.size() - 2].getDestination()
+ == Destination::SHAPEINSTRUCTION)
+ {
+ // Do not resolve shape if shape instruction destination is inside other shape instruction
+ }
+ else if (!m_bObject && !rState.getInListpicture() && !rState.getHadShapeText()
+ && (!rState.getInShapeGroup() || rState.getInShape()))
+ {
+ // Don't trigger a shape import in case we're only leaving the \shpinst of the groupshape itself.
+ RTFSdrImport::ShapeOrPict eType
+ = (rState.getDestination() == Destination::SHAPEINSTRUCTION)
+ ? RTFSdrImport::SHAPE
+ : RTFSdrImport::PICT;
+ if (!m_aStates.top().getCurrentBuffer() || eType != RTFSdrImport::SHAPE)
+ m_pSdrImport->resolve(m_aStates.top().getShape(), true, eType);
+ else
+ {
+ // Shape inside table: buffer the import to have correct anchor position.
+ // Also buffer the RTFPicture of the state stack as it contains
+ // the shape size.
+ auto pPictureValue = new RTFValue(m_aStates.top().getPicture());
+ m_aStates.top().getCurrentBuffer()->emplace_back(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()->emplace_back(BUFFER_RESOLVESHAPE, pValue,
+ nullptr);
+ }
+ }
+ else if (rState.getInShapeGroup() && !rState.getInShape())
+ {
+ // End of a groupshape, as we're in shapegroup, but not in a real shape.
+ for (const auto& rGroupProperty : rState.getShape().getGroupProperties())
+ m_pSdrImport->appendGroupProperty(rGroupProperty.first, rGroupProperty.second);
+ rState.getShape().getGroupProperties().clear();
+ }
+ break;
+ case Destination::BOOKMARKSTART:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ int nPos = m_aBookmarks.size();
+ m_aBookmarks[aStr] = nPos;
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(lcl_getBookmarkProperties(nPos, aStr)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(lcl_getBookmarkProperties(nPos, aStr)), nullptr);
+ }
+ break;
+ case Destination::BOOKMARKEND:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(
+ lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(lcl_getBookmarkProperties(m_aBookmarks[aStr], aStr)),
+ nullptr);
+ }
+ break;
+ case Destination::INDEXENTRY:
+ case Destination::TOCENTRY:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString str(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ // dmapper expects this as a field, so let's fake something...
+ auto const field((Destination::INDEXENTRY == rState.getDestination())
+ ? std::u16string_view(u"XE")
+ : std::u16string_view(u"TC"));
+ str = OUString::Concat(field) + " \"" + str.replaceAll("\"", "\\\"") + "\"";
+ singleChar(cFieldStart);
+ Mapper().utext(str.getStr(), str.getLength());
+ singleChar(cFieldSep, true);
+ // no result
+ singleChar(cFieldEnd);
+ }
+ break;
+ case Destination::FORMFIELDNAME:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFData_name, pValue);
+ }
+ break;
+ case Destination::FORMFIELDLIST:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ // OOXML puts these into a LN_CT_FFData_ddList but FFDataHandler should handle this too
+ m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_listEntry, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ break;
+ case Destination::DATAFIELD:
+ {
+ if (m_bFormField)
+ {
+ OUStringBuffer* pCurrentDestinationText
+ = m_aStates.top().getCurrentDestinationText();
+ if (&m_aStates.top().getDestinationText() != pCurrentDestinationText)
+ break; // not for nested group
+ OString aStr
+ = OUStringToOString(*pCurrentDestinationText, rState.getCurrentEncoding());
+ pCurrentDestinationText->setLength(0);
+ // 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())
+ {
+ OUStringBuffer* pCurrentDestinationText
+ = m_aStates.top().getCurrentDestinationText();
+ m_xDocumentProperties->setKeywords(
+ comphelper::string::convertCommaSeparated(*pCurrentDestinationText));
+ pCurrentDestinationText->setLength(0);
+ }
+ break;
+ case Destination::COMMENT:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setGenerator(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::SUBJECT:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setSubject(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::TITLE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setTitle(
+ rState.getCurrentDestinationText()->makeStringAndClear());
+ }
+ break;
+
+ case Destination::DOCCOMM:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ m_xDocumentProperties->setDescription(
+ m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::OPERATOR:
+ case Destination::COMPANY:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aName = rState.getDestination() == Destination::OPERATOR ? OUString("Operator")
+ : OUString("Company");
+ uno::Any aValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ if (m_xDocumentProperties.is())
+ {
+ uno::Reference<beans::XPropertyContainer> xUserDefinedProperties
+ = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xPropertySet(xUserDefinedProperties,
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xPropertySetInfo
+ = xPropertySet->getPropertySetInfo();
+ if (xPropertySetInfo->hasPropertyByName(aName))
+ xPropertySet->setPropertyValue(aName, aValue);
+ else
+ xUserDefinedProperties->addProperty(aName, beans::PropertyAttribute::REMOVABLE,
+ aValue);
+ }
+ }
+ break;
+ case Destination::OBJDATA:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+
+ RTFError eError = handleEmbeddedObject();
+ if (eError != RTFError::OK)
+ return eError;
+ }
+ break;
+ case Destination::OBJCLASS:
+ {
+ auto pValue
+ = new RTFValue(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ m_aOLEAttributes.set(NS_ooxml::LN_CT_OLEObject_ProgID, pValue);
+ break;
+ }
+ case Destination::OBJECT:
+ {
+ if (!m_bObject)
+ {
+ // if the object is in a special container we will use the \result
+ // element instead of the \objdata
+ // (see RTFKeyword::OBJECT in RTFDocumentImpl::dispatchDestination)
+ break;
+ }
+
+ RTFSprms aObjectSprms;
+ auto pOLEValue = new RTFValue(m_aOLEAttributes);
+ aObjectSprms.set(NS_ooxml::LN_OLEObject_OLEObject, pOLEValue);
+
+ RTFSprms aObjAttributes;
+ RTFSprms aObjSprms;
+ auto pValue = new RTFValue(m_aObjectAttributes, aObjectSprms);
+ aObjSprms.set(NS_ooxml::LN_object, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aObjAttributes), std::move(aObjSprms));
+ uno::Reference<drawing::XShape> xShape;
+ RTFValue::Pointer_t pShape = m_aObjectAttributes.find(NS_ooxml::LN_shape);
+ OSL_ASSERT(pShape);
+ if (pShape)
+ pShape->getAny() >>= xShape;
+ if (xShape.is())
+ {
+ Mapper().startShape(xShape);
+ Mapper().props(pProperties);
+ Mapper().endShape();
+ }
+ m_aObjectAttributes.clear();
+ m_aOLEAttributes.clear();
+ m_bObject = false;
+ }
+ break;
+ case Destination::ANNOTATIONDATE:
+ {
+ OUStringBuffer* pCurrentDestinationText = m_aStates.top().getCurrentDestinationText();
+ if (&m_aStates.top().getDestinationText() != pCurrentDestinationText)
+ break; // not for nested group
+ OUString aStr(OStringToOUString(DTTM22OString(o3tl::toInt32(*pCurrentDestinationText)),
+ rState.getCurrentEncoding()));
+ pCurrentDestinationText->setLength(0);
+ auto pValue = new RTFValue(aStr);
+ RTFSprms aAnnAttributes;
+ aAnnAttributes.set(NS_ooxml::LN_CT_TrackChange_date, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAnnAttributes));
+ Mapper().props(pProperties);
+ }
+ break;
+ case Destination::ANNOTATIONAUTHOR:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ m_aAuthor = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ break;
+ case Destination::ATNID:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ m_aAuthorInitials = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ break;
+ case Destination::ANNOTATIONREFERENCESTART:
+ case Destination::ANNOTATIONREFERENCEEND:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ auto pValue = new RTFValue(aStr.toInt32());
+ RTFSprms aAttributes;
+ if (rState.getDestination() == Destination::ANNOTATIONREFERENCESTART)
+ aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeStart, pValue);
+ else
+ aAttributes.set(NS_ooxml::LN_EG_RangeMarkupElements_commentRangeEnd, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ {
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aAttributes));
+ Mapper().props(pProperties);
+ }
+ else
+ {
+ auto const pValue2 = new RTFValue(aAttributes, RTFSprms());
+ bufferProperties(*m_aStates.top().getCurrentBuffer(), pValue2, nullptr);
+ }
+ }
+ break;
+ case Destination::ANNOTATIONREFERENCE:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ RTFSprms aAnnAttributes;
+ aAnnAttributes.set(NS_ooxml::LN_CT_Markup_id, new RTFValue(aStr.toInt32()));
+ Mapper().props(new RTFReferenceProperties(std::move(aAnnAttributes)));
+ }
+ break;
+ case Destination::FALT:
+ {
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ OUString aStr(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ auto pValue = new RTFValue(aStr);
+ rState.getTableSprms().set(NS_ooxml::LN_CT_Font_altName, pValue);
+ }
+ break;
+ case Destination::DRAWINGOBJECT:
+ if (m_aStates.top().getDrawingObject().getShape().is())
+ {
+ RTFDrawingObject& rDrawing = m_aStates.top().getDrawingObject();
+ const uno::Reference<drawing::XShape>& xShape(rDrawing.getShape());
+ const uno::Reference<beans::XPropertySet>& xPropertySet(rDrawing.getPropertySet());
+
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
+ bool bTextFrame = xServiceInfo->supportsService("com.sun.star.text.TextFrame");
+
+ // The default is certainly not inline, but then what Word supports is just at-character.
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+
+ if (bTextFrame)
+ {
+ xPropertySet->setPropertyValue("HoriOrientPosition",
+ uno::Any(rDrawing.getLeft()));
+ xPropertySet->setPropertyValue("VertOrientPosition",
+ uno::Any(rDrawing.getTop()));
+ }
+ else
+ {
+ xShape->setPosition(awt::Point(rDrawing.getLeft(), rDrawing.getTop()));
+ }
+ xShape->setSize(awt::Size(rDrawing.getRight(), rDrawing.getBottom()));
+
+ if (rDrawing.getHasLineColor())
+ {
+ uno::Any aLineColor(sal_uInt32((rDrawing.getLineColorR() << 16)
+ + (rDrawing.getLineColorG() << 8)
+ + rDrawing.getLineColorB()));
+ uno::Any aLineWidth;
+ RTFSdrImport::resolveLineColorAndWidth(bTextFrame, xPropertySet, aLineColor,
+ aLineWidth);
+ }
+ if (rDrawing.getHasFillColor())
+ xPropertySet->setPropertyValue(
+ "FillColor", uno::Any(sal_uInt32((rDrawing.getFillColorR() << 16)
+ + (rDrawing.getFillColorG() << 8)
+ + rDrawing.getFillColorB())));
+ else if (!bTextFrame)
+ // If there is no fill, the Word default is 100% transparency.
+ xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_Int32(100)));
+
+ RTFSdrImport::resolveFLine(xPropertySet, rDrawing.getFLine());
+
+ if (!m_aStates.top().getDrawingObject().getHadShapeText())
+ {
+ Mapper().startShape(xShape);
+ }
+ Mapper().endShape();
+ }
+ break;
+ case Destination::PICT:
+ // fdo#79319 ignore picture data if it's really a shape
+ if (!m_pSdrImport->isFakePict())
+ {
+ resolvePict(true, m_pSdrImport->getCurrentShape());
+ }
+ m_bNeedFinalPar = true;
+ break;
+ case Destination::SHAPE:
+ m_bNeedFinalPar = true;
+ m_bNeedCr = m_bNeedCrOrig;
+ // tdf#47036 insert paragraph break for graphic object inside text
+ // frame at start of document - TODO: the object may actually be
+ // anchored inside the text frame and this ends up putting the
+ // anchor in the body, but better than losing the shape...
+ if (rState.getFrame().hasProperties() && m_pSdrImport->isTextGraphicObject())
+ {
+ // 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);
+ if (oox::FormulaImExportBase* pImport
+ = dynamic_cast<oox::FormulaImExportBase*>(xComponent.get()))
+ pImport->readFormulaOoxml(m_aMathBuffer);
+
+ auto pValue = new RTFValue(xObject);
+ RTFSprms aMathAttributes;
+ aMathAttributes.set(NS_ooxml::LN_starmath, pValue);
+ writerfilter::Reference<Properties>::Pointer_t pProperties
+ = new RTFReferenceProperties(std::move(aMathAttributes));
+ Mapper().props(pProperties);
+ }
+
+ m_aMathBuffer = oox::formulaimport::XmlStreamBuilder();
+ }
+ break;
+ case Destination::MR:
+ lcl_DestinationToMath(m_aStates.top().getCurrentDestinationText(), m_aMathBuffer,
+ m_bMathNor);
+ break;
+ case Destination::MF:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(f));
+ break;
+ case Destination::MFPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(fPr));
+ break;
+ case Destination::MCTRLPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(ctrlPr));
+ break;
+ case Destination::MNUM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(num));
+ break;
+ case Destination::MDEN:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(den));
+ break;
+ case Destination::MACC:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(acc));
+ break;
+ case Destination::MACCPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(accPr));
+ break;
+ case Destination::MCHR:
+ case Destination::MPOS:
+ case Destination::MVERTJC:
+ case Destination::MSTRIKEH:
+ case Destination::MDEGHIDE:
+ case Destination::MBEGCHR:
+ case Destination::MSEPCHR:
+ case Destination::MENDCHR:
+ case Destination::MSUBHIDE:
+ case Destination::MSUPHIDE:
+ case Destination::MTYPE:
+ case Destination::MGROW:
+ {
+ sal_Int32 nMathToken = 0;
+ switch (rState.getDestination())
+ {
+ case Destination::MCHR:
+ nMathToken = M_TOKEN(chr);
+ break;
+ case Destination::MPOS:
+ nMathToken = M_TOKEN(pos);
+ break;
+ case Destination::MVERTJC:
+ nMathToken = M_TOKEN(vertJc);
+ break;
+ case Destination::MSTRIKEH:
+ nMathToken = M_TOKEN(strikeH);
+ break;
+ case Destination::MDEGHIDE:
+ nMathToken = M_TOKEN(degHide);
+ break;
+ case Destination::MBEGCHR:
+ nMathToken = M_TOKEN(begChr);
+ break;
+ case Destination::MSEPCHR:
+ nMathToken = M_TOKEN(sepChr);
+ break;
+ case Destination::MENDCHR:
+ nMathToken = M_TOKEN(endChr);
+ break;
+ case Destination::MSUBHIDE:
+ nMathToken = M_TOKEN(subHide);
+ break;
+ case Destination::MSUPHIDE:
+ nMathToken = M_TOKEN(supHide);
+ break;
+ case Destination::MTYPE:
+ nMathToken = M_TOKEN(type);
+ break;
+ case Destination::MGROW:
+ nMathToken = M_TOKEN(grow);
+ break;
+ default:
+ break;
+ }
+
+ oox::formulaimport::XmlStream::AttributeList aAttribs;
+ aAttribs[M_TOKEN(val)]
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ m_aMathBuffer.appendOpeningTag(nMathToken, aAttribs);
+ m_aMathBuffer.appendClosingTag(nMathToken);
+ }
+ break;
+ case Destination::ME:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(e));
+ break;
+ case Destination::MBAR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(bar));
+ break;
+ case Destination::MBARPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(barPr));
+ break;
+ case Destination::MD:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(d));
+ break;
+ case Destination::MDPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(dPr));
+ break;
+ case Destination::MFUNC:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(func));
+ break;
+ case Destination::MFUNCPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(funcPr));
+ break;
+ case Destination::MFNAME:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(fName));
+ break;
+ case Destination::MLIMLOW:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limLow));
+ break;
+ case Destination::MLIMLOWPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limLowPr));
+ break;
+ case Destination::MLIM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(lim));
+ break;
+ case Destination::MM:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(m));
+ break;
+ case Destination::MMPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(mPr));
+ break;
+ case Destination::MMR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(mr));
+ break;
+ case Destination::MNARY:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(nary));
+ break;
+ case Destination::MNARYPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(naryPr));
+ break;
+ case Destination::MSUB:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sub));
+ break;
+ case Destination::MSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sup));
+ break;
+ case Destination::MLIMUPP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limUpp));
+ break;
+ case Destination::MLIMUPPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(limUppPr));
+ break;
+ case Destination::MGROUPCHR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(groupChr));
+ break;
+ case Destination::MGROUPCHRPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(groupChrPr));
+ break;
+ case Destination::MBORDERBOX:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(borderBox));
+ break;
+ case Destination::MBORDERBOXPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(borderBoxPr));
+ break;
+ case Destination::MRAD:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(rad));
+ break;
+ case Destination::MRADPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(radPr));
+ break;
+ case Destination::MDEG:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(deg));
+ break;
+ case Destination::MSSUB:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSub));
+ break;
+ case Destination::MSSUBPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubPr));
+ break;
+ case Destination::MSSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSup));
+ break;
+ case Destination::MSSUPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSupPr));
+ break;
+ case Destination::MSSUBSUP:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSup));
+ break;
+ case Destination::MSSUBSUPPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sSubSupPr));
+ break;
+ case Destination::MSPRE:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sPre));
+ break;
+ case Destination::MSPREPR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(sPrePr));
+ break;
+ case Destination::MBOX:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(box));
+ break;
+ case Destination::MEQARR:
+ m_aMathBuffer.appendClosingTag(M_TOKEN(eqArr));
+ break;
+ case Destination::SHAPEGROUP:
+ if (rState.getCreatedShapeGroup())
+ m_pSdrImport->popParent();
+ break;
+ case Destination::PROPNAME:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ rState.setPropName(m_aStates.top().getCurrentDestinationText()->makeStringAndClear());
+ break;
+ case Destination::STATICVAL:
+ if (&m_aStates.top().getDestinationText()
+ != m_aStates.top().getCurrentDestinationText())
+ break; // not for nested group
+ if (m_xDocumentProperties.is())
+ {
+ // Find out what is the key, value type and value we want to set.
+ uno::Reference<beans::XPropertyContainer> xPropertyContainer
+ = m_xDocumentProperties->getUserDefinedProperties();
+ const OUString& rKey = m_aStates.top().getPropName();
+ OUString aStaticVal
+ = m_aStates.top().getCurrentDestinationText()->makeStringAndClear();
+ uno::Any aAny;
+ if (m_aStates.top().getPropType() == cppu::UnoType<OUString>::get())
+ aAny <<= aStaticVal;
+ else if (m_aStates.top().getPropType() == cppu::UnoType<sal_Int32>::get())
+ aAny <<= aStaticVal.toInt32();
+ else if (m_aStates.top().getPropType() == cppu::UnoType<bool>::get())
+ aAny <<= aStaticVal.toBoolean();
+ else if (m_aStates.top().getPropType() == cppu::UnoType<util::DateTime>::get())
+ aAny <<= getDateTimeFromUserProp(aStaticVal);
+ else if (m_aStates.top().getPropType() == cppu::UnoType<double>::get())
+ aAny <<= aStaticVal.toDouble();
+
+ xPropertyContainer->addProperty(rKey, beans::PropertyAttribute::REMOVABLE, aAny);
+ }
+ break;
+ case Destination::USERPROPS:
+ {
+ // These are the imported properties.
+ uno::Reference<document::XDocumentProperties> xDocumentProperties
+ = m_xDocumentProperties;
+
+ // These are the real document properties.
+ uno::Reference<document::XDocumentPropertiesSupplier> xDocumentPropertiesSupplier(
+ m_xDstDoc, uno::UNO_QUERY);
+ if (xDocumentPropertiesSupplier.is())
+ m_xDocumentProperties = xDocumentPropertiesSupplier->getDocumentProperties();
+
+ if (m_xDocumentProperties.is())
+ {
+ if (!m_bIsNewDoc)
+ {
+ // Check classification.
+ if (!SfxClassificationHelper::ShowPasteInfo(SfxClassificationHelper::CheckPaste(
+ xDocumentProperties, m_xDocumentProperties)))
+ return RTFError::CLASSIFICATION;
+ }
+
+ uno::Reference<beans::XPropertyContainer> xClipboardPropertyContainer
+ = xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertyContainer> xDocumentPropertyContainer
+ = m_xDocumentProperties->getUserDefinedProperties();
+ uno::Reference<beans::XPropertySet> xClipboardPropertySet(
+ xClipboardPropertyContainer, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xDocumentPropertySet(xDocumentPropertyContainer,
+ uno::UNO_QUERY);
+ const uno::Sequence<beans::Property> aClipboardProperties
+ = xClipboardPropertySet->getPropertySetInfo()->getProperties();
+ uno::Sequence<beans::Property> aDocumentProperties
+ = xDocumentPropertySet->getPropertySetInfo()->getProperties();
+
+ for (const beans::Property& rProperty : aClipboardProperties)
+ {
+ const OUString& rKey = rProperty.Name;
+ uno::Any aValue = xClipboardPropertySet->getPropertyValue(rKey);
+
+ try
+ {
+ if (lcl_containsProperty(aDocumentProperties, rKey))
+ {
+ // When pasting, don't update existing properties.
+ if (!m_bIsNewDoc)
+ xDocumentPropertySet->setPropertyValue(rKey, aValue);
+ }
+ else
+ xDocumentPropertyContainer->addProperty(
+ rKey, beans::PropertyAttribute::REMOVABLE, aValue);
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("writerfilter.rtf", "failed to set property " << rKey);
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return RTFError::OK;
+}
+
+void RTFDocumentImpl::afterPopState(RTFParserState& rState)
+{
+ // list table
+ switch (rState.getDestination())
+ {
+ case Destination::LISTENTRY:
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pValue,
+ RTFOverwrite::NO_APPEND);
+ m_aListTable[rState.getCurrentListIndex()] = pValue;
+ m_nListLevel = -1;
+ m_aInvalidListTableFirstIndents[rState.getCurrentListIndex()]
+ = m_aInvalidListLevelFirstIndents;
+ m_aInvalidListLevelFirstIndents.clear();
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING:
+ {
+ RTFValue::Pointer_t pIdValue
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_AbstractNum_nsid);
+ if (pIdValue && !m_aStates.empty())
+ {
+ // Abstract numbering
+ RTFSprms aLeveltextAttributes;
+ OUString aTextValue;
+ RTFValue::Pointer_t pTextBefore
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelText_val);
+ if (pTextBefore)
+ aTextValue += pTextBefore->getString();
+ aTextValue += "%1";
+ RTFValue::Pointer_t pTextAfter
+ = rState.getTableAttributes().find(NS_ooxml::LN_CT_LevelSuffix_val);
+ if (pTextAfter)
+ aTextValue += pTextAfter->getString();
+ auto pTextValue = new RTFValue(aTextValue);
+ aLeveltextAttributes.set(NS_ooxml::LN_CT_LevelText_val, pTextValue);
+
+ RTFSprms aLevelAttributes;
+ RTFSprms aLevelSprms;
+ auto pIlvlValue = new RTFValue(0);
+ aLevelAttributes.set(NS_ooxml::LN_CT_Lvl_ilvl, pIlvlValue);
+
+ RTFValue::Pointer_t pFmtValue
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_numFmt);
+ if (pFmtValue)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_numFmt, pFmtValue);
+
+ RTFValue::Pointer_t pStartatValue
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_start);
+ if (pStartatValue)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_start, pStartatValue);
+
+ auto pLeveltextValue = new RTFValue(aLeveltextAttributes);
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_lvlText, pLeveltextValue);
+ RTFValue::Pointer_t pRunProps
+ = rState.getTableSprms().find(NS_ooxml::LN_CT_Lvl_rPr);
+ if (pRunProps)
+ aLevelSprms.set(NS_ooxml::LN_CT_Lvl_rPr, pRunProps);
+
+ RTFSprms aAbstractAttributes;
+ RTFSprms aAbstractSprms;
+ aAbstractAttributes.set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, pIdValue);
+ auto pLevelValue = new RTFValue(aLevelAttributes, aLevelSprms);
+ aAbstractSprms.set(NS_ooxml::LN_CT_AbstractNum_lvl, pLevelValue,
+ RTFOverwrite::NO_APPEND);
+
+ RTFSprms aListTableSprms;
+ auto pAbstractValue = new RTFValue(aAbstractAttributes, aAbstractSprms);
+ // It's important that Numbering_abstractNum and Numbering_num never overwrites previous values.
+ aListTableSprms.set(NS_ooxml::LN_CT_Numbering_abstractNum, pAbstractValue,
+ RTFOverwrite::NO_APPEND);
+
+ // Numbering
+ RTFSprms aNumberingAttributes;
+ RTFSprms aNumberingSprms;
+ aNumberingAttributes.set(NS_ooxml::LN_CT_AbstractNum_nsid, pIdValue);
+ aNumberingSprms.set(NS_ooxml::LN_CT_Num_abstractNumId, pIdValue);
+ auto pNumberingValue = new RTFValue(aNumberingAttributes, aNumberingSprms);
+ aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pNumberingValue,
+ RTFOverwrite::NO_APPEND);
+
+ // Table
+ RTFSprms aListTableAttributes;
+ writerfilter::Reference<Properties>::Pointer_t pProp = new RTFReferenceProperties(
+ std::move(aListTableAttributes), std::move(aListTableSprms));
+
+ RTFReferenceTable::Entries_t aListTableEntries;
+ aListTableEntries.insert(std::make_pair(0, pProp));
+ writerfilter::Reference<Table>::Pointer_t const pTable(
+ new RTFReferenceTable(std::move(aListTableEntries)));
+ Mapper().table(NS_ooxml::LN_NUMBERING, pTable);
+
+ // Use it
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_ilvl, pIlvlValue, RTFOverwrite::YES_PREPEND);
+ putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr,
+ NS_ooxml::LN_CT_NumPr_numId, pIdValue, RTFOverwrite::YES_PREPEND);
+ }
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING_TEXTAFTER:
+ if (!m_aStates.empty())
+ {
+ // FIXME: don't use pDestinationText, points to popped state
+ auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelSuffix_val, pValue);
+ }
+ break;
+ case Destination::PARAGRAPHNUMBERING_TEXTBEFORE:
+ if (!m_aStates.empty())
+ {
+ // FIXME: don't use pDestinationText, points to popped state
+ auto pValue = new RTFValue(rState.getDestinationText().makeStringAndClear(), true);
+ m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_LevelText_val, pValue);
+ }
+ break;
+ case Destination::LISTNAME:
+ break;
+ case Destination::LISTLEVEL:
+ if (!m_aStates.empty())
+ {
+ auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_Lvl_ilvl, pInnerValue);
+
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ if (m_aStates.top().getDestination() != Destination::LFOLEVEL)
+ m_aStates.top().getListLevelEntries().set(NS_ooxml::LN_CT_AbstractNum_lvl,
+ pValue, RTFOverwrite::NO_APPEND);
+ else
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_NumLvl_lvl, pValue);
+ }
+ break;
+ case Destination::LFOLEVEL:
+ if (!m_aStates.empty())
+ {
+ auto pInnerValue = new RTFValue(m_aStates.top().getListLevelNum()++);
+ rState.getTableAttributes().set(NS_ooxml::LN_CT_NumLvl_ilvl, pInnerValue);
+
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_lvlOverride, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ break;
+ // list override table
+ case Destination::LISTOVERRIDEENTRY:
+ if (!m_aStates.empty())
+ {
+ if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY)
+ {
+ // copy properties upwards so upper popState() inserts it
+ m_aStates.top().getTableAttributes() = rState.getTableAttributes();
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ }
+ else
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes(), rState.getTableSprms());
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_num, pValue,
+ RTFOverwrite::NO_APPEND);
+ m_aListOverrideTable[rState.getCurrentListOverrideIndex()]
+ = rState.getCurrentListIndex();
+ }
+ }
+ break;
+ case Destination::LEVELTEXT:
+ if (!m_aStates.empty())
+ {
+ auto pValue = new RTFValue(rState.getTableAttributes());
+ m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_lvlText, pValue);
+ }
+ break;
+ case Destination::LEVELNUMBERS:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS
+ || m_aStates.top().getDestination() == Destination::LISTLEVEL)
+ // Parent state is level number or list level, current state is
+ // level numbers: mark parent as invalid as well if necessary.
+ m_aStates.top().setLevelNumbersValid(rState.getLevelNumbersValid());
+ }
+ break;
+ case Destination::FIELDINSTRUCTION:
+ if (!m_aStates.empty())
+ m_aStates.top().setFieldStatus(RTFFieldStatus::INSTRUCTION);
+ break;
+ case Destination::FIELDRESULT:
+ if (!m_aStates.empty())
+ m_aStates.top().setFieldStatus(RTFFieldStatus::RESULT);
+ break;
+ case Destination::FIELD:
+ if (rState.getFieldStatus() == RTFFieldStatus::INSTRUCTION)
+ singleChar(cFieldEnd);
+ break;
+ case Destination::DOCVAR:
+ if (!m_aStates.empty())
+ {
+ OUString docvar(rState.getDocVar());
+ if (m_aStates.top().getDocVarName().isEmpty())
+ {
+ m_aStates.top().setDocVarName(docvar);
+ }
+ else
+ {
+ uno::Reference<beans::XPropertySet> xMaster(
+ m_xModelFactory->createInstance("com.sun.star.text.FieldMaster.User"),
+ uno::UNO_QUERY_THROW);
+ xMaster->setPropertyValue("Name", uno::Any(m_aStates.top().getDocVarName()));
+ uno::Reference<text::XDependentTextField> xField(
+ m_xModelFactory->createInstance("com.sun.star.text.TextField.User"),
+ uno::UNO_QUERY);
+ xField->attachTextFieldMaster(xMaster);
+ xField->getTextFieldMaster()->setPropertyValue("Content", uno::Any(docvar));
+
+ m_aStates.top().clearDocVarName();
+ }
+ }
+ break;
+ case Destination::SHAPEPROPERTYVALUEPICT:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getPicture() = rState.getPicture();
+ // both \sp and \sv are destinations, copy the text up-ward for later
+ m_aStates.top().getDestinationText() = rState.getDestinationText();
+ }
+ break;
+ case Destination::FALT:
+ if (!m_aStates.empty())
+ m_aStates.top().getTableSprms() = rState.getTableSprms();
+ break;
+ case Destination::SHAPEPROPERTYNAME:
+ case Destination::SHAPEPROPERTYVALUE:
+ case Destination::SHAPEPROPERTY:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getShape() = rState.getShape();
+ m_aStates.top().getPicture() = rState.getPicture();
+ m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
+ }
+ break;
+ case Destination::SHAPEINSTRUCTION:
+ if (!m_aStates.empty()
+ && m_aStates.top().getDestination() == Destination::SHAPEINSTRUCTION)
+ {
+ // Shape instruction inside other shape instruction: just copy new shape settings:
+ // it will be resolved on end of topmost shape instruction destination
+ m_aStates.top().getShape() = rState.getShape();
+ m_aStates.top().getPicture() = rState.getPicture();
+ m_aStates.top().getCharacterSprms() = rState.getCharacterSprms();
+ m_aStates.top().getCharacterAttributes() = rState.getCharacterAttributes();
+ }
+ break;
+ case Destination::FLYMAINCONTENT:
+ case Destination::SHPPICT:
+ case Destination::SHAPE:
+ if (!m_aStates.empty())
+ {
+ m_aStates.top().getFrame() = rState.getFrame();
+ if (rState.getDestination() == Destination::SHPPICT
+ && m_aStates.top().getDestination() == Destination::LISTPICTURE)
+ {
+ RTFSprms aAttributes;
+ aAttributes.set(NS_ooxml::LN_CT_NumPicBullet_numPicBulletId,
+ new RTFValue(m_nListPictureId++));
+ RTFSprms aSprms;
+ // Dummy value, real picture is already sent to dmapper.
+ aSprms.set(NS_ooxml::LN_CT_NumPicBullet_pict, new RTFValue(0));
+ auto pValue = new RTFValue(aAttributes, aSprms);
+ m_aListTableSprms.set(NS_ooxml::LN_CT_Numbering_numPicBullet, pValue,
+ RTFOverwrite::NO_APPEND);
+ }
+ }
+ break;
+ case Destination::SHAPETEXT:
+ if (!m_aStates.empty())
+ {
+ // If we're leaving the shapetext group (it may have nested ones) and this is a shape, not an old drawingobject.
+ if (m_aStates.top().getDestination() != Destination::SHAPETEXT
+ && !m_aStates.top().getDrawingObject().getHadShapeText())
+ {
+ m_aStates.top().setHadShapeText(true);
+ if (!m_aStates.top().getCurrentBuffer())
+ m_pSdrImport->close();
+ else
+ m_aStates.top().getCurrentBuffer()->emplace_back(BUFFER_ENDSHAPE, nullptr,
+ nullptr);
+ }
+
+ // It's allowed to declare these inside the shape text, and they
+ // are expected to have an effect for the whole shape.
+ if (rState.getDrawingObject().getLeft())
+ m_aStates.top().getDrawingObject().setLeft(rState.getDrawingObject().getLeft());
+ if (rState.getDrawingObject().getTop())
+ m_aStates.top().getDrawingObject().setTop(rState.getDrawingObject().getTop());
+ if (rState.getDrawingObject().getRight())
+ m_aStates.top().getDrawingObject().setRight(
+ rState.getDrawingObject().getRight());
+ if (rState.getDrawingObject().getBottom())
+ m_aStates.top().getDrawingObject().setBottom(
+ rState.getDrawingObject().getBottom());
+ }
+ break;
+ case Destination::PROPNAME:
+ if (m_aStates.top().getDestination() == Destination::USERPROPS)
+ m_aStates.top().setPropName(rState.getPropName());
+ break;
+ default:
+ {
+ if (!m_aStates.empty() && m_aStates.top().getDestination() == Destination::PICT)
+ m_aStates.top().getPicture() = rState.getPicture();
+ }
+ break;
+ }
+}
+
+RTFError RTFDocumentImpl::popState()
+{
+ //SAL_INFO("writerfilter", __func__ << " before pop: m_pTokenizer->getGroup() " << m_pTokenizer->getGroup() <<
+ // ", dest state: " << m_aStates.top().eDestination);
+
+ checkUnicode(/*bUnicode =*/true, /*bHex =*/true);
+ RTFParserState aState(m_aStates.top());
+ m_bWasInFrame = aState.getFrame().hasProperties();
+
+ // dmapper expects some content in header/footer, so if there would be nothing, add an empty paragraph.
+ if (m_pTokenizer->getGroup() == 1 && m_bFirstRun)
+ {
+ switch (m_nStreamType)
+ {
+ case NS_ooxml::LN_headerl:
+ case NS_ooxml::LN_headerr:
+ case NS_ooxml::LN_headerf:
+ case NS_ooxml::LN_footerl:
+ case NS_ooxml::LN_footerr:
+ case NS_ooxml::LN_footerf:
+ dispatchSymbol(RTFKeyword::PAR);
+ break;
+ }
+ }
+
+ RTFError eError = beforePopState(aState);
+ if (eError != RTFError::OK)
+ return eError;
+
+ // See if we need to end a track change
+ if (aState.getStartedTrackchange())
+ {
+ RTFSprms aTCSprms;
+ auto pValue = new RTFValue(0);
+ aTCSprms.set(NS_ooxml::LN_endtrackchange, pValue);
+ if (!m_aStates.top().getCurrentBuffer())
+ Mapper().props(new RTFReferenceProperties(RTFSprms(), std::move(aTCSprms)));
+ else
+ bufferProperties(*m_aStates.top().getCurrentBuffer(),
+ new RTFValue(RTFSprms(), aTCSprms), nullptr);
+ }
+
+ // This is the end of the doc, see if we need to close the last section.
+ if (m_pTokenizer->getGroup() == 1 && !m_bFirstRun)
+ {
+ // \par means an empty paragraph at the end of footnotes/endnotes, but
+ // not in case of other substreams, like headers.
+ if (m_bNeedCr && m_nStreamType != NS_ooxml::LN_footnote
+ && m_nStreamType != NS_ooxml::LN_endnote)
+ {
+ if (!m_bIsNewDoc)
+ {
+ // Make sure all the paragraph settings are set, but do not add next paragraph
+ Mapper().markLastParagraph();
+ }
+ dispatchSymbol(RTFKeyword::PAR);
+ }
+ if (m_bNeedSect) // may be set by dispatchSymbol above!
+ sectBreak(true);
+ else if (!m_pSuperstream)
+ {
+ Mapper().markLastSectionGroup(); // ensure it's set for \par below
+ }
+ if (m_bNeedPar && !m_pSuperstream)
+ {
+ assert(!m_bNeedSect);
+ dispatchSymbol(RTFKeyword::PAR);
+ m_bNeedSect = false; // reset - m_bNeedPar was set for \sect at
+ // end of doc so don't need another one
+ }
+ }
+
+ m_aStates.pop();
+
+ m_pTokenizer->popGroup();
+
+ afterPopState(aState);
+
+ if (aState.getCurrentBuffer() == &m_aSuperBuffer)
+ {
+ OSL_ASSERT(!m_aStates.empty() && m_aStates.top().getCurrentBuffer() == nullptr);
+
+ if (!m_aSuperBuffer.empty())
+ replayBuffer(m_aSuperBuffer, nullptr, nullptr);
+ }
+
+ if (!m_aStates.empty() && m_aStates.top().getTableRowWidthAfter() > 0
+ && aState.getTableRowWidthAfter() == 0)
+ // An RTFKeyword::ROW in the inner group already parsed nTableRowWidthAfter,
+ // don't do it again in the outer state later.
+ m_aStates.top().setTableRowWidthAfter(0);
+
+ if (m_nResetBreakOnSectBreak != RTFKeyword::invalid && !m_aStates.empty())
+ {
+ // Section break type created for \page still has an effect in the
+ // outer state as well.
+ RTFValue::Pointer_t pType
+ = aState.getSectionSprms().find(NS_ooxml::LN_EG_SectPrContents_type);
+ if (pType)
+ m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_type, pType);
+ }
+
+ return RTFError::OK;
+}
+
+RTFError RTFDocumentImpl::handleEmbeddedObject()
+{
+ OUStringBuffer* pCurrentDestinationText = m_aStates.top().getCurrentDestinationText();
+ OString aStr = OUStringToOString(*pCurrentDestinationText, RTL_TEXTENCODING_ASCII_US);
+ pCurrentDestinationText->setLength(0);
+ 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));
+ m_aOLEAttributes.set(NS_ooxml::LN_inputstream, new RTFValue(xInputStream));
+
+ return RTFError::OK;
+}
+
+bool RTFDocumentImpl::isInBackground() { return m_aStates.top().getInBackground(); }
+
+RTFInternalState RTFDocumentImpl::getInternalState() { return m_aStates.top().getInternalState(); }
+
+void RTFDocumentImpl::setInternalState(RTFInternalState nInternalState)
+{
+ m_aStates.top().setInternalState(nInternalState);
+}
+
+Destination RTFDocumentImpl::getDestination() { return m_aStates.top().getDestination(); }
+
+void RTFDocumentImpl::setDestination(Destination eDestination)
+{
+ m_aStates.top().setDestination(eDestination);
+}
+
+// this is a questionably named method that is used only in a very special
+// situation where it looks like the "current" buffer is needed?
+void RTFDocumentImpl::setDestinationText(std::u16string_view rString)
+{
+ m_aStates.top().getDestinationText().setLength(0);
+ m_aStates.top().getDestinationText().append(rString);
+}
+
+bool RTFDocumentImpl::getSkipUnknown() { return m_bSkipUnknown; }
+
+void RTFDocumentImpl::setSkipUnknown(bool bSkipUnknown) { m_bSkipUnknown = bSkipUnknown; }
+
+static auto FilterControlChars(Destination const destination, OUString const& rString) -> OUString
+{
+ if (destination == Destination::LEVELNUMBERS || destination == Destination::LEVELTEXT)
+ { // control characters are magic here!
+ return rString;
+ }
+ OUStringBuffer buf(rString.getLength());
+ for (sal_Int32 i = 0; i < rString.getLength(); ++i)
+ {
+ sal_Unicode const ch(rString[i]);
+ if (!linguistic::IsControlChar(ch) || ch == '\r' || ch == '\n' || ch == '\t')
+ {
+ buf.append(ch);
+ }
+ else
+ {
+ SAL_INFO("writerfilter.rtf", "filtering control character");
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+void RTFDocumentImpl::checkUnicode(bool bUnicode, bool bHex)
+{
+ if (bUnicode && !m_aUnicodeBuffer.isEmpty())
+ {
+ OUString aString = m_aUnicodeBuffer.toString();
+ m_aUnicodeBuffer.setLength(0);
+ aString = FilterControlChars(m_aStates.top().getDestination(), aString);
+ text(aString);
+ }
+ if (bHex && !m_aHexBuffer.isEmpty())
+ {
+ rtl_TextEncoding nEncoding = m_aStates.top().getCurrentEncoding();
+ if (nEncoding == RTL_TEXTENCODING_SYMBOL
+ && (m_aStates.top().getDestination() == Destination::FONTENTRY
+ || (m_aStates.size() > 1
+ && m_aStates[m_aStates.size() - 2].getDestination()
+ == Destination::FIELDINSTRUCTION)))
+ nEncoding = RTL_TEXTENCODING_MS_1252;
+ OUString aString = OStringToOUString(m_aHexBuffer, nEncoding);
+ m_aHexBuffer.setLength(0);
+ aString = FilterControlChars(m_aStates.top().getDestination(), aString);
+ text(aString);
+ }
+}
+
+RTFParserState::RTFParserState(RTFDocumentImpl* pDocumentImpl)
+ : m_pDocumentImpl(pDocumentImpl)
+ , m_nInternalState(RTFInternalState::NORMAL)
+ , m_eDestination(Destination::NORMAL)
+ , m_eFieldStatus(RTFFieldStatus::NONE)
+ , m_bFieldLocked(false)
+ , m_nBorderState(RTFBorderState::NONE)
+ , m_nCurrentEncoding(rtl_getTextEncodingFromWindowsCharset(0))
+ , m_nUc(1)
+ , m_nCharsToSkip(0)
+ , m_nBinaryToRead(0)
+ , m_nListLevelNum(0)
+ , m_bLevelNumbersValid(true)
+ , m_aFrame(this)
+ , m_eRunType(RunType::NONE)
+ , m_nYear(0)
+ , m_nMonth(0)
+ , m_nDay(0)
+ , m_nHour(0)
+ , m_nMinute(0)
+ , m_pCurrentDestinationText(nullptr)
+ , m_nCurrentStyleIndex(0)
+ , m_nCurrentCharacterStyleIndex(-1)
+ , m_pCurrentBuffer(nullptr)
+ , m_bInListpicture(false)
+ , m_bInBackground(false)
+ , m_bHadShapeText(false)
+ , m_bInShapeGroup(false)
+ , m_bInShape(false)
+ , m_bCreatedShapeGroup(false)
+ , m_bStartedTrackchange(false)
+ , m_nTableRowWidthAfter(0)
+{
+}
+
+void RTFDocumentImpl::resetFrame() { m_aStates.top().getFrame() = RTFFrame(&m_aStates.top()); }
+
+void RTFDocumentImpl::bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
+ const tools::SvRef<TableRowBuffer>& pTableProperties,
+ Id const nStyleType)
+{
+ rBuffer.emplace_back(BUFFER_SETSTYLE, new RTFValue(m_aStates.top().getCurrentStyleIndex()),
+ nullptr);
+ assert(nStyleType == 0 || nStyleType == NS_ooxml::LN_Value_ST_StyleType_character);
+ rBuffer.emplace_back(nStyleType == NS_ooxml::LN_Value_ST_StyleType_character ? BUFFER_PROPS_CHAR
+ : 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)
+{
+ 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;
+ }
+
+ if (m_pDocumentImpl->getFirstRun() && !m_pDocumentImpl->isStyleSheetImport() && hasProperties())
+ {
+ m_pDocumentImpl->checkFirstRun();
+ m_pDocumentImpl->setNeedPar(false);
+ }
+}
+
+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_text;
+ 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
+{
+ // tdf#153178 \dxfrtext \dfrmtxtx \dfrmtxty \wrapdefault do *not* create frame
+ return m_nX != 0 || m_nY != 0 || m_nW != 0 || m_nH != 0
+ || (m_nHoriAlign && m_nHoriAlign != NS_ooxml::LN_Value_doc_ST_XAlign_left)
+ || (m_nHoriAnchor && m_nHoriAnchor != NS_ooxml::LN_Value_doc_ST_HAnchor_text)
+ || (m_nVertAlign && m_nVertAlign != NS_ooxml::LN_Value_doc_ST_YAlign_inline)
+ || (m_nVertAnchor && m_nVertAnchor != NS_ooxml::LN_Value_doc_ST_VAnchor_margin)
+ || (m_oWrap && *m_oWrap != NS_ooxml::LN_Value_doc_ST_Wrap_auto);
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx b/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
new file mode 100644
index 000000000000..f05f7d321cdd
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfdocumentimpl.hxx
@@ -0,0 +1,995 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <queue>
+#include <tuple>
+#include <vector>
+#include <optional>
+
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <oox/mathml/importutils.hxx>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/color.hxx>
+#include <tools/long.hxx>
+
+#include <rtftok/RTFDocument.hxx>
+#include "rtfreferencetable.hxx"
+#include "rtfsprm.hxx"
+#include "rtflistener.hxx"
+
+class SvStream;
+namespace oox
+{
+class GraphicHelper;
+}
+namespace com::sun::star
+{
+namespace beans
+{
+class XPropertySet;
+}
+namespace document
+{
+class XDocumentProperties;
+}
+namespace lang
+{
+class XMultiServiceFactory;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFParserState;
+class RTFDocumentImpl;
+class RTFTokenizer;
+class RTFSdrImport;
+class TableRowBuffer;
+
+enum class RTFBorderState
+{
+ NONE,
+ PARAGRAPH,
+ PARAGRAPH_BOX,
+ CELL,
+ PAGE,
+ CHARACTER
+};
+
+/// Different kind of buffers for table cell contents.
+enum RTFBufferTypes
+{
+ BUFFER_SETSTYLE,
+ /// Stores properties, should be created only in bufferProperties().
+ BUFFER_PROPS,
+ BUFFER_PROPS_CHAR,
+ 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);
+ /// If we got tokens indicating we're in a frame.
+ bool hasProperties() const;
+};
+
+/// State of the parser, which gets saved / restored when changing groups.
+class RTFParserState
+{
+public:
+ /// Maps to OOXML's ascii, cs or eastAsia.
+ enum class RunType
+ {
+ NONE,
+ LOCH,
+ HICH,
+ DBCH,
+ LTRCH_RTLCH_1,
+ LTRCH_RTLCH_2,
+ RTLCH_LTRCH_1,
+ RTLCH_LTRCH_2
+ };
+
+ explicit RTFParserState(RTFDocumentImpl* pDocumentImpl);
+
+ void appendDestinationText(std::u16string_view rString)
+ {
+ if (m_pCurrentDestinationText)
+ m_pCurrentDestinationText->append(rString);
+ }
+
+ void setPropName(const OUString& rPropName) { m_aPropName = rPropName; }
+ OUString const& getPropName() const { return m_aPropName; }
+ void setPropType(const css::uno::Type& rPropType) { m_aPropType = rPropType; }
+ css::uno::Type const& getPropType() const { return m_aPropType; }
+ void setTableRowWidthAfter(int nTableRowWidthAfter)
+ {
+ m_nTableRowWidthAfter = nTableRowWidthAfter;
+ }
+ int getTableRowWidthAfter() const { return m_nTableRowWidthAfter; }
+ void setStartedTrackchange(bool bStartedTrackchange)
+ {
+ m_bStartedTrackchange = bStartedTrackchange;
+ }
+ bool getStartedTrackchange() const { return m_bStartedTrackchange; }
+ void setCreatedShapeGroup(bool bCreatedShapeGroup)
+ {
+ m_bCreatedShapeGroup = bCreatedShapeGroup;
+ }
+ bool getCreatedShapeGroup() const { return m_bCreatedShapeGroup; }
+ void setInShape(bool bInShape) { m_bInShape = bInShape; }
+ bool getInShape() const { return m_bInShape; }
+ void setInShapeGroup(bool bInShapeGroup) { m_bInShapeGroup = bInShapeGroup; }
+ bool getInShapeGroup() const { return m_bInShapeGroup; }
+ void setHadShapeText(bool bHadShapeText) { m_bHadShapeText = bHadShapeText; }
+ bool getHadShapeText() const { return m_bHadShapeText; }
+ void setInBackground(bool bInBackground) { m_bInBackground = bInBackground; }
+ bool getInBackground() const { return m_bInBackground; }
+ void setInListpicture(bool bInListpicture) { m_bInListpicture = bInListpicture; }
+ bool getInListpicture() const { return m_bInListpicture; }
+ void setCurrentBuffer(RTFBuffer_t* pCurrentBuffer) { m_pCurrentBuffer = pCurrentBuffer; }
+ RTFBuffer_t* getCurrentBuffer() const { return m_pCurrentBuffer; }
+ void setCurrentListOverrideIndex(int nCurrentListOverrideIndex)
+ {
+ m_nCurrentListOverrideIndex = nCurrentListOverrideIndex;
+ }
+ int getCurrentListOverrideIndex() const { return m_nCurrentListOverrideIndex; }
+ void setCurrentListIndex(int nCurrentListIndex) { m_nCurrentListIndex = nCurrentListIndex; }
+ int getCurrentListIndex() const { return m_nCurrentListIndex; }
+ void setCurrentCharacterStyleIndex(int nCurrentCharacterStyleIndex)
+ {
+ m_nCurrentCharacterStyleIndex = nCurrentCharacterStyleIndex;
+ }
+ int getCurrentCharacterStyleIndex() const { return m_nCurrentCharacterStyleIndex; }
+ void setCurrentStyleIndex(int nCurrentStyleIndex) { m_nCurrentStyleIndex = nCurrentStyleIndex; }
+ int getCurrentStyleIndex() const { return m_nCurrentStyleIndex; }
+ void setCurrentDestinationText(OUStringBuffer* pDestinationText)
+ {
+ m_pCurrentDestinationText = pDestinationText;
+ }
+ OUStringBuffer* getCurrentDestinationText() const { return m_pCurrentDestinationText; }
+ OUStringBuffer& getDestinationText() { return m_aDestinationText; }
+ void setMinute(sal_uInt16 nMinute) { m_nMinute = nMinute; }
+ sal_uInt16 getMinute() const { return m_nMinute; }
+ void setHour(sal_uInt16 nHour) { m_nHour = nHour; }
+ sal_uInt16 getHour() const { return m_nHour; }
+ void setDay(sal_uInt16 nDay) { m_nDay = nDay; }
+ sal_uInt16 getDay() const { return m_nDay; }
+ void setMonth(sal_uInt16 nMonth) { m_nMonth = nMonth; }
+ sal_uInt16 getMonth() const { return m_nMonth; }
+ void setYear(sal_uInt16 nYear) { m_nYear = nYear; }
+ sal_uInt16 getYear() const { return m_nYear; }
+ void setRunType(RunType eRunType) { m_eRunType = eRunType; }
+ RunType getRunType() const { return m_eRunType; }
+ RTFFrame& getFrame() { return m_aFrame; }
+ RTFDrawingObject& getDrawingObject() { return m_aDrawingObject; }
+ RTFShape& getShape() { return m_aShape; }
+ RTFPicture& getPicture() { return m_aPicture; }
+ void setLevelNumbersValid(bool bLevelNumbersValid)
+ {
+ m_bLevelNumbersValid = bLevelNumbersValid;
+ }
+ bool getLevelNumbersValid() const { return m_bLevelNumbersValid; }
+ std::vector<sal_Int32>& getLevelNumbers() { return m_aLevelNumbers; }
+ RTFSprms& getListLevelEntries() { return m_aListLevelEntries; }
+ int& getListLevelNum() { return m_nListLevelNum; }
+ void setBinaryToRead(int nBinaryToRead) { m_nBinaryToRead = nBinaryToRead; }
+ int getBinaryToRead() const { return m_nBinaryToRead; }
+ int& getCharsToSkip() { return m_nCharsToSkip; }
+ void setUc(int nUc) { m_nUc = nUc; }
+ int getUc() const { return m_nUc; }
+ void setCurrentEncoding(rtl_TextEncoding nCurrentEncoding)
+ {
+ m_nCurrentEncoding = nCurrentEncoding;
+ }
+ rtl_TextEncoding getCurrentEncoding() const { return m_nCurrentEncoding; }
+ RTFColorTableEntry& getCurrentColor() { return m_aCurrentColor; }
+ RTFSprms& getTabAttributes() { return m_aTabAttributes; }
+ RTFSprms& getTableCellAttributes() { return m_aTableCellAttributes; }
+ RTFSprms& getTableCellSprms() { return m_aTableCellSprms; }
+ RTFSprms& getTableRowAttributes() { return m_aTableRowAttributes; }
+ RTFSprms& getTableRowSprms() { return m_aTableRowSprms; }
+ RTFSprms& getSectionAttributes() { return m_aSectionAttributes; }
+ RTFSprms& getSectionSprms() { return m_aSectionSprms; }
+ RTFSprms& getParagraphAttributes() { return m_aParagraphAttributes; }
+ RTFSprms& getParagraphSprms() { return m_aParagraphSprms; }
+ RTFSprms& getCharacterAttributes() { return m_aCharacterAttributes; }
+ RTFSprms& getCharacterSprms() { return m_aCharacterSprms; }
+ RTFSprms& getTableAttributes() { return m_aTableAttributes; }
+ RTFSprms& getTableSprms() { return m_aTableSprms; }
+ void setBorderState(RTFBorderState nBorderState) { m_nBorderState = nBorderState; }
+ RTFBorderState getBorderState() const { return m_nBorderState; }
+ void setFieldStatus(RTFFieldStatus eFieldStatus) { m_eFieldStatus = eFieldStatus; }
+ RTFFieldStatus getFieldStatus() const { return m_eFieldStatus; }
+ void setFieldLocked(bool bSet) { m_bFieldLocked = bSet; }
+ bool isFieldLocked() const { return m_bFieldLocked; }
+ void setDestination(Destination eDestination) { m_eDestination = eDestination; }
+ Destination getDestination() const { return m_eDestination; }
+ void setInternalState(RTFInternalState nInternalState) { m_nInternalState = nInternalState; }
+ RTFInternalState getInternalState() const { return m_nInternalState; }
+ RTFDocumentImpl* getDocumentImpl() { return m_pDocumentImpl; }
+ OUString getDocVar() { return m_aDocVar; }
+ void appendDocVar(OUString& aDocVar) { m_aDocVar += aDocVar; };
+ OUString getDocVarName() { return m_aDocVarName; }
+ void setDocVarName(OUString& aDocVarName) { m_aDocVarName = aDocVarName; }
+ void clearDocVarName() { m_aDocVarName = ""; }
+
+private:
+ RTFDocumentImpl* m_pDocumentImpl;
+ RTFInternalState m_nInternalState;
+ Destination m_eDestination;
+ RTFFieldStatus m_eFieldStatus;
+ bool m_bFieldLocked;
+ RTFBorderState m_nBorderState;
+ // font table, stylesheet table
+ RTFSprms m_aTableSprms;
+ RTFSprms m_aTableAttributes;
+ // reset by plain
+ RTFSprms m_aCharacterSprms;
+ RTFSprms m_aCharacterAttributes;
+ // reset by pard
+ RTFSprms m_aParagraphSprms;
+ RTFSprms m_aParagraphAttributes;
+ // reset by sectd
+ RTFSprms m_aSectionSprms;
+ RTFSprms m_aSectionAttributes;
+ // reset by trowd
+ RTFSprms m_aTableRowSprms;
+ RTFSprms m_aTableRowAttributes;
+ // reset by cellx
+ RTFSprms m_aTableCellSprms;
+ RTFSprms m_aTableCellAttributes;
+ // reset by tx
+ RTFSprms m_aTabAttributes;
+
+ RTFColorTableEntry m_aCurrentColor;
+
+ rtl_TextEncoding m_nCurrentEncoding;
+
+ /// Current \uc value.
+ int m_nUc;
+ /// Characters to skip, set to nUc by \u.
+ int m_nCharsToSkip;
+ /// Characters to read, once in binary mode.
+ int m_nBinaryToRead;
+
+ /// Next list level index to use when parsing list table.
+ int m_nListLevelNum;
+ /// List level entries, which will form a list entry later.
+ RTFSprms m_aListLevelEntries;
+ /// List of character positions in leveltext to replace.
+ std::vector<sal_Int32> m_aLevelNumbers;
+ /// If aLevelNumbers should be read at all.
+ bool m_bLevelNumbersValid;
+
+ RTFPicture m_aPicture;
+ RTFShape m_aShape;
+ RTFDrawingObject m_aDrawingObject;
+ RTFFrame m_aFrame;
+
+ RunType m_eRunType;
+
+ // Info group.
+ sal_Int16 m_nYear;
+ sal_uInt16 m_nMonth;
+ sal_uInt16 m_nDay;
+ sal_uInt16 m_nHour;
+ sal_uInt16 m_nMinute;
+
+ /// Text from special destinations.
+ OUStringBuffer m_aDestinationText{ 512 };
+ /// point to the buffer of the current destination
+ OUStringBuffer* m_pCurrentDestinationText;
+
+ /// Index of the current style.
+ int m_nCurrentStyleIndex;
+ /// Index of the current character style.
+ int m_nCurrentCharacterStyleIndex;
+ /// Current listid, points to a listtable entry.
+ int m_nCurrentListIndex = -1;
+ /// Current ls, points to a listoverridetable entry.
+ int m_nCurrentListOverrideIndex = -1;
+
+ /// Points to the active buffer, if there is one.
+ RTFBuffer_t* m_pCurrentBuffer;
+
+ /// If we're inside a \listpicture group.
+ bool m_bInListpicture;
+
+ /// If we're inside a \background group.
+ bool m_bInBackground;
+
+ bool m_bHadShapeText;
+ bool m_bInShapeGroup; ///< If we're inside a \shpgrp group.
+ bool m_bInShape; ///< If we're inside a \shp group.
+ bool m_bCreatedShapeGroup; ///< A GroupShape was created and pushed to the parent stack.
+ bool m_bStartedTrackchange; ///< Track change is started, need to end it before popping.
+
+ /// User-defined property: key name.
+ OUString m_aPropName;
+ /// User-defined property: value type.
+ css::uno::Type m_aPropType;
+
+ /// Width of invisible cell at the end of the row.
+ int m_nTableRowWidthAfter;
+
+ /// For importing document variables which are not referenced in the document
+ OUString m_aDocVar;
+ OUString m_aDocVarName;
+};
+
+/// An RTF stack is similar to std::stack, except that it has an operator[].
+struct RTFStack
+{
+private:
+ std::deque<RTFParserState> m_Impl;
+
+public:
+ RTFParserState& top()
+ {
+ if (m_Impl.empty())
+ throw css::io::WrongFormatException(
+ "Parser state is empty! Invalid usage of destination braces in RTF?", nullptr);
+ return m_Impl.back();
+ }
+ void pop()
+ {
+ if (m_Impl.empty())
+ throw css::io::WrongFormatException(
+ "Parser state is empty! Invalid usage of destination braces in RTF?", nullptr);
+ return m_Impl.pop_back();
+ }
+ void push(RTFParserState const& rState) { return m_Impl.push_back(rState); }
+ bool empty() const { return m_Impl.empty(); }
+ size_t size() const { return m_Impl.size(); }
+ const RTFParserState& operator[](size_t nIndex) const { return m_Impl[nIndex]; }
+ RTFParserState& operator[](size_t nIndex) { return m_Impl[nIndex]; }
+};
+
+void putBorderProperty(RTFStack& aStates, Id nId, const RTFValue::Pointer_t& pValue);
+void putNestedSprm(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::NO_APPEND);
+Id getParagraphBorder(sal_uInt32 nIndex);
+void putNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::YES, bool bAttribute = true);
+bool eraseNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Looks up the nParent then the nested nId attribute in rSprms.
+RTFValue::Pointer_t getNestedAttribute(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Looks up the nParent then the nested nId sprm in rSprms.
+RTFValue::Pointer_t getNestedSprm(RTFSprms& rSprms, Id nParent, Id nId);
+
+/// Checks if rName is contained at least once in rProperties as a key.
+bool findPropertyName(const std::vector<css::beans::PropertyValue>& rProperties,
+ const OUString& rName);
+RTFSprms& getLastAttributes(RTFSprms& rSprms, Id nId);
+OString DTTM22OString(tools::Long nDTTM);
+
+/// Implementation of the RTFDocument interface.
+class RTFDocumentImpl : public RTFDocument, public RTFListener
+{
+public:
+ using Pointer_t = tools::SvRef<RTFDocumentImpl>;
+ RTFDocumentImpl(css::uno::Reference<css::uno::XComponentContext> const& xContext,
+ css::uno::Reference<css::io::XInputStream> const& xInputStream,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc,
+ css::uno::Reference<css::frame::XFrame> const& xFrame,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator,
+ const utl::MediaDescriptor& rMediaDescriptor);
+ ~RTFDocumentImpl() override;
+
+ // RTFDocument
+ void resolve(Stream& rMapper) override;
+
+ // RTFListener
+ RTFError dispatchDestination(RTFKeyword nKeyword) override;
+ RTFError dispatchFlag(RTFKeyword nKeyword) override;
+ /// Dispatches flags related to Positioned Wrapped Tables.
+ bool dispatchFloatingTableFlag(RTFKeyword nKeyword);
+ RTFError dispatchSymbol(RTFKeyword nKeyword) override;
+ RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) override;
+ RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
+ bool dispatchTableSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchInfoValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchFrameValue(RTFKeyword nKeyword, int nParam);
+ bool dispatchTableValue(RTFKeyword nKeyword, int nParam);
+ RTFError resolveChars(char ch) override;
+ RTFError pushState() override;
+ RTFError beforePopState(RTFParserState& rState);
+ RTFError popState() override;
+ void afterPopState(RTFParserState& rState);
+ Destination getDestination() override;
+ void setDestination(Destination eDestination) override;
+ RTFInternalState getInternalState() override;
+ void setInternalState(RTFInternalState nInternalState) override;
+ bool getSkipUnknown() override;
+ void setSkipUnknown(bool bSkipUnknown) override;
+ void finishSubstream() override;
+ bool isSubstream() const override;
+
+ Stream& Mapper() { return *m_pMapperStream; }
+ void setSuperstream(RTFDocumentImpl* pSuperstream);
+ const css::uno::Reference<css::lang::XMultiServiceFactory>& getModelFactory() const
+ {
+ return m_xModelFactory;
+ }
+ bool isInBackground();
+ void setDestinationText(std::u16string_view rString);
+ /// Resolve a picture: If not inline, then anchored.
+ void resolvePict(bool bInline, css::uno::Reference<css::drawing::XShape> const& rShape);
+
+ /// If this is the first run of the document, starts the initial paragraph.
+ void checkFirstRun();
+ /// Send NS_ooxml::LN_settings_settings to dmapper.
+ void outputSettingsTable();
+ /// If the initial paragraph is started.
+ bool getFirstRun() const { return m_bFirstRun; }
+ /// If we need to add a dummy paragraph before a section break.
+ void setNeedPar(bool bNeedPar);
+ /// Return the dmapper index of an RTF index for fonts.
+ int getFontIndex(int nIndex);
+ /// Return the name of the font, based on a dmapper index.
+ OUString getFontName(int nIndex);
+ /// Return the style name of an RTF style index.
+ OUString getStyleName(int nIndex);
+ /// Return the style type of an RTF style index.
+ Id getStyleType(int nIndex);
+ /// Return the encoding associated with a font index.
+ rtl_TextEncoding getEncoding(int nFontIndex);
+ /// Get the default parser state.
+ RTFParserState& getDefaultState();
+ oox::GraphicHelper& getGraphicHelper();
+ /// Are we inside the stylesheet table?
+ bool isStyleSheetImport();
+ /// Resets m_aStates.top().aFrame.
+ void resetFrame();
+ /// Buffers properties to be sent later.
+ void bufferProperties(RTFBuffer_t& rBuffer, const RTFValue::Pointer_t& pValue,
+ const tools::SvRef<TableRowBuffer>& pTableProperties, Id nStyleType = 0);
+ /// implement non-obvious RTF specific style inheritance
+ RTFReferenceTable::Entries_t deduplicateStyleTable();
+
+private:
+ SvStream& Strm();
+ Color getColorTable(sal_uInt32 nIndex);
+ writerfilter::Reference<Properties>::Pointer_t createStyleProperties();
+ void resetSprms();
+ void resetAttributes();
+ void resolveSubstream(std::size_t nPos, Id nId);
+ void resolveSubstream(std::size_t nPos, Id nId, OUString const& rIgnoreFirst);
+
+ void text(OUString& rString);
+ // Sends a single character to dmapper, taking care of buffering.
+ void singleChar(sal_uInt8 nValue, bool bRunProps = false);
+ // Sends run properties to dmapper, taking care of buffering.
+ void runProps();
+ void runBreak();
+ void parBreak();
+ void tableBreak();
+ writerfilter::Reference<Properties>::Pointer_t
+ getProperties(const RTFSprms& rAttributes, RTFSprms const& rSprms, Id nStyleType);
+ void checkNeedPap();
+ void handleFontTableEntry();
+ void sectBreak(bool bFinal = false);
+ void prepareProperties(RTFParserState& rState,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t& o_rpTableRowProperties,
+ int nCells, int nCurrentCellX);
+ /// Send the passed properties to dmapper.
+ void sendProperties(writerfilter::Reference<Properties>::Pointer_t const& pParagraphProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pFrameProperties,
+ writerfilter::Reference<Properties>::Pointer_t const& pTableRowProperties);
+ void replayRowBuffer(RTFBuffer_t& rBuffer, ::std::deque<RTFSprms>& rCellsSprms,
+ ::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;
+ /// a synthetic \par was dispatched at the end of the current section
+ bool m_bParAtEndOfSection = false;
+ /// The list table and list override table combined.
+ RTFSprms m_aListTableSprms;
+ /// Maps between listoverridetable and listtable indexes.
+ std::map<int, int> m_aListOverrideTable;
+ /// Maps listtable indexes to listtable entries.
+ std::map<int, RTFValue::Pointer_t> m_aListTable;
+ /// Index of the current list level in a list table entry.
+ int m_nListLevel = -1;
+ /// Maps List level indexes to removed values in the current list entry.
+ std::map<int, int> m_aInvalidListLevelFirstIndents;
+ /// Maps list table indexes to levels (and their removed values).
+ std::map<int, std::map<int, int>> m_aInvalidListTableFirstIndents;
+ /// The settings table attributes.
+ RTFSprms m_aSettingsTableAttributes;
+ /// The settings table sprms.
+ RTFSprms m_aSettingsTableSprms;
+
+ std::shared_ptr<oox::GraphicHelper> m_pGraphicHelper;
+
+ /// cell props buffer for nested tables, reset by \nestrow
+ /// the \nesttableprops is a destination and must follow the
+ /// nested cells, so it should be sufficient to store the
+ /// currently active one, no need for a stack of them
+ int m_nNestedCells;
+ std::deque<RTFSprms> m_aNestedTableCellsSprms;
+ std::deque<RTFSprms> m_aNestedTableCellsAttributes;
+ /// cell props buffer for top-level table, reset by \row
+ int m_nTopLevelCells;
+ std::deque<RTFSprms> m_aTopLevelTableCellsSprms;
+ std::deque<RTFSprms> m_aTopLevelTableCellsAttributes;
+ /// backup of top-level props, to support inheriting cell props
+ int m_nInheritingCells;
+ std::deque<RTFSprms> m_aTableInheritingCellsSprms;
+ std::deque<RTFSprms> m_aTableInheritingCellsAttributes;
+
+ // Left row margin (for nested and top-level rows)
+ int m_nNestedTRLeft;
+ int m_nTopLevelTRLeft;
+
+ /// Current cellx value (nested table)
+ int m_nNestedCurrentCellX;
+ /// Current cellx value (top-level table)
+ int m_nTopLevelCurrentCellX;
+
+ // Backup of what \trowd clears, to work around invalid input.
+ RTFSprms m_aBackupTableRowSprms;
+ RTFSprms m_aBackupTableRowAttributes;
+ int m_nBackupTopLevelCurrentCellX;
+
+ /// Buffered table cells, till cell definitions are not reached.
+ /// for nested table, one buffer per table level
+ std::deque<RTFBuffer_t> m_aTableBufferStack;
+ /// Buffered superscript, till footnote is reached (or not).
+ RTFBuffer_t m_aSuperBuffer;
+
+ /// Superstream of this substream.
+ RTFDocumentImpl* m_pSuperstream;
+ /// Type of the stream: header, footer, footnote, etc.
+ Id m_nStreamType;
+ std::queue<std::pair<Id, std::size_t>> m_nHeaderFooterPositions;
+ std::size_t m_nGroupStartPos;
+ /// Ignore the first occurrence of this text.
+ OUString m_aIgnoreFirst;
+ /// Bookmark name <-> index map.
+ std::map<OUString, int> m_aBookmarks;
+ /// Revision index <-> author map.
+ std::map<int, OUString> m_aAuthors;
+ /// Annotation author of the next annotation.
+ OUString m_aAuthor;
+ /// Initials of author of the next annotation.
+ OUString m_aAuthorInitials;
+
+ RTFSprms m_aFormfieldSprms;
+ RTFSprms m_aFormfieldAttributes;
+ RTFFormFieldType m_nFormFieldType;
+
+ /// OLE attributes are attributes of the ooxml:OLEObject_OLEObject sprm.
+ RTFSprms m_aOLEAttributes;
+ RTFSprms m_aObjectAttributes;
+ /** If we are in an object group and if the we use its
+ * \objdata element.
+ * (if we don't use the \objdata we use the \result element)*/
+ bool m_bObject;
+ /// If the data for a picture is a binary one, it's stored here.
+ std::shared_ptr<SvStream> m_pBinaryData;
+
+ RTFReferenceTable::Entries_t m_aFontTableEntries;
+ int m_nCurrentFontIndex;
+ /// Used only during font table parsing till we don't know the font name.
+ int m_nCurrentEncoding;
+ /// Raw default font index, use getFont() on it to get a real one.
+ int m_nDefaultFontIndex;
+
+ /// To avoid copying entries between DomainMapper instances it is stored as pointer
+ std::shared_ptr<RTFReferenceTable::Entries_t> m_pStyleTableEntries;
+ int m_nCurrentStyleIndex;
+ bool m_bFormField;
+ /// For the INCLUDEPICTURE field's argument.
+ OUString m_aPicturePath;
+ // Unicode characters are collected here so we don't have to send them one by one.
+ OUStringBuffer m_aUnicodeBuffer{ 512 };
+ /// Same for hex characters.
+ OStringBuffer m_aHexBuffer{ 512 };
+ /// Formula import.
+ oox::formulaimport::XmlStreamBuilder m_aMathBuffer;
+ /// Normal text property, that is math italic and math spacing are not applied to the current run.
+ bool m_bMathNor;
+ /// If the next continuous section break should be ignored.
+ bool m_bIgnoreNextContSectBreak;
+ /// clean up a synthetic page break, see RTF_PAGE
+ /// if inactive value is -1, otherwise the RTF_SKB* to restore
+ RTFKeyword m_nResetBreakOnSectBreak;
+ /// If a section break is needed before the end of the doc (false right after a section break).
+ bool m_bNeedSect;
+ /// If aFrame.hasProperties() 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;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtffly.hxx b/sw/source/writerfilter/rtftok/rtffly.hxx
new file mode 100644
index 000000000000..b1dec0c77b4f
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtffly.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+
+#include <ooxml/resourceids.hxx>
+#include <osl/endian.h>
+
+namespace writerfilter::rtftok
+{
+/// Stores the vertical orientation properties of an RTF fly frame.
+class RTFVertOrient
+{
+public:
+ explicit RTFVertOrient(sal_uInt16 nValue)
+ : m_nVal(nValue)
+ {
+ }
+
+ sal_uInt16 GetOrient() const { return OSL_LONIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_uInt16 GetRelation() const { return OSL_HINIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_Int32 GetAlign() const
+ {
+ sal_Int32 nAlign = 0;
+ switch (GetOrient())
+ {
+ case css::text::VertOrientation::CENTER:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_center;
+ break;
+ case css::text::VertOrientation::TOP:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_top;
+ break;
+ case css::text::VertOrientation::BOTTOM:
+ nAlign = NS_ooxml::LN_Value_doc_ST_YAlign_bottom;
+ break;
+ }
+
+ return nAlign;
+ }
+
+ sal_Int32 GetAnchor() const
+ {
+ sal_Int32 nAnchor = 0;
+ switch (GetRelation())
+ {
+ case css::text::RelOrientation::FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_text;
+ break;
+ case css::text::RelOrientation::PAGE_FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_page;
+ break;
+ case css::text::RelOrientation::PAGE_PRINT_AREA:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_VAnchor_margin;
+ break;
+ }
+
+ return nAnchor;
+ }
+
+private:
+ sal_uInt16 m_nVal;
+};
+
+/// Stores the horizontal orientation properties of an RTF fly frame.
+class RTFHoriOrient
+{
+public:
+ explicit RTFHoriOrient(sal_uInt16 nValue)
+ : m_nVal(nValue)
+ {
+ }
+
+ sal_uInt16 GetOrient() const { return OSL_LONIBBLE(OSL_LOBYTE(m_nVal)); }
+
+ sal_uInt16 GetRelation() const { return OSL_LONIBBLE(OSL_HIBYTE(m_nVal)); }
+
+ sal_Int32 GetAlign() const
+ {
+ sal_Int32 nAlign = 0;
+ switch (GetOrient())
+ {
+ case css::text::HoriOrientation::CENTER:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_center;
+ break;
+ case css::text::HoriOrientation::RIGHT:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_right;
+ break;
+ case css::text::HoriOrientation::LEFT:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_left;
+ break;
+ case css::text::HoriOrientation::INSIDE:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_inside;
+ break;
+ case css::text::HoriOrientation::OUTSIDE:
+ nAlign = NS_ooxml::LN_Value_doc_ST_XAlign_outside;
+ break;
+ }
+
+ return nAlign;
+ }
+
+ sal_Int32 GetAnchor() const
+ {
+ sal_Int32 nAnchor = 0;
+ switch (GetRelation())
+ {
+ case css::text::RelOrientation::FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_text;
+ break;
+ case css::text::RelOrientation::PAGE_FRAME:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_page;
+ break;
+ case css::text::RelOrientation::PAGE_PRINT_AREA:
+ nAnchor = NS_ooxml::LN_Value_doc_ST_HAnchor_margin;
+ break;
+ }
+
+ return nAnchor;
+ }
+
+private:
+ sal_uInt16 m_nVal;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtflistener.hxx b/sw/source/writerfilter/rtftok/rtflistener.hxx
new file mode 100644
index 000000000000..150440afbb47
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtflistener.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "rtfcontrolwords.hxx"
+
+namespace writerfilter::rtftok
+{
+enum class RTFInternalState
+{
+ NORMAL,
+ BIN,
+ HEX
+};
+
+enum class RTFError
+{
+ OK,
+ GROUP_UNDER,
+ GROUP_OVER,
+ UNEXPECTED_EOF,
+ HEX_INVALID,
+ CHAR_OVER,
+ CLASSIFICATION
+};
+
+/**
+ * RTFTokenizer needs a class implementing this interface. While
+ * RTFTokenizer separates control words (and their arguments) from
+ * text, the class implementing this interface is expected to map the
+ * raw RTF tokens to dmapper tokens.
+ */
+class RTFListener
+{
+public:
+ virtual ~RTFListener() = default;
+ // Dispatching of control words and characters.
+ virtual RTFError dispatchDestination(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchFlag(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchSymbol(RTFKeyword nKeyword) = 0;
+ virtual RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) = 0;
+ virtual RTFError dispatchValue(RTFKeyword nKeyword, int nParam) = 0;
+ virtual RTFError resolveChars(char ch) = 0;
+
+ // State handling.
+ virtual RTFError pushState() = 0;
+ virtual RTFError popState() = 0;
+
+ virtual Destination getDestination() = 0;
+ virtual void setDestination(Destination eDestination) = 0;
+ virtual RTFInternalState getInternalState() = 0;
+ virtual void setInternalState(RTFInternalState nInternalState) = 0;
+ virtual bool getSkipUnknown() = 0;
+ virtual void setSkipUnknown(bool bSkipUnknown) = 0;
+
+ // Substream handling.
+ virtual void finishSubstream() = 0;
+ virtual bool isSubstream() const = 0;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtflookahead.cxx b/sw/source/writerfilter/rtftok/rtflookahead.cxx
new file mode 100644
index 000000000000..033feacce69d
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtflookahead.cxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtflookahead.hxx"
+#include <com/sun/star/uno/Reference.hxx>
+#include <tools/stream.hxx>
+#include "rtftokenizer.hxx"
+
+namespace com::sun::star::task
+{
+class XStatusIndicator;
+}
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFLookahead::RTFLookahead(SvStream& rStream, sal_uInt64 nGroupStart)
+ : m_rStream(rStream)
+ , m_bHasTable(false)
+ , m_bHasColumns(false)
+{
+ sal_uInt64 const nPos = m_rStream.Tell();
+ m_rStream.Seek(nGroupStart);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+ m_pTokenizer = new RTFTokenizer(*this, &m_rStream, xStatusIndicator);
+ m_pTokenizer->resolveParse();
+ m_rStream.Seek(nPos);
+}
+
+RTFLookahead::~RTFLookahead() = default;
+
+RTFError RTFLookahead::dispatchDestination(RTFKeyword /*nKeyword*/) { return RTFError::OK; }
+
+RTFError RTFLookahead::dispatchFlag(RTFKeyword nKeyword)
+{
+ if (nKeyword == RTFKeyword::INTBL)
+ m_bHasTable = true;
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::dispatchSymbol(RTFKeyword /*nKeyword*/) { return RTFError::OK; }
+
+RTFError RTFLookahead::dispatchToggle(RTFKeyword /*nKeyword*/, bool /*bParam*/, int /*nParam*/)
+{
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::dispatchValue(RTFKeyword nKeyword, int nParam)
+{
+ if (nKeyword == RTFKeyword::COLS && nParam >= 2)
+ m_bHasColumns = true;
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::resolveChars(char ch)
+{
+ while (!m_rStream.eof() && (ch != '{' && ch != '}' && ch != '\\'))
+ m_rStream.ReadChar(ch);
+ if (!m_rStream.eof())
+ m_rStream.SeekRel(-1);
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::pushState()
+{
+ m_pTokenizer->pushGroup();
+ return RTFError::OK;
+}
+
+RTFError RTFLookahead::popState()
+{
+ m_pTokenizer->popGroup();
+ return RTFError::OK;
+}
+
+Destination RTFLookahead::getDestination() { return Destination::NORMAL; }
+
+void RTFLookahead::setDestination(Destination /*eDestination*/) {}
+
+RTFInternalState RTFLookahead::getInternalState() { return RTFInternalState::NORMAL; }
+
+void RTFLookahead::setInternalState(RTFInternalState /*nInternalState*/) {}
+
+bool RTFLookahead::getSkipUnknown() { return false; }
+
+void RTFLookahead::setSkipUnknown(bool /*bSkipUnknown*/) {}
+
+void RTFLookahead::finishSubstream() {}
+
+bool RTFLookahead::isSubstream() const { return false; }
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtflookahead.hxx b/sw/source/writerfilter/rtftok/rtflookahead.hxx
new file mode 100644
index 000000000000..9ec213f624c3
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtflookahead.hxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <tools/ref.hxx>
+#include "rtflistener.hxx"
+
+class SvStream;
+
+namespace writerfilter::rtftok
+{
+class RTFTokenizer;
+/**
+ * This acts like an importer, but used for looking ahead, e.g. to
+ * determine if the current group contains a table, etc.
+ */
+class RTFLookahead : public RTFListener
+{
+public:
+ RTFLookahead(SvStream& rStream, sal_uInt64 nGroupStart);
+ ~RTFLookahead() override;
+ RTFError dispatchDestination(RTFKeyword nKeyword) override;
+ RTFError dispatchFlag(RTFKeyword nKeyword) override;
+ RTFError dispatchSymbol(RTFKeyword nKeyword) override;
+ RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) override;
+ RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
+ RTFError resolveChars(char ch) override;
+ RTFError pushState() override;
+ RTFError popState() override;
+ Destination getDestination() override;
+ void setDestination(Destination eDestination) override;
+ RTFInternalState getInternalState() override;
+ void setInternalState(RTFInternalState nInternalState) override;
+ bool getSkipUnknown() override;
+ void setSkipUnknown(bool bSkipUnknown) override;
+ void finishSubstream() override;
+ bool isSubstream() const override;
+ bool hasTable() const { return m_bHasTable; }
+ bool hasColumns() const { return m_bHasColumns; }
+
+private:
+ tools::SvRef<RTFTokenizer> m_pTokenizer;
+ SvStream& m_rStream;
+ bool m_bHasTable;
+ bool m_bHasColumns;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfreferenceproperties.cxx b/sw/source/writerfilter/rtftok/rtfreferenceproperties.cxx
new file mode 100644
index 000000000000..d32557bc7d46
--- /dev/null
+++ b/sw/source/writerfilter/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/sw/source/writerfilter/rtftok/rtfreferenceproperties.hxx b/sw/source/writerfilter/rtftok/rtfreferenceproperties.hxx
new file mode 100644
index 000000000000..6a5e5618ba30
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfreferenceproperties.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "rtfsprm.hxx"
+
+namespace writerfilter::rtftok
+{
+/// Sends RTFSprm instances to DomainMapper.
+class RTFReferenceProperties : public writerfilter::Reference<Properties>
+{
+public:
+ RTFReferenceProperties(RTFSprms aAttributes, RTFSprms aSprms);
+ explicit RTFReferenceProperties(RTFSprms aAttributes);
+ ~RTFReferenceProperties() override;
+ void resolve(Properties& rHandler) override;
+ RTFSprms& getAttributes() { return m_aAttributes; }
+ RTFSprms& getSprms() { return m_aSprms; }
+
+private:
+ RTFSprms m_aAttributes;
+ RTFSprms m_aSprms;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfreferencetable.cxx b/sw/source/writerfilter/rtftok/rtfreferencetable.cxx
new file mode 100644
index 000000000000..1a70a93d9bf8
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfreferencetable.cxx
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfreferencetable.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFReferenceTable::RTFReferenceTable(Entries_t aEntries)
+ : m_aEntries(std::move(aEntries))
+{
+}
+
+RTFReferenceTable::~RTFReferenceTable() = default;
+
+void RTFReferenceTable::resolve(Table& rHandler)
+{
+ for (const auto& rEntry : m_aEntries)
+ rHandler.entry(rEntry.first, rEntry.second);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfreferencetable.hxx b/sw/source/writerfilter/rtftok/rtfreferencetable.hxx
new file mode 100644
index 000000000000..76cbaacf2371
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfreferencetable.hxx
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <map>
+#include <dmapper/resourcemodel.hxx>
+
+namespace writerfilter::rtftok
+{
+/// Sends tables (e.g. font table) to the domain mapper.
+class RTFReferenceTable : public writerfilter::Reference<Table>
+{
+public:
+ using Entries_t = std::map<int, writerfilter::Reference<Properties>::Pointer_t>;
+ using Entry_t = std::pair<int, writerfilter::Reference<Properties>::Pointer_t>;
+ explicit RTFReferenceTable(Entries_t aEntries);
+ ~RTFReferenceTable() override;
+ void resolve(Table& rHandler) override;
+
+private:
+ Entries_t m_aEntries;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfsdrimport.cxx b/sw/source/writerfilter/rtftok/rtfsdrimport.cxx
new file mode 100644
index 000000000000..d9c57be4a8a8
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfsdrimport.cxx
@@ -0,0 +1,1186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfsdrimport.hxx"
+#include <cmath>
+#include <optional>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/FillStyle.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/LineStyle.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
+#include <com/sun/star/drawing/ColorMode.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/text/HoriOrientation.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <ooxml/resourceids.hxx>
+#include <filter/msfilter/escherex.hxx>
+#include <filter/msfilter/util.hxx>
+#include <filter/msfilter/rtfutil.hxx>
+#include <sal/log.hxx>
+#include <svx/svdtrans.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/propertysequence.hxx>
+#include "rtfreferenceproperties.hxx"
+#include <oox/vml/vmlformatting.hxx>
+#include <oox/helper/modelobjecthelper.hxx>
+#include <oox/drawingml/drawingmltypes.hxx>
+#include <oox/drawingml/shapepropertymap.hxx>
+#include <oox/helper/propertyset.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <svx/svdobj.hxx>
+#include <tools/UnitConversion.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include "rtfdocumentimpl.hxx"
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFSdrImport::RTFSdrImport(RTFDocumentImpl& rDocument,
+ uno::Reference<lang::XComponent> const& xDstDoc)
+ : m_rImport(rDocument)
+ , m_bTextFrame(false)
+ , m_bTextGraphicObject(false)
+ , m_bFakePict(false)
+{
+ uno::Reference<drawing::XDrawPageSupplier> xDrawings(xDstDoc, uno::UNO_QUERY);
+ if (xDrawings.is())
+ m_aParents.push(xDrawings->getDrawPage());
+ m_aGraphicZOrderHelpers.push(writerfilter::dmapper::GraphicZOrderHelper());
+}
+
+RTFSdrImport::~RTFSdrImport()
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ m_aGraphicZOrderHelpers.pop();
+ if (!m_aParents.empty())
+ m_aParents.pop();
+}
+
+void RTFSdrImport::createShape(const OUString& rService, uno::Reference<drawing::XShape>& xShape,
+ uno::Reference<beans::XPropertySet>& xPropertySet)
+{
+ if (m_rImport.getModelFactory().is())
+ xShape.set(m_rImport.getModelFactory()->createInstance(rService), uno::UNO_QUERY);
+ xPropertySet.set(xShape, uno::UNO_QUERY);
+}
+
+std::vector<beans::PropertyValue> RTFSdrImport::getTextFrameDefaults(bool bNew)
+{
+ std::vector<beans::PropertyValue> aRet;
+ beans::PropertyValue aPropertyValue;
+
+ aPropertyValue.Name = "HoriOrient";
+ aPropertyValue.Value <<= text::HoriOrientation::NONE;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "HoriOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "VertOrient";
+ aPropertyValue.Value <<= text::VertOrientation::NONE;
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "VertOrientRelation";
+ aPropertyValue.Value <<= text::RelOrientation::FRAME;
+ aRet.push_back(aPropertyValue);
+ if (!bNew)
+ {
+ aPropertyValue.Name = "BackColorTransparency";
+ aPropertyValue.Value <<= sal_Int32(100);
+ aRet.push_back(aPropertyValue);
+ }
+ // See the spec, new-style frame default margins are specified in EMUs.
+ aPropertyValue.Name = "LeftBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "RightBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (91440 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "TopBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "BottomBorderDistance";
+ aPropertyValue.Value <<= sal_Int32(bNew ? (45720 / 360) : 0);
+ aRet.push_back(aPropertyValue);
+ aPropertyValue.Name = "SizeType";
+ aPropertyValue.Value <<= text::SizeType::FIX;
+ aRet.push_back(aPropertyValue);
+ return aRet;
+}
+
+void RTFSdrImport::pushParent(uno::Reference<drawing::XShapes> const& xParent)
+{
+ m_aParents.push(xParent);
+ m_aGraphicZOrderHelpers.push(writerfilter::dmapper::GraphicZOrderHelper());
+}
+
+void RTFSdrImport::popParent()
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ m_aGraphicZOrderHelpers.pop();
+ if (!m_aParents.empty())
+ m_aParents.pop();
+}
+
+void RTFSdrImport::resolveDhgt(uno::Reference<beans::XPropertySet> const& xPropertySet,
+ sal_Int32 const nZOrder, bool const bOldStyle)
+{
+ if (!m_aGraphicZOrderHelpers.empty())
+ {
+ writerfilter::dmapper::GraphicZOrderHelper& rHelper = m_aGraphicZOrderHelpers.top();
+ xPropertySet->setPropertyValue("ZOrder", uno::Any(rHelper.findZOrder(nZOrder, bOldStyle)));
+ rHelper.addItem(xPropertySet, nZOrder);
+ }
+}
+
+void RTFSdrImport::resolveLineColorAndWidth(bool bTextFrame,
+ const uno::Reference<beans::XPropertySet>& xPropertySet,
+ uno::Any const& rLineColor, uno::Any const& rLineWidth)
+{
+ if (!bTextFrame)
+ {
+ xPropertySet->setPropertyValue("LineColor", rLineColor);
+ xPropertySet->setPropertyValue("LineWidth", rLineWidth);
+ }
+ else
+ {
+ static const char* aBorders[]
+ = { "TopBorder", "LeftBorder", "BottomBorder", "RightBorder" };
+ for (const char* pBorder : aBorders)
+ {
+ auto aBorderLine = xPropertySet->getPropertyValue(OUString::createFromAscii(pBorder))
+ .get<table::BorderLine2>();
+ if (rLineColor.hasValue())
+ aBorderLine.Color = rLineColor.get<sal_Int32>();
+ if (rLineWidth.hasValue())
+ aBorderLine.LineWidth = rLineWidth.get<sal_Int32>();
+ xPropertySet->setPropertyValue(OUString::createFromAscii(pBorder),
+ uno::Any(aBorderLine));
+ }
+ }
+}
+
+void RTFSdrImport::resolveFLine(uno::Reference<beans::XPropertySet> const& xPropertySet,
+ sal_Int32 const nFLine)
+{
+ if (nFLine == 0)
+ xPropertySet->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE));
+ else
+ xPropertySet->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_SOLID));
+}
+
+void RTFSdrImport::applyProperty(uno::Reference<drawing::XShape> const& xShape,
+ std::u16string_view aKey, std::u16string_view aValue) const
+{
+ uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
+ sal_Int16 nHoriOrient = 0;
+ sal_Int16 nVertOrient = 0;
+ std::optional<bool> obFitShapeToText;
+ bool bFilled = true;
+
+ if (aKey == u"posh")
+ {
+ switch (o3tl::toInt32(aValue))
+ {
+ case 1:
+ nHoriOrient = text::HoriOrientation::LEFT;
+ break;
+ case 2:
+ nHoriOrient = text::HoriOrientation::CENTER;
+ break;
+ case 3:
+ nHoriOrient = text::HoriOrientation::RIGHT;
+ break;
+ case 4:
+ nHoriOrient = text::HoriOrientation::INSIDE;
+ break;
+ case 5:
+ nHoriOrient = text::HoriOrientation::OUTSIDE;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (aKey == u"posv")
+ {
+ switch (o3tl::toInt32(aValue))
+ {
+ case 1:
+ nVertOrient = text::VertOrientation::TOP;
+ break;
+ case 2:
+ nVertOrient = text::VertOrientation::CENTER;
+ break;
+ case 3:
+ nVertOrient = text::VertOrientation::BOTTOM;
+ break;
+ default:
+ break;
+ }
+ }
+ else if (aKey == u"fFitShapeToText")
+ obFitShapeToText = o3tl::toInt32(aValue) == 1;
+ else if (aKey == u"fFilled")
+ bFilled = o3tl::toInt32(aValue) == 1;
+ else if (aKey == u"rotation")
+ {
+ // See DffPropertyReader::Fix16ToAngle(): in RTF, positive rotation angles are clockwise, we have them as counter-clockwise.
+ // Additionally, RTF type is 0..360*2^16, our is 0..360*100.
+ sal_Int32 nRotation = o3tl::toInt32(aValue) * 100 / RTF_MULTIPLIER;
+ uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY);
+ if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
+ xPropertySet->setPropertyValue(
+ "RotateAngle", uno::Any(NormAngle36000(Degree100(nRotation * -1)).get()));
+ }
+
+ if (nHoriOrient != 0 && xPropertySet.is())
+ xPropertySet->setPropertyValue("HoriOrient", uno::Any(nHoriOrient));
+ if (nVertOrient != 0 && xPropertySet.is())
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(nVertOrient));
+ if (obFitShapeToText.has_value() && xPropertySet.is())
+ {
+ xPropertySet->setPropertyValue(
+ "SizeType", uno::Any(*obFitShapeToText ? text::SizeType::MIN : text::SizeType::FIX));
+ xPropertySet->setPropertyValue("FrameIsAutomaticHeight", uno::Any(*obFitShapeToText));
+ }
+ if (!bFilled && xPropertySet.is())
+ {
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("BackColorTransparency", uno::Any(sal_Int32(100)));
+ else
+ xPropertySet->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE));
+ }
+}
+
+int RTFSdrImport::initShape(uno::Reference<drawing::XShape>& o_xShape,
+ uno::Reference<beans::XPropertySet>& o_xPropSet, bool& o_rIsCustomShape,
+ RTFShape const& rShape, bool const bClose,
+ ShapeOrPict const shapeOrPict)
+{
+ assert(!o_xShape.is());
+ assert(!o_xPropSet.is());
+ o_rIsCustomShape = false;
+ m_bFakePict = false;
+
+ // first, find the shape type
+ int nType = -1;
+ auto iter = std::find_if(rShape.getProperties().begin(), rShape.getProperties().end(),
+ [](const std::pair<OUString, OUString>& rProperty) {
+ return rProperty.first == "shapeType";
+ });
+
+ if (iter == rShape.getProperties().end())
+ {
+ if (SHAPE == shapeOrPict)
+ {
+ // The spec doesn't state what is the default for shapeType,
+ // Word seems to implement it as a rectangle.
+ nType = ESCHER_ShpInst_Rectangle;
+ }
+ else
+ {
+ // pict is picture by default but can be a rectangle too fdo#79319
+ nType = ESCHER_ShpInst_PictureFrame;
+ }
+ }
+ else
+ {
+ nType = iter->second.toInt32();
+ if (PICT == shapeOrPict && ESCHER_ShpInst_PictureFrame != nType)
+ {
+ m_bFakePict = true;
+ }
+ }
+
+ switch (nType)
+ {
+ case ESCHER_ShpInst_PictureFrame:
+ createShape("com.sun.star.drawing.GraphicObjectShape", o_xShape, o_xPropSet);
+ m_bTextGraphicObject = true;
+ break;
+ case ESCHER_ShpInst_Line:
+ createShape("com.sun.star.drawing.LineShape", o_xShape, o_xPropSet);
+ break;
+ case ESCHER_ShpInst_Rectangle:
+ case ESCHER_ShpInst_TextBox:
+ // If we're inside a groupshape, can't use text frames.
+ if (!bClose && m_aParents.size() == 1)
+ {
+ createShape("com.sun.star.text.TextFrame", o_xShape, o_xPropSet);
+ m_bTextFrame = true;
+ std::vector<beans::PropertyValue> aDefaults = getTextFrameDefaults(true);
+ for (const beans::PropertyValue& i : aDefaults)
+ o_xPropSet->setPropertyValue(i.Name, i.Value);
+ break;
+ }
+ [[fallthrough]];
+ default:
+ createShape("com.sun.star.drawing.CustomShape", o_xShape, o_xPropSet);
+ o_rIsCustomShape = true;
+ break;
+ }
+
+ // Defaults
+ if (o_xPropSet.is() && !m_bTextFrame)
+ {
+ o_xPropSet->setPropertyValue(
+ "FillColor",
+ uno::Any(sal_uInt32(0xffffff))); // White in Word, kind of blue in Writer.
+ o_xPropSet->setPropertyValue("VertOrient", uno::Any(text::VertOrientation::NONE));
+ }
+
+ return nType;
+}
+
+void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, ShapeOrPict const shapeOrPict)
+{
+ bool bPib = false;
+ m_bTextFrame = false;
+ m_bTextGraphicObject = false;
+
+ uno::Reference<drawing::XShape> xShape;
+ uno::Reference<beans::XPropertySet> xPropertySet;
+ uno::Any aAny;
+ beans::PropertyValue aPropertyValue;
+ awt::Rectangle aViewBox;
+ std::vector<beans::PropertyValue> aPath;
+ // Default line color is black in Word, blue in Writer.
+ uno::Any aLineColor(COL_BLACK);
+ // Default line width is 0.75 pt (26 mm100) in Word, 0 in Writer.
+ uno::Any aLineWidth(sal_Int32(26));
+ sal_Int16 eWritingMode = text::WritingMode2::LR_TB;
+ // Groupshape support
+ std::optional<sal_Int32> oGroupLeft;
+ std::optional<sal_Int32> oGroupTop;
+ std::optional<sal_Int32> oGroupRight;
+ std::optional<sal_Int32> oGroupBottom;
+ std::optional<sal_Int32> oRelLeft;
+ std::optional<sal_Int32> oRelTop;
+ std::optional<sal_Int32> oRelRight;
+ std::optional<sal_Int32> oRelBottom;
+
+ // Importing these are not trivial, let the VML import do the hard work.
+ oox::vml::FillModel aFillModel; // Gradient.
+ oox::vml::ShadowModel aShadowModel; // Shadow.
+
+ bool bOpaque = true;
+
+ std::optional<sal_Int16> oRelativeWidth;
+ std::optional<sal_Int16> oRelativeHeight;
+ sal_Int16 nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ sal_Int16 nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ std::optional<bool> obRelFlipV;
+ bool obFlipH(false);
+ bool obFlipV(false);
+
+ OUString aShapeText = "";
+ OUString aFontFamily = "";
+ float nFontSize = 1.0;
+
+ sal_Int32 nContrast = 0x10000;
+ sal_Int16 nBrightness = 0;
+
+ bool bCustom(false);
+ int const nType = initShape(xShape, xPropertySet, bCustom, rShape, bClose, shapeOrPict);
+ if (nType == ESCHER_ShpInst_PictureFrame && xPropertySet.is())
+ {
+ xPropertySet->setPropertyValue("IsEmptyPresentationObject", uno::Any(true));
+ }
+
+ for (auto& rProperty : rShape.getProperties())
+ {
+ if (rProperty.first == "shapeType")
+ {
+ continue; // ignore: already handled by initShape
+ }
+ if (rProperty.first == "wzName")
+ {
+ if (m_bTextFrame)
+ {
+ uno::Reference<container::XNamed> xNamed(xShape, uno::UNO_QUERY);
+ xNamed->setName(rProperty.second);
+ }
+ else
+ xPropertySet->setPropertyValue("Name", uno::Any(rProperty.second));
+ }
+ else if (rProperty.first == "wzDescription")
+ xPropertySet->setPropertyValue("Description", uno::Any(rProperty.second));
+ else if (rProperty.first == "gtextUNICODE")
+ aShapeText = rProperty.second;
+ else if (rProperty.first == "gtextFont")
+ aFontFamily = rProperty.second;
+ else if (rProperty.first == "gtextSize")
+ {
+ // RTF size is multiplied by 2^16
+ nFontSize = static_cast<float>(rProperty.second.toUInt32()) / RTF_MULTIPLIER;
+ }
+ else if (rProperty.first == "pib")
+ {
+ m_rImport.setDestinationText(rProperty.second);
+ bPib = true;
+ }
+ else if (rProperty.first == "fillColor" && xPropertySet.is())
+ {
+ aAny <<= msfilter::util::BGRToRGB(rProperty.second.toUInt32());
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("BackColor", aAny);
+ else
+ xPropertySet->setPropertyValue("FillColor", aAny);
+
+ // fillType will decide, possible it'll be the start color of a gradient.
+ aFillModel.moColor
+ = "#"
+ + msfilter::util::ConvertColorOU(Color(ColorTransparency, aAny.get<sal_Int32>()));
+ }
+ else if (rProperty.first == "fillBackColor")
+ // fillType will decide, possible it'll be the end color of a gradient.
+ aFillModel.moColor2 = "#"
+ + msfilter::util::ConvertColorOU(
+ msfilter::util::BGRToRGB(rProperty.second.toInt32()));
+ else if (rProperty.first == "lineColor")
+ aLineColor <<= msfilter::util::BGRToRGB(rProperty.second.toInt32());
+ else if (rProperty.first == "lineBackColor")
+ ; // Ignore: complementer of lineColor
+ else if (rProperty.first == "txflTextFlow" && xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1: // Top to bottom ASCII font
+ case 3: // Top to bottom non-ASCII font
+ eWritingMode = text::WritingMode2::TB_RL;
+ break;
+ case 2: // Bottom to top non-ASCII font
+ eWritingMode = text::WritingMode2::BT_LR;
+ break;
+ }
+ }
+ else if (rProperty.first == "fLine" && xPropertySet.is())
+ resolveFLine(xPropertySet, rProperty.second.toInt32());
+ else if (rProperty.first == "fillOpacity" && xPropertySet.is())
+ {
+ int opacity = 100 - (rProperty.second.toInt32()) * 100 / RTF_MULTIPLIER;
+ xPropertySet->setPropertyValue("FillTransparence", uno::Any(sal_uInt32(opacity)));
+ }
+ else if (rProperty.first == "lineWidth")
+ aLineWidth <<= rProperty.second.toInt32() / 360;
+ else if (rProperty.first == "pVerticies")
+ {
+ std::vector<drawing::EnhancedCustomShapeParameterPair> aCoordinates;
+ sal_Int32 nSize = 0; // Size of a token (its value is hardwired in the exporter)
+ sal_Int32 nCount = 0; // Number of tokens
+ sal_Int32 nCharIndex = 0; // Character index
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(rProperty.second, 0, ';', nCharIndex);
+ if (!nSize)
+ nSize = o3tl::toInt32(aToken);
+ else if (!nCount)
+ nCount = o3tl::toInt32(aToken);
+ else if (!aToken.empty())
+ {
+ // The coordinates are in an (x,y) form.
+ aToken = aToken.substr(1, aToken.size() - 2);
+ sal_Int32 nI = 0;
+ sal_Int32 nX = o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI));
+ sal_Int32 nY
+ = (nI >= 0) ? o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI)) : 0;
+ drawing::EnhancedCustomShapeParameterPair aPair;
+ aPair.First.Value <<= nX;
+ aPair.Second.Value <<= nY;
+ aCoordinates.push_back(aPair);
+ }
+ } while (nCharIndex >= 0);
+ aPropertyValue.Name = "Coordinates";
+ aPropertyValue.Value <<= comphelper::containerToSequence(aCoordinates);
+ aPath.push_back(aPropertyValue);
+ }
+ else if (rProperty.first == "pSegmentInfo")
+ {
+ std::vector<drawing::EnhancedCustomShapeSegment> aSegments;
+ sal_Int32 nSize = 0;
+ sal_Int32 nCount = 0;
+ sal_Int32 nCharIndex = 0;
+ do
+ {
+ sal_Int32 nSeg
+ = o3tl::toInt32(o3tl::getToken(rProperty.second, 0, ';', nCharIndex));
+ if (!nSize)
+ nSize = nSeg;
+ else if (!nCount)
+ nCount = nSeg;
+ else
+ {
+ sal_Int32 nPoints = 1;
+ if (nSeg >= 0x2000 && nSeg < 0x20FF)
+ {
+ nPoints = nSeg & 0x0FFF;
+ nSeg &= 0xFF00;
+ }
+
+ drawing::EnhancedCustomShapeSegment aSegment;
+ switch (nSeg)
+ {
+ case 0x0001: // lineto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
+ aSegment.Count = sal_Int32(1);
+ aSegments.push_back(aSegment);
+ break;
+ case 0x4000: // moveto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
+ aSegment.Count = sal_Int32(1);
+ aSegments.push_back(aSegment);
+ break;
+ case 0x2000: // curveto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::CURVETO;
+ aSegment.Count = nPoints;
+ aSegments.push_back(aSegment);
+ break;
+ case 0xb300: // arcto
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::ARCTO;
+ aSegment.Count = sal_Int32(0);
+ aSegments.push_back(aSegment);
+ break;
+ case 0xac00:
+ case 0xaa00: // nofill
+ case 0xab00: // nostroke
+ case 0x6001: // close
+ break;
+ case 0x8000: // end
+ aSegment.Command
+ = drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
+ aSegment.Count = sal_Int32(0);
+ aSegments.push_back(aSegment);
+ break;
+ default: // given number of lineto elements
+ aSegment.Command = drawing::EnhancedCustomShapeSegmentCommand::LINETO;
+ aSegment.Count = nSeg;
+ aSegments.push_back(aSegment);
+ break;
+ }
+ }
+ } while (nCharIndex >= 0);
+ aPropertyValue.Name = "Segments";
+ aPropertyValue.Value <<= comphelper::containerToSequence(aSegments);
+ aPath.push_back(aPropertyValue);
+ }
+ else if (rProperty.first == "geoLeft")
+ aViewBox.X = rProperty.second.toInt32();
+ else if (rProperty.first == "geoTop")
+ aViewBox.Y = rProperty.second.toInt32();
+ else if (rProperty.first == "geoRight")
+ aViewBox.Width = rProperty.second.toInt32();
+ else if (rProperty.first == "geoBottom")
+ aViewBox.Height = rProperty.second.toInt32();
+ else if (rProperty.first == "dhgt")
+ {
+ // dhgt is Word 2007, \shpz is Word 97-2003, the later has priority.
+ if (!rShape.hasZ())
+ resolveDhgt(xPropertySet, rProperty.second.toInt32(), /*bOldStyle=*/false);
+ }
+ // These are in EMU, convert to mm100.
+ else if (rProperty.first == "dxTextLeft")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("LeftBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyTextTop")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("TopBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxTextRight")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("RightBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyTextBottom")
+ {
+ if (xPropertySet.is())
+ xPropertySet->setPropertyValue("BottomBorderDistance",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxWrapDistLeft")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distL,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("LeftMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyWrapDistTop")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distT,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("TopMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dxWrapDistRight")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distR,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("RightMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "dyWrapDistBottom")
+ {
+ if (m_bTextGraphicObject)
+ rShape.getAnchorAttributes().set(NS_ooxml::LN_CT_Anchor_distB,
+ new RTFValue(rProperty.second.toInt32()));
+ else if (xPropertySet.is())
+ xPropertySet->setPropertyValue("BottomMargin",
+ uno::Any(rProperty.second.toInt32() / 360));
+ }
+ else if (rProperty.first == "fillType")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 7: // Shade using the fillAngle
+ aFillModel.moType = oox::XML_gradient;
+ break;
+ default:
+ SAL_INFO("writerfilter",
+ "TODO handle fillType value '" << rProperty.second << "'");
+ break;
+ }
+ }
+ else if (rProperty.first == "fillAngle")
+ {
+ aFillModel.moAngle = rProperty.second.toInt32() / oox::drawingml::PER_DEGREE;
+ }
+ else if (rProperty.first == "fillFocus")
+ aFillModel.moFocus = 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 = "#"
+ + msfilter::util::ConvertColorOU(
+ msfilter::util::BGRToRGB(rProperty.second.toInt32()));
+ else if (rProperty.first == "shadowOffsetX")
+ // EMUs to points
+ aShadowModel.moOffset = OUString::number(rProperty.second.toDouble() / 12700) + "pt";
+ else if (rProperty.first == "posh" || rProperty.first == "posv"
+ || rProperty.first == "fFitShapeToText" || rProperty.first == "fFilled"
+ || rProperty.first == "rotation")
+ applyProperty(xShape, rProperty.first, rProperty.second);
+ else if (rProperty.first == "posrelh")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1:
+ rShape.setHoriOrientRelation(text::RelOrientation::PAGE_FRAME);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rProperty.first == "posrelv")
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 1:
+ rShape.setVertOrientRelation(text::RelOrientation::PAGE_FRAME);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (rProperty.first == "groupLeft")
+ oGroupLeft = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupTop")
+ oGroupTop = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupRight")
+ oGroupRight = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "groupBottom")
+ oGroupBottom = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relLeft")
+ oRelLeft = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relTop")
+ oRelTop = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relRight")
+ oRelRight = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "relBottom")
+ oRelBottom = convertTwipToMm100(rProperty.second.toInt32());
+ else if (rProperty.first == "fBehindDocument")
+ bOpaque = !rProperty.second.toInt32();
+ else if (rProperty.first == "pctHoriz" || rProperty.first == "pctVert")
+ {
+ sal_Int16 nPercentage = rtl::math::round(rProperty.second.toDouble() / 10);
+ if (nPercentage)
+ {
+ std::optional<sal_Int16>& rPercentage
+ = rProperty.first == "pctHoriz" ? oRelativeWidth : oRelativeHeight;
+ rPercentage = nPercentage;
+ }
+ }
+ else if (rProperty.first == "sizerelh")
+ {
+ if (xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 0: // margin
+ nRelativeWidthRelation = text::RelOrientation::FRAME;
+ break;
+ case 1: // page
+ nRelativeWidthRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+ default:
+ SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelh value: "
+ << rProperty.second);
+ break;
+ }
+ }
+ }
+ else if (rProperty.first == "sizerelv")
+ {
+ if (xPropertySet.is())
+ {
+ switch (rProperty.second.toInt32())
+ {
+ case 0: // margin
+ nRelativeHeightRelation = text::RelOrientation::FRAME;
+ break;
+ case 1: // page
+ nRelativeHeightRelation = text::RelOrientation::PAGE_FRAME;
+ break;
+ default:
+ SAL_WARN("writerfilter", "RTFSdrImport::resolve: unhandled sizerelv value: "
+ << rProperty.second);
+ break;
+ }
+ }
+ }
+ else if (rProperty.first == "fHorizRule") // TODO: what does "fStandardHR" do?
+ {
+ // horizontal rule: relative width defaults to 100% of paragraph
+ // TODO: does it have a default height?
+ if (!oRelativeWidth)
+ {
+ oRelativeWidth = 100;
+ }
+ nRelativeWidthRelation = text::RelOrientation::FRAME;
+ if (xPropertySet.is())
+ {
+ sal_Int16 const nVertOrient = text::VertOrientation::CENTER;
+ xPropertySet->setPropertyValue("VertOrient", uno::Any(nVertOrient));
+ }
+ }
+ else if (rProperty.first == "pctHR")
+ {
+ // horizontal rule relative width in permille
+ oRelativeWidth = rProperty.second.toInt32() / 10;
+ }
+ else if (rProperty.first == "dxHeightHR")
+ {
+ // horizontal rule height
+ sal_uInt32 const nHeight(convertTwipToMm100(rProperty.second.toInt32()));
+ rShape.setBottom(rShape.getTop() + nHeight);
+ }
+ else if (rProperty.first == "dxWidthHR")
+ {
+ // horizontal rule width
+ sal_uInt32 const nWidth(convertTwipToMm100(rProperty.second.toInt32()));
+ rShape.setRight(rShape.getLeft() + nWidth);
+ }
+ else if (rProperty.first == "alignHR")
+ {
+ // horizontal orientation *for horizontal rule*
+ sal_Int16 nHoriOrient = text::HoriOrientation::NONE;
+ switch (rProperty.second.toInt32())
+ {
+ case 0:
+ nHoriOrient = text::HoriOrientation::LEFT;
+ break;
+ case 1:
+ nHoriOrient = text::HoriOrientation::CENTER;
+ break;
+ case 2:
+ nHoriOrient = text::HoriOrientation::RIGHT;
+ break;
+ }
+ if (xPropertySet.is() && text::HoriOrientation::NONE != nHoriOrient)
+ {
+ xPropertySet->setPropertyValue("HoriOrient", uno::Any(nHoriOrient));
+ }
+ }
+ else if (rProperty.first == "pWrapPolygonVertices")
+ {
+ RTFSprms aPolygonSprms;
+ sal_Int32 nSize = 0; // Size of a token
+ sal_Int32 nCount = 0; // Number of tokens
+ sal_Int32 nCharIndex = 0; // Character index
+ do
+ {
+ std::u16string_view aToken = o3tl::getToken(rProperty.second, 0, ';', nCharIndex);
+ if (!nSize)
+ nSize = o3tl::toInt32(aToken);
+ else if (!nCount)
+ nCount = o3tl::toInt32(aToken);
+ else if (!aToken.empty())
+ {
+ // The coordinates are in an (x,y) form.
+ aToken = aToken.substr(1, aToken.size() - 2);
+ sal_Int32 nI = 0;
+ sal_Int32 nX = o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI));
+ sal_Int32 nY
+ = (nI >= 0) ? o3tl::toInt32(o3tl::getToken(aToken, 0, ',', nI)) : 0;
+ RTFSprms aPathAttributes;
+ aPathAttributes.set(NS_ooxml::LN_CT_Point2D_x, new RTFValue(nX));
+ aPathAttributes.set(NS_ooxml::LN_CT_Point2D_y, new RTFValue(nY));
+ aPolygonSprms.set(NS_ooxml::LN_CT_WrapPath_lineTo,
+ new RTFValue(aPathAttributes), RTFOverwrite::NO_APPEND);
+ }
+ } while (nCharIndex >= 0);
+ rShape.getWrapPolygonSprms() = aPolygonSprms;
+ }
+ else if (rProperty.first == "fRelFlipV")
+ obRelFlipV = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "fFlipH")
+ obFlipH = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "fFlipV")
+ obFlipV = rProperty.second.toInt32() == 1;
+ else if (rProperty.first == "pictureContrast")
+ {
+ // Gain / contrast.
+ nContrast = rProperty.second.toInt32();
+ if (nContrast < 0x10000)
+ {
+ nContrast *= 101; // 100 + 1 to round
+ nContrast /= 0x10000;
+ nContrast -= 100;
+ }
+ }
+ else if (rProperty.first == "pictureBrightness")
+ {
+ // Blacklevel / brightness.
+ nBrightness = rProperty.second.toInt32();
+ if (nBrightness != 0)
+ {
+ nBrightness /= 327;
+ }
+ }
+ else
+ SAL_INFO("writerfilter", "TODO handle shape property '" << rProperty.first << "':'"
+ << rProperty.second << "'");
+ }
+
+ if (xPropertySet.is())
+ {
+ resolveLineColorAndWidth(m_bTextFrame, xPropertySet, aLineColor, aLineWidth);
+ if (rShape.hasZ())
+ {
+ bool bOldStyle = m_aParents.size() > 1;
+ resolveDhgt(xPropertySet, rShape.getZ(), bOldStyle);
+ }
+ if (m_bTextFrame)
+ xPropertySet->setPropertyValue("WritingMode", uno::Any(eWritingMode));
+ else
+ // Only Writer textframes implement text::WritingMode2.
+ xPropertySet->setPropertyValue("TextWritingMode",
+ uno::Any(text::WritingMode(eWritingMode)));
+ }
+
+ if (!m_aParents.empty() && m_aParents.top().is() && !m_bTextFrame)
+ m_aParents.top()->add(xShape);
+
+ if (nContrast == -70 && nBrightness == 70 && xPropertySet.is())
+ {
+ // Map MSO 'washout' to our watermark colormode.
+ xPropertySet->setPropertyValue("GraphicColorMode", uno::Any(drawing::ColorMode_WATERMARK));
+ }
+
+ if (bCustom && xShape.is() && !bPib)
+ {
+ uno::Reference<drawing::XEnhancedCustomShapeDefaulter> xDefaulter(xShape, uno::UNO_QUERY);
+ xDefaulter->createCustomShapeDefaults(OUString::number(nType));
+ }
+
+ // Set shape text
+ if (bCustom && !aShapeText.isEmpty())
+ {
+ uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
+ if (xTextRange.is())
+ xTextRange->setString(aShapeText);
+
+ xPropertySet->setPropertyValue("CharFontName", uno::Any(aFontFamily));
+ xPropertySet->setPropertyValue("CharHeight", uno::Any(nFontSize));
+ }
+
+ // Creating CustomShapeGeometry property
+ if (bCustom && xPropertySet.is())
+ {
+ bool bChanged = false;
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+
+ if (aViewBox.X || aViewBox.Y || aViewBox.Width || aViewBox.Height)
+ {
+ aViewBox.Width -= aViewBox.X;
+ aViewBox.Height -= aViewBox.Y;
+ aCustomShapeGeometry["ViewBox"] <<= aViewBox;
+ bChanged = true;
+ }
+
+ if (!aPath.empty())
+ {
+ aCustomShapeGeometry["Path"] <<= comphelper::containerToSequence(aPath);
+ bChanged = true;
+ }
+
+ if (!aShapeText.isEmpty())
+ {
+ uno::Sequence<beans::PropertyValue> aSequence(comphelper::InitPropertySequence({
+ { "TextPath", uno::Any(true) },
+ }));
+ aCustomShapeGeometry["TextPath"] <<= aSequence;
+ xPropertySet->setPropertyValue("TextAutoGrowHeight", uno::Any(false));
+ xPropertySet->setPropertyValue("TextAutoGrowWidth", uno::Any(false));
+ bChanged = true;
+ }
+
+ if (bChanged)
+ {
+ xPropertySet->setPropertyValue(
+ "CustomShapeGeometry",
+ uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ }
+ }
+
+ if (obRelFlipV.has_value() && xPropertySet.is())
+ {
+ if (nType == ESCHER_ShpInst_Line)
+ {
+ // Line shape inside group shape: get the polygon sequence and transform it.
+ uno::Sequence<uno::Sequence<awt::Point>> aPolyPolySequence;
+ if ((xPropertySet->getPropertyValue("PolyPolygon") >>= aPolyPolySequence)
+ && aPolyPolySequence.hasElements())
+ {
+ uno::Sequence<awt::Point>& rPolygon = aPolyPolySequence.getArray()[0];
+ basegfx::B2DPolygon aPoly;
+ for (const awt::Point& rPoint : rPolygon)
+ {
+ aPoly.append(basegfx::B2DPoint(rPoint.X, rPoint.Y));
+ }
+ basegfx::B2DHomMatrix aTransformation;
+ aTransformation.scale(1.0, *obRelFlipV ? -1.0 : 1.0);
+ aPoly.transform(aTransformation);
+ auto pPolygon = rPolygon.getArray();
+ for (sal_Int32 i = 0; i < rPolygon.getLength(); ++i)
+ {
+ basegfx::B2DPoint aPoint(aPoly.getB2DPoint(i));
+ pPolygon[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()),
+ static_cast<sal_Int32>(aPoint.getY()));
+ }
+ xPropertySet->setPropertyValue("PolyPolygon", uno::Any(aPolyPolySequence));
+ }
+ }
+ }
+
+ // Set position and size
+ if (xShape.is())
+ {
+ sal_Int32 nLeft = rShape.getLeft();
+ sal_Int32 nTop = rShape.getTop();
+
+ bool bInShapeGroup = oGroupLeft && oGroupTop && oGroupRight && oGroupBottom && oRelLeft
+ && oRelTop && oRelRight && oRelBottom;
+ awt::Size aSize;
+ if (bInShapeGroup)
+ {
+ // See lclGetAbsPoint() in the VML import: rShape is the group shape, oGroup is its coordinate system, oRel is the relative child shape.
+ sal_Int32 nShapeWidth = rShape.getRight() - rShape.getLeft();
+ sal_Int32 nShapeHeight = rShape.getBottom() - rShape.getTop();
+ sal_Int32 nCoordSysWidth = *oGroupRight - *oGroupLeft;
+ sal_Int32 nCoordSysHeight = *oGroupBottom - *oGroupTop;
+ double fWidthRatio = static_cast<double>(nShapeWidth) / nCoordSysWidth;
+ double fHeightRatio = static_cast<double>(nShapeHeight) / nCoordSysHeight;
+ nLeft = static_cast<sal_Int32>(rShape.getLeft()
+ + fWidthRatio * (*oRelLeft - *oGroupLeft));
+ nTop = static_cast<sal_Int32>(rShape.getTop() + fHeightRatio * (*oRelTop - *oGroupTop));
+
+ // See lclGetAbsRect() in the VML import.
+ aSize.Width = std::lround(fWidthRatio * (*oRelRight - *oRelLeft));
+ aSize.Height = std::lround(fHeightRatio * (*oRelBottom - *oRelTop));
+ }
+
+ if (m_bTextFrame)
+ {
+ xPropertySet->setPropertyValue("HoriOrientPosition", uno::Any(nLeft));
+ xPropertySet->setPropertyValue("VertOrientPosition", uno::Any(nTop));
+ }
+ else
+ xShape->setPosition(awt::Point(nLeft, nTop));
+
+ if (bInShapeGroup)
+ xShape->setSize(aSize);
+ else
+ xShape->setSize(awt::Size(rShape.getRight() - rShape.getLeft(),
+ rShape.getBottom() - rShape.getTop()));
+
+ if (obFlipH || obFlipV)
+ {
+ if (bCustom)
+ {
+ // This has to be set after position and size is set, otherwise flip will affect the position.
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(
+ xPropertySet->getPropertyValue("CustomShapeGeometry"));
+ if (obFlipH)
+ aCustomShapeGeometry["MirroredX"] <<= true;
+ if (obFlipV)
+ aCustomShapeGeometry["MirroredY"] <<= true;
+ xPropertySet->setPropertyValue(
+ "CustomShapeGeometry",
+ uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ }
+ else if (SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape))
+ {
+ Point aRef1 = pObject->GetSnapRect().Center();
+ Point aRef2(aRef1);
+ if (obFlipH)
+ {
+ // Horizontal mirror means a vertical reference line.
+ aRef2.AdjustY(1);
+ }
+ if (obFlipV)
+ {
+ // Vertical mirror means a horizontal reference line.
+ aRef2.AdjustX(1);
+ }
+ pObject->Mirror(aRef1, aRef2);
+ }
+ }
+
+ if (rShape.getHoriOrientRelation() != 0)
+ xPropertySet->setPropertyValue("HoriOrientRelation",
+ uno::Any(rShape.getHoriOrientRelation()));
+ if (rShape.getVertOrientRelation() != 0)
+ xPropertySet->setPropertyValue("VertOrientRelation",
+ uno::Any(rShape.getVertOrientRelation()));
+ if (rShape.getWrap() != text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE)
+ xPropertySet->setPropertyValue("Surround", uno::Any(rShape.getWrap()));
+ oox::ModelObjectHelper aModelObjectHelper(m_rImport.getModelFactory());
+ if (aFillModel.moType.has_value())
+ {
+ oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
+ aFillModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
+ // Sets the FillStyle and FillGradient UNO properties.
+ oox::PropertySet(xShape).setProperties(aPropMap);
+ }
+
+ if (aShadowModel.mbHasShadow)
+ {
+ oox::drawingml::ShapePropertyMap aPropMap(aModelObjectHelper);
+ aShadowModel.pushToPropMap(aPropMap, m_rImport.getGraphicHelper());
+ // Sets the ShadowFormat UNO property.
+ oox::PropertySet(xShape).setProperties(aPropMap);
+ }
+ xPropertySet->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ xPropertySet->setPropertyValue("Opaque", uno::Any(bOpaque));
+ if (oRelativeWidth)
+ {
+ xPropertySet->setPropertyValue("RelativeWidth", uno::Any(*oRelativeWidth));
+ xPropertySet->setPropertyValue("RelativeWidthRelation",
+ uno::Any(nRelativeWidthRelation));
+ }
+ if (oRelativeHeight)
+ {
+ xPropertySet->setPropertyValue("RelativeHeight", uno::Any(*oRelativeHeight));
+ xPropertySet->setPropertyValue("RelativeHeightRelation",
+ uno::Any(nRelativeHeightRelation));
+ }
+ }
+
+ if (bPib)
+ {
+ m_rImport.resolvePict(false, xShape);
+ }
+
+ if (nType == ESCHER_ShpInst_PictureFrame) // picture frame
+ {
+ assert(!m_bTextFrame);
+ if (!bPib) // ??? not sure if the early return should be removed on else?
+ {
+ m_xShape = xShape; // store it for later resolvePict call
+ }
+
+ // Handle horizontal flip.
+ if (obFlipH && xPropertySet.is())
+ xPropertySet->setPropertyValue("IsMirrored", uno::Any(true));
+ return;
+ }
+
+ // Send it to dmapper
+ if (xShape.is())
+ {
+ m_rImport.Mapper().startShape(xShape);
+ if (bClose)
+ {
+ m_rImport.Mapper().endShape();
+ }
+ }
+
+ if (m_rImport.isInBackground())
+ {
+ RTFSprms aSprms;
+ aSprms.set(NS_ooxml::LN_background_background, new RTFValue()); // action="end"
+ m_rImport.Mapper().props(new RTFReferenceProperties(RTFSprms(), std::move(aSprms)));
+ }
+
+ // If the shape has an inner shape, the inner object's properties should not be influenced by
+ // the outer one.
+ rShape.getProperties().clear();
+
+ m_xShape = xShape;
+}
+
+void RTFSdrImport::close() { m_rImport.Mapper().endShape(); }
+
+void RTFSdrImport::append(std::u16string_view aKey, std::u16string_view aValue)
+{
+ applyProperty(m_xShape, aKey, aValue);
+}
+
+void RTFSdrImport::appendGroupProperty(std::u16string_view aKey, std::u16string_view aValue)
+{
+ if (m_aParents.empty())
+ return;
+ uno::Reference<drawing::XShape> xShape(m_aParents.top(), uno::UNO_QUERY);
+ if (xShape.is())
+ applyProperty(xShape, aKey, aValue);
+}
+
+} // namespace writerfilter
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfsdrimport.hxx b/sw/source/writerfilter/rtftok/rtfsdrimport.hxx
new file mode 100644
index 000000000000..b06803bd0f64
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfsdrimport.hxx
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <stack>
+#include <vector>
+
+#include <dmapper/GraphicZOrderHelper.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star
+{
+namespace beans
+{
+class XPropertySet;
+struct PropertyValue;
+}
+namespace drawing
+{
+class XShape;
+class XShapes;
+}
+namespace lang
+{
+class XComponent;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFDocumentImpl;
+class RTFShape;
+
+/// Handles the import of drawings using RTF markup.
+class RTFSdrImport final : public virtual SvRefBase
+{
+public:
+ RTFSdrImport(RTFDocumentImpl& rDocument,
+ css::uno::Reference<css::lang::XComponent> const& xDstDoc);
+ ~RTFSdrImport() override;
+
+ enum ShapeOrPict
+ {
+ SHAPE,
+ PICT
+ };
+ void resolve(RTFShape& rShape, bool bClose, ShapeOrPict shapeOrPict);
+ void close();
+ void append(std::u16string_view aKey, std::u16string_view aValue);
+ /// Append property on the current parent.
+ void appendGroupProperty(std::u16string_view aKey, std::u16string_view aValue);
+ void resolveDhgt(css::uno::Reference<css::beans::XPropertySet> const& xPropertySet,
+ sal_Int32 nZOrder, bool bOldStyle);
+ /// Set line color and line width on the shape, using the relevant API depending on if the shape is a text frame or not.
+ static void
+ resolveLineColorAndWidth(bool bTextFrame,
+ const css::uno::Reference<css::beans::XPropertySet>& xPropertySet,
+ css::uno::Any const& rLineColor, css::uno::Any const& rLineWidth);
+ static void resolveFLine(css::uno::Reference<css::beans::XPropertySet> const& xPropertySet,
+ sal_Int32 nFLine);
+ /**
+ * These are the default in Word, but not in Writer.
+ *
+ * @param bNew if the frame is new-style or old-style.
+ */
+ static std::vector<css::beans::PropertyValue> getTextFrameDefaults(bool bNew);
+ /// Push a new group shape to the parent stack.
+ void pushParent(css::uno::Reference<css::drawing::XShapes> const& xParent);
+ /// Pop the current group shape from the parent stack.
+ void popParent();
+ css::uno::Reference<css::drawing::XShape> const& getCurrentShape() const { return m_xShape; }
+ bool isFakePict() const { return m_bFakePict; }
+ bool isTextGraphicObject() const { return m_bTextGraphicObject; }
+
+private:
+ void createShape(const OUString& rService, css::uno::Reference<css::drawing::XShape>& xShape,
+ css::uno::Reference<css::beans::XPropertySet>& xPropertySet);
+ void applyProperty(css::uno::Reference<css::drawing::XShape> const& xShape,
+ std::u16string_view aKey, std::u16string_view aValue) const;
+ int initShape(css::uno::Reference<css::drawing::XShape>& o_xShape,
+ css::uno::Reference<css::beans::XPropertySet>& o_xPropSet, bool& o_rIsCustomShape,
+ RTFShape const& rShape, bool bClose, ShapeOrPict shapeOrPict);
+
+ RTFDocumentImpl& m_rImport;
+ std::stack<css::uno::Reference<css::drawing::XShapes>> m_aParents;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ /// If m_xShape is imported as a Writer text frame (instead of a drawinglayer rectangle).
+ bool m_bTextFrame;
+ /// If m_xShape is imported as a Writer text graphic object (instead of a drawinglayer shape).
+ bool m_bTextGraphicObject;
+ /// if inside \pict, but actually it's a shape (not a picture)
+ bool m_bFakePict;
+ std::stack<writerfilter::dmapper::GraphicZOrderHelper> m_aGraphicZOrderHelpers;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfskipdestination.cxx b/sw/source/writerfilter/rtftok/rtfskipdestination.cxx
new file mode 100644
index 000000000000..ad2122318333
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfskipdestination.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfskipdestination.hxx"
+#include <sal/log.hxx>
+#include "rtflistener.hxx"
+
+namespace writerfilter::rtftok
+{
+RTFSkipDestination::RTFSkipDestination(RTFListener& rImport)
+ : m_rImport(rImport)
+ , m_bParsed(true)
+ , m_bReset(true)
+{
+}
+
+RTFSkipDestination::~RTFSkipDestination()
+{
+ if (m_rImport.getSkipUnknown() && m_bReset)
+ {
+ if (!m_bParsed)
+ {
+ SAL_INFO("writerfilter", __func__ << ": skipping destination");
+ m_rImport.setDestination(Destination::SKIP);
+ }
+ m_rImport.setSkipUnknown(false);
+ }
+}
+
+void RTFSkipDestination::setParsed(bool bParsed) { m_bParsed = bParsed; }
+
+void RTFSkipDestination::setReset(bool bReset) { m_bReset = bReset; }
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfskipdestination.hxx b/sw/source/writerfilter/rtftok/rtfskipdestination.hxx
new file mode 100644
index 000000000000..4a894373f1e4
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfskipdestination.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+namespace writerfilter::rtftok
+{
+class RTFListener;
+
+/// Skips a destination after a not parsed control word if it was prefixed with \*
+class RTFSkipDestination final
+{
+public:
+ explicit RTFSkipDestination(RTFListener& rImport);
+ ~RTFSkipDestination();
+ void setParsed(bool bParsed);
+ void setReset(bool bReset);
+
+private:
+ RTFListener& m_rImport;
+ bool m_bParsed;
+ /// If false, the destructor is a noop, required by the \* symbol itself.
+ bool m_bReset;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfsprm.cxx b/sw/source/writerfilter/rtftok/rtfsprm.cxx
new file mode 100644
index 000000000000..148d39c2e48b
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfsprm.cxx
@@ -0,0 +1,487 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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("', '" + m_pValue->toString() + "')");
+
+ return std::string(aBuf);
+}
+#endif
+
+namespace
+{
+class RTFSprms_compare
+{
+ Id m_keyword;
+
+public:
+ RTFSprms_compare(Id keyword)
+ : m_keyword{ keyword }
+ {
+ }
+ bool operator()(const std::pair<Id, RTFValue::Pointer_t>& raPair) const
+ {
+ return raPair.first == m_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:
+ {
+ std::erase_if(*m_pSprms, RTFSprms_compare{ nKeyword });
+ m_pSprms->emplace(m_pSprms->cbegin(), nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::YES:
+ {
+ auto it
+ = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword });
+ if (it != m_pSprms->end())
+ it->second = pValue;
+ else
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::NO_IGNORE:
+ {
+ if (std::none_of(m_pSprms->cbegin(), m_pSprms->cend(), RTFSprms_compare{ nKeyword }))
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ case RTFOverwrite::NO_APPEND:
+ {
+ m_pSprms->emplace_back(nKeyword, pValue);
+ break;
+ }
+ }
+}
+
+bool RTFSprms::erase(Id nKeyword)
+{
+ ensureCopyBeforeWrite();
+
+ auto i = std::find_if(m_pSprms->begin(), m_pSprms->end(), RTFSprms_compare{ nKeyword });
+ if (i != m_pSprms->end())
+ {
+ m_pSprms->erase(i);
+ return true;
+ }
+ return false;
+}
+
+void RTFSprms::eraseLast(Id nKeyword)
+{
+ ensureCopyBeforeWrite();
+
+ auto i = std::find_if(m_pSprms->rbegin(), m_pSprms->rend(), RTFSprms_compare{ nKeyword });
+ if (i != m_pSprms->rend())
+ m_pSprms->erase(std::next(i).base());
+}
+
+static RTFValue::Pointer_t getDefaultSPRM(Id const id, Id nStyleType)
+{
+ if (nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ switch (id)
+ {
+ case NS_ooxml::LN_EG_RPrBase_szCs:
+ case NS_ooxml::LN_EG_RPrBase_sz:
+ return new RTFValue(24);
+ case NS_ooxml::LN_CT_Color_val:
+ return new RTFValue(0);
+ case NS_ooxml::LN_EG_RPrBase_b:
+ case NS_ooxml::LN_EG_RPrBase_i:
+ return new RTFValue(0);
+ case NS_ooxml::LN_CT_Underline_val:
+ return new RTFValue(NS_ooxml::LN_Value_ST_Underline_none);
+ case NS_ooxml::LN_CT_Fonts_ascii:
+ case NS_ooxml::LN_CT_Fonts_eastAsia:
+ case NS_ooxml::LN_CT_Fonts_cs:
+ return new RTFValue("Times New Roman");
+ default:
+ break;
+ }
+ }
+
+ if (!nStyleType || nStyleType == NS_ooxml::LN_Value_ST_StyleType_paragraph)
+ {
+ switch (id)
+ {
+ case NS_ooxml::LN_CT_Spacing_before:
+ case NS_ooxml::LN_CT_Spacing_after:
+ case NS_ooxml::LN_CT_Ind_left:
+ case NS_ooxml::LN_CT_Ind_right:
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ return new RTFValue(0);
+ case NS_ooxml::LN_CT_Spacing_lineRule:
+ return new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto);
+ case NS_ooxml::LN_CT_Spacing_line:
+ // presumably this means 100%, cf. static const int nSingleLineSpacing = 240;
+ return new RTFValue(240);
+ case NS_ooxml::LN_CT_NumPr_numId:
+ return new RTFValue(0);
+ case NS_ooxml::LN_CT_PrBase_pBdr:
+ { // tdf#150382 default all paragraph borders to none
+ RTFSprms attributes;
+ RTFSprms sprms;
+ for (int i = 0; i < 4; ++i)
+ {
+ auto const nBorder = getParagraphBorder(i);
+ RTFSprms aAttributes;
+ RTFSprms aSprms;
+ aAttributes.set(NS_ooxml::LN_CT_Border_val,
+ new RTFValue(NS_ooxml::LN_Value_ST_Border_none));
+ sprms.set(nBorder, new RTFValue(aAttributes, aSprms));
+ }
+ return new RTFValue(attributes, sprms);
+ }
+
+ default:
+ break;
+ }
+ }
+
+ return RTFValue::Pointer_t();
+}
+
+/// Is it problematic to deduplicate this SPRM?
+static bool isSPRMDeduplicateDenylist(Id nId, RTFSprms* pDirect)
+{
+ switch (nId)
+ {
+ // See the NS_ooxml::LN_CT_PPrBase_tabs handler in DomainMapper,
+ // deduplication is explicitly not wanted for these tokens.
+ case NS_ooxml::LN_CT_TabStop_val:
+ case NS_ooxml::LN_CT_TabStop_leader:
+ case NS_ooxml::LN_CT_TabStop_pos:
+ // \htmautsp arrives after the style table, so only the non-style value is
+ // correct, keep these.
+ case NS_ooxml::LN_CT_Spacing_beforeAutospacing:
+ case NS_ooxml::LN_CT_Spacing_afterAutospacing:
+ // \chbrdr requires *all* of the border settings to be present,
+ // otherwise a default (NONE) border is created from the removed
+ // attributes which then overrides the style-defined border.
+ // See BorderHandler.cxx and NS_ooxml::LN_EG_RPrBase_bdr in DomainMapper.
+ // This also is needed for NS_ooxml::LN_CT_PBdr_top etc.
+ case NS_ooxml::LN_CT_Border_sz:
+ case NS_ooxml::LN_CT_Border_val:
+ case NS_ooxml::LN_CT_Border_color:
+ case NS_ooxml::LN_CT_Border_space:
+ case NS_ooxml::LN_CT_Border_shadow:
+ case NS_ooxml::LN_CT_Border_frame:
+ case NS_ooxml::LN_CT_Border_themeTint:
+ case NS_ooxml::LN_CT_Border_themeColor:
+ return true;
+ // Removing \fi and \li if the style has the same value would mean taking these values from
+ // \ls, while deduplication would be done to take the values from the style.
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ case NS_ooxml::LN_CT_Ind_left:
+ return pDirect && pDirect->find(NS_ooxml::LN_CT_PPrBase_numPr);
+
+ default:
+ return false;
+ }
+}
+
+/// Should this SPRM be removed if all its children are removed?
+static bool isSPRMChildrenExpected(Id nId)
+{
+ switch (nId)
+ {
+ case NS_ooxml::LN_CT_PBdr_top:
+ case NS_ooxml::LN_CT_PBdr_left:
+ case NS_ooxml::LN_CT_PBdr_bottom:
+ case NS_ooxml::LN_CT_PBdr_right:
+ // Expected children are NS_ooxml::LN_CT_Border_*.
+ case NS_ooxml::LN_CT_PrBase_shd:
+ // Expected children are NS_ooxml::LN_CT_Shd_*.
+ case NS_ooxml::LN_CT_PPrBase_ind:
+ // Expected children are NS_ooxml::LN_CT_Ind_*.
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/// Does the clone / deduplication of a single sprm.
+static void cloneAndDeduplicateSprm(std::pair<Id, RTFValue::Pointer_t> const& rSprm, RTFSprms& ret,
+ Id nStyleType, RTFSprms* pDirect = nullptr)
+{
+ RTFValue::Pointer_t const pValue(ret.find(rSprm.first));
+ if (pValue)
+ {
+ if (rSprm.second->equals(*pValue))
+ {
+ //this removes properties that are equal at the style and at the sprm
+ //don't do that for paragraph styles
+ if (nStyleType == NS_ooxml::LN_Value_ST_StyleType_character)
+ {
+ if (!isSPRMDeduplicateDenylist(rSprm.first, pDirect))
+ {
+ ret.erase(rSprm.first); // duplicate to style
+ }
+ }
+ }
+ else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty())
+ {
+ RTFSprms const sprms(pValue->getSprms().cloneAndDeduplicate(
+ rSprm.second->getSprms(), nStyleType, /*bImplicitPPr =*/false, pDirect));
+ RTFSprms const attributes(pValue->getAttributes().cloneAndDeduplicate(
+ rSprm.second->getAttributes(), nStyleType, /*bImplicitPPr =*/false, pDirect));
+ // Don't copy the sprm in case we expect it to have children but it doesn't have some.
+ if (!isSPRMChildrenExpected(rSprm.first) || !sprms.empty() || !attributes.empty())
+ ret.set(rSprm.first,
+ RTFValue::Pointer_t(pValue->CloneWithSprms(attributes, sprms)));
+ }
+ }
+ else
+ {
+ // not found - try to override style with default
+ RTFValue::Pointer_t const pDefault(getDefaultSPRM(rSprm.first, nStyleType));
+ if (pDefault)
+ {
+ ret.set(rSprm.first, pDefault);
+ }
+ else if (!rSprm.second->getSprms().empty() || !rSprm.second->getAttributes().empty())
+ {
+ RTFSprms const sprms(
+ RTFSprms().cloneAndDeduplicate(rSprm.second->getSprms(), nStyleType));
+ RTFSprms const attributes(
+ RTFSprms().cloneAndDeduplicate(rSprm.second->getAttributes(), nStyleType));
+ if (!sprms.empty() || !attributes.empty())
+ {
+ ret.set(rSprm.first, new RTFValue(attributes, sprms));
+ }
+ }
+ }
+}
+
+/// Extracts the list level matching nLevel from pAbstract.
+static RTFValue::Pointer_t getListLevel(const RTFValue::Pointer_t& pAbstract, int nLevel)
+{
+ for (const auto& rPair : pAbstract->getSprms())
+ {
+ if (rPair.first != NS_ooxml::LN_CT_AbstractNum_lvl)
+ continue;
+
+ RTFValue::Pointer_t pLevel = rPair.second->getAttributes().find(NS_ooxml::LN_CT_Lvl_ilvl);
+ if (!pLevel)
+ continue;
+
+ if (pLevel->getInt() != nLevel)
+ continue;
+
+ return rPair.second;
+ }
+
+ return RTFValue::Pointer_t();
+}
+
+void RTFSprms::deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents)
+{
+ int nLevel = 0;
+ RTFValue::Pointer_t pLevelId
+ = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl);
+ if (pLevelId)
+ nLevel = pLevelId->getInt();
+
+ auto it = rInvalidListLevelFirstIndents.find(nLevel);
+ if (it == rInvalidListLevelFirstIndents.end())
+ return;
+
+ int nListValue = it->second;
+
+ RTFValue::Pointer_t pParagraphValue
+ = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine);
+ if (!pParagraphValue)
+ return;
+
+ int nParagraphValue = pParagraphValue->getInt();
+
+ if (nParagraphValue == nListValue)
+ eraseNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, NS_ooxml::LN_CT_Ind_firstLine);
+}
+
+void RTFSprms::duplicateList(const RTFValue::Pointer_t& pAbstract)
+{
+ int nLevel = 0;
+ RTFValue::Pointer_t pLevelId
+ = getNestedSprm(*this, NS_ooxml::LN_CT_PPrBase_numPr, NS_ooxml::LN_CT_NumPr_ilvl);
+ if (pLevelId)
+ nLevel = pLevelId->getInt();
+
+ RTFValue::Pointer_t pLevel = getListLevel(pAbstract, nLevel);
+ if (!pLevel)
+ return;
+
+ RTFValue::Pointer_t pLevelInd = pLevel->getSprms().find(NS_ooxml::LN_CT_PPrBase_ind);
+ if (!pLevelInd)
+ return;
+
+ for (const auto& rListLevelPair : pLevelInd->getAttributes())
+ {
+ switch (rListLevelPair.first)
+ {
+ case NS_ooxml::LN_CT_Ind_left:
+ case NS_ooxml::LN_CT_Ind_right:
+ case NS_ooxml::LN_CT_Ind_firstLine:
+ RTFValue::Pointer_t pParagraphValue
+ = getNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first);
+ if (!pParagraphValue)
+ putNestedAttribute(*this, NS_ooxml::LN_CT_PPrBase_ind, rListLevelPair.first,
+ getDefaultSPRM(rListLevelPair.first, 0));
+
+ break;
+ }
+ }
+}
+
+RTFSprms RTFSprms::cloneAndDeduplicate(RTFSprms& rReference, Id const nStyleType,
+ bool const bImplicitPPr, RTFSprms* pDirect) const
+{
+ RTFSprms ret(*this);
+ ret.ensureCopyBeforeWrite();
+
+ // Note: apparently some attributes are set with OVERWRITE_NO_APPEND;
+ // it is probably a bad idea to mess with those in any way here?
+ for (auto& rSprm : rReference)
+ {
+ // Paragraph formatting sprms are directly contained in case of
+ // paragraphs, but they are below NS_ooxml::LN_CT_Style_pPr in case of
+ // styles. So handle those children directly, to avoid unexpected
+ // addition of direct formatting sprms at the paragraph level.
+ if (bImplicitPPr && rSprm.first == NS_ooxml::LN_CT_Style_pPr)
+ {
+ for (const auto& i : rSprm.second->getSprms())
+ cloneAndDeduplicateSprm(i, ret, nStyleType, pDirect);
+ }
+ else
+ cloneAndDeduplicateSprm(rSprm, ret, nStyleType, pDirect);
+ }
+ return ret;
+}
+
+bool RTFSprms::equals(const RTFSprms& rOther) const
+{
+ auto it1 = m_pSprms->cbegin();
+ auto it1End = m_pSprms->cend();
+ auto it2 = rOther.m_pSprms->cbegin();
+ auto it2End = rOther.m_pSprms->cend();
+ while (it1 != it1End && it2 != it2End)
+ {
+ if (it1->first != it2->first)
+ return false;
+ if (!it1->second->equals(*it2->second))
+ return false;
+ ++it1;
+ ++it2;
+ }
+ return it1 == it1End && it2 == it2End;
+}
+
+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/sw/source/writerfilter/rtftok/rtfsprm.hxx b/sw/source/writerfilter/rtftok/rtfsprm.hxx
new file mode 100644
index 000000000000..132a2bbcbeb2
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfsprm.hxx
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <string>
+#include <utility>
+#include <vector>
+#include <map>
+
+#include <tools/ref.hxx>
+#include "rtfvalue.hxx"
+
+namespace writerfilter::rtftok
+{
+using RTFSprmsImplBase = std::vector<std::pair<Id, RTFValue::Pointer_t>>;
+
+/// The payload of RTFSprms which is only copied on write.
+class RTFSprmsImpl : public RTFSprmsImplBase, public virtual SvRefBase
+{
+};
+
+enum class RTFOverwrite
+{
+ YES, ///< Yes, if an existing key is found, overwrite it.
+ NO_APPEND, ///< No, always append the value to the end of the list.
+ NO_IGNORE, ///< No, if the key is already in the list, then ignore, otherwise append.
+ YES_PREPEND ///< Yes, always prepend the value to the start of the list and remove existing entries.
+};
+
+/// A list of RTFSprm with a copy constructor that performs a deep copy.
+class RTFSprms : public virtual SvRefBase
+{
+public:
+ using Pointer_t = tools::SvRef<RTFSprms>;
+ using Entry_t = std::pair<Id, RTFValue::Pointer_t>;
+ using Iterator_t = std::vector<Entry_t>::iterator;
+ using ReverseIterator_t = std::vector<Entry_t>::reverse_iterator;
+ RTFSprms();
+ ~RTFSprms() override;
+
+ RTFSprms(RTFSprms const&) = default;
+ RTFSprms(RTFSprms&&) = default;
+ RTFSprms& operator=(RTFSprms const&) = default;
+ RTFSprms& operator=(RTFSprms&&) = default;
+
+ RTFValue::Pointer_t find(Id nKeyword, bool bFirst = true, bool bForWrite = false);
+ /// Does the same as ->push_back(), except that it can overwrite or ignore existing entries.
+ void set(Id nKeyword, const RTFValue::Pointer_t& pValue,
+ RTFOverwrite eOverwrite = RTFOverwrite::YES);
+ bool erase(Id nKeyword);
+ void eraseLast(Id nKeyword);
+ /// Removes elements which are already in the reference set.
+ /// Also insert default values to override attributes of style
+ /// (yes, really; that's what Word does).
+ /// @param bImplicitPPr implicit dereference of top-level pPr SPRM
+ /// @param pDirect pointer to the root of the direct formatting SPRM tree, if any
+ RTFSprms cloneAndDeduplicate(RTFSprms& rReference, Id nStyleType, bool bImplicitPPr = false,
+ RTFSprms* pDirect = nullptr) const;
+ /// Inserts default values to override attributes of pAbstract.
+ void duplicateList(const RTFValue::Pointer_t& pAbstract);
+ /// Removes duplicated values based on in-list properties.
+ void deduplicateList(const std::map<int, int>& rInvalidListLevelFirstIndents);
+ std::size_t size() const { return m_pSprms->size(); }
+ bool empty() const { return m_pSprms->empty(); }
+ Entry_t& back() { return m_pSprms->back(); }
+ Iterator_t begin() { return m_pSprms->begin(); }
+ Iterator_t end() { return m_pSprms->end(); }
+ void clear();
+ bool equals(const RTFSprms& rOther) const;
+
+private:
+ void ensureCopyBeforeWrite();
+ tools::SvRef<RTFSprmsImpl> m_pSprms;
+};
+
+/// RTF keyword with a parameter
+class RTFSprm : public Sprm
+{
+public:
+ RTFSprm(Id nKeyword, RTFValue::Pointer_t& pValue);
+ sal_uInt32 getId() const override;
+ Value::Pointer_t getValue() override;
+ writerfilter::Reference<Properties>::Pointer_t getProps() override;
+#ifdef DBG_UTIL
+ std::string getName() const override;
+ std::string toString() const override;
+#endif
+private:
+ Id m_nKeyword;
+ RTFValue::Pointer_t& m_pValue;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtftokenizer.cxx b/sw/source/writerfilter/rtftok/rtftokenizer.cxx
new file mode 100644
index 000000000000..420c6d36f0c3
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtftokenizer.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/.
+ */
+
+#include "rtftokenizer.hxx"
+#include <o3tl/string_view.hxx>
+#include <tools/stream.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <rtl/strbuf.hxx>
+#include <rtl/character.hxx>
+#include <sal/log.hxx>
+#include "rtfskipdestination.hxx"
+#include <com/sun/star/io/BufferSizeExceededException.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <filter/msfilter/rtfutil.hxx>
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+std::unordered_map<OString, RTFSymbol> RTFTokenizer::s_aRTFControlWords;
+bool RTFTokenizer::s_bControlWordsInitialised;
+std::vector<RTFMathSymbol> RTFTokenizer::s_aRTFMathControlWords;
+bool RTFTokenizer::s_bMathControlWordsSorted;
+
+RTFTokenizer::RTFTokenizer(RTFListener& rImport, SvStream* pInStream,
+ uno::Reference<task::XStatusIndicator> const& xStatusIndicator)
+ : m_rImport(rImport)
+ , m_pInStream(pInStream)
+ , m_xStatusIndicator(xStatusIndicator)
+ , m_nGroup(0)
+ , m_nLineNumber(0)
+ , m_nLineStartPos(0)
+ , m_nGroupStart(0)
+{
+ if (!RTFTokenizer::s_bControlWordsInitialised)
+ {
+ RTFTokenizer::s_bControlWordsInitialised = true;
+ for (int i = 0; i < nRTFControlWords; ++i)
+ s_aRTFControlWords.emplace(OString(aRTFControlWords[i].GetKeyword()),
+ aRTFControlWords[i]);
+ }
+ if (!RTFTokenizer::s_bMathControlWordsSorted)
+ {
+ RTFTokenizer::s_bMathControlWordsSorted = true;
+ s_aRTFMathControlWords = std::vector<RTFMathSymbol>(
+ aRTFMathControlWords, aRTFMathControlWords + nRTFMathControlWords);
+ std::sort(s_aRTFMathControlWords.begin(), s_aRTFMathControlWords.end());
+ }
+}
+
+RTFTokenizer::~RTFTokenizer() = default;
+
+RTFError RTFTokenizer::resolveParse()
+{
+ SAL_INFO("writerfilter.rtf", __func__);
+ char ch;
+ RTFError ret;
+ // for hex chars
+ int b = 0;
+ int count = 2;
+ std::size_t nPercentSize = 0;
+ sal_uInt64 nLastPos = 0;
+
+ if (m_xStatusIndicator.is())
+ {
+ OUString sDocLoad(SvxResId(RID_SVXSTR_DOC_LOAD));
+
+ sal_uInt64 const nCurrentPos = Strm().Tell();
+ sal_uInt64 const nEndPos = nCurrentPos + Strm().remainingSize();
+ m_xStatusIndicator->start(sDocLoad, nEndPos);
+ nPercentSize = nEndPos / 100;
+
+ nLastPos = nCurrentPos;
+ m_xStatusIndicator->setValue(nLastPos);
+ }
+
+ while (Strm().ReadChar(ch), !Strm().eof())
+ {
+ //SAL_INFO("writerfilter", __func__ << ": parsing character '" << ch << "'");
+
+ sal_uInt64 const nCurrentPos = Strm().Tell();
+ if (m_xStatusIndicator.is() && nCurrentPos > (nLastPos + nPercentSize))
+ {
+ nLastPos = nCurrentPos;
+ m_xStatusIndicator->setValue(nLastPos);
+ }
+
+ if (m_nGroup < 0)
+ return RTFError::GROUP_UNDER;
+ if (m_nGroup > 0 && m_rImport.getInternalState() == RTFInternalState::BIN)
+ {
+ ret = m_rImport.resolveChars(ch);
+ if (ret != RTFError::OK)
+ return ret;
+ }
+ else
+ {
+ switch (ch)
+ {
+ case '{':
+ m_nGroupStart = Strm().Tell() - 1;
+ ret = m_rImport.pushState();
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case '}':
+ ret = m_rImport.popState();
+ if (ret != RTFError::OK)
+ return ret;
+ if (m_nGroup == 0)
+ {
+ if (m_rImport.isSubstream())
+ m_rImport.finishSubstream();
+ return RTFError::OK;
+ }
+ break;
+ case '\\':
+ ret = resolveKeyword();
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case 0x0d:
+ break; // ignore this
+ case 0x0a:
+ m_nLineNumber++;
+ m_nLineStartPos = nCurrentPos;
+ break;
+ default:
+ if (m_nGroup == 0)
+ return RTFError::CHAR_OVER;
+ if (m_rImport.getInternalState() == RTFInternalState::NORMAL)
+ {
+ ret = m_rImport.resolveChars(ch);
+ if (ret != RTFError::OK)
+ return ret;
+ }
+ else
+ {
+ SAL_INFO("writerfilter.rtf", __func__ << ": hex internal state");
+ // Assume that \'<number><junk> means \'0<number>.
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch))
+ || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'))
+ {
+ b = b << 4;
+ sal_Int8 parsed = msfilter::rtfutil::AsHex(ch);
+ if (parsed == -1)
+ return RTFError::HEX_INVALID;
+ b += parsed;
+ }
+ count--;
+ if (!count)
+ {
+ ret = m_rImport.resolveChars(b);
+ if (ret != RTFError::OK)
+ return ret;
+ count = 2;
+ b = 0;
+ m_rImport.setInternalState(RTFInternalState::NORMAL);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (m_nGroup < 0)
+ return RTFError::GROUP_UNDER;
+ if (m_nGroup > 0)
+ return RTFError::GROUP_OVER;
+ return RTFError::OK;
+}
+
+void RTFTokenizer::pushGroup() { m_nGroup++; }
+
+void RTFTokenizer::popGroup() { m_nGroup--; }
+
+RTFError RTFTokenizer::resolveKeyword()
+{
+ char ch;
+
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ return RTFError::UNEXPECTED_EOF;
+
+ if (!rtl::isAsciiAlpha(static_cast<unsigned char>(ch)))
+ {
+ // control symbols aren't followed by a space, so we can return here
+ // without doing any SeekRel()
+ return dispatchKeyword(OString(ch), false, 0);
+ }
+ OStringBuffer aBuf(32);
+ while (rtl::isAsciiAlpha(static_cast<unsigned char>(ch)))
+ {
+ aBuf.append(ch);
+ if (aBuf.getLength() > 32)
+ // See RTF spec v1.9.1, page 7
+ // A control word's name cannot be longer than 32 letters.
+ throw io::BufferSizeExceededException();
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ {
+ ch = ' ';
+ break;
+ }
+ }
+
+ bool bNeg = false;
+ if (ch == '-')
+ {
+ // in case we'll have a parameter, that will be negative
+ bNeg = true;
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ return RTFError::UNEXPECTED_EOF;
+ }
+ bool bParam = false;
+ int nParam = 0;
+ if (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ {
+ OStringBuffer aParameter;
+
+ // we have a parameter
+ bParam = true;
+ while (rtl::isAsciiDigit(static_cast<unsigned char>(ch)))
+ {
+ aParameter.append(ch);
+ Strm().ReadChar(ch);
+ if (Strm().eof())
+ {
+ ch = ' ';
+ break;
+ }
+ }
+ nParam = o3tl::toInt32(aParameter);
+ if (bNeg)
+ nParam = -nParam;
+ }
+ if (ch != ' ')
+ Strm().SeekRel(-1);
+ OString aKeyword = aBuf.makeStringAndClear();
+ return dispatchKeyword(aKeyword, bParam, nParam);
+}
+
+bool RTFTokenizer::lookupMathKeyword(RTFMathSymbol& rSymbol)
+{
+ auto low
+ = std::lower_bound(s_aRTFMathControlWords.begin(), s_aRTFMathControlWords.end(), rSymbol);
+ if (low == s_aRTFMathControlWords.end() || rSymbol < *low)
+ return false;
+ rSymbol = *low;
+ return true;
+}
+
+RTFError RTFTokenizer::dispatchKeyword(OString const& rKeyword, bool bParam, int nParam)
+{
+ if (m_rImport.getDestination() == Destination::SKIP)
+ {
+ // skip binary data explicitly, to not trip over rtf markup
+ // control characters
+ if (rKeyword == "bin" && nParam > 0)
+ Strm().SeekRel(nParam);
+ return RTFError::OK;
+ }
+ SAL_INFO("writerfilter.rtf", __func__ << ": keyword '\\" << rKeyword << "' with param? "
+ << (bParam ? 1 : 0) << " param val: '"
+ << (bParam ? nParam : 0) << "'");
+ auto findIt = s_aRTFControlWords.find(rKeyword);
+ if (findIt == s_aRTFControlWords.end())
+ {
+ SAL_INFO("writerfilter.rtf", __func__ << ": unknown keyword '\\" << rKeyword << "'");
+ RTFSkipDestination aSkip(m_rImport);
+ aSkip.setParsed(false);
+ return RTFError::OK;
+ }
+
+ RTFError ret;
+ RTFSymbol const& rSymbol = findIt->second;
+ switch (rSymbol.GetControlType())
+ {
+ case RTFControlType::FLAG:
+ // flags ignore any parameter by definition
+ ret = m_rImport.dispatchFlag(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::DESTINATION:
+ // same for destinations
+ ret = m_rImport.dispatchDestination(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::SYMBOL:
+ // and symbols
+ ret = m_rImport.dispatchSymbol(rSymbol.GetIndex());
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::TOGGLE:
+ ret = m_rImport.dispatchToggle(rSymbol.GetIndex(), bParam, nParam);
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ case RTFControlType::VALUE:
+ if (!bParam)
+ nParam = rSymbol.GetDefValue();
+ ret = m_rImport.dispatchValue(rSymbol.GetIndex(), nParam);
+ if (ret != RTFError::OK)
+ return ret;
+ break;
+ }
+
+ return RTFError::OK;
+}
+
+OUString RTFTokenizer::getPosition()
+{
+ return OUString::number(m_nLineNumber + 1) + ","
+ + OUString::number(Strm().Tell() - m_nLineStartPos + 1);
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtftokenizer.hxx b/sw/source/writerfilter/rtftok/rtftokenizer.hxx
new file mode 100644
index 000000000000..feb74fc63c57
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtftokenizer.hxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "rtflistener.hxx"
+
+#include <vector>
+#include <unordered_map>
+
+#include <com/sun/star/uno/Reference.h>
+
+#include <rtl/ustring.hxx>
+#include <tools/ref.hxx>
+
+namespace com::sun::star::task
+{
+class XStatusIndicator;
+}
+class SvStream;
+
+namespace writerfilter::rtftok
+{
+/// RTF tokenizer that separates control words from text.
+class RTFTokenizer final : public virtual SvRefBase
+{
+public:
+ RTFTokenizer(RTFListener& rImport, SvStream* pInStream,
+ css::uno::Reference<css::task::XStatusIndicator> const& xStatusIndicator);
+ ~RTFTokenizer() override;
+
+ RTFError resolveParse();
+ /// Number of states on the stack.
+ int getGroup() const { return m_nGroup; }
+ /// To be invoked by the pushState() callback to signal when the importer enters a group.
+ void pushGroup();
+ /// To be invoked by the popState() callback to signal when the importer leaves a group.
+ void popGroup();
+ OUString getPosition();
+ std::size_t getGroupStart() const { return m_nGroupStart; }
+ /// To look up additional properties of a math symbol.
+ static bool lookupMathKeyword(RTFMathSymbol& rSymbol);
+
+private:
+ SvStream& Strm() { return *m_pInStream; }
+ RTFError resolveKeyword();
+ RTFError dispatchKeyword(OString const& rKeyword, bool bParam, int nParam);
+
+ RTFListener& m_rImport;
+ SvStream* m_pInStream;
+ css::uno::Reference<css::task::XStatusIndicator> const& m_xStatusIndicator;
+ // This is the same as aRTFControlWords, but mapped by token name for fast lookup
+ static std::unordered_map<OString, RTFSymbol> s_aRTFControlWords;
+ static bool s_bControlWordsInitialised;
+ // This is the same as aRTFMathControlWords, but sorted
+ static std::vector<RTFMathSymbol> s_aRTFMathControlWords;
+ static bool s_bMathControlWordsSorted;
+ /// Same as the size of the importer's states, except that this can be negative for invalid input.
+ int m_nGroup;
+ sal_Int32 m_nLineNumber;
+ std::size_t m_nLineStartPos;
+ std::size_t m_nGroupStart;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfvalue.cxx b/sw/source/writerfilter/rtftok/rtfvalue.cxx
new file mode 100644
index 000000000000..6654a3f2eca5
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfvalue.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "rtfreferenceproperties.hxx"
+#include "rtfdocumentimpl.hxx"
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+using namespace com::sun::star;
+
+namespace writerfilter::rtftok
+{
+RTFValue::RTFValue(int nValue, OUString sValue, const RTFSprms* pAttributes, const RTFSprms* pSprms,
+ uno::Reference<drawing::XShape> xShape, uno::Reference<io::XInputStream> xStream,
+ uno::Reference<embed::XEmbeddedObject> xObject, bool bForceString,
+ const RTFShape* pShape, const RTFPicture* pPicture)
+ : m_nValue(nValue)
+ , m_sValue(std::move(sValue))
+ , m_xShape(std::move(xShape))
+ , m_xStream(std::move(xStream))
+ , m_xObject(std::move(xObject))
+ , m_bForceString(bForceString)
+{
+ if (pAttributes)
+ m_pAttributes = new RTFSprms(*pAttributes);
+ if (pSprms)
+ m_pSprms = new RTFSprms(*pSprms);
+ if (pShape)
+ m_pShape = new RTFShape(*pShape);
+ if (pPicture)
+ m_pPicture = new RTFPicture(*pPicture);
+}
+
+RTFValue::RTFValue() {}
+
+RTFValue::RTFValue(int nValue)
+ : m_nValue(nValue)
+{
+}
+
+RTFValue::RTFValue(OUString sValue, bool bForce)
+ : m_sValue(std::move(sValue))
+ , m_bForceString(bForce)
+{
+}
+
+RTFValue::RTFValue(const RTFSprms& rAttributes)
+ : m_pAttributes(new RTFSprms(rAttributes))
+{
+}
+
+RTFValue::RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms)
+ : m_pAttributes(new RTFSprms(rAttributes))
+ , m_pSprms(new RTFSprms(rSprms))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<drawing::XShape> xShape)
+ : m_xShape(std::move(xShape))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<io::XInputStream> xStream)
+ : m_xStream(std::move(xStream))
+{
+}
+
+RTFValue::RTFValue(uno::Reference<embed::XEmbeddedObject> xObject)
+ : m_xObject(std::move(xObject))
+{
+}
+
+RTFValue::RTFValue(const RTFShape& aShape)
+ : m_pShape(new RTFShape(aShape))
+{
+}
+
+RTFValue::RTFValue(const RTFPicture& rPicture)
+ : m_pPicture(new RTFPicture(rPicture))
+{
+}
+
+RTFValue::RTFValue(text::GraphicCrop const& rCrop)
+ : m_oCrop(rCrop)
+{
+}
+
+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 if (m_oCrop)
+ {
+ ret <<= *m_oCrop;
+ }
+ else
+ ret <<= static_cast<sal_Int32>(m_nValue);
+ return ret;
+}
+
+RTFShape& RTFValue::getShape() const
+{
+ if (!m_pShape)
+ m_pShape = new RTFShape();
+ return *m_pShape;
+}
+
+RTFPicture& RTFValue::getPicture() const
+{
+ if (!m_pPicture)
+ m_pPicture = new RTFPicture;
+ return *m_pPicture;
+}
+
+writerfilter::Reference<Properties>::Pointer_t RTFValue::getProperties()
+{
+ return new RTFReferenceProperties(getAttributes(), getSprms());
+}
+
+writerfilter::Reference<BinaryObj>::Pointer_t RTFValue::getBinary()
+{
+ return writerfilter::Reference<BinaryObj>::Pointer_t();
+}
+
+#ifdef DBG_UTIL
+std::string RTFValue::toString() const
+{
+ if (!m_sValue.isEmpty() || m_bForceString)
+ return std::string(OUStringToOString(m_sValue, RTL_TEXTENCODING_UTF8));
+
+ return std::string(OString::number(m_nValue));
+}
+#endif
+
+RTFValue* RTFValue::Clone() const
+{
+ return new RTFValue(m_nValue, m_sValue, m_pAttributes.get(), m_pSprms.get(), m_xShape,
+ m_xStream, m_xObject, m_bForceString, m_pShape.get(), m_pPicture.get());
+}
+
+RTFValue* RTFValue::CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) const
+{
+ return new RTFValue(m_nValue, m_sValue, &rAttributes, &rSprms, m_xShape, m_xStream, m_xObject,
+ m_bForceString, m_pShape.get(), m_pPicture.get());
+}
+
+bool RTFValue::equals(const RTFValue& rOther) const
+{
+ if (m_nValue != rOther.m_nValue)
+ return false;
+ if (m_sValue != rOther.m_sValue)
+ return false;
+
+ if (m_pAttributes && rOther.m_pAttributes)
+ {
+ if (m_pAttributes->size() != rOther.m_pAttributes->size())
+ return false;
+ if (!m_pAttributes->equals(*rOther.m_pAttributes))
+ return false;
+ }
+ else if (m_pAttributes && m_pAttributes->size())
+ {
+ return false;
+ }
+ else if (rOther.m_pAttributes && rOther.m_pAttributes->size())
+ {
+ return false;
+ }
+
+ if (m_pSprms && rOther.m_pSprms)
+ {
+ if (m_pSprms->size() != rOther.m_pSprms->size())
+ return false;
+ if (!m_pSprms->equals(*rOther.m_pSprms))
+ return false;
+ }
+ else if (m_pSprms && m_pSprms->size())
+ {
+ return false;
+ }
+ else if (rOther.m_pSprms && rOther.m_pSprms->size())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+RTFSprms& RTFValue::getAttributes() const
+{
+ if (!m_pAttributes)
+ m_pAttributes = new RTFSprms();
+ return *m_pAttributes;
+}
+
+RTFSprms& RTFValue::getSprms() const
+{
+ if (!m_pSprms)
+ m_pSprms = new RTFSprms();
+ return *m_pSprms;
+}
+
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/writerfilter/rtftok/rtfvalue.hxx b/sw/source/writerfilter/rtftok/rtfvalue.hxx
new file mode 100644
index 000000000000..6c87c61a1d05
--- /dev/null
+++ b/sw/source/writerfilter/rtftok/rtfvalue.hxx
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <dmapper/resourcemodel.hxx>
+
+#include <com/sun/star/text/GraphicCrop.hpp>
+
+#include <optional>
+
+namespace com::sun::star
+{
+namespace embed
+{
+class XEmbeddedObject;
+}
+namespace io
+{
+class XInputStream;
+}
+}
+
+namespace writerfilter::rtftok
+{
+class RTFSprms;
+class RTFShape;
+class RTFPicture;
+/// Value of an RTF keyword
+class RTFValue : public Value
+{
+ RTFValue(int nValue, OUString sValue, const RTFSprms* pAttributes, const RTFSprms* pSprms,
+ css::uno::Reference<css::drawing::XShape> xShape,
+ css::uno::Reference<css::io::XInputStream> xStream,
+ css::uno::Reference<css::embed::XEmbeddedObject> xObject, bool bForceString,
+ const RTFShape* pShape, const RTFPicture* pPicture);
+
+public:
+ using Pointer_t = tools::SvRef<RTFValue>;
+ RTFValue();
+ explicit RTFValue(int nValue);
+ RTFValue(OUString sValue, bool bForce = false);
+ explicit RTFValue(const RTFSprms& rAttributes);
+ RTFValue(const RTFSprms& rAttributes, const RTFSprms& rSprms);
+ explicit RTFValue(css::uno::Reference<css::drawing::XShape> xShape);
+ explicit RTFValue(css::uno::Reference<css::io::XInputStream> xStream);
+ explicit RTFValue(css::uno::Reference<css::embed::XEmbeddedObject> xObject);
+ explicit RTFValue(const RTFShape& aShape);
+ explicit RTFValue(const RTFPicture& rPicture);
+ explicit RTFValue(css::text::GraphicCrop const& rCrop);
+ ~RTFValue() override;
+ void setString(const OUString& sValue);
+ int getInt() const override;
+ OUString getString() const override;
+ css::uno::Any getAny() const override;
+ writerfilter::Reference<Properties>::Pointer_t getProperties() override;
+ writerfilter::Reference<BinaryObj>::Pointer_t getBinary() override;
+#ifdef DBG_UTIL
+ std::string toString() const override;
+#endif
+ RTFValue* Clone() const;
+ RTFValue* CloneWithSprms(RTFSprms const& rAttributes, RTFSprms const& rSprms) const;
+ RTFSprms& getAttributes() const;
+ RTFSprms& getSprms() const;
+ RTFShape& getShape() const;
+ RTFPicture& getPicture() const;
+ bool equals(const RTFValue& rOther) const;
+ RTFValue& operator=(RTFValue const& rOther) = delete;
+
+private:
+ int m_nValue = 0;
+ OUString m_sValue;
+ mutable tools::SvRef<RTFSprms> m_pAttributes;
+ mutable tools::SvRef<RTFSprms> m_pSprms;
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ css::uno::Reference<css::io::XInputStream> m_xStream;
+ css::uno::Reference<css::embed::XEmbeddedObject> m_xObject;
+ bool m_bForceString = false;
+ mutable tools::SvRef<RTFShape> m_pShape;
+ mutable tools::SvRef<RTFPicture> m_pPicture;
+ ::std::optional<css::text::GraphicCrop> m_oCrop;
+};
+} // namespace writerfilter::rtftok
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */