#include "Table.h" #include "Common.h" #include "src/CCompiledStyle.h" namespace HTML { #define MAX_STRING_BLOCK_SIZE (size_t)10485760 #define FIRST_ELEMENT 0x00000001 #define LAST_ELEMENT 0x00000002 #define MID_ELEMENT 0x00000004 #define PARSE_MODE_HEADER 0x00000100 #define PARSE_MODE_BODY 0x00000200 #define PARSE_MODE_FOOTHER 0x00000400 #define COL_POSITION_MASK 0x0000000F #define ROW_POSITION_MASK 0x000000F0 #define PARSE_MODE_MASK 0x00000F00 #define DEFAULT_PAGE_WIDTH 12240 // Значение в Twips #define DEFAULT_PAGE_HEIGHT 15840 // Значение в Twips // const TTableCellStyle* CStorageTable::GetColStyle(UINT unColumnNumber) const // { // if (m_arColgroups.empty()) // return NULL; // UINT unCurrentNumber = 0; // for (const CTableColgroup* pColgroup : m_arColgroups) // { // for (const CTableCol* pCol : pColgroup->GetCols()) // { // unCurrentNumber += pCol->GetSpan(); // if (unCurrentNumber >= unColumnNumber) // return pCol->GetStyle(); // } // } // return NULL; // } // void CStorageTable::AddColgroup(CTableColgroup* pElement) // { // if (NULL != pElement) // m_arColgroups.push_back(pElement); // } // void CStorageTable::RecalculateMaxColumns() // { // for (const std::vector& arHeaders : m_arHeaders) // for (const CStorageTableRow* pHeader : arHeaders) // m_unMaxColumns = std::max(m_unMaxColumns, pHeader->GetIndex()); // for (const CStorageTableRow* pRow : m_arRows) // m_unMaxColumns = std::max(m_unMaxColumns, pRow->GetIndex()); // for (const CStorageTableRow* pFoother : m_arFoother) // m_unMaxColumns = std::max(m_unMaxColumns, pFoother->GetIndex()); // } // void CStorageTable::Shorten() // { // UINT unIndex = 0; // CStorageTableCell* pCell = NULL; // UINT unMaxIndex = 0; //Максимальный индекс без учета строк, где имеется только 1 ячейка // for (const CStorageTableRow* pRow : m_arRows) // { // if (1 < pRow->GetCount()) // unMaxIndex = std::max(unMaxIndex, pRow->GetIndex()); // } // while (unIndex < m_arMinColspan.size()) // { // for (CStorageTableRow* pRow : m_arRows) // { // if (0 != unMaxIndex && 1 == pRow->GetCount() && pRow->GetIndex() > unMaxIndex) // { // pCell = (*pRow)[unIndex]; // if (NULL == pCell) // continue; // pCell->SetColspan(unMaxIndex, MAXCOLUMNSINTABLE); // continue; // } // if (1 == m_arMinColspan[unIndex]) // break; // pCell = (*pRow)[unIndex]; // if (NULL == pCell) // continue; // if (1 < pCell->GetColspan() && pCell->GetColspan() > m_arMinColspan[unIndex]) // { // pCell->SetColspan(m_arMinColspan[unIndex], MAXCOLUMNSINTABLE); // continue; // } // if ((*pRow)[unIndex]->GetColspan() == m_arMinColspan[unIndex] + 1) // (*pRow)[unIndex]->SetColspan(2, MAXCOLUMNSINTABLE); // else if ((*pRow)[unIndex]->GetColspan() > m_arMinColspan[unIndex]) // (*pRow)[unIndex]->SetColspan((*pRow)[unIndex]->GetColspan() - m_arMinColspan[unIndex], MAXCOLUMNSINTABLE); // } // ++unIndex; // } // } ITableElementCell::ITableElementCell(size_t unColspan) : m_unColspan(unColspan) {} void ITableElementCell::SetColspan(size_t unColspan) { if (0 < unColspan) m_unColspan = unColspan; } size_t ITableElementCell::GetColspan() const { return m_unColspan; } CTableElementCell::CTableElementCell(bool bIsFilling, size_t unColspan) : ITableElementCell(unColspan), m_eType{(bIsFilling) ? ETableElement::FillingCell : ETableElement::Cell} {} CTableElementCell::~CTableElementCell() {} ETableElement CTableElementCell::GetType() const { return m_eType; } void CTableElementCell::IsFlatTable() { m_eType = ETableElement::FlatTable; } CTableElementCell* CTableElementCell::CreateCell(const size_t& unColspan) { return new CTableElementCell(false, unColspan); } CTableElementCell* CTableElementCell::CreateFillingCell(const size_t& unColspan) { return new CTableElementCell(true, unColspan); } CTableMatrix::CTableMatrix() {} CTableMatrix::~CTableMatrix() { for (Row& oRow : m_arCells) { for (ITableElementCell* pCell : oRow) { if (nullptr != pCell) delete pCell; } } } bool CTableMatrix::Empty() const { return m_arCells.empty(); } void CTableMatrix::Clear() { m_arCells.clear(); } bool CTableMatrix::SetCell(size_t unRowIndex, size_t unColumnIndex, ITableElementCell* pCell, bool bAutoClean) { if (nullptr == pCell) return false; if (m_arCells.size() <= unRowIndex) { if (!m_arCells.empty()) { const size_t unMaxColumn{m_arCells.back().size()}; const size_t unOldSize{m_arCells.size()}; m_arCells.resize(unRowIndex + 1); for (size_t unIndex = unOldSize; unIndex < m_arCells.size(); ++unIndex) m_arCells[unIndex].resize(unMaxColumn); } else m_arCells.resize(unRowIndex + 1); } if (m_arCells[unRowIndex].size() <= unColumnIndex) { m_arCells[unRowIndex].resize(unColumnIndex + 1); m_arCells[unRowIndex][unColumnIndex] = pCell; return true; } if (nullptr != m_arCells[unRowIndex][unColumnIndex]) { pCell->SetColspan(m_arCells[unRowIndex][unColumnIndex]->GetColspan()); if (bAutoClean) delete m_arCells[unRowIndex][unColumnIndex]; } m_arCells[unRowIndex][unColumnIndex] = pCell; return true; } void CTableMatrix::NormalizeNumberColumns(size_t unNumberColumns) { if (m_arCells.empty()) return; for (Row& oRow : m_arCells) if (unNumberColumns > oRow.size()) oRow.resize(unNumberColumns); } bool CTableMatrix::IsFillingCell(size_t unRowIndex, size_t unColumnIndex) const { if (unRowIndex >= m_arCells.size()) return false; if (unColumnIndex >= m_arCells[unRowIndex].size()) return false; return (nullptr != m_arCells[unRowIndex][unColumnIndex]) ? ETableElement::FillingCell == m_arCells[unRowIndex][unColumnIndex]->GetType() : false; } bool CTableMatrix::IsNotNullCell(size_t unRowIndex, size_t unColumnIndex) const { if (unRowIndex >= m_arCells.size()) return false; if (unColumnIndex >= m_arCells[unRowIndex].size()) return false; return nullptr != m_arCells[unRowIndex][unColumnIndex]; } size_t CTableMatrix::GetRowSize() const { return m_arCells.size(); } size_t CTableMatrix::GetColumnSize() const { return (m_arCells.empty()) ? 0 : m_arCells.front().size(); } Table& CTableMatrix::GetMatrixCells() { return m_arCells; } const Table& CTableMatrix::GetMatrixCells() const { return m_arCells; } const ITableElementCell* CTableMatrix::GetCell(size_t unRowIndex, size_t unColumnIndex) const { if (unRowIndex >= m_arCells.size()) return nullptr; if (unColumnIndex >= m_arCells[unRowIndex].size()) return nullptr; return m_arCells[unRowIndex][unColumnIndex]; } ITableElementCell* CTableMatrix::GetCell(size_t unRowIndex, size_t unColumnIndex) { if (unRowIndex >= m_arCells.size()) return nullptr; if (unColumnIndex >= m_arCells[unRowIndex].size()) return nullptr; return m_arCells[unRowIndex][unColumnIndex]; } CTableElement::CTableElement(TExternalTableData &oExternalData) : m_pCaption(nullptr), m_oExternalData(oExternalData) {} CTableElement::~CTableElement() { Clear(); } void CTableElement::Clear() { if (nullptr != m_pCaption) { delete m_pCaption; m_pCaption = nullptr; } for (CTableColgroup* pColgroup : m_arColgroups) if (nullptr != pColgroup) delete pColgroup; m_arColgroups.clear(); m_oHeader.Clear(); m_oBody.Clear(); m_oFoother.Clear(); } bool CTableElement::Empty() const { return m_oHeader.Empty() && m_oBody.Empty() && m_oFoother.Empty(); } bool CTableElement::HaveCaption() const { return nullptr != m_pCaption && 0 != m_pCaption->GetCurSize(); } const NSCSS::CCompiledStyle* CTableElement::GetColStyle(size_t unColIndex) const { if (m_arColgroups.empty()) return nullptr; const NSCSS::CCompiledStyle* pColStyle{nullptr}; size_t unSkipSpans{0}; for (const CTableColgroup* pColgroup : m_arColgroups) { pColStyle = pColgroup->GetColStyle(unColIndex - unSkipSpans); if (nullptr != pColStyle) return pColStyle; unSkipSpans += pColgroup->GetTotalSpans(); } return nullptr; } bool MoveToNextTableCell(XmlUtils::CXmlLiteReader& oReader, std::vector& arSelectors, std::stack& arDepths, TExternalTableData::FuncGetSubClass& GetSubClass) { while (!arDepths.empty() && !oReader.ReadNextSiblingNode2(arDepths.top())) { arDepths.pop(); arSelectors.pop_back(); } if (arDepths.empty()) return false; do { const std::wstring wsName = oReader.GetName(); if (L"#text" == wsName || L"colgroup" == wsName || L"caption" == wsName) return MoveToNextTableCell(oReader, arSelectors, arDepths, GetSubClass); GetSubClass(oReader, arSelectors); if (L"td" == wsName || L"th" == wsName) return true; else if (L"table" == wsName) return false; arDepths.push(oReader.GetDepth()); return MoveToNextTableCell(oReader, arSelectors, arDepths, GetSubClass); }while(oReader.ReadNextSiblingNode2(arDepths.top())); return false; } CTableContainer::CTableContainer() : ITableElementCell(1) {} CTableContainer::~CTableContainer() { for (const CTableElement* pTable : m_arTables) if (nullptr != pTable) delete pTable; } ETableElement CTableContainer::GetType() const { return ETableElement::TableContainer; } void CTableContainer::AddTable(CTableElement* pTable) { if (nullptr != pTable) m_arTables.push_back(pTable); } const std::vector& CTableContainer::GetTables() const { return m_arTables; } CTableCol::CTableCol(NSCSS::CNode& oTableColNode) : m_pStyle(oTableColNode.m_pCompiledStyle) { oTableColNode.m_pCompiledStyle = nullptr; m_unSpan = NSStringFinder::ToInt(oTableColNode.GetAttributeValue(L"span"), 1); } CTableCol::~CTableCol() { if (nullptr != m_pStyle) delete m_pStyle; } UINT CTableCol::GetSpan() const { return m_unSpan; } const NSCSS::CCompiledStyle* CTableCol::GetStyle() const { return m_pStyle; } CTableColgroup::CTableColgroup(const NSCSS::CNode& oTableColgroupNode) : m_unTotalSpans(0) { m_unWidth = NSStringFinder::ToInt(oTableColgroupNode.GetAttributeValue(L"width"), 0); } CTableColgroup::~CTableColgroup() { for (CTableCol* pCol : m_arCols) if (nullptr != pCol) delete pCol; } bool CTableColgroup::Empty() const { return m_arCols.empty(); } void CTableColgroup::AddCol(CTableCol* pCol) { if (nullptr == pCol) return; m_arCols.push_back(pCol); m_unTotalSpans += pCol->GetSpan(); } UINT CTableColgroup::GetTotalSpans() const { return m_unTotalSpans; } const std::vector& CTableColgroup::GetCols() const { return m_arCols; } const NSCSS::CCompiledStyle* CTableColgroup::GetColStyle(size_t unIndex) const { if (m_arCols.empty()) return nullptr; size_t unCurrentIndex{0}; for (const CTableCol* pCol : m_arCols) { if (unCurrentIndex <= unIndex && (unCurrentIndex + pCol->GetSpan()) > unIndex) return pCol->GetStyle(); unCurrentIndex += pCol->GetSpan(); } return nullptr; } }