diff options
author | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-05-09 09:13:25 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2016-05-09 15:29:09 +0000 |
commit | a3615d5517ee84ddf9a9b2c28ff6a3a37fcb70db (patch) | |
tree | 6f3db784e5696a2ca8b4896512059c1d5a5cec94 /writerfilter/source/rtftok/rtfdispatchsymbol.cxx | |
parent | a75aa73b2bf793faac1adb3b5f67e09d252d5fe9 (diff) |
writerfilter: extract dispatch{destination,flag,symbol,value} from rtfdocimpl
These were half of the lines of rtfdocumentimpl.
Change-Id: I3f24cd5d23c91bf0d53b898266c187699ae6ee56
Reviewed-on: https://gerrit.libreoffice.org/24790
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'writerfilter/source/rtftok/rtfdispatchsymbol.cxx')
-rw-r--r-- | writerfilter/source/rtftok/rtfdispatchsymbol.cxx | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/writerfilter/source/rtftok/rtfdispatchsymbol.cxx b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx new file mode 100644 index 000000000000..98aa43d6bb9a --- /dev/null +++ b/writerfilter/source/rtftok/rtfdispatchsymbol.cxx @@ -0,0 +1,409 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 <svl/lngmisc.hxx> + +#include <ooxml/resourceids.hxx> + +#include <rtfreferenceproperties.hxx> +#include <rtfskipdestination.hxx> + +using namespace com::sun::star; + +namespace writerfilter +{ +namespace rtftok +{ + +RTFError RTFDocumentImpl::dispatchSymbol(RTFKeyword nKeyword) +{ + setNeedSect(true); + if (nKeyword != RTF_HEXCHAR) + checkUnicode(/*bUnicode =*/ true, /*bHex =*/ true); + else + checkUnicode(/*bUnicode =*/ true, /*bHex =*/ false); + RTFSkipDestination aSkip(*this); + + if (RTF_LINE == nKeyword) + { + // very special handling since text() will eat lone '\n' + singleChar('\n'); + return RTFError::OK; + } + // Trivial symbols + sal_uInt8 cCh = 0; + switch (nKeyword) + { + case RTF_TAB: + cCh = '\t'; + break; + case RTF_BACKSLASH: + cCh = '\\'; + break; + case RTF_LBRACE: + cCh = '{'; + break; + case RTF_RBRACE: + cCh = '}'; + break; + case RTF_EMDASH: + cCh = 151; + break; + case RTF_ENDASH: + cCh = 150; + break; + case RTF_BULLET: + cCh = 149; + break; + case RTF_LQUOTE: + cCh = 145; + break; + case RTF_RQUOTE: + cCh = 146; + break; + case RTF_LDBLQUOTE: + cCh = 147; + break; + case RTF_RDBLQUOTE: + cCh = 148; + break; + default: + break; + } + if (cCh > 0) + { + OUString aStr(OStringToOUString(OString(cCh), RTL_TEXTENCODING_MS_1252)); + text(aStr); + return RTFError::OK; + } + + switch (nKeyword) + { + case RTF_IGNORE: + { + m_bSkipUnknown = true; + aSkip.setReset(false); + return RTFError::OK; + } + break; + case RTF_PAR: + { + if (m_aStates.top().eDestination == Destination::FOOTNOTESEPARATOR) + break; // just ignore it - only thing we read in here is CHFTNSEP + checkFirstRun(); + bool bNeedPap = m_bNeedPap; + checkNeedPap(); + if (bNeedPap) + runProps(); + if (!m_aStates.top().pCurrentBuffer) + { + parBreak(); + // Not in table? Reset max width. + if (m_nCellxMax) + { + // Was in table, but not anymore -> tblEnd. + RTFSprms aAttributes; + RTFSprms aSprms; + aSprms.set(NS_ooxml::LN_tblEnd, std::make_shared<RTFValue>(1)); + writerfilter::Reference<Properties>::Pointer_t pProperties = std::make_shared<RTFReferenceProperties>(aAttributes, aSprms); + Mapper().props(pProperties); + } + m_nCellxMax = 0; + } + else if (m_aStates.top().eDestination != Destination::SHAPETEXT) + { + RTFValue::Pointer_t pValue; + m_aStates.top().pCurrentBuffer->push_back( + Buf_t(BUFFER_PAR, pValue, nullptr)); + } + // but don't emit properties yet, since they may change till the first text token arrives + m_bNeedPap = true; + if (!m_aStates.top().aFrame.inFrame()) + m_bNeedPar = false; + m_bNeedFinalPar = false; + } + break; + case RTF_SECT: + { + m_bHadSect = true; + if (m_bIgnoreNextContSectBreak) + m_bIgnoreNextContSectBreak = false; + else + { + sectBreak(); + if (m_nResetBreakOnSectBreak != RTF_invalid) + { + // this should run on _second_ \sect after \page + dispatchSymbol(m_nResetBreakOnSectBreak); // lazy reset + m_nResetBreakOnSectBreak = RTF_invalid; + m_bNeedSect = false; // dispatchSymbol set it + } + } + } + break; + case RTF_NOBREAK: + { + OUString aStr(SVT_HARD_SPACE); + text(aStr); + } + break; + case RTF_NOBRKHYPH: + { + OUString aStr(SVT_HARD_HYPHEN); + text(aStr); + } + break; + case RTF_OPTHYPH: + { + OUString aStr(SVT_SOFT_HYPHEN); + text(aStr); + } + break; + case RTF_HEXCHAR: + m_aStates.top().nInternalState = RTFInternalState::HEX; + break; + case RTF_CELL: + case RTF_NESTCELL: + { + checkFirstRun(); + if (m_bNeedPap) + { + // There were no runs in the cell, so we need to send paragraph and character properties here. + auto pPValue = std::make_shared<RTFValue>(m_aStates.top().aParagraphAttributes, m_aStates.top().aParagraphSprms); + m_aTableBufferStack.back().push_back(Buf_t(BUFFER_PROPS, pPValue, nullptr)); + auto pCValue = std::make_shared<RTFValue>(m_aStates.top().aCharacterAttributes, m_aStates.top().aCharacterSprms); + m_aTableBufferStack.back().push_back(Buf_t(BUFFER_PROPS, pCValue, nullptr)); + } + + RTFValue::Pointer_t pValue; + m_aTableBufferStack.back().push_back(Buf_t(BUFFER_CELLEND, pValue, nullptr)); + m_bNeedPap = true; + } + break; + case RTF_NESTROW: + { + std::shared_ptr<TableRowBuffer> const pBuffer( + new TableRowBuffer( + m_aTableBufferStack.back(), + m_aNestedTableCellsSprms, + m_aNestedTableCellsAttributes, + m_nNestedCells)); + prepareProperties(m_aStates.top(), + pBuffer->pParaProperties, + pBuffer->pFrameProperties, + pBuffer->pRowProperties, + m_nNestedCells, m_nNestedCurrentCellX); + + assert(m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back()); + if (m_aTableBufferStack.size() == 1) + { + throw io::WrongFormatException( + "mismatch between \\itap and number of \\nestrow", nullptr); + } + // note: there may be several states pointing to table buffer! + for (std::size_t i = 0; i < m_aStates.size(); ++i) + { + if (m_aStates[i].pCurrentBuffer == &m_aTableBufferStack.back()) + { + m_aStates[i].pCurrentBuffer = + &m_aTableBufferStack[m_aTableBufferStack.size()-2]; + } + } + m_aTableBufferStack.pop_back(); + m_aTableBufferStack.back().push_back( + Buf_t(BUFFER_NESTROW, RTFValue::Pointer_t(), pBuffer)); + + m_aNestedTableCellsSprms.clear(); + m_aNestedTableCellsAttributes.clear(); + m_nNestedCells = 0; + m_bNeedPap = true; + } + break; + case RTF_ROW: + { + bool bRestored = false; + // Ending a row, but no cells defined? + // See if there was an invalid table row reset, so we can restore cell infos to help invalid documents. + if (!m_nTopLevelCurrentCellX && m_nBackupTopLevelCurrentCellX) + { + restoreTableRowProperties(); + bRestored = true; + } + + // If the right edge of the last cell (row width) is smaller than the width of some other row, mimic WW8TabDesc::CalcDefaults(): resize the last cell + const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames. + if ((m_nCellxMax - m_nTopLevelCurrentCellX) >= MINLAY) + { + auto pXValueLast = m_aStates.top().aTableRowSprms.find(NS_ooxml::LN_CT_TblGridBase_gridCol, false); + auto pXValue = std::make_shared<RTFValue>(pXValueLast->getInt() + m_nCellxMax - m_nTopLevelCurrentCellX); + m_aStates.top().aTableRowSprms.eraseLast(NS_ooxml::LN_CT_TblGridBase_gridCol); + m_aStates.top().aTableRowSprms.set(NS_ooxml::LN_CT_TblGridBase_gridCol, pXValue, RTFOverwrite::NO_APPEND); + m_nTopLevelCurrentCellX = m_nCellxMax; + } + + if (m_nTopLevelCells) + { + // Make a backup before we start popping elements + m_aTableInheritingCellsSprms = m_aTopLevelTableCellsSprms; + m_aTableInheritingCellsAttributes = m_aTopLevelTableCellsAttributes; + m_nInheritingCells = m_nTopLevelCells; + } + else + { + // No table definition? Then inherit from the previous row + m_aTopLevelTableCellsSprms = m_aTableInheritingCellsSprms; + m_aTopLevelTableCellsAttributes = m_aTableInheritingCellsAttributes; + m_nTopLevelCells = m_nInheritingCells; + } + + while (m_aTableBufferStack.size() > 1) + { + SAL_WARN("writerfilter.rtf", "dropping extra table buffer"); + // note: there may be several states pointing to table buffer! + for (std::size_t i = 0; i < m_aStates.size(); ++i) + { + if (m_aStates[i].pCurrentBuffer == &m_aTableBufferStack.back()) + { + m_aStates[i].pCurrentBuffer = + &m_aTableBufferStack.front(); + } + } + m_aTableBufferStack.pop_back(); + } + + replayRowBuffer(m_aTableBufferStack.back(), + m_aTopLevelTableCellsSprms, m_aTopLevelTableCellsAttributes, + m_nTopLevelCells); + + m_aStates.top().aTableCellSprms = m_aDefaultState.aTableCellSprms; + m_aStates.top().aTableCellAttributes = m_aDefaultState.aTableCellAttributes; + + writerfilter::Reference<Properties>::Pointer_t paraProperties; + writerfilter::Reference<Properties>::Pointer_t frameProperties; + writerfilter::Reference<Properties>::Pointer_t rowProperties; + prepareProperties(m_aStates.top(), + paraProperties, frameProperties, rowProperties, + m_nTopLevelCells, m_nTopLevelCurrentCellX); + sendProperties(paraProperties, frameProperties, rowProperties); + + m_bNeedPap = true; + m_bNeedFinalPar = true; + m_aTableBufferStack.back().clear(); + m_nTopLevelCells = 0; + + if (bRestored) + // We restored cell definitions, clear these now. + // This is necessary, as later cell definitions want to overwrite the restored ones. + resetTableRowProperties(); + } + break; + case RTF_COLUMN: + { + bool bColumns = false; // If we have multiple columns + RTFValue::Pointer_t pCols = m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_cols); + if (pCols.get()) + { + RTFValue::Pointer_t pNum = pCols->getAttributes().find(NS_ooxml::LN_CT_Columns_num); + if (pNum.get() && pNum->getInt() > 1) + bColumns = true; + } + checkFirstRun(); + if (bColumns) + { + sal_uInt8 sBreak[] = { 0xe }; + Mapper().startCharacterGroup(); + Mapper().text(sBreak, 1); + Mapper().endCharacterGroup(); + } + else + dispatchSymbol(RTF_PAGE); + } + break; + case RTF_CHFTN: + { + if (m_aStates.top().pCurrentBuffer == &m_aSuperBuffer) + // Stop buffering, there will be no custom mark for this footnote or endnote. + m_aStates.top().pCurrentBuffer = nullptr; + break; + } + case RTF_PAGE: + { + // Ignore page breaks inside tables. + if (m_aStates.top().pCurrentBuffer == &m_aTableBufferStack.back()) + break; + + // If we're inside a continuous section, we should send a section break, not a page one. + RTFValue::Pointer_t pBreak = m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_type); + // Unless we're on a title page. + RTFValue::Pointer_t pTitlePg = m_aStates.top().aSectionSprms.find(NS_ooxml::LN_EG_SectPrContents_titlePg); + if (((pBreak.get() && pBreak->getInt() == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous)) + || m_nResetBreakOnSectBreak == RTF_SBKNONE) + && !(pTitlePg.get() && pTitlePg->getInt())) + { + if (m_bWasInFrame) + { + dispatchSymbol(RTF_PAR); + m_bWasInFrame = false; + } + sectBreak(); + // note: this will not affect the following section break + // but the one just pushed + dispatchFlag(RTF_SBKPAGE); + if (m_bNeedPar) + dispatchSymbol(RTF_PAR); + m_bIgnoreNextContSectBreak = true; + // arrange to clean up the synthetic RTF_SBKPAGE + m_nResetBreakOnSectBreak = RTF_SBKNONE; + } + else + { + checkFirstRun(); + checkNeedPap(); + sal_uInt8 sBreak[] = { 0xc }; + Mapper().text(sBreak, 1); + if (!m_bNeedPap) + { + parBreak(); + m_bNeedPap = true; + } + m_bNeedCr = true; + } + } + break; + case RTF_CHPGN: + { + OUString aStr("PAGE"); + singleChar(cFieldStart); + text(aStr); + singleChar(cFieldSep, true); + singleChar(cFieldEnd); + } + break; + case RTF_CHFTNSEP: + { + static const sal_Unicode uFtnEdnSep = 0x3; + Mapper().utext(reinterpret_cast<const sal_uInt8*>(&uFtnEdnSep), 1); + } + break; + default: + { + SAL_INFO("writerfilter", "TODO handle symbol '" << keywordToString(nKeyword) << "'"); + aSkip.setParsed(false); + } + break; + } + return RTFError::OK; +} + +} // namespace rtftok +} // namespace writerfilter + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |