From 84b8850a52cfe034957707d631fdac2669c05fdb Mon Sep 17 00:00:00 2001 From: Alexey Date: Thu, 25 Jul 2024 16:12:40 +0300 Subject: [PATCH] Fix bug with spaces --- DesktopEditor/common/StringUTF32.cpp | 11 +- DesktopEditor/common/StringUTF32.h | 3 + DocxRenderer/src/logic/Document.cpp | 7 +- DocxRenderer/src/logic/Page.cpp | 133 ++++++------------ DocxRenderer/src/logic/elements/ContText.cpp | 57 ++++++-- DocxRenderer/src/logic/elements/ContText.h | 3 +- DocxRenderer/src/logic/elements/Paragraph.cpp | 6 +- DocxRenderer/src/logic/elements/TextLine.cpp | 3 +- DocxRenderer/src/resources/VectorGraphics.h | 8 +- 9 files changed, 117 insertions(+), 114 deletions(-) diff --git a/DesktopEditor/common/StringUTF32.cpp b/DesktopEditor/common/StringUTF32.cpp index 3f745a2b6c..6ee795b8d6 100644 --- a/DesktopEditor/common/StringUTF32.cpp +++ b/DesktopEditor/common/StringUTF32.cpp @@ -42,7 +42,7 @@ CStringUTF32::CStringUTF32(const vector &other): m_vec(other) {} CStringUTF32::CStringUTF32(const uint32_t* data, const size_t& len) { - m_vec.reserve(len); + m_vec.reserve(len); for (size_t i = 0; i < len; ++i) this->m_vec.push_back(data[i]); } @@ -152,3 +152,12 @@ CStringUTF32 CStringUTF32::substr(size_t start, size_t count) const result.m_vec.insert(result.m_vec.end(), m_vec.begin() + start, m_vec.begin() + start + count); return result; } + +const uint32_t& CStringUTF32::at(size_t index) const +{ + return this->m_vec.at(index); +} +uint32_t& CStringUTF32::at(size_t index) +{ + return this->m_vec.at(index); +} diff --git a/DesktopEditor/common/StringUTF32.h b/DesktopEditor/common/StringUTF32.h index 2341fa7397..0871ad8d98 100644 --- a/DesktopEditor/common/StringUTF32.h +++ b/DesktopEditor/common/StringUTF32.h @@ -70,6 +70,9 @@ namespace NSStringUtils CStringUTF32 &operator += (const uint32_t& symbol); CStringUTF32 substr(size_t start, size_t count) const; + + const uint32_t& at(size_t index) const; + uint32_t& at(size_t index); }; } diff --git a/DocxRenderer/src/logic/Document.cpp b/DocxRenderer/src/logic/Document.cpp index bcdf9a3c1a..7472ae79fc 100644 --- a/DocxRenderer/src/logic/Document.cpp +++ b/DocxRenderer/src/logic/Document.cpp @@ -628,19 +628,14 @@ namespace NSDocxRenderer HRESULT CDocument::DrawPath(long nType) { std::shared_ptr pInfo = nullptr; - if ((nType > 0xFF) && (c_BrushTypeTexture == m_oBrush.Type)) { - double x = 0; - double y = 0; - double w = 0; - double h = 0; + double x = 0, y = 0, w = 0, h = 0; if (m_oBrush.Image) pInfo = m_oImageManager.WriteImage(m_oBrush.Image, x, y, w, h); else pInfo = m_oImageManager.WriteImage(m_oBrush.TexturePath, x, y, w, h); } - m_oCurrentPage.DrawPath(nType, pInfo); return S_OK; } diff --git a/DocxRenderer/src/logic/Page.cpp b/DocxRenderer/src/logic/Page.cpp index f700c6ee33..ae0a330b4e 100644 --- a/DocxRenderer/src/logic/Page.cpp +++ b/DocxRenderer/src/logic/Page.cpp @@ -73,91 +73,44 @@ namespace NSDocxRenderer // image commands void CPage::WriteImage(const std::shared_ptr pInfo, double& fX, double& fY, double& fWidth, double& fHeight) { - auto pImage = std::make_shared(pInfo, L""); - pImage->m_eType = CShape::eShapeType::stPicture; + auto image = std::make_shared(pInfo, L""); + image->m_eType = CShape::eShapeType::stPicture; - double dRotation = m_pTransform->z_Rotation(); + double rotation = m_pTransform->z_Rotation(); - if (fabs(dRotation) < 5.0) - { - double x1 = fX; - double y1 = fY; - double x2 = fX + fWidth; - double y2 = fY + fHeight; + Point p1(fX, fY); + Point p2(fX + fWidth, fY + fHeight); - m_pTransform->TransformPoint(x1, y1); - m_pTransform->TransformPoint(x2, y2); + m_pTransform->TransformPoint(p1.x, p1.y); + m_pTransform->TransformPoint(p2.x, p2.y); - if (x1 <= x2) - { - pImage->m_dLeft = x1; - pImage->m_dWidth = x2 - x1; - } - else - { - pImage->m_dLeft = x2; - pImage->m_dWidth = x1 - x2; - } + // rotate - calc all 4 points - rotate it back + Point c((p1.x + p2.x) / 2, (p1.y + p2.y) / 2); + Aggplus::CMatrix rotate_matrix; + rotate_matrix.RotateAt(-rotation, c.x, c.y, Aggplus::MatrixOrderAppend); - if (y1 <= y2) - { - pImage->m_dTop = y1; - pImage->m_dHeight = y2 - y1; - } - else - { - pImage->m_dTop = y2; - pImage->m_dHeight = y1 - y2; - } + rotate_matrix.TransformPoint(p1.x, p1.y); + rotate_matrix.TransformPoint(p2.x, p2.y); - pImage->m_dRotate = 0.0; - } - else - { - double x1 = fX; - double y1 = fY; - double x2 = fX + fWidth; - double y2 = fY + fHeight; + Point p3(p1.x, p2.y); + Point p4(p2.x, p1.y); - Aggplus::CMatrix oTemp = *m_pTransform; + image->m_dBaselinePos = std::max({p1.y, p2.y, p3.y, p4.y}); + image->m_dTop = std::min({p1.y, p2.y, p3.y, p4.y}); + image->m_dLeft = std::min({p1.x, p2.x, p3.x, p4.x}); + image->m_dRight = std::max({p1.x, p2.x, p3.x, p4.x}); - double dCx = (x1 + x2) / 2; - double dCy = (y1 + y2) / 2; - m_pTransform->TransformPoint(dCx, dCy); - oTemp.RotateAt(-dRotation, dCx, dCy, Aggplus::MatrixOrderAppend); + image->m_dHeight = image->m_dBaselinePos - image->m_dTop; + image->m_dWidth = image->m_dRight - image->m_dLeft; + image->m_dRotate = rotation; - oTemp.TransformPoint(x1, y1); - oTemp.TransformPoint(x2, y2); +// rotate_matrix.RotateAt(rotation, c.x, c.y, Aggplus::MatrixOrderAppend); +// rotate_matrix.TransformPoint(p1.x, p1.y); +// rotate_matrix.TransformPoint(p2.x, p2.y); +// rotate_matrix.TransformPoint(p3.x, p3.y); +// rotate_matrix.TransformPoint(p4.x, p4.y); - if (x1 <= x2) - { - pImage->m_dLeft = x1; - pImage->m_dWidth = x2 - x1; - } - else - { - pImage->m_dLeft = x2; - pImage->m_dWidth = x1 - x2; - } - - if (y1 <= y2) - { - pImage->m_dTop = y1; - pImage->m_dHeight = y2 - y1; - } - else - { - pImage->m_dTop = y2; - pImage->m_dHeight = y1 - y2; - } - - pImage->m_dRotate = dRotation; - } - - pImage->m_dBaselinePos = pImage->m_dTop + pImage->m_dHeight; - pImage->m_dRight = pImage->m_dLeft + pImage->m_dWidth; - - m_arImages.push_back(pImage); + m_arImages.push_back(image); } // path commands @@ -265,6 +218,14 @@ namespace NSDocxRenderer pShape->m_oPen.Size *= dDeterminant; pShape->SetVector(std::move(m_oVector)); + + // big white shape with page width & height skip + if (fabs(pShape->m_dHeight - m_dHeight) <= c_dSHAPE_X_OFFSET * 2 && + fabs(pShape->m_dWidth - m_dWidth) <= c_dSHAPE_X_OFFSET * 2 && + pShape->m_oBrush.Color1 == c_iWhiteColor && + m_nShapeOrder == 0) + return; + pShape->m_nOrder = ++m_nShapeOrder; m_arShapes.push_back(pShape); } @@ -337,13 +298,12 @@ namespace NSDocxRenderer double width = _w; double right = left + _w; - // if new text is close to current cont if (m_pCurrCont != nullptr && fabs(m_pCurrCont->m_dBaselinePos - baseline) < c_dTHE_SAME_STRING_Y_PRECISION_MM && m_oPrevFont.IsEqual2(m_pFont) && m_oPrevBrush.IsEqual(m_pBrush) && - (fabs(m_pCurrCont->m_dRight - left) < m_pCurrCont->CalculateSpace() * 0.4)) + (fabs(m_pCurrCont->m_dRight - left) < m_pCurrCont->CalculateSpace() * 0.5)) { // just in case if oText contains more than 1 symbol std::vector ar_widths; @@ -466,8 +426,8 @@ namespace NSDocxRenderer { if (m_arConts[i] && m_arConts[i]->GetText().length() == 1) { - auto text = m_arConts[i]->GetText(); - if (IsDiacriticalMark(text[0])) + const auto& text = m_arConts[i]->GetText(); + if (IsDiacriticalMark(text.at(0))) m_arDiacriticalSymbols.push_back(std::move(m_arConts[i])); } } @@ -511,12 +471,13 @@ namespace NSDocxRenderer { bool only_spaces = true; for (auto& cont : m_arTextLines[i]->m_arConts) + { if (!cont->IsOnlySpaces()) { only_spaces = false; break; } - + } if (only_spaces) m_arTextLines.erase(m_arTextLines.begin() + i, m_arTextLines.begin() + i + 1); } @@ -1066,13 +1027,11 @@ namespace NSDocxRenderer if ((bIf1 && bIf6) || (bIf2 && bIf7) || (bIf4 && bIf8) || (bIf5 && bIf7)) { - auto text = d_sym->GetText(); - cont->AddSymBack(text[0], 0); + cont->AddSymBack(d_sym->GetText().at(0), 0); } else if (bIf3 && bIf7) { - auto text = d_sym->GetText(); - cont->AddSymFront(text[0], 0); + cont->AddSymFront(d_sym->GetText().at(0), 0); } d_sym = nullptr; isBreak = true; @@ -1185,11 +1144,11 @@ namespace NSDocxRenderer if (!cont) continue; - auto text = cont->GetText().ToStdWString(); + const auto& text = cont->GetText(); auto ar_widths = cont->GetSymWidths(); - for (size_t i = 0; i < text.size(); ++i) + for (size_t i = 0; i < text.length(); ++i) { - if (text[i] == L' ') + if (text.at(i) == c_SPACE_SYM) { line->m_dFirstWordWidth = width; next_line = true; diff --git a/DocxRenderer/src/logic/elements/ContText.cpp b/DocxRenderer/src/logic/elements/ContText.cpp index e975d1dace..8963a8e8f8 100644 --- a/DocxRenderer/src/logic/elements/ContText.cpp +++ b/DocxRenderer/src/logic/elements/ContText.cpp @@ -5,6 +5,18 @@ namespace NSDocxRenderer { + bool IsTextOnlySpaces(const NSStringUtils::CStringUTF32& oText) + { + bool only_spaces = true; + for (size_t j = 0; j < oText.length(); ++j) + if (!IsSpaceUtf32(oText.at(j))) + { + only_spaces = false; + break; + } + return only_spaces; + } + CSelectedSizes::CSelectedSizes(const CSelectedSizes& oSelectedSizes) { *this = oSelectedSizes; @@ -502,27 +514,28 @@ namespace NSDocxRenderer return false; } - bool CContText::IsOnlySpaces() + bool CContText::IsOnlySpaces() const { - bool only_spaces = true; - for (size_t j = 0; j < m_oText.length(); ++j) - { - if (!IsSpaceUtf32(m_oText[j])) - { - only_spaces = false; - break; - } - } - return only_spaces; + return IsTextOnlySpaces(m_oText); } void CContText::AddTextBack(const NSStringUtils::CStringUTF32& oText, const std::vector& arSymWidths) { - m_oText += oText; - for (auto& w : arSymWidths) + bool is_space_twice = m_oText.at(m_oText.length() - 1) == c_SPACE_SYM && + oText.at(0) == c_SPACE_SYM; + + for (size_t i = 0; i < arSymWidths.size(); ++i) { + auto& w = arSymWidths[i]; + if (i == 0 && is_space_twice) + { + m_arSymWidths.back() = m_arSymWidths.back() + arSymWidths[i]; + m_dWidth += arSymWidths[i]; + continue; + } m_arSymWidths.push_back(w); m_dWidth += w; + m_oText += oText.at(i); } m_dRight = m_dLeft + m_dWidth; } @@ -551,8 +564,15 @@ namespace NSDocxRenderer void CContText::AddSymBack(uint32_t cSym, double nWidth) { - m_oText += cSym; - m_arSymWidths.push_back(nWidth); + bool is_space_twice = m_oText.at(m_oText.length() - 1) == c_SPACE_SYM && cSym == c_SPACE_SYM; + + if (is_space_twice) + m_arSymWidths.back() += nWidth; + else + { + m_arSymWidths.push_back(nWidth); + m_oText += cSym; + } m_dWidth += nWidth; m_dRight = m_dLeft + m_dWidth; @@ -574,6 +594,13 @@ namespace NSDocxRenderer m_dWidth = nWidth; m_dRight = m_dLeft + m_dWidth; } + void CContText::RemoveLastSym() + { + m_oText = m_oText.substr(0, m_oText.length() - 1); + m_dWidth -= m_arSymWidths[m_arSymWidths.size() - 1]; + m_dRight = m_dLeft + m_dWidth; + m_arSymWidths.resize(m_arSymWidths.size() - 1); + } const NSStringUtils::CStringUTF32& CContText::GetText() const noexcept { diff --git a/DocxRenderer/src/logic/elements/ContText.h b/DocxRenderer/src/logic/elements/ContText.h index a5b513a2e5..281932b495 100644 --- a/DocxRenderer/src/logic/elements/ContText.h +++ b/DocxRenderer/src/logic/elements/ContText.h @@ -93,6 +93,7 @@ namespace NSDocxRenderer void AddSymBack(uint32_t cSym, double nWidth); void AddSymFront(uint32_t cSym, double nWidth); void SetSym(uint32_t cSym, double nWidth); + void RemoveLastSym(); const NSStringUtils::CStringUTF32& GetText() const noexcept; const std::vector& GetSymWidths() const noexcept; @@ -107,7 +108,7 @@ namespace NSDocxRenderer UINT GetNumberOfFeatures() const noexcept; bool IsDuplicate(CContText *pCont, eVerticalCrossingType eVType) const noexcept; - bool IsOnlySpaces(); + bool IsOnlySpaces() const; // check font effect and delete not needed cont // return true if was deleted diff --git a/DocxRenderer/src/logic/elements/Paragraph.cpp b/DocxRenderer/src/logic/elements/Paragraph.cpp index 6f2f7693ed..3ec85fd2be 100644 --- a/DocxRenderer/src/logic/elements/Paragraph.cpp +++ b/DocxRenderer/src/logic/elements/Paragraph.cpp @@ -194,7 +194,11 @@ namespace NSDocxRenderer while(!pLastCont) pLastCont = pLine->m_arConts[--iNumConts]; - pLastCont->AddSymBack(c_SPACE_SYM, 0); + auto text = pLastCont->GetText(); + auto last_sym = text[text.length() - 1]; + + if (last_sym != c_SPACE_SYM) + pLastCont->AddSymBack(c_SPACE_SYM, 0); } } } diff --git a/DocxRenderer/src/logic/elements/TextLine.cpp b/DocxRenderer/src/logic/elements/TextLine.cpp index 11fa724fdf..ae512f975c 100644 --- a/DocxRenderer/src/logic/elements/TextLine.cpp +++ b/DocxRenderer/src/logic/elements/TextLine.cpp @@ -64,7 +64,7 @@ namespace NSDocxRenderer double dDifference = fabs(pCurrent->m_dLeft - pFirst->m_dRight); bool bIsEqual = pFirst->IsEqual(pCurrent.get()); - bool bIsSpaceDelta = dDifference > dSpaceDefaultSize * 0.4; + bool bIsSpaceDelta = dDifference > dSpaceDefaultSize * 0.5; bool bIsWideSpaceDelta = dDifference > dSpaceDefaultSize * 3; if (bIsWideSpaceDelta || (pCurrent->m_bPossibleSplit && bIsSpaceDelta)) @@ -123,6 +123,7 @@ namespace NSDocxRenderer pFirst->AddSymBack(c_SPACE_SYM, pCurrent->m_dLeft - pFirst->m_dRight); pFirst->AddTextBack(pCurrent->GetText(), pCurrent->GetSymWidths()); } + if (pFirst->m_pCont.expired()) { pFirst->m_pCont = pCurrent->m_pCont; diff --git a/DocxRenderer/src/resources/VectorGraphics.h b/DocxRenderer/src/resources/VectorGraphics.h index dbd0e4d4cb..ad35a11b69 100644 --- a/DocxRenderer/src/resources/VectorGraphics.h +++ b/DocxRenderer/src/resources/VectorGraphics.h @@ -5,8 +5,12 @@ namespace NSDocxRenderer { struct Point { - double x; - double y; + double x = 0; + double y = 0; + + Point() {} + Point(double x, double y) : x(x), y(y) {} + Point(const Point& point) : x(point.x), y(point.y) {} }; class CVectorGraphics