summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-11-22 08:40:47 +0100
committerMiklos Vajna <vmiklos@collabora.com>2022-11-22 12:18:33 +0100
commit44c23800e3e94143f3737d32232e15169a092eac (patch)
treed4e0ca1a4f5cdc5421e0fe658dd1fab97cef3ef8
parent54b4a1adcf01ac83794ac3fd4f877570218fa1fa (diff)
sw, createTextRangeByPixelPosition(): fix crash when the position is an imagedistro/vector/vector-7.0
Using createTextRangeByPixelPosition() with a pixel position that leads to a graphic node resulted in a crash. The direct reason for this is that the makeMark() call in SwXTextRange::SetPositions() returns nullptr in case rPaM points to a graphic node, but later we dereference that result unconditionally. This also uncovers that the XTextRange returned by createTextRangeByPixelPosition() is meant to point to a text node, but a pixel position may be closest to a graphic node. Fix the problem by explicitly checking for graphic nodes; and try to look up the anchor position of such graphics, which will be definitely a text node. In practice this will mean that in case the image's anchor type is as-char, then we'll return a cursor position which will be on the left hand side of the image. (cherry picked from commit 2302ebefb2e25878e8fe1e64d208f265f87d5b9b) Conflicts: sw/qa/uibase/uno/uno.cxx sw/source/uibase/uno/unotxvw.cxx Change-Id: Ief58148247fe3cd4371ed245b4eff5b45ca2aa15
-rw-r--r--offapi/com/sun/star/text/XTextViewTextRangeSupplier.idl7
-rw-r--r--sw/qa/uibase/uno/uno.cxx64
-rw-r--r--sw/source/uibase/uno/unotxvw.cxx18
3 files changed, 88 insertions, 1 deletions
diff --git a/offapi/com/sun/star/text/XTextViewTextRangeSupplier.idl b/offapi/com/sun/star/text/XTextViewTextRangeSupplier.idl
index 57adf359f756..e5a8b6913eab 100644
--- a/offapi/com/sun/star/text/XTextViewTextRangeSupplier.idl
+++ b/offapi/com/sun/star/text/XTextViewTextRangeSupplier.idl
@@ -32,7 +32,12 @@ module com { module sun { module star { module text {
*/
interface XTextViewTextRangeSupplier: com::sun::star::uno::XInterface
{
- /** @returns
+ /** creates the text range of the document model position at a view-dependent pixel position.
+
+ Note that in case the model position is a graphic, then the model position of its anchor is
+ returned.
+
+ @returns
the text range of the document position.
*/
com::sun::star::text::XTextRange createTextRangeByPixelPosition([in] com::sun::star::awt::Point PixelPosition);
diff --git a/sw/qa/uibase/uno/uno.cxx b/sw/qa/uibase/uno/uno.cxx
index 23c1829ab7de..8085798d8f4d 100644
--- a/sw/qa/uibase/uno/uno.cxx
+++ b/sw/qa/uibase/uno/uno.cxx
@@ -10,6 +10,18 @@
#include <swmodeltestbase.hxx>
#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextViewTextRangeSupplier.hpp>
+
+#include <rootfrm.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <frameformats.hxx>
+#include <fmtanchr.hxx>
+#include <wrtsh.hxx>
+#include <edtwin.hxx>
+#include <view.hxx>
+#include <unotextrange.hxx>
/// Covers sw/source/uibase/uno/ fixes.
class SwUibaseUnoTest : public SwModelTestBase
@@ -31,6 +43,58 @@ CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testLockControllers)
mxComponent.clear();
}
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testCreateTextRangeByPixelPositionGraphic)
+{
+ // Given a document with an as-char image and the center of that image in pixels:
+ mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument");
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xTextGraphic(
+ xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
+ xTextGraphic->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AS_CHARACTER));
+ xTextGraphic->setPropertyValue("Width", uno::Any(static_cast<sal_Int32>(10000)));
+ xTextGraphic->setPropertyValue("Height", uno::Any(static_cast<sal_Int32>(10000)));
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xBodyText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor(xBodyText->createTextCursor());
+ uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY);
+ xBodyText->insertTextContent(xCursor, xTextContent, false);
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
+ SwDocShell* pDocShell = pDoc->GetDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwRootFrame* pLayout = pWrtShell->GetLayout();
+ SwFrame* pPage = pLayout->GetLower();
+ SwFrame* pBody = pPage->GetLower();
+ SwFrame* pText = pBody->GetLower();
+ SwSortedObjs& rDrawObjs = *pText->GetDrawObjs();
+ SwAnchoredObject* pAnchored = rDrawObjs[0];
+ Point aLogic = pAnchored->GetObjRect().Center();
+ SwView* pView = pDocShell->GetView();
+ SwEditWin& rEditWin = pView->GetEditWin();
+ Point aPixel = rEditWin.LogicToPixel(aLogic);
+
+ // When converting that pixel position to a document model position (text range):
+ uno::Reference<frame::XModel2> xModel(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xControllers = xModel->getControllers();
+ uno::Reference<text::XTextViewTextRangeSupplier> xController(xControllers->nextElement(),
+ uno::UNO_QUERY);
+ awt::Point aPoint(aPixel.getX(), aPixel.getY());
+ // Without the accompanying fix in place, this test would have crashed, because an XTextRange
+ // can't point to a graphic node.
+ uno::Reference<text::XTextRange> xTextRange
+ = xController->createTextRangeByPixelPosition(aPoint);
+
+ // Then make sure that the anchor of the image is returned:
+ const SwFrameFormats& rFormats = *pDoc->GetSpzFrameFormats();
+ const SwFrameFormat* pFormat = rFormats[0];
+ SwPosition aAnchorPos(*pFormat->GetAnchor().GetContentAnchor());
+ auto pTextRange = dynamic_cast<SwXTextRange*>(xTextRange.get());
+ SwPaM aPaM(pDoc->GetNodes());
+ pTextRange->GetPositions(aPaM);
+ CPPUNIT_ASSERT_EQUAL(aAnchorPos, *aPaM.GetPoint());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/uno/unotxvw.cxx b/sw/source/uibase/uno/unotxvw.cxx
index 438e648f480c..821ec11fe934 100644
--- a/sw/source/uibase/uno/unotxvw.cxx
+++ b/sw/source/uibase/uno/unotxvw.cxx
@@ -72,6 +72,7 @@
#include <comphelper/servicehelper.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <cppuhelper/typeprovider.hxx>
+#include <fmtanchr.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
@@ -528,6 +529,23 @@ SwXTextView::createTextRangeByPixelPosition(const awt::Point& rPixelPosition)
SwWrtShell& rSh = m_pView->GetWrtShell();
SwPosition aPosition(*rSh.GetCurrentShellCursor().GetPoint());
rSh.GetLayout()->GetModelPositionForViewPoint(&aPosition, aLogicPoint);
+
+ if (aPosition.nNode.GetNode().IsGrfNode())
+ {
+ // The point is closest to a graphic node, look up its format.
+ const SwFrameFormat* pGraphicFormat = aPosition.nNode.GetNode().GetFlyFormat();
+ if (pGraphicFormat)
+ {
+ // Get the anchor of this format.
+ const SwFormatAnchor& rAnchor = pGraphicFormat->GetAnchor();
+ const SwPosition* pAnchor = rAnchor.GetContentAnchor();
+ if (pAnchor)
+ {
+ aPosition = *pAnchor;
+ }
+ }
+ }
+
uno::Reference<text::XTextRange> xRet
= SwXTextRange::CreateXTextRange(*rSh.GetDoc(), aPosition, /*pMark=*/nullptr);