diff --git a/Common/3dParty/html/css/src/xhtml/CDocumentStyle.cpp b/Common/3dParty/html/css/src/xhtml/CDocumentStyle.cpp index 816ca43c35..9948bb9e72 100644 --- a/Common/3dParty/html/css/src/xhtml/CDocumentStyle.cpp +++ b/Common/3dParty/html/css/src/xhtml/CDocumentStyle.cpp @@ -317,7 +317,7 @@ namespace NSCSS oXmlElement.AddPropertiesInP(PProperties::P_ContextualSpacing, L"true"); } - if (!oStyle.m_oBackground.Empty() && oStyle.HaveThisParent(L"table")) + if (!oStyle.m_oBackground.Empty() && !oStyle.HaveThisParent(L"table")) oXmlElement.AddPropertiesInP(PProperties::P_Shd, oStyle.m_oBackground.IsNone() ? L"auto" : oStyle.m_oBackground.GetColor().ToWString()); if (!oStyle.m_oBorder.Empty() && !oStyle.HaveThisParent(L"table")) diff --git a/HtmlFile2/htmlfile2.cpp b/HtmlFile2/htmlfile2.cpp index bdbfcad343..ee91b818e4 100644 --- a/HtmlFile2/htmlfile2.cpp +++ b/HtmlFile2/htmlfile2.cpp @@ -41,6 +41,8 @@ #define DEFAULT_PAGE_WIDTH 12240 // Значение в Twips #define DEFAULT_PAGE_HEIGHT 15840 // Значение в Twips +#define SAVE_NORMALIZED_HTML 0 + std::wstring rStyle = L" a area b strong bdo bdi big br center cite dfn em i var code kbd samp tt del s font img ins u mark q rt sup small sub svg input basefont button label data object noscript output abbr time ruby progress hgroup meter span acronym "; //struct CTree @@ -273,6 +275,11 @@ public: m_oStyles.m_wsAlign = wsAlign; } + void SetBackground(const NSCSS::NSProperties::CColor& oColor) + { + m_oStyles.m_oBackground = oColor; + } + std::wstring ConvertToOOXML(const TTableStyles& oTableStyles) { NSStringUtils::CStringBuilder oCell; @@ -285,12 +292,25 @@ public: if (NSCSS::UnitMeasure::Percent == m_oStyles.m_oWidth.GetUnitMeasure()) oCell += L""; else - oCell += L""; + { + if (!m_oStyles.m_oWidth.Zero()) + { + int nWidth; + if (NSCSS::UnitMeasure::None != m_oStyles.m_oWidth.GetUnitMeasure()) + nWidth = m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Twips); + else + nWidth = static_cast(NSCSS::CUnitMeasureConverter::ConvertPx(m_oStyles.m_oWidth.ToDouble(), NSCSS::UnitMeasure::Twips, 96) + 0.5); + + oCell += L""; + } + else + oCell += L""; + } } else oCell += L""; - if (1 < m_unColspan) + if (1 != m_unColspan) oCell += L""; if (m_bIsMerged) @@ -465,6 +485,29 @@ public: RELEASEOBJECT(pRow); } + CTableRow* operator[](UINT unIndex) + { + if (unIndex < m_arRows.size()) + return m_arRows[unIndex]; + + return NULL; + } + + bool Empty() const + { + return m_arRows.empty(); + } + + bool HaveCaption() + { + return 0 != m_oCaption.GetCurSize(); + } + + UINT GetRowCount() const + { + return m_arRows.size(); + } + void AddRow(CTableRow* pRow) { if (NULL == pRow) @@ -481,6 +524,11 @@ public: m_arRows.push_back(pRow); } + void SetCaption(const NSStringUtils::CStringBuilder& oCaption) + { + m_oCaption = oCaption; + } + void SetPadding(const NSCSS::NSProperties::CIndent& oPadding) { m_oStyles.m_oPadding = oPadding; @@ -521,6 +569,16 @@ public: return m_oStyles.m_bHaveBorderAttribute; } + UINT GetMaxColumns() + { + UINT unMaxColumns = 0; + + for (const CTableRow* pRow : m_arRows) + unMaxColumns = std::max(unMaxColumns, pRow->GetIndex()); + + return unMaxColumns; + } + void ApplyRowspan() { CTableCell* pCell = NULL; @@ -553,6 +611,12 @@ public: if (NULL == pCell) continue; + if (1 != pCell->GetColspan() && unIndex + pCell->GetColspan() > m_arMinColspan[unIndex]) + { + pCell->SetColspan(m_arMinColspan[unIndex] - unIndex, MAXCOLUMNSINTABLE); + continue; + } + if ((*pRow)[unIndex]->GetColspan() == m_arMinColspan[unIndex] + 1) (*pRow)[unIndex]->SetColspan(2, MAXCOLUMNSINTABLE); else if ((*pRow)[unIndex]->GetColspan() > m_arMinColspan[unIndex]) @@ -596,12 +660,23 @@ public: if (NSCSS::UnitMeasure::Percent == m_oStyles.m_oWidth.GetUnitMeasure()) oTable += L""; else - oTable += L""; + { + int nWidth; + if (NSCSS::UnitMeasure::None != m_oStyles.m_oWidth.GetUnitMeasure()) + nWidth = m_oStyles.m_oWidth.ToInt(NSCSS::UnitMeasure::Twips); + else + nWidth = static_cast(NSCSS::CUnitMeasureConverter::ConvertPx(m_oStyles.m_oWidth.ToDouble(), NSCSS::UnitMeasure::Twips, 96) + 0.5); + + oTable += L""; + } } else oTable += L""; - if (0 < m_oStyles.m_nCellSpacing) + if (!m_oStyles.m_wsAlign.empty()) + oTable += L""; + + if (0 <= m_oStyles.m_nCellSpacing) oTable += L""; if (!m_oStyles.m_oBorder.Empty() && !m_oStyles.m_oBorder.Zero()) @@ -624,12 +699,28 @@ public: else oTable += L""; - if (!m_oStyles.m_wsAlign.empty()) - oTable += L""; - oTable += L""; oTable.WriteNodeEnd(L"w:tblPr"); + if (HaveCaption()) + { + oTable.WriteNodeBegin(L"w:tr"); + oTable.WriteNodeBegin(L"w:trPr"); + oTable += L""; + oTable.WriteNodeEnd(L"w:trPr"); + oTable.WriteNodeBegin(L"w:tc"); + oTable.WriteNodeBegin(L"w:tcPr"); + oTable += L""; + oTable += L""; + oTable += L""; + oTable += L""; + oTable += L""; + oTable.WriteNodeEnd(L"w:tcPr"); + oTable.WriteString(m_oCaption.GetData()); + oTable.WriteNodeEnd(L"w:tc"); + oTable.WriteNodeEnd(L"w:tr"); + } + for (CTableRow* pRow : m_arRows) oTable += pRow->ConvertToOOXML(m_oStyles); @@ -641,6 +732,8 @@ private: std::vector m_arRows; std::vector m_arMinColspan; + NSStringUtils::CStringBuilder m_oCaption; + TTableStyles m_oStyles; }; @@ -1074,13 +1167,16 @@ public: std::wstring sRes = htmlToXhtml(sFileContent); -// NSFile::CFileBinary oWriter; -// if (oWriter.CreateFileW(m_sTmp + L"/res.html")) -// { -// oWriter.WriteStringUTF8(sRes); -// oWriter.CloseFile(); -// } - + #ifdef SAVE_NORMALIZED_HTML + #if 1 == SAVE_NORMALIZED_HTML + NSFile::CFileBinary oWriter; + if (oWriter.CreateFileW(m_sTmp + L"/res.html")) + { + oWriter.WriteStringUTF8(sRes); + oWriter.CloseFile(); + } + #endif + #endif return m_oLightReader.FromString(sRes); } @@ -1892,7 +1988,7 @@ private: // Таблицы else if(sName == L"table") readTable(oXml, sSelectors, oTS); - // Текст с границами + // Текст с границами else if(sName == L"textarea" || sName == L"fieldset") { CTextSettings oTSP(oTS); @@ -2197,6 +2293,51 @@ private: } } + void CalculateCellStyles(CTableCell* pCell, const std::vector& arSelectors) + { + if (NULL == pCell) + return; + + std::vector arNewSelectors{(std::vector::const_iterator)std::find_if(arSelectors.begin(), arSelectors.end(), [](const NSCSS::CNode& oNode){ return L"table" == oNode.m_wsName; }), arSelectors.cend()}; + + NSCSS::CCompiledStyle oStyle; + m_oStylesCalculator.GetCompiledStyle(oStyle, arNewSelectors); + + pCell->SetAlign(oStyle.m_oDisplay.GetHAlign().ToWString()); + pCell->SetBackground(oStyle.m_oBackground.GetColor()); + pCell->SetHeight(oStyle.m_oDisplay.GetHeight()); + pCell->SetWidth(oStyle.m_oDisplay.GetWidth()); + pCell->SetPadding(oStyle.m_oPadding); + pCell->SetBorder(oStyle.m_oBorder); + } + + struct TTableCaption + { + UINT m_unPrevRows; + NSStringUtils::CStringBuilder m_oData; + + TTableCaption(UINT unPrevRows = 0) : m_unPrevRows(unPrevRows) + {} + }; + + void ParseTableCaption(CTable& oTable, std::vector& sSelectors, const CTextSettings& oTS, std::vector& arCaptions) + { + GetSubClass(NULL, sSelectors); + + TTableCaption *pData = new TTableCaption(oTable.GetRowCount()); + + CTextSettings oTSCaption{oTS}; + oTSCaption.sPStyle += L""; + + wrP(&(pData->m_oData), sSelectors, oTSCaption); + readStream(&(pData->m_oData), sSelectors, oTSCaption); + CloseP(&(pData->m_oData), sSelectors); + + arCaptions.push_back(pData); + sSelectors.pop_back(); + return; + } + void ParseTableRows(CTable& oTable, std::vector& sSelectors, const CTextSettings& oTS) { int nDeath = m_oLightReader.GetDepth(); @@ -2215,17 +2356,7 @@ private: CTableCell *pCell = new CTableCell(); GetSubClass(pCell->GetData(), sSelectors); - - std::vector arNewSelectors{(std::vector::const_iterator)std::find_if(sSelectors.begin(), sSelectors.end(), [](const NSCSS::CNode& oNode){ return L"table" == oNode.m_wsName; }), sSelectors.cend()}; - - NSCSS::CCompiledStyle oStyle; - m_oStylesCalculator.GetCompiledStyle(oStyle, arNewSelectors); - - pCell->SetAlign(oStyle.m_oDisplay.GetHAlign().ToWString()); - pCell->SetHeight(oStyle.m_oDisplay.GetHeight()); - pCell->SetWidth(oStyle.m_oDisplay.GetWidth()); - pCell->SetPadding(oStyle.m_oPadding); - pCell->SetBorder(oStyle.m_oBorder); + CalculateCellStyles(pCell, sSelectors); while(m_oLightReader.MoveToNextAttribute()) { @@ -2242,8 +2373,11 @@ private: if(m_oLightReader.GetName() == L"th") { CTextSettings oTSR(oTS); + oTSR.sPStyle += L""; oTSR.sRStyle += L""; + wrP(pCell->GetData(), sSelectors, oTS); readStream(pCell->GetData(), sSelectors, oTSR); + CloseP(pCell->GetData(), sSelectors); } // Читаем td. Ячейка таблицы. Выравнивание вправо else if(m_oLightReader.GetName() == L"td") @@ -2291,7 +2425,7 @@ private: { if(m_oLightReader.IsEmptyNode()) return; - + CTable oTable; //Table styles @@ -2327,6 +2461,8 @@ private: oTable.SetAlign(oStyle.m_oDisplay.GetHAlign().ToWString()); //------ + std::vector arCaptions; + int nDeath = m_oLightReader.GetDepth(); while(m_oLightReader.ReadNextSiblingNode(nDeath)) { @@ -2334,35 +2470,79 @@ private: GetSubClass(oXml, sSelectors); // Заголовок таблицы if(sName == L"caption") - { - if (!m_bInP) - { - oXml->WriteString(L""); - for (const NSCSS::CNode& item : sSelectors) - { - if (item.m_wsName == L"a") - oXml->WriteString(L""); - } - m_bInP = true; - m_bWasPStyle = false; - } - // Заголовок таблицы выравнивание посередине - CTextSettings oTSP(oTS); - oTSP.sPStyle += L""; - readStream(oXml, sSelectors, oTSP); - if (m_bInP) - m_bWasPStyle = false; - CloseP(oXml, sSelectors); - } + ParseTableCaption(oTable, sSelectors, oTS, arCaptions); // if(sName == L"thead") // readTr(&oHead, sSelectors, oTS, oTableStyles); - else if(sName == L"tbody") + if(sName == L"tbody") ParseTableRows(oTable, sSelectors, oTS); // else if(sName == L"tfoot") // readTr(&oFoot, sSelectors, oTS, oTableStyles); sSelectors.pop_back(); } + if (!arCaptions.empty() && !oTable.Empty()) + { + std::vector arUnnecessaryCaptions; + + for (TTableCaption* pCaption : arCaptions) + { + if (0 == pCaption->m_unPrevRows || oTable.GetRowCount() == pCaption->m_unPrevRows) + { + arUnnecessaryCaptions.push_back(&pCaption->m_oData); + continue; + } + + if (arUnnecessaryCaptions.empty() && !oTable.HaveCaption()) + { + oTable.SetCaption(pCaption->m_oData); + continue; + } + + CTableRow* pRow = oTable[pCaption->m_unPrevRows - 1]; + + if (NULL == pRow) + continue; + + CTableCell *pCell = new CTableCell; + + if (NULL == pCell) + continue; + + pCell->GetData()->SetText(pCaption->m_oData.GetData()); + pRow->AddCell(pCell); + } + + if (!arUnnecessaryCaptions.empty()) + { + oTable.SetCaption(*arUnnecessaryCaptions.back()); + arUnnecessaryCaptions.pop_back(); + } + + if (!oTable.Empty()) + { + CTableRow* pRow = oTable[0]; + if (NULL != pRow) + { + CTableCell *pCell = (*pRow)[0]; + if (NULL != pCell) + { + NSStringUtils::CStringBuilder oData; + + for (NSStringUtils::CStringBuilder* pData : arUnnecessaryCaptions) + oData += pData->GetData(); + + arCaptions.clear(); + + oData += pCell->GetData()->GetData(); + pCell->GetData()->SetText(oData.GetData()); + } + } + } + } + + for (TTableCaption* pCaption : arCaptions) + delete pCaption; + oTable.ApplyRowspan(); oTable.Shorten(); oTable.CompleteTable(); @@ -2958,12 +3138,12 @@ private: NSCSS::CCompiledStyle oStyle = m_oStylesCalculator.GetCompiledStyle(sSelectors); NSCSS::CCompiledStyle::StyleEquation(oStyle, oStyleSetting); - + std::wstring sPStyle = GetStyle(oStyle, true); - if (sPStyle.empty()) + if (sPStyle.empty() && oTS.sPStyle.empty()) return L""; - + m_oXmlStyle.WriteLitePStyle(oStyleSetting); std::wstring sPSettings = m_oXmlStyle.GetStyle(); m_oXmlStyle.Clear(); @@ -2987,11 +3167,17 @@ private: } } - oXml->WriteString(L"WriteString(sPStyle); - oXml->WriteString(L"\"/>"); + oXml->WriteNodeBegin(L"w:pPr"); + + if (!sPStyle.empty()) + { + oXml->WriteString(L"WriteString(sPStyle); + oXml->WriteString(L"\"/>"); + } + oXml->WriteString(oTS.sPStyle + L' ' + sPSettings); - oXml->WriteString(L""); + oXml->WriteNodeEnd(L"w:pPr"); m_bWasPStyle = true; return sPStyle; }