/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.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 #include #include #include #include #include #include #include #include #include #include "rtfcharsets.hxx" #include "rtffly.hxx" #include "rtfreferenceproperties.hxx" #include "rtfskipdestination.hxx" #include #include 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 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 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(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 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(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 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::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 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 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(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 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(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 is 0-based, RTF is 1-based. auto pStart = tools::make_ref(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> 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::get()); break; case 5: m_aStates.top().setPropType(cppu::UnoType::get()); break; case 11: m_aStates.top().setPropType(cppu::UnoType::get()); break; case 30: m_aStates.top().setPropType(cppu::UnoType::get()); break; case 64: m_aStates.top().setPropType(cppu::UnoType::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: */