diff options
Diffstat (limited to 'writerfilter/source/rtftok/rtfdispatchvalue.cxx')
-rw-r--r-- | writerfilter/source/rtftok/rtfdispatchvalue.cxx | 1832 |
1 files changed, 1832 insertions, 0 deletions
diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx b/writerfilter/source/rtftok/rtfdispatchvalue.cxx new file mode 100644 index 000000000..2bea9dc9e --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx @@ -0,0 +1,1832 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "rtfdocumentimpl.hxx" + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/text/WrapTextMode.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <comphelper/sequence.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <osl/thread.h> +#include <sal/log.hxx> +#include <rtl/tencinfo.h> +#include <tools/UnitConversion.hxx> + +#include <ooxml/resourceids.hxx> + +#include "rtfcharsets.hxx" +#include "rtffly.hxx" +#include "rtfreferenceproperties.hxx" +#include "rtfskipdestination.hxx" + +#include <unotools/defaultencoding.hxx> +#include <unotools/wincodepage.hxx> + +using namespace com::sun::star; + +namespace writerfilter +{ +static int getNumberFormat(int nParam) +{ + static const int aMap[] + = { NS_ooxml::LN_Value_ST_NumberFormat_decimal, + NS_ooxml::LN_Value_ST_NumberFormat_upperRoman, + NS_ooxml::LN_Value_ST_NumberFormat_lowerRoman, + NS_ooxml::LN_Value_ST_NumberFormat_upperLetter, + NS_ooxml::LN_Value_ST_NumberFormat_lowerLetter, + NS_ooxml::LN_Value_ST_NumberFormat_ordinal, + NS_ooxml::LN_Value_ST_NumberFormat_cardinalText, + NS_ooxml::LN_Value_ST_NumberFormat_ordinalText, + NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec. + NS_ooxml::LN_Value_ST_NumberFormat_none, // Undefined in RTF 1.8 spec. + NS_ooxml::LN_Value_ST_NumberFormat_ideographDigital, + NS_ooxml::LN_Value_ST_NumberFormat_japaneseCounting, + NS_ooxml::LN_Value_ST_NumberFormat_aiueo, + NS_ooxml::LN_Value_ST_NumberFormat_iroha, + NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth, + NS_ooxml::LN_Value_ST_NumberFormat_decimalHalfWidth, + NS_ooxml::LN_Value_ST_NumberFormat_japaneseLegal, + NS_ooxml::LN_Value_ST_NumberFormat_japaneseDigitalTenThousand, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese, + NS_ooxml::LN_Value_ST_NumberFormat_decimalFullWidth2, + NS_ooxml::LN_Value_ST_NumberFormat_aiueoFullWidth, + NS_ooxml::LN_Value_ST_NumberFormat_irohaFullWidth, + NS_ooxml::LN_Value_ST_NumberFormat_decimalZero, + NS_ooxml::LN_Value_ST_NumberFormat_bullet, + NS_ooxml::LN_Value_ST_NumberFormat_ganada, + NS_ooxml::LN_Value_ST_NumberFormat_chosung, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedFullstop, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedParen, + NS_ooxml::LN_Value_ST_NumberFormat_decimalEnclosedCircleChinese, + NS_ooxml::LN_Value_ST_NumberFormat_ideographEnclosedCircle, + NS_ooxml::LN_Value_ST_NumberFormat_ideographTraditional, + NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiac, + NS_ooxml::LN_Value_ST_NumberFormat_ideographZodiacTraditional, + NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCounting, + NS_ooxml::LN_Value_ST_NumberFormat_ideographLegalTraditional, + NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseCountingThousand, + NS_ooxml::LN_Value_ST_NumberFormat_taiwaneseDigital, + NS_ooxml::LN_Value_ST_NumberFormat_chineseCounting, + NS_ooxml::LN_Value_ST_NumberFormat_chineseLegalSimplified, + NS_ooxml::LN_Value_ST_NumberFormat_chineseCountingThousand, + NS_ooxml::LN_Value_ST_NumberFormat_decimal, + NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital, + NS_ooxml::LN_Value_ST_NumberFormat_koreanCounting, + NS_ooxml::LN_Value_ST_NumberFormat_koreanLegal, + NS_ooxml::LN_Value_ST_NumberFormat_koreanDigital2, + NS_ooxml::LN_Value_ST_NumberFormat_hebrew1, + NS_ooxml::LN_Value_ST_NumberFormat_arabicAlpha, + NS_ooxml::LN_Value_ST_NumberFormat_hebrew2, + NS_ooxml::LN_Value_ST_NumberFormat_arabicAbjad }; + const int nLen = SAL_N_ELEMENTS(aMap); + int nValue = 0; + if (nParam >= 0 && nParam < nLen) + nValue = aMap[nParam]; + else // 255 and the other cases. + nValue = NS_ooxml::LN_Value_ST_NumberFormat_none; + return nValue; +} + +namespace rtftok +{ +bool RTFDocumentImpl::dispatchTableSprmValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); + switch (nKeyword) + { + case RTFKeyword::LEVELJC: + { + nSprm = NS_ooxml::LN_CT_Lvl_lvlJc; + int nValue = 0; + switch (nParam) + { + case 0: + nValue = NS_ooxml::LN_Value_ST_Jc_left; + break; + case 1: + nValue = NS_ooxml::LN_Value_ST_Jc_center; + break; + case 2: + nValue = NS_ooxml::LN_Value_ST_Jc_right; + break; + } + pIntValue = new RTFValue(nValue); + break; + } + case RTFKeyword::LEVELSTARTAT: + nSprm = NS_ooxml::LN_CT_Lvl_start; + break; + case RTFKeyword::LEVELPICTURE: + nSprm = NS_ooxml::LN_CT_Lvl_lvlPicBulletId; + break; + case RTFKeyword::SBASEDON: + nSprm = NS_ooxml::LN_CT_Style_basedOn; + pIntValue = new RTFValue(getStyleName(nParam)); + break; + case RTFKeyword::SNEXT: + nSprm = NS_ooxml::LN_CT_Style_next; + pIntValue = new RTFValue(getStyleName(nParam)); + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().getTableSprms().set(nSprm, pIntValue); + return true; + } + if (nKeyword == RTFKeyword::LEVELNFC) + { + pIntValue = new RTFValue(getNumberFormat(nParam)); + putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_numFmt, + NS_ooxml::LN_CT_NumFmt_val, pIntValue); + return true; + } + + return false; +} + +bool RTFDocumentImpl::dispatchCharacterSprmValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); + + switch (nKeyword) + { + case RTFKeyword::FS: + case RTFKeyword::AFS: + switch (m_aStates.top().getRunType()) + { + case RTFParserState::RunType::HICH: + case RTFParserState::RunType::RTLCH_LTRCH_1: + case RTFParserState::RunType::LTRCH_RTLCH_2: + nSprm = NS_ooxml::LN_EG_RPrBase_szCs; + break; + case RTFParserState::RunType::NONE: + case RTFParserState::RunType::LOCH: + case RTFParserState::RunType::LTRCH_RTLCH_1: + case RTFParserState::RunType::RTLCH_LTRCH_2: + case RTFParserState::RunType::DBCH: + default: + nSprm = NS_ooxml::LN_EG_RPrBase_sz; + break; + } + break; + case RTFKeyword::EXPNDTW: + nSprm = NS_ooxml::LN_EG_RPrBase_spacing; + break; + case RTFKeyword::KERNING: + nSprm = NS_ooxml::LN_EG_RPrBase_kern; + break; + case RTFKeyword::CHARSCALEX: + nSprm = NS_ooxml::LN_EG_RPrBase_w; + break; + default: + break; + } + if (nSprm > 0) + { + if (m_aStates.top().getDestination() == Destination::LISTLEVEL) + { + m_aStates.top().getTableSprms().set(nSprm, pIntValue); + } + else + { + m_aStates.top().getCharacterSprms().set(nSprm, pIntValue); + } + return true; + } + + return false; +} + +bool RTFDocumentImpl::dispatchCharacterAttributeValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + + switch (nKeyword) + { + case RTFKeyword::LANG: + case RTFKeyword::ALANG: + switch (m_aStates.top().getRunType()) + { + case RTFParserState::RunType::HICH: + case RTFParserState::RunType::RTLCH_LTRCH_1: + case RTFParserState::RunType::LTRCH_RTLCH_2: + nSprm = NS_ooxml::LN_CT_Language_bidi; + break; + case RTFParserState::RunType::DBCH: + nSprm = NS_ooxml::LN_CT_Language_eastAsia; + break; + case RTFParserState::RunType::NONE: + case RTFParserState::RunType::LOCH: + case RTFParserState::RunType::LTRCH_RTLCH_1: + case RTFParserState::RunType::RTLCH_LTRCH_2: + default: + nSprm = NS_ooxml::LN_CT_Language_val; + break; + } + break; + case RTFKeyword::LANGFE: // this one is always CJK apparently + nSprm = NS_ooxml::LN_CT_Language_eastAsia; + break; + default: + break; + } + if (nSprm > 0) + { + LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam)))); + auto pValue = new RTFValue(aTag.getBcp47()); + putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_lang, nSprm, + pValue); + // Language is a character property, but we should store it at a paragraph level as well for fields. + if (nKeyword == RTFKeyword::LANG && m_bNeedPap) + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_EG_RPrBase_lang, + nSprm, pValue); + return true; + } + + return false; +} + +bool RTFDocumentImpl::dispatchParagraphSprmValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); + + switch (nKeyword) + { + case RTFKeyword::ITAP: + nSprm = NS_ooxml::LN_tblDepth; + // tdf#117268: If \itap0 is encountered inside tables (between \cellxN and \cell), then + // use the default value (1), as Word apparently does + if (nParam == 0 && (m_nTopLevelCells != 0 || m_nNestedCells != 0)) + { + nParam = 1; + pIntValue = new RTFValue(nParam); + } + break; + default: + break; + } + if (nSprm > 0) + { + m_aStates.top().getParagraphSprms().set(nSprm, pIntValue); + if (nKeyword == RTFKeyword::ITAP && nParam > 0) + { + while (m_aTableBufferStack.size() < sal::static_int_cast<std::size_t>(nParam)) + { + m_aTableBufferStack.emplace_back(); + } + // Invalid tables may omit INTBL after ITAP + dispatchFlag(RTFKeyword::INTBL); // sets newly pushed buffer as current + assert(m_aStates.top().getCurrentBuffer() == &m_aTableBufferStack.back()); + } + return true; + } + + return false; +} + +bool RTFDocumentImpl::dispatchInfoValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + + switch (nKeyword) + { + case RTFKeyword::YR: + { + m_aStates.top().setYear(nParam); + nSprm = 1; + } + break; + case RTFKeyword::MO: + { + m_aStates.top().setMonth(nParam); + nSprm = 1; + } + break; + case RTFKeyword::DY: + { + m_aStates.top().setDay(nParam); + nSprm = 1; + } + break; + case RTFKeyword::HR: + { + m_aStates.top().setHour(nParam); + nSprm = 1; + } + break; + case RTFKeyword::MIN: + { + m_aStates.top().setMinute(nParam); + nSprm = 1; + } + break; + default: + break; + } + + return nSprm > 0; +} + +bool RTFDocumentImpl::dispatchFrameValue(RTFKeyword nKeyword, int nParam) +{ + Id nId = 0; + switch (nKeyword) + { + case RTFKeyword::ABSW: + nId = NS_ooxml::LN_CT_FramePr_w; + break; + case RTFKeyword::ABSH: + nId = NS_ooxml::LN_CT_FramePr_h; + break; + case RTFKeyword::POSX: + { + nId = NS_ooxml::LN_CT_FramePr_x; + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, 0); + } + break; + case RTFKeyword::POSY: + { + nId = NS_ooxml::LN_CT_FramePr_y; + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, 0); + } + break; + default: + break; + } + + if (nId > 0) + { + m_bNeedPap = true; + // Don't try to support text frames inside tables for now. + if (m_aStates.top().getCurrentBuffer() != &m_aTableBufferStack.back()) + m_aStates.top().getFrame().setSprm(nId, nParam); + + return true; + } + + return false; +} + +bool RTFDocumentImpl::dispatchTableValue(RTFKeyword nKeyword, int nParam) +{ + int nSprm = 0; + tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); + + switch (nKeyword) + { + case RTFKeyword::CELLX: + { + int& rCurrentCellX( + (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination()) + ? m_nNestedCurrentCellX + : m_nTopLevelCurrentCellX); + int nCellX = nParam - rCurrentCellX; + const int COL_DFLT_WIDTH + = 41; // sw/source/filter/inc/wrtswtbl.hxx, minimal possible width of cells. + if (!nCellX) + nCellX = COL_DFLT_WIDTH; + + // If there is a negative left margin, then the first cellx is relative to that. + RTFValue::Pointer_t pTblInd + = m_aStates.top().getTableRowSprms().find(NS_ooxml::LN_CT_TblPrBase_tblInd); + if (rCurrentCellX == 0 && pTblInd) + { + RTFValue::Pointer_t pWidth + = pTblInd->getAttributes().find(NS_ooxml::LN_CT_TblWidth_w); + if (pWidth && pWidth->getInt() < 0) + nCellX = -1 * (pWidth->getInt() - nParam); + } + + rCurrentCellX = nParam; + auto pXValue = new RTFValue(nCellX); + m_aStates.top().getTableRowSprms().set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue, + RTFOverwrite::NO_APPEND); + if (Destination::NESTEDTABLEPROPERTIES == m_aStates.top().getDestination()) + { + m_nNestedCells++; + // Push cell properties. + m_aNestedTableCellsSprms.push_back(m_aStates.top().getTableCellSprms()); + m_aNestedTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes()); + } + else + { + m_nTopLevelCells++; + // Push cell properties. + m_aTopLevelTableCellsSprms.push_back(m_aStates.top().getTableCellSprms()); + m_aTopLevelTableCellsAttributes.push_back(m_aStates.top().getTableCellAttributes()); + } + + m_aStates.top().getTableCellSprms() = m_aDefaultState.getTableCellSprms(); + m_aStates.top().getTableCellAttributes() = m_aDefaultState.getTableCellAttributes(); + // We assume text after a row definition always belongs to the table, to handle text before the real INTBL token + dispatchFlag(RTFKeyword::INTBL); + if (!m_nCellxMax) + { + // Wasn't in table, but now is -> tblStart. + RTFSprms aAttributes; + RTFSprms aSprms; + aSprms.set(NS_ooxml::LN_tblStart, new RTFValue(1)); + writerfilter::Reference<Properties>::Pointer_t pProperties + = new RTFReferenceProperties(std::move(aAttributes), std::move(aSprms)); + Mapper().props(pProperties); + } + m_nCellxMax = std::max(m_nCellxMax, nParam); + return true; + } + break; + case RTFKeyword::TRRH: + { + OUString hRule("auto"); + if (nParam < 0) + { + tools::SvRef<RTFValue> pAbsValue(new RTFValue(-nParam)); + std::swap(pIntValue, pAbsValue); + + hRule = "exact"; + } + else if (nParam > 0) + hRule = "atLeast"; + + putNestedAttribute(m_aStates.top().getTableRowSprms(), + NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_val, + pIntValue); + + auto pHRule = new RTFValue(hRule); + putNestedAttribute(m_aStates.top().getTableRowSprms(), + NS_ooxml::LN_CT_TrPrBase_trHeight, NS_ooxml::LN_CT_Height_hRule, + pHRule); + return true; + } + break; + case RTFKeyword::TRLEFT: + { + // the value is in twips + putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd, + NS_ooxml::LN_CT_TblWidth_type, + new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); + putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblInd, + NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); + auto const aDestination = m_aStates.top().getDestination(); + int& rCurrentTRLeft((Destination::NESTEDTABLEPROPERTIES == aDestination) + ? m_nNestedTRLeft + : m_nTopLevelTRLeft); + int& rCurrentCellX((Destination::NESTEDTABLEPROPERTIES == aDestination) + ? m_nNestedCurrentCellX + : m_nTopLevelCurrentCellX); + rCurrentTRLeft = rCurrentCellX = nParam; + return true; + } + break; + case RTFKeyword::CLSHDNG: + { + int nValue = -1; + + if (nParam < 1) + nValue = NS_ooxml::LN_Value_ST_Shd_clear; + else if (nParam < 750) + // Values in between 1 and 250 visually closer to 0% shading (white) + // But this will mean "no shading" while cell actually have some. + // So lets use minimal available value. + nValue = NS_ooxml::LN_Value_ST_Shd_pct5; + else if (nParam < 1100) + nValue = NS_ooxml::LN_Value_ST_Shd_pct10; + else if (nParam < 1350) + nValue = NS_ooxml::LN_Value_ST_Shd_pct12; + else if (nParam < 1750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct15; + else if (nParam < 2250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct20; + else if (nParam < 2750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct25; + else if (nParam < 3250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct30; + else if (nParam < 3600) + nValue = NS_ooxml::LN_Value_ST_Shd_pct35; + else if (nParam < 3850) + nValue = NS_ooxml::LN_Value_ST_Shd_pct37; + else if (nParam < 4250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct40; + else if (nParam < 4750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct45; + else if (nParam < 5250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct50; + else if (nParam < 5750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct55; + else if (nParam < 6100) + nValue = NS_ooxml::LN_Value_ST_Shd_pct60; + else if (nParam < 6350) + nValue = NS_ooxml::LN_Value_ST_Shd_pct62; + else if (nParam < 6750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct65; + else if (nParam < 7250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct70; + else if (nParam < 7750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct75; + else if (nParam < 8250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct80; + else if (nParam < 8600) + nValue = NS_ooxml::LN_Value_ST_Shd_pct85; + else if (nParam < 8850) + nValue = NS_ooxml::LN_Value_ST_Shd_pct87; + else if (nParam < 9250) + nValue = NS_ooxml::LN_Value_ST_Shd_pct90; + else if (nParam < 9750) + nValue = NS_ooxml::LN_Value_ST_Shd_pct95; + else + // Solid fill + nValue = NS_ooxml::LN_Value_ST_Shd_solid; + + putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd, + NS_ooxml::LN_CT_Shd_val, new RTFValue(nValue)); + return true; + } + break; + case RTFKeyword::CLPADB: + case RTFKeyword::CLPADL: + case RTFKeyword::CLPADR: + case RTFKeyword::CLPADT: + { + RTFSprms aAttributes; + aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, + new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); + aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); + // Top and left is swapped, that's what Word does. + switch (nKeyword) + { + case RTFKeyword::CLPADB: + nSprm = NS_ooxml::LN_CT_TcMar_bottom; + break; + case RTFKeyword::CLPADL: + nSprm = NS_ooxml::LN_CT_TcMar_top; + break; + case RTFKeyword::CLPADR: + nSprm = NS_ooxml::LN_CT_TcMar_right; + break; + case RTFKeyword::CLPADT: + nSprm = NS_ooxml::LN_CT_TcMar_left; + break; + default: + break; + } + putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, + nSprm, new RTFValue(aAttributes)); + return true; + } + break; + case RTFKeyword::TRPADDFB: + case RTFKeyword::TRPADDFL: + case RTFKeyword::TRPADDFR: + case RTFKeyword::TRPADDFT: + { + RTFSprms aAttributes; + switch (nParam) + { + case 3: + aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, + new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); + break; + } + switch (nKeyword) + { + case RTFKeyword::TRPADDFB: + nSprm = NS_ooxml::LN_CT_TcMar_bottom; + break; + case RTFKeyword::TRPADDFL: + nSprm = NS_ooxml::LN_CT_TcMar_left; + break; + case RTFKeyword::TRPADDFR: + nSprm = NS_ooxml::LN_CT_TcMar_right; + break; + case RTFKeyword::TRPADDFT: + nSprm = NS_ooxml::LN_CT_TcMar_top; + break; + default: + break; + } + putNestedAttribute(m_aStates.top().getTableRowSprms(), + NS_ooxml::LN_CT_TblPrBase_tblCellMar, nSprm, + new RTFValue(aAttributes)); + // tdf#74795 also set on current cell, and as default for table cells + // (why isn't this done by domainmapper?) + putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, + nSprm, new RTFValue(aAttributes)); + putNestedAttribute(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, + nSprm, new RTFValue(aAttributes)); + return true; + } + break; + case RTFKeyword::TRPADDB: + case RTFKeyword::TRPADDL: + case RTFKeyword::TRPADDR: + case RTFKeyword::TRPADDT: + { + RTFSprms aAttributes; + aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, new RTFValue(nParam)); + switch (nKeyword) + { + case RTFKeyword::TRPADDB: + nSprm = NS_ooxml::LN_CT_TcMar_bottom; + break; + case RTFKeyword::TRPADDL: + nSprm = NS_ooxml::LN_CT_TcMar_left; + break; + case RTFKeyword::TRPADDR: + nSprm = NS_ooxml::LN_CT_TcMar_right; + break; + case RTFKeyword::TRPADDT: + nSprm = NS_ooxml::LN_CT_TcMar_top; + break; + default: + break; + } + putNestedSprm(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblCellMar, + nSprm, new RTFValue(aAttributes)); + // tdf#74795 also set on current cell, and as default for table cells + // (why isn't this done by domainmapper?) + putNestedSprm(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, + nSprm, new RTFValue(aAttributes)); + putNestedSprm(m_aDefaultState.getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_tcMar, + nSprm, new RTFValue(aAttributes)); + return true; + } + case RTFKeyword::TRGAPH: + // Half of the space between the cells of a table row: default left/right table cell margin. + if (nParam > 0) + { + RTFSprms aAttributes; + aAttributes.set(NS_ooxml::LN_CT_TblWidth_type, + new RTFValue(NS_ooxml::LN_Value_ST_TblWidth_dxa)); + aAttributes.set(NS_ooxml::LN_CT_TblWidth_w, pIntValue); + // FIXME: this is wrong, it is half-gap, needs to be distinguished from margin! depending on TRPADDFL/TRPADDFR + putNestedSprm(m_aStates.top().getTableRowSprms(), + NS_ooxml::LN_CT_TblPrBase_tblCellMar, NS_ooxml::LN_CT_TblCellMar_left, + new RTFValue(aAttributes)); + putNestedSprm(m_aStates.top().getTableRowSprms(), + NS_ooxml::LN_CT_TblPrBase_tblCellMar, + NS_ooxml::LN_CT_TblCellMar_right, new RTFValue(aAttributes)); + } + return true; + case RTFKeyword::TRFTSWIDTH: + putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW, + NS_ooxml::LN_CT_TblWidth_type, pIntValue); + return true; + case RTFKeyword::TRWWIDTH: + putNestedAttribute(m_aStates.top().getTableRowSprms(), NS_ooxml::LN_CT_TblPrBase_tblW, + NS_ooxml::LN_CT_TblWidth_w, pIntValue); + return true; + default: + break; + } + + return false; +} + +RTFError RTFDocumentImpl::dispatchValue(RTFKeyword nKeyword, int nParam) +{ + setNeedSect(true); + checkUnicode(/*bUnicode =*/nKeyword != RTFKeyword::U, /*bHex =*/true); + RTFSkipDestination aSkip(*this); + int nSprm = 0; + tools::SvRef<RTFValue> pIntValue(new RTFValue(nParam)); + // Trivial table sprms. + if (dispatchTableSprmValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Trivial character sprms. + if (dispatchCharacterSprmValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Trivial character attributes. + if (dispatchCharacterAttributeValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Trivial paragraph sprms. + if (dispatchParagraphSprmValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Info group. + if (dispatchInfoValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Frame size / position. + if (dispatchFrameValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Table-related values. + if (dispatchTableValue(nKeyword, nParam)) + { + return RTFError::OK; + } + + // Then check for the more complex ones. + switch (nKeyword) + { + case RTFKeyword::F: + case RTFKeyword::AF: + switch (m_aStates.top().getRunType()) + { + case RTFParserState::RunType::RTLCH_LTRCH_1: + case RTFParserState::RunType::LTRCH_RTLCH_2: + nSprm = NS_ooxml::LN_CT_Fonts_cs; + break; + case RTFParserState::RunType::DBCH: + nSprm = NS_ooxml::LN_CT_Fonts_eastAsia; + break; + case RTFParserState::RunType::NONE: + case RTFParserState::RunType::LOCH: + case RTFParserState::RunType::HICH: + case RTFParserState::RunType::LTRCH_RTLCH_1: + case RTFParserState::RunType::RTLCH_LTRCH_2: + default: + nSprm = NS_ooxml::LN_CT_Fonts_ascii; + break; + } + + if (m_aStates.top().getDestination() == Destination::FONTTABLE + || m_aStates.top().getDestination() == Destination::FONTENTRY) + { + // Some text in buffer? It is font name. So previous font definition is complete + if (m_aStates.top().getCurrentDestinationText()->getLength()) + handleFontTableEntry(); + + m_aFontIndexes.push_back(nParam); + m_nCurrentFontIndex = getFontIndex(nParam); + } + else if (m_aStates.top().getDestination() == Destination::LISTLEVEL) + { + RTFSprms aFontAttributes; + aFontAttributes.set(nSprm, new RTFValue(m_aFontNames[getFontIndex(nParam)])); + RTFSprms aRunPropsSprms; + aRunPropsSprms.set(NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aFontAttributes)); + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_rPr, + new RTFValue(RTFSprms(), aRunPropsSprms), + RTFOverwrite::NO_APPEND); + } + else + { + m_nCurrentFontIndex = getFontIndex(nParam); + auto pValue = new RTFValue(getFontName(m_nCurrentFontIndex)); + putNestedAttribute(m_aStates.top().getCharacterSprms(), + NS_ooxml::LN_EG_RPrBase_rFonts, nSprm, pValue); + if (nKeyword == RTFKeyword::F) + m_aStates.top().setCurrentEncoding(getEncoding(m_nCurrentFontIndex)); + } + break; + case RTFKeyword::RED: + m_aStates.top().getCurrentColor().SetRed(nParam); + break; + case RTFKeyword::GREEN: + m_aStates.top().getCurrentColor().SetGreen(nParam); + break; + case RTFKeyword::BLUE: + m_aStates.top().getCurrentColor().SetBlue(nParam); + break; + case RTFKeyword::FCHARSET: + { + // we always send text to the domain mapper in OUString, so no + // need to send encoding info + int i; + for (i = 0; i < nRTFEncodings; i++) + { + if (aRTFEncodings[i].charset == nParam) + break; + } + if (i == nRTFEncodings) + // not found + return RTFError::OK; + + m_nCurrentEncoding + = aRTFEncodings[i].codepage == 0 // Default (CP_ACP) + ? osl_getThreadTextEncoding() + : rtl_getTextEncodingFromWindowsCodePage(aRTFEncodings[i].codepage); + m_aStates.top().setCurrentEncoding(m_nCurrentEncoding); + } + break; + case RTFKeyword::ANSICPG: + case RTFKeyword::CPG: + { + rtl_TextEncoding nEncoding + = (nParam == 0) + ? utl_getWinTextEncodingFromLangStr(utl_getLocaleForGlobalDefaultEncoding()) + : rtl_getTextEncodingFromWindowsCodePage(nParam); + if (nKeyword == RTFKeyword::ANSICPG) + m_aDefaultState.setCurrentEncoding(nEncoding); + else + m_nCurrentEncoding = nEncoding; + m_aStates.top().setCurrentEncoding(nEncoding); + } + break; + case RTFKeyword::CF: + { + RTFSprms aAttributes; + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + aAttributes.set(NS_ooxml::LN_CT_Color_val, pValue); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_color, + new RTFValue(aAttributes)); + } + break; + case RTFKeyword::S: + { + m_aStates.top().setCurrentStyleIndex(nParam); + + if (m_aStates.top().getDestination() == Destination::STYLESHEET + || m_aStates.top().getDestination() == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_paragraph); + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, + pValue); // paragraph style + } + else + { + OUString aName = getStyleName(nParam); + if (!aName.isEmpty()) + { + if (m_aStates.top().getDestination() == Destination::LISTLEVEL) + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_pStyle, + new RTFValue(aName)); + else + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_pStyle, + new RTFValue(aName)); + } + } + } + break; + case RTFKeyword::CS: + m_aStates.top().setCurrentCharacterStyleIndex(nParam); + if (m_aStates.top().getDestination() == Destination::STYLESHEET + || m_aStates.top().getDestination() == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + auto pValue = new RTFValue(NS_ooxml::LN_Value_ST_StyleType_character); + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, + pValue); // character style + } + else + { + OUString aName = getStyleName(nParam); + if (!aName.isEmpty()) + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_rStyle, + new RTFValue(aName)); + } + break; + case RTFKeyword::DS: + if (m_aStates.top().getDestination() == Destination::STYLESHEET + || m_aStates.top().getDestination() == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + auto pValue = new RTFValue(0); // TODO no value in enum StyleType? + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, + pValue); // section style + } + break; + case RTFKeyword::TS: + if (m_aStates.top().getDestination() == Destination::STYLESHEET + || m_aStates.top().getDestination() == Destination::STYLEENTRY) + { + m_nCurrentStyleIndex = nParam; + // FIXME the correct value would be NS_ooxml::LN_Value_ST_StyleType_table but maybe table styles mess things up in dmapper, be cautious and disable them for now + auto pValue = new RTFValue(0); + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_Style_type, + pValue); // table style + } + break; + case RTFKeyword::DEFF: + m_nDefaultFontIndex = nParam; + break; + case RTFKeyword::STSHFDBCH: + // tdf#123703 switch off longer space sequence except in the case of the fixed compatibility setting font id 31505 + if (nParam != 31505) + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_longerSpaceSequence, + new RTFValue(0)); + break; + case RTFKeyword::DEFLANG: + case RTFKeyword::ADEFLANG: + { + LanguageTag aTag((LanguageType(static_cast<sal_uInt16>(nParam)))); + auto pValue = new RTFValue(aTag.getBcp47()); + putNestedAttribute(m_aStates.top().getCharacterSprms(), + (nKeyword == RTFKeyword::DEFLANG ? NS_ooxml::LN_EG_RPrBase_lang + : NS_ooxml::LN_CT_Language_bidi), + nSprm, pValue); + } + break; + case RTFKeyword::CHCBPAT: + { + auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO)); + putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_EG_RPrBase_shd, + NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTFKeyword::CLCBPAT: + case RTFKeyword::CLCBPATRAW: + { + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + putNestedAttribute(m_aStates.top().getTableCellSprms(), NS_ooxml::LN_CT_TcPrBase_shd, + NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTFKeyword::CBPAT: + if (nParam) + { + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PrBase_shd, + NS_ooxml::LN_CT_Shd_fill, pValue); + } + break; + case RTFKeyword::ULC: + { + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + m_aStates.top().getCharacterSprms().set(0x6877, pValue); + } + break; + case RTFKeyword::HIGHLIGHT: + { + auto pValue = new RTFValue(sal_uInt32(nParam ? getColorTable(nParam) : COL_AUTO)); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_highlight, pValue); + } + break; + case RTFKeyword::UP: + case RTFKeyword::DN: + { + auto pValue = new RTFValue(nParam * (nKeyword == RTFKeyword::UP ? 1 : -1)); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_position, pValue); + } + break; + case RTFKeyword::HORZVERT: + { + auto pValue = new RTFValue(int(true)); + m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_vert, + pValue); + if (nParam) + // rotate fits to a single line + m_aStates.top().getCharacterAttributes().set( + NS_ooxml::LN_CT_EastAsianLayout_vertCompress, pValue); + } + break; + case RTFKeyword::EXPND: + { + // Convert quarter-points to twentieths of a point + auto pValue = new RTFValue(nParam * 5); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_spacing, pValue); + } + break; + case RTFKeyword::TWOINONE: + { + auto pValue = new RTFValue(int(true)); + m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_EastAsianLayout_combine, + pValue); + Id nId = 0; + switch (nParam) + { + case 0: + nId = NS_ooxml::LN_Value_ST_CombineBrackets_none; + break; + case 1: + nId = NS_ooxml::LN_Value_ST_CombineBrackets_round; + break; + case 2: + nId = NS_ooxml::LN_Value_ST_CombineBrackets_square; + break; + case 3: + nId = NS_ooxml::LN_Value_ST_CombineBrackets_angle; + break; + case 4: + nId = NS_ooxml::LN_Value_ST_CombineBrackets_curly; + break; + } + if (nId > 0) + m_aStates.top().getCharacterAttributes().set( + NS_ooxml::LN_CT_EastAsianLayout_combineBrackets, new RTFValue(nId)); + } + break; + case RTFKeyword::SL: + { + // This is similar to RTFKeyword::ABSH, negative value means 'exact', positive means 'at least'. + tools::SvRef<RTFValue> pValue( + new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_atLeast)); + if (nParam < 0) + { + pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact); + pIntValue = new RTFValue(-nParam); + } + m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, pValue); + m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_line, pIntValue); + } + break; + case RTFKeyword::SLMULT: + if (nParam > 0) + { + auto pValue = new RTFValue(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_auto); + m_aStates.top().getParagraphAttributes().set(NS_ooxml::LN_CT_Spacing_lineRule, + pValue); + } + break; + case RTFKeyword::BRDRW: + { + // dmapper expects it in 1/8 pt, we have it in twip - but avoid rounding 1 to 0 + if (nParam > 1) + nParam = nParam * 2 / 5; + auto pValue = new RTFValue(nParam); + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_sz, pValue); + } + break; + case RTFKeyword::BRDRCF: + { + auto pValue = new RTFValue(sal_uInt32(getColorTable(nParam))); + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_color, pValue); + } + break; + case RTFKeyword::BRSP: + { + // dmapper expects it in points, we have it in twip + auto pValue = new RTFValue(nParam / 20); + putBorderProperty(m_aStates, NS_ooxml::LN_CT_Border_space, pValue); + } + break; + case RTFKeyword::TX: + { + m_aStates.top().getTabAttributes().set(NS_ooxml::LN_CT_TabStop_pos, pIntValue); + auto pValue = new RTFValue(m_aStates.top().getTabAttributes()); + if (m_aStates.top().getDestination() == Destination::LISTLEVEL) + putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_tabs, + NS_ooxml::LN_CT_Tabs_tab, pValue); + else + putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_tabs, + NS_ooxml::LN_CT_Tabs_tab, pValue); + m_aStates.top().getTabAttributes().clear(); + } + break; + case RTFKeyword::ILVL: + putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr, + NS_ooxml::LN_CT_NumPr_ilvl, pIntValue); + break; + case RTFKeyword::LISTTEMPLATEID: + // This one is not referenced anywhere, so it's pointless to store it at the moment. + break; + case RTFKeyword::LISTID: + { + if (m_aStates.top().getDestination() == Destination::LISTENTRY) + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_abstractNumId, + pIntValue); + else if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY) + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Num_abstractNumId, pIntValue); + m_aStates.top().setCurrentListIndex(nParam); + } + break; + case RTFKeyword::LS: + { + if (m_aStates.top().getDestination() == Destination::LISTOVERRIDEENTRY) + { + m_aStates.top().getTableAttributes().set(NS_ooxml::LN_CT_AbstractNum_nsid, + pIntValue); + m_aStates.top().setCurrentListOverrideIndex(nParam); + } + else + { + // Insert at the start, so properties inherited from the list + // can be overridden by direct formatting. But still allow the + // case when old-style paragraph numbering is already + // tokenized. + putNestedSprm(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_numPr, + NS_ooxml::LN_CT_NumPr_numId, pIntValue, RTFOverwrite::YES_PREPEND); + } + } + break; + case RTFKeyword::UC: + if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_INT16)) + m_aStates.top().setUc(nParam); + break; + case RTFKeyword::U: + // sal_Unicode is unsigned 16-bit, RTF may represent that as a + // signed SAL_MIN_INT16..SAL_MAX_INT16 or 0..SAL_MAX_UINT16. The + // static_cast() will do the right thing. + if ((SAL_MIN_INT16 <= nParam) && (nParam <= SAL_MAX_UINT16)) + { + if (m_aStates.top().getDestination() == Destination::LEVELNUMBERS) + { + if (nParam != ';') + m_aStates.top().getLevelNumbers().push_back(sal_Int32(nParam)); + else + // ';' in \u form is not considered valid. + m_aStates.top().setLevelNumbersValid(false); + } + else + m_aUnicodeBuffer.append(static_cast<sal_Unicode>(nParam)); + m_aStates.top().getCharsToSkip() = m_aStates.top().getUc(); + } + break; + case RTFKeyword::LEVELFOLLOW: + { + OUString sValue; + switch (nParam) + { + case 0: + sValue = "tab"; + break; + case 1: + sValue = "space"; + break; + case 2: + sValue = "nothing"; + break; + } + if (!sValue.isEmpty()) + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_suff, new RTFValue(sValue)); + } + break; + case RTFKeyword::FPRQ: + { + sal_Int32 nValue = 0; + switch (nParam) + { + case 0: + nValue = NS_ooxml::LN_Value_ST_Pitch_default; + break; + case 1: + nValue = NS_ooxml::LN_Value_ST_Pitch_fixed; + break; + case 2: + nValue = NS_ooxml::LN_Value_ST_Pitch_variable; + break; + } + if (nValue) + { + RTFSprms aAttributes; + aAttributes.set(NS_ooxml::LN_CT_Pitch_val, new RTFValue(nValue)); + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Font_pitch, + new RTFValue(aAttributes)); + } + } + break; + case RTFKeyword::LISTOVERRIDECOUNT: + // Ignore this for now, the exporter always emits it with a zero parameter. + break; + case RTFKeyword::PICSCALEX: + m_aStates.top().getPicture().nScaleX = nParam; + break; + case RTFKeyword::PICSCALEY: + m_aStates.top().getPicture().nScaleY = nParam; + break; + case RTFKeyword::PICW: + m_aStates.top().getPicture().nWidth = nParam; + break; + case RTFKeyword::PICH: + m_aStates.top().getPicture().nHeight = nParam; + break; + case RTFKeyword::PICWGOAL: + m_aStates.top().getPicture().nGoalWidth = convertTwipToMm100(nParam); + break; + case RTFKeyword::PICHGOAL: + m_aStates.top().getPicture().nGoalHeight = convertTwipToMm100(nParam); + break; + case RTFKeyword::PICCROPL: + m_aStates.top().getPicture().nCropL = convertTwipToMm100(nParam); + break; + case RTFKeyword::PICCROPR: + m_aStates.top().getPicture().nCropR = convertTwipToMm100(nParam); + break; + case RTFKeyword::PICCROPT: + m_aStates.top().getPicture().nCropT = convertTwipToMm100(nParam); + break; + case RTFKeyword::PICCROPB: + m_aStates.top().getPicture().nCropB = convertTwipToMm100(nParam); + break; + case RTFKeyword::SHPWRK: + { + int nValue = 0; + switch (nParam) + { + case 0: + nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides; + break; + case 1: + nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left; + break; + case 2: + nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right; + break; + case 3: + nValue = NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest; + break; + default: + break; + } + auto pValue = new RTFValue(nValue); + RTFValue::Pointer_t pTight + = m_aStates.top().getCharacterSprms().find(NS_ooxml::LN_EG_WrapType_wrapTight); + if (pTight) + pTight->getAttributes().set(NS_ooxml::LN_CT_WrapTight_wrapText, pValue); + else + m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_WrapSquare_wrapText, + pValue); + } + break; + case RTFKeyword::SHPWR: + { + switch (nParam) + { + case 1: + m_aStates.top().getShape().setWrap(text::WrapTextMode_NONE); + break; + case 2: + m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL); + break; + case 3: + m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapNone, + new RTFValue()); + break; + case 4: + m_aStates.top().getShape().setWrap(text::WrapTextMode_PARALLEL); + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_WrapType_wrapTight, + new RTFValue()); + break; + case 5: + m_aStates.top().getShape().setWrap(text::WrapTextMode_THROUGH); + break; + } + } + break; + case RTFKeyword::COLS: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_num, + pIntValue); + break; + case RTFKeyword::COLSX: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols, NS_ooxml::LN_CT_Columns_space, + pIntValue); + break; + case RTFKeyword::COLNO: + putNestedSprm(m_aStates.top().getSectionSprms(), NS_ooxml::LN_EG_SectPrContents_cols, + NS_ooxml::LN_CT_Columns_col, pIntValue); + break; + case RTFKeyword::COLW: + case RTFKeyword::COLSR: + { + RTFSprms& rAttributes = getLastAttributes(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_cols); + rAttributes.set((nKeyword == RTFKeyword::COLW ? NS_ooxml::LN_CT_Column_w + : NS_ooxml::LN_CT_Column_space), + pIntValue); + } + break; + case RTFKeyword::PAPERH: + putNestedAttribute(m_aDefaultState.getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, + pIntValue); + [[fallthrough]]; // set the default + current value + case RTFKeyword::PGHSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_h, + pIntValue); + break; + case RTFKeyword::PAPERW: + putNestedAttribute(m_aDefaultState.getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, + pIntValue); + [[fallthrough]]; // set the default + current value + case RTFKeyword::PGWSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgSz, NS_ooxml::LN_CT_PageSz_w, + pIntValue); + break; + case RTFKeyword::MARGL: + putNestedAttribute(m_aDefaultState.getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, + pIntValue); + [[fallthrough]]; // set the default + current value + case RTFKeyword::MARGLSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_left, + pIntValue); + break; + case RTFKeyword::MARGR: + putNestedAttribute(m_aDefaultState.getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, + pIntValue); + [[fallthrough]]; // set the default + current value + case RTFKeyword::MARGRSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_right, + pIntValue); + break; + case RTFKeyword::MARGT: + putNestedAttribute(m_aDefaultState.getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, + pIntValue); + [[fallthrough]]; // set the default + current value + case RTFKeyword::MARGTSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_top, + pIntValue); + break; + case RTFKeyword::MARGB: + putNestedAttribute(m_aDefaultState.getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, + pIntValue); + [[fallthrough]]; // set the default + current value + case RTFKeyword::MARGBSXN: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_bottom, + pIntValue); + break; + case RTFKeyword::HEADERY: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_header, + pIntValue); + break; + case RTFKeyword::FOOTERY: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_footer, + pIntValue); + break; + case RTFKeyword::GUTTER: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgMar, NS_ooxml::LN_CT_PageMar_gutter, + pIntValue); + break; + case RTFKeyword::DEFTAB: + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_defaultTabStop, pIntValue); + break; + case RTFKeyword::LINEMOD: + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_lnNumType, + NS_ooxml::LN_CT_LineNumber_countBy, pIntValue); + break; + case RTFKeyword::LINEX: + if (nParam) + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_lnNumType, + NS_ooxml::LN_CT_LineNumber_distance, pIntValue); + break; + case RTFKeyword::LINESTARTS: + { + // OOXML <w:lnNumType w:start="..."/> is 0-based, RTF is 1-based. + auto pStart = tools::make_ref<RTFValue>(nParam - 1); + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_lnNumType, + NS_ooxml::LN_CT_LineNumber_start, pStart); + } + break; + case RTFKeyword::REVAUTH: + case RTFKeyword::REVAUTHDEL: + { + auto pValue = new RTFValue(m_aAuthors[nParam]); + putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange, + NS_ooxml::LN_CT_TrackChange_author, pValue); + } + break; + case RTFKeyword::REVDTTM: + case RTFKeyword::REVDTTMDEL: + { + OUString aStr( + OStringToOUString(DTTM22OString(nParam), m_aStates.top().getCurrentEncoding())); + auto pValue = new RTFValue(aStr); + putNestedAttribute(m_aStates.top().getCharacterSprms(), NS_ooxml::LN_trackchange, + NS_ooxml::LN_CT_TrackChange_date, pValue); + } + break; + case RTFKeyword::SHPLEFT: + m_aStates.top().getShape().setLeft(convertTwipToMm100(nParam)); + break; + case RTFKeyword::SHPTOP: + m_aStates.top().getShape().setTop(convertTwipToMm100(nParam)); + break; + case RTFKeyword::SHPRIGHT: + m_aStates.top().getShape().setRight(convertTwipToMm100(nParam)); + break; + case RTFKeyword::SHPBOTTOM: + m_aStates.top().getShape().setBottom(convertTwipToMm100(nParam)); + break; + case RTFKeyword::SHPZ: + m_aStates.top().getShape().setZ(nParam); + break; + case RTFKeyword::FFTYPE: + switch (nParam) + { + case 0: + m_nFormFieldType = RTFFormFieldType::TEXT; + break; + case 1: + m_nFormFieldType = RTFFormFieldType::CHECKBOX; + break; + case 2: + m_nFormFieldType = RTFFormFieldType::LIST; + break; + default: + m_nFormFieldType = RTFFormFieldType::NONE; + break; + } + break; + case RTFKeyword::FFDEFRES: + if (m_nFormFieldType == RTFFormFieldType::CHECKBOX) + m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_default, pIntValue); + else if (m_nFormFieldType == RTFFormFieldType::LIST) + m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_default, pIntValue); + break; + case RTFKeyword::FFRES: + // 25 means undefined, see [MS-DOC] 2.9.79, FFDataBits. + if (m_nFormFieldType == RTFFormFieldType::CHECKBOX && nParam != 25) + m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFCheckBox_checked, pIntValue); + else if (m_nFormFieldType == RTFFormFieldType::LIST) + m_aFormfieldSprms.set(NS_ooxml::LN_CT_FFDDList_result, pIntValue); + break; + case RTFKeyword::EDMINS: + if (m_xDocumentProperties.is()) + { + // tdf#116851 some RTF may be malformed + if (nParam < 0) + nParam = -nParam; + m_xDocumentProperties->setEditingDuration(nParam); + } + break; + case RTFKeyword::NOFPAGES: + case RTFKeyword::NOFWORDS: + case RTFKeyword::NOFCHARS: + case RTFKeyword::NOFCHARSWS: + if (m_xDocumentProperties.is()) + { + comphelper::SequenceAsHashMap aSeq = m_xDocumentProperties->getDocumentStatistics(); + OUString aName; + switch (nKeyword) + { + case RTFKeyword::NOFPAGES: + aName = "PageCount"; + nParam = 99; + break; + case RTFKeyword::NOFWORDS: + aName = "WordCount"; + break; + case RTFKeyword::NOFCHARS: + aName = "CharacterCount"; + break; + case RTFKeyword::NOFCHARSWS: + aName = "NonWhitespaceCharacterCount"; + break; + default: + break; + } + if (!aName.isEmpty()) + { + aSeq[aName] <<= sal_Int32(nParam); + m_xDocumentProperties->setDocumentStatistics(aSeq.getAsConstNamedValueList()); + } + } + break; + case RTFKeyword::VERSION: + if (m_xDocumentProperties.is()) + m_xDocumentProperties->setEditingCycles(nParam); + break; + case RTFKeyword::VERN: + // Ignore this for now, later the RTF writer version could be used to add hacks for older buggy writers. + break; + case RTFKeyword::FTNSTART: + putNestedSprm(m_aDefaultState.getParagraphSprms(), + NS_ooxml::LN_EG_SectPrContents_footnotePr, + NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue); + break; + case RTFKeyword::AFTNSTART: + putNestedSprm(m_aDefaultState.getParagraphSprms(), + NS_ooxml::LN_EG_SectPrContents_endnotePr, + NS_ooxml::LN_EG_FtnEdnNumProps_numStart, pIntValue); + break; + case RTFKeyword::DFRMTXTX: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam); + break; + case RTFKeyword::DFRMTXTY: + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam); + break; + case RTFKeyword::DXFRTEXT: + { + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hSpace, nParam); + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vSpace, nParam); + } + break; + case RTFKeyword::FLYVERT: + { + RTFVertOrient aVertOrient(nParam); + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_yAlign, + aVertOrient.GetAlign()); + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_vAnchor, + aVertOrient.GetAnchor()); + } + break; + case RTFKeyword::FLYHORZ: + { + RTFHoriOrient aHoriOrient(nParam); + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_xAlign, + aHoriOrient.GetAlign()); + m_aStates.top().getFrame().setSprm(NS_ooxml::LN_CT_FramePr_hAnchor, + aHoriOrient.GetAnchor()); + } + break; + case RTFKeyword::FLYANCHOR: + break; + case RTFKeyword::WMETAFILE: + m_aStates.top().getPicture().eWMetafile = nParam; + break; + case RTFKeyword::SB: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, + NS_ooxml::LN_CT_Spacing_before, pIntValue); + break; + case RTFKeyword::SA: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_spacing, + NS_ooxml::LN_CT_Spacing_after, pIntValue); + break; + case RTFKeyword::DPX: + m_aStates.top().getDrawingObject().setLeft(convertTwipToMm100(nParam)); + break; + case RTFKeyword::DPY: + m_aStates.top().getDrawingObject().setTop(convertTwipToMm100(nParam)); + break; + case RTFKeyword::DPXSIZE: + m_aStates.top().getDrawingObject().setRight(convertTwipToMm100(nParam)); + break; + case RTFKeyword::DPYSIZE: + m_aStates.top().getDrawingObject().setBottom(convertTwipToMm100(nParam)); + break; + case RTFKeyword::PNSTART: + m_aStates.top().getTableSprms().set(NS_ooxml::LN_CT_Lvl_start, pIntValue); + break; + case RTFKeyword::PNF: + { + auto pValue = new RTFValue(m_aFontNames[getFontIndex(nParam)]); + RTFSprms aAttributes; + aAttributes.set(NS_ooxml::LN_CT_Fonts_ascii, pValue); + putNestedSprm(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_Lvl_rPr, + NS_ooxml::LN_EG_RPrBase_rFonts, new RTFValue(aAttributes)); + } + break; + case RTFKeyword::VIEWSCALE: + m_aSettingsTableAttributes.set(NS_ooxml::LN_CT_Zoom_percent, pIntValue); + break; + case RTFKeyword::BIN: + { + m_aStates.top().setInternalState(RTFInternalState::BIN); + m_aStates.top().setBinaryToRead(nParam); + } + break; + case RTFKeyword::DPLINECOR: + m_aStates.top().getDrawingObject().setLineColorR(nParam); + m_aStates.top().getDrawingObject().setHasLineColor(true); + break; + case RTFKeyword::DPLINECOG: + m_aStates.top().getDrawingObject().setLineColorG(nParam); + m_aStates.top().getDrawingObject().setHasLineColor(true); + break; + case RTFKeyword::DPLINECOB: + m_aStates.top().getDrawingObject().setLineColorB(nParam); + m_aStates.top().getDrawingObject().setHasLineColor(true); + break; + case RTFKeyword::DPFILLBGCR: + m_aStates.top().getDrawingObject().setFillColorR(nParam); + m_aStates.top().getDrawingObject().setHasFillColor(true); + break; + case RTFKeyword::DPFILLBGCG: + m_aStates.top().getDrawingObject().setFillColorG(nParam); + m_aStates.top().getDrawingObject().setHasFillColor(true); + break; + case RTFKeyword::DPFILLBGCB: + m_aStates.top().getDrawingObject().setFillColorB(nParam); + m_aStates.top().getDrawingObject().setHasFillColor(true); + break; + case RTFKeyword::DODHGT: + m_aStates.top().getDrawingObject().setDhgt(nParam); + break; + case RTFKeyword::DPPOLYCOUNT: + if (nParam >= 0) + { + m_aStates.top().getDrawingObject().setPolyLineCount(nParam); + } + break; + case RTFKeyword::DPPTX: + { + RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject(); + + if (rDrawingObject.getPolyLinePoints().empty()) + dispatchValue(RTFKeyword::DPPOLYCOUNT, 2); + + rDrawingObject.getPolyLinePoints().emplace_back(convertTwipToMm100(nParam), 0); + } + break; + case RTFKeyword::DPPTY: + { + RTFDrawingObject& rDrawingObject = m_aStates.top().getDrawingObject(); + if (!rDrawingObject.getPolyLinePoints().empty()) + { + rDrawingObject.getPolyLinePoints().back().Y = convertTwipToMm100(nParam); + rDrawingObject.setPolyLineCount(rDrawingObject.getPolyLineCount() - 1); + if (rDrawingObject.getPolyLineCount() == 0 && rDrawingObject.getPropertySet().is()) + { + uno::Sequence<uno::Sequence<awt::Point>> aPointSequenceSequence + = { comphelper::containerToSequence(rDrawingObject.getPolyLinePoints()) }; + rDrawingObject.getPropertySet()->setPropertyValue( + "PolyPolygon", uno::Any(aPointSequenceSequence)); + } + } + } + break; + case RTFKeyword::SHPFBLWTXT: + // Shape is below text -> send it to the background. + m_aStates.top().getShape().setInBackground(nParam != 0); + break; + case RTFKeyword::FI: + { + if (m_aStates.top().getDestination() == Destination::LISTLEVEL) + { + if (m_aStates.top().getLevelNumbersValid()) + putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_firstLine, pIntValue); + else + m_aInvalidListLevelFirstIndents[m_nListLevel] = nParam; + } + else + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_firstLine, pIntValue); + break; + } + case RTFKeyword::LI: + { + if (m_aStates.top().getDestination() == Destination::LISTLEVEL) + { + if (m_aStates.top().getLevelNumbersValid()) + putNestedAttribute(m_aStates.top().getTableSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_left, pIntValue); + } + else + { + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_left, pIntValue); + } + // It turns out \li should reset the \fi inherited from the stylesheet. + // So set the direct formatting to zero, if we don't have such direct formatting yet. + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_firstLine, new RTFValue(0), + RTFOverwrite::NO_IGNORE); + } + break; + case RTFKeyword::RI: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_right, pIntValue); + break; + case RTFKeyword::LIN: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_start, pIntValue); + break; + case RTFKeyword::RIN: + putNestedAttribute(m_aStates.top().getParagraphSprms(), NS_ooxml::LN_CT_PPrBase_ind, + NS_ooxml::LN_CT_Ind_end, pIntValue); + break; + case RTFKeyword::OUTLINELEVEL: + m_aStates.top().getParagraphSprms().set(NS_ooxml::LN_CT_PPrBase_outlineLvl, pIntValue); + break; + case RTFKeyword::PROPTYPE: + { + switch (nParam) + { + case 3: + m_aStates.top().setPropType(cppu::UnoType<sal_Int32>::get()); + break; + case 5: + m_aStates.top().setPropType(cppu::UnoType<double>::get()); + break; + case 11: + m_aStates.top().setPropType(cppu::UnoType<bool>::get()); + break; + case 30: + m_aStates.top().setPropType(cppu::UnoType<OUString>::get()); + break; + case 64: + m_aStates.top().setPropType(cppu::UnoType<util::DateTime>::get()); + break; + } + } + break; + case RTFKeyword::DIBITMAP: + m_aStates.top().getPicture().eStyle = RTFBmpStyle::DIBITMAP; + break; + case RTFKeyword::TRWWIDTHA: + m_aStates.top().setTableRowWidthAfter(nParam); + break; + case RTFKeyword::ANIMTEXT: + { + Id nId = 0; + switch (nParam) + { + case 0: + nId = NS_ooxml::LN_Value_ST_TextEffect_none; + break; + case 2: + nId = NS_ooxml::LN_Value_ST_TextEffect_blinkBackground; + break; + } + + if (nId > 0) + m_aStates.top().getCharacterSprms().set(NS_ooxml::LN_EG_RPrBase_effect, + new RTFValue(nId)); + break; + } + case RTFKeyword::VIEWBKSP: + { + m_aSettingsTableSprms.set(NS_ooxml::LN_CT_Settings_displayBackgroundShape, pIntValue); + // Send this token immediately, if it only appears before the first + // run, it will be too late, we ignored the background shape already by then. + outputSettingsTable(); + break; + } + case RTFKeyword::STEXTFLOW: + { + Id nId = 0; + switch (nParam) + { + case 0: + nId = NS_ooxml::LN_Value_ST_TextDirection_lrTb; + break; + case 1: + nId = NS_ooxml::LN_Value_ST_TextDirection_tbRl; + break; + } + + if (nId > 0) + { + m_aStates.top().getSectionSprms().set(NS_ooxml::LN_EG_SectPrContents_textDirection, + new RTFValue(nId)); + } + } + break; + case RTFKeyword::LBR: + { + Id nId = 0; + switch (nParam) + { + case 1: + nId = NS_ooxml::LN_Value_ST_BrClear_left; + break; + case 2: + nId = NS_ooxml::LN_Value_ST_BrClear_right; + break; + case 3: + nId = NS_ooxml::LN_Value_ST_BrClear_all; + break; + } + + if (nId > 0) + { + m_aStates.top().getCharacterAttributes().set(NS_ooxml::LN_CT_Br_clear, + new RTFValue(nId)); + } + } + break; + case RTFKeyword::PGBRDROPT: + { + sal_Int16 nOffsetFrom = (nParam & 0xe0) >> 5; + bool bFromEdge = nOffsetFrom == 1; + if (bFromEdge) + { + Id nId = NS_ooxml::LN_Value_doc_ST_PageBorderOffset_page; + putNestedAttribute(m_aStates.top().getSectionSprms(), + NS_ooxml::LN_EG_SectPrContents_pgBorders, + NS_ooxml::LN_CT_PageBorders_offsetFrom, new RTFValue(nId)); + } + } + break; + default: + { + SAL_INFO("writerfilter", "TODO handle value '" << keywordToString(nKeyword) << "'"); + aSkip.setParsed(false); + } + break; + } + return RTFError::OK; +} + +} // namespace rtftok +} // namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |