diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2023-12-15 08:42:02 +0300 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2023-12-21 12:03:32 +0100 |
commit | 2f9ecce61b0c806a33a9f641e43f4a71ed699fee (patch) | |
tree | ea41fa50bda1265ae0a558a8fdac8c72d794f69b | |
parent | 57d32cde67239f6723dfb09d8809c989f4c3bf78 (diff) |
tdf#158556: provide objects anchored to node as a hidden property
This introduces a hidden property of SwXParagraph, named
OOXMLImport_AnchoredShapes.
Testing on my system, starting the main process first, then launching
another one like
time soffice path/to/bugdoc.docx
... so that it only measures time spent in import, gave the following
figures:
LibreOffice 7.5.0.3 (TDF build):
real 1m49.016s
user 0m0.000s
sys 0m0.000s
LibreOffice 7.6.0.3 (TDF build):
real 8m37.386s
user 0m0.000s
sys 0m0.000s
Current master (my no-debug build):
real 10m6.776s
user 0m0.000s
sys 0m0.000s
Current master with this patch (my no-debug build):
real 5m41.524s
user 0m0.000s
sys 0m0.015s
Indeed, it is not as fast as it used to be; and the fix doesn't really
remove the quadratic complexity, just uses faster iteration. If there
is a way to directly list objects anchored to a given paragraph, rather
than iterating over all objects checking their anchors, that would get
much faster, but that would be a rather large change.
Change-Id: Ie50515815e85fdce498d065185199c9b31d95794
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160813
Tested-by: Mike Kaganski <mike.kaganski@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit dcae6615ed254cf7884fa6415f64561f85b93588)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160807
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
-rw-r--r-- | sw/source/core/inc/unoparaframeenum.hxx | 4 | ||||
-rw-r--r-- | sw/source/core/unocore/unoobj2.cxx | 25 | ||||
-rw-r--r-- | sw/source/core/unocore/unoparagraph.cxx | 18 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 79 |
4 files changed, 92 insertions, 34 deletions
diff --git a/sw/source/core/inc/unoparaframeenum.hxx b/sw/source/core/inc/unoparaframeenum.hxx index 81a653aac57f..c44e0f660c6d 100644 --- a/sw/source/core/inc/unoparaframeenum.hxx +++ b/sw/source/core/inc/unoparaframeenum.hxx @@ -31,6 +31,8 @@ class SwNodeIndex; class SwPaM; class SwFrameFormat; +namespace com { namespace sun { namespace star { namespace text { class XTextContent; } } } } + namespace sw { struct FrameClient final : public SwClient @@ -70,6 +72,8 @@ struct SwXParaFrameEnumeration static rtl::Reference<SwXParaFrameEnumeration> Create(const SwPaM& rPaM, const enum ParaFrameMode eParaFrameMode, SwFrameFormat* const pFormat = nullptr); }; +css::uno::Reference<css::text::XTextContent> FrameClientToXTextContent(sw::FrameClient* pClient); + #endif // INCLUDED_SW_SOURCE_CORE_INC_UNOPARAFRAMEENUM_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/unocore/unoobj2.cxx b/sw/source/core/unocore/unoobj2.cxx index e4f5ccdf22d9..7614f0a31485 100644 --- a/sw/source/core/unocore/unoobj2.cxx +++ b/sw/source/core/unocore/unoobj2.cxx @@ -1788,9 +1788,17 @@ bool SwXParaFrameEnumerationImpl::CreateNextObject() if (m_vFrames.empty()) return false; - SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>( - m_vFrames.front()->GetRegisteredIn()); + m_xNextObject.set(FrameClientToXTextContent(m_vFrames.front().get())); m_vFrames.pop_front(); + return m_xNextObject.is(); +} + +uno::Reference<text::XTextContent> FrameClientToXTextContent(sw::FrameClient* pClient) +{ + assert(pClient); + + uno::Reference<text::XTextContent> xRet; + SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>(pClient->GetRegisteredIn()); // the format should be valid here, otherwise the client // would have been removed by PurgeFrameClients // check for a shape first @@ -1799,33 +1807,32 @@ bool SwXParaFrameEnumerationImpl::CreateNextObject() SdrObject* pObject(nullptr); pFormat->CallSwClientNotify(sw::FindSdrObjectHint(pObject)); if(pObject) - m_xNextObject.set(pObject->getUnoShape(), uno::UNO_QUERY); + xRet.set(pObject->getUnoShape(), uno::UNO_QUERY); } else { const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx(); OSL_ENSURE(pIdx, "where is the index?"); - SwNode const*const pNd = - m_pUnoCursor->GetDoc().GetNodes()[ pIdx->GetIndex() + 1 ]; + SwNode const* const pNd = pIdx->GetNodes()[pIdx->GetIndex() + 1]; if (!pNd->IsNoTextNode()) { - m_xNextObject = static_cast<SwXFrame*>(SwXTextFrame::CreateXTextFrame( + xRet = static_cast<SwXFrame*>(SwXTextFrame::CreateXTextFrame( *pFormat->GetDoc(), pFormat).get()); } else if (pNd->IsGrfNode()) { - m_xNextObject.set(SwXTextGraphicObject::CreateXTextGraphicObject( + xRet.set(SwXTextGraphicObject::CreateXTextGraphicObject( *pFormat->GetDoc(), pFormat)); } else { assert(pNd->IsOLENode()); - m_xNextObject.set(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( + xRet.set(SwXTextEmbeddedObject::CreateXTextEmbeddedObject( *pFormat->GetDoc(), pFormat)); } } - return m_xNextObject.is(); + return xRet; } sal_Bool SAL_CALL diff --git a/sw/source/core/unocore/unoparagraph.cxx b/sw/source/core/unocore/unoparagraph.cxx index 68dbe34f55d5..dab5270588e3 100644 --- a/sw/source/core/unocore/unoparagraph.cxx +++ b/sw/source/core/unocore/unoparagraph.cxx @@ -54,6 +54,7 @@ #include <com/sun/star/drawing/BitmapMode.hpp> #include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> #include <comphelper/servicehelper.hxx> #include <editeng/unoipset.hxx> #include <svl/listener.hxx> @@ -550,6 +551,23 @@ uno::Sequence< uno::Any > SwXParagraph::Impl::GetPropertyValues_Impl( continue; } + if (pPropertyNames[nProp] == "OOXMLImport_AnchoredShapes") + { + // A hack to provide list of anchored objects fast + // See reanchorObjects in writerfilter/source/dmapper/DomainMapper_Impl.cxx + FrameClientSortList_t aFrames; + CollectFrameAtNode(rTextNode, aFrames, false); // Frames anchored to paragraph + CollectFrameAtNode(rTextNode, aFrames, true); // Frames anchored to character + std::vector<uno::Reference<text::XTextContent>> aRet; + aRet.reserve(aFrames.size()); + for (const auto& rFrame : aFrames) + if (auto xContent = FrameClientToXTextContent(rFrame.pFrameClient.get())) + aRet.push_back(xContent); + + pValues[nProp] <<= comphelper::containerToSequence(aRet); + continue; + } + SfxItemPropertyMapEntry const*const pEntry = rMap.getByName( pPropertyNames[nProp] ); if (!pEntry) diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index 57a9f3bc5223..0ae745eec97a 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -750,6 +750,59 @@ void DomainMapper_Impl::AddDummyParaForTableInSection() return sName; } +static void reanchorObjects(const uno::Reference<uno::XInterface>& xFrom, + const uno::Reference<text::XTextRange>& xTo, + const uno::Reference<drawing::XDrawPage>& xDrawPage) +{ + std::vector<uno::Reference<text::XTextContent>> aShapes; + bool bFastPathDone = false; + if (uno::Reference<beans::XPropertySet> xProps{ xFrom, uno::UNO_QUERY }) + { + try + { + // See SwXParagraph::Impl::GetPropertyValues_Impl + uno::Sequence<uno::Reference<text::XTextContent>> aSeq; + xProps->getPropertyValue(u"OOXMLImport_AnchoredShapes"_ustr) >>= aSeq; + aShapes.insert(aShapes.end(), aSeq.begin(), aSeq.end()); + bFastPathDone = true; + } + catch (const uno::Exception&) + { + } + } + + if (!bFastPathDone) + { + // Can this happen? Fallback to slow DrawPage iteration and range comparison + uno::Reference<text::XTextRange> xRange(xFrom, uno::UNO_QUERY_THROW); + uno::Reference<text::XTextRangeCompare> xCompare(xRange->getText(), uno::UNO_QUERY_THROW); + + const sal_Int32 count = xDrawPage->getCount(); + for (sal_Int32 i = 0; i < count; ++i) + { + try + { + uno::Reference<text::XTextContent> xShape(xDrawPage->getByIndex(i), + uno::UNO_QUERY_THROW); + uno::Reference<text::XTextRange> xAnchor(xShape->getAnchor(), uno::UNO_SET_THROW); + if (xCompare->compareRegionStarts(xAnchor, xRange) <= 0 + && xCompare->compareRegionEnds(xAnchor, xRange) >= 0) + { + aShapes.push_back(xShape); + } + } + catch (const uno::Exception&) + { + // Can happen e.g. in compareRegion*, when the shape is in a header, + // and paragraph in body + } + } + } + + for (const auto& xShape : aShapes) + xShape->attach(xTo); +} + void DomainMapper_Impl::RemoveLastParagraph( ) { if (m_bDiscardHeaderFooter) @@ -828,31 +881,7 @@ void DomainMapper_Impl::RemoveLastParagraph( ) auto xEnumeration = xEA->createEnumeration(); uno::Reference<text::XTextRange> xPrevParagraph(xEnumeration->nextElement(), uno::UNO_QUERY_THROW); - - uno::Reference<text::XTextRange> xParaRange(xParagraph, uno::UNO_QUERY_THROW); - uno::Reference<text::XTextRangeCompare> xRegionCompare(xParaRange->getText(), - uno::UNO_QUERY_THROW); - const sal_Int32 count = xDrawPage->getCount(); - for (sal_Int32 i = 0; i < count; ++i) - { - try - { - uno::Reference<text::XTextContent> xShape(xDrawPage->getByIndex(i), - uno::UNO_QUERY_THROW); - uno::Reference<text::XTextRange> xAnchor(xShape->getAnchor(), - uno::UNO_SET_THROW); - if (xRegionCompare->compareRegionStarts(xAnchor, xParaRange) <= 0 - && xRegionCompare->compareRegionEnds(xAnchor, xParaRange) >= 0) - { - xShape->attach(xPrevParagraph); - } - } - catch (const uno::Exception&) - { - // Can happen e.g. in compareRegion*, when the shape is in a header, - // and paragraph in body - } - } + reanchorObjects(xParagraph, xPrevParagraph, xDrawPage); } xParagraph->dispose(); |