summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/ww8/ww8par6.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/ww8/ww8par6.cxx')
-rw-r--r--sw/source/filter/ww8/ww8par6.cxx6208
1 files changed, 6208 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx
new file mode 100644
index 000000000..96059da34
--- /dev/null
+++ b/sw/source/filter/ww8/ww8par6.cxx
@@ -0,0 +1,6208 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <stdlib.h>
+#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <svl/itemiter.hxx>
+#include <svl/grabbagitem.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+
+#include <hintids.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/cmapitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/spltitem.hxx>
+#include <editeng/keepitem.hxx>
+#include <editeng/orphitem.hxx>
+#include <editeng/widwitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/tstpitem.hxx>
+#include <editeng/autokernitem.hxx>
+#include <editeng/paperinf.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/twolinesitem.hxx>
+#include <editeng/charscaleitem.hxx>
+#include <editeng/charrotateitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/blinkitem.hxx>
+#include <editeng/hyphenzoneitem.hxx>
+#include <editeng/paravertalignitem.hxx>
+#include <editeng/pgrditem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/charhiddenitem.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include "sortedarray.hxx"
+#include "sprmids.hxx"
+#include <node.hxx>
+#include <ndtxt.hxx>
+#include <pam.hxx>
+#include <doc.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <pagedesc.hxx>
+#include <fmtanchr.hxx>
+#include <fmtcntnt.hxx>
+#include <fchrfmt.hxx>
+#include <fmthdft.hxx>
+#include <fmtclds.hxx>
+#include <fmtftntx.hxx>
+#include <frmatr.hxx>
+#include <section.hxx>
+#include <lineinfo.hxx>
+#include <fmtline.hxx>
+#include <txatbase.hxx>
+#include <fmtflcnt.hxx>
+#include <tgrditem.hxx>
+#include <hfspacingitem.hxx>
+#include <swtable.hxx>
+#include <fltini.hxx>
+#include "writerhelper.hxx"
+#include "writerwordglue.hxx"
+#include "ww8scan.hxx"
+#include "ww8par2.hxx"
+#include "ww8graf.hxx"
+
+#include <fmtwrapinfluenceonobjpos.hxx>
+
+using namespace sw::util;
+using namespace sw::types;
+using namespace ::com::sun::star;
+using namespace nsHdFtFlags;
+
+// various
+
+// WW default for horizontal borders: 2.5 cm
+constexpr auto MM_250 = o3tl::convert(25, o3tl::Length::mm, o3tl::Length::twip); // 1417
+// WW default for lower border: 2.0 cm
+constexpr auto MM_200 = o3tl::convert(20, o3tl::Length::mm, o3tl::Length::twip); // 1134
+
+
+static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
+ const WW8RStyle* pSty = nullptr, const WW8PLCFx_SEPX* pSep = nullptr);
+
+Color SwWW8ImplReader::GetCol(sal_uInt8 nIco)
+{
+ static const Color eSwWW8ColA[] =
+ {
+ COL_AUTO, COL_BLACK, COL_LIGHTBLUE, COL_LIGHTCYAN, COL_LIGHTGREEN,
+ COL_LIGHTMAGENTA, COL_LIGHTRED, COL_YELLOW, COL_WHITE, COL_BLUE,
+ COL_CYAN, COL_GREEN, COL_MAGENTA, COL_RED, COL_BROWN, COL_GRAY,
+ COL_LIGHTGRAY
+ };
+ SAL_WARN_IF(
+ nIco >= SAL_N_ELEMENTS(eSwWW8ColA), "sw.ww8",
+ "ico " << sal_uInt32(nIco) << " >= " << SAL_N_ELEMENTS(eSwWW8ColA));
+ return nIco < SAL_N_ELEMENTS(eSwWW8ColA) ? eSwWW8ColA[nIco] : COL_AUTO;
+}
+
+static sal_uInt32 MSRoundTweak(sal_uInt32 x)
+{
+ return x;
+}
+
+// page attribute which are not handled via the attribute management but
+// using ...->HasSprm
+// (except OLST which stays a normal attribute)
+static short ReadSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
+{
+ SprmResult aRes = pSep->HasSprm(nId); // sprm here?
+ const sal_uInt8* pS = aRes.pSprm;
+ short nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToInt16(pS) : nDefaultVal;
+ return nVal;
+}
+
+static sal_uInt16 ReadUSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, short nDefaultVal )
+{
+ SprmResult aRes = pSep->HasSprm(nId); // sprm here?
+ const sal_uInt8* pS = aRes.pSprm;
+ sal_uInt16 nVal = (pS && aRes.nRemainingData >= 2) ? SVBT16ToUInt16(pS) : nDefaultVal;
+ return nVal;
+}
+
+static sal_uInt8 ReadBSprm( const WW8PLCFx_SEPX* pSep, sal_uInt16 nId, sal_uInt8 nDefaultVal )
+{
+ SprmResult aRes = pSep->HasSprm(nId); // sprm here?
+ const sal_uInt8* pS = aRes.pSprm;
+ sal_uInt8 nVal = (pS && aRes.nRemainingData >= 1) ? *pS : nDefaultVal;
+ return nVal;
+}
+
+void wwSection::SetDirection()
+{
+ //sprmSTextFlow
+ switch (maSep.wTextFlow)
+ {
+ default:
+ OSL_ENSURE(false, "Unknown layout type");
+ [[fallthrough]];
+ case 0:
+ meDir=SvxFrameDirection::Horizontal_LR_TB;
+ break;
+ case 1:
+ meDir=SvxFrameDirection::Vertical_RL_TB;
+ break;
+ case 2:
+ //asian letters are not rotated, western are. We can't import
+ //bottom to top going left to right, we can't do this in
+ //pages, (in drawboxes we could partly hack it with a rotated
+ //drawing box, though not frame)
+ meDir=SvxFrameDirection::Vertical_RL_TB;
+ break;
+ case 3:
+ //asian letters are not rotated, western are. We can't import
+ meDir=SvxFrameDirection::Vertical_RL_TB;
+ break;
+ case 4:
+ //asian letters are rotated, western not. We can't import
+ meDir=SvxFrameDirection::Horizontal_LR_TB;
+ break;
+ }
+
+ sal_uInt8 bRTLPgn = maSep.fBiDi;
+ if ((meDir == SvxFrameDirection::Horizontal_LR_TB) && bRTLPgn)
+ meDir = SvxFrameDirection::Horizontal_RL_TB;
+}
+
+bool wwSection::IsVertical() const
+{
+ return meDir == SvxFrameDirection::Vertical_RL_TB || meDir == SvxFrameDirection::Vertical_LR_TB;
+}
+
+/*
+ This is something of festering mapping, I'm open to better ways of doing it,
+ but primarily the grid in writer is different to that in word. In writer the
+ grid elements are squares with ruby rows inbetween. While in word there is no
+ ruby stuff, and the elements are rectangles. By misusing the ruby row I can
+ handle distortions in one direction, but its all a bit of a mess:
+*/
+void SwWW8ImplReader::SetDocumentGrid(SwFrameFormat &rFormat, const wwSection &rSection)
+{
+ if (m_bVer67)
+ return;
+
+ rFormat.SetFormatAttr(SvxFrameDirectionItem(rSection.meDir, RES_FRAMEDIR));
+
+ SwTwips nTextareaHeight = rFormat.GetFrameSize().GetHeight();
+ const SvxULSpaceItem &rUL = rFormat.GetFormatAttr(RES_UL_SPACE);
+ nTextareaHeight -= rUL.GetUpper();
+ nTextareaHeight -= rUL.GetLower();
+
+ SwTwips nTextareaWidth = rFormat.GetFrameSize().GetWidth();
+ const SvxLRSpaceItem &rLR = rFormat.GetFormatAttr(RES_LR_SPACE);
+ nTextareaWidth -= rLR.GetLeft();
+ nTextareaWidth -= rLR.GetRight();
+
+ if (rSection.IsVertical())
+ std::swap(nTextareaHeight, nTextareaWidth);
+
+ SwTextGridItem aGrid;
+ aGrid.SetDisplayGrid(false);
+ aGrid.SetPrintGrid(false);
+ SwTextGrid eType=GRID_NONE;
+
+ switch (rSection.maSep.clm)
+ {
+ case 0:
+ eType = GRID_NONE;
+ break;
+ default:
+ OSL_ENSURE(false, "Unknown grid type");
+ [[fallthrough]];
+ case 3:
+ eType = GRID_LINES_CHARS;
+ aGrid.SetSnapToChars(true);
+ break;
+ case 1:
+ eType = GRID_LINES_CHARS;
+ aGrid.SetSnapToChars(false);
+ break;
+ case 2:
+ eType = GRID_LINES_ONLY;
+ break;
+ }
+
+ aGrid.SetGridType(eType);
+
+ // seem to not add external leading in word, or the character would run across
+ // two line in some cases.
+ if (eType != GRID_NONE)
+ m_rDoc.getIDocumentSettingAccess().set(DocumentSettingId::ADD_EXT_LEADING, false);
+
+ //force to set document as standard page mode
+ bool bSquaredMode = false;
+ m_rDoc.SetDefaultPageMode( bSquaredMode );
+ aGrid.SetSquaredMode( bSquaredMode );
+
+ //Get the size of word's default styles font
+ sal_uInt32 nCharWidth=240;
+ for (sal_uInt16 nI = 0; nI < m_xStyles->GetCount(); ++nI)
+ {
+ if (m_vColl[nI].m_bValid && m_vColl[nI].m_pFormat &&
+ m_vColl[nI].IsWW8BuiltInDefaultStyle())
+ {
+ const SvxFontHeightItem& rFontHeightItem =
+ m_vColl[nI].m_pFormat->GetFormatAttr(RES_CHRATR_CJK_FONTSIZE);
+ nCharWidth = rFontHeightItem.GetHeight();
+ break;
+ }
+ }
+
+ //dxtCharSpace
+ if (rSection.maSep.dxtCharSpace)
+ {
+ sal_uInt32 nCharSpace = rSection.maSep.dxtCharSpace;
+ //main lives in top 20 bits, and is signed.
+ sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
+ nMain/=0x1000;
+ nCharWidth += nMain*20;
+
+ int nFraction = (nCharSpace & 0x00000FFF);
+ nFraction = (nFraction*20)/0xFFF;
+ nCharWidth += nFraction;
+ }
+
+ aGrid.SetBaseWidth( writer_cast<sal_uInt16>(nCharWidth));
+
+ //sep.dyaLinePitch
+ sal_Int32 nLinePitch = rSection.maSep.dyaLinePitch;
+ if (nLinePitch >= 1 && nLinePitch <= 31680)
+ {
+ aGrid.SetLines(writer_cast<sal_uInt16>(nTextareaHeight/nLinePitch));
+ aGrid.SetBaseHeight(writer_cast<sal_uInt16>(nLinePitch));
+ }
+
+ aGrid.SetRubyHeight(0);
+
+ rFormat.SetFormatAttr(aGrid);
+}
+
+void SwWW8ImplReader::SetRelativeJustify( bool bRel )
+{
+ if ( m_pCurrentColl && StyleExists(m_nCurrentColl) ) // importing style
+ m_vColl[m_nCurrentColl].m_nRelativeJustify = bRel ? 1 : 0;
+ else if ( m_xPlcxMan && m_xPlcxMan->GetPap() ) // importing paragraph
+ m_xPlcxMan->GetPap()->nRelativeJustify = bRel ? 1 : 0;
+}
+
+bool SwWW8ImplReader::IsRelativeJustify()
+{
+ bool bRet = m_xWwFib->GetFIBVersion() >= ww::eWW8;
+ if ( bRet )
+ {
+ // if relativeJustify is undefined (-1), then check the parent style.
+ if ( m_pCurrentColl && StyleExists(m_nCurrentColl) )
+ {
+ sal_Int16 nRelative = m_vColl[m_nCurrentColl].m_nRelativeJustify;
+ if ( nRelative < 0 && m_nCurrentColl )
+ {
+ o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
+ bRet = IsRelativeJustify(m_vColl[m_nCurrentColl].m_nBase, aVisitedStyles);
+ }
+ else
+ bRet = nRelative > 0;
+ }
+ else if ( m_xPlcxMan && m_xPlcxMan->GetPap() )
+ {
+ sal_Int16 nRelative = m_xPlcxMan->GetPap()->nRelativeJustify;
+ if ( nRelative < 0 )
+ {
+ o3tl::sorted_vector<sal_uInt16> aVisitedStyles;
+ bRet = IsRelativeJustify(m_nCurrentColl, aVisitedStyles);
+ }
+ else
+ bRet = nRelative > 0;
+ }
+ }
+
+ return bRet;
+}
+
+bool SwWW8ImplReader::IsRelativeJustify(sal_uInt16 nColl, o3tl::sorted_vector<sal_uInt16>& rVisitedStyles)
+{
+ assert( m_xWwFib->GetFIBVersion() >= ww::eWW8
+ && "pointless to search styles if relative justify is impossible");
+ bool bRet = true;
+ if ( StyleExists(nColl) )
+ {
+ rVisitedStyles.insert(nColl);
+ // if relativeJustify is undefined (-1), then check the parent style.
+ sal_Int16 nRelative = m_vColl[nColl].m_nRelativeJustify;
+ if ( nColl == 0 || nRelative >= 0 )
+ bRet = nRelative > 0;
+ else if (rVisitedStyles.find(m_vColl[nColl].m_nBase) == rVisitedStyles.end()) // detect loop in chain
+ bRet = IsRelativeJustify(m_vColl[nColl].m_nBase, rVisitedStyles);
+ }
+
+ return bRet;
+}
+
+void SwWW8ImplReader::Read_ParaBiDi(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_FRAMEDIR);
+ else
+ {
+ SvxFrameDirection eDir =
+ *pData ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB;
+
+ // In eWW8+, justify can be absolute, or relative to BiDi
+ bool bBiDiSwap = IsRelativeJustify();
+ if ( bBiDiSwap )
+ {
+ // Only change if ParaBiDi doesn't match previous setting.
+ const bool bParentRTL = IsRightToLeft();
+ bBiDiSwap = (eDir == SvxFrameDirection::Horizontal_RL_TB && !bParentRTL)
+ || (eDir == SvxFrameDirection::Horizontal_LR_TB && bParentRTL);
+ }
+
+ if ( bBiDiSwap )
+ {
+ const SvxAdjustItem* pItem = static_cast<const SvxAdjustItem*>(GetFormatAttr(RES_PARATR_ADJUST));
+ if ( !pItem )
+ {
+ // no previous adjust: set appropriate default
+ if ( eDir == SvxFrameDirection::Horizontal_LR_TB )
+ NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
+ else
+ NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
+ }
+ else
+ {
+ // previous adjust and bidi has changed: swap Left/Right
+ const SvxAdjust eJustify = pItem->GetAdjust();
+ if ( eJustify == SvxAdjust::Left )
+ NewAttr( SvxAdjustItem( SvxAdjust::Right, RES_PARATR_ADJUST ) );
+ else if ( eJustify == SvxAdjust::Right )
+ NewAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
+ }
+ }
+
+ NewAttr(SvxFrameDirectionItem(eDir, RES_FRAMEDIR));
+
+ if ( m_pCurrentColl && m_xStyles ) // in style definition
+ m_xStyles->mbBidiChanged = true;
+ }
+}
+
+bool wwSectionManager::SetCols(SwFrameFormat &rFormat, const wwSection &rSection,
+ sal_uInt32 nNetWidth)
+{
+ //sprmSCcolumns - number of columns - 1
+ const sal_Int16 nCols = rSection.NoCols();
+
+ if (nCols < 2) //check for no columns or other weird state
+ return false;
+
+ const sal_uInt16 nNetWriterWidth = writer_cast<sal_uInt16>(nNetWidth);
+ if (nNetWriterWidth == 0)
+ return false;
+
+ SwFormatCol aCol; // Create SwFormatCol
+
+ //sprmSDxaColumns - Default distance is 1.25 cm
+ sal_Int32 nColSpace = rSection.StandardColSeparation();
+
+ const SEPr& rSep = rSection.maSep;
+
+ // sprmSLBetween
+ if (rSep.fLBetween)
+ {
+ aCol.SetLineAdj(COLADJ_TOP); // Line
+ aCol.SetLineHeight(100);
+ aCol.SetLineColor(COL_BLACK);
+ aCol.SetLineWidth(1);
+ }
+
+ aCol.Init(nCols, writer_cast<sal_uInt16>(nColSpace), nNetWriterWidth);
+
+ // sprmSFEvenlySpaced
+ if (!rSep.fEvenlySpaced)
+ {
+ aCol.SetOrtho_(false);
+ const sal_uInt16 maxIdx = SAL_N_ELEMENTS(rSep.rgdxaColumnWidthSpacing);
+ for (sal_uInt16 i = 0, nIdx = 1; i < nCols && nIdx < maxIdx; i++, nIdx+=2 )
+ {
+ SwColumn* pCol = &aCol.GetColumns()[i];
+ const sal_Int32 nLeft = rSep.rgdxaColumnWidthSpacing[nIdx-1]/2;
+ const sal_Int32 nRight = rSep.rgdxaColumnWidthSpacing[nIdx+1]/2;
+ const sal_Int32 nWishWidth = rSep.rgdxaColumnWidthSpacing[nIdx]
+ + nLeft + nRight;
+ pCol->SetWishWidth(writer_cast<sal_uInt16>(nWishWidth));
+ pCol->SetLeft(writer_cast<sal_uInt16>(nLeft));
+ pCol->SetRight(writer_cast<sal_uInt16>(nRight));
+ }
+ aCol.SetWishWidth(nNetWriterWidth);
+ }
+ rFormat.SetFormatAttr(aCol);
+ return true;
+}
+
+void wwSectionManager::SetLeftRight(wwSection &rSection)
+{
+ // 3. LR-Margin
+ sal_uInt32 nWWLe = MSRoundTweak(rSection.maSep.dxaLeft);
+ sal_uInt32 nWWRi = MSRoundTweak(rSection.maSep.dxaRight);
+ sal_uInt32 nWWGu = rSection.maSep.dzaGutter;
+
+ /*
+ fRTLGutter is set if the gutter is on the right, the gutter is otherwise
+ placed on the left unless the global dop options are to put it on top, that
+ case is handled in GetPageULData.
+ */
+ if (rSection.maSep.fRTLGutter)
+ {
+ rSection.m_bRtlGutter = true;
+ }
+
+ // Left / Right
+ if ((rSection.m_nPgWidth - nWWLe - nWWRi) < MINLAY)
+ {
+ /*
+ There are some label templates which are "broken", they specify
+ margins which make no sense e.g. Left 16.10cm, Right 16.10cm. So the
+ space left between the margins is less than 0 In word the left margin
+ is honoured and if the right margin would be past the left margin is
+ left at the left margin position.
+
+ Now this will work fine for importing, layout and exporting, *but* the
+ page layout dialog has a hardcoded minimum page width of 0.5cm so it
+ will report a different value than what is actually being used. i.e.
+ it will add up the values to give a wider page than is actually being
+ used.
+ */
+ nWWRi = rSection.m_nPgWidth - nWWLe - MINLAY;
+ }
+
+ rSection.m_nPgLeft = nWWLe;
+ rSection.m_nPgRight = nWWRi;
+ rSection.m_nPgGutter = nWWGu;
+}
+
+void wwSectionManager::SetPage(SwPageDesc &rInPageDesc, SwFrameFormat &rFormat,
+ const wwSection &rSection, bool bIgnoreCols)
+{
+ // 1. orientation
+ rInPageDesc.SetLandscape(rSection.IsLandScape());
+
+ // 2. paper size
+ SwFormatFrameSize aSz( rFormat.GetFrameSize() );
+ aSz.SetWidth(rSection.GetPageWidth());
+ aSz.SetHeight(SvxPaperInfo::GetSloppyPaperDimension(rSection.GetPageHeight()));
+ rFormat.SetFormatAttr(aSz);
+
+ SvxLRSpaceItem aLR(rSection.GetPageLeft(), rSection.GetPageRight(), 0, 0, RES_LR_SPACE);
+ aLR.SetGutterMargin(rSection.m_nPgGutter);
+ rFormat.SetFormatAttr(aLR);
+
+ SfxBoolItem aRtlGutter(RES_RTL_GUTTER, rSection.m_bRtlGutter);
+ rFormat.SetFormatAttr(aRtlGutter);
+
+ if (!bIgnoreCols)
+ SetCols(rFormat, rSection, rSection.GetTextAreaWidth());
+}
+
+namespace {
+// Returns corrected (ODF) margin size
+tools::Long SetBorderDistance(bool bFromEdge, SvxBoxItem& aBox, SvxBoxItemLine eLine, tools::Long nMSMargin)
+{
+ const editeng::SvxBorderLine* pLine = aBox.GetLine(eLine);
+ if (!pLine)
+ return nMSMargin;
+ sal_Int32 nNewMargin = nMSMargin;
+ sal_Int32 nNewDist = aBox.GetDistance(eLine);
+ sal_Int32 nLineWidth = pLine->GetScaledWidth();
+
+ editeng::BorderDistanceFromWord(bFromEdge, nNewMargin, nNewDist, nLineWidth);
+ aBox.SetDistance(nNewDist, eLine);
+
+ return nNewMargin;
+}
+}
+
+void SwWW8ImplReader::SetPageBorder(SwFrameFormat &rFormat, const wwSection &rSection)
+{
+ if (!IsBorder(rSection.m_brc))
+ return;
+
+ SfxItemSet aSet(rFormat.GetAttrSet());
+ short aSizeArray[5]={0};
+ SetFlyBordersShadow(aSet, rSection.m_brc, &aSizeArray[0]);
+ SvxLRSpaceItem aLR(aSet.Get(RES_LR_SPACE));
+ SvxULSpaceItem aUL(aSet.Get(RES_UL_SPACE));
+ SvxBoxItem aBox(aSet.Get(RES_BOX));
+ bool bFromEdge = rSection.maSep.pgbOffsetFrom == 1;
+
+ aLR.SetLeft(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::LEFT, aLR.GetLeft()));
+ aLR.SetRight(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::RIGHT, aLR.GetRight()));
+ aUL.SetUpper(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::TOP, aUL.GetUpper()));
+ aUL.SetLower(SetBorderDistance(bFromEdge, aBox, SvxBoxItemLine::BOTTOM, aUL.GetLower()));
+
+ aSet.Put(aBox);
+ aSet.Put(aLR);
+ aSet.Put(aUL);
+ rFormat.SetFormatAttr(aSet);
+}
+
+void wwSectionManager::GetPageULData(const wwSection &rSection,
+ wwSectionManager::wwULSpaceData& rData) const
+{
+ sal_Int32 nWWUp = rSection.maSep.dyaTop;
+ sal_Int32 nWWLo = rSection.maSep.dyaBottom;
+ sal_uInt32 nWWHTop = rSection.maSep.dyaHdrTop;
+ sal_uInt32 nWWFBot = rSection.maSep.dyaHdrBottom;
+
+ /*
+ If there is gutter in 97+ and the dop says put it on top then get the
+ gutter distance and set it to the top margin. When we are "two pages
+ in one" the gutter is put at the top of odd pages, and bottom of
+ even pages, something we cannot do. So we will put it on top of all
+ pages, that way the pages are at least the right size.
+ */
+ if (!mrReader.m_bVer67 && mrReader.m_xWDop->iGutterPos &&
+ rSection.maSep.fRTLGutter)
+ {
+ nWWUp += rSection.maSep.dzaGutter;
+ }
+
+ /* Check whether this section has headers / footers */
+ sal_uInt16 nHeaderMask = WW8_HEADER_EVEN | WW8_HEADER_ODD;
+ sal_uInt16 nFooterMask = WW8_FOOTER_EVEN | WW8_FOOTER_ODD;
+ /* Ignore the presence of a first-page header/footer unless it is enabled */
+ if( rSection.HasTitlePage() )
+ {
+ nHeaderMask |= WW8_HEADER_FIRST;
+ nFooterMask |= WW8_FOOTER_FIRST;
+ }
+ rData.bHasHeader = (rSection.maSep.grpfIhdt & nHeaderMask) != 0;
+ rData.bHasFooter = (rSection.maSep.grpfIhdt & nFooterMask) != 0;
+
+ if( rData.bHasHeader )
+ {
+ rData.nSwUp = nWWHTop; // Header -> convert
+ // #i19922# - correction:
+ // consider that <nWWUp> can be negative, compare only if it's positive
+ if ( nWWUp > 0 &&
+ o3tl::make_unsigned(nWWUp) >= nWWHTop )
+ rData.nSwHLo = nWWUp - nWWHTop;
+ else
+ rData.nSwHLo = 0;
+
+ // #i19922# - minimum page header height is now 1mm
+ // use new constant <cMinHdFtHeight>
+ if (rData.nSwHLo < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
+ rData.nSwHLo = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
+ }
+ else // no header -> just use Up as-is
+ rData.nSwUp = std::abs(nWWUp);
+
+ if( rData.bHasFooter )
+ {
+ rData.nSwLo = nWWFBot; // footer -> convert
+ // #i19922# - correction: consider that <nWWLo> can be negative, compare only if it's positive
+ if ( nWWLo > 0 &&
+ o3tl::make_unsigned(nWWLo) >= nWWFBot )
+ rData.nSwFUp = nWWLo - nWWFBot;
+ else
+ rData.nSwFUp = 0;
+
+ // #i19922# - minimum page header height is now 1mm
+ // use new constant <cMinHdFtHeight>
+ if (rData.nSwFUp < sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight))
+ rData.nSwFUp = sal::static_int_cast< sal_uInt32 >(cMinHdFtHeight);
+ }
+ else // no footer -> just use Lo as-is
+ rData.nSwLo = std::abs(nWWLo);
+}
+
+void wwSectionManager::SetPageULSpaceItems(SwFrameFormat &rFormat,
+ wwSectionManager::wwULSpaceData const & rData, const wwSection &rSection)
+{
+ if (rData.bHasHeader) // ... and set Header-Lower
+ {
+ // set header height to minimum
+ if (SwFrameFormat* pHdFormat = const_cast<SwFrameFormat*>(rFormat.GetHeader().GetHeaderFormat()))
+ {
+ SvxULSpaceItem aHdUL(pHdFormat->GetULSpace());
+ if (!rSection.IsFixedHeightHeader()) //normal
+ {
+ pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwHLo));
+ // #i19922# - minimum page header height is now 1mm
+ // use new constant <cMinHdFtHeight>
+ aHdUL.SetLower( writer_cast<sal_uInt16>(rData.nSwHLo - cMinHdFtHeight) );
+ pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
+ RES_HEADER_FOOTER_EAT_SPACING, true));
+ }
+ else
+ {
+ // Hack alert: these calculations are based on
+ // #112727# import negative height headers/footers as floating frames inside fixed height headers/footer
+ // #i48832# - set correct spacing between header and body.
+ const sal_Int32 nHdLowerSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaTop) - rData.nSwUp - rData.nSwHLo));
+ pHdFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwHLo + nHdLowerSpace));
+ aHdUL.SetLower( static_cast< sal_uInt16 >(nHdLowerSpace) );
+ pHdFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
+ RES_HEADER_FOOTER_EAT_SPACING, false));
+ }
+ pHdFormat->SetFormatAttr(aHdUL);
+ }
+ }
+
+ if (rData.bHasFooter) // ... and set footer-upper
+ {
+ if (SwFrameFormat* pFtFormat = const_cast<SwFrameFormat*>(rFormat.GetFooter().GetFooterFormat()))
+ {
+ SvxULSpaceItem aFtUL(pFtFormat->GetULSpace());
+ if (!rSection.IsFixedHeightFooter()) //normal
+ {
+ pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Minimum, 0, rData.nSwFUp));
+ // #i19922# - minimum page header height is now 1mm
+ // use new constant <cMinHdFtHeight>
+ aFtUL.SetUpper( writer_cast<sal_uInt16>(rData.nSwFUp - cMinHdFtHeight) );
+ pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
+ RES_HEADER_FOOTER_EAT_SPACING, true));
+ }
+ else
+ {
+ // #i48832# - set correct spacing between footer and body.
+ const sal_Int32 nFtUpperSpace(std::max<sal_Int32>(0, std::abs(rSection.maSep.dyaBottom) - rData.nSwLo - rData.nSwFUp));
+ pFtFormat->SetFormatAttr(SwFormatFrameSize(SwFrameSize::Fixed, 0, rData.nSwFUp + nFtUpperSpace));
+ aFtUL.SetUpper( static_cast< sal_uInt16 >(nFtUpperSpace) );
+ pFtFormat->SetFormatAttr(SwHeaderAndFooterEatSpacingItem(
+ RES_HEADER_FOOTER_EAT_SPACING, false));
+ }
+ pFtFormat->SetFormatAttr(aFtUL);
+ }
+ }
+
+ SvxULSpaceItem aUL(writer_cast<sal_uInt16>(rData.nSwUp),
+ writer_cast<sal_uInt16>(rData.nSwLo), RES_UL_SPACE);
+ rFormat.SetFormatAttr(aUL);
+}
+
+SwSectionFormat *wwSectionManager::InsertSection(
+ SwPaM const & rMyPaM, wwSection &rSection)
+{
+ SwSectionData aSection( SectionType::Content,
+ mrReader.m_rDoc.GetUniqueSectionName() );
+
+ SfxItemSet aSet( mrReader.m_rDoc.GetAttrPool(), aFrameFormatSetRange );
+
+ bool bRTLPgn = !maSegments.empty() && maSegments.back().IsBiDi();
+ aSet.Put(SvxFrameDirectionItem(
+ bRTLPgn ? SvxFrameDirection::Horizontal_RL_TB : SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
+
+ if (2 == mrReader.m_xWDop->fpc)
+ aSet.Put( SwFormatFootnoteAtTextEnd(FTNEND_ATTXTEND));
+ if (0 == mrReader.m_xWDop->epc)
+ aSet.Put( SwFormatEndAtTextEnd(FTNEND_ATTXTEND));
+
+ aSection.SetProtectFlag(SectionIsProtected(rSection));
+
+ rSection.mpSection =
+ mrReader.m_rDoc.InsertSwSection( rMyPaM, aSection, nullptr, & aSet );
+ OSL_ENSURE(rSection.mpSection, "section not inserted!");
+ if (!rSection.mpSection)
+ return nullptr;
+
+ SwPageDesc *pPage = nullptr;
+ auto aIter = std::find_if(maSegments.rbegin(), maSegments.rend(),
+ [](const wwSection& rSegment) { return rSegment.mpPage != nullptr; });
+ if (aIter != maSegments.rend())
+ pPage = aIter->mpPage;
+
+ OSL_ENSURE(pPage, "no page outside this section!");
+
+ if (!pPage)
+ pPage = &mrReader.m_rDoc.GetPageDesc(0);
+
+ SwSectionFormat *pFormat = rSection.mpSection->GetFormat();
+ OSL_ENSURE(pFormat, "impossible");
+ if (!pFormat)
+ return nullptr;
+
+ SwFrameFormat& rFormat = pPage->GetMaster();
+ const SvxLRSpaceItem& rLR = rFormat.GetLRSpace();
+ tools::Long nPageLeft = rLR.GetLeft();
+ tools::Long nPageRight = rLR.GetRight();
+ tools::Long nSectionLeft = rSection.GetPageLeft() - nPageLeft;
+ tools::Long nSectionRight = rSection.GetPageRight() - nPageRight;
+ if ((nSectionLeft != 0) || (nSectionRight != 0))
+ {
+ SvxLRSpaceItem aLR(nSectionLeft, nSectionRight, 0, 0, RES_LR_SPACE);
+ pFormat->SetFormatAttr(aLR);
+ }
+
+ SetCols(*pFormat, rSection, rSection.GetTextAreaWidth());
+ return pFormat;
+}
+
+void SwWW8ImplReader::HandleLineNumbering(const wwSection &rSection)
+{
+ // check if Line Numbering must be activated or reset
+ if (!(m_bNewDoc && rSection.maSep.nLnnMod))
+ return;
+
+ // restart-numbering-mode: 0 per page, 1 per section, 2 never restart
+ bool bRestartLnNumPerSection = (1 == rSection.maSep.lnc);
+
+ if (m_bNoLnNumYet)
+ {
+ SwLineNumberInfo aInfo( m_rDoc.GetLineNumberInfo() );
+
+ aInfo.SetPaintLineNumbers(true);
+
+ aInfo.SetRestartEachPage(rSection.maSep.lnc == 0);
+
+ // A value of 0 (auto) indicates that the application MUST automatically determine positioning.
+ if ( rSection.maSep.dxaLnn )
+ aInfo.SetPosFromLeft(writer_cast<sal_uInt16>(rSection.maSep.dxaLnn));
+
+ //Paint only for every n line
+ aInfo.SetCountBy(rSection.maSep.nLnnMod);
+
+ // to be defaulted features ( HARDCODED in MS Word 6,7,8,9 )
+ aInfo.SetCountBlankLines(true);
+ aInfo.SetCountInFlys(false);
+ aInfo.SetPos( LINENUMBER_POS_LEFT );
+ SvxNumberType aNumType; // this sets SVX_NUM_ARABIC per default
+ aInfo.SetNumType( aNumType );
+
+ m_rDoc.SetLineNumberInfo( aInfo );
+ m_bNoLnNumYet = false;
+ }
+
+ if ((0 < rSection.maSep.lnnMin) || bRestartLnNumPerSection)
+ {
+ SwFormatLineNumber aLN;
+ if (const SwFormatLineNumber* pLN
+ = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
+ {
+ aLN.SetCountLines( pLN->IsCount() );
+ }
+ aLN.SetStartValue(1 + rSection.maSep.lnnMin);
+ NewAttr(aLN);
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LINENUMBER);
+ }
+}
+
+wwSection::wwSection(const SwPosition &rPos) : maStart(rPos.nNode)
+ , mpSection(nullptr)
+ , mpPage(nullptr)
+ , meDir(SvxFrameDirection::Horizontal_LR_TB)
+ , m_nPgWidth(SvxPaperInfo::GetPaperSize(PAPER_A4).Width())
+ , m_nPgLeft(MM_250)
+ , m_nPgRight(MM_250)
+ , m_nPgGutter(0)
+ , mnVerticalAdjustment(drawing::TextVerticalAdjust_TOP)
+ , mnBorders(0)
+ , mbHasFootnote(false)
+{
+}
+
+void wwSectionManager::SetNumberingType(const wwSection &rNewSection,
+ SwPageDesc &rPageDesc)
+{
+ // save page number format
+ static const SvxNumType aNumTyp[5] =
+ {
+ SVX_NUM_ARABIC, SVX_NUM_ROMAN_UPPER, SVX_NUM_ROMAN_LOWER,
+ SVX_NUM_CHARS_UPPER_LETTER_N, SVX_NUM_CHARS_LOWER_LETTER_N
+ };
+
+ SvxNumberType aType;
+ aType.SetNumberingType( aNumTyp[rNewSection.maSep.nfcPgn] );
+ rPageDesc.SetNumType(aType);
+}
+
+// CreateSep is called for every section change (even at the start of
+// the document. CreateSep also creates the pagedesc(s) and
+// fills it/them with attributes and KF texts.
+// This has become necessary because the translation of the various
+// page attributes is interconnected too much.
+void wwSectionManager::CreateSep(const tools::Long nTextPos)
+{
+ /*
+ #i1909# section/page breaks should not occur in tables or subpage
+ elements like frames. Word itself ignores them in this case. The bug is
+ more likely that this filter created such documents in the past!
+ */
+ if (mrReader.m_nInTable || mrReader.m_bTxbxFlySection || mrReader.InLocalApo())
+ return;
+
+ WW8PLCFx_SEPX* pSep = mrReader.m_xPlcxMan->GetSepPLCF();
+ OSL_ENSURE(pSep, "impossible!");
+ if (!pSep)
+ return;
+
+ if (!maSegments.empty() && mrReader.m_pLastAnchorPos && *mrReader.m_pLastAnchorPos == *mrReader.m_pPaM->GetPoint())
+ {
+ bool insert = true;
+ SwPaM pam( *mrReader.m_pLastAnchorPos );
+ if( pam.Move(fnMoveBackward, GoInNode))
+ if( SwTextNode* txtNode = pam.GetPoint()->nNode.GetNode().GetTextNode())
+ if( txtNode->Len() == 0 )
+ insert = false;
+ if( insert )
+ mrReader.AppendTextNode(*mrReader.m_pPaM->GetPoint());
+ }
+
+ ww::WordVersion eVer = mrReader.GetFib().GetFIBVersion();
+
+ // M.M. Create a linked section if the WkbPLCF
+ // has an entry for one at this cp
+ WW8PLCFspecial* pWkb = mrReader.m_xPlcxMan->GetWkbPLCF();
+ if (pWkb && pWkb->SeekPosExact(nTextPos) &&
+ pWkb->Where() == nTextPos)
+ {
+ void* pData;
+ WW8_CP nTest;
+ bool bSuccess = pWkb->Get(nTest, pData);
+ if (!bSuccess)
+ return;
+ OUString sSectionName = mrReader.m_aLinkStringMap[SVBT16ToUInt16( static_cast<WW8_WKB*>(pData)->nLinkId) ];
+ sSectionName = mrReader.ConvertFFileName(sSectionName);
+ SwSectionData aSection(SectionType::FileLink, sSectionName);
+ aSection.SetLinkFileName( sSectionName );
+ aSection.SetProtectFlag(true);
+ // #i19922# - improvement: return value of method <Insert> not used.
+ mrReader.m_rDoc.InsertSwSection(*mrReader.m_pPaM, aSection, nullptr, nullptr, false);
+ }
+
+ wwSection aLastSection(*mrReader.m_pPaM->GetPoint());
+ if (!maSegments.empty())
+ aLastSection = maSegments.back();
+
+ //Here
+ sal_uInt16 nLIdx = ( ( static_cast<sal_uInt16>(mrReader.m_xWwFib->m_lid) & 0xff ) == 0x9 ) ? 1 : 0;
+
+ //BEGIN read section values
+ wwSection aNewSection(*mrReader.m_pPaM->GetPoint());
+
+ static const sal_uInt16 aVer2Ids0[] =
+ {
+ /*sprmSBkc*/ 117,
+ /*sprmSFTitlePage*/ 118,
+ /*sprmSNfcPgn*/ 122,
+ /*sprmSCcolumns*/ 119,
+ /*sprmSDxaColumns*/ 120,
+ /*sprmSLBetween*/ 133
+ };
+
+ static const sal_uInt16 aVer67Ids0[] =
+ {
+ NS_sprm::v6::sprmSBkc,
+ NS_sprm::v6::sprmSFTitlePage,
+ NS_sprm::v6::sprmSNfcPgn,
+ NS_sprm::v6::sprmSCcolumns,
+ NS_sprm::v6::sprmSDxaColumns,
+ NS_sprm::v6::sprmSLBetween
+ };
+
+ static const sal_uInt16 aVer8Ids0[] =
+ {
+ NS_sprm::SBkc::val,
+ NS_sprm::SFTitlePage::val,
+ NS_sprm::SNfcPgn::val,
+ NS_sprm::SCcolumns::val,
+ NS_sprm::SDxaColumns::val,
+ NS_sprm::SLBetween::val
+ };
+
+ const sal_uInt16* pIds = eVer <= ww::eWW2 ? aVer2Ids0 : eVer <= ww::eWW7 ? aVer67Ids0 : aVer8Ids0;
+
+ SprmResult aRes = pSep->HasSprm(pIds[0]);
+ const sal_uInt8* pSprmBkc = aRes.pSprm;
+ if (!maSegments.empty())
+ {
+ // Type of break: break codes are:
+ // 0 No break
+ // 1 New column
+ // 2 New page
+ // 3 Even page
+ // 4 Odd page
+ if (pSprmBkc && aRes.nRemainingData >= 1)
+ aNewSection.maSep.bkc = *pSprmBkc;
+ }
+
+ // Has a table page
+ aNewSection.maSep.fTitlePage =
+ sal_uInt8(0 != ReadBSprm( pSep, pIds[1], 0 ));
+
+ // sprmSNfcPgn
+ aNewSection.maSep.nfcPgn = ReadBSprm( pSep, pIds[2], 0 );
+ if (aNewSection.maSep.nfcPgn > 4)
+ aNewSection.maSep.nfcPgn = 0;
+
+ aNewSection.maSep.fUnlocked = eVer > ww::eWW2 ? ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFProtected : NS_sprm::SFProtected::val), 0 ) : 0;
+
+ // sprmSFBiDi
+ aNewSection.maSep.fBiDi = eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFBiDi::val, 0) : 0;
+
+ // Reading section property sprmSCcolumns - one less than the number of columns in the section.
+ // It must be less than MAX_NO_OF_SEP_COLUMNS according the WW8 specification.
+ aNewSection.maSep.ccolM1 = ReadSprm(pSep, pIds[3], 0 );
+ if ( aNewSection.maSep.ccolM1 >= MAX_NO_OF_SEP_COLUMNS )
+ {
+ // clip to max
+ aNewSection.maSep.ccolM1 = MAX_NO_OF_SEP_COLUMNS-1;
+ }
+
+ //sprmSDxaColumns - default distance 1.25 cm
+ aNewSection.maSep.dxaColumns = ReadUSprm( pSep, pIds[4], 708 );
+
+ // sprmSLBetween
+ aNewSection.maSep.fLBetween = ReadBSprm(pSep, pIds[5], 0 );
+
+ if (eVer >= ww::eWW6)
+ {
+ // sprmSFEvenlySpaced
+ aNewSection.maSep.fEvenlySpaced =
+ sal_uInt8(ReadBSprm(pSep, (eVer <= ww::eWW7 ? NS_sprm::v6::sprmSFEvenlySpaced : NS_sprm::SFEvenlySpaced::val), 1) != 0);
+
+ if (aNewSection.maSep.ccolM1 > 0 && !aNewSection.maSep.fEvenlySpaced)
+ {
+ int nColumnDataIdx = 0;
+ aNewSection.maSep.rgdxaColumnWidthSpacing[nColumnDataIdx] = 0;
+
+ const sal_uInt16 nColumnWidthSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColWidth : NS_sprm::SDxaColWidth::val);
+ const sal_uInt16 nColumnSpacingSprmId = ( eVer <= ww::eWW7 ? NS_sprm::v6::sprmSDxaColSpacing : NS_sprm::SDxaColSpacing::val);
+ const sal_uInt8 nColumnCount = static_cast< sal_uInt8 >(aNewSection.maSep.ccolM1 + 1);
+ for ( sal_uInt8 nColumn = 0; nColumn < nColumnCount; ++nColumn )
+ {
+ //sprmSDxaColWidth
+ SprmResult aSWRes = pSep->HasSprm(nColumnWidthSprmId, nColumn);
+ const sal_uInt8* pSW = aSWRes.pSprm;
+
+ OSL_ENSURE( pSW, "+Sprm 136 (resp. 0xF203) (ColWidth) missing" );
+ sal_uInt16 nWidth = (pSW && aSWRes.nRemainingData >= 3) ? SVBT16ToUInt16(pSW + 1) : 1440;
+
+ aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
+
+ if ( nColumn < nColumnCount - 1 )
+ {
+ //sprmSDxaColSpacing
+ SprmResult aSDRes = pSep->HasSprm(nColumnSpacingSprmId, nColumn);
+ const sal_uInt8* pSD = aSDRes.pSprm;
+
+ OSL_ENSURE( pSD, "+Sprm 137 (resp. 0xF204) (Colspacing) missing" );
+ if (pSD && aSDRes.nRemainingData >= 3)
+ {
+ nWidth = SVBT16ToUInt16(pSD + 1);
+ aNewSection.maSep.rgdxaColumnWidthSpacing[++nColumnDataIdx] = nWidth;
+ }
+ }
+ }
+ }
+ }
+
+ static const sal_uInt16 aVer2Ids1[] =
+ {
+ /*sprmSBOrientation*/ 137,
+ /*sprmSXaPage*/ 139,
+ /*sprmSYaPage*/ 140,
+ /*sprmSDxaLeft*/ 141,
+ /*sprmSDxaRight*/ 142,
+ /*sprmSDzaGutter*/ 145,
+ /*sprmSFPgnRestart*/ 125,
+ /*sprmSPgnStart*/ 136,
+ /*sprmSDmBinFirst*/ 115,
+ /*sprmSDmBinOther*/ 116
+ };
+
+ static const sal_uInt16 aVer67Ids1[] =
+ {
+ NS_sprm::v6::sprmSBOrientation,
+ NS_sprm::v6::sprmSXaPage,
+ NS_sprm::v6::sprmSYaPage,
+ NS_sprm::v6::sprmSDxaLeft,
+ NS_sprm::v6::sprmSDxaRight,
+ NS_sprm::v6::sprmSDzaGutter,
+ NS_sprm::v6::sprmSFPgnRestart,
+ NS_sprm::v6::sprmSPgnStart,
+ NS_sprm::v6::sprmSDmBinFirst,
+ NS_sprm::v6::sprmSDmBinOther
+ };
+
+ static const sal_uInt16 aVer8Ids1[] =
+ {
+ NS_sprm::SBOrientation::val,
+ NS_sprm::SXaPage::val,
+ NS_sprm::SYaPage::val,
+ NS_sprm::SDxaLeft::val,
+ NS_sprm::SDxaRight::val,
+ NS_sprm::SDzaGutter::val,
+ NS_sprm::SFPgnRestart::val,
+ NS_sprm::SPgnStart97::val,
+ NS_sprm::SDmBinFirst::val,
+ NS_sprm::SDmBinOther::val
+ };
+
+ pIds = eVer <= ww::eWW2 ? aVer2Ids1 : eVer <= ww::eWW7 ? aVer67Ids1 : aVer8Ids1;
+
+ // 1. orientation
+ aNewSection.maSep.dmOrientPage = ReadBSprm(pSep, pIds[0], 0);
+
+ // 2. paper size
+ aNewSection.maSep.xaPage = ReadUSprm(pSep, pIds[1], lLetterWidth);
+ aNewSection.m_nPgWidth = SvxPaperInfo::GetSloppyPaperDimension(aNewSection.maSep.xaPage);
+
+ aNewSection.maSep.yaPage = ReadUSprm(pSep, pIds[2], lLetterHeight);
+
+ // 3. LR borders
+ static const sal_uInt16 nLef[] = { MM_250, 1800 };
+ static const sal_uInt16 nRig[] = { MM_250, 1800 };
+
+ aNewSection.maSep.dxaLeft = ReadUSprm( pSep, pIds[3], nLef[nLIdx]);
+ aNewSection.maSep.dxaRight = ReadUSprm( pSep, pIds[4], nRig[nLIdx]);
+
+ // 2pages in 1sheet hackery ?
+ // #i31806# but only swap if 2page in 1sheet is enabled.
+ // it's not clear if dmOrientPage is the correct member to
+ // decide on this.
+ if(mrReader.m_xWDop->doptypography.m_f2on1 &&
+ aNewSection.maSep.dmOrientPage == 2)
+ std::swap(aNewSection.maSep.dxaLeft, aNewSection.maSep.dxaRight);
+
+ aNewSection.maSep.dzaGutter = ReadUSprm( pSep, pIds[5], 0);
+
+ aNewSection.maSep.fRTLGutter = static_cast<sal_uInt8>(
+ eVer >= ww::eWW8 ? ReadBSprm(pSep, NS_sprm::SFRTLGutter::val, 0) : 0);
+
+ // Page Number Restarts - sprmSFPgnRestart
+ aNewSection.maSep.fPgnRestart = ReadBSprm(pSep, pIds[6], 0);
+
+ aNewSection.maSep.pgnStart = ReadUSprm( pSep, pIds[7], 0 );
+
+ // if the document's first page number is unspecified, but it starts with an even page break,
+ // then set the first page number to two
+ if ( maSegments.empty() && !aNewSection.maSep.fPgnRestart && pSprmBkc && *pSprmBkc == 3 )
+ {
+ aNewSection.maSep.pgnStart = 2;
+ aNewSection.maSep.fPgnRestart = 1;
+ }
+
+ if (eVer >= ww::eWW6)
+ {
+ aRes = pSep->HasSprm(eVer <= ww::eWW7 ? NS_sprm::v6::sprmSiHeadingPgn : NS_sprm::SiHeadingPgn::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 1)
+ aNewSection.maSep.iHeadingPgn = *aRes.pSprm;
+
+ aRes = pSep->HasSprm(eVer <= ww::eWW7 ? NS_sprm::v6::sprmSScnsPgn : NS_sprm::ScnsPgn::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 1)
+ aNewSection.maSep.cnsPgn = *aRes.pSprm;
+ }
+
+ aRes = pSep->HasSprm(pIds[8]);
+ const sal_uInt8* pSprmSDmBinFirst = aRes.pSprm;
+ if (pSprmSDmBinFirst && aRes.nRemainingData >= 1)
+ aNewSection.maSep.dmBinFirst = *pSprmSDmBinFirst;
+
+ aRes = pSep->HasSprm(pIds[9]);
+ const sal_uInt8* pSprmSDmBinOther = aRes.pSprm;
+ if (pSprmSDmBinOther && aRes.nRemainingData >= 1)
+ aNewSection.maSep.dmBinOther = *pSprmSDmBinOther;
+
+ static const sal_uInt16 nTop[] = { MM_250, 1440 };
+ static const sal_uInt16 nBot[] = { MM_200, 1440 };
+
+ static const sal_uInt16 aVer2Ids2[] =
+ {
+ /*sprmSDyaTop*/ 143,
+ /*sprmSDyaBottom*/ 144,
+ /*sprmSDyaHdrTop*/ 131,
+ /*sprmSDyaHdrBottom*/ 132,
+ /*sprmSNLnnMod*/ 129,
+ /*sprmSLnc*/ 127,
+ /*sprmSDxaLnn*/ 130,
+ /*sprmSLnnMin*/ 135
+ };
+
+ static const sal_uInt16 aVer67Ids2[] =
+ {
+ NS_sprm::v6::sprmSDyaTop,
+ NS_sprm::v6::sprmSDyaBottom,
+ NS_sprm::v6::sprmSDyaHdrTop,
+ NS_sprm::v6::sprmSDyaHdrBottom,
+ NS_sprm::v6::sprmSNLnnMod,
+ NS_sprm::v6::sprmSLnc,
+ NS_sprm::v6::sprmSDxaLnn,
+ NS_sprm::v6::sprmSLnnMin
+ };
+ static const sal_uInt16 aVer8Ids2[] =
+ {
+ NS_sprm::SDyaTop::val,
+ NS_sprm::SDyaBottom::val,
+ NS_sprm::SDyaHdrTop::val,
+ NS_sprm::SDyaHdrBottom::val,
+ NS_sprm::SNLnnMod::val,
+ NS_sprm::SLnc::val,
+ NS_sprm::SDxaLnn::val,
+ NS_sprm::SLnnMin::val
+ };
+
+ pIds = eVer <= ww::eWW2 ? aVer2Ids2 : eVer <= ww::eWW7 ? aVer67Ids2 : aVer8Ids2;
+
+ aNewSection.maSep.dyaTop = ReadSprm( pSep, pIds[0], nTop[nLIdx] );
+ aNewSection.maSep.dyaBottom = ReadSprm( pSep, pIds[1], nBot[nLIdx] );
+ aNewSection.maSep.dyaHdrTop = ReadUSprm( pSep, pIds[2], 720 );
+ aNewSection.maSep.dyaHdrBottom = ReadUSprm( pSep, pIds[3], 720 );
+
+ if (eVer >= ww::eWW8)
+ {
+ aNewSection.maSep.wTextFlow = ReadUSprm(pSep, NS_sprm::STextFlow::val, 0);
+ aNewSection.maSep.clm = ReadUSprm( pSep, NS_sprm::SClm::val, 0 );
+ aNewSection.maSep.dyaLinePitch = ReadUSprm(pSep, NS_sprm::SDyaLinePitch::val, 360);
+ aRes = pSep->HasSprm(NS_sprm::SDxtCharSpace::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 4)
+ aNewSection.maSep.dxtCharSpace = SVBT32ToUInt32(aRes.pSprm);
+
+ //sprmSPgbProp
+ sal_uInt16 pgbProp = ReadSprm( pSep, NS_sprm::SPgbProp::val, 0 );
+ aNewSection.maSep.pgbApplyTo = pgbProp & 0x0007;
+ aNewSection.maSep.pgbPageDepth = (pgbProp & 0x0018) >> 3;
+ aNewSection.maSep.pgbOffsetFrom = (pgbProp & 0x00E0) >> 5;
+
+ aNewSection.mnBorders = ::lcl_ReadBorders(false, aNewSection.m_brc, nullptr, nullptr, pSep);
+ }
+
+ // check if Line Numbering must be activated or reset
+ SprmResult aSprmSNLnnMod = pSep->HasSprm(pIds[4]);
+ if (aSprmSNLnnMod.pSprm && aSprmSNLnnMod.nRemainingData >= 1)
+ aNewSection.maSep.nLnnMod = *aSprmSNLnnMod.pSprm;
+
+ SprmResult aSprmSLnc = pSep->HasSprm(pIds[5]);
+ if (aSprmSLnc.pSprm && aSprmSLnc.nRemainingData >= 1)
+ aNewSection.maSep.lnc = *aSprmSLnc.pSprm;
+
+ SprmResult aSprmSDxaLnn = pSep->HasSprm(pIds[6]);
+ if (aSprmSDxaLnn.pSprm && aSprmSDxaLnn.nRemainingData >= 2)
+ aNewSection.maSep.dxaLnn = SVBT16ToUInt16(aSprmSDxaLnn.pSprm);
+
+ SprmResult aSprmSLnnMin = pSep->HasSprm(pIds[7]);
+ if (aSprmSLnnMin.pSprm && aSprmSLnnMin.nRemainingData >= 1)
+ aNewSection.maSep.lnnMin = *aSprmSLnnMin.pSprm;
+
+ if (eVer <= ww::eWW7)
+ aNewSection.maSep.grpfIhdt = ReadBSprm(pSep, eVer <= ww::eWW2 ? 128 : 153, 0);
+ else if (mrReader.m_xHdFt)
+ {
+ aNewSection.maSep.grpfIhdt = WW8_HEADER_ODD | WW8_FOOTER_ODD
+ | WW8_HEADER_FIRST | WW8_FOOTER_FIRST;
+
+ // It is possible for a first page header to be provided
+ // for this section, but not actually shown in this section. In this
+ // case (aNewSection.maSep.grpfIhdt & WW8_HEADER_FIRST) will be nonzero
+ // but aNewSection.HasTitlePage() will be false.
+ // Likewise for first page footer.
+
+ if (mrReader.m_xWDop->fFacingPages)
+ aNewSection.maSep.grpfIhdt |= WW8_HEADER_EVEN | WW8_FOOTER_EVEN;
+
+ //See if we have a header or footer for each enabled possibility
+ //if we do not then we inherit the previous sections header/footer,
+ for (int nI = 0, nMask = 1; nI < 6; ++nI, nMask <<= 1)
+ {
+ if (aNewSection.maSep.grpfIhdt & nMask)
+ {
+ WW8_CP nStart, nLen;
+ mrReader.m_xHdFt->GetTextPosExact( static_cast< short >(nI + ( maSegments.size() + 1) * 6), nStart, nLen);
+ //No header or footer, inherit previous one, or set to zero
+ //if no previous one
+ if (!nLen)
+ {
+ if (
+ maSegments.empty() ||
+ !(maSegments.back().maSep.grpfIhdt & nMask)
+ )
+ {
+ aNewSection.maSep.grpfIhdt &= ~nMask;
+ }
+ }
+ }
+ }
+ }
+
+ SetLeftRight(aNewSection);
+ //END read section values
+
+ if (eVer >= ww::eWW8)
+ aNewSection.SetDirection();
+
+ mrReader.HandleLineNumbering(aNewSection);
+ maSegments.push_back(aNewSection);
+}
+
+void SwWW8ImplReader::CopyPageDescHdFt(const SwPageDesc* pOrgPageDesc,
+ SwPageDesc* pNewPageDesc, sal_uInt8 nCode )
+{
+ // copy odd header content section
+ if( nCode & WW8_HEADER_ODD )
+ {
+ m_rDoc.CopyHeader(pOrgPageDesc->GetMaster(),
+ pNewPageDesc->GetMaster() );
+ }
+ // copy odd footer content section
+ if( nCode & WW8_FOOTER_ODD )
+ {
+ m_rDoc.CopyFooter(pOrgPageDesc->GetMaster(),
+ pNewPageDesc->GetMaster());
+ }
+ // copy even header content section
+ if( nCode & WW8_HEADER_EVEN )
+ {
+ m_rDoc.CopyHeader(pOrgPageDesc->GetLeft(),
+ pNewPageDesc->GetLeft());
+ }
+ // copy even footer content section
+ if( nCode & WW8_FOOTER_EVEN )
+ {
+ m_rDoc.CopyFooter(pOrgPageDesc->GetLeft(),
+ pNewPageDesc->GetLeft());
+ }
+ // copy first page header content section
+ if( nCode & WW8_HEADER_FIRST )
+ {
+ m_rDoc.CopyHeader(pOrgPageDesc->GetFirstMaster(),
+ pNewPageDesc->GetFirstMaster());
+ }
+ // copy first page footer content section
+ if( nCode & WW8_FOOTER_FIRST )
+ {
+ m_rDoc.CopyFooter(pOrgPageDesc->GetFirstMaster(),
+ pNewPageDesc->GetFirstMaster());
+ }
+}
+
+// helper functions for graphics, Apos and tables
+
+// Read BoRder Control structure
+// nBrcVer should be set to the version of the BRC record being read (6, 8 or 9)
+// This will be converted to the latest format (9).
+static bool SetWW8_BRC(int nBrcVer, WW8_BRCVer9& rVar, const sal_uInt8* pS, size_t nLen)
+{
+
+ if( pS )
+ {
+ if (nBrcVer == 9 && nLen >= sizeof(WW8_BRCVer9))
+ rVar = *reinterpret_cast<const WW8_BRCVer9*>(pS);
+ else if (nBrcVer == 8 && nLen >= sizeof(WW8_BRC))
+ rVar = WW8_BRCVer9(*reinterpret_cast<const WW8_BRC*>(pS));
+ else if (nLen >= sizeof(WW8_BRCVer6)) // nBrcVer == 6
+ rVar = WW8_BRCVer9(WW8_BRC(*reinterpret_cast<const WW8_BRCVer6*>(pS)));
+ }
+
+ return nullptr != pS;
+}
+
+static sal_uInt8 lcl_ReadBorders(bool bVer67, WW8_BRCVer9* brc, WW8PLCFx_Cp_FKP* pPap,
+ const WW8RStyle* pSty, const WW8PLCFx_SEPX* pSep)
+{
+
+//returns a sal_uInt8 filled with a bit for each position that had a sprm
+//setting that border
+
+ sal_uInt8 nBorder = 0;
+ if( pSep )
+ {
+ if( !bVer67 )
+ {
+ SprmResult a8Sprm[4];
+ if (pSep->Find4Sprms(
+ NS_sprm::SBrcTop80::val, NS_sprm::SBrcLeft80::val,
+ NS_sprm::SBrcBottom80::val, NS_sprm::SBrcRight80::val,
+ a8Sprm[0], a8Sprm[1], a8Sprm[2], a8Sprm[3]))
+ {
+ for( int i = 0; i < 4; ++i )
+ nBorder |= int(SetWW8_BRC(8, brc[i], a8Sprm[i].pSprm, a8Sprm[i].nRemainingData))<<i;
+ }
+
+ // Version 9 BRCs if present will override version 8
+ SprmResult a9Sprm[4];
+ if (pSep->Find4Sprms(
+ NS_sprm::SBrcTop::val, NS_sprm::SBrcLeft::val,
+ NS_sprm::SBrcBottom::val, NS_sprm::SBrcRight::val,
+ a9Sprm[0], a9Sprm[1], a9Sprm[2], a9Sprm[3]))
+ {
+ for( int i = 0; i < 4; ++i )
+ nBorder |= int(SetWW8_BRC(9, brc[i], a9Sprm[i].pSprm, a9Sprm[i].nRemainingData))<<i;
+ }
+ }
+ }
+ else
+ {
+
+ static const sal_uInt16 aVer67Ids[5] = {
+ NS_sprm::v6::sprmPBrcTop,
+ NS_sprm::v6::sprmPBrcLeft,
+ NS_sprm::v6::sprmPBrcBottom,
+ NS_sprm::v6::sprmPBrcRight,
+ NS_sprm::v6::sprmPBrcBetween
+ };
+
+ static const sal_uInt16 aVer8Ids[5] = {
+ NS_sprm::PBrcTop80::val,
+ NS_sprm::PBrcLeft80::val,
+ NS_sprm::PBrcBottom80::val,
+ NS_sprm::PBrcRight80::val,
+ NS_sprm::PBrcBetween80::val
+ };
+
+ static const sal_uInt16 aVer9Ids[5] = {
+ NS_sprm::PBrcTop::val,
+ NS_sprm::PBrcLeft::val,
+ NS_sprm::PBrcBottom::val,
+ NS_sprm::PBrcRight::val,
+ NS_sprm::PBrcBetween::val
+ };
+
+ if( pPap )
+ {
+ if (bVer67)
+ {
+ for( int i = 0; i < 5; ++i )
+ {
+ SprmResult aRes(pPap->HasSprm(aVer67Ids[i]));
+ nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
+ }
+ }
+ else
+ {
+ for( int i = 0; i < 5; ++i )
+ {
+ SprmResult aRes(pPap->HasSprm(aVer8Ids[i]));
+ nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
+ }
+ // Version 9 BRCs if present will override version 8
+ for( int i = 0; i < 5; ++i )
+ {
+ SprmResult aRes(pPap->HasSprm(aVer9Ids[i]));
+ nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
+ }
+ }
+ }
+ else if( pSty )
+ {
+ if (bVer67)
+ {
+ for( int i = 0; i < 5; ++i )
+ {
+ SprmResult aRes(pSty->HasParaSprm(aVer67Ids[i]));
+ nBorder |= int(SetWW8_BRC(6 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
+ }
+ }
+ else
+ {
+ for( int i = 0; i < 5; ++i )
+ {
+ SprmResult aRes(pSty->HasParaSprm(aVer8Ids[i]));
+ nBorder |= int(SetWW8_BRC(8 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
+ }
+ // Version 9 BRCs if present will override version 8
+ for( int i = 0; i < 5; ++i )
+ {
+ SprmResult aRes(pSty->HasParaSprm(aVer9Ids[i]));
+ nBorder |= int(SetWW8_BRC(9 , brc[i], aRes.pSprm, aRes.nRemainingData))<<i;
+ }
+ }
+ }
+ else {
+ OSL_ENSURE( pSty || pPap, "WW8PLCFx_Cp_FKP and WW8RStyle "
+ "and WW8PLCFx_SEPX is 0" );
+ }
+ }
+
+ return nBorder;
+}
+
+static void GetLineIndex(SvxBoxItem &rBox, short nLineThickness, short nSpace,
+ sal_uInt32 cv, short nIdx, SvxBoxItemLine nOOIndex, sal_uInt16 nWWIndex,
+ short *pSize)
+{
+ // LO cannot handle outset/inset (new in WW9 BRC) so fall back same as WW8
+ if ( nIdx == 0x1A || nIdx == 0x1B )
+ {
+ nIdx = (nIdx == 0x1A) ? 0x12 : 0x11;
+ cv = 0xc0c0c0;
+ }
+
+ SvxBorderLineStyle const eStyle(
+ ::editeng::ConvertBorderStyleFromWord(nIdx));
+
+ ::editeng::SvxBorderLine aLine;
+ aLine.SetBorderLineStyle( eStyle );
+ double const fConverted( (SvxBorderLineStyle::NONE == eStyle) ? 0.0 :
+ ::editeng::ConvertBorderWidthFromWord(eStyle, nLineThickness, nIdx));
+ aLine.SetWidth(fConverted);
+
+ //No AUTO for borders as yet, so if AUTO, use BLACK
+ Color col = (cv==0xff000000) ? COL_BLACK : msfilter::util::BGRToRGB(cv);
+
+ aLine.SetColor(col);
+
+ if (pSize)
+ pSize[nWWIndex] = fConverted + nSpace;
+
+ rBox.SetLine(&aLine, nOOIndex);
+ rBox.SetDistance(nSpace, nOOIndex);
+
+}
+
+static void Set1Border(SvxBoxItem &rBox, const WW8_BRCVer9& rBor, SvxBoxItemLine nOOIndex,
+ sal_uInt16 nWWIndex, short *pSize, const bool bIgnoreSpace)
+{
+ short nSpace;
+ short nLineThickness = rBor.DetermineBorderProperties(&nSpace);
+
+ GetLineIndex(rBox, nLineThickness, bIgnoreSpace ? 0 : nSpace,
+ rBor.cv(), rBor.brcType(), nOOIndex, nWWIndex, pSize );
+
+}
+
+static bool lcl_IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn = false)
+{
+ return pbrc[WW8_TOP ].brcType() || // brcType != 0
+ pbrc[WW8_LEFT ].brcType() ||
+ pbrc[WW8_BOT ].brcType() ||
+ pbrc[WW8_RIGHT].brcType() ||
+ (bChkBtwn && pbrc[WW8_BETW ].brcType());
+}
+
+bool SwWW8ImplReader::IsBorder(const WW8_BRCVer9* pbrc, bool bChkBtwn)
+{
+ return lcl_IsBorder(pbrc, bChkBtwn);
+}
+
+bool SwWW8ImplReader::SetBorder(SvxBoxItem& rBox, const WW8_BRCVer9* pbrc,
+ short *pSizeArray, sal_uInt8 nSetBorders)
+{
+ bool bChange = false;
+ static const std::pair<sal_uInt16, SvxBoxItemLine> aIdArr[] =
+ {
+ { WW8_TOP, SvxBoxItemLine::TOP },
+ { WW8_LEFT, SvxBoxItemLine::LEFT },
+ { WW8_RIGHT, SvxBoxItemLine::RIGHT },
+ { WW8_BOT, SvxBoxItemLine::BOTTOM },
+ { WW8_BETW, SvxBoxItemLine::BOTTOM }
+ };
+
+ for( int i = 0; i < 4; ++i )
+ {
+ // filter out the invalid borders
+ const WW8_BRCVer9& rB = pbrc[ aIdArr[ i ].first ];
+ if( !rB.isNil() && rB.brcType() )
+ {
+ Set1Border(rBox, rB, aIdArr[i].second, aIdArr[i].first, pSizeArray, false);
+ bChange = true;
+ }
+ else if ( nSetBorders & (1 << aIdArr[i].first) )
+ {
+ /*
+ ##826##, ##653##
+
+ If a style has borders set,and the para attributes attempt remove
+ the borders, then this is perfectly acceptable, so we shouldn't
+ ignore this blank entry
+
+ nSetBorders has a bit set for each location that a sprm set a
+ border, so with a sprm set, but no border, then disable the
+ appropriate border
+ */
+ rBox.SetLine( nullptr, aIdArr[ i ].second );
+ }
+ }
+ return bChange;
+}
+
+bool SwWW8ImplReader::SetShadow(SvxShadowItem& rShadow, const short *pSizeArray,
+ const WW8_BRCVer9& aRightBrc)
+{
+ bool bRet = aRightBrc.fShadow() && pSizeArray && pSizeArray[WW8_RIGHT];
+ if (bRet)
+ {
+ rShadow.SetColor(COL_BLACK);
+ //i120718
+ short nVal = aRightBrc.DetermineBorderProperties();
+ //End
+ if (nVal < 0x10)
+ nVal = 0x10;
+ rShadow.SetWidth(nVal);
+ rShadow.SetLocation(SvxShadowLocation::BottomRight);
+ bRet = true;
+ }
+ return bRet;
+}
+
+void SwWW8ImplReader::GetBorderDistance(const WW8_BRCVer9* pbrc,
+ tools::Rectangle& rInnerDist)
+{
+ rInnerDist = tools::Rectangle( pbrc[ 1 ].dptSpace() * 20,
+ pbrc[ 0 ].dptSpace() * 20,
+ pbrc[ 3 ].dptSpace() * 20,
+ pbrc[ 2 ].dptSpace() * 20 );
+}
+
+bool SwWW8ImplReader::SetFlyBordersShadow(SfxItemSet& rFlySet,
+ const WW8_BRCVer9 *pbrc, short *pSizeArray)
+{
+ bool bShadowed = false;
+ if (IsBorder(pbrc))
+ {
+ SvxBoxItem aBox( RES_BOX );
+ SetBorder(aBox, pbrc, pSizeArray);
+
+ rFlySet.Put( aBox );
+
+ // fShadow
+ SvxShadowItem aShadow( RES_SHADOW );
+ if( SetShadow( aShadow, pSizeArray, pbrc[WW8_RIGHT] ))
+ {
+ bShadowed = true;
+ rFlySet.Put( aShadow );
+ }
+ }
+ return bShadowed;
+}
+
+// APOs
+
+ // for computing the minimal FrameSize
+#define MAX_BORDER_SIZE 210 // max. size of border
+#define MAX_EMPTY_BORDER 10 // for off-by-one errors, at least 1
+
+static void FlySecur1(short& rSize, const bool bBorder)
+{
+ short nMin = MINFLY +
+ (bBorder ? MAX_BORDER_SIZE : MAX_EMPTY_BORDER);
+
+ if ( rSize < nMin )
+ rSize = nMin;
+}
+
+static bool SetValSprm( sal_Int16* pVar, WW8PLCFx_Cp_FKP* pPap, sal_uInt16 nId )
+{
+ SprmResult aS = pPap->HasSprm(nId);
+ if (aS.pSprm && aS.nRemainingData >= 2)
+ *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
+ return aS.pSprm != nullptr;
+}
+
+static bool SetValSprm( sal_Int16* pVar, const WW8RStyle* pStyle, sal_uInt16 nId )
+{
+ SprmResult aS = pStyle->HasParaSprm(nId);
+ if (aS.pSprm && aS.nRemainingData >= 2)
+ *pVar = static_cast<sal_Int16>(SVBT16ToUInt16(aS.pSprm));
+ return aS.pSprm != nullptr;
+}
+
+/*
+#i1930 revealed that sprm 0x360D (sprmTPc) as used in tables can affect the frame
+around the table. Its full structure is not fully understood as yet.
+*/
+void WW8FlyPara::ApplyTabPos(const WW8_TablePos *pTabPos)
+{
+ if (pTabPos)
+ {
+ nSp26 = pTabPos->nSp26;
+ nSp27 = pTabPos->nSp27;
+ nSp29 = pTabPos->nSp29;
+ nLeMgn = pTabPos->nLeMgn;
+ nRiMgn = pTabPos->nRiMgn;
+ nUpMgn = pTabPos->nUpMgn;
+ nLoMgn = pTabPos->nLoMgn;
+ nSp37 = pTabPos->nSp37;
+ }
+}
+
+WW8FlyPara::WW8FlyPara(bool bIsVer67, const WW8FlyPara* pSrc /* = 0 */)
+{
+ if ( pSrc )
+ memcpy( this, pSrc, sizeof( WW8FlyPara ) ); // Copy-Ctor
+ else
+ {
+ nSp26 = 0;
+ nSp27 = 0;
+ nSp45 = 0;
+ nSp28 = 0;
+ nLeMgn = 0;
+ nRiMgn = 0;
+ nUpMgn = 0;
+ nLoMgn = 0;
+ nSp29 = 0;
+ nSp37 = 2; // Default: wrapping
+ bBorderLines = false;
+ bGrafApo = false;
+ mbVertSet = false;
+ }
+ bVer67 = bIsVer67;
+}
+
+bool WW8FlyPara::operator==(const WW8FlyPara& rSrc) const
+{
+ /*
+ Compare the parts that word seems to compare for equivalence.
+ Interestingly being autoheight or absolute height (the & 0x7fff) doesn't
+ matter to word
+ */
+ return
+ (
+ (nSp26 == rSrc.nSp26) &&
+ (nSp27 == rSrc.nSp27) &&
+ ((nSp45 & 0x7fff) == (rSrc.nSp45 & 0x7fff)) &&
+ (nSp28 == rSrc.nSp28) &&
+ (nLeMgn == rSrc.nLeMgn) &&
+ (nRiMgn == rSrc.nRiMgn) &&
+ (nUpMgn == rSrc.nUpMgn) &&
+ (nLoMgn == rSrc.nLoMgn) &&
+ (nSp29 == rSrc.nSp29) &&
+ (nSp37 == rSrc.nSp37)
+ );
+}
+
+// Read for normal text
+void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8PLCFx_Cp_FKP* pPap)
+{
+ if( bVer67 )
+ {
+ SetValSprm( &nSp26, pPap, 26 ); // X-position //sprmPDxaAbs
+ //set in me or in parent style
+ mbVertSet |= SetValSprm( &nSp27, pPap, 27 ); // Y-position //sprmPDyaAbs
+ SetValSprm( &nSp45, pPap, 45 ); // height //sprmPWHeightAbs
+ SetValSprm( &nSp28, pPap, 28 ); // width //sprmPDxaWidth
+ SetValSprm( &nLeMgn, pPap, 49 ); // L-border //sprmPDxaFromText
+ SetValSprm( &nRiMgn, pPap, 49 ); // R-border //sprmPDxaFromText
+ SetValSprm( &nUpMgn, pPap, 48 ); // U-border //sprmPDyaFromText
+ SetValSprm( &nLoMgn, pPap, 48 ); // D-border //sprmPDyaFromText
+
+ SprmResult aS = pPap->HasSprm(NS_sprm::v6::sprmPWr);
+ if (aS.pSprm && aS.nRemainingData >= 1)
+ nSp37 = *aS.pSprm;
+ }
+ else
+ {
+ SetValSprm( &nSp26, pPap, NS_sprm::PDxaAbs::val ); // X-position
+ //set in me or in parent style
+ mbVertSet |= SetValSprm( &nSp27, pPap, NS_sprm::PDyaAbs::val ); // Y-position
+ SetValSprm( &nSp45, pPap, NS_sprm::PWHeightAbs::val ); // height
+ SetValSprm( &nSp28, pPap, NS_sprm::PDxaWidth::val ); // width
+ SetValSprm( &nLeMgn, pPap, NS_sprm::PDxaFromText::val ); // L-border
+ SetValSprm( &nRiMgn, pPap, NS_sprm::PDxaFromText::val ); // R-border
+ SetValSprm( &nUpMgn, pPap, NS_sprm::PDyaFromText::val ); // U-border
+ SetValSprm( &nLoMgn, pPap, NS_sprm::PDyaFromText::val ); // D-border
+
+ SprmResult aS = pPap->HasSprm(NS_sprm::PWr::val); // wrapping
+ if (aS.pSprm && aS.nRemainingData >= 1)
+ nSp37 = *aS.pSprm;
+ }
+
+ if( ::lcl_ReadBorders( bVer67, brc, pPap )) // borders
+ bBorderLines = ::lcl_IsBorder( brc );
+
+ /*
+ #i8798#
+ Appears that with no dyaAbs set then the actual vert anchoring set is
+ ignored and we remain relative to text, so if that is the case we are 0
+ from para anchor, so we update the frame to have explicitly this type of
+ anchoring
+ */
+ if (!mbVertSet)
+ nSp29 = (nOrigSp29 & 0xCF) | 0x20;
+ else
+ nSp29 = nOrigSp29;
+}
+
+void WW8FlyPara::ReadFull(sal_uInt8 nOrigSp29, SwWW8ImplReader* pIo)
+{
+ std::shared_ptr<WW8PLCFMan> xPlcxMan = pIo->m_xPlcxMan;
+ WW8PLCFx_Cp_FKP* pPap = xPlcxMan->GetPapPLCF();
+
+ Read(nOrigSp29, pPap); // read Apo parameter
+
+ do{ // block for quick exit
+ if( nSp45 != 0 /* || nSp28 != 0 */ )
+ break; // bGrafApo only automatic for height
+ if( pIo->m_xWwFib->m_fComplex )
+ break; // (*pPap)++ does not work for FastSave
+ // -> for FastSave, no test for graphics APO
+ SvStream* pIoStrm = pIo->m_pStrm;
+ sal_uInt64 nPos = pIoStrm->Tell();
+ WW8PLCFxSave1 aSave;
+ xPlcxMan->GetPap()->Save( aSave );
+ bGrafApo = false;
+
+ do{ // block for quick exit
+ sal_uInt8 nText[2];
+
+ if (!checkRead(*pIoStrm, nText, 2)) // read text
+ break;
+
+ if( nText[0] != 0x01 || nText[1] != 0x0d )// only graphics + CR?
+ break; // no
+
+ pPap->advance(); // next line
+
+ // in APO ?
+ //sprmPPc
+ SprmResult aS = pPap->HasSprm( bVer67 ? NS_sprm::v6::sprmPPc : NS_sprm::PPc::val);
+
+ // no -> graphics Apo
+ if (!aS.pSprm || aS.nRemainingData < 1)
+ {
+ bGrafApo = true;
+ break; // end of APO
+ }
+
+ ww::WordVersion eVer = pIo->GetFib().GetFIBVersion();
+ WW8FlyPara *pNowStyleApo=nullptr;
+ sal_uInt16 nColl = pPap->GetIstd();
+
+ o3tl::sorted_vector<sal_uInt16> aSeenStyles;
+ ww::sti eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc(nColl) : static_cast<ww::sti>(nColl);
+ while (eSti != ww::stiNil && static_cast<size_t>(nColl) < pIo->m_vColl.size() && nullptr == (pNowStyleApo = pIo->m_vColl[nColl].m_xWWFly.get()))
+ {
+ aSeenStyles.insert(nColl);
+
+ nColl = pIo->m_vColl[nColl].m_nBase;
+
+ if (aSeenStyles.find(nColl) != aSeenStyles.end())
+ {
+ SAL_WARN("sw.ww8", "loop in style chain");
+ break;
+ }
+
+ eSti = eVer < ww::eWW6 ? ww::GetCanonicalStiFromStc(nColl) : static_cast<ww::sti>(nColl);
+ }
+
+ WW8FlyPara aF(bVer67, pNowStyleApo);
+ // new FlaPara for comparison
+ aF.Read(*aS.pSprm, pPap); // WWPara for new Para
+ if( !( aF == *this ) ) // same APO? (or a new one?)
+ bGrafApo = true; // no -> 1-line APO
+ // -> graphics APO
+ }
+ while( false ); // block for quick exit
+
+ xPlcxMan->GetPap()->Restore( aSave );
+ pIoStrm->Seek( nPos );
+ }while( false ); // block for quick exit
+}
+
+// read for Apo definitions in Styledefs
+void WW8FlyPara::Read(sal_uInt8 nOrigSp29, WW8RStyle const * pStyle)
+{
+ if (bVer67)
+ {
+ SetValSprm( &nSp26, pStyle, NS_sprm::v6::sprmPDxaAbs ); // X-position
+ //set in me or in parent style
+ mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::v6::sprmPDyaAbs); // Y-position
+ SetValSprm( &nSp45, pStyle, NS_sprm::v6::sprmPWHeightAbs ); // height
+ SetValSprm( &nSp28, pStyle, NS_sprm::v6::sprmPDxaWidth ); // width
+ SetValSprm( &nLeMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // L-border
+ SetValSprm( &nRiMgn, pStyle, NS_sprm::v6::sprmPDxaFromText ); // R-border
+ SetValSprm( &nUpMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // U-border
+ SetValSprm( &nLoMgn, pStyle, NS_sprm::v6::sprmPDyaFromText ); // D-border
+
+ SprmResult aS = pStyle->HasParaSprm( NS_sprm::v6::sprmPWr ); // wrapping
+ if (aS.pSprm && aS.nRemainingData >= 1)
+ nSp37 = *aS.pSprm;
+ }
+ else
+ {
+ SetValSprm( &nSp26, pStyle, NS_sprm::PDxaAbs::val ); // X-position
+ //set in me or in parent style
+ mbVertSet |= SetValSprm(&nSp27, pStyle, NS_sprm::PDyaAbs::val); // Y-position
+ SetValSprm( &nSp45, pStyle, NS_sprm::PWHeightAbs::val ); // height
+ SetValSprm( &nSp28, pStyle, NS_sprm::PDxaWidth::val ); // width
+ SetValSprm( &nLeMgn, pStyle, NS_sprm::PDxaFromText::val ); // L-border
+ SetValSprm( &nRiMgn, pStyle, NS_sprm::PDxaFromText::val ); // R-border
+ SetValSprm( &nUpMgn, pStyle, NS_sprm::PDyaFromText::val ); // U-border
+ SetValSprm( &nLoMgn, pStyle, NS_sprm::PDyaFromText::val ); // D-border
+
+ SprmResult aS = pStyle->HasParaSprm( NS_sprm::PWr::val ); // wrapping
+ if (aS.pSprm && aS.nRemainingData >= 1)
+ nSp37 = *aS.pSprm;
+ }
+
+ if (::lcl_ReadBorders(bVer67, brc, nullptr, pStyle)) // border
+ bBorderLines = ::lcl_IsBorder(brc);
+
+ /*
+ #i8798#
+ Appears that with no dyaAbs set then the actual vert anchoring set is
+ ignored and we remain relative to text, so if that is the case we are 0
+ from para anchor, so we update the frame to have explicitly this type of
+ anchoring
+ */
+ if (!mbVertSet)
+ nSp29 = (nOrigSp29 & 0xCF) | 0x20;
+ else
+ nSp29 = nOrigSp29;
+}
+
+bool WW8FlyPara::IsEmpty() const
+{
+ WW8FlyPara aEmpty(bVer67);
+ /*
+ wr of 0 like 2 appears to me to be equivalent for checking here. See
+ #107103# if wrong, so given that the empty is 2, if we are 0 then set
+ empty to 0 to make 0 equiv to 2 for empty checking
+ */
+ OSL_ENSURE(aEmpty.nSp37 == 2, "this is not what we expect for nSp37");
+ if (this->nSp37 == 0)
+ aEmpty.nSp37 = 0;
+ return aEmpty == *this;
+}
+
+// #i18732# - changes made on behalf of CMC
+WW8SwFlyPara::WW8SwFlyPara( SwPaM& rPaM,
+ SwWW8ImplReader& rIo,
+ WW8FlyPara& rWW,
+ const sal_uInt32 nWWPgTop,
+ const sal_uInt32 nPgWidth,
+ const sal_Int32 nIniFlyDx,
+ const sal_Int32 nIniFlyDy ):
+nXPos(0),
+nYPos(0),
+nLeMgn(rWW.nLeMgn),
+nRiMgn(rWW.nRiMgn),
+nUpMgn(rWW.nUpMgn),
+nLoMgn(rWW.nLoMgn),
+nWidth(rWW.nSp28),
+nHeight(rWW.nSp45),
+nNetWidth(rWW.nSp28),
+eHeightFix(SwFrameSize::Fixed),
+eHRel(text::RelOrientation::PAGE_FRAME),
+eVRel(text::RelOrientation::FRAME),
+eVAlign(text::VertOrientation::NONE),
+eHAlign(text::HoriOrientation::NONE),
+eSurround(( rWW.nSp37 > 1 ) ? css::text::WrapTextMode_DYNAMIC : css::text::WrapTextMode_NONE),
+nXBind(( rWW.nSp29 & 0xc0 ) >> 6),
+nYBind(( rWW.nSp29 & 0x30 ) >> 4),
+nNewNetWidth(MINFLY),
+nLineSpace(0),
+bAutoWidth(false),
+bTogglePos(false)
+{
+ //#i119466 mapping "Around" wrap setting to "Parallel" for table
+ const bool bIsTable = rIo.m_xPlcxMan->HasParaSprm(NS_sprm::PFInTable::val).pSprm;
+ if (bIsTable && rWW.nSp37 == 2)
+ eSurround = css::text::WrapTextMode_PARALLEL;
+
+ /*
+ #95905#, #83307# seems to have gone away now, so re-enable parallel
+ wrapping support for frames in headers/footers. I don't know if we truly
+ have an explicitly specified behaviour for these circumstances.
+ */
+
+ if( nHeight & 0x8000 )
+ {
+ nHeight &= 0x7fff;
+ eHeightFix = SwFrameSize::Minimum;
+ }
+
+ if( nHeight <= MINFLY )
+ { // no data, or bad data
+ eHeightFix = SwFrameSize::Minimum;
+ nHeight = MINFLY;
+ }
+
+ if( nWidth <= 10 ) // auto width
+ {
+ bAutoWidth = true;
+ nWidth = nNetWidth =
+ msword_cast<sal_Int16>(nPgWidth ? nPgWidth : 2268); // 4 cm
+ }
+ if( nWidth <= MINFLY )
+ nWidth = nNetWidth = MINFLY; // minimum width
+
+ /*
+ See issue #i9178# for the 9 anchoring options, and make sure they stay
+ working if you modify the anchoring logic here.
+ */
+
+ // If the Fly is aligned left, right, up, or down,
+ // the outer text distance will be ignored, because otherwise
+ // the Fly will end up in the wrong position.
+ // The only problem is with inside/outside.
+
+ //#i53725# - absolute positioned objects have to be
+ // anchored at-paragraph to assure its correct anchor position.
+ rIo.m_pLastAnchorPos.reset( new SwPosition(*rPaM.GetPoint()));
+
+ switch (nYBind)
+ {
+ case 0: //relative to margin
+ eVRel = text::RelOrientation::PAGE_PRINT_AREA;
+ break;
+ case 1: //relative to page
+ eVRel = text::RelOrientation::PAGE_FRAME;
+ break;
+ default: //relative to text
+ // put in initialization part eVRel = text::RelOrientation::FRAME;
+ break;
+ }
+
+// #i18732#
+ switch( rWW.nSp27 ) // particular Y-positions ?
+ {
+ case -4:
+ eVAlign = text::VertOrientation::TOP;
+ if (nYBind < 2)
+ nUpMgn = 0;
+ break; // up
+ case -8:
+ eVAlign = text::VertOrientation::CENTER;
+ break; // centered
+ case -12:
+ eVAlign = text::VertOrientation::BOTTOM;
+ if (nYBind < 2)
+ nLoMgn = 0;
+ break; // down
+ default:
+ nYPos = rWW.nSp27 + static_cast<short>(nIniFlyDy);
+ break; // corrections from ini file
+ }
+
+ switch( rWW.nSp26 ) // particular X-positions ?
+ {
+ case 0:
+ eHAlign = text::HoriOrientation::LEFT;
+ nLeMgn = 0;
+ break; // left
+ case -4:
+ eHAlign = text::HoriOrientation::CENTER;
+ break; // centered
+ case -8:
+ eHAlign = text::HoriOrientation::RIGHT;
+ nRiMgn = 0;
+ break; // right
+ case -12:
+ eHAlign = text::HoriOrientation::LEFT;
+ bTogglePos = true;
+ break; // inside
+ case -16:
+ eHAlign = text::HoriOrientation::RIGHT;
+ bTogglePos = true;
+ break; // outside
+ default:
+ nXPos = rWW.nSp26 + static_cast<short>(nIniFlyDx);
+ break; // corrections from ini file
+ }
+
+// #i18732#
+ switch (nXBind) // X - binding -> transform coordinates
+ {
+ case 0: //relative to column
+ eHRel = text::RelOrientation::FRAME;
+ break;
+ case 1: //relative to margin
+ eHRel = text::RelOrientation::PAGE_PRINT_AREA;
+ break;
+ default: //relative to page
+ // put in initialization part eHRel= text::RelOrientation::PAGE_FRAME;
+ break;
+ }
+
+ // #i36649# - adjustments for certain horizontal alignments
+ // Note: These special adjustments found by an investigation of documents
+ // containing frames with different left/right border distances and
+ // distances to text. The outcome is somehow strange.
+ // Note: These adjustments causes wrong horizontal positions for frames,
+ // which are aligned inside|outside to page|margin on even pages,
+ // the left and right border distances are different.
+ // no adjustments possible, if frame has automatic width.
+ // determine left border distance
+ sal_Int16 nLeBorderMgn( 0 );
+ if ( !bAutoWidth )
+ {
+ WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
+ sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeBorderMgn);
+ nLeBorderMgn = nLeBorderMgn + nTemp;
+ }
+ // determine right border distance
+ sal_Int16 nRiBorderMgn( 0 );
+ if ( !bAutoWidth )
+ {
+ WW8_BRCVer9 &rBrc = rWW.brc[WW8_RIGHT];
+ sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nRiBorderMgn);
+ nRiBorderMgn = nRiBorderMgn + nTemp;
+ }
+ if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_FRAME )
+ {
+ // convert 'left to page' to
+ // 'from left -<width>-<2*left border distance>-<right wrap distance>
+ // to page text area'
+ eHAlign = text::HoriOrientation::NONE;
+ eHRel = text::RelOrientation::PAGE_PRINT_AREA;
+ nXPos = -nWidth - (2*nLeBorderMgn) - rWW.nRiMgn;
+ // re-set left wrap distance
+ nLeMgn = rWW.nLeMgn;
+ }
+ else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_FRAME )
+ {
+ // convert 'right to page' to
+ // 'from left <right border distance-left border distance>+<left wrap distance>
+ // to right page border'
+ eHAlign = text::HoriOrientation::NONE;
+ eHRel = text::RelOrientation::PAGE_RIGHT;
+ nXPos = ( nRiBorderMgn - nLeBorderMgn ) + rWW.nLeMgn;
+ // re-set right wrap distance
+ nRiMgn = rWW.nRiMgn;
+ }
+ else if ( !bAutoWidth && eHAlign == text::HoriOrientation::LEFT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
+ {
+ // convert 'left to margin' to
+ // 'from left -<left border distance> to page text area'
+ eHAlign = text::HoriOrientation::NONE;
+ eHRel = text::RelOrientation::PAGE_PRINT_AREA;
+ nXPos = -nLeBorderMgn;
+ // re-set left wrap distance
+ nLeMgn = rWW.nLeMgn;
+ }
+ else if ( !bAutoWidth && eHAlign == text::HoriOrientation::RIGHT && eHRel == text::RelOrientation::PAGE_PRINT_AREA )
+ {
+ // convert 'right to margin' to
+ // 'from left -<width>-<left border distance> to right page border'
+ eHAlign = text::HoriOrientation::NONE;
+ eHRel = text::RelOrientation::PAGE_RIGHT;
+ nXPos = -nWidth - nLeBorderMgn;
+ // re-set right wrap distance
+ nRiMgn = rWW.nRiMgn;
+ }
+ else if (rWW.bBorderLines)
+ {
+ /*
+ #i582#
+ Word has a curious bug where the offset stored do not take into
+ account the internal distance from the corner both
+ */
+ WW8_BRCVer9 &rBrc = rWW.brc[WW8_LEFT];
+ sal_Int16 nLeLMgn = 0;
+ sal_Int16 nTemp = rBrc.DetermineBorderProperties(&nLeLMgn);
+ nLeLMgn = nLeLMgn + nTemp;
+
+ if (nLeLMgn)
+ {
+ if (eHAlign == text::HoriOrientation::LEFT)
+ eHAlign = text::HoriOrientation::NONE;
+ nXPos = nXPos - nLeLMgn;
+ }
+ }
+
+ // adjustments for certain vertical alignments
+ if ( eVAlign == text::VertOrientation::NONE && eVRel == text::RelOrientation::PAGE_PRINT_AREA )
+ {
+ // convert "<X> from top page text area" to
+ // "<X + page top margin> from page"
+ eVRel = text::RelOrientation::PAGE_FRAME;
+ nYPos = static_cast< sal_Int16 >( nYPos + nWWPgTop );
+ }
+
+ FlySecur1( nWidth, rWW.bBorderLines ); // Do the borders match ?
+ FlySecur1( nHeight, rWW.bBorderLines );
+
+}
+
+// If a Fly in WW has automatic width, this has to be simulated
+// by modifying the Fly width (fixed in SW) afterwards.
+// This can increase or decrease the Fly width, because the default value
+// is set without knowledge of the contents.
+void WW8SwFlyPara::BoxUpWidth( tools::Long nInWidth )
+{
+ if( bAutoWidth && nInWidth > nNewNetWidth )
+ nNewNetWidth = nInWidth;
+}
+
+SwFlyFrameFormat* WW8SwFlyPara::GetFlyFormat() const
+{
+ if (!m_xFlyFormat)
+ return nullptr;
+ return static_cast<SwFlyFrameFormat*>(m_xFlyFormat->GetFormat());
+}
+
+void WW8SwFlyPara::SetFlyFormat(SwFlyFrameFormat* pNewFlyFormat)
+{
+ if (pNewFlyFormat)
+ m_xFlyFormat.reset(new FrameDeleteWatch(pNewFlyFormat));
+ else
+ m_xFlyFormat.reset();
+}
+
+// The class WW8FlySet is derived from SfxItemSetFixed and does not
+// provide more, but is easier to handle for me.
+// WW8FlySet-ctor for Apos and graphics Apos
+WW8FlySet::WW8FlySet(SwWW8ImplReader& rReader, const WW8FlyPara* pFW,
+ const WW8SwFlyPara* pFS, bool bGraf)
+ : SfxItemSetFixed(rReader.m_rDoc.GetAttrPool())
+{
+ Reader::ResetFrameFormatAttrs(*this); // remove distance/border
+ // position
+ Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
+
+/*Below can all go when we have from left in rtl mode*/
+ SwTwips nXPos = pFS->nXPos;
+ sal_Int16 eHRel = pFS->eHRel;
+ rReader.MiserableRTLGraphicsHack(nXPos, pFS->nWidth, pFS->eHAlign, eHRel);
+/*Above can all go when we have from left in rtl mode*/
+ Put( SwFormatHoriOrient(nXPos, pFS->eHAlign, pFS->eHRel, pFS->bTogglePos ));
+ Put( SwFormatVertOrient( pFS->nYPos, pFS->eVAlign, pFS->eVRel ) );
+
+ if (pFS->nLeMgn || pFS->nRiMgn) // set borders
+ Put(SvxLRSpaceItem(pFS->nLeMgn, pFS->nRiMgn, 0, 0, RES_LR_SPACE));
+
+ if (pFS->nUpMgn || pFS->nLoMgn)
+ Put(SvxULSpaceItem(pFS->nUpMgn, pFS->nLoMgn, RES_UL_SPACE));
+
+ //we no longer need to hack around the header/footer problems
+ SwFormatSurround aSurround(pFS->eSurround);
+ if ( pFS->eSurround == css::text::WrapTextMode_DYNAMIC )
+ aSurround.SetAnchorOnly( true );
+ Put( aSurround );
+
+ short aSizeArray[5]={0};
+ SwWW8ImplReader::SetFlyBordersShadow(*this,pFW->brc,&aSizeArray[0]);
+
+ // the 5th parameter is always 0, thus we lose nothing due to the cast
+
+ // #i27767#
+ // #i35017# - constant name has changed
+ Put( SwFormatWrapInfluenceOnObjPos(
+ text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ) );
+
+ if( bGraf )
+ return;
+
+ Put( SwFormatAnchor(WW8SwFlyPara::eAnchor) );
+ // adjust size
+
+ //Ordinarily with frames, the border width and spacing is
+ //placed outside the frame, making it larger. With these
+ //types of frames, the left right thickness and space makes
+ //it wider, but the top bottom spacing and border thickness
+ //is placed inside.
+ Put( SwFormatFrameSize( pFS->eHeightFix, pFS->nWidth +
+ aSizeArray[WW8_LEFT] + aSizeArray[WW8_RIGHT],
+ pFS->nHeight));
+}
+
+// WW8FlySet-ctor for character bound graphics
+WW8FlySet::WW8FlySet( SwWW8ImplReader& rReader, const SwPaM* pPaM,
+ const WW8_PIC& rPic, tools::Long nWidth, tools::Long nHeight )
+ : SfxItemSetFixed<RES_FRMATR_BEGIN,RES_FRMATR_END-1>(rReader.m_rDoc.GetAttrPool())
+{
+ Init(rReader, pPaM);
+
+ Put(SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, RES_FRAMEDIR));
+
+ short aSizeArray[5]={0};
+ /*
+ If we have set borders then in word the graphic is displaced from the left
+ and top the width of the borders of those sides, and then the shadow
+ itself is drawn to the bottom and right of the displaced graphic. In word
+ the total size is that of the graphic plus the borders, plus the total
+ shadow around all edges, for this translation the top and left shadow
+ region is translated spacing around the graphic to those sides, and the
+ bottom and right shadow size is added to the graphic size.
+ */
+ WW8_BRCVer9 brcVer9[4];
+ for (int i = 0; i < 4; i++)
+ brcVer9[i] = WW8_BRCVer9(rPic.rgbrc[i]);
+ if (SwWW8ImplReader::SetFlyBordersShadow( *this, brcVer9, &aSizeArray[0]))
+ {
+ Put(SvxLRSpaceItem( aSizeArray[WW8_LEFT], 0, 0, 0, RES_LR_SPACE ) );
+ Put(SvxULSpaceItem( aSizeArray[WW8_TOP], 0, RES_UL_SPACE ));
+ aSizeArray[WW8_RIGHT]*=2;
+ aSizeArray[WW8_BOT]*=2;
+ }
+
+ Put( SwFormatFrameSize( SwFrameSize::Fixed, nWidth+aSizeArray[WW8_LEFT]+
+ aSizeArray[WW8_RIGHT], nHeight+aSizeArray[WW8_TOP]
+ + aSizeArray[WW8_BOT]) );
+}
+
+void WW8FlySet::Init(const SwWW8ImplReader& rReader, const SwPaM* pPaM)
+{
+ Reader::ResetFrameFormatAttrs(*this); // remove distance/borders
+
+ Put(SvxLRSpaceItem(RES_LR_SPACE)); //inline writer ole2 objects start with 0.2cm l/r
+ SwFormatAnchor aAnchor(RndStdIds::FLY_AS_CHAR);
+
+ aAnchor.SetAnchor(pPaM->GetPoint());
+ Put(aAnchor);
+
+ //The horizontal default is on the baseline, the vertical is centered
+ //around the character center it appears
+ if (rReader.m_aSectionManager.CurrentSectionIsVertical())
+ Put(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER,text::RelOrientation::CHAR));
+ else
+ Put(SwFormatVertOrient(0, text::VertOrientation::TOP, text::RelOrientation::FRAME));
+}
+
+WW8DupProperties::WW8DupProperties(SwDoc &rDoc, SwWW8FltControlStack *pStack)
+ : pCtrlStck(pStack),
+ aChrSet(rDoc.GetAttrPool()),
+ aParSet(rDoc.GetAttrPool())
+{
+ //Close any open character properties and duplicate them inside the
+ //first table cell
+ size_t nCnt = pCtrlStck->size();
+ for (size_t i=0; i < nCnt; ++i)
+ {
+ const SwFltStackEntry& rEntry = (*pCtrlStck)[ i ];
+ if (rEntry.m_bOpen)
+ {
+ if (isCHRATR(rEntry.m_pAttr->Which()))
+ {
+ aChrSet.Put( *rEntry.m_pAttr );
+
+ }
+ else if (isPARATR(rEntry.m_pAttr->Which()))
+ {
+ aParSet.Put( *rEntry.m_pAttr );
+ }
+ }
+ }
+}
+
+void WW8DupProperties::Insert(const SwPosition &rPos)
+{
+ for (const SfxItemSet* pSet : {&aChrSet, &aParSet})
+ {
+ if( pSet->Count() )
+ {
+ SfxItemIter aIter( *pSet );
+ const SfxPoolItem* pItem = aIter.GetCurItem();
+ do
+ {
+ pCtrlStck->NewAttr(rPos, *pItem);
+ } while ((pItem = aIter.NextItem()));
+ }
+ }
+}
+
+void SwWW8ImplReader::MoveInsideFly(const SwFrameFormat *pFlyFormat)
+{
+ WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
+
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
+
+ // set Pam in FlyFrame
+ const SwFormatContent& rContent = pFlyFormat->GetContent();
+ OSL_ENSURE( rContent.GetContentIdx(), "No content prepared." );
+ m_pPaM->GetPoint()->nNode = rContent.GetContentIdx()->GetIndex() + 1;
+ m_pPaM->GetPoint()->nContent.Assign( m_pPaM->GetContentNode(), 0 );
+
+ aDup.Insert(*m_pPaM->GetPoint());
+}
+
+SwTwips SwWW8ImplReader::MoveOutsideFly(SwFrameFormat *pFlyFormat,
+ const SwPosition &rPos, bool bTableJoin)
+{
+ SwTwips nRetWidth = 0;
+ if (!pFlyFormat)
+ return nRetWidth;
+ // Close all attributes, because otherwise attributes can appear
+ // that extend out of Flys
+ WW8DupProperties aDup(m_rDoc, m_xCtrlStck.get());
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), 0, false);
+
+ /*
+ #i1291
+ If this fly frame consists entirely of one table inside a frame
+ followed by an empty paragraph then we want to delete the empty
+ paragraph so as to get the frame to autoshrink to the size of the
+ table to emulate words behaviour closer.
+ */
+ if (bTableJoin)
+ {
+ const SwNodeIndex* pNodeIndex = pFlyFormat->GetContent().
+ GetContentIdx();
+ if (pNodeIndex)
+ {
+ SwNodeIndex aIdx( *pNodeIndex, 1 ),
+ aEnd( *pNodeIndex->GetNode().EndOfSectionNode() );
+
+ if (aIdx < aEnd)
+ {
+ if(aIdx.GetNode().IsTableNode())
+ {
+ SwTableNode *pTable = aIdx.GetNode().GetTableNode();
+ aIdx = *aIdx.GetNode().EndOfSectionNode();
+ ++aIdx;
+ if ( (aIdx < aEnd) && aIdx.GetNode().IsTextNode() )
+ {
+ SwTextNode *pNd = aIdx.GetNode().GetTextNode();
+ ++aIdx;
+ if (aIdx == aEnd && pNd && pNd->GetText().isEmpty())
+ {
+ //An extra pre-created by writer unused paragraph
+
+ //delete after import is complete rather than now
+ //to avoid the complication of managing uncommitted
+ //ctrlstack properties that refer to it.
+ m_aExtraneousParas.insert(pNd);
+
+ SwTable& rTable = pTable->GetTable();
+ SwFrameFormat* pTableFormat = rTable.GetFrameFormat();
+
+ if (pTableFormat)
+ {
+ SwFormatFrameSize aSize = pTableFormat->GetFrameSize();
+ aSize.SetHeightSizeType(SwFrameSize::Minimum);
+ aSize.SetHeight(MINLAY);
+ pFlyFormat->SetFormatAttr(aSize);
+ SwFormatHoriOrient aHori = pTableFormat->GetHoriOrient();
+ // passing the table orientation of
+ // LEFT_AND_WIDTH to the frame seems to
+ // work better than FULL, especially if the
+ // table width exceeds the page width, however
+ // I am not brave enough to set it in all
+ // instances
+ pTableFormat->SetFormatAttr( SwFormatHoriOrient(0, ( aHori.GetHoriOrient() == text::HoriOrientation::LEFT_AND_WIDTH ) ? ::text::HoriOrientation::LEFT_AND_WIDTH : text::HoriOrientation::FULL ) );
+ nRetWidth = aSize.GetWidth();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ *m_pPaM->GetPoint() = rPos;
+ aDup.Insert(*m_pPaM->GetPoint());
+ return nRetWidth;
+}
+
+std::unique_ptr<WW8FlyPara> SwWW8ImplReader::ConstructApo(const ApoTestResults &rApo,
+ const WW8_TablePos *pTabPos)
+{
+ OSL_ENSURE(rApo.HasFrame() || pTabPos,
+ "If no frame found, *MUST* be in a table");
+
+ std::unique_ptr<WW8FlyPara> pRet(new WW8FlyPara(m_bVer67, rApo.mpStyleApo));
+
+ // find APO parameter and test for bGrafApo
+ if (rApo.HasFrame())
+ pRet->ReadFull(rApo.m_nSprm29, this);
+
+ pRet->ApplyTabPos(pTabPos);
+
+ if (pRet->IsEmpty())
+ {
+ pRet.reset();
+ }
+ return pRet;
+}
+
+bool SwWW8ImplReader::IsDropCap() const
+{
+ // Find the DCS (Drop Cap Specifier) for the paragraph
+ // if does not exist or if the first three bits are 0
+ // then there is no dropcap on the paragraph
+ WW8PLCFx_Cp_FKP *pPap = m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr;
+ if (pPap)
+ {
+ SprmResult aDCS;
+ if (m_bVer67)
+ aDCS = pPap->HasSprm(NS_sprm::v6::sprmPDcs);
+ else
+ aDCS = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PDcs::val);
+ if (aDCS.pSprm && aDCS.nRemainingData >= 2)
+ {
+ /*
+ fdct short :3 0007 drop cap type
+ 0 no drop cap
+ 1 normal drop cap
+ 2 drop cap in margin
+ */
+ short nDCS = SVBT16ToUInt16(aDCS.pSprm);
+ if (nDCS & 7)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *pTabPos)
+{
+ m_xWFlyPara = ConstructApo(rApo, pTabPos);
+ if (!m_xWFlyPara)
+ return false;
+
+ // <WW8SwFlyPara> constructor has changed - new 4th parameter
+ // containing WW8 page top margin.
+ m_xSFlyPara.reset(new WW8SwFlyPara( *m_pPaM, *this, *m_xWFlyPara,
+ m_aSectionManager.GetWWPageTopMargin(),
+ m_aSectionManager.GetTextAreaWidth(),
+ m_nIniFlyDx, m_nIniFlyDy));
+
+ // If this paragraph is a Dropcap set the flag and we will deal with it later
+ if (IsDropCap())
+ {
+ m_bDropCap = true;
+ m_xCurrentItemSet.reset(new SfxItemSet(m_rDoc.GetAttrPool(), svl::Items<RES_CHRATR_BEGIN, RES_PARATR_END - 1>));
+ return false;
+ }
+
+ if (!m_xWFlyPara->bGrafApo)
+ {
+
+ // Within the GrafApo text attributes have to be ignored, because
+ // they would apply to the following lines. The frame is only inserted
+ // if it is not merely positioning a single image. If it is an image
+ // frame, pWFlyPara and pSFlyPara are retained and the resulting
+ // attributes applied to the image when inserting the image.
+
+ WW8FlySet aFlySet(*this, m_xWFlyPara.get(), m_xSFlyPara.get(), false);
+
+ if (pTabPos && pTabPos->bNoFly)
+ {
+ m_xSFlyPara->SetFlyFormat(nullptr);
+ }
+ else
+ {
+ // ofz#34749 we shouldn't anchor anything into an 'extra' paragraph scheduled for
+ // removal at end of import, but check if that scenario is happening
+ m_aExtraneousParas.remove_if_present(m_pPaM->GetNode().GetTextNode());
+ m_xSFlyPara->SetFlyFormat(m_rDoc.MakeFlySection(WW8SwFlyPara::eAnchor,
+ m_pPaM->GetPoint(), &aFlySet));
+ OSL_ENSURE(m_xSFlyPara->GetFlyFormat()->GetAnchor().GetAnchorId() ==
+ WW8SwFlyPara::eAnchor, "Not the anchor type requested!");
+ }
+
+ if (SwFlyFrameFormat* pFlyFormat = m_xSFlyPara->GetFlyFormat())
+ {
+ if (!m_pDrawModel)
+ GraphicCtor();
+
+ SdrObject* pOurNewObject = CreateContactObject(pFlyFormat);
+ m_xWWZOrder->InsertTextLayerObject(pOurNewObject);
+ }
+
+ if (RndStdIds::FLY_AS_CHAR != WW8SwFlyPara::eAnchor && m_xSFlyPara->GetFlyFormat())
+ {
+ m_xAnchorStck->AddAnchor(*m_pPaM->GetPoint(), m_xSFlyPara->GetFlyFormat());
+ }
+
+ // remember Pos in body text
+ m_xSFlyPara->xMainTextPos = m_rDoc.CreateUnoCursor(*m_pPaM->GetPoint());
+
+ //remove fltanchors, otherwise they will be closed inside the
+ //frame, which makes no sense, restore them after the frame is
+ //closed
+ m_xSFlyPara->xOldAnchorStck = std::move(m_xAnchorStck);
+ m_xAnchorStck.reset(new SwWW8FltAnchorStack(m_rDoc, m_nFieldFlags));
+
+ if (SwFlyFrameFormat* pFlyFormat = m_xSFlyPara->GetFlyFormat())
+ MoveInsideFly(pFlyFormat);
+
+ // 1) ReadText() is not called recursively because the length of
+ // the Apo is unknown at that time, and ReadText() needs it.
+ // 2) the CtrlStck is not re-created.
+ // the Char attributes continue (trouble with Sw-attributes)
+ // Para attributes must be reset at the end of every paragraph,
+ // i.e. at the end of a paragraph there must not be para attributes
+ // on the stack
+ }
+ return true;
+}
+
+void wwSectionManager::JoinNode(const SwPosition &rPos, const SwNode &rNode)
+{
+ if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
+ maSegments.back().maStart.Assign(rNode);
+}
+
+bool SwWW8ImplReader::JoinNode(SwPaM &rPam, bool bStealAttr)
+{
+ bool bRet = false;
+ rPam.GetPoint()->nContent = 0; // go to start of paragraph
+
+ SwNodeIndex aPref(rPam.GetPoint()->nNode, -1);
+
+ if (SwTextNode* pNode = aPref.GetNode().GetTextNode())
+ {
+ m_aSectionManager.JoinNode(*rPam.GetPoint(), aPref.GetNode());
+ rPam.GetPoint()->nNode = aPref;
+ rPam.GetPoint()->nContent.Assign(pNode, pNode->GetText().getLength());
+ if (bStealAttr)
+ m_xCtrlStck->StealAttr(rPam.GetPoint()->nNode);
+
+ if (m_pLastAnchorPos || m_xPreviousNode || (m_xSFlyPara && m_xSFlyPara->xMainTextPos))
+ {
+ SwNodeIndex aToBeJoined(aPref, 1);
+
+ if (m_pLastAnchorPos)
+ {
+ //If the last anchor pos is here, then clear the anchor pos.
+ //This "last anchor pos" is only used for fixing up the
+ //positions of things anchored to page breaks and here
+ //we are removing the last paragraph of a frame, so there
+ //cannot be a page break at this point so we can
+ //safely reset m_pLastAnchorPos to avoid any dangling
+ //SwIndex's pointing into the deleted paragraph
+ SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
+ if (aLastAnchorPos == aToBeJoined)
+ m_pLastAnchorPos.reset();
+ }
+
+ if (m_xPreviousNode)
+ {
+ //If the drop character start pos is here, then clear it.
+ SwNodeIndex aDropCharPos(*m_xPreviousNode->GetTextNode());
+ if (aDropCharPos == aToBeJoined)
+ m_xPreviousNode.reset();
+ }
+
+ if (m_xSFlyPara && m_xSFlyPara->xMainTextPos)
+ {
+ // If an open apo pos is here, then clear it before
+ // JoinNext destroys it
+ SwNodeIndex aOpenApoPos(m_xSFlyPara->xMainTextPos->GetPoint()->nNode);
+ if (aOpenApoPos == aToBeJoined)
+ m_xSFlyPara->xMainTextPos.reset();
+ }
+ }
+
+ pNode->JoinNext();
+
+ bRet = true;
+ }
+ return bRet;
+}
+
+//In auto-width word frames negative after-indent values are ignored
+void SwWW8ImplReader::StripNegativeAfterIndent(SwFrameFormat const *pFlyFormat)
+{
+ const SwNodeIndex* pSttNd = pFlyFormat->GetContent().GetContentIdx();
+ if (!pSttNd)
+ return;
+
+ SwNodeIndex aIdx(*pSttNd, 1);
+ SwNodeIndex aEnd(*pSttNd->GetNode().EndOfSectionNode());
+ while (aIdx < aEnd)
+ {
+ SwTextNode *pNd = aIdx.GetNode().GetTextNode();
+ if (pNd)
+ {
+ const SvxLRSpaceItem& rLR = pNd->GetAttr(RES_LR_SPACE);
+ if (rLR.GetRight() < 0)
+ {
+ SvxLRSpaceItem aLR(rLR);
+ aLR.SetRight(0);
+ pNd->SetAttr(aLR);
+ }
+ }
+ ++aIdx;
+ }
+}
+
+void SwWW8ImplReader::StopApo()
+{
+ OSL_ENSURE(m_xWFlyPara, "no pWFlyPara to close");
+ if (!m_xWFlyPara)
+ return;
+ if (m_xWFlyPara->bGrafApo)
+ {
+ // image frame that has not been inserted: delete empty paragraph + attr
+ JoinNode(*m_pPaM, true);
+
+ }
+ else
+ {
+ if (!m_xSFlyPara->xMainTextPos)
+ {
+ OSL_ENSURE(m_xSFlyPara->xMainTextPos, "StopApo: xMainTextPos is nullptr");
+ return;
+ }
+
+ /*
+ What we are doing with this temporary nodeindex is as follows: The
+ stack of attributes normally only places them into the document when
+ the current insertion point has passed them by. Otherwise the end
+ point of the attribute gets pushed along with the insertion point. The
+ insertion point is moved and the properties committed during
+ MoveOutsideFly. We also may want to remove the final paragraph in the
+ frame, but we need to wait until the properties for that frame text
+ have been committed otherwise they will be lost. So we first get a
+ handle to the last the filter inserted. After the attributes are
+ committed, if that paragraph exists we join it with the para after it
+ that comes with the frame by default so that as normal we don't end up
+ with one more paragraph than we wanted.
+ */
+ SwNodeIndex aPref(m_pPaM->GetPoint()->nNode, -1);
+
+ SwTwips nNewWidth =
+ MoveOutsideFly(m_xSFlyPara->GetFlyFormat(), *m_xSFlyPara->xMainTextPos->GetPoint());
+ if (nNewWidth)
+ m_xSFlyPara->BoxUpWidth(nNewWidth);
+
+ Color aBg(ColorTransparency, 0xFE, 0xFF, 0xFF, 0xFF); //Transparent by default
+
+ SwTextNode* pNd = aPref.GetNode().GetTextNode();
+ SwTextNode* pJoinNext = nullptr;
+ if (pNd && m_xSFlyPara->GetFlyFormat())
+ {
+ /*
+ #i582#
+ Take the last paragraph background colour and fill the frame with
+ it. Otherwise, make it transparent, this appears to be how MSWord
+ works
+ */
+ const SfxPoolItem &rItm = pNd->SwContentNode::GetAttr(RES_BACKGROUND);
+ const SvxBrushItem &rBrush = static_cast<const SvxBrushItem&>(rItm);
+ if (rBrush.GetColor() != COL_AUTO)
+ aBg = rBrush.GetColor();
+
+ if (m_pLastAnchorPos)
+ {
+ //If the last anchor pos is here, then clear the anchor pos.
+ //This "last anchor pos" is only used for fixing up the
+ //positions of things anchored to page breaks and here
+ //we are removing the last paragraph of a frame, so there
+ //cannot be a page break at this point so we can
+ //safely reset m_pLastAnchorPos to avoid any dangling
+ //SwIndex's pointing into the deleted paragraph
+ SwNodeIndex aLastAnchorPos(m_pLastAnchorPos->nNode);
+ SwNodeIndex aToBeJoined(aPref, 1);
+ if (aLastAnchorPos == aToBeJoined)
+ m_pLastAnchorPos.reset();
+ }
+
+ //Get rid of extra empty paragraph
+ pJoinNext = pNd;
+ }
+
+ if (SwFlyFrameFormat* pFlyFormat = m_xSFlyPara->GetFlyFormat())
+ pFlyFormat->SetFormatAttr(SvxBrushItem(aBg, RES_BACKGROUND));
+
+ DeleteAnchorStack();
+ if (pJoinNext)
+ pJoinNext->JoinNext();
+
+ m_xAnchorStck = std::move(m_xSFlyPara->xOldAnchorStck);
+
+ // When inserting a graphic into the fly frame using the auto
+ // function, the extension of the SW-fly has to be set
+ // manually as the SW fly has no auto function to adjust the
+ // frame´s size.
+ if (m_xSFlyPara->nNewNetWidth > MINFLY && m_xSFlyPara->GetFlyFormat()) // BoxUpWidth ?
+ {
+ tools::Long nW = m_xSFlyPara->nNewNetWidth;
+ nW += m_xSFlyPara->nWidth - m_xSFlyPara->nNetWidth; // border for it
+ m_xSFlyPara->GetFlyFormat()->SetFormatAttr(
+ SwFormatFrameSize(m_xSFlyPara->eHeightFix, nW, m_xSFlyPara->nHeight));
+ }
+ /*
+ Word set *no* width meaning it's an automatic width. The
+ SwFlyPara reader will have already set a fallback width of the
+ printable regions width, so we should reuse it. Despite the related
+ problems with layout addressed with a hack in WW8FlyPara's constructor
+ #i27204# Added AutoWidth setting. Left the old CalculateFlySize in place
+ so that if the user unselects autowidth, the width doesn't max out
+ */
+ else if (!m_xWFlyPara->nSp28 && m_xSFlyPara->GetFlyFormat())
+ {
+ using namespace sw::util;
+ SfxItemSet aFlySet( m_xSFlyPara->GetFlyFormat()->GetAttrSet() );
+
+ SwFormatFrameSize aSize(aFlySet.Get(RES_FRM_SIZE));
+
+ aFlySet.ClearItem(RES_FRM_SIZE);
+
+ if (!m_bFuzzing)
+ {
+ CalculateFlySize(aFlySet, m_xSFlyPara->xMainTextPos->GetPoint()->nNode,
+ m_xSFlyPara->nWidth);
+ }
+
+ nNewWidth = aFlySet.Get(RES_FRM_SIZE).GetWidth();
+
+ aSize.SetWidth(nNewWidth);
+ aSize.SetWidthSizeType(SwFrameSize::Variable);
+
+ m_xSFlyPara->GetFlyFormat()->SetFormatAttr(aSize);
+ }
+
+ m_xSFlyPara->xMainTextPos.reset();
+// To create the SwFrames when inserting into an existing document, fltshell.cxx
+// will call pFlyFrame->MakeFrames() when setting the FltAnchor attribute
+
+ }
+
+ //#i8062#
+ if (m_xSFlyPara && m_xSFlyPara->GetFlyFormat())
+ m_xFormatOfJustInsertedApo.reset(new FrameDeleteWatch(m_xSFlyPara->GetFlyFormat()));
+
+ m_xSFlyPara.reset();
+ m_xWFlyPara.reset();
+}
+
+// TestSameApo() returns if it's the same Apo or a different one
+bool SwWW8ImplReader::TestSameApo(const ApoTestResults &rApo,
+ const WW8_TablePos *pTabPos)
+{
+ if (!m_xWFlyPara)
+ {
+ OSL_ENSURE(m_xWFlyPara, " Where is my pWFlyPara ? ");
+ return true;
+ }
+
+ // We need to a full comparison (excepting borders) to identify all
+ // combinations style/hard correctly. For this reason we create a
+ // temporary WW8FlyPara (depending on if style or not), apply the
+ // hard attributes and then compare.
+
+ // For comparison
+ WW8FlyPara aF(m_bVer67, rApo.mpStyleApo);
+ // WWPara for current para
+ if (rApo.HasFrame())
+ aF.Read(rApo.m_nSprm29, m_xPlcxMan->GetPapPLCF());
+ aF.ApplyTabPos(pTabPos);
+
+ return aF == *m_xWFlyPara;
+}
+
+void SwWW8ImplReader::NewAttr( const SfxPoolItem& rAttr,
+ const bool bFirstLineOfStSet,
+ const bool bLeftIndentSet )
+{
+ if( m_bNoAttrImport ) // for ignoring styles during doc inserts
+ return;
+
+ if (m_pCurrentColl)
+ {
+ OSL_ENSURE(rAttr.Which() != RES_FLTR_REDLINE, "redline in style!");
+ m_pCurrentColl->SetFormatAttr(rAttr);
+ }
+ else if (m_xCurrentItemSet)
+ {
+ m_xCurrentItemSet->Put(rAttr);
+ }
+ else if (rAttr.Which() == RES_FLTR_REDLINE)
+ {
+ m_xRedlineStack->open(*m_pPaM->GetPoint(), rAttr);
+ }
+ else
+ {
+ m_xCtrlStck->NewAttr(*m_pPaM->GetPoint(), rAttr);
+ // #i103711#
+ if ( bFirstLineOfStSet )
+ {
+ const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
+ m_aTextNodesHavingFirstLineOfstSet.insert( pNd );
+ }
+ // #i105414#
+ if ( bLeftIndentSet )
+ {
+ const SwNode* pNd = &(m_pPaM->GetPoint()->nNode.GetNode());
+ m_aTextNodesHavingLeftIndentSet.insert( pNd );
+ }
+ }
+
+ if (m_pPostProcessAttrsInfo && m_pPostProcessAttrsInfo->mbCopy)
+ m_pPostProcessAttrsInfo->mItemSet.Put(rAttr);
+}
+
+// fetches attribute from FormatColl / Stack / Doc
+const SfxPoolItem* SwWW8ImplReader::GetFormatAttr( sal_uInt16 nWhich )
+{
+ const SfxPoolItem* pRet = nullptr;
+ if (m_pCurrentColl)
+ pRet = &(m_pCurrentColl->GetFormatAttr(nWhich));
+ else if (m_xCurrentItemSet)
+ {
+ pRet = m_xCurrentItemSet->GetItem(nWhich);
+ if (!pRet)
+ pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
+ if (!pRet)
+ pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
+ }
+ else if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
+ {
+ pRet = m_xCtrlStck->GetStackAttr(*m_pPaM->GetPoint(), nWhich);
+ if (!pRet)
+ {
+ if (m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_pFormat &&
+ m_vColl[m_nCurrentColl].m_bColl)
+ {
+ pRet = &(m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(nWhich));
+ }
+ }
+ if (!pRet)
+ pRet = m_pStandardFormatColl ? &(m_pStandardFormatColl->GetFormatAttr(nWhich)) : nullptr;
+ if (!pRet)
+ pRet = &m_rDoc.GetAttrPool().GetDefaultItem(nWhich);
+ }
+ else
+ pRet = m_xCtrlStck->GetFormatAttr(*m_pPaM->GetPoint(), nWhich);
+ return pRet;
+}
+
+// The methods get as parameters the token id and the length of the following
+// parameters according to the table in WWScan.cxx.
+void SwWW8ImplReader::Read_Special(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 1)
+ {
+ m_bSpec = false;
+ return;
+ }
+ m_bSpec = ( *pData != 0 );
+}
+
+// Read_Obj is used for fObj and for fOle2 !
+void SwWW8ImplReader::Read_Obj(sal_uInt16 , const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 1)
+ m_bObj = false;
+ else
+ {
+ m_bObj = 0 != *pData;
+
+ if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
+ {
+ if (!m_aFieldStack.empty() && m_aFieldStack.back().mnFieldId == 56)
+ {
+ // For LINK fields, store the nObjLocFc value in the field entry
+ m_aFieldStack.back().mnObjLocFc = m_nPicLocFc;
+ }
+ else
+ {
+ m_nObjLocFc = m_nPicLocFc;
+ }
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_PicLoc(sal_uInt16 , const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 4)
+ {
+ m_nPicLocFc = 0;
+ m_bSpec = false; // Is this always correct?
+ }
+ else
+ {
+ m_nPicLocFc = SVBT32ToUInt32( pData );
+ m_bSpec = true;
+
+ if( m_bObj && m_nPicLocFc && m_bEmbeddObj )
+ m_nObjLocFc = m_nPicLocFc;
+ }
+}
+
+void SwWW8ImplReader::Read_POutLvl(sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 0)
+ {
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_PARATR_OUTLINELEVEL);
+ return;
+ }
+
+ if (m_pCurrentColl != nullptr)
+ {
+ SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
+ if (pSI && pSI->m_bColl && pSI->m_pFormat)
+ {
+ pSI->mnWW8OutlineLevel =
+ static_cast< sal_uInt8 >( ( (pData && nLen >= 1) ? *pData : 0 ) );
+ auto nLevel = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(pSI->mnWW8OutlineLevel);
+ if (nLevel == 0)
+ {
+ SwTextFormatColl* pTextFormatColl = static_cast<SwTextFormatColl*>(pSI->m_pFormat);
+ pTextFormatColl->DeleteAssignmentToListLevelOfOutlineStyle();
+ }
+ NewAttr(SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nLevel));
+ }
+ }
+ else if (m_pPaM != nullptr)
+ {
+ const sal_uInt8 nOutlineLevel
+ = SwWW8StyInf::WW8OutlineLevelToOutlinelevel(
+ static_cast<sal_uInt8>(((pData && nLen >= 1) ? *pData : 0)));
+ NewAttr(SfxUInt16Item(RES_PARATR_OUTLINELEVEL, nOutlineLevel));
+ }
+}
+
+void SwWW8ImplReader::Read_Symbol(sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if( m_bIgnoreText )
+ return;
+
+ if (nLen < (m_bVer67 ? 3 : 4))
+ {
+ //otherwise disable after we print the char
+ if (m_xPlcxMan && m_xPlcxMan->GetDoingDrawTextBox())
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_FONT );
+ m_bSymbol = false;
+ }
+ else
+ {
+ // Make new Font-Attribute
+ // (will be closed in SwWW8ImplReader::ReadChars() )
+
+ //Will not be added to the charencoding stack, for styles the real
+ //font setting will be put in as the styles charset, and for plain
+ //text encoding for symbols is moot. Drawing boxes will check bSymbol
+ //themselves so they don't need to add it to the stack either.
+ if (SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_FONT))
+ {
+ SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CJK_FONT);
+ SetNewFontAttr(SVBT16ToUInt16( pData ), false, RES_CHRATR_CTL_FONT);
+ if( m_bVer67 )
+ {
+ //convert single byte from MS1252 to Unicode
+ m_cSymbol = OUString(
+ reinterpret_cast<const char*>(pData+2), 1,
+ RTL_TEXTENCODING_MS_1252).toChar();
+ }
+ else
+ {
+ //already is Unicode
+ m_cSymbol = SVBT16ToUInt16( pData+2 );
+ }
+ m_bSymbol = true;
+ }
+ }
+}
+
+SwWW8StyInf *SwWW8ImplReader::GetStyle(sal_uInt16 nColl) const
+{
+ return const_cast<SwWW8StyInf *>(nColl < m_vColl.size() ? &m_vColl[nColl] : nullptr);
+}
+
+// Read_BoldUsw for italic, bold, small caps, majuscule, struck out,
+// contour and shadow
+void SwWW8ImplReader::Read_BoldUsw( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ const int nContiguousWestern = 8;
+ const int nWestern = nContiguousWestern + 1;
+ const int nEastern = 2;
+ const int nCTL = 2;
+ const int nIds = nWestern + nEastern + nCTL;
+ static const sal_uInt16 nEndIds[ nIds ] =
+ {
+ RES_CHRATR_WEIGHT, RES_CHRATR_POSTURE,
+ RES_CHRATR_CROSSEDOUT, RES_CHRATR_CONTOUR,
+ RES_CHRATR_SHADOWED, RES_CHRATR_CASEMAP,
+ RES_CHRATR_CASEMAP, RES_CHRATR_HIDDEN,
+
+ RES_CHRATR_CROSSEDOUT,
+
+ RES_CHRATR_CJK_WEIGHT, RES_CHRATR_CJK_POSTURE,
+
+ RES_CHRATR_CTL_WEIGHT, RES_CHRATR_CTL_POSTURE
+ };
+
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+
+ sal_uInt8 nI;
+ // the attribute number for "double strike-through" breaks rank
+ if (NS_sprm::CFDStrike::val == nId)
+ nI = nContiguousWestern; // The out of sequence western id
+ else
+ {
+ // The contiguous western ids
+ if (eVersion <= ww::eWW2)
+ nI = static_cast< sal_uInt8 >(nId - 60);
+ else if (eVersion < ww::eWW8)
+ nI = static_cast< sal_uInt8 >(nId - NS_sprm::v6::sprmCFBold);
+ else
+ nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBold::val);
+ }
+
+ sal_uInt16 nMask = 1 << nI;
+
+ if (nLen < 1)
+ {
+ if (nI < 2)
+ {
+ if (eVersion <= ww::eWW6)
+ {
+ // reset the CTL Weight and Posture, because they are the same as their
+ // western equivalents in ww6
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nEastern + nI ] );
+ }
+ // reset the CJK Weight and Posture, because they are the same as their
+ // western equivalents in word
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nWestern + nI ] );
+ }
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nEndIds[ nI ] );
+ m_xCtrlStck->SetToggleAttr(nI, false);
+ return;
+ }
+ // value: 0 = off, 1 = on, 128 = like style, 129 contrary to style
+ bool bOn = *pData & 1;
+ SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
+ if (m_xPlcxMan && eVersion > ww::eWW2)
+ {
+ SprmResult aCharIstd =
+ m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
+ if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
+ pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
+ }
+
+ if( m_pCurrentColl ) // StyleDef -> remember flags
+ {
+ if (pSI)
+ {
+ // The style based on has Bit 7 set ?
+ if (
+ pSI->m_nBase < m_vColl.size() && (*pData & 0x80) &&
+ (m_vColl[pSI->m_nBase].m_n81Flags & nMask)
+ )
+ {
+ bOn = !bOn; // invert
+ }
+
+ if (bOn)
+ pSI->m_n81Flags |= nMask; // set flag
+ else
+ pSI->m_n81Flags &= ~nMask; // delete flag
+ }
+ }
+ else
+ {
+
+ // in text -> look at flags
+ if( *pData & 0x80 ) // bit 7 set?
+ {
+ if (pSI && pSI->m_n81Flags & nMask) // and in StyleDef at ?
+ bOn = !bOn; // then invert
+ // remember on stack that this is a toggle-attribute
+ m_xCtrlStck->SetToggleAttr(nI, true);
+ }
+ }
+
+ SetToggleAttr( nI, bOn );
+}
+
+void SwWW8ImplReader::Read_Bidi(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 1) //Property end
+ {
+ m_bBidi = false;
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),RES_CHRATR_BIDIRTL);
+ }
+ else //Property start
+ {
+ m_bBidi = true;
+ sal_uInt8 nBidi = *pData;
+ NewAttr( SfxInt16Item( RES_CHRATR_BIDIRTL, (nBidi!=0)? 1 : 0 ) );
+ }
+}
+
+/*
+ tdf#91916, #i8726, #i42685# there is an ambiguity
+ around certain properties as to what they mean,
+ which appears to be a problem with different versions
+ of the file format where properties conflict, i.e.
+
+ooo40606-2.doc, magic is a699
+ : 0x6f 0x4 0x0 0x71 0x4 0x0
+ooo40635-1.doc, magic is a699
+ : 0x6f 0x4 0x0 0x71 0x4 0x0
+ooo31093/SIMPCHIN.doc, magic is a699
+ : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
+ : 0x6f 0x5 0x0 0x70 0x5 0x0
+ooo31093/TRADCHIN.doc, magic is a699
+ : 0x6f 0x1 0x0 0x70 0x0 0x0 0x71 0x1 0x0
+ooo31093/JAPANESE.doc, magic is a697
+ : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
+ooo31093/KOREAN.doc, magic is a698
+ : 0x6f 0x2 0x0 0x70 0x0 0x0 0x71 0x2 0x0
+ooo31093-1.doc, magic is a698
+ : 0x6f 0x5 0x0 0x70 0x5 0x0
+ooo31093-1.doc, magic is a698
+ : 0x6f 0x5 0x0 0x70 0x5 0x0
+
+meanwhile...
+
+ooo27954-1.doc, magic is a5dc
+ : 0x6f 0x1 0x81 0x71 0x2 0x4 0x0 0x74 0x2 0x20 0x0
+
+ooo33251-1.doc, magic is a5dc
+ : 0x6f 0x1 0x81 0x71 0x2 0x3 0x0 0x74 0x2 0x1c 0x0
+
+---
+
+So we have the same sprm values, but different payloads, where
+the a5dc versions appear to use a len argument, followed by len
+bytes, while the a698<->a699 versions use a 2byte argument
+
+commit c2213db9ed70c1fd546482d22e36e4029c10aa45
+
+ INTEGRATION: CWS tl28 (1.169.24); FILE MERGED
+ 2006/10/25 13:40:41 tl 1.169.24.2: RESYNC: (1.169-1.170); FILE MERGED
+ 2006/09/20 11:55:50 hbrinkm 1.169.24.1: #i42685# applied patch
+
+changed 0x6f and 0x70 from Read_BoldBiDiUsw to Read_FontCode for all versions.
+
+In the Word for Window 2 spec we have...
+ 78 //sprmCMajority
+ 80 //sprmCFBoldBi
+ 81 //sprmCFItalicBi
+ 82 //sprmCFtcBi
+ 83 //sprmClidBi
+ 84 //sprmCIcoBi
+ 85 //sprmCHpsBi
+as see in GetWW2SprmDispatcher, different numbers, but the sequence starts with
+the same sprmCMajority as appears before 0x6f in word 6/95
+
+I think the easiest explanation is that the CJK Word for Window 95, or whatever
+the product was went rogue, and did their own things with at least first three
+slots after sprmCMajority to do a different thing. I have no reason to think Tono
+was wrong with what they do in the a698<->a699 versions, but with magic
+a5dc they probably did mean sprmCFBoldBi, sprmCFItalicBi cause they have that 0x81
+pattern which has significance for those types of properties.
+*/
+void SwWW8ImplReader::Read_AmbiguousSPRM(sal_uInt16 nId, const sal_uInt8* pData,
+ short nLen)
+{
+ if (m_xWwFib->m_wIdent >= 0xa697 && m_xWwFib->m_wIdent <= 0xa699)
+ {
+ Read_FontCode(nId, pData, nLen);
+ }
+ else
+ {
+ Read_BoldBiDiUsw(nId, pData, nLen);
+ }
+}
+
+// Read_BoldUsw for BiDi Italic, Bold
+void SwWW8ImplReader::Read_BoldBiDiUsw(sal_uInt16 nId, const sal_uInt8* pData,
+ short nLen)
+{
+ static const sal_uInt16 nEndIds[2] =
+ {
+ RES_CHRATR_CTL_WEIGHT, RES_CHRATR_CTL_POSTURE,
+ };
+
+ sal_uInt8 nI;
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+ if (eVersion <= ww::eWW2)
+ nI = static_cast< sal_uInt8 >(nId - 80);
+ else if (eVersion < ww::eWW8)
+ nI = static_cast< sal_uInt8 >(nId - 111);
+ else
+ nI = static_cast< sal_uInt8 >(nId - NS_sprm::CFBoldBi::val);
+
+ OSL_ENSURE(nI <= 1, "not happening");
+ if (nI > 1)
+ return;
+
+ sal_uInt16 nMask = 1 << nI;
+
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),nEndIds[nI]);
+ m_xCtrlStck->SetToggleBiDiAttr(nI, false);
+ return;
+ }
+ bool bOn = *pData & 1;
+ SwWW8StyInf* pSI = GetStyle(m_nCurrentColl);
+ if (m_xPlcxMan)
+ {
+ SprmResult aCharIstd =
+ m_xPlcxMan->GetChpPLCF()->HasSprm(m_bVer67 ? NS_sprm::v6::sprmCIstd : NS_sprm::CIstd::val);
+ if (aCharIstd.pSprm && aCharIstd.nRemainingData >= 2)
+ pSI = GetStyle(SVBT16ToUInt16(aCharIstd.pSprm));
+ }
+
+ if (m_pCurrentColl && eVersion > ww::eWW2) // StyleDef -> remember flags
+ {
+ if (pSI)
+ {
+ if( pSI->m_nBase < m_vColl.size() // Style Based on
+ && ( *pData & 0x80 ) // bit 7 set?
+ && ( m_vColl[pSI->m_nBase].m_n81BiDiFlags & nMask ) ) // base mask?
+ bOn = !bOn; // invert
+
+ if( bOn )
+ pSI->m_n81BiDiFlags |= nMask; // set flag
+ else
+ pSI->m_n81BiDiFlags &= ~nMask; // delete flag
+ }
+ }
+ else
+ {
+
+ // in text -> look at flags
+ if (*pData & 0x80) // Bit 7 set?
+ {
+ if (pSI && pSI->m_n81BiDiFlags & nMask) // and in StyleDef at ?
+ bOn = !bOn; // then invert
+ // remember on stack that this is a toggle-attribute
+ m_xCtrlStck->SetToggleBiDiAttr(nI, true);
+ }
+ }
+
+ SetToggleBiDiAttr(nI, bOn);
+}
+
+void SwWW8ImplReader::SetToggleBiDiAttr(sal_uInt8 nAttrId, bool bOn)
+{
+ switch (nAttrId)
+ {
+ case 0:
+ {
+ SvxWeightItem aAttr( bOn ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT );
+ aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
+ NewAttr( aAttr );
+ }
+ break;
+ case 1:
+ {
+ SvxPostureItem aAttr( bOn ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE );
+ aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
+ NewAttr( aAttr );
+ }
+ break;
+ default:
+ OSL_ENSURE(false, "Unhandled unknown bidi toggle attribute");
+ break;
+
+ }
+}
+
+void SwWW8ImplReader::SetToggleAttr(sal_uInt8 nAttrId, bool bOn)
+{
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+
+ switch (nAttrId)
+ {
+ case 0:
+ {
+ SvxWeightItem aAttr( bOn ? WEIGHT_BOLD : WEIGHT_NORMAL, RES_CHRATR_WEIGHT );
+ NewAttr( aAttr );
+ aAttr.SetWhich( RES_CHRATR_CJK_WEIGHT );
+ NewAttr( aAttr );
+ if (eVersion <= ww::eWW6)
+ {
+ aAttr.SetWhich( RES_CHRATR_CTL_WEIGHT );
+ NewAttr( aAttr );
+ }
+ }
+ break;
+ case 1:
+ {
+ SvxPostureItem aAttr( bOn ? ITALIC_NORMAL : ITALIC_NONE, RES_CHRATR_POSTURE );
+ NewAttr( aAttr );
+ aAttr.SetWhich( RES_CHRATR_CJK_POSTURE );
+ NewAttr( aAttr );
+ if (eVersion <= ww::eWW6)
+ {
+ aAttr.SetWhich( RES_CHRATR_CTL_POSTURE );
+ NewAttr( aAttr );
+ }
+ }
+ break;
+ case 2:
+ NewAttr(SvxCrossedOutItem(bOn ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT));
+ break;
+ case 3:
+ NewAttr( SvxContourItem( bOn, RES_CHRATR_CONTOUR ) );
+ break;
+ case 4:
+ NewAttr( SvxShadowedItem( bOn, RES_CHRATR_SHADOWED ) );
+ break;
+ case 5:
+ NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::SmallCaps
+ : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
+ break;
+ case 6:
+ NewAttr( SvxCaseMapItem( bOn ? SvxCaseMap::Uppercase
+ : SvxCaseMap::NotMapped, RES_CHRATR_CASEMAP ) );
+ break;
+ case 7:
+ NewAttr(SvxCharHiddenItem(bOn, RES_CHRATR_HIDDEN));
+ break;
+ case 8:
+ NewAttr( SvxCrossedOutItem( bOn ? STRIKEOUT_DOUBLE
+ : STRIKEOUT_NONE, RES_CHRATR_CROSSEDOUT ) );
+ break;
+ default:
+ OSL_ENSURE(false, "Unhandled unknown toggle attribute");
+ break;
+ }
+}
+
+void SwWW8ImplReader::ChkToggleAttr_( sal_uInt16 nOldStyle81Mask,
+ sal_uInt16 nNewStyle81Mask )
+{
+ sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleAttrFlags();
+ for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
+ {
+ if (
+ (i & nToggleAttrFlags) &&
+ ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
+ )
+ {
+ SetToggleAttr(n, (i & nOldStyle81Mask));
+ }
+ }
+}
+
+void SwWW8ImplReader::ChkToggleBiDiAttr_( sal_uInt16 nOldStyle81Mask,
+ sal_uInt16 nNewStyle81Mask )
+{
+ sal_uInt16 i = 1, nToggleAttrFlags = m_xCtrlStck->GetToggleBiDiAttrFlags();
+ for (sal_uInt8 n = 0; n < 7; ++n, i <<= 1)
+ {
+ if (
+ (i & nToggleAttrFlags) &&
+ ((i & nOldStyle81Mask) != (i & nNewStyle81Mask))
+ )
+ {
+ SetToggleBiDiAttr(n, (i & nOldStyle81Mask));
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_SubSuper( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ESCAPEMENT );
+ return;
+ }
+
+ short nEs;
+ sal_uInt8 nProp;
+ switch( *pData )
+ {
+ case 1:
+ nEs = DFLT_ESC_AUTO_SUPER;
+ nProp = DFLT_ESC_PROP;
+ break;
+ case 2:
+ nEs = DFLT_ESC_AUTO_SUB;
+ nProp = DFLT_ESC_PROP;
+ break;
+ default:
+ nEs = 0;
+ nProp = 100;
+ break;
+ }
+ NewAttr( SvxEscapementItem( nEs, nProp, RES_CHRATR_ESCAPEMENT ) );
+}
+
+SwFrameFormat *SwWW8ImplReader::ContainsSingleInlineGraphic(const SwPaM &rRegion)
+{
+ /*
+ For inline graphics and objects word has a hacked in feature to use
+ subscripting to force the graphic into a centered position on the line, so
+ we must check when applying sub/super to see if it the subscript range
+ contains only a single graphic, and if that graphic is anchored as
+ RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
+ */
+ SwFrameFormat *pRet=nullptr;
+ SwNodeIndex aBegin(rRegion.Start()->nNode);
+ const sal_Int32 nBegin(rRegion.Start()->nContent.GetIndex());
+ SwNodeIndex aEnd(rRegion.End()->nNode);
+ const sal_Int32 nEnd(rRegion.End()->nContent.GetIndex());
+ const SwTextNode* pTNd;
+ const SwTextAttr* pTFlyAttr;
+ if (
+ aBegin == aEnd && nBegin == nEnd - 1 &&
+ nullptr != (pTNd = aBegin.GetNode().GetTextNode()) &&
+ nullptr != (pTFlyAttr = pTNd->GetTextAttrForCharAt(nBegin, RES_TXTATR_FLYCNT))
+ )
+ {
+ const SwFormatFlyCnt& rFly = pTFlyAttr->GetFlyCnt();
+ SwFrameFormat *pFlyFormat = rFly.GetFrameFormat();
+ if (pFlyFormat &&
+ (RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()))
+ {
+ pRet = pFlyFormat;
+ }
+ }
+ return pRet;
+}
+
+bool SwWW8ImplReader::ConvertSubToGraphicPlacement()
+{
+ /*
+ For inline graphics and objects word has a hacked in feature to use
+ subscripting to force the graphic into a centered position on the line, so
+ we must check when applying sub/super to see if it the subscript range
+ contains only a single graphic, and if that graphic is anchored as
+ RndStdIds::FLY_AS_CHAR and then we can change its anchoring to centered in the line.
+ */
+ bool bIsGraphicPlacementHack = false;
+ sal_uInt16 nPos;
+ if (m_xCtrlStck->GetFormatStackAttr(RES_CHRATR_ESCAPEMENT, &nPos))
+ {
+ SwPaM aRegion(*m_pPaM->GetPoint());
+
+ SwFltPosition aMkPos((*m_xCtrlStck)[nPos].m_aMkPos);
+ SwFltPosition aPtPos(*m_pPaM->GetPoint());
+
+ SwFrameFormat *pFlyFormat = nullptr;
+ if (SwFltStackEntry::MakeRegion(m_rDoc, aRegion, SwFltStackEntry::RegionMode::NoCheck, aMkPos, aPtPos)
+ && nullptr != (pFlyFormat = ContainsSingleInlineGraphic(aRegion)))
+ {
+ m_xCtrlStck->DeleteAndDestroy(nPos);
+ pFlyFormat->SetFormatAttr(SwFormatVertOrient(0, text::VertOrientation::CHAR_CENTER, text::RelOrientation::CHAR));
+ bIsGraphicPlacementHack = true;
+ }
+ }
+ return bIsGraphicPlacementHack;
+}
+
+void SwWW8ImplReader::Read_SubSuperProp( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+
+ if (nLen < (eVersion <= ww::eWW2 ? 1 : 2))
+ {
+ if (!ConvertSubToGraphicPlacement())
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ESCAPEMENT );
+ return;
+ }
+
+ // if the fontsize for these characters is specified, make sure it is updated first
+ if ( m_xPlcxMan )
+ {
+ const sal_uInt16 nFontsizeID = m_bVer67 ? NS_sprm::v6::sprmCHps : NS_sprm::CHps::val;
+ const SprmResult aFontsize = m_xPlcxMan->GetChpPLCF()->HasSprm( nFontsizeID, /*bFindFirst=*/false );
+ if ( aFontsize.pSprm && aFontsize.nRemainingData )
+ Read_FontSize(nFontsizeID, aFontsize.pSprm, aFontsize.nRemainingData);
+ }
+
+ // font position in HalfPoints
+ short nPos = eVersion <= ww::eWW2 ? static_cast< sal_Int8 >( *pData ) : SVBT16ToInt16( pData );
+ sal_Int32 nPos2 = nPos * ( 10 * 100 ); // HalfPoints in 100 * tw
+ const SvxFontHeightItem* pF
+ = static_cast<const SvxFontHeightItem*>(GetFormatAttr(RES_CHRATR_FONTSIZE));
+ OSL_ENSURE(pF, "Expected to have the fontheight available here");
+
+ // #i59022: Check ensure nHeight != 0. Div by zero otherwise.
+ sal_Int32 nHeight = 240;
+ if (pF != nullptr && pF->GetHeight() != 0)
+ nHeight = pF->GetHeight();
+ nPos2 /= nHeight; // ... now in % (rounded)
+ if( nPos2 > MAX_ESC_POS )
+ nPos2 = MAX_ESC_POS;
+ if( nPos2 < -MAX_ESC_POS )
+ nPos2 = -MAX_ESC_POS;
+ SvxEscapementItem aEs( static_cast<short>(nPos2), 100, RES_CHRATR_ESCAPEMENT );
+ NewAttr( aEs );
+}
+
+void SwWW8ImplReader::Read_Underline( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ FontLineStyle eUnderline = LINESTYLE_NONE;
+ bool bWordLine = false;
+ if (pData && nLen)
+ {
+ // Parameter: 0 = none, 1 = single, 2 = by Word,
+ // 3 = double, 4 = dotted, 5 = hidden
+ // 6 = thick, 7 = dash, 8 = dot(not used)
+ // 9 = dotdash 10 = dotdotdash 11 = wave
+ switch( *pData )
+ {
+ case 2: bWordLine = true;
+ [[fallthrough]];
+ case 1: eUnderline = LINESTYLE_SINGLE; break;
+ case 3: eUnderline = LINESTYLE_DOUBLE; break;
+ case 4: eUnderline = LINESTYLE_DOTTED; break;
+ case 7: eUnderline = LINESTYLE_DASH; break;
+ case 9: eUnderline = LINESTYLE_DASHDOT; break;
+ case 10:eUnderline = LINESTYLE_DASHDOTDOT; break;
+ case 6: eUnderline = LINESTYLE_BOLD; break;
+ case 11:eUnderline = LINESTYLE_WAVE; break;
+ case 20:eUnderline = LINESTYLE_BOLDDOTTED; break;
+ case 23:eUnderline = LINESTYLE_BOLDDASH; break;
+ case 39:eUnderline = LINESTYLE_LONGDASH; break;
+ case 55:eUnderline = LINESTYLE_BOLDLONGDASH; break;
+ case 25:eUnderline = LINESTYLE_BOLDDASHDOT; break;
+ case 26:eUnderline = LINESTYLE_BOLDDASHDOTDOT;break;
+ case 27:eUnderline = LINESTYLE_BOLDWAVE; break;
+ case 43:eUnderline = LINESTYLE_DOUBLEWAVE; break;
+ }
+ }
+
+ // if necessary, mix up stack and exit!
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_WORDLINEMODE );
+ }
+ else
+ {
+ NewAttr( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ));
+ if( bWordLine )
+ NewAttr(SvxWordLineModeItem(true, RES_CHRATR_WORDLINEMODE));
+ }
+}
+
+/*
+//The last three vary, measurements, rotation ? ?
+NoBracket 78 CA 06 - 02 00 00 02 34 52
+() 78 CA 06 - 02 01 00 02 34 52
+[] 78 CA 06 - 02 02 00 02 34 52
+<> 78 CA 06 - 02 03 00 02 34 52
+{} 78 CA 06 - 02 04 00 02 34 52
+*/
+void SwWW8ImplReader::Read_DoubleLine_Rotate( sal_uInt16, const sal_uInt8* pData,
+ short nLen )
+{
+ if (nLen < 0) // close the tag
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_TWO_LINES );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_ROTATE );
+ }
+ else if( pData && 6 == nLen )
+ {
+ switch( *pData )
+ {
+ case 2: // double line
+ {
+ sal_Unicode cStt = 0, cEnd = 0;
+ switch( SVBT16ToUInt16( pData+1 ) )
+ {
+ case 1: cStt = '('; cEnd = ')'; break;
+ case 2: cStt = '['; cEnd = ']'; break;
+ case 3: cStt = '<'; cEnd = '>'; break;
+ case 4: cStt = '{'; cEnd = '}'; break;
+ }
+ NewAttr( SvxTwoLinesItem( true, cStt, cEnd, RES_CHRATR_TWO_LINES ));
+ }
+ break;
+
+ case 1: // rotated characters
+ {
+ bool bFitToLine = 0 != *(pData+1);
+ NewAttr( SvxCharRotateItem( 900_deg10, bFitToLine, RES_CHRATR_ROTATE ));
+ }
+ break;
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_TextColor( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ //Has newer colour variant, ignore this old variant
+ if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CCv::val).pSprm)
+ return;
+
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
+ else
+ {
+ sal_uInt8 b = *pData; // parameter: 0 = Auto, 1..16 colors
+
+ if( b > 16 ) // unknown -> Black
+ b = 0;
+
+ NewAttr( SvxColorItem(GetCol(b), RES_CHRATR_COLOR));
+ if (m_pCurrentColl && m_xStyles)
+ m_xStyles->mbTextColChanged = true;
+ }
+}
+
+void SwWW8ImplReader::Read_TextForeColor(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 4)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_COLOR );
+ else
+ {
+ Color aColor = msfilter::util::BGRToRGB(SVBT32ToUInt32(pData));
+
+ // At least when transparency is 0xff and the color is black, Word renders that as black.
+ if (aColor.IsTransparent() && aColor != COL_AUTO)
+ {
+ aColor.SetAlpha(255);
+ }
+
+ NewAttr(SvxColorItem(aColor, RES_CHRATR_COLOR));
+ if (m_pCurrentColl && m_xStyles)
+ m_xStyles->mbTextColChanged = true;
+ }
+}
+
+void SwWW8ImplReader::Read_UnderlineColor(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 0)
+ {
+ //because the UnderlineColor is not a standalone attribute in SW, it belongs to the underline attribute.
+ //And, the .doc file stores attributes separately, this attribute ends here, the "underline"
+ //attribute also terminates (if the character next owns underline, that will be a new underline attribute).
+ //so nothing is left to be done here.
+ return;
+ }
+ else
+ {
+ if ( m_pCurrentColl ) //importing style
+ {
+ if( SfxItemState::SET == m_pCurrentColl->GetItemState( RES_CHRATR_UNDERLINE, false ) )
+ {
+ if (nLen >= 4)
+ {
+ const SwAttrSet& aSet = m_pCurrentColl->GetAttrSet();
+ std::unique_ptr<SvxUnderlineItem> pUnderline(aSet.Get(RES_CHRATR_UNDERLINE, false).Clone());
+ pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
+ m_pCurrentColl->SetFormatAttr( *pUnderline );
+ }
+ }
+ }
+ else if (m_xCurrentItemSet)
+ {
+ if ( SfxItemState::SET == m_xCurrentItemSet->GetItemState( RES_CHRATR_UNDERLINE, false ) )
+ {
+ if (nLen >= 4)
+ {
+ std::unique_ptr<SvxUnderlineItem> pUnderline(m_xCurrentItemSet->Get(RES_CHRATR_UNDERLINE, false).Clone());
+ pUnderline->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32(pData)) );
+ m_xCurrentItemSet->Put( std::move(pUnderline) );
+ }
+ }
+ }
+ else
+ {
+ SvxUnderlineItem* pUnderlineAttr = const_cast<SvxUnderlineItem*>(static_cast<const SvxUnderlineItem*>(m_xCtrlStck->GetOpenStackAttr( *m_pPaM->GetPoint(), RES_CHRATR_UNDERLINE )));
+ if (pUnderlineAttr && nLen >= 4)
+ pUnderlineAttr->SetColor( msfilter::util::BGRToRGB(SVBT32ToUInt32( pData ) ));
+ }
+ }
+}
+bool SwWW8ImplReader::GetFontParams( sal_uInt16 nFCode, FontFamily& reFamily,
+ OUString& rName, FontPitch& rePitch, rtl_TextEncoding& reCharSet )
+{
+ // the definitions that are the base for these tables are in windows.h
+ static const FontPitch ePitchA[] =
+ {
+ PITCH_DONTKNOW, PITCH_FIXED, PITCH_VARIABLE, PITCH_DONTKNOW
+ };
+
+ static const FontFamily eFamilyA[] =
+ {
+ FAMILY_DONTKNOW, FAMILY_ROMAN, FAMILY_SWISS, FAMILY_MODERN,
+ FAMILY_SCRIPT, FAMILY_DECORATIVE, FAMILY_DONTKNOW, FAMILY_DONTKNOW
+ };
+
+ const WW8_FFN* pF = m_xFonts->GetFont( nFCode ); // Info for it
+ if( !pF ) // font number unknown ?
+ return false; // then ignore
+
+ rName = pF->sFontname;
+
+ // pF->prg : Pitch
+ rePitch = ePitchA[pF->aFFNBase.prg];
+
+ // pF->chs: Charset
+ if( 77 == pF->aFFNBase.chs ) // Mac font in Mac Charset or
+ reCharSet = m_eTextCharSet; // translated to ANSI charset
+ else
+ {
+ // #i52786#, for word 67 we'll assume that ANSI is basically invalid,
+ // might be true for (above) mac as well, but would need a mac example
+ // that exercises this to be sure
+ if (m_bVer67 && pF->aFFNBase.chs == 0)
+ reCharSet = RTL_TEXTENCODING_DONTKNOW;
+ else
+ reCharSet = rtl_getTextEncodingFromWindowsCharset(pF->aFFNBase.chs);
+ }
+
+ // make sure Font Family Code is set correctly
+ // at least for the most important fonts
+ // ( might be set wrong when Doc was not created by
+ // Winword but by third party program like Applixware... )
+ if (rName.startsWithIgnoreAsciiCase("Tms Rmn") ||
+ rName.startsWithIgnoreAsciiCase("Timmons") ||
+ rName.startsWithIgnoreAsciiCase("CG Times") ||
+ rName.startsWithIgnoreAsciiCase("MS Serif") ||
+ rName.startsWithIgnoreAsciiCase("Garamond") ||
+ rName.startsWithIgnoreAsciiCase("Times Roman") ||
+ rName.startsWithIgnoreAsciiCase("Times New Roman"))
+ {
+ reFamily = FAMILY_ROMAN;
+ }
+ else if (rName.startsWithIgnoreAsciiCase("Helv") ||
+ rName.startsWithIgnoreAsciiCase("Arial") ||
+ rName.startsWithIgnoreAsciiCase("Univers") ||
+ rName.startsWithIgnoreAsciiCase("LinePrinter") ||
+ rName.startsWithIgnoreAsciiCase("Lucida Sans") ||
+ rName.startsWithIgnoreAsciiCase("Small Fonts") ||
+ rName.startsWithIgnoreAsciiCase("MS Sans Serif"))
+ {
+ reFamily = FAMILY_SWISS;
+ }
+ else
+ {
+ reFamily = eFamilyA[pF->aFFNBase.ff];
+ }
+
+ return true;
+}
+
+bool SwWW8ImplReader::SetNewFontAttr(sal_uInt16 nFCode, bool bSetEnums,
+ sal_uInt16 nWhich)
+{
+ FontFamily eFamily;
+ OUString aName;
+ FontPitch ePitch;
+ rtl_TextEncoding eSrcCharSet;
+
+ if( !GetFontParams( nFCode, eFamily, aName, ePitch, eSrcCharSet ) )
+ {
+ //If we fail (and are not doing a style) then put something into the
+ //character encodings stack anyway so that the property end that pops
+ //off the stack will keep in sync
+ if (!m_pCurrentColl && IsListOrDropcap())
+ {
+ if (nWhich == RES_CHRATR_CJK_FONT)
+ {
+ if (!m_aFontSrcCJKCharSets.empty())
+ {
+ eSrcCharSet = m_aFontSrcCJKCharSets.top();
+ }
+ else
+ {
+ eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
+ }
+
+ m_aFontSrcCJKCharSets.push(eSrcCharSet);
+ }
+ else
+ {
+ if (!m_aFontSrcCharSets.empty())
+ {
+ eSrcCharSet = m_aFontSrcCharSets.top();
+ }
+ else
+ {
+ eSrcCharSet = RTL_TEXTENCODING_DONTKNOW;
+ }
+
+ m_aFontSrcCharSets.push(eSrcCharSet);
+ }
+ }
+ return false;
+ }
+
+ rtl_TextEncoding eDstCharSet = eSrcCharSet;
+
+ SvxFontItem aFont( eFamily, aName, OUString(), ePitch, eDstCharSet, nWhich);
+
+ if( bSetEnums )
+ {
+ if( m_pCurrentColl && m_nCurrentColl < m_vColl.size() ) // StyleDef
+ {
+ switch(nWhich)
+ {
+ default:
+ case RES_CHRATR_FONT:
+ m_vColl[m_nCurrentColl].m_eLTRFontSrcCharSet = eSrcCharSet;
+ break;
+ case RES_CHRATR_CTL_FONT:
+ m_vColl[m_nCurrentColl].m_eRTLFontSrcCharSet = eSrcCharSet;
+ break;
+ case RES_CHRATR_CJK_FONT:
+ m_vColl[m_nCurrentColl].m_eCJKFontSrcCharSet = eSrcCharSet;
+ break;
+ }
+ }
+ else if (IsListOrDropcap())
+ {
+ //Add character text encoding to stack
+ if (nWhich == RES_CHRATR_CJK_FONT)
+ m_aFontSrcCJKCharSets.push(eSrcCharSet);
+ else
+ m_aFontSrcCharSets.push(eSrcCharSet);
+ }
+ }
+
+ NewAttr( aFont ); // ...and insert
+
+ return true;
+}
+
+void SwWW8ImplReader::ResetCharSetVars()
+{
+ OSL_ENSURE(!m_aFontSrcCharSets.empty(),"no charset to remove");
+ if (!m_aFontSrcCharSets.empty())
+ m_aFontSrcCharSets.pop();
+}
+
+void SwWW8ImplReader::ResetCJKCharSetVars()
+{
+ OSL_ENSURE(!m_aFontSrcCJKCharSets.empty(),"no charset to remove");
+ if (!m_aFontSrcCJKCharSets.empty())
+ m_aFontSrcCJKCharSets.pop();
+}
+
+void SwWW8ImplReader::openFont(sal_uInt16 nFCode, sal_uInt16 nId)
+{
+ if (SetNewFontAttr(nFCode, true, nId) && m_pCurrentColl && m_xStyles)
+ {
+ // remember for simulating default font
+ if (RES_CHRATR_CJK_FONT == nId)
+ m_xStyles->mbCJKFontChanged = true;
+ else if (RES_CHRATR_CTL_FONT == nId)
+ m_xStyles->mbCTLFontChanged = true;
+ else
+ m_xStyles->mbFontChanged = true;
+ }
+}
+
+void SwWW8ImplReader::closeFont(sal_uInt16 nId)
+{
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
+ if (nId == RES_CHRATR_CJK_FONT)
+ ResetCJKCharSetVars();
+ else
+ ResetCharSetVars();
+}
+
+/*
+ Turn font on or off:
+*/
+void SwWW8ImplReader::Read_FontCode( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ //Note: this function needs to be able to run multiple times on the same data.
+ //It is called by Read_SubSuperProp to ensure that the current fontsize is known.
+
+ if (m_bSymbol) // if bSymbol, the symbol's font
+ return;
+
+// (see sprmCSymbol) is valid!
+ switch( nId )
+ {
+ case 113: //WW7
+ case NS_sprm::CRgFtc2::val: //"Other" font, override with BiDi if it exists
+ case NS_sprm::CFtcBi::val: //BiDi Font
+ nId = RES_CHRATR_CTL_FONT;
+ break;
+ case NS_sprm::v6::sprmCFtc: //WW6
+ case 111: //WW7
+ case NS_sprm::CRgFtc0::val:
+ nId = RES_CHRATR_FONT;
+ break;
+ case 112: //WW7
+ case NS_sprm::CRgFtc1::val:
+ nId = RES_CHRATR_CJK_FONT;
+ break;
+ default:
+ return ;
+ }
+
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+
+ if (nLen < 2) // end of attribute
+ {
+ if (eVersion <= ww::eWW6)
+ {
+ closeFont(RES_CHRATR_CTL_FONT);
+ closeFont(RES_CHRATR_CJK_FONT);
+ }
+ closeFont(nId);
+ }
+ else
+ {
+ sal_uInt16 nFCode = SVBT16ToUInt16( pData ); // font number
+ openFont(nFCode, nId);
+ if (eVersion <= ww::eWW6)
+ {
+ openFont(nFCode, RES_CHRATR_CJK_FONT);
+ openFont(nFCode, RES_CHRATR_CTL_FONT);
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_FontSize( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ switch( nId )
+ {
+ case 74: // WW2
+ case NS_sprm::v6::sprmCHps:
+ case NS_sprm::CHps::val:
+ nId = RES_CHRATR_FONTSIZE;
+ break;
+ case 85: //WW2
+ case 116: //WW7
+ case NS_sprm::CHpsBi::val:
+ nId = RES_CHRATR_CTL_FONTSIZE;
+ break;
+ default:
+ return ;
+ }
+
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+
+ if (nLen < (eVersion <= ww::eWW2 ? 1 : 2)) // end of attribute
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
+ if (eVersion <= ww::eWW6) // reset additionally the CTL size
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CTL_FONTSIZE );
+ if (RES_CHRATR_FONTSIZE == nId) // reset additionally the CJK size
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_CJK_FONTSIZE );
+ }
+ else
+ {
+ // Font-Size in half points e.g. 10 = 1440 / ( 72 * 2 )
+ sal_uLong nFSize = eVersion <= ww::eWW2 ? *pData : SVBT16ToUInt16(pData);
+ nFSize*= 10;
+
+ SvxFontHeightItem aSz( nFSize, 100, nId );
+ NewAttr( aSz );
+ if (RES_CHRATR_FONTSIZE == nId) // set additionally the CJK size
+ {
+ aSz.SetWhich( RES_CHRATR_CJK_FONTSIZE );
+ NewAttr( aSz );
+ }
+ if (eVersion <= ww::eWW6) // set additionally the CTL size
+ {
+ aSz.SetWhich( RES_CHRATR_CTL_FONTSIZE );
+ NewAttr( aSz );
+ }
+ if (m_pCurrentColl && m_xStyles) // Style-Def ?
+ {
+ // remember for simulating default font size
+ if (nId == RES_CHRATR_CTL_FONTSIZE)
+ m_xStyles->mbFCTLSizeChanged = true;
+ else
+ {
+ m_xStyles->mbFSizeChanged = true;
+ if (eVersion <= ww::eWW6)
+ m_xStyles->mbFCTLSizeChanged= true;
+ }
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_CharSet(sal_uInt16 , const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 1)
+ { // end of attribute
+ m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
+ return;
+ }
+ sal_uInt8 nfChsDiff = *pData;
+
+ if (nfChsDiff && nLen >= 2)
+ m_eHardCharSet = rtl_getTextEncodingFromWindowsCharset( *(pData + 1) );
+ else
+ m_eHardCharSet = RTL_TEXTENCODING_DONTKNOW;
+}
+
+void SwWW8ImplReader::Read_Language( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ switch( nId )
+ {
+ case NS_sprm::v6::sprmCLid:
+ case NS_sprm::CRgLid0_80::val:
+ case NS_sprm::CRgLid0::val:
+ nId = RES_CHRATR_LANGUAGE;
+ break;
+ case NS_sprm::CRgLid1_80::val:
+ case NS_sprm::CRgLid1::val:
+ nId = RES_CHRATR_CJK_LANGUAGE;
+ break;
+ case 83: // WW2
+ case 114: // WW7
+ case NS_sprm::CLidBi::val:
+ nId = RES_CHRATR_CTL_LANGUAGE;
+ break;
+ default:
+ return;
+ }
+
+ if (nLen < 2) // end of attribute
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
+ else
+ {
+ sal_uInt16 nLang = SVBT16ToUInt16( pData ); // Language-Id
+ NewAttr(SvxLanguageItem(LanguageType(nLang), nId));
+ }
+}
+
+/*
+ Turn on character style:
+*/
+void SwWW8ImplReader::Read_CColl( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 2) // end of attribute
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_TXTATR_CHARFMT );
+ m_nCharFormat = -1;
+ return;
+ }
+ sal_uInt16 nId = SVBT16ToUInt16( pData ); // Style-Id (NOT Sprm-Id!)
+
+ if( nId >= m_vColl.size() || !m_vColl[nId].m_pFormat // invalid Id?
+ || m_vColl[nId].m_bColl ) // or paragraph style?
+ return; // then ignore
+
+ // if current on loading a TOX field, and current trying to apply a hyperlink character style,
+ // just ignore. For the hyperlinks inside TOX in MS Word is not same with a common hyperlink
+ // Character styles: without underline and blue font color. And such type style will be applied in others
+ // processes.
+ if (m_bLoadingTOXCache && m_vColl[nId].GetWWStyleId() == ww::stiHyperlink)
+ {
+ return;
+ }
+
+ NewAttr( SwFormatCharFormat( static_cast<SwCharFormat*>(m_vColl[nId].m_pFormat) ) );
+ m_nCharFormat = static_cast<short>(nId);
+}
+
+/*
+ Narrower or wider than normal:
+*/
+void SwWW8ImplReader::Read_Kern( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 2) // end of attribute
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_KERNING );
+ return;
+ }
+ sal_Int16 nKern = SVBT16ToUInt16( pData ); // Kerning in Twips
+ NewAttr( SvxKerningItem( nKern, RES_CHRATR_KERNING ) );
+}
+
+void SwWW8ImplReader::Read_FontKern( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 2) // end of attribute
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_AUTOKERN );
+ return;
+ }
+ sal_Int16 nAutoKern = SVBT16ToUInt16( pData ); // Kerning in Twips
+ NewAttr(SvxAutoKernItem(static_cast<bool>(nAutoKern), RES_CHRATR_AUTOKERN));
+}
+
+void SwWW8ImplReader::Read_CharShadow( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ //Has newer colour variant, ignore this old variant
+ if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CShd::val).pSprm)
+ return;
+
+ if (nLen < 2)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BACKGROUND );
+ }
+ else
+ {
+ WW8_SHD aSHD;
+ aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
+ SwWW8Shade aSh( m_bVer67, aSHD );
+
+ NewAttr( SvxBrushItem( aSh.m_aColor, RES_CHRATR_BACKGROUND ));
+
+ // Add a marker to the grabbag indicating that character background was imported from MSO shading
+ SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
+ std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
+ rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::Any(true)));
+ NewAttr(aGrabBag);
+ }
+}
+
+void SwWW8ImplReader::Read_TextBackColor(sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen <= 0)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BACKGROUND );
+ }
+ else
+ {
+ OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
+ if (nLen != 10)
+ return;
+ Color aColour(ExtractColour(pData, m_bVer67));
+ NewAttr(SvxBrushItem(aColour, RES_CHRATR_BACKGROUND));
+
+ // Add a marker to the grabbag indicating that character background was imported from MSO shading
+ SfxGrabBagItem aGrabBag = *static_cast<const SfxGrabBagItem*>(GetFormatAttr(RES_CHRATR_GRABBAG));
+ std::map<OUString, css::uno::Any>& rMap = aGrabBag.GetGrabBag();
+ rMap.insert(std::pair<OUString, css::uno::Any>("CharShadingMarker",uno::Any(true)));
+ NewAttr(aGrabBag);
+ }
+}
+
+void SwWW8ImplReader::Read_CharHighlight(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ // MS Word completely ignores character highlighting in character styles.
+ if ( m_pCurrentColl && m_pCurrentColl->Which() == RES_CHRFMT )
+ return;
+
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_HIGHLIGHT );
+ }
+ else
+ {
+ sal_uInt8 b = *pData; // Parameter: 0 = Auto, 1..16 colors
+
+ if( b > 16 ) // invalid -> Black
+ b = 0; // Auto -> Black
+
+ Color aCol(GetCol(b));
+ NewAttr( SvxBrushItem( aCol , RES_CHRATR_HIGHLIGHT ));
+ }
+}
+
+void SwWW8ImplReader::Read_NoLineNumb(sal_uInt16 , const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 0) // end of attribute
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_LINENUMBER );
+ return;
+ }
+ SwFormatLineNumber aLN;
+ if (const SwFormatLineNumber* pLN
+ = static_cast<const SwFormatLineNumber*>(GetFormatAttr(RES_LINENUMBER)))
+ {
+ aLN.SetStartValue( pLN->GetStartValue() );
+ }
+
+ aLN.SetCountLines(pData && nLen >= 1 && (0 == *pData));
+ NewAttr( aLN );
+}
+
+static bool lcl_HasExplicitLeft(const WW8PLCFMan *pPlcxMan, bool bVer67)
+{
+ WW8PLCFx_Cp_FKP *pPap = pPlcxMan ? pPlcxMan->GetPapPLCF() : nullptr;
+ if (pPap)
+ {
+ if (bVer67)
+ return pPap->HasSprm(NS_sprm::v6::sprmPDxaLeft).pSprm;
+ else
+ return (pPap->HasSprm(NS_sprm::PDxaLeft80::val).pSprm || pPap->HasSprm(NS_sprm::PDxaLeft::val).pSprm);
+ }
+ return false;
+}
+
+// Sprm 16, 17
+void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 2) // end of attribute
+ {
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_LR_SPACE);
+ return;
+ }
+
+ short nPara = SVBT16ToUInt16( pData );
+
+ std::shared_ptr<SvxLRSpaceItem> aLR(std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE));
+ const SfxPoolItem* pLR = GetFormatAttr(RES_LR_SPACE);
+ if( pLR )
+ aLR.reset(static_cast<SvxLRSpaceItem*>(pLR->Clone()));
+
+ // Fix the regression issue: #i99822#: Discussion?
+ // Since the list level formatting doesn't apply into paragraph style
+ // for list levels of mode LABEL_ALIGNMENT.(see ww8par3.cxx
+ // W8ImplReader::RegisterNumFormatOnTextNode).
+ // Need to apply the list format to the paragraph here.
+ SwTextNode* pTextNode = m_pPaM->GetNode().GetTextNode();
+ if( pTextNode && pTextNode->AreListLevelIndentsApplicable() )
+ {
+ SwNumRule * pNumRule = pTextNode->GetNumRule();
+ if( pNumRule )
+ {
+ sal_uInt8 nLvl = static_cast< sal_uInt8 >(pTextNode->GetActualListLevel());
+ const SwNumFormat* pFormat = pNumRule->GetNumFormat( nLvl );
+ if ( pFormat && pFormat->GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ aLR->SetTextLeft( pFormat->GetIndentAt() );
+ aLR->SetTextFirstLineOffset( static_cast<short>(pFormat->GetFirstLineIndent()) );
+ // make paragraph have hard-set indent attributes
+ pTextNode->SetAttr( *aLR );
+ }
+ }
+ }
+
+ /*
+ The older word sprms mean left/right, while the new ones mean before/after.
+ Writer now also works with before after, so when we see old left/right and
+ we're RTL. We swap them
+ */
+ if (IsRightToLeft())
+ {
+ switch (nId)
+ {
+ //Left becomes after;
+ case NS_sprm::v6::sprmPDxaLeft:
+ nId = NS_sprm::v6::sprmPDxaRight;
+ break;
+ case NS_sprm::PDxaLeft80::val:
+ nId = NS_sprm::PDxaRight80::val;
+ break;
+ //Right becomes before;
+ case NS_sprm::v6::sprmPDxaRight:
+ nId = NS_sprm::v6::sprmPDxaLeft;
+ break;
+ case NS_sprm::PDxaRight80::val:
+ nId = NS_sprm::PDxaLeft80::val;
+ break;
+ }
+ }
+
+ bool bFirstLinOfstSet( false ); // #i103711#
+ bool bLeftIndentSet( false ); // #i105414#
+
+ switch (nId)
+ {
+ //sprmPDxaLeft
+ case NS_sprm::v6::sprmPDxaLeft:
+ case NS_sprm::PDxaLeft80::val:
+ case NS_sprm::PDxaLeft::val:
+ aLR->SetTextLeft( nPara );
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
+ {
+ m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
+ }
+ bLeftIndentSet = true; // #i105414#
+ break;
+ //sprmPDxaLeft1
+ case NS_sprm::v6::sprmPDxaLeft1:
+ case NS_sprm::PDxaLeft180::val:
+ case NS_sprm::PDxaLeft1::val:
+ /*
+ As part of an attempt to break my spirit ww 8+ formats can contain
+ ww 7- lists. If they do and the list is part of the style, then
+ when removing the list from a paragraph of that style there
+ appears to be a bug where the hanging indent value which the list
+ set is still factored into the left indent of the paragraph. Its
+ not listed in the winword dialogs, but it is clearly there. So if
+ our style has a broken ww 7- list and we know that the list has
+ been removed then we will factor the original list applied hanging
+ into our calculation.
+ */
+ if (m_xPlcxMan && m_nCurrentColl < m_vColl.size() && m_vColl[m_nCurrentColl].m_bHasBrokenWW6List)
+ {
+ SprmResult aIsZeroed = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PIlfo::val);
+ if (aIsZeroed.pSprm && aIsZeroed.nRemainingData >= 1 && *aIsZeroed.pSprm == 0)
+ {
+ const SvxLRSpaceItem &rLR =
+ m_vColl[m_nCurrentColl].m_pFormat->GetFormatAttr(RES_LR_SPACE);
+ nPara = nPara - rLR.GetTextFirstLineOffset();
+ }
+ }
+
+ aLR->SetTextFirstLineOffset(nPara);
+
+ if (!m_pCurrentColl)
+ {
+ if (const SwTextNode* pNode = m_pPaM->GetNode().GetTextNode())
+ {
+ if ( const SwNumFormat *pNumFormat = GetNumFormatFromTextNode(*pNode) )
+ {
+ if (!lcl_HasExplicitLeft(m_xPlcxMan.get(), m_bVer67))
+ {
+ aLR->SetTextLeft(pNumFormat->GetIndentAt());
+
+ // If have not explicit left, set number format list tab position is doc default tab
+ const SvxTabStopItem *pDefaultStopItem = m_rDoc.GetAttrPool().GetPoolDefaultItem(RES_PARATR_TABSTOP);
+ if ( pDefaultStopItem && pDefaultStopItem->Count() > 0 )
+ const_cast<SwNumFormat*>(pNumFormat)->SetListtabPos( const_cast<SvxTabStop&>((*pDefaultStopItem)[0]).GetTabPos() );
+ }
+ }
+ }
+ }
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
+ {
+ m_vColl[m_nCurrentColl].m_bListRelevantIndentSet = true;
+ }
+ bFirstLinOfstSet = true; // #i103711#
+ break;
+ //sprmPDxaRight
+ case NS_sprm::v6::sprmPDxaRight:
+ case NS_sprm::PDxaRight80::val:
+ case NS_sprm::PDxaRight::val:
+ aLR->SetRight( nPara );
+ break;
+ default:
+ return;
+ }
+
+ NewAttr( *aLR, bFirstLinOfstSet, bLeftIndentSet ); // #i103711#, #i105414#
+}
+
+// Sprm 20
+void SwWW8ImplReader::Read_LineSpace( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+// comment see Read_UL()
+ if (m_bStyNormal && m_bWWBugNormal)
+ return;
+
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+
+ if (nLen < (eVersion <= ww::eWW2 ? 3 : 4))
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_LINESPACING );
+ if( !( m_nIniFlags & WW8FL_NO_IMPLPASP ) )
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
+ return;
+ }
+
+ short nSpace = SVBT16ToUInt16( pData );
+ short nMulti = (eVersion <= ww::eWW2) ? 1 : SVBT16ToUInt16( pData + 2 );
+
+ SvxLineSpaceRule eLnSpc;
+ if( 0 > nSpace )
+ {
+ nSpace = -nSpace;
+ eLnSpc = SvxLineSpaceRule::Fix;
+ }
+ else
+ eLnSpc = SvxLineSpaceRule::Min;
+
+ // WW has implicit additional paragraph spacing depending on
+ // the line spacing. It is, for "exactly", 0.8 * line spacing "before"
+ // and 0.2 * line spacing "after".
+ // For "at least", it is 1 * line spacing "before" and 0 * line spacing "after".
+ // For "multiple", it is 0 "before" and min(0cm, FontSize*(nFach-1)) "after".
+
+ // SW also has implicit line spacing. It is, for "at least"
+ // 1 * line spacing "before" and 0 "after".
+ // For proportional, it is min(0cm, FontSize*(nFach-1)) both "before" and "after".
+
+ sal_uInt16 nSpaceTw = 0;
+
+ SvxLineSpacingItem aLSpc( LINE_SPACE_DEFAULT_HEIGHT, RES_PARATR_LINESPACING );
+
+ if( 1 == nMulti ) // MultilineSpace ( proportional )
+ {
+ tools::Long n = nSpace * 10 / 24; // WW: 240 = 100%, SW: 100 = 100%
+
+ // here n is in [0..13653]
+ aLSpc.SetPropLineSpace( o3tl::narrowing<sal_uInt16>(n) );
+ const SvxFontHeightItem* pH = static_cast<const SvxFontHeightItem*>(
+ GetFormatAttr( RES_CHRATR_FONTSIZE ));
+ nSpaceTw = o3tl::narrowing<sal_uInt16>( n * pH->GetHeight() / 100 );
+ }
+ else // Fixed / Minimum
+ {
+ // for negative space, the distance is "exact", otherwise "at least"
+ nSpaceTw = o3tl::narrowing<sal_uInt16>(nSpace);
+ aLSpc.SetLineHeight( nSpaceTw );
+ aLSpc.SetLineSpaceRule( eLnSpc);
+ }
+ NewAttr( aLSpc );
+ if (m_xSFlyPara)
+ m_xSFlyPara->nLineSpace = nSpaceTw; // linespace for graphics APOs
+}
+
+//#i18519# AutoSpace value depends on Dop fDontUseHTMLAutoSpacing setting
+sal_uInt16 SwWW8ImplReader::GetParagraphAutoSpace(bool fDontUseHTMLAutoSpacing)
+{
+ if (fDontUseHTMLAutoSpacing)
+ return 100; //Seems to be always 5points in this case
+ else
+ return 280; //Seems to be always 14points in this case
+}
+
+void SwWW8ImplReader::Read_ParaAutoBefore(sal_uInt16, const sal_uInt8 *pData, short nLen)
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
+ return;
+ }
+
+ if (*pData)
+ {
+ SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
+ aUL.SetUpper(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
+ NewAttr(aUL);
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
+ m_vColl[m_nCurrentColl].m_bParaAutoBefore = true;
+ else
+ m_bParaAutoBefore = true;
+ }
+ else
+ {
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
+ m_vColl[m_nCurrentColl].m_bParaAutoBefore = false;
+ else
+ m_bParaAutoBefore = false;
+ }
+}
+
+void SwWW8ImplReader::Read_ParaAutoAfter(sal_uInt16, const sal_uInt8 *pData, short nLen)
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_UL_SPACE);
+ return;
+ }
+
+ if (*pData)
+ {
+ SvxULSpaceItem aUL(*static_cast<const SvxULSpaceItem*>(GetFormatAttr(RES_UL_SPACE)));
+ aUL.SetLower(GetParagraphAutoSpace(m_xWDop->fDontUseHTMLAutoSpacing));
+ NewAttr(aUL);
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
+ m_vColl[m_nCurrentColl].m_bParaAutoAfter = true;
+ else
+ m_bParaAutoAfter = true;
+ }
+ else
+ {
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size())
+ m_vColl[m_nCurrentColl].m_bParaAutoAfter = false;
+ else
+ m_bParaAutoAfter = false;
+ }
+}
+
+// Sprm 21, 22
+void SwWW8ImplReader::Read_UL( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ // A workaround for an error in WW: For nProduct == 0c03d, usually
+ // DyaAfter 240 (delta y distance after, comment of the translator)
+ // is incorrectly inserted into style "Normal", even though it isn't there.
+ // Using the ini flag WW8FL_NO_STY_DYA you can force this behavior for other
+ // WW versions as well.
+ // OSL_ENSURE( !bStyNormal || bWWBugNormal, "+This Document may point to a bug
+ // in the WW version used for creating it. If the Styles <Standard> resp.
+ // <Normal> differentiate between WW and SW in paragraph or line spacing,
+ // then please send this Document to SH.");
+ // bWWBugNormal is not a sufficient criterion for this distance being wrong.
+
+ if (nLen < 2)
+ {
+ // end of attribute
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
+ return;
+ }
+ short nPara = SVBT16ToUInt16( pData );
+ if( nPara < 0 )
+ nPara = -nPara;
+
+ SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
+
+ switch( nId )
+ {
+ //sprmPDyaBefore
+ case NS_sprm::v6::sprmPDyaBefore:
+ case NS_sprm::PDyaBefore::val:
+ aUL.SetUpper( nPara );
+ break;
+ //sprmPDyaAfter
+ case NS_sprm::v6::sprmPDyaAfter:
+ case NS_sprm::PDyaAfter::val:
+ aUL.SetLower( nPara );
+ break;
+ default:
+ return;
+ }
+
+ NewAttr( aUL );
+}
+
+void SwWW8ImplReader::Read_ParaContextualSpacing( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_UL_SPACE );
+ return;
+ }
+ SvxULSpaceItem aUL( *static_cast<const SvxULSpaceItem*>(GetFormatAttr( RES_UL_SPACE )));
+ aUL.SetContextValue(*pData != 0);
+ NewAttr( aUL );
+}
+
+void SwWW8ImplReader::Read_LineBreakClear(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
+{
+ if (nLen == -1 && m_oLineBreakClear.has_value())
+ {
+ SwTextNode* pText = m_pPaM->GetNode().GetTextNode();
+ sal_Int32 nPos = m_pPaM->GetPoint()->nContent.GetIndex();
+ if (!pText || !nPos)
+ {
+ // There should have been a linebreak char.
+ return;
+ }
+
+ // Replace the linebreak char with a clearing break.
+ --nPos;
+ m_pPaM->SetMark();
+ --m_pPaM->GetMark()->nContent;
+ m_rDoc.getIDocumentContentOperations().DeleteRange(*m_pPaM);
+ m_pPaM->DeleteMark();
+ SwFormatLineBreak aLineBreak(*m_oLineBreakClear);
+ m_oLineBreakClear.reset();
+ pText->InsertItem(aLineBreak, nPos, nPos);
+ }
+
+ if (nLen < 1)
+ {
+ return;
+ }
+
+ sal_uInt8 nClear = pData[0];
+ if (nClear > 3)
+ {
+ return;
+ }
+
+ auto eClear = static_cast<SwLineBreakClear>(nClear);
+ m_oLineBreakClear = eClear;
+}
+
+void SwWW8ImplReader::Read_IdctHint( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ // sprmcidcthint (opcode 0x286f) specifies a script bias for the text in the run.
+ // for unicode characters that are shared between far east and non-far east scripts,
+ // this property determines what font and language the character will use.
+ // when this value is 0, text properties bias towards non-far east properties.
+ // when this value is 1, text properties bias towards far east properties.
+ // when this value is 2, text properties bias towards complex properties.
+ if (nLen < 1) //Property end
+ {
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(),RES_CHRATR_IDCTHINT);
+ }
+ else //Property start
+ {
+ NewAttr(SfxInt16Item(RES_CHRATR_IDCTHINT, *pData));
+ }
+}
+
+void SwWW8ImplReader::Read_Justify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
+ return;
+ }
+
+ SvxAdjust eAdjust(SvxAdjust::Left);
+ bool bDistributed = false;
+ switch (*pData)
+ {
+ default:
+ case 0:
+ break;
+ case 1:
+ eAdjust = SvxAdjust::Center;
+ break;
+ case 2:
+ eAdjust = SvxAdjust::Right;
+ break;
+ case 3:
+ eAdjust = SvxAdjust::Block;
+ break;
+ case 4:
+ eAdjust = SvxAdjust::Block;
+ bDistributed = true;
+ break;
+ }
+ SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
+ if (bDistributed)
+ aAdjust.SetLastBlock(SvxAdjust::Block);
+
+ NewAttr(aAdjust);
+ SetRelativeJustify( nId != NS_sprm::PJc80::val );
+}
+
+bool SwWW8ImplReader::IsRightToLeft()
+{
+ bool bRTL = false;
+ SprmResult aDir;
+ if (m_xPlcxMan)
+ aDir = m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PFBiDi::val);
+ if (aDir.pSprm && aDir.nRemainingData >= 1)
+ bRTL = *aDir.pSprm != 0;
+ else
+ {
+ const SvxFrameDirectionItem* pItem=
+ static_cast<const SvxFrameDirectionItem*>(GetFormatAttr(RES_FRAMEDIR));
+ if (pItem && (pItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB))
+ bRTL = true;
+ }
+ return bRTL;
+}
+
+void SwWW8ImplReader::Read_RTLJustify( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ADJUST );
+ return;
+ }
+
+ //If we are in a ltr paragraph this is the same as normal Justify,
+ //If we are in a rtl paragraph the meaning is reversed.
+ if (!IsRightToLeft())
+ Read_Justify(nId, pData, nLen);
+ else
+ {
+ SvxAdjust eAdjust(SvxAdjust::Right);
+ bool bDistributed = false;
+ switch (*pData)
+ {
+ default:
+ case 0:
+ break;
+ case 1:
+ eAdjust = SvxAdjust::Center;
+ break;
+ case 2:
+ eAdjust = SvxAdjust::Left;
+ break;
+ case 3:
+ eAdjust = SvxAdjust::Block;
+ break;
+ case 4:
+ eAdjust = SvxAdjust::Block;
+ bDistributed = true;
+ break;
+ }
+ SvxAdjustItem aAdjust(eAdjust, RES_PARATR_ADJUST);
+ if (bDistributed)
+ aAdjust.SetLastBlock(SvxAdjust::Block);
+
+ NewAttr(aAdjust);
+ SetRelativeJustify( true );
+ }
+}
+
+void SwWW8ImplReader::Read_BoolItem( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ switch( nId )
+ {
+ case NS_sprm::PFKinsoku::val:
+ nId = RES_PARATR_FORBIDDEN_RULES;
+ break;
+ case NS_sprm::PFOverflowPunct::val:
+ nId = RES_PARATR_HANGINGPUNCTUATION;
+ break;
+ case NS_sprm::PFAutoSpaceDE::val:
+ nId = RES_PARATR_SCRIPTSPACE;
+ break;
+ default:
+ OSL_ENSURE( false, "wrong Id" );
+ return ;
+ }
+
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), nId );
+ else
+ {
+ std::unique_ptr<SfxBoolItem> pI(static_cast<SfxBoolItem*>(GetDfltAttr( nId )->Clone()));
+ pI->SetValue( 0 != *pData );
+ NewAttr( *pI );
+ }
+}
+
+void SwWW8ImplReader::Read_Emphasis( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_EMPHASIS_MARK );
+ else
+ {
+ LanguageType nLang;
+ //Check to see if there is an up and coming cjk language property. If
+ //there is use it, if there is not fall back to the currently set one.
+ //Only the cjk language setting seems to matter to word, the western
+ //one is ignored
+ SprmResult aLang;
+ if (m_xPlcxMan)
+ aLang = m_xPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CRgLid1_80::val);
+
+ if (aLang.pSprm && aLang.nRemainingData >= 2)
+ nLang = LanguageType(SVBT16ToUInt16(aLang.pSprm));
+ else
+ {
+ nLang = static_cast<const SvxLanguageItem *>(
+ GetFormatAttr(RES_CHRATR_CJK_LANGUAGE))->GetLanguage();
+ }
+
+ FontEmphasisMark nVal;
+ switch( *pData )
+ {
+ case 0:
+ nVal = FontEmphasisMark::NONE;
+ break;
+ case 2:
+ if (MsLangId::isKorean(nLang) || MsLangId::isTraditionalChinese(nLang))
+ nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
+ else if (nLang == LANGUAGE_JAPANESE)
+ nVal = (FontEmphasisMark::Accent | FontEmphasisMark::PosAbove);
+ else
+ nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
+ break;
+ case 3:
+ nVal = (FontEmphasisMark::Circle | FontEmphasisMark::PosAbove);
+ break;
+ case 4:
+ nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
+ break;
+ case 1:
+ if (MsLangId::isSimplifiedChinese(nLang))
+ nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosBelow);
+ else
+ nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
+ break;
+ default:
+ nVal = (FontEmphasisMark::Dot | FontEmphasisMark::PosAbove);
+ break;
+ }
+
+ NewAttr( SvxEmphasisMarkItem( nVal, RES_CHRATR_EMPHASIS_MARK ) );
+ }
+}
+
+void SwWW8ImplReader::Read_ScaleWidth( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 2)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SCALEW );
+ else
+ {
+ sal_uInt16 nVal = SVBT16ToUInt16( pData );
+ //The number must be between 1 and 600
+ if (nVal < 1 || nVal > 600)
+ nVal = 100;
+ NewAttr( SvxCharScaleWidthItem( nVal, RES_CHRATR_SCALEW ) );
+ }
+}
+
+void SwWW8ImplReader::Read_Relief( sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_RELIEF );
+ else
+ {
+ if( *pData )
+ {
+// not so easy because this is also a toggle attribute!
+// 2 x emboss on -> no emboss !!!
+// the actual value must be searched over the stack / template
+
+ const SvxCharReliefItem* pOld = static_cast<const SvxCharReliefItem*>(
+ GetFormatAttr( RES_CHRATR_RELIEF ));
+ FontRelief nNewValue = NS_sprm::CFImprint::val == nId ? FontRelief::Engraved
+ : ( NS_sprm::CFEmboss::val == nId ? FontRelief::Embossed
+ : FontRelief::NONE );
+ if( pOld->GetValue() == nNewValue )
+ {
+ if( FontRelief::NONE != nNewValue )
+ nNewValue = FontRelief::NONE;
+ }
+ NewAttr( SvxCharReliefItem( nNewValue, RES_CHRATR_RELIEF ));
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_TextAnim(sal_uInt16 /*nId*/, const sal_uInt8* pData, short nLen)
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr(*m_pPaM->GetPoint(), RES_CHRATR_BLINK);
+ else
+ {
+ if (*pData)
+ {
+ bool bBlink;
+
+ // The 7 animated text effects available in word all get
+ // mapped to a blinking text effect in LibreOffice
+ // 0 no animation 1 Las Vegas lights
+ // 2 background blink 3 sparkle text
+ // 4 marching ants 5 marching red ants
+ // 6 shimmer
+ bBlink = *pData > 0 && *pData < 7;
+
+ NewAttr(SvxBlinkItem(bBlink, RES_CHRATR_BLINK));
+ }
+ }
+}
+
+SwWW8Shade::SwWW8Shade(bool bVer67, const WW8_SHD& rSHD)
+{
+ sal_uInt8 b = rSHD.GetFore();
+ OSL_ENSURE(b < 17, "ww8: colour out of range");
+ if (b >= 17)
+ b = 0;
+
+ Color nFore(SwWW8ImplReader::GetCol(b));
+
+ b = rSHD.GetBack();
+ OSL_ENSURE(b < 17, "ww8: colour out of range");
+ if( b >= 17 )
+ b = 0;
+
+ Color nBack(SwWW8ImplReader::GetCol(b));
+
+ b = rSHD.GetStyle(bVer67);
+
+ SetShade(nFore, nBack, b);
+}
+
+void SwWW8Shade::SetShade(Color nFore, Color nBack, sal_uInt16 nIndex)
+{
+ static const sal_uLong eMSGrayScale[] =
+ {
+ // Clear-Brush
+ 0, // 0 clear
+ // Solid-Brush
+ 1000, // 1 solid
+ // Percent values
+ 50, // 2 pct5
+ 100, // 3 pct10
+ 200, // 4 pct20
+ 250, // 5 pct25
+ 300, // 6 pct30
+ 400, // 7 pct40
+ 500, // 8 pct50
+ 600, // 9 pct60
+ 700, // 10 pct70
+ 750, // 11 pct75
+ 800, // 12 pct80
+ 900, // 13 pct90
+ // Special cases
+ 333, // 14 Dark Horizontal
+ 333, // 15 Dark Vertical
+ 333, // 16 Dark Forward Diagonal
+ 333, // 17 Dark Backward Diagonal
+ 333, // 18 Dark Cross
+ 333, // 19 Dark Diagonal Cross
+ 333, // 20 Horizontal
+ 333, // 21 Vertical
+ 333, // 22 Forward Diagonal
+ 333, // 23 Backward Diagonal
+ 333, // 24 Cross
+ 333, // 25 Diagonal Cross
+ // Undefined values in DOC spec-sheet
+ 500, // 26
+ 500, // 27
+ 500, // 28
+ 500, // 29
+ 500, // 30
+ 500, // 31
+ 500, // 32
+ 500, // 33
+ 500, // 34
+ // Different shading types
+ 25, // 35 [available in DOC, not available in DOCX]
+ 75, // 36 [available in DOC, not available in DOCX]
+ 125, // 37 pct12
+ 150, // 38 pct15
+ 175, // 39 [available in DOC, not available in DOCX]
+ 225, // 40 [available in DOC, not available in DOCX]
+ 275, // 41 [available in DOC, not available in DOCX]
+ 325, // 42 [available in DOC, not available in DOCX]
+ 350, // 43 pct35
+ 375, // 44 pct37
+ 425, // 45 [available in DOC, not available in DOCX]
+ 450, // 46 pct45
+ 475, // 47 [available in DOC, not available in DOCX]
+ 525, // 48 [available in DOC, not available in DOCX]
+ 550, // 49 pct55
+ 575, // 50 [available in DOC, not available in DOCX]
+ 625, // 51 pct62
+ 650, // 52 pct65
+ 675, // 53 [available in DOC, not available in DOCX]
+ 725, // 54 [available in DOC, not available in DOCX]
+ 775, // 55 [available in DOC, not available in DOCX]
+ 825, // 56 [available in DOC, not available in DOCX]
+ 850, // 57 pct85
+ 875, // 58 pct87
+ 925, // 59 [available in DOC, not available in DOCX]
+ 950, // 60 pct95
+ 975 // 61 [available in DOC, not available in DOCX]
+ };// 62
+
+ //NO auto for shading so Foreground: Auto = Black
+ if (nFore == COL_AUTO)
+ nFore = COL_BLACK;
+
+ //NO auto for shading so background: Auto = White
+ Color nUseBack = nBack;
+ if (nUseBack == COL_AUTO)
+ nUseBack = COL_WHITE;
+
+ if( nIndex >= SAL_N_ELEMENTS( eMSGrayScale ) )
+ nIndex = 0;
+
+ sal_uLong nWW8BrushStyle = eMSGrayScale[nIndex];
+
+ switch (nWW8BrushStyle)
+ {
+ case 0: // Null-Brush
+ m_aColor = nBack;
+ break;
+ default:
+ {
+ Color aForeColor(nFore);
+ Color aBackColor(nUseBack);
+
+ sal_uInt32 nRed = aForeColor.GetRed() * nWW8BrushStyle;
+ sal_uInt32 nGreen = aForeColor.GetGreen() * nWW8BrushStyle;
+ sal_uInt32 nBlue = aForeColor.GetBlue() * nWW8BrushStyle;
+ nRed += aBackColor.GetRed() * (1000 - nWW8BrushStyle);
+ nGreen += aBackColor.GetGreen()* (1000 - nWW8BrushStyle);
+ nBlue += aBackColor.GetBlue() * (1000 - nWW8BrushStyle);
+
+ m_aColor = Color( nRed/1000, nGreen/1000, nBlue/1000 );
+ }
+ break;
+ }
+}
+
+void SwWW8ImplReader::Read_Shade( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (!m_bVer67 && m_xPlcxMan && m_xPlcxMan->GetPapPLCF()->HasSprm(NS_sprm::PShd::val).pSprm)
+ return;
+
+ if (nLen < 2)
+ {
+ // end of attribute
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
+ }
+ else
+ {
+ WW8_SHD aSHD;
+ aSHD.SetWWValue( *reinterpret_cast<SVBT16 const *>(pData) );
+ SwWW8Shade aSh( m_bVer67, aSHD );
+
+ NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
+ NewAttr( XFillColorItem(OUString(), aSh.m_aColor) );
+ }
+}
+
+void SwWW8ImplReader::Read_ParaBackColor(sal_uInt16, const sal_uInt8* pData, short nLen)
+{
+ if (nLen <= 0)
+ {
+ // end of attribute
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLSTYLE );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), XATTR_FILLCOLOR );
+ }
+ else
+ {
+ OSL_ENSURE(nLen == 10, "Len of para back colour not 10!");
+ if (nLen != 10)
+ return;
+
+ const Color aColor = ExtractColour(pData, m_bVer67);
+ NewAttr( XFillColorItem(OUString(), aColor) );
+ if ( aColor == COL_AUTO )
+ NewAttr( XFillStyleItem(drawing::FillStyle_NONE) );
+ else
+ NewAttr( XFillStyleItem(drawing::FillStyle_SOLID) );
+ }
+}
+
+Color SwWW8ImplReader::ExtractColour(const sal_uInt8* &rpData, bool bVer67)
+{
+ OSL_ENSURE(!bVer67, "Impossible");
+ Color nFore = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
+ rpData+=4;
+ Color nBack = msfilter::util::BGRToRGB(SVBT32ToUInt32(rpData));
+ rpData+=4;
+ sal_uInt16 nIndex = SVBT16ToUInt16(rpData);
+ rpData+=2;
+ //Being a transparent background colour doesn't actually show the page
+ //background through, it merely acts like white
+ if (nBack == Color(ColorTransparency, 0xFF000000))
+ nBack = COL_AUTO;
+ OSL_ENSURE(nBack == COL_AUTO || !nBack.IsTransparent(),
+ "ww8: don't know what to do with such a transparent bg colour, report");
+ SwWW8Shade aShade(nFore, nBack, nIndex);
+ return aShade.m_aColor;
+}
+
+void SwWW8ImplReader::Read_TextVerticalAdjustment( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if( nLen <= 0 )
+ return;
+
+ drawing::TextVerticalAdjust nVA = drawing::TextVerticalAdjust_TOP;
+ switch( *pData )
+ {
+ case 1:
+ nVA = drawing::TextVerticalAdjust_CENTER;
+ break;
+ case 2: //justify
+ nVA = drawing::TextVerticalAdjust_BLOCK;
+ break;
+ case 3:
+ nVA = drawing::TextVerticalAdjust_BOTTOM;
+ break;
+ default:
+ break;
+ }
+ m_aSectionManager.SetCurrentSectionVerticalAdjustment( nVA );
+}
+
+void SwWW8ImplReader::Read_Border(sal_uInt16 , const sal_uInt8*, short nLen)
+{
+ if (nLen < 0)
+ {
+ if( m_bHasBorder )
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BOX );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_SHADOW );
+ m_bHasBorder = false;
+ }
+ }
+ else if( !m_bHasBorder )
+ {
+ // the borders on all four sides are bundled. That
+ // simplifies the administration, i.e., the box does not have
+ // to be put on and removed from CtrlStack 4 times.
+ m_bHasBorder = true;
+
+ WW8_BRCVer9_5 aBrcs; // Top, Left, Bottom, Right, Between
+ sal_uInt8 nBorder;
+
+ if( m_pCurrentColl )
+ nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, nullptr, m_xStyles.get());
+ else
+ nBorder = ::lcl_ReadBorders(m_bVer67, aBrcs, m_xPlcxMan ? m_xPlcxMan->GetPapPLCF() : nullptr);
+
+ if( nBorder ) // Border
+ {
+ bool bIsB = IsBorder(aBrcs, true);
+ if (!InLocalApo() || !bIsB || (m_xWFlyPara && !m_xWFlyPara->bBorderLines))
+ {
+ // Do not turn *on* borders in APO, since otherwise
+ // I get the Fly border twice;
+ // but only when it is set on in the Fly, skip it;
+ // otherwise there is none at all!
+
+ // even if no border is set, the attribute has to be set,
+ // otherwise it's not possible to turn off the style attribute.
+ const SvxBoxItem* pBox
+ = static_cast<const SvxBoxItem*>(GetFormatAttr( RES_BOX ));
+ std::shared_ptr<SvxBoxItem> aBox(std::make_shared<SvxBoxItem>(RES_BOX));
+ if (pBox)
+ aBox.reset(pBox->Clone());
+ short aSizeArray[5]={0};
+
+ SetBorder(*aBox, aBrcs, &aSizeArray[0], nBorder);
+
+ tools::Rectangle aInnerDist;
+ GetBorderDistance( aBrcs, aInnerDist );
+
+ if (nBorder & (1 << WW8_LEFT))
+ aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Left()), SvxBoxItemLine::LEFT );
+
+ if (nBorder & (1 << WW8_TOP))
+ aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Top()), SvxBoxItemLine::TOP );
+
+ if (nBorder & (1 << WW8_RIGHT))
+ aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Right()), SvxBoxItemLine::RIGHT );
+
+ if (nBorder & (1 << WW8_BOT))
+ aBox->SetDistance( o3tl::narrowing<sal_uInt16>(aInnerDist.Bottom()), SvxBoxItemLine::BOTTOM );
+
+ NewAttr( *aBox );
+
+ SvxShadowItem aS(RES_SHADOW);
+ // Word only allows shadows on visible borders
+ if ( aBox->CalcLineSpace( SvxBoxItemLine::RIGHT ) )
+ SetShadow( aS, &aSizeArray[0], aBrcs[WW8_RIGHT] );
+ NewAttr( aS );
+ }
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_CharBorder(sal_uInt16 nId, const sal_uInt8* pData, short nLen )
+{
+ //Ignore this old border type
+ //if (!bVer67 && pPlcxMan && pPlcxMan->GetChpPLCF()->HasSprm(NS_sprm::CBrc::val))
+ // return;
+
+ if (nLen < 0)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_BOX );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_CHRATR_SHADOW );
+ }
+ else
+ {
+ const SvxBoxItem* pBox
+ = static_cast<const SvxBoxItem*>(GetFormatAttr( RES_CHRATR_BOX ));
+ if( pBox )
+ {
+ std::unique_ptr<SvxBoxItem> aBoxItem(pBox->Clone());
+ WW8_BRCVer9 aBrc;
+ int nBrcVer = (nId == NS_sprm::CBrc::val) ? 9 : (m_bVer67 ? 6 : 8);
+
+ SetWW8_BRC(nBrcVer, aBrc, pData, nLen);
+
+ Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::TOP, 0, nullptr, true);
+ Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::BOTTOM, 0, nullptr, true);
+ Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::LEFT, 0, nullptr, true);
+ Set1Border(*aBoxItem, aBrc, SvxBoxItemLine::RIGHT, 0, nullptr, true);
+ NewAttr( *aBoxItem );
+
+ short aSizeArray[WW8_RIGHT+1]={0}; aSizeArray[WW8_RIGHT] = 1;
+ SvxShadowItem aShadowItem(RES_CHRATR_SHADOW);
+ // Word only allows shadows on visible borders
+ if ( aBoxItem->CalcLineSpace( SvxBoxItemLine::RIGHT ) )
+ SetShadow( aShadowItem, &aSizeArray[0], aBrc );
+ NewAttr( aShadowItem );
+ }
+ }
+}
+
+void SwWW8ImplReader::Read_Hyphenation( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ // set Hyphenation flag
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_HYPHENZONE );
+ else
+ {
+ SvxHyphenZoneItem aAttr(
+ *static_cast<const SvxHyphenZoneItem*>(GetFormatAttr( RES_PARATR_HYPHENZONE ) ));
+
+ aAttr.SetHyphen( 0 == *pData ); // sic !
+
+ if( !*pData )
+ {
+ aAttr.GetMinLead() = 2;
+ aAttr.GetMinTrail() = 2;
+ aAttr.GetMaxHyphens() = 0;
+ }
+
+ NewAttr( aAttr );
+ }
+}
+
+void SwWW8ImplReader::Read_WidowControl( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ {
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_WIDOWS );
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_ORPHANS );
+ }
+ else
+ {
+ sal_uInt8 nL = ( *pData & 1 ) ? 2 : 0;
+
+ NewAttr( SvxWidowsItem( nL, RES_PARATR_WIDOWS ) ); // Off -> nLines = 0
+ NewAttr( SvxOrphansItem( nL, RES_PARATR_ORPHANS ) );
+
+ if( m_pCurrentColl && m_xStyles ) // Style-Def ?
+ m_xStyles->mbWidowsChanged = true; // save for simulation
+ // Default-Widows
+ }
+}
+
+void SwWW8ImplReader::Read_UsePgsuSettings(sal_uInt16,const sal_uInt8* pData,short nLen)
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_SNAPTOGRID);
+ else
+ {
+ if(m_nInTable)
+ NewAttr( SvxParaGridItem(false, RES_PARATR_SNAPTOGRID) );
+ else
+ NewAttr( SvxParaGridItem(*pData, RES_PARATR_SNAPTOGRID) );
+ }
+}
+
+void SwWW8ImplReader::Read_AlignFont( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 2)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_VERTALIGN);
+ else
+ {
+ sal_uInt16 nVal = SVBT16ToUInt16( pData );
+ SvxParaVertAlignItem::Align nAlign;
+ switch (nVal)
+ {
+ case 0:
+ nAlign = SvxParaVertAlignItem::Align::Top;
+ break;
+ case 1:
+ nAlign = SvxParaVertAlignItem::Align::Center;
+ break;
+ case 2:
+ nAlign = SvxParaVertAlignItem::Align::Baseline;
+ break;
+ case 3:
+ nAlign = SvxParaVertAlignItem::Align::Bottom;
+ break;
+ case 4:
+ nAlign = SvxParaVertAlignItem::Align::Automatic;
+ break;
+ default:
+ nAlign = SvxParaVertAlignItem::Align::Automatic;
+ OSL_ENSURE(false,"Unknown paragraph vertical align");
+ break;
+ }
+ NewAttr( SvxParaVertAlignItem( nAlign, RES_PARATR_VERTALIGN ) );
+ }
+}
+
+void SwWW8ImplReader::Read_KeepLines( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_PARATR_SPLIT );
+ else
+ NewAttr( SvxFormatSplitItem( ( *pData & 1 ) == 0, RES_PARATR_SPLIT ) );
+}
+
+void SwWW8ImplReader::Read_KeepParas( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_KEEP );
+ else
+ NewAttr( SvxFormatKeepItem( ( *pData & 1 ) != 0 , RES_KEEP) );
+}
+
+void SwWW8ImplReader::Read_BreakBefore( sal_uInt16, const sal_uInt8* pData, short nLen )
+{
+ if (nLen < 1)
+ m_xCtrlStck->SetAttr( *m_pPaM->GetPoint(), RES_BREAK );
+ else
+ NewAttr( SvxFormatBreakItem(
+ ( *pData & 1 ) ? SvxBreak::PageBefore : SvxBreak::NONE, RES_BREAK ) );
+}
+
+void SwWW8ImplReader::Read_ApoPPC( sal_uInt16, const sal_uInt8* pData, short )
+{
+ if (m_pCurrentColl && m_nCurrentColl < m_vColl.size()) // only for Styledef, otherwise solved differently
+ {
+ SwWW8StyInf& rSI = m_vColl[m_nCurrentColl];
+ if (!rSI.m_xWWFly)
+ rSI.m_xWWFly = std::make_shared<WW8FlyPara>(m_bVer67);
+ rSI.m_xWWFly->Read(*pData, m_xStyles.get());
+ if (rSI.m_xWWFly->IsEmpty())
+ {
+ m_vColl[m_nCurrentColl].m_xWWFly.reset();
+ }
+ }
+}
+
+bool SwWW8ImplReader::ParseTabPos(WW8_TablePos *pTabPos, WW8PLCFx_Cp_FKP* pPap)
+{
+ bool bRet = false;
+ memset(pTabPos, 0, sizeof(WW8_TablePos));
+ // sprmTPc contains a PositionCodeOperand structure that specifies the origin
+ // that is used to calculate the table position when it is absolutely positioned
+ SprmResult aRes = pPap->HasSprm(NS_sprm::TPc::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 1)
+ {
+ pTabPos->nSp29 = *aRes.pSprm;
+ pTabPos->nSp37 = 2; //Possible fail area, always parallel wrap
+ aRes = pPap->HasSprm(NS_sprm::TDxaAbs::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 2)
+ pTabPos->nSp26 = SVBT16ToUInt16(aRes.pSprm);
+ aRes = pPap->HasSprm(NS_sprm::TDyaAbs::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 2)
+ pTabPos->nSp27 = SVBT16ToUInt16(aRes.pSprm);
+ aRes = pPap->HasSprm(NS_sprm::TDxaFromText::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 2)
+ pTabPos->nLeMgn = SVBT16ToUInt16(aRes.pSprm);
+ aRes = pPap->HasSprm(NS_sprm::TDxaFromTextRight::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 2)
+ pTabPos->nRiMgn = SVBT16ToUInt16(aRes.pSprm);
+ aRes = pPap->HasSprm(NS_sprm::TDyaFromText::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 2)
+ pTabPos->nUpMgn = SVBT16ToUInt16(aRes.pSprm);
+ aRes = pPap->HasSprm(NS_sprm::TDyaFromTextBottom::val);
+ if (aRes.pSprm && aRes.nRemainingData >= 2)
+ pTabPos->nLoMgn = SVBT16ToUInt16(aRes.pSprm);
+ pTabPos->bNoFly = !FloatingTableConversion(pPap);
+ bRet = true;
+ }
+ return bRet;
+}
+
+// page attribute won't be used as attribute anymore
+// ( except OLST )
+tools::Long SwWW8ImplReader::ImportExtSprm(WW8PLCFManResult* pRes)
+{
+ // array for reading of the extended ( self-defined ) SPRMs
+ typedef tools::Long (SwWW8ImplReader::*FNReadRecordExt)(WW8PLCFManResult*);
+
+ static const FNReadRecordExt aWwSprmTab[] =
+ {
+ /* 0 (256) */ &SwWW8ImplReader::Read_Footnote, // FootNote
+ /* 1 (257) */ &SwWW8ImplReader::Read_Footnote, // EndNote
+ /* 2 (258) */ &SwWW8ImplReader::Read_Field, // Field
+ /* 3 (259) */ &SwWW8ImplReader::Read_Book, // Bookmark
+ /* 4 (260) */ &SwWW8ImplReader::Read_And, // Annotation
+ /* 5 (261) */ &SwWW8ImplReader::Read_AtnBook, // Annotationmark
+ /* 6 (262) */ &SwWW8ImplReader::Read_FactoidBook // Smart tag bookmark
+ };
+
+ if( pRes->nSprmId < 280 )
+ {
+ sal_uInt8 nIdx = static_cast< sal_uInt8 >(pRes->nSprmId - eFTN);
+ if( nIdx < SAL_N_ELEMENTS(aWwSprmTab)
+ && aWwSprmTab[nIdx] )
+ return (this->*aWwSprmTab[nIdx])(pRes);
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+void SwWW8ImplReader::EndExtSprm(sal_uInt16 nSprmId)
+{
+ typedef sal_uInt16 (SwWW8ImplReader::*FNReadRecordExt)();
+
+ static const FNReadRecordExt aWwSprmTab[] =
+ {
+ /* 0 (256) */ &SwWW8ImplReader::End_Footnote, // FootNote
+ /* 1 (257) */ &SwWW8ImplReader::End_Footnote, // EndNote
+ /* 2 (258) */ &SwWW8ImplReader::End_Field, // Field
+ /* 3 (259) */ nullptr, // Bookmark
+ /* 4 (260) */ nullptr // Annotation
+ };
+
+ sal_uInt8 nIdx = static_cast< sal_uInt8 >(nSprmId - eFTN);
+ if( nIdx < SAL_N_ELEMENTS(aWwSprmTab)
+ && aWwSprmTab[nIdx] )
+ (this->*aWwSprmTab[nIdx])();
+}
+
+// arrays for reading the SPRMs
+
+// function for reading of SPRMs. Par1: SprmId
+typedef void (SwWW8ImplReader::*FNReadRecord)( sal_uInt16, const sal_uInt8*, short );
+
+struct SprmReadInfo
+{
+ sal_uInt16 nId;
+ FNReadRecord pReadFnc;
+};
+
+static bool operator<(const SprmReadInfo &rFirst, const SprmReadInfo &rSecond)
+{
+ return (rFirst.nId < rSecond.nId);
+}
+
+typedef ww::SortedArray<SprmReadInfo> wwSprmDispatcher;
+
+static const wwSprmDispatcher *GetWW2SprmDispatcher()
+{
+ static SprmReadInfo aSprms[] =
+ {
+ {0, nullptr}, // "0" default resp. error
+ // will be skipped! ,
+ {2, &SwWW8ImplReader::Read_StyleCode}, //"sprmPIstd", pap.istd
+ //(style code)
+ {3, nullptr}, //"sprmPIstdPermute", pap.istd
+ //permutation
+ {4, nullptr}, //"sprmPIncLv1",
+ //pap.istddifference
+ {5, &SwWW8ImplReader::Read_Justify}, //"sprmPJc", pap.jc
+ //(justification)
+ {6, nullptr}, //"sprmPFSideBySide",
+ //pap.fSideBySide
+ {7, &SwWW8ImplReader::Read_KeepLines}, //"sprmPFKeep", pap.fKeep
+ {8, &SwWW8ImplReader::Read_KeepParas}, //"sprmPFKeepFollow ",
+ //pap.fKeepFollow
+ {9, &SwWW8ImplReader::Read_BreakBefore}, //"sprmPPageBreakBefore",
+ //pap.fPageBreakBefore
+ {10, nullptr}, //"sprmPBrcl", pap.brcl
+ {11, nullptr}, //"sprmPBrcp ", pap.brcp
+ {12, &SwWW8ImplReader::Read_ANLevelDesc}, //"sprmPAnld", pap.anld (ANLD
+ //structure)
+ {13, &SwWW8ImplReader::Read_ANLevelNo}, //"sprmPNLvlAnm", pap.nLvlAnm
+ //nn
+ {14, &SwWW8ImplReader::Read_NoLineNumb}, //"sprmPFNoLineNumb", ap.fNoLnn
+ {15, &SwWW8ImplReader::Read_Tab}, //"?sprmPChgTabsPapx",
+ //pap.itbdMac, ...
+ {16, &SwWW8ImplReader::Read_LR}, //"sprmPDxaRight", pap.dxaRight
+ {17, &SwWW8ImplReader::Read_LR}, //"sprmPDxaLeft", pap.dxaLeft
+ {18, nullptr}, //"sprmPNest", pap.dxaLeft
+ {19, &SwWW8ImplReader::Read_LR}, //"sprmPDxaLeft1", pap.dxaLeft1
+ {20, &SwWW8ImplReader::Read_LineSpace}, //"sprmPDyaLine", pap.lspd
+ //an LSPD
+ {21, &SwWW8ImplReader::Read_UL}, //"sprmPDyaBefore",
+ //pap.dyaBefore
+ {22, &SwWW8ImplReader::Read_UL}, //"sprmPDyaAfter", pap.dyaAfter
+ {23, nullptr}, //"?sprmPChgTabs", pap.itbdMac,
+ //pap.rgdxaTab, ...
+ {24, nullptr}, //"sprmPFInTable", pap.fInTable
+ {25, &SwWW8ImplReader::Read_TabRowEnd}, //"sprmPTtp", pap.fTtp
+ {26, nullptr}, //"sprmPDxaAbs", pap.dxaAbs
+ {27, nullptr}, //"sprmPDyaAbs", pap.dyaAbs
+ {28, nullptr}, //"sprmPDxaWidth", pap.dxaWidth
+ {29, &SwWW8ImplReader::Read_ApoPPC}, //"sprmPPc", pap.pcHorz,
+ //pap.pcVert
+ {30, nullptr}, //"sprmPBrcTop10", pap.brcTop
+ //BRC10
+ {31, nullptr}, //"sprmPBrcLeft10",
+ //pap.brcLeft BRC10
+ {32, nullptr}, //"sprmPBrcBottom10",
+ //pap.brcBottom BRC10
+ {33, nullptr}, //"sprmPBrcRight10",
+ //pap.brcRight BRC10
+ {34, nullptr}, //"sprmPBrcBetween10",
+ //pap.brcBetween BRC10
+ {35, nullptr}, //"sprmPBrcBar10", pap.brcBar
+ //BRC10
+ {36, nullptr}, //"sprmPFromText10",
+ //pap.dxaFromText dxa
+ {37, nullptr}, //"sprmPWr", pap.wr wr
+ {38, &SwWW8ImplReader::Read_Border}, //"sprmPBrcTop", pap.brcTop BRC
+ {39, &SwWW8ImplReader::Read_Border}, //"sprmPBrcLeft",
+ //pap.brcLeft BRC
+ {40, &SwWW8ImplReader::Read_Border}, //"sprmPBrcBottom",
+ //pap.brcBottom BRC
+ {41, &SwWW8ImplReader::Read_Border}, //"sprmPBrcRight",
+ //pap.brcRight BRC
+ {42, &SwWW8ImplReader::Read_Border}, //"sprmPBrcBetween",
+ //pap.brcBetween BRC
+ {43, nullptr}, //"sprmPBrcBar", pap.brcBar
+ //BRC word
+ {44, &SwWW8ImplReader::Read_Hyphenation}, //"sprmPFNoAutoHyph",
+ //pap.fNoAutoHyph
+ {45, nullptr}, //"sprmPWHeightAbs",
+ //pap.wHeightAbs w
+ {46, nullptr}, //"sprmPDcs", pap.dcs DCS
+ {47, &SwWW8ImplReader::Read_Shade}, //"sprmPShd", pap.shd SHD
+ {48, nullptr}, //"sprmPDyaFromText",
+ //pap.dyaFromText dya
+ {49, nullptr}, //"sprmPDxaFromText",
+ //pap.dxaFromText dxa
+ {50, nullptr}, //"sprmPFLocked", pap.fLocked
+ //0 or 1 byte
+ {51, &SwWW8ImplReader::Read_WidowControl}, //"sprmPFWidowControl",
+ //pap.fWidowControl 0 or 1 byte
+ {52, nullptr}, //"?sprmPRuler 52",
+ {53, nullptr}, //"??53",
+ {54, nullptr}, //"??54",
+ {55, nullptr}, //"??55",
+ {56, nullptr}, //"??56",
+ {57, nullptr}, //"??57",
+ {58, nullptr}, //"??58",
+ {59, nullptr}, //"??59",
+
+ {60, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFBold", chp.fBold 0,1,
+ //128, or 129 byte
+ {61, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFItalic", chp.fItalic
+ //0,1, 128, or 129 byte
+ {62, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFStrike", chp.fStrike
+ //0,1, 128, or 129 byte
+ {63, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFOutline", chp.fOutline
+ //0,1, 128, or 129 byte
+ {64, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFShadow", chp.fShadow
+ //0,1, 128, or 129 byte
+ {65, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFSmallCaps",
+ //chp.fSmallCaps 0,1, 128, or
+ //129 byte
+ {66, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFCaps", chp.fCaps 0,1,
+ //128, or 129 byte
+ {67, &SwWW8ImplReader::Read_BoldUsw}, //"sprmCFVanish", chp.fVanish
+ //0,1, 128, or 129 byte
+ {68, &SwWW8ImplReader::Read_FontCode}, //"sprmCFtc", chp.ftc ftc word
+ {69, &SwWW8ImplReader::Read_Underline}, // "sprmCKul", chp.kul kul byte
+ {70, nullptr}, //"sprmCSizePos", chp.hps,
+ //chp.hpsPos 3 bytes
+ {71, &SwWW8ImplReader::Read_Kern}, //"sprmCDxaSpace",
+ //chp.dxaSpace dxa word
+ {72, &SwWW8ImplReader::Read_Language}, //"sprmCLid", chp.lid LID word
+ {73, &SwWW8ImplReader::Read_TextColor}, //"sprmCIco", chp.ico ico byte
+ {74, &SwWW8ImplReader::Read_FontSize}, //"sprmCHps", chp.hps hps word!
+ {75, nullptr}, //"sprmCHpsInc", chp.hps byte
+ {76, &SwWW8ImplReader::Read_SubSuperProp}, //"sprmCHpsPos", chp.hpsPos
+ //hps byte
+ {77, nullptr}, //"sprmCHpsPosAdj", chp.hpsPos
+ //hps byte
+ {78, &SwWW8ImplReader::Read_Majority}, //"?sprmCMajority", chp.fBold,
+ //chp.fItalic, chp.fSmallCaps
+ {80, &SwWW8ImplReader::Read_BoldBiDiUsw}, //sprmCFBoldBi
+ {81, &SwWW8ImplReader::Read_BoldBiDiUsw}, //sprmCFItalicBi
+ {82, &SwWW8ImplReader::Read_FontCode}, //sprmCFtcBi
+ {83, &SwWW8ImplReader::Read_Language}, //sprmClidBi
+ {84, &SwWW8ImplReader::Read_TextColor}, //sprmCIcoBi
+ {85, &SwWW8ImplReader::Read_FontSize}, //sprmCHpsBi
+ {86, nullptr}, //sprmCFBiDi
+ {87, nullptr}, //sprmCFDiacColor
+ {94, nullptr}, //"sprmPicBrcl", pic.brcl brcl
+ //(see PIC structure
+ //definition) byte
+ {95, nullptr}, //"sprmPicScale", pic.mx,
+ //pic.my, pic.dxaCropleft,
+ {96, nullptr}, //"sprmPicBrcTop", pic.brcTop
+ //BRC word
+ {97, nullptr}, //"sprmPicBrcLeft",
+ //pic.brcLeft BRC word
+ {98, nullptr}, //"sprmPicBrcBottom",
+ //pic.brcBottom BRC word
+ {99, nullptr} //"sprmPicBrcRight",
+ };
+
+ static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
+ return &aSprmSrch;
+}
+
+static const wwSprmDispatcher *GetWW6SprmDispatcher()
+{
+ static SprmReadInfo aSprms[] =
+ {
+ {0, nullptr}, // "0" default resp. error
+ // will be skipped!
+ {NS_sprm::v6::sprmPIstd, &SwWW8ImplReader::Read_StyleCode}, // pap.istd (style code)
+ {NS_sprm::v6::sprmPIstdPermute, nullptr}, // pap.istd permutation
+ {NS_sprm::v6::sprmPIncLv1, nullptr}, // pap.istddifference
+ {NS_sprm::v6::sprmPJc, &SwWW8ImplReader::Read_Justify}, // pap.jc (justification)
+ {NS_sprm::v6::sprmPFSideBySide, nullptr}, // pap.fSideBySide
+ {NS_sprm::v6::sprmPFKeep, &SwWW8ImplReader::Read_KeepLines}, // pap.fKeep
+ {NS_sprm::v6::sprmPFKeepFollow, &SwWW8ImplReader::Read_KeepParas}, // pap.fKeepFollow
+ {NS_sprm::v6::sprmPPageBreakBefore, &SwWW8ImplReader::Read_BreakBefore}, // pap.fPageBreakBefore
+ {NS_sprm::v6::sprmPBrcl, nullptr}, // pap.brcl
+ {NS_sprm::v6::sprmPBrcp, nullptr}, // pap.brcp
+ {NS_sprm::v6::sprmPAnld, &SwWW8ImplReader::Read_ANLevelDesc}, // pap.anld (ANLD structure)
+ {NS_sprm::v6::sprmPNLvlAnm, &SwWW8ImplReader::Read_ANLevelNo}, // pap.nLvlAnm nn
+ {NS_sprm::v6::sprmPFNoLineNumb, &SwWW8ImplReader::Read_NoLineNumb}, // ap.fNoLnn
+ {NS_sprm::v6::sprmPChgTabsPapx, &SwWW8ImplReader::Read_Tab}, // pap.itbdMac, ...
+ {NS_sprm::v6::sprmPDxaRight, &SwWW8ImplReader::Read_LR}, // pap.dxaRight
+ {NS_sprm::v6::sprmPDxaLeft, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft
+ {NS_sprm::v6::sprmPNest, nullptr}, // pap.dxaLeft
+ {NS_sprm::v6::sprmPDxaLeft1, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft1
+ {NS_sprm::v6::sprmPDyaLine, &SwWW8ImplReader::Read_LineSpace}, // pap.lspd an LSPD
+ {NS_sprm::v6::sprmPDyaBefore, &SwWW8ImplReader::Read_UL}, // pap.dyaBefore
+ {NS_sprm::v6::sprmPDyaAfter, &SwWW8ImplReader::Read_UL}, // pap.dyaAfter
+ {NS_sprm::v6::sprmPChgTabs, nullptr}, // pap.itbdMac, pap.rgdxaTab, ...
+ {NS_sprm::v6::sprmPFInTable, nullptr}, // pap.fInTable
+ {NS_sprm::v6::sprmPTtp, &SwWW8ImplReader::Read_TabRowEnd}, // pap.fTtp
+ {NS_sprm::v6::sprmPDxaAbs, nullptr}, // pap.dxaAbs
+ {NS_sprm::v6::sprmPDyaAbs, nullptr}, // pap.dyaAbs
+ {NS_sprm::v6::sprmPDxaWidth, nullptr}, // pap.dxaWidth
+ {NS_sprm::v6::sprmPPc, &SwWW8ImplReader::Read_ApoPPC}, // pap.pcHorz, pap.pcVert
+ {NS_sprm::v6::sprmPBrcTop10, nullptr}, // pap.brcTop BRC10
+ {NS_sprm::v6::sprmPBrcLeft10, nullptr}, // pap.brcLeft BRC10
+ {NS_sprm::v6::sprmPBrcBottom10, nullptr}, // pap.brcBottom BRC10
+ {NS_sprm::v6::sprmPBrcRight10, nullptr}, // pap.brcRight BRC10
+ {NS_sprm::v6::sprmPBrcBetween10, nullptr}, // pap.brcBetween BRC10
+ {NS_sprm::v6::sprmPBrcBar10, nullptr}, // pap.brcBar BRC10
+ {NS_sprm::v6::sprmPFromText10, nullptr}, // pap.dxaFromText dxa
+ {NS_sprm::v6::sprmPWr, nullptr}, // pap.wr wr
+ {NS_sprm::v6::sprmPBrcTop, &SwWW8ImplReader::Read_Border}, // pap.brcTop BRC
+ {NS_sprm::v6::sprmPBrcLeft, &SwWW8ImplReader::Read_Border}, // pap.brcLeft BRC
+ {NS_sprm::v6::sprmPBrcBottom, &SwWW8ImplReader::Read_Border}, // pap.brcBottom BRC
+ {NS_sprm::v6::sprmPBrcRight, &SwWW8ImplReader::Read_Border}, // pap.brcRight BRC
+ {NS_sprm::v6::sprmPBrcBetween, &SwWW8ImplReader::Read_Border}, // pap.brcBetween BRC
+ {NS_sprm::v6::sprmPBrcBar, nullptr}, // pap.brcBar BRC word
+ {NS_sprm::v6::sprmPFNoAutoHyph, &SwWW8ImplReader::Read_Hyphenation}, // pap.fNoAutoHyph
+ {NS_sprm::v6::sprmPWHeightAbs, nullptr}, // pap.wHeightAbs w
+ {NS_sprm::v6::sprmPDcs, nullptr}, // pap.dcs DCS
+ {NS_sprm::v6::sprmPShd, &SwWW8ImplReader::Read_Shade}, // pap.shd SHD
+ {NS_sprm::v6::sprmPDyaFromText, nullptr}, // pap.dyaFromText dya
+ {NS_sprm::v6::sprmPDxaFromText, nullptr}, // pap.dxaFromText dxa
+ {NS_sprm::v6::sprmPFLocked, nullptr}, // pap.fLocked 0 or 1 byte
+ {NS_sprm::v6::sprmPFWidowControl, &SwWW8ImplReader::Read_WidowControl}, // pap.fWidowControl 0 or 1 byte
+ {NS_sprm::v6::sprmPRuler, nullptr},
+ {53, nullptr}, //"??53",
+ {54, nullptr}, //"??54",
+ {55, nullptr}, //"??55",
+ {56, nullptr}, //"??56",
+ {57, nullptr}, //"??57",
+ {58, nullptr}, //"??58",
+ {59, nullptr}, //"??59",
+ {60, nullptr}, //"??60",
+ {61, nullptr}, //"??61",
+ {62, nullptr}, //"??62",
+ {63, nullptr}, //"??63",
+ {64, &SwWW8ImplReader::Read_ParaBiDi}, //"rtl bidi ?
+ {NS_sprm::v6::sprmCFStrikeRM, &SwWW8ImplReader::Read_CFRMarkDel}, // chp.fRMarkDel 1 or 0 bit
+ {NS_sprm::v6::sprmCFRMark, &SwWW8ImplReader::Read_CFRMark}, // chp.fRMark 1 or 0 bit
+ {NS_sprm::v6::sprmCFFldVanish, &SwWW8ImplReader::Read_FieldVanish}, // chp.fFieldVanish 1 or 0 bit
+ {NS_sprm::v6::sprmCPicLocation, &SwWW8ImplReader::Read_PicLoc}, // chp.fcPic and chp.fSpec
+ {NS_sprm::v6::sprmCIbstRMark, nullptr}, // chp.ibstRMark index into sttbRMark
+ {NS_sprm::v6::sprmCDttmRMark, nullptr}, // chp.dttm DTTM long
+ {NS_sprm::v6::sprmCFData, nullptr}, // chp.fData 1 or 0 bit
+ {NS_sprm::v6::sprmCRMReason, nullptr}, // chp.idslRMReason an index to a table
+ {NS_sprm::v6::sprmCChse, &SwWW8ImplReader::Read_CharSet}, // chp.fChsDiff and chp.chse 3 bytes
+ {NS_sprm::v6::sprmCSymbol, &SwWW8ImplReader::Read_Symbol}, // chp.fSpec, chp.chSym and chp.ftcSym
+ {NS_sprm::v6::sprmCFOle2, &SwWW8ImplReader::Read_Obj}, // chp.fOle2 1 or 0 bit
+ {76, nullptr}, //"??76",
+ {77, nullptr}, //"??77",
+ {78, nullptr}, //"??78",
+ {79, nullptr}, //"??79",
+ {NS_sprm::v6::sprmCIstd, &SwWW8ImplReader::Read_CColl}, // chp.istd istd, see stylesheet definition; short
+ {NS_sprm::v6::sprmCIstdPermute, nullptr}, // chp.istd permutation vector
+ {NS_sprm::v6::sprmCDefault, nullptr}, // whole CHP none variable length
+ {NS_sprm::v6::sprmCPlain, nullptr}, // whole CHP none 0
+ {84, nullptr}, //"??84",
+ {NS_sprm::v6::sprmCFBold, &SwWW8ImplReader::Read_BoldUsw}, // chp.fBold 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFItalic, &SwWW8ImplReader::Read_BoldUsw}, // chp.fItalic 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFStrike, &SwWW8ImplReader::Read_BoldUsw}, // chp.fStrike 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFOutline, &SwWW8ImplReader::Read_BoldUsw}, // chp.fOutline 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFShadow, &SwWW8ImplReader::Read_BoldUsw}, // chp.fShadow 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFSmallCaps, &SwWW8ImplReader::Read_BoldUsw}, // chp.fSmallCaps 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFCaps, &SwWW8ImplReader::Read_BoldUsw}, // chp.fCaps 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFVanish, &SwWW8ImplReader::Read_BoldUsw}, // chp.fVanish 0,1, 128, or 129 byte
+ {NS_sprm::v6::sprmCFtc, &SwWW8ImplReader::Read_FontCode}, // chp.ftc ftc word
+ {NS_sprm::v6::sprmCKul, &SwWW8ImplReader::Read_Underline}, // chp.kul kul byte
+ {NS_sprm::v6::sprmCSizePos, nullptr}, // chp.hps, chp.hpsPos 3 bytes
+ {NS_sprm::v6::sprmCDxaSpace, &SwWW8ImplReader::Read_Kern}, // chp.dxaSpace dxa word
+ {NS_sprm::v6::sprmCLid, &SwWW8ImplReader::Read_Language}, // chp.lid LID word
+ {NS_sprm::v6::sprmCIco, &SwWW8ImplReader::Read_TextColor}, // chp.ico ico byte
+ {NS_sprm::v6::sprmCHps, &SwWW8ImplReader::Read_FontSize}, // chp.hps hps word!
+ {NS_sprm::v6::sprmCHpsInc, nullptr}, // chp.hps byte
+ {NS_sprm::v6::sprmCHpsPos, &SwWW8ImplReader::Read_SubSuperProp}, // chp.hpsPos hps byte
+ {NS_sprm::v6::sprmCHpsPosAdj, nullptr}, // chp.hpsPos hps byte
+ {NS_sprm::v6::sprmCMajority, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fSmallCaps
+ {NS_sprm::v6::sprmCIss, &SwWW8ImplReader::Read_SubSuper}, // chp.iss iss byte
+ {NS_sprm::v6::sprmCHpsNew50, nullptr}, // chp.hps hps variable width, length always recorded as 2
+ {NS_sprm::v6::sprmCHpsInc1, nullptr}, // chp.hps complex variable width, length always recorded as 2
+ {NS_sprm::v6::sprmCHpsKern, &SwWW8ImplReader::Read_FontKern}, // chp.hpsKern hps short
+ {NS_sprm::v6::sprmCMajority50, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fSmallCaps, chp.fVanish, ...
+ {NS_sprm::v6::sprmCHpsMul, nullptr}, // chp.hps percentage to grow hps short
+ {NS_sprm::v6::sprmCCondHyhen, nullptr}, // chp.ysri ysri short
+ {111, &SwWW8ImplReader::Read_AmbiguousSPRM},//sprmCFBoldBi or font code
+ {112, &SwWW8ImplReader::Read_AmbiguousSPRM},//sprmCFItalicBi or font code
+ {113, &SwWW8ImplReader::Read_FontCode}, //sprmCFtcBi
+ {114, &SwWW8ImplReader::Read_Language}, //sprmClidBi
+ {115, &SwWW8ImplReader::Read_TextColor}, //sprmCIcoBi
+ {116, &SwWW8ImplReader::Read_FontSize}, //sprmCHpsBi
+ {NS_sprm::v6::sprmCFSpec, &SwWW8ImplReader::Read_Special}, // chp.fSpec 1 or 0 bit
+ {NS_sprm::v6::sprmCFObj, &SwWW8ImplReader::Read_Obj}, // chp.fObj 1 or 0 bit
+ {NS_sprm::v6::sprmPicBrcl, nullptr}, // pic.brcl brcl (see PIC structure definition) byte
+ {NS_sprm::v6::sprmPicScale, nullptr}, // pic.mx, pic.my, pic.dxaCropleft,
+ {NS_sprm::v6::sprmPicBrcTop, nullptr}, // pic.brcTop BRC word
+ {NS_sprm::v6::sprmPicBrcLeft, nullptr}, // pic.brcLeft BRC word
+ {NS_sprm::v6::sprmPicBrcBottom, nullptr}, // pic.brcBottom BRC word
+ {NS_sprm::v6::sprmPicBrcRight, nullptr}, // pic.brcRight BRC word
+ {125, nullptr}, //"??125",
+ {126, nullptr}, //"??126",
+ {127, nullptr}, //"??127",
+ {128, nullptr}, //"??128",
+ {129, nullptr}, //"??129",
+ {130, nullptr}, //"??130",
+ {NS_sprm::v6::sprmSScnsPgn, nullptr}, // sep.cnsPgn cns byte
+ {NS_sprm::v6::sprmSiHeadingPgn, nullptr}, // sep.iHeadingPgn heading number level byte
+ {NS_sprm::v6::sprmSOlstAnm, &SwWW8ImplReader::Read_OLST}, // sep.olstAnm OLST variable length
+ {134, nullptr}, //"??135",
+ {135, nullptr}, //"??135",
+ {NS_sprm::v6::sprmSDxaColWidth, nullptr}, // sep.rgdxaColWidthSpacing complex 3 bytes
+ {NS_sprm::v6::sprmSDxaColSpacing, nullptr}, // sep.rgdxaColWidthSpacing complex 3 bytes
+ {NS_sprm::v6::sprmSFEvenlySpaced, nullptr}, // sep.fEvenlySpaced 1 or 0 byte
+ {NS_sprm::v6::sprmSFProtected, nullptr}, // sep.fUnlocked 1 or 0 byte
+ {NS_sprm::v6::sprmSDmBinFirst, nullptr}, // sep.dmBinFirst word
+ {NS_sprm::v6::sprmSDmBinOther, nullptr}, // sep.dmBinOther word
+ {NS_sprm::v6::sprmSBkc, nullptr}, // sep.bkc bkc byte BreakCode
+ {NS_sprm::v6::sprmSFTitlePage, nullptr}, // sep.fTitlePage 0 or 1 byte
+ {NS_sprm::v6::sprmSCcolumns, nullptr}, // sep.ccolM1 # of cols - 1 word
+ {NS_sprm::v6::sprmSDxaColumns, nullptr}, // sep.dxaColumns dxa word
+ {NS_sprm::v6::sprmSFAutoPgn, nullptr}, // sep.fAutoPgn obsolete byte
+ {NS_sprm::v6::sprmSNfcPgn, nullptr}, // sep.nfcPgn nfc byte
+ {NS_sprm::v6::sprmSDyaPgn, nullptr}, // sep.dyaPgn dya short
+ {NS_sprm::v6::sprmSDxaPgn, nullptr}, // sep.dxaPgn dya short
+ {NS_sprm::v6::sprmSFPgnRestart, nullptr}, // sep.fPgnRestart 0 or 1 byte
+ {NS_sprm::v6::sprmSFEndnote, nullptr}, // sep.fEndnote 0 or 1 byte
+ {NS_sprm::v6::sprmSLnc, nullptr}, // sep.lnc lnc byte
+ {NS_sprm::v6::sprmSGprfIhdt, nullptr}, // sep.grpfIhdt grpfihdt byte
+ {NS_sprm::v6::sprmSNLnnMod, nullptr}, // sep.nLnnMod non-neg int. word
+ {NS_sprm::v6::sprmSDxaLnn, nullptr}, // sep.dxaLnn dxa word
+ {NS_sprm::v6::sprmSDyaHdrTop, nullptr}, // sep.dyaHdrTop dya word
+ {NS_sprm::v6::sprmSDyaHdrBottom, nullptr}, // sep.dyaHdrBottom dya word
+ {NS_sprm::v6::sprmSLBetween, nullptr}, // sep.fLBetween 0 or 1 byte
+ {NS_sprm::v6::sprmSVjc, nullptr}, // sep.vjc vjc byte
+ {NS_sprm::v6::sprmSLnnMin, nullptr}, // sep.lnnMin lnn word
+ {NS_sprm::v6::sprmSPgnStart, nullptr}, // sep.pgnStart pgn word
+ {NS_sprm::v6::sprmSBOrientation, nullptr}, // sep.dmOrientPage dm byte
+ {NS_sprm::v6::sprmSBCustomize, nullptr}, // ?
+ {NS_sprm::v6::sprmSXaPage, nullptr}, // sep.xaPage xa word
+ {NS_sprm::v6::sprmSYaPage, nullptr}, // sep.yaPage ya word
+ {NS_sprm::v6::sprmSDxaLeft, nullptr}, // sep.dxaLeft dxa word
+ {NS_sprm::v6::sprmSDxaRight, nullptr}, // sep.dxaRight dxa word
+ {NS_sprm::v6::sprmSDyaTop, nullptr}, // sep.dyaTop dya word
+ {NS_sprm::v6::sprmSDyaBottom, nullptr}, // sep.dyaBottom dya word
+ {NS_sprm::v6::sprmSDzaGutter, nullptr}, // sep.dzaGutter dza word
+ {NS_sprm::v6::sprmSDMPaperReq, nullptr}, // sep.dmPaperReq dm word
+ {172, nullptr}, //"??172",
+ {173, nullptr}, //"??173",
+ {174, nullptr}, //"??174",
+ {175, nullptr}, //"??175",
+ {176, nullptr}, //"??176",
+ {177, nullptr}, //"??177",
+ {178, nullptr}, //"??178",
+ {179, nullptr}, //"??179",
+ {180, nullptr}, //"??180",
+ {181, nullptr}, //"??181",
+ {NS_sprm::v6::sprmTJc, nullptr}, // tap.jc jc word (low order byte is significant)
+ {NS_sprm::v6::sprmTDxaLeft, nullptr}, // tap.rgdxaCenter dxa word
+ {NS_sprm::v6::sprmTDxaGapHalf, nullptr}, // tap.dxaGapHalf, tap.rgdxaCenter dxa word
+ {NS_sprm::v6::sprmTFCantSplit, nullptr}, // tap.fCantSplit 1 or 0 byte
+ {NS_sprm::v6::sprmTTableHeader, nullptr}, // tap.fTableHeader 1 or 0 byte
+ {NS_sprm::v6::sprmTTableBorders, nullptr}, // tap.rgbrcTable complex 12 bytes
+ {NS_sprm::v6::sprmTDefTable10, nullptr}, // tap.rgdxaCenter, tap.rgtc complex variable length
+ {NS_sprm::v6::sprmTDyaRowHeight, nullptr}, // tap.dyaRowHeight dya word
+ {NS_sprm::v6::sprmTDefTable, nullptr}, // tap.rgtc complex
+ {NS_sprm::v6::sprmTDefTableShd, nullptr}, // tap.rgshd complex
+ {NS_sprm::v6::sprmTTlp, nullptr}, // tap.tlp TLP 4 bytes
+ {NS_sprm::v6::sprmTSetBrc, nullptr}, // tap.rgtc[].rgbrc complex 5 bytes
+ {NS_sprm::v6::sprmTInsert, nullptr}, // tap.rgdxaCenter, tap.rgtc complex 4 bytes
+ {NS_sprm::v6::sprmTDelete, nullptr}, // tap.rgdxaCenter, tap.rgtc complex word
+ {NS_sprm::v6::sprmTDxaCol, nullptr}, // tap.rgdxaCenter complex 4 bytes
+ {NS_sprm::v6::sprmTMerge, nullptr}, // tap.fFirstMerged, tap.fMerged complex word
+ {NS_sprm::v6::sprmTSplit, nullptr}, // tap.fFirstMerged, tap.fMerged complex word
+ {NS_sprm::v6::sprmTSetBrc10, nullptr}, // tap.rgtc[].rgbrc complex 5 bytes
+ {NS_sprm::v6::sprmTSetShd, nullptr}, // tap.rgshd complex 4 bytes
+ {207, nullptr}, //dunno
+ };
+
+ static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
+ return &aSprmSrch;
+}
+
+static const wwSprmDispatcher *GetWW8SprmDispatcher()
+{
+ static SprmReadInfo aSprms[] =
+ {
+ {0, nullptr}, // "0" default resp. error
+
+ {NS_sprm::PIstd::val, &SwWW8ImplReader::Read_StyleCode}, // pap.istd;istd (style code);short;
+ {NS_sprm::PIstdPermute::val, nullptr}, // pap.istd;permutation vector;
+ // variable length;
+ {NS_sprm::PIncLvl::val, nullptr}, // pap.istd, pap.lvl;difference between
+ // istd of base PAP and istd of
+ // PAP to be produced;byte;
+ {NS_sprm::PJc80::val, &SwWW8ImplReader::Read_Justify}, // pap.jc;jc (justification);byte;
+ {NS_sprm::LN_PFSideBySide, nullptr}, // pap.fSideBySide;0 or 1;byte;
+ {NS_sprm::PFKeep::val, &SwWW8ImplReader::Read_KeepLines}, // pap.fKeep;0 or 1;byte;
+ {NS_sprm::PFKeepFollow::val, &SwWW8ImplReader::Read_KeepParas}, // pap.fKeepFollow;0 or 1;byte;
+ {NS_sprm::PFPageBreakBefore::val, &SwWW8ImplReader::Read_BreakBefore}, // pap.fPageBreakBefore;0 or 1;byte;
+ {NS_sprm::LN_PBrcl, nullptr}, // pap.brcl;brcl;byte;
+ {NS_sprm::LN_PBrcp, nullptr}, // pap.brcp;brcp;byte;
+ {NS_sprm::PIlvl::val, &SwWW8ImplReader::Read_ListLevel}, // pap.ilvl;ilvl;byte;
+ {NS_sprm::PIlfo::val, &SwWW8ImplReader::Read_LFOPosition}, // pap.ilfo;ilfo (list index);short;
+ {NS_sprm::PFNoLineNumb::val, &SwWW8ImplReader::Read_NoLineNumb}, // pap.fNoLnn;0 or 1;byte;
+ {NS_sprm::PChgTabsPapx::val, &SwWW8ImplReader::Read_Tab}, // pap.itbdMac, pap.rgdxaTab, pap.rgtbd;
+ // complex;variable length
+ {NS_sprm::PDxaRight80::val, &SwWW8ImplReader::Read_LR}, // pap.dxaRight;dxa;word;
+ {NS_sprm::PDxaLeft80::val, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft;dxa;word;
+ {NS_sprm::PNest80::val, nullptr}, // pap.dxaLeft;dxa;word;
+ {NS_sprm::PDxaLeft180::val, &SwWW8ImplReader::Read_LR}, // pap.dxaLeft1;dxa;word;
+ {NS_sprm::PDyaLine::val, &SwWW8ImplReader::Read_LineSpace}, // pap.lspd;an LSPD, a long word
+ // structure consisting of a short
+ // of dyaLine followed by a short
+ // of fMultLinespace;long;
+ {NS_sprm::PDyaBefore::val, &SwWW8ImplReader::Read_UL}, // pap.dyaBefore;dya;word;
+ {NS_sprm::PDyaAfter::val, &SwWW8ImplReader::Read_UL}, // pap.dyaAfter;dya;word;
+ {NS_sprm::PChgTabs::val, nullptr}, // pap.itbdMac, pap.rgdxaTab, pap.rgtbd;
+ // complex;variable length;
+ {NS_sprm::PFInTable::val, nullptr}, // pap.fInTable;0 or 1;byte;
+ {NS_sprm::PFTtp::val, &SwWW8ImplReader::Read_TabRowEnd}, // pap.fTtp;0 or 1;byte;
+ {NS_sprm::PDxaAbs::val, nullptr}, // pap.dxaAbs;dxa;word;
+ {NS_sprm::PDyaAbs::val, nullptr}, // pap.dyaAbs;dya;word;
+ {NS_sprm::PDxaWidth::val, nullptr}, // pap.dxaWidth;dxa;word;
+ {NS_sprm::PPc::val, &SwWW8ImplReader::Read_ApoPPC}, // pap.pcHorz, pap.pcVert;complex;byte;
+ {NS_sprm::LN_PBrcTop10, nullptr}, // pap.brcTop;BRC10;word;
+ {NS_sprm::LN_PBrcLeft10, nullptr}, // pap.brcLeft;BRC10;word;
+ {NS_sprm::LN_PBrcBottom10, nullptr}, // pap.brcBottom;BRC10;word;
+ {NS_sprm::LN_PBrcRight10, nullptr}, // pap.brcRight;BRC10;word;
+ {NS_sprm::LN_PBrcBetween10, nullptr}, // pap.brcBetween;BRC10;word;
+ {NS_sprm::LN_PBrcBar10, nullptr}, // pap.brcBar;BRC10;word;
+ {NS_sprm::LN_PDxaFromText10, nullptr}, // pap.dxaFromText;dxa;word;
+ {NS_sprm::PWr::val, nullptr}, // pap.wr;wr;byte;
+ {NS_sprm::PBrcTop80::val, &SwWW8ImplReader::Read_Border}, // pap.brcTop;BRC;long;
+ {NS_sprm::PBrcLeft80::val, &SwWW8ImplReader::Read_Border}, // pap.brcLeft;BRC;long;
+ {NS_sprm::PBrcBottom80::val, &SwWW8ImplReader::Read_Border}, // pap.brcBottom;BRC;long;
+ {NS_sprm::PBrcRight80::val, &SwWW8ImplReader::Read_Border}, // pap.brcRight;BRC;long;
+ {NS_sprm::PBrcBetween80::val, &SwWW8ImplReader::Read_Border}, // pap.brcBetween;BRC;long;
+ {NS_sprm::PBrcBar80::val, nullptr}, // pap.brcBar;BRC;long;
+ {NS_sprm::PFNoAutoHyph::val, &SwWW8ImplReader::Read_Hyphenation}, // pap.fNoAutoHyph;0 or 1;byte;
+ {NS_sprm::PWHeightAbs::val, nullptr}, // pap.wHeightAbs;w;word;
+ {NS_sprm::PDcs::val, nullptr}, // pap.dcs;DCS;short;
+ {NS_sprm::PShd80::val, &SwWW8ImplReader::Read_Shade}, // pap.shd;SHD;word;
+ {NS_sprm::PDyaFromText::val, nullptr}, // pap.dyaFromText;dya;word;
+ {NS_sprm::PDxaFromText::val, nullptr}, // pap.dxaFromText;dxa;word;
+ {NS_sprm::PFLocked::val, nullptr}, // pap.fLocked;0 or 1;byte;
+ {NS_sprm::PFWidowControl::val, &SwWW8ImplReader::Read_WidowControl}, // pap.fWidowControl;0 or 1;byte
+ {NS_sprm::LN_PRuler, nullptr}, // variable length;
+ {NS_sprm::PFKinsoku::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fKinsoku;0 or 1;byte;
+ {NS_sprm::PFWordWrap::val, nullptr}, // pap.fWordWrap;0 or 1;byte;
+ {NS_sprm::PFOverflowPunct::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fOverflowPunct; 0 or 1;byte;
+ {NS_sprm::PFTopLinePunct::val, nullptr}, // pap.fTopLinePunct;0 or 1;byte
+ {NS_sprm::PFAutoSpaceDE::val, &SwWW8ImplReader::Read_BoolItem}, // pap.fAutoSpaceDE;0 or 1;byte;
+ {NS_sprm::PFAutoSpaceDN::val, nullptr}, // pap.fAutoSpaceDN;0 or 1;byte;
+ {NS_sprm::PWAlignFont::val, &SwWW8ImplReader::Read_AlignFont}, // pap.wAlignFont;iFa;word;
+ {NS_sprm::PFrameTextFlow::val, nullptr}, // pap.fVertical pap.fBackward
+ // pap.fRotateFont;complex; word
+ {NS_sprm::LN_PISnapBaseLine, nullptr}, // obsolete, not applicable in
+ // Word97 and later versions;;byte;
+ {NS_sprm::LN_PAnld, &SwWW8ImplReader::Read_ANLevelDesc}, // pap.anld;;variable length;
+ {NS_sprm::LN_PPropRMark, nullptr}, // pap.fPropRMark;complex;
+ // variable length;
+ {NS_sprm::POutLvl::val, &SwWW8ImplReader::Read_POutLvl}, // pap.lvl;has no effect if pap.istd
+ // is < 1 or is > 9;byte;
+ {NS_sprm::PFBiDi::val, &SwWW8ImplReader::Read_ParaBiDi}, // ;;byte;
+ {NS_sprm::PFNumRMIns::val, nullptr}, // pap.fNumRMIns;1 or 0;bit;
+ {NS_sprm::LN_PCrLf, nullptr}, // ;;byte;
+ {NS_sprm::PNumRM::val, nullptr}, // pap.numrm;;variable length;
+ {NS_sprm::LN_PHugePapx, nullptr}, // ;fc in the data stream to locate
+ // the huge grpprl;long;
+ {NS_sprm::PHugePapx::val, nullptr}, // ;fc in the data stream to locate
+ // the huge grpprl;long;
+ {NS_sprm::PFUsePgsuSettings::val, &SwWW8ImplReader::Read_UsePgsuSettings}, // pap.fUsePgsuSettings;1 or 0;byte;
+ {NS_sprm::PFAdjustRight::val, nullptr}, // pap.fAdjustRight;1 or 0;byte;
+ {NS_sprm::CFRMarkDel::val, &SwWW8ImplReader::Read_CFRMarkDel}, // chp.fRMarkDel;1 or 0;bit;
+ {NS_sprm::CFRMarkIns::val, &SwWW8ImplReader::Read_CFRMark}, // chp.fRMark;1 or 0;bit;
+ {NS_sprm::CFFldVanish::val, &SwWW8ImplReader::Read_FieldVanish}, // chp.fFieldVanish;1 or 0;bit;
+ {NS_sprm::CPicLocation::val, &SwWW8ImplReader::Read_PicLoc}, // chp.fcPic and chp.fSpec;variable
+ // length, length recorded is always 4;
+ {NS_sprm::CIbstRMark::val, nullptr}, // chp.ibstRMark;index into
+ // sttbRMark;short;
+ {NS_sprm::CDttmRMark::val, nullptr}, // chp.dttmRMark;DTTM;long;
+ {NS_sprm::CFData::val, nullptr}, // chp.fData;1 or 0;bit;
+ {NS_sprm::CIdslRMark::val, nullptr}, // chp.idslRMReason;an index to
+ // a table of strings defined in
+ // Word 6.0 executables;short;
+ {NS_sprm::LN_CChs, &SwWW8ImplReader::Read_CharSet}, // chp.fChsDiff and chp.chse;3 bytes;
+ {NS_sprm::CSymbol::val, &SwWW8ImplReader::Read_Symbol}, // chp.fSpec, chp.xchSym and chp.ftcSym;
+ // variable length, length
+ // recorded is always 4;
+ {NS_sprm::CFOle2::val, &SwWW8ImplReader::Read_Obj}, // chp.fOle2;1 or 0;bit;
+ //NS_sprm::LN_CIdCharType, // obsolete: not applicable in Word97
+ // and later versions
+ {NS_sprm::CHighlight::val, &SwWW8ImplReader::Read_CharHighlight}, // chp.fHighlight, chp.icoHighlight;ico
+ // (fHighlight is set to 1 iff
+ // ico is not 0);byte;
+ {NS_sprm::LN_CObjLocation, &SwWW8ImplReader::Read_PicLoc}, // chp.fcObj;FC;long;
+ //NS_sprm::LN_CFFtcAsciSymb, ? ? ?,
+ {NS_sprm::CIstd::val, &SwWW8ImplReader::Read_CColl}, // chp.istd;istd,short;
+ {NS_sprm::CIstdPermute::val, nullptr}, // chp.istd;permutation vector;
+ // variable length;
+ {NS_sprm::LN_CDefault, nullptr}, // whole CHP;none;variable length;
+ {NS_sprm::CPlain::val, nullptr}, // whole CHP;none;length: 0;
+ {NS_sprm::CKcd::val, &SwWW8ImplReader::Read_Emphasis},
+ {NS_sprm::CFBold::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fBold;0,1, 128, or 129;byte;
+ {NS_sprm::CFItalic::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fItalic;0,1, 128, or 129; byte;
+ {NS_sprm::CFStrike::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fStrike;0,1, 128, or 129; byte;
+ {NS_sprm::CFOutline::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fOutline;0,1, 128, or 129; byte;
+ {NS_sprm::CFShadow::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fShadow;0,1, 128, or 129; byte;
+ {NS_sprm::CFSmallCaps::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fSmallCaps;0,1, 128, or 129;byte;
+ {NS_sprm::CFCaps::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fCaps;0,1, 128, or 129; byte;
+ {NS_sprm::CFVanish::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fVanish;0,1, 128, or 129; byte;
+ //NS_sprm::LN_CFtcDefault, 0, // ftc, only used internally, never
+ // stored in file;word;
+ {NS_sprm::CKul::val, &SwWW8ImplReader::Read_Underline}, // chp.kul;kul;byte;
+ {NS_sprm::LN_CSizePos, nullptr}, // chp.hps, chp.hpsPos;3 bytes;
+ {NS_sprm::CDxaSpace::val, &SwWW8ImplReader::Read_Kern}, // chp.dxaSpace;dxa;word;
+ {NS_sprm::LN_CLid, &SwWW8ImplReader::Read_Language}, // ;only used internally, never stored;
+ // word;
+ {NS_sprm::CIco::val, &SwWW8ImplReader::Read_TextColor}, // chp.ico;ico;byte;
+ {NS_sprm::CHps::val, &SwWW8ImplReader::Read_FontSize}, // chp.hps;hps;byte;
+ {NS_sprm::LN_CHpsInc, nullptr}, // chp.hps;byte;
+ {NS_sprm::CHpsPos::val, &SwWW8ImplReader::Read_SubSuperProp}, // chp.hpsPos;hps;byte;
+ {NS_sprm::LN_CHpsPosAdj, nullptr}, // chp.hpsPos;hps;byte;
+ {NS_sprm::CMajority::val, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fStrike,
+ // chp.fSmallCaps, chp.fVanish, chp.fCaps,
+ // chp.hps, chp.hpsPos, chp.dxaSpace,
+ // chp.kul, chp.ico, chp.rgftc, chp.rglid;
+ // complex;variable length, length byte
+ // plus size of following grpprl;
+ {NS_sprm::CIss::val, &SwWW8ImplReader::Read_SubSuper}, // chp.iss;iss;byte;
+ {NS_sprm::LN_CHpsNew50, nullptr}, // chp.hps;hps;variable width, length
+ // always recorded as 2;
+ {NS_sprm::LN_CHpsInc1, nullptr}, // chp.hps;complex; variable width,
+ // length always recorded as 2;
+ {NS_sprm::CHpsKern::val, &SwWW8ImplReader::Read_FontKern}, // chp.hpsKern;hps;short;
+ {NS_sprm::LN_CMajority50, &SwWW8ImplReader::Read_Majority}, // chp.fBold, chp.fItalic, chp.fStrike,
+ // chp.fSmallCaps, chp.fVanish, chp.fCaps,
+ // chp.ftc, chp.hps, chp.hpsPos, chp.kul,
+ // chp.dxaSpace, chp.ico;complex;
+ // variable length;
+ {NS_sprm::LN_CHpsMul, nullptr}, // chp.hps;percentage to grow hps;short;
+ {NS_sprm::CHresi::val, nullptr}, // ???? "sprmCYsri" chp.ysri;ysri;short;
+ {NS_sprm::CRgFtc0::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[0];ftc for ASCII text;short;
+ {NS_sprm::CRgFtc1::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[1];ftc for Far East text;
+ // short;
+ {NS_sprm::CRgFtc2::val, &SwWW8ImplReader::Read_FontCode}, // chp.rgftc[2];ftc for non-Far East text;
+ // short;
+ {NS_sprm::CCharScale::val, &SwWW8ImplReader::Read_ScaleWidth},
+ {NS_sprm::CFDStrike::val, &SwWW8ImplReader::Read_BoldUsw}, // chp.fDStrike;;byte;
+ {NS_sprm::CFImprint::val, &SwWW8ImplReader::Read_Relief}, // chp.fImprint;1 or 0;bit;
+ {NS_sprm::CFSpec::val, &SwWW8ImplReader::Read_Special}, // chp.fSpec;1 or 0;bit;
+ {NS_sprm::CFObj::val, &SwWW8ImplReader::Read_Obj}, // chp.fObj;1 or 0;bit;
+ {NS_sprm::CPropRMark90::val, &SwWW8ImplReader::Read_CPropRMark}, // chp.fPropRMark, chp.ibstPropRMark,
+ // chp.dttmPropRMark;Complex;variable
+ // length always recorded as 7 bytes;
+ {NS_sprm::CFEmboss::val, &SwWW8ImplReader::Read_Relief}, // chp.fEmboss;1 or 0;bit;
+ {NS_sprm::CSfxText::val, &SwWW8ImplReader::Read_TextAnim}, // chp.sfxtText;text animation;byte;
+ {NS_sprm::CFBiDi::val, &SwWW8ImplReader::Read_Bidi},
+ {NS_sprm::LN_CFDiacColor, nullptr},
+ {NS_sprm::CFBoldBi::val, &SwWW8ImplReader::Read_BoldBiDiUsw},
+ {NS_sprm::CFItalicBi::val, &SwWW8ImplReader::Read_BoldBiDiUsw},
+ {NS_sprm::CFtcBi::val, &SwWW8ImplReader::Read_FontCode},
+ {NS_sprm::CLidBi::val, &SwWW8ImplReader::Read_Language},
+ //NS_sprm::CIcoBi::val, ? ? ?,
+ {NS_sprm::CHpsBi::val, &SwWW8ImplReader::Read_FontSize},
+ {NS_sprm::CDispFldRMark::val, nullptr}, // chp.fDispFieldRMark,
+ // chp.ibstDispFieldRMark,
+ // chp.dttmDispFieldRMark;
+ // Complex;variable length
+ // always recorded as 39 bytes;
+ {NS_sprm::CIbstRMarkDel::val, nullptr}, // chp.ibstRMarkDel;index into
+ // sttbRMark;short;
+ {NS_sprm::CDttmRMarkDel::val, nullptr}, // chp.dttmRMarkDel;DTTM;long;
+ {NS_sprm::CBrc80::val, &SwWW8ImplReader::Read_CharBorder}, // chp.brc;BRC;long;
+ {NS_sprm::CBrc::val, &SwWW8ImplReader::Read_CharBorder}, // chp.brc;BRC;long;
+ {NS_sprm::CShd80::val, &SwWW8ImplReader::Read_CharShadow}, // chp.shd;SHD;short;
+ {NS_sprm::CIdslRMarkDel::val, nullptr}, // chp.idslRMReasonDel;an index to
+ // a table of strings defined in
+ // Word 6.0 executables;short;
+ {NS_sprm::CFUsePgsuSettings::val, nullptr}, // chp.fUsePgsuSettings; 1 or 0;bit;
+ {NS_sprm::LN_CCpg, nullptr}, // ;;word;
+ {NS_sprm::CRgLid0_80::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[0];
+ // LID: for non-Far East text;word;
+ {NS_sprm::CRgLid1_80::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[1];
+ // LID: for Far East text;word;
+ {NS_sprm::CIdctHint::val, &SwWW8ImplReader::Read_IdctHint}, // chp.idctHint;IDCT: byte;
+ {NS_sprm::LN_PicBrcl, nullptr}, // pic.brcl;brcl (see PIC structure
+ // definition);byte;
+ {NS_sprm::LN_PicScale, nullptr}, // pic.mx, pic.my, pic.dxaCropleft,
+ // pic.dyaCropTop pic.dxaCropRight,
+ // pic.dyaCropBottom;Complex;
+ // length byte plus 12 bytes;
+ {NS_sprm::PicBrcTop80::val, nullptr}, // pic.brcTop;BRC;long;
+ {NS_sprm::PicBrcLeft80::val, nullptr}, // pic.brcLeft;BRC;long;
+ {NS_sprm::PicBrcBottom80::val, nullptr}, // pic.brcBottom;BRC;long;
+ {NS_sprm::PicBrcRight80::val, nullptr}, // pic.brcRight;BRC;long;
+ {NS_sprm::ScnsPgn::val, nullptr}, // sep.cnsPgn;cns;byte;
+ {NS_sprm::SiHeadingPgn::val, nullptr}, // sep.iHeadingPgn;heading number level;
+ // byte;
+ {NS_sprm::LN_SOlstAnm, &SwWW8ImplReader::Read_OLST}, // sep.olstAnm;OLST;variable length;
+ {NS_sprm::SDxaColWidth::val, nullptr}, // sep.rgdxaColWidthSpacing;complex;
+ // 3 bytes;
+ {NS_sprm::SDxaColSpacing::val, nullptr}, // sep.rgdxaColWidthSpacing;complex;
+ // 3 bytes;
+ {NS_sprm::SFEvenlySpaced::val, nullptr}, // sep.fEvenlySpaced; 1 or 0;byte;
+ {NS_sprm::SFProtected::val, nullptr}, // sep.fUnlocked;1 or 0;byte;
+ {NS_sprm::SDmBinFirst::val, nullptr}, // sep.dmBinFirst;;word;
+ {NS_sprm::SDmBinOther::val, nullptr}, // sep.dmBinOther;;word;
+ {NS_sprm::SBkc::val, nullptr}, // sep.bkc;bkc;byte;
+ {NS_sprm::SFTitlePage::val, nullptr}, // sep.fTitlePage;0 or 1;byte;
+ {NS_sprm::SCcolumns::val, nullptr}, // sep.ccolM1;# of cols - 1;word;
+ {NS_sprm::SDxaColumns::val, nullptr}, // sep.dxaColumns;dxa;word;
+ {NS_sprm::LN_SFAutoPgn, nullptr}, // sep.fAutoPgn;obsolete;byte;
+ {NS_sprm::SNfcPgn::val, nullptr}, // sep.nfcPgn;nfc;byte;
+ {NS_sprm::LN_SDyaPgn, nullptr}, // sep.dyaPgn;dya;short;
+ {NS_sprm::LN_SDxaPgn, nullptr}, // sep.dxaPgn;dya;short;
+ {NS_sprm::SFPgnRestart::val, nullptr}, // sep.fPgnRestart;0 or 1;byte;
+ {NS_sprm::SFEndnote::val, nullptr}, // sep.fEndnote;0 or 1;byte;
+ {NS_sprm::SLnc::val, nullptr}, // sep.lnc;lnc;byte;
+ {NS_sprm::LN_SGprfIhdt, nullptr}, // sep.grpfIhdt;grpfihdt;byte;
+ {NS_sprm::SNLnnMod::val, nullptr}, // sep.nLnnMod;non-neg int.;word;
+ {NS_sprm::SDxaLnn::val, nullptr}, // sep.dxaLnn;dxa;word;
+ {NS_sprm::SDyaHdrTop::val, nullptr}, // sep.dyaHdrTop;dya;word;
+ {NS_sprm::SDyaHdrBottom::val, nullptr}, // sep.dyaHdrBottom;dya;word;
+ {NS_sprm::SLBetween::val, nullptr}, // sep.fLBetween;0 or 1;byte;
+ {NS_sprm::SVjc::val, &SwWW8ImplReader::Read_TextVerticalAdjustment}, // sep.vjc;vjc;byte;
+ {NS_sprm::SLnnMin::val, nullptr}, // sep.lnnMin;lnn;word;
+ {NS_sprm::SPgnStart97::val, nullptr}, // sep.pgnStart;pgn;word;
+ {NS_sprm::SBOrientation::val, nullptr}, // sep.dmOrientPage;dm;byte;
+ //NS_sprm::LN_SBCustomize, ? ? ?,
+ {NS_sprm::SXaPage::val, nullptr}, // sep.xaPage;xa;word;
+ {NS_sprm::SYaPage::val, nullptr}, // sep.yaPage;ya;word;
+ {0x2205, nullptr}, // ???? "sprmSDxaLeft" sep.dxaLeft;
+ // dxa;word;
+ {NS_sprm::SDxaLeft::val, nullptr}, // sep.dxaLeft;dxa;word;
+ {NS_sprm::SDxaRight::val, nullptr}, // sep.dxaRight;dxa;word;
+ {NS_sprm::SDyaTop::val, nullptr}, // sep.dyaTop;dya;word;
+ {NS_sprm::SDyaBottom::val, nullptr}, // sep.dyaBottom;dya;word;
+ {NS_sprm::SDzaGutter::val, nullptr}, // sep.dzaGutter;dza;word;
+ {NS_sprm::SDmPaperReq::val, nullptr}, // sep.dmPaperReq;dm;word;
+ {NS_sprm::LN_SPropRMark, nullptr}, // sep.fPropRMark, sep.ibstPropRMark,
+ // sep.dttmPropRMark;complex; variable
+ // length always recorded as 7 bytes;
+ //NS_sprm::SFBiDi::val, ? ? ?,
+ //NS_sprm::LN_SFFacingCol, ? ? ?,
+ {NS_sprm::SFRTLGutter::val, nullptr}, // set to 1 if gutter is on the right.
+ {NS_sprm::SBrcTop80::val, nullptr}, // sep.brcTop;BRC;long;
+ {NS_sprm::SBrcLeft80::val, nullptr}, // sep.brcLeft;BRC;long;
+ {NS_sprm::SBrcBottom80::val, nullptr}, // sep.brcBottom;BRC;long;
+ {NS_sprm::SBrcRight80::val, nullptr}, // sep.brcRight;BRC;long;
+ {NS_sprm::SPgbProp::val, nullptr}, // sep.pgbProp;word;
+ {NS_sprm::SDxtCharSpace::val, nullptr}, // sep.dxtCharSpace;dxt;long;
+ {NS_sprm::SDyaLinePitch::val, nullptr}, // sep.dyaLinePitch;dya;
+ // WRONG:long; RIGHT:short; !
+ //NS_sprm::SClm::val, ? ? ?,
+ {NS_sprm::STextFlow::val, nullptr}, // sep.wTextFlow;complex;short
+ {NS_sprm::TJc90::val, nullptr}, // tap.jc;jc;word
+ // (low order byte is significant);
+ {NS_sprm::TDxaLeft::val, nullptr}, // tap.rgdxaCenter;dxa;word;
+ {NS_sprm::TDxaGapHalf::val, nullptr}, // tap.dxaGapHalf,
+ // tap.rgdxaCenter;dxa;word;
+ {NS_sprm::TFCantSplit90::val, nullptr}, // tap.fCantSplit90;1 or 0;byte;
+ {NS_sprm::TTableHeader::val, nullptr}, // tap.fTableHeader;1 or 0;byte;
+ {NS_sprm::TFCantSplit::val, nullptr}, // tap.fCantSplit;1 or 0;byte;
+ {NS_sprm::TTableBorders80::val, nullptr}, // tap.rgbrcTable;complex;24 bytes;
+ {NS_sprm::LN_TDefTable10, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
+ // variable length;
+ {NS_sprm::TDyaRowHeight::val, nullptr}, // tap.dyaRowHeight;dya;word;
+ {NS_sprm::TDefTable::val, nullptr}, // tap.rgtc;complex
+ {NS_sprm::TDefTableShd80::val, nullptr}, // tap.rgshd;complex
+ {NS_sprm::TTlp::val, nullptr}, // tap.tlp;TLP;4 bytes;
+ //NS_sprm::TFBiDi::val, ? ? ?,
+ //NS_sprm::LN_THTMLProps, ? ? ?,
+ {NS_sprm::TSetBrc80::val, nullptr}, // tap.rgtc[].rgbrc;complex;5 bytes;
+ {NS_sprm::TInsert::val, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
+ // 4 bytes;
+ {NS_sprm::TDelete::val, nullptr}, // tap.rgdxaCenter, tap.rgtc;complex;
+ // word;
+ {NS_sprm::TDxaCol::val, nullptr}, // tap.rgdxaCenter;complex;4 bytes;
+ {NS_sprm::TMerge::val, nullptr}, // tap.fFirstMerged, tap.fMerged;
+ // complex; word;
+ {NS_sprm::TSplit::val, nullptr}, // tap.fFirstMerged, tap.fMerged;
+ // complex;word;
+ {NS_sprm::LN_TSetBrc10, nullptr}, // tap.rgtc[].rgbrc;complex;5 bytes;
+ {NS_sprm::LN_TSetShd80, nullptr}, // tap.rgshd;complex;4 bytes;
+ {NS_sprm::LN_TSetShdOdd80, nullptr}, // tap.rgshd;complex;4 bytes;
+ {NS_sprm::TTextFlow::val, nullptr}, // tap.rgtc[].fVertical
+ // tap.rgtc[].fBackward
+ // tap.rgtc[].fRotateFont
+ // 0 or 10 or 10 or 1;word;
+ //NS_sprm::LN_TDiagLine, ? ? ? ,
+ {NS_sprm::TVertMerge::val, nullptr}, // tap.rgtc[].vertMerge;complex;variable
+ // length always recorded as 2 bytes;
+ {NS_sprm::TVertAlign::val, nullptr}, // tap.rgtc[].vertAlign;complex;variable
+ // length always recorded as 3 bytes;
+ {NS_sprm::CFELayout::val, &SwWW8ImplReader::Read_DoubleLine_Rotate},
+ {NS_sprm::PItap::val, nullptr},
+ {NS_sprm::TTableWidth::val, nullptr}, // recorded as 3 bytes;
+ {NS_sprm::TDefTableShd::val, nullptr},
+ {NS_sprm::TTableBorders::val, nullptr},
+ {NS_sprm::TBrcTopCv::val, nullptr},
+ {NS_sprm::TBrcLeftCv::val, nullptr},
+ {NS_sprm::TBrcBottomCv::val, nullptr},
+ {NS_sprm::TBrcRightCv::val, nullptr},
+ {NS_sprm::TCellPaddingDefault::val, nullptr},
+ {NS_sprm::TCellPadding::val, nullptr},
+ {0xD238, nullptr}, // undocumented sep
+ {NS_sprm::PBrcTop::val, &SwWW8ImplReader::Read_Border},
+ {NS_sprm::PBrcLeft::val, &SwWW8ImplReader::Read_Border},
+ {NS_sprm::PBrcBottom::val, &SwWW8ImplReader::Read_Border},
+ {NS_sprm::PBrcRight::val, &SwWW8ImplReader::Read_Border},
+ {NS_sprm::PBrcBetween::val, &SwWW8ImplReader::Read_Border},
+ {NS_sprm::TWidthIndent::val, nullptr},
+ {NS_sprm::CRgLid0::val, &SwWW8ImplReader::Read_Language}, // chp.rglid[0];
+ // LID: for non-Far East text;
+ {NS_sprm::CRgLid1::val, nullptr}, // chp.rglid[1];
+ // LID: for Far East text
+ {0x6463, nullptr}, // undocumented
+ {NS_sprm::PJc::val, &SwWW8ImplReader::Read_RTLJustify},
+ {NS_sprm::PDxaLeft::val, &SwWW8ImplReader::Read_LR},
+ {NS_sprm::PDxaLeft1::val, &SwWW8ImplReader::Read_LR},
+ {NS_sprm::PDxaRight::val, &SwWW8ImplReader::Read_LR},
+ {NS_sprm::TFAutofit::val, nullptr},
+ {NS_sprm::TPc::val, nullptr},
+ {NS_sprm::TDxaAbs::val, nullptr},
+ {NS_sprm::TDyaAbs::val, nullptr},
+ {NS_sprm::TDxaFromText::val, nullptr},
+ {NS_sprm::SRsid::val, nullptr},
+ {NS_sprm::SFpc::val, nullptr},
+ {NS_sprm::PFInnerTableCell::val, &SwWW8ImplReader::Read_TabCellEnd},
+ {NS_sprm::PFInnerTtp::val, &SwWW8ImplReader::Read_TabRowEnd},
+ {NS_sprm::CRsidProp::val, nullptr},
+ {NS_sprm::CRsidText::val, nullptr},
+ {NS_sprm::CCv::val, &SwWW8ImplReader::Read_TextForeColor},
+ {NS_sprm::CCvUl::val, &SwWW8ImplReader::Read_UnderlineColor},
+ {NS_sprm::PShd::val, &SwWW8ImplReader::Read_ParaBackColor},
+ {NS_sprm::PRsid::val, nullptr},
+ {NS_sprm::TWidthBefore::val, nullptr},
+ {NS_sprm::TSetShdTable::val, nullptr},
+ {NS_sprm::TDefTableShdRaw::val, nullptr},
+ {NS_sprm::CShd::val, &SwWW8ImplReader::Read_TextBackColor},
+ {NS_sprm::SRncFtn::val, nullptr},
+ {NS_sprm::PFDyaBeforeAuto::val, &SwWW8ImplReader::Read_ParaAutoBefore},
+ {NS_sprm::PFDyaAfterAuto::val, &SwWW8ImplReader::Read_ParaAutoAfter},
+ {NS_sprm::PFContextualSpacing::val, &SwWW8ImplReader::Read_ParaContextualSpacing},
+ {NS_sprm::CLbcCRJ::val, &SwWW8ImplReader::Read_LineBreakClear},
+ };
+
+ static wwSprmDispatcher aSprmSrch(aSprms, SAL_N_ELEMENTS(aSprms));
+ return &aSprmSrch;
+}
+
+// helper routines : find SPRM
+
+const SprmReadInfo& SwWW8ImplReader::GetSprmReadInfo(sal_uInt16 nId) const
+{
+ ww::WordVersion eVersion = m_xWwFib->GetFIBVersion();
+ const wwSprmDispatcher *pDispatcher;
+ if (eVersion <= ww::eWW2)
+ pDispatcher = GetWW2SprmDispatcher();
+ else if (eVersion < ww::eWW8)
+ pDispatcher = GetWW6SprmDispatcher();
+ else
+ pDispatcher = GetWW8SprmDispatcher();
+
+ SprmReadInfo aSrch = {0, nullptr};
+ aSrch.nId = nId;
+ const SprmReadInfo* pFound = pDispatcher->search(aSrch);
+
+ if (!pFound)
+ {
+ aSrch.nId = 0;
+ pFound = pDispatcher->search(aSrch);
+ }
+
+ return *pFound;
+}
+
+// helper routines : SPRMs
+
+void SwWW8ImplReader::EndSprm( sal_uInt16 nId )
+{
+ if( ( nId > 255 ) && ( nId < 0x0800 ) ) return;
+
+ const SprmReadInfo& rSprm = GetSprmReadInfo( nId );
+
+ if (rSprm.pReadFnc)
+ (this->*rSprm.pReadFnc)( nId, nullptr, -1 );
+}
+
+short SwWW8ImplReader::ImportSprm(const sal_uInt8* pPos, sal_Int32 nMemLen, sal_uInt16 nId)
+{
+ if (!nId)
+ nId = m_xSprmParser->GetSprmId(pPos);
+
+ OSL_ENSURE( nId != 0xff, "Sprm FF !!!!" );
+
+ const SprmReadInfo& rSprm = GetSprmReadInfo(nId);
+
+ sal_Int32 nFixedLen = m_xSprmParser->DistanceToData(nId);
+ sal_Int32 nL = m_xSprmParser->GetSprmSize(nId, pPos, nMemLen);
+
+ if (rSprm.pReadFnc)
+ (this->*rSprm.pReadFnc)(nId, pPos + nFixedLen, nL - nFixedLen);
+
+ return nL;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */