summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2023-12-15 08:42:02 +0300
committerXisco Fauli <xiscofauli@libreoffice.org>2023-12-21 12:03:32 +0100
commit2f9ecce61b0c806a33a9f641e43f4a71ed699fee (patch)
treeea41fa50bda1265ae0a558a8fdac8c72d794f69b
parent57d32cde67239f6723dfb09d8809c989f4c3bf78 (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.hxx4
-rw-r--r--sw/source/core/unocore/unoobj2.cxx25
-rw-r--r--sw/source/core/unocore/unoparagraph.cxx18
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx79
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();