/* -*- 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 <iostream>
#include <stdio.h>
#include "WW8TableInfo.hxx"
#include <fmtfsize.hxx>
#include "attributeoutputbase.hxx"
#include <swtable.hxx>
#include <frmfmt.hxx>
#include <pam.hxx>
#include <dbgoutsw.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <rtl/string.hxx>
namespace ww8
{
WW8TableNodeInfoInner::WW8TableNodeInfoInner(WW8TableNodeInfo * pParent)
: mpParent(pParent)
, mnDepth(0)
, mnCell(0)
, mnRow(0)
, mnShadowsBefore(0)
, mnShadowsAfter(0)
, mbEndOfLine(false)
, mbFinalEndOfLine(false)
, mbEndOfCell(false)
, mbFirstInTable(false)
, mbVertMerge(false)
, mpTableBox(nullptr)
, mpTable(nullptr)
{
}
void WW8TableNodeInfoInner::setDepth(sal_uInt32 nDepth)
{
mnDepth = nDepth;
}
void WW8TableNodeInfoInner::setCell(sal_uInt32 nCell)
{
mnCell = nCell;
}
void WW8TableNodeInfoInner::setRow(sal_uInt32 nRow)
{
mnRow = nRow;
}
void WW8TableNodeInfoInner::setShadowsBefore(sal_uInt32 nShadowsBefore)
{
mnShadowsBefore = nShadowsBefore;
}
void WW8TableNodeInfoInner::setShadowsAfter(sal_uInt32 nShadowsAfter)
{
mnShadowsAfter = nShadowsAfter;
}
void WW8TableNodeInfoInner::setEndOfLine(bool bEndOfLine)
{
mbEndOfLine = bEndOfLine;
}
void WW8TableNodeInfoInner::setFinalEndOfLine(bool bFinalEndOfLine)
{
mbFinalEndOfLine = bFinalEndOfLine;
}
void WW8TableNodeInfoInner::setEndOfCell(bool bEndOfCell)
{
mbEndOfCell = bEndOfCell;
}
void WW8TableNodeInfoInner::setFirstInTable(bool bFirstInTable)
{
mbFirstInTable = bFirstInTable;
}
void WW8TableNodeInfoInner::setVertMerge(bool bVertMerge)
{
mbVertMerge = bVertMerge;
}
void WW8TableNodeInfoInner::setTableBox(const SwTableBox * pTableBox)
{
mpTableBox = pTableBox;
}
void WW8TableNodeInfoInner::setTable(const SwTable * pTable)
{
mpTable = pTable;
}
void WW8TableNodeInfoInner::setRect(const SwRect & rRect)
{
maRect = rRect;
}
const SwNode * WW8TableNodeInfoInner::getNode() const
{
const SwNode * pResult = nullptr;
if (mpParent != nullptr)
pResult = mpParent->getNode();
return pResult;
}
TableBoxVectorPtr WW8TableNodeInfoInner::getTableBoxesOfRow() const
{
TableBoxVectorPtr pResult = std::make_shared<TableBoxVector>();
WW8TableCellGrid::Pointer_t pCellGrid =
mpParent->getParent()->getCellGridForTable(getTable(), false);
if (!pCellGrid)
{
const SwTableLine * pTabLine = getTableBox()->GetUpper();
const SwTableBoxes & rTableBoxes = pTabLine->GetTabBoxes();
sal_uInt8 nBoxes = rTableBoxes.size();
if (nBoxes > MAXTABLECELLS)
nBoxes = MAXTABLECELLS;
for ( sal_uInt8 n = 0; n < nBoxes; n++ )
{
pResult->push_back(rTableBoxes[n]);
}
}
else
pResult = pCellGrid->getTableBoxesOfRow(this);
return pResult;
}
GridColsPtr WW8TableNodeInfoInner::getGridColsOfRow(AttributeOutputBase & rBase, bool calculateColumnsFromAllRows)
{
GridColsPtr pResult = std::make_shared<GridCols>();
WidthsPtr pWidths;
// Check which columns should be checked - only the current row,
// or all the rows together
if (calculateColumnsFromAllRows)
{
// Calculate the width of all the columns based on ALL the rows.
// The difference is that this kind of draws vertical lines,
// so that if the rows look like this:
//
// ------------------------
// | | |
// ------------------------
// | | |
// ------------------------
// | | |
// ------------------------
// then the actual column widths will be broken down like this:
//
// ------------------------
// | | | | |
// ------------------------
// See the example at
// http://officeopenxml.com/WPtableGrid.php
// Under "Word 2007 Example"
pWidths = getColumnWidthsBasedOnAllRows();
}
else
{
// Calculate the width of all the columns based on the current row
pWidths = getWidthsOfRow();
}
const SwFrameFormat *pFormat = getTable()->GetFrameFormat();
OSL_ENSURE(pFormat,"Impossible");
if (!pFormat)
return pResult;
const SwFormatFrameSize &rSize = pFormat->GetFrameSize();
tools::ULong nTableSz = static_cast<tools::ULong>(rSize.GetWidth());
tools::Long nPageSize = 0;
bool bRelBoxSize = false;
rBase.GetTablePageSize( this, nPageSize, bRelBoxSize );
SwTwips nSz = 0;
for (const auto& rWidth : *pWidths)
{
nSz += rWidth;
SwTwips nCalc = nSz;
if ( bRelBoxSize )
nCalc = ( nCalc * nPageSize ) / nTableSz;
pResult->push_back( nCalc );
}
return pResult;
}
WidthsPtr WW8TableNodeInfoInner::getColumnWidthsBasedOnAllRows() const
{
WidthsPtr pWidths;
WW8TableCellGrid::Pointer_t pCellGrid =
mpParent->getParent()->getCellGridForTable(getTable(), false);
if (!pCellGrid)
{
const SwTable * pTable = getTable();
const SwTableLines& rTableLines = pTable->GetTabLines();
const size_t nNumOfLines = rTableLines.size();
// Go over all the rows - and for each row - calculate where
// there is a separator between columns
WidthsPtr pSeparators = std::make_shared<Widths>();
for ( size_t nLineIndex = 0; nLineIndex < nNumOfLines; ++nLineIndex )
{
const SwTableLine *pCurrentLine = rTableLines[nLineIndex];
const SwTableBoxes & rTabBoxes = pCurrentLine->GetTabBoxes();
size_t nBoxes = rTabBoxes.size();
if (nBoxes > MAXTABLECELLS)
nBoxes = MAXTABLECELLS;
sal_uInt32 nSeparatorPosition = 0;
for (size_t nBoxIndex = 0; nBoxIndex < nBoxes; ++nBoxIndex)
{
const SwFrameFormat* pBoxFormat = rTabBoxes[ nBoxIndex ]->GetFrameFormat();
const SwFormatFrameSize& rLSz = pBoxFormat->GetFrameSize();
nSeparatorPosition += rLSz.GetWidth();
pSeparators->push_back(nSeparatorPosition);
}
}
// Sort the separator positions and remove any duplicates
std::sort(pSeparators->begin(), pSeparators->end());
std::vector<sal_uInt32>::iterator it = std::unique(pSeparators->begin(), pSeparators->end());
pSeparators->erase(it, pSeparators->end());
// Calculate the widths based on the position of the unique & sorted
// column separators
pWidths = std::make_shared<Widths>();
sal_uInt32 nPreviousWidth = 0;
for (const sal_uInt32 nCurrentWidth : *pSeparators)
{
pWidths->push_back(nCurrentWidth - nPreviousWidth);
nPreviousWidth = nCurrentWidth;
}
}
else
{
pWidths = pCellGrid->getWidthsOfRow(this);
}
return pWidths;
}
WidthsPtr WW8TableNodeInfoInner::getWidthsOfRow() const
{
WidthsPtr pWidths;
WW8TableCellGrid::Pointer_t pCellGrid =
mpParent->getParent()->getCellGridForTable(getTable(), false);
if (!pCellGrid)
{
const SwTableBox * pTabBox = getTableBox();
const SwTableLine * pTabLine = pTabBox->GetUpper();
const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
pWidths = std::make_shared<Widths>();
// number of cell written
sal_uInt32 nBoxes = rTabBoxes.size();
if (nBoxes > MAXTABLECELLS)
nBoxes = MAXTABLECELLS;
for (sal_uInt32 n = 0; n < nBoxes; n++)
{
const SwFrameFormat* pBoxFormat = rTabBoxes[ n ]->GetFrameFormat();
const SwFormatFrameSize& rLSz = pBoxFormat->GetFrameSize();
pWidths->push_back(rLSz.GetWidth());
}
}
else
pWidths = pCellGrid->getWidthsOfRow(this);
return pWidths;
}
RowSpansPtr WW8TableNodeInfoInner::getRowSpansOfRow() const
{
RowSpansPtr pResult = std::make_shared<RowSpans>();
WW8TableCellGrid::Pointer_t pCellGrid =
mpParent->getParent()->getCellGridForTable(getTable(), false);
if (!pCellGrid)
{
const SwTableBox * pTabBox = getTableBox();
const SwTableLine * pTabLine = pTabBox->GetUpper();
const SwTableBoxes & rTabBoxes = pTabLine->GetTabBoxes();
sal_uInt32 nBoxes = rTabBoxes.size();
if (nBoxes > MAXTABLECELLS)
nBoxes = MAXTABLECELLS;
for (sal_uInt32 n = 0; n < nBoxes; ++n)
{
pResult->push_back(rTabBoxes[n]->getRowSpan());
}
}
else
pResult = pCellGrid->getRowSpansOfRow(this);
return pResult;
}
#ifdef DBG_UTIL
std::string WW8TableNodeInfoInner::toString() const
{
static char buffer[256];
snprintf(buffer, sizeof(buffer),
"<tableinner depth=\"%" SAL_PRIuUINT32 "\""
" cell=\"%" SAL_PRIuUINT32 "\""
" row=\"%" SAL_PRIuUINT32 "\""
" endOfCell=\"%s\""
" endOfLine=\"%s\""
" shadowsBefore=\"%" SAL_PRIuUINT32 "\""
" shadowsAfter=\"%" SAL_PRIuUINT32 "\""
" vertMerge=\"%s\"/>",
mnDepth, mnCell, mnRow,
mbEndOfCell ? "yes" : "no",
mbEndOfLine ? "yes" : "no",
mnShadowsBefore,
mnShadowsAfter,
mbVertMerge ? "yes" : "no");
return std::string(buffer);
}
#endif
WW8TableNodeInfo::WW8TableNodeInfo(WW8TableInfo * pParent,
const SwNode * pNode)
: mpParent(pParent),
mnDepth(0),
mpNode(pNode),
mpNext(nullptr),
mpNextNode(nullptr)
{
}
WW8TableNodeInfo::~WW8TableNodeInfo()
{
}
#ifdef DBG_UTIL
std::string WW8TableNodeInfo::toString() const
{
static char buffer[1024];
snprintf(buffer, sizeof(buffer),
"<tableNodeInfo p=\"%p\" depth=\"%" SAL_PRIuUINT32 "\">"
,this, getDepth());
std::string sResult(buffer);
for (const auto& rInner : mInners)
{
WW8TableNodeInfoInner::Pointer_t pInner = rInner.second;
sResult += pInner->toString();
}
sResult += dbg_out(*mpNode);
sResult += "</tableNodeInfo>";
return sResult;
}
#endif
void WW8TableNodeInfo::setDepth(sal_uInt32 nDepth)
{
mnDepth = nDepth;
Inners_t::iterator aIt = mInners.find(mnDepth);
if (aIt == mInners.end())
mInners[mnDepth] = std::make_shared<ww8::WW8TableNodeInfoInner>(this);
mInners[mnDepth]->setDepth(mnDepth);
}
void WW8TableNodeInfo::setEndOfLine(bool bEndOfLine)
{
WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
pInner->setEndOfLine(bEndOfLine);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", "<endOfLine depth=\"" << mnDepth << "\">" << toString() << "</endOfLine>" );
#endif
}
void WW8TableNodeInfo::setEndOfCell(bool bEndOfCell)
{
WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
pInner->setEndOfCell(bEndOfCell);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", "<endOfCell depth=\"" << mnDepth << "\">" << toString() << "</endOfCell>" );
#endif
}
void WW8TableNodeInfo::setFirstInTable(bool bFirstInTable)
{
WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
pInner->setFirstInTable(bFirstInTable);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", "<firstInTable depth=\"" << mnDepth << "\">" << toString() << "</firstInTable>" );
#endif
}
void WW8TableNodeInfo::setVertMerge(bool bVertMerge)
{
WW8TableNodeInfoInner::Pointer_t pInner = getInnerForDepth(mnDepth);
pInner->setVertMerge(bVertMerge);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", "<vertMerge depth=\"" << mnDepth << "\">" << toString() << "</vertMerge>" );
#endif
}
void WW8TableNodeInfo::setTableBox(const SwTableBox * pTableBox)
{
getInnerForDepth(mnDepth)->setTableBox(pTableBox);
}
void WW8TableNodeInfo::setTable(const SwTable * pTable)
{
getInnerForDepth(mnDepth)->setTable(pTable);
}
void WW8TableNodeInfo::setNext(WW8TableNodeInfo * pNext)
{
mpNext = pNext;
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", "<setnext><from>" << toString() << "</from><to>" << pNext->toString() << "</to></setnext>" );
#endif
}
void WW8TableNodeInfo::setNextNode(const SwNode * pNode)
{
mpNextNode = pNode;
}
void WW8TableNodeInfo::setRect(const SwRect & rRect)
{
getInnerForDepth(mnDepth)->setRect(rRect);
}
void WW8TableNodeInfo::setCell(sal_uInt32 nCell)
{
getInnerForDepth(mnDepth)->setCell(nCell);
}
void WW8TableNodeInfo::setRow(sal_uInt32 nRow)
{
getInnerForDepth(mnDepth)->setRow(nRow);
}
void WW8TableNodeInfo::setShadowsBefore(sal_uInt32 nShadowsBefore)
{
getInnerForDepth(mnDepth)->setShadowsBefore(nShadowsBefore);
}
void WW8TableNodeInfo::setShadowsAfter(sal_uInt32 nShadowsAfter)
{
getInnerForDepth(mnDepth)->setShadowsAfter(nShadowsAfter);
}
sal_uInt32 WW8TableNodeInfo::getDepth() const
{
if (!mInners.empty())
return mInners.begin()->second->getDepth();
return mnDepth;
}
const SwTableBox * WW8TableNodeInfo::getTableBox() const
{
return getInnerForDepth(mnDepth)->getTableBox();
}
sal_uInt32 WW8TableNodeInfo::getCell() const
{
return getInnerForDepth(mnDepth)->getCell();
}
sal_uInt32 WW8TableNodeInfo::getRow() const
{
return getInnerForDepth(mnDepth)->getRow();
}
WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getFirstInner() const
{
WW8TableNodeInfoInner::Pointer_t pResult;
if (!mInners.empty())
pResult = mInners.begin()->second;
return pResult;
}
WW8TableNodeInfoInner::Pointer_t WW8TableNodeInfo::getInnerForDepth(sal_uInt32 nDepth) const
{
WW8TableNodeInfoInner::Pointer_t pResult;
Inners_t::const_iterator aIt = mInners.find(nDepth);
if (aIt != mInners.end())
{
pResult = aIt->second;
}
return pResult;
}
WW8TableInfo::WW8TableInfo()
{
}
WW8TableInfo::~WW8TableInfo()
{
}
WW8TableNodeInfo *
WW8TableInfo::processSwTableByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
{
SwTableCellInfo aTableCellInfo(pTable);
while (aTableCellInfo.getNext())
{
SwRect aRect = aTableCellInfo.getRect();
SAL_INFO( "sw.ww8", "<CellFrame>" );
SAL_INFO( "sw.ww8", "<rect top=\"" << aRect.Top() << "\" bottom=\"" << aRect.Bottom()
<< "\" left=\"" << aRect.Left() << "\" right=\"" << aRect.Right() << "\"/>" );
const SwTableBox * pTableBox = aTableCellInfo.getTableBox();
const SwStartNode * pSttNd = pTableBox->GetSttNd();
if (pSttNd != nullptr)
{
SwPaM aPam(*pSttNd, 0);
bool bDone = false;
do
{
SwNode & rNode = aPam.GetPoint()->GetNode();
insertTableNodeInfo(&rNode, pTable, pTableBox, 0, 0, 1, & aRect);
if (rNode.IsEndNode())
{
SwEndNode * pEndNode = rNode.GetEndNode();
SwStartNode * pTmpSttNd = pEndNode->StartOfSectionNode();
if (pTmpSttNd == pSttNd)
bDone = true;
}
aPam.GetPoint()->Adjust(SwNodeOffset(1));
}
while (!bDone);
}
SAL_INFO( "sw.ww8", "</CellFrame>" );
}
return reorderByLayout(pTable, rLastRowEnds);
}
void WW8TableInfo::processSwTable(const SwTable * pTable)
{
SAL_INFO( "sw.ww8", "<processSwTable>" );
WW8TableNodeInfo * pPrev = nullptr;
RowEndInners_t aLastRowEnds;
if (pTable->IsTableComplex() && pTable->HasLayout())
{
pPrev = processSwTableByLayout(pTable, aLastRowEnds);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", getCellGridForTable(pTable)->toString());
#endif
}
else
{
const SwTableLines & rLines = pTable->GetTabLines();
for (size_t n = 0; n < rLines.size(); ++n)
{
const SwTableLine * pLine = rLines[n];
pPrev = processTableLine(pTable, pLine, static_cast<sal_uInt32>(n), 1, pPrev, aLastRowEnds);
}
}
if (pPrev)
{
SwTableNode * pTableNode = pTable->GetTableNode();
SwEndNode * pEndNode = pTableNode->EndOfSectionNode();
pPrev->setNextNode(pEndNode);
assert(!aLastRowEnds.empty());
for (auto &a : aLastRowEnds)
{
assert(a.second->isEndOfLine());
a.second->setFinalEndOfLine(true);
}
}
SAL_INFO( "sw.ww8", "</processSwTable>" );
}
WW8TableNodeInfo *
WW8TableInfo::processTableLine(const SwTable * pTable,
const SwTableLine * pTableLine,
sal_uInt32 nRow,
sal_uInt32 nDepth,
WW8TableNodeInfo * pPrev,
RowEndInners_t &rLastRowEnds)
{
SAL_INFO( "sw.ww8", "<processTableLine row=\"" << nRow << "\" depth=\"" << nDepth << "\">" );
const SwTableBoxes & rBoxes = pTableLine->GetTabBoxes();
for (size_t n = 0; n < rBoxes.size(); ++n)
{
const SwTableBox * pBox = rBoxes[n];
pPrev = processTableBox(pTable, pBox, nRow, static_cast<sal_uInt32>(n), nDepth, n == rBoxes.size() - 1, pPrev, rLastRowEnds);
}
SAL_INFO( "sw.ww8", "</processTableLine>" );
return pPrev;
}
WW8TableNodeInfo::Pointer_t
WW8TableInfo::processTableBoxLines(const SwTableBox * pBox,
const SwTable * pTable,
const SwTableBox * pBoxToSet,
sal_uInt32 nRow,
sal_uInt32 nCell,
sal_uInt32 nDepth)
{
SAL_INFO( "sw.ww8", "<processTableBoxLines depth=\"" << nDepth << "\" row=\"" << nRow
<< "\" cell=\"" << nCell << "\">" );
const SwTableLines & rLines = pBox->GetTabLines();
WW8TableNodeInfo::Pointer_t pNodeInfo;
if (!rLines.empty())
{
for (size_t n = 0; n < rLines.size(); ++n)
{
const SwTableLine * pLine = rLines[n];
const SwTableBoxes & rBoxes = pLine->GetTabBoxes();
for (size_t nBox = 0; nBox < rBoxes.size(); ++nBox)
pNodeInfo = processTableBoxLines(rBoxes[nBox], pTable, pBoxToSet, nRow, nCell, nDepth);
}
}
else
{
const SwStartNode * pSttNd = pBox->GetSttNd();
const SwEndNode * pEndNd = pSttNd->EndOfSectionNode();
SwPaM aPaM(*pSttNd, 0);
SwPaM aEndPaM(*pEndNd, 0);
bool bDone = false;
while (!bDone)
{
SwNode & rNode = aPaM.GetPoint()->GetNode();
pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBoxToSet, nRow, nCell, nDepth);
if (aPaM.GetPoint()->GetNode() == aEndPaM.GetPoint()->GetNode())
bDone = true;
else
aPaM.GetPoint()->Adjust(SwNodeOffset(1));
}
}
SAL_INFO( "sw.ww8", "</processTableBoxLines>" );
return pNodeInfo;
}
static void updateFinalEndOfLine(RowEndInners_t &rLastRowEnds, WW8TableNodeInfo const * pEndOfCellInfo)
{
sal_Int32 nDepth = pEndOfCellInfo->getDepth();
WW8TableNodeInfoInner::Pointer_t pInner = pEndOfCellInfo->getInnerForDepth(nDepth);
auto aIt = rLastRowEnds.find(nDepth);
if (aIt == rLastRowEnds.end() || (pInner->getRow() > aIt->second->getRow()))
rLastRowEnds[nDepth] = pInner.get();
}
WW8TableNodeInfo *
WW8TableInfo::processTableBox(const SwTable * pTable,
const SwTableBox * pBox,
sal_uInt32 nRow,
sal_uInt32 nCell,
sal_uInt32 nDepth,
bool bEndOfLine,
WW8TableNodeInfo * pPrev,
RowEndInners_t &rLastRowEnds)
{
SAL_INFO( "sw.ww8", "<processTableBox row=\"" << nRow << "\" cell=\"" << nCell
<< "\" depth=\"" << nDepth << "\">" );
WW8TableNodeInfo::Pointer_t pNodeInfo;
const SwTableLines & rLines = pBox->GetTabLines();
const SwStartNode * pSttNd = pBox->GetSttNd();
WW8TableNodeInfo::Pointer_t pEndOfCellInfo;
if (!rLines.empty())
{
pNodeInfo = processTableBoxLines(pBox, pTable, pBox, nRow, nCell, nDepth);
pNodeInfo->setEndOfCell(true);
if (bEndOfLine)
{
pNodeInfo->setEndOfLine(true);
updateFinalEndOfLine(rLastRowEnds, pNodeInfo.get());
}
for (size_t n = 0; n < rLines.size(); n++)
{
const SwTableLine * pLine = rLines[n];
pPrev = processTableLine(pTable, pLine, n, 1, pPrev, rLastRowEnds);
}
}
else
{
SwPaM aPaM(*pSttNd, 0);
bool bDone = false;
sal_uInt32 nDepthInsideCell = 0;
do
{
SwNode & rNode = aPaM.GetPoint()->GetNode();
if (rNode.IsStartNode())
{
if (nDepthInsideCell > 0)
pEndOfCellInfo.reset();
nDepthInsideCell++;
}
pNodeInfo = insertTableNodeInfo(&rNode, pTable, pBox, nRow, nCell, nDepth);
if (pPrev)
pPrev->setNext(pNodeInfo.get());
pPrev = pNodeInfo.get();
if (nDepthInsideCell == 1 && rNode.IsTextNode())
pEndOfCellInfo = pNodeInfo;
if (rNode.IsEndNode())
{
nDepthInsideCell--;
if (nDepthInsideCell == 0 && !pEndOfCellInfo)
pEndOfCellInfo = pNodeInfo;
SwEndNode * pEndNode = rNode.GetEndNode( );
SwStartNode * pTmpSttNd = pEndNode->StartOfSectionNode();
if (pTmpSttNd == pSttNd)
bDone = true;
}
aPaM.GetPoint()->Adjust(SwNodeOffset(1));
}
while (!bDone);
if (pEndOfCellInfo)
{
pEndOfCellInfo->setEndOfCell(true);
if (bEndOfLine)
{
pEndOfCellInfo->setEndOfLine(true);
updateFinalEndOfLine(rLastRowEnds, pEndOfCellInfo.get());
}
}
}
SAL_INFO( "sw.ww8", "</processTableBox>" );
return pPrev;
}
WW8TableNodeInfo::Pointer_t WW8TableInfo::insertTableNodeInfo
(const SwNode * pNode,
const SwTable * pTable,
const SwTableBox * pTableBox,
sal_uInt32 nRow,
sal_uInt32 nCell,
sal_uInt32 nDepth,
SwRect const * pRect)
{
WW8TableNodeInfo::Pointer_t pNodeInfo = getTableNodeInfo(pNode);
if (!pNodeInfo)
{
pNodeInfo =
std::make_shared<ww8::WW8TableNodeInfo>(this, pNode);
mMap.emplace(pNode, pNodeInfo);
}
pNodeInfo->setDepth(nDepth + pNodeInfo->getDepth());
pNodeInfo->setTable(pTable);
pNodeInfo->setTableBox(pTableBox);
pNodeInfo->setCell(nCell);
pNodeInfo->setRow(nRow);
if (pNode->IsTextNode())
{
FirstInTableMap_t::const_iterator aIt = mFirstInTableMap.find(pTable);
if (aIt == mFirstInTableMap.end())
{
mFirstInTableMap[pTable] = pNode;
pNodeInfo->setFirstInTable(true);
}
}
if (pRect)
{
WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
pCellGrid->insert(*pRect, pNodeInfo.get());
pNodeInfo->setRect(*pRect);
}
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", pNodeInfo->toString());
#endif
return pNodeInfo;
}
WW8TableCellGrid::Pointer_t WW8TableInfo::getCellGridForTable
(const SwTable * pTable, bool bCreate)
{
WW8TableCellGrid::Pointer_t pResult;
CellGridMap_t::iterator aIt = mCellGridMap.find(pTable);
if (aIt == mCellGridMap.end())
{
if (bCreate)
{
pResult = std::make_shared<ww8::WW8TableCellGrid>();
mCellGridMap[pTable] = pResult;
}
}
else
pResult = mCellGridMap[pTable];
return pResult;
}
WW8TableNodeInfo::Pointer_t WW8TableInfo::getTableNodeInfo
(const SwNode * pNode)
{
WW8TableNodeInfo::Pointer_t pResult;
Map_t::iterator aIt = mMap.find(pNode);
if (aIt != mMap.end())
pResult = (*aIt).second;
return pResult;
}
const SwNode * WW8TableInfo::getNextNode(const SwNode * pNode)
{
const SwNode * pResult = nullptr;
WW8TableNodeInfo::Pointer_t pNodeInfo = getTableNodeInfo(pNode);
if (pNodeInfo)
{
WW8TableNodeInfo * pNextInfo = pNodeInfo->getNext();
if (pNextInfo != nullptr)
pResult = pNextInfo->getNode();
else
{
const SwNode * pNextNode = pNodeInfo->getNextNode();
if (pNextNode != nullptr)
pResult = pNextNode;
}
}
return pResult;
}
bool WW8TableNodeInfo::operator < (const WW8TableNodeInfo & rInfo) const
{
bool bRet = false;
if (rInfo.mpNode != nullptr)
{
if (mpNode == nullptr)
{
bRet = true;
}
else
{
if (mpNode->GetIndex() < rInfo.mpNode->GetIndex())
bRet = true;
}
}
return bRet;
}
bool CellInfo::operator < (const CellInfo & aCellInfo) const
{
bool aRet = false;
if (top() < aCellInfo.top())
aRet = true;
else if (top() == aCellInfo.top())
{
if (left() < aCellInfo.left())
aRet = true;
else if (left() == aCellInfo.left())
{
if (width() < aCellInfo.width())
aRet = true;
else if (width() == aCellInfo.width())
{
if (height() < aCellInfo.height())
aRet = true;
else if (height() == aCellInfo.height())
{
if (aCellInfo.getTableNodeInfo())
{
if (m_pNodeInfo == nullptr)
aRet = true;
else
{
aRet = *m_pNodeInfo < *aCellInfo.getTableNodeInfo();
}
}
}
}
}
}
return aRet;
}
#ifdef DBG_UTIL
std::string CellInfo::toString() const
{
static char sBuffer[256];
snprintf(sBuffer, sizeof(sBuffer),
"<cellinfo left=\"%" SAL_PRIdINT64 "\""
" right=\"%" SAL_PRIdINT64 "\""
" top=\"%" SAL_PRIdINT64 "\""
" bottom=\"%" SAL_PRIdINT64 "\""
" node=\"%p\"/>",
sal_Int64(left()),
sal_Int64(right()),
sal_Int64(top()),
sal_Int64(bottom()),
m_pNodeInfo);
return sBuffer;
}
#endif
WW8TableNodeInfo * WW8TableInfo::reorderByLayout(const SwTable * pTable, RowEndInners_t &rLastRowEnds)
{
WW8TableCellGrid::Pointer_t pCellGrid = getCellGridForTable(pTable);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", pCellGrid->toString());
#endif
pCellGrid->addShadowCells();
return pCellGrid->connectCells(rLastRowEnds);
}
WW8TableCellGrid::WW8TableCellGrid()
{
}
WW8TableCellGrid::~WW8TableCellGrid()
{
}
WW8TableCellGridRow::Pointer_t WW8TableCellGrid::getRow(tools::Long nTop, bool bCreate)
{
WW8TableCellGridRow::Pointer_t pResult;
RowTops_t::iterator aIt = m_aRowTops.find(nTop);
if (aIt == m_aRowTops.end())
{
if (bCreate)
{
pResult = std::make_shared<ww8::WW8TableCellGridRow>();
m_aRows[nTop] = pResult;
m_aRowTops.insert(nTop);
}
}
else
pResult = m_aRows[nTop];
return pResult;
}
WW8TableCellGrid::RowTops_t::const_iterator WW8TableCellGrid::getRowTopsBegin() const
{
return m_aRowTops.begin();
}
WW8TableCellGrid::RowTops_t::const_iterator WW8TableCellGrid::getRowTopsEnd() const
{
return m_aRowTops.end();
}
CellInfoMultiSet::const_iterator WW8TableCellGrid::getCellsBegin(tools::Long nTop)
{
return getRow(nTop)->begin();
}
CellInfoMultiSet::const_iterator WW8TableCellGrid::getCellsEnd(tools::Long nTop)
{
return getRow(nTop)->end();
}
void WW8TableCellGrid::insert(const SwRect & rRect,
WW8TableNodeInfo * pNodeInfo,
const tools::ULong * pFormatFrameWidth)
{
CellInfo aCellInfo(rRect, pNodeInfo);
if (pFormatFrameWidth != nullptr)
aCellInfo.setFormatFrameWidth(*pFormatFrameWidth);
WW8TableCellGridRow::Pointer_t pRow = getRow(rRect.Top());
pRow->insert(aCellInfo);
}
void WW8TableCellGrid::addShadowCells()
{
SAL_INFO( "sw.ww8", "<addShadowCells>" );
RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
while (aTopsIt != getRowTopsEnd())
{
CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
CellInfoMultiSet::const_iterator aCellEndIt = getCellsEnd(*aTopsIt);
RowSpansPtr pRowSpans = std::make_shared<RowSpans>();
bool bBeginningOfCell = true;
bool bVertMerge = false;
SwRect aRect = aCellIt->getRect();
sal_Int32 nRowSpan = 1;
while (aCellIt != aCellEndIt)
{
WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
if (bBeginningOfCell)
{
RowTops_t::const_iterator aRowSpanIt(aTopsIt);
++aRowSpanIt;
if (aRowSpanIt != getRowTopsEnd() &&
*aRowSpanIt < aCellIt->bottom())
{
aRect.Top(*aRowSpanIt);
tools::ULong nFormatFrameWidth = aCellIt->getFormatFrameWidth();
insert(aRect, nullptr, &nFormatFrameWidth);
bVertMerge = true;
}
else
bVertMerge = false;
nRowSpan = 1;
while (aRowSpanIt != getRowTopsEnd() &&
*aRowSpanIt < aCellIt->bottom())
{
++aRowSpanIt;
nRowSpan++;
}
if (pNodeInfo)
pRowSpans->push_back(nRowSpan);
else
pRowSpans->push_back(-nRowSpan);
}
if (pNodeInfo)
{
pNodeInfo->setVertMerge(bVertMerge);
}
++aCellIt;
if (aCellIt != aCellEndIt)
{
bBeginningOfCell = (aRect.Left() != aCellIt->left());
aRect = aCellIt->getRect();
}
}
WW8TableCellGridRow::Pointer_t pRow = getRow(*aTopsIt);
if (pRow)
pRow->setRowSpans(pRowSpans);
++aTopsIt;
}
SAL_INFO( "sw.ww8", "</addShadowCells>" );
}
WW8TableNodeInfo * WW8TableCellGrid::connectCells(RowEndInners_t &rLastRowEnds)
{
RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
sal_uInt32 nRow = 0;
WW8TableNodeInfo * pLastNodeInfo = nullptr;
while (aTopsIt != getRowTopsEnd())
{
CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
CellInfoMultiSet::const_iterator aCellEndIt = getCellsEnd(*aTopsIt);
GridColsPtr pWidths = std::make_shared<Widths>();
TableBoxVectorPtr pTableBoxes = std::make_shared<TableBoxVector>();
sal_uInt32 nShadows = 0;
sal_uInt32 nCell = 0;
bool bBeginningOfCell = true;
WW8TableNodeInfo * pEndOfCellInfo = nullptr;
sal_uInt32 nDepthInCell = 0;
while (aCellIt != aCellEndIt)
{
tools::Long nCellX = aCellIt->left();
WW8TableNodeInfo * pNodeInfo = aCellIt->getTableNodeInfo();
if (pNodeInfo)
{
const SwNode * pNode = pNodeInfo->getNode();
if (pNode->IsStartNode())
{
nDepthInCell++;
pEndOfCellInfo = nullptr;
}
if (nDepthInCell == 1 && pNode->IsTextNode())
pEndOfCellInfo = pNodeInfo;
pNodeInfo->setShadowsBefore(nShadows);
pNodeInfo->setCell(nCell);
pNodeInfo->setRow(nRow);
if (pLastNodeInfo)
{
pLastNodeInfo->setNext(pNodeInfo);
pLastNodeInfo->setNextNode(pNode);
}
pLastNodeInfo = pNodeInfo;
nShadows = 0;
if (pNode->IsEndNode())
{
assert(nDepthInCell > 0 && "otherwise overflow");
nDepthInCell--;
if (nDepthInCell == 0 && !pEndOfCellInfo)
pEndOfCellInfo = pNodeInfo;
}
}
else
{
nShadows++;
}
if (bBeginningOfCell)
{
pWidths->push_back(aCellIt->getFormatFrameWidth());
if (pNodeInfo)
pTableBoxes->push_back(pNodeInfo->getTableBox());
else
pTableBoxes->push_back(nullptr);
}
++aCellIt;
bBeginningOfCell = false;
if (aCellIt != aCellEndIt && aCellIt->left() != nCellX)
{
nCell++;
bBeginningOfCell = true;
if (pEndOfCellInfo)
{
pEndOfCellInfo->setEndOfCell(true);
}
pEndOfCellInfo = nullptr;
}
}
pLastNodeInfo->setShadowsAfter(nShadows);
if (!pEndOfCellInfo)
{
pEndOfCellInfo = pLastNodeInfo;
}
pEndOfCellInfo->setEndOfCell(true);
pLastNodeInfo->setEndOfLine(true);
updateFinalEndOfLine(rLastRowEnds, pLastNodeInfo);
WW8TableCellGridRow::Pointer_t pRow(getRow(*aTopsIt));
pRow->setTableBoxVector(pTableBoxes);
pRow->setWidths(pWidths);
++aTopsIt;
nRow++;
}
return pLastNodeInfo;
}
#ifdef DBG_UTIL
std::string WW8TableCellGrid::toString()
{
std::string sResult = "<WW8TableCellGrid>";
RowTops_t::const_iterator aTopsIt = getRowTopsBegin();
static char sBuffer[1024];
while (aTopsIt != getRowTopsEnd())
{
sResult += "<row y=\"";
sResult += OString::number(*aTopsIt);
sResult += "\">";
CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
CellInfoMultiSet::const_iterator aCellsEnd = getCellsEnd(*aTopsIt);
while (aCellIt != aCellsEnd)
{
snprintf(sBuffer, sizeof(sBuffer), "<cellInfo top=\"%" SAL_PRIdINT64 "\" bottom=\"%" SAL_PRIdINT64 "\" left=\"%" SAL_PRIdINT64 "\" right=\"%" SAL_PRIdINT64 "\">",
sal_Int64(aCellIt->top()), sal_Int64(aCellIt->bottom()), sal_Int64(aCellIt->left()), sal_Int64(aCellIt->right()));
sResult += sBuffer;
WW8TableNodeInfo * pInfo = aCellIt->getTableNodeInfo();
if (pInfo)
sResult += pInfo->toString();
else
sResult += "<shadow/>\n";
sResult += "</cellInfo>\n";
++aCellIt;
}
WW8TableCellGridRow::Pointer_t pRow = getRow(*aTopsIt);
WidthsPtr pWidths = pRow->getWidths();
if (pWidths != nullptr)
{
sResult += "<widths>";
Widths::const_iterator aItEnd = pWidths->end();
for (Widths::const_iterator aIt = pWidths->begin();
aIt != aItEnd;
++aIt)
{
if (aIt != pWidths->begin())
sResult += ", ";
snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32 "", *aIt);
sResult += sBuffer;
}
sResult += "</widths>";
}
RowSpansPtr pRowSpans = pRow->getRowSpans();
if (pRowSpans)
{
sResult += "<rowspans>";
RowSpans::const_iterator aItEnd = pRowSpans->end();
for (RowSpans::const_iterator aIt = pRowSpans->begin();
aIt != aItEnd;
++aIt)
{
if (aIt != pRowSpans->begin())
sResult += ", ";
snprintf(sBuffer, sizeof(sBuffer), "%" SAL_PRIxUINT32 "", *aIt);
sResult += sBuffer;
}
sResult += "</rowspans>";
}
sResult += "</row>\n";
++aTopsIt;
}
sResult += "</WW8TableCellGrid>\n";
return sResult;
}
#endif
TableBoxVectorPtr WW8TableCellGrid::getTableBoxesOfRow
(WW8TableNodeInfoInner const * pNodeInfoInner)
{
TableBoxVectorPtr pResult;
WW8TableCellGridRow::Pointer_t pRow =
getRow(pNodeInfoInner->getRect().Top(), false);
if (pRow)
{
pResult = pRow->getTableBoxVector();
}
return pResult;
}
WidthsPtr WW8TableCellGrid::getWidthsOfRow
(WW8TableNodeInfoInner const * pNodeInfoInner)
{
GridColsPtr pResult;
WW8TableCellGridRow::Pointer_t pRow =
getRow(pNodeInfoInner->getRect().Top(), false);
if (pRow)
{
pResult = pRow->getWidths();
}
return pResult;
}
RowSpansPtr WW8TableCellGrid::getRowSpansOfRow
(WW8TableNodeInfoInner const * pNodeInfoInner)
{
RowSpansPtr pResult;
WW8TableCellGridRow::Pointer_t pRow =
getRow(pNodeInfoInner->getRect().Top(), false);
if (pRow)
{
pResult = pRow->getRowSpans();
}
return pResult;
}
WW8TableCellGridRow::WW8TableCellGridRow()
: m_pCellInfos(std::make_shared<CellInfoMultiSet>())
{
}
WW8TableCellGridRow::~WW8TableCellGridRow()
{
}
void WW8TableCellGridRow::insert(const CellInfo & rCellInfo)
{
m_pCellInfos->insert(rCellInfo);
#ifdef DBG_UTIL
SAL_INFO( "sw.ww8", "<gridRowInsert>" << rCellInfo.toString() << "</gridRowInsert>" );
#endif
}
CellInfoMultiSet::const_iterator WW8TableCellGridRow::begin() const
{
return m_pCellInfos->begin();
}
CellInfoMultiSet::const_iterator WW8TableCellGridRow::end() const
{
return m_pCellInfos->end();
}
void WW8TableCellGridRow::setTableBoxVector(TableBoxVectorPtr const & pTableBoxVector)
{
if (pTableBoxVector->size() > MAXTABLECELLS)
pTableBoxVector->resize(MAXTABLECELLS);
m_pTableBoxVector = pTableBoxVector;
}
void WW8TableCellGridRow::setWidths(WidthsPtr const & pWidths)
{
m_pWidths = pWidths;
}
void WW8TableCellGridRow::setRowSpans(RowSpansPtr const & pRowSpans)
{
m_pRowSpans = pRowSpans;
}
CellInfo::CellInfo(const SwRect & aRect, WW8TableNodeInfo * pNodeInfo)
: m_aRect(aRect), m_pNodeInfo(pNodeInfo), m_nFormatFrameWidth(0)
{
if (pNodeInfo != nullptr)
{
const SwTableBox * pBox = pNodeInfo->getTableBox();
const SwFrameFormat * pFrameFormat = pBox->GetFrameFormat();
const SwFormatFrameSize & rSize = pFrameFormat->GetFrameSize();
m_nFormatFrameWidth = rSize.GetWidth();
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1029 Numeric Truncation Error. Return value of the 'size' function is written to the 8-bit variable.