sw/inc/textboxhelper.hxx                     |   39 ++
 sw/qa/extras/ooxmlexport/data/tdf141550.docx |binary
 sw/qa/extras/ooxmlexport/ooxmlexport16.cxx   |   17 +
 sw/qa/extras/uiwriter/data/tdf140975.docx    |binary
 sw/qa/extras/uiwriter/uiwriter3.cxx          |   30 ++
 sw/qa/uitest/data/tdf141557.docx             |binary
 sw/qa/uitest/writer_tests7/tdf141557.py      |   40 ++
 sw/source/core/doc/textboxhelper.cxx         |  362 +++++++++++++++++++--------
 sw/source/core/text/porfly.cxx               |    1 
 9 files changed, 384 insertions(+), 105 deletions(-)

New commits:
commit cb965f2cf6d68c284ccbd8a9635abfdfcc0538ca
Author:     Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu>
AuthorDate: Thu Apr 1 17:08:58 2021 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Mon Apr 19 10:44:28 2021 +0200

    tdf#141550 tdf#141557 tdf#140975 sw: fix textbox crash
    
    and regressions by refactoring SwTextBoxHelper.
    
    tdf#141550 was a DOCX import regression from
    commit ff321dd36554d25f0817903becf4598065e0a194
    (tdf#140828 sw textbox: fix AS_CHAR regression),
    resulting bad horizontal position of the frame of
    the textbox.
    
    tdf#141557 was a regression resulting crash
    by changing text box anchoring "To Paragraph".
    
    tdf#140975 was an implementation error, resulting
    broken textbox by changing box anchoring to
    "As Character".
    
    In the SwTextBoxHelper class there were many
    repeating code parts for textbox positioning.
    Now these parts have been replaced with
    the calls of several new functions:
    
    1) getShapeFormat() returns with the SwFrameFormat
       of the UNO XShape;
    
    2) setWrapThrough() only sets the surround
       of the textframe (used in the code frequently);
    
    3) changeAnchor() sets the anchor of the textframe
       according to the anchor of the shape;
    
    4) doTextFramePositioning() sets the position of the
       textbox according to the shape (used in the code
       frequently);
    
    5) isAnchorTypeDifferent() shows difference of the
       anchor types of the shape and the textframe. Also it
       handles the situation of anchoring "As Character";
    
    6) isTextBoxHasValidTextFrame() checks if the shape
       is a part of a textbox or not.
    
    Every function returns with true on success, otherwise
    gives information to the log. All of them can be called
    with ShapeFormat or UNO XShape.
    
    The goal of this to make the possibility to advance this
    class for further functions – rotation, grouped
    textboxes etc. – without code copying.
    
    Change-Id: I4441cab87931f161d0ace4983646d6d2a68a7321
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113463
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 51261a8f77a3..21a1c5a97d83 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -81,9 +81,48 @@ public:
     /// Similar to syncProperty(), but used by the internal API (e.g. for UI 
purposes).
     static void syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& 
rSet);
 
+    /// Returns the SwFrameFormat* of the given UNO-XShape if exists otherwise 
nullptr.
+    static SwFrameFormat* 
getShapeFormat(css::uno::Reference<css::drawing::XShape> xShape);
+
     /// Copy shape attributes to the text frame
     static void updateTextBoxMargin(SdrObject* pObj);
 
+    /// Sets the surround to through for the textframe of the given shape,
+    /// not to interfere with the layout. Returns true on success.
+    static bool setWrapThrough(SwFrameFormat* pShape);
+
+    /// Sets the surround to through for the textframe of the given shape,
+    /// not to interfere with the layout. Returns true on success.
+    static bool setWrapThrough(css::uno::Reference<css::drawing::XShape> 
xShape);
+
+    /// Sets the anchor of the associated textframe of the given shape, and
+    /// returns true on success.
+    static bool changeAnchor(SwFrameFormat* pShape);
+
+    /// Sets the anchor of the associated textframe of the given shape, and
+    /// returns true on success.
+    static bool changeAnchor(css::uno::Reference<css::drawing::XShape> xShape);
+
+    /// Does the positioning for the associated textframe of the shape, and
+    /// returns true on success.
+    static bool doTextBoxPositioning(SwFrameFormat* pShape);
+
+    /// Does the positioning for the associated textframe of the shape, and
+    /// returns true on success.
+    static bool doTextBoxPositioning(css::uno::Reference<css::drawing::XShape> 
xShape);
+
+    /// Returns true if the anchor different for the  given shape, and the
+    /// associated textframe of the given shape.
+    /// Note: In case of AS_CHAR anchor the anchor type must be different,
+    /// because if not, layout breaks, but this situation also handled by
+    /// this function, and returns true in that case too.
+    static std::optional<bool> isAnchorTypeDifferent(SwFrameFormat* pShape);
+
+    /// Returns true if the given shape has a valid textframe.
+    static bool isTextBoxShapeHasValidTextFrame(SwFrameFormat* pShape);
+    /// Returns true if the given shape has a valid textframe.
+    static bool 
isTextBoxShapeHasValidTextFrame(css::uno::Reference<css::drawing::XShape> 
xShape);
+
     /**
      * If we have an associated TextFrame, then return that.
      *
diff --git a/sw/qa/extras/ooxmlexport/data/tdf141550.docx 
b/sw/qa/extras/ooxmlexport/data/tdf141550.docx
new file mode 100644
index 000000000000..170ebebba689
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf141550.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index 722eb4f96606..0c50f3198dcb 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -27,6 +27,8 @@
 #include <comphelper/propertysequence.hxx>
 #include <editeng/escapementitem.hxx>
 #include <unotools/fltrcfg.hxx>
+#include <textboxhelper.hxx>
+#include <unoprnms.hxx>
 
 constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/ooxmlexport/data/";
 
@@ -308,6 +310,21 @@ DECLARE_OOXMLEXPORT_TEST(testTdf133473_shadowSize, 
"tdf133473.docx")
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(200000), nSize1);
 }
 
+DECLARE_OOXMLEXPORT_TEST(testTdf141550, "tdf141550.docx")
+{
+    uno::Reference<drawing::XShape> xShape(getShape(1));
+    uno::Reference<text::XTextFrame> xFrame = 
SwTextBoxHelper::getUnoTextFrame(xShape);
+
+    CPPUNIT_ASSERT(xShape);
+    CPPUNIT_ASSERT(xFrame);
+
+    const sal_uInt16 nShapeRelOri = getProperty<sal_uInt16>(xShape, 
UNO_NAME_HORI_ORIENT_RELATION);
+    const sal_uInt16 nFrameRelOri = getProperty<sal_uInt16>(xFrame, 
UNO_NAME_HORI_ORIENT_RELATION);
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Textbox fallen apart!", nShapeRelOri, 
nFrameRelOri);
+    // Without the fix in place it fails with difference.
+}
+
 DECLARE_OOXMLEXPORT_TEST(testTdf140137, "tdf140137.docx")
 {
     // Don't throw exception during load
diff --git a/sw/qa/extras/uiwriter/data/tdf140975.docx 
b/sw/qa/extras/uiwriter/data/tdf140975.docx
new file mode 100644
index 000000000000..d11a912d34a6
Binary files /dev/null and b/sw/qa/extras/uiwriter/data/tdf140975.docx differ
diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx 
b/sw/qa/extras/uiwriter/uiwriter3.cxx
index 8454b3ed92e4..b2ece7527de4 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -1039,6 +1039,36 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, TestAsCharTextBox)
     // Without the fix in place the two texboxes has been fallen apart, and  
asserts will broken.
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf140975)
+{
+    // Load the bugdoc
+    load(DATA_DIRECTORY, "tdf140975.docx");
+    SwXTextDocument* pTextDoc = 
dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    CPPUNIT_ASSERT(pTextDoc);
+
+    // Set the Anchor of the shape to As_Char
+    dispatchCommand(mxComponent, ".uno:JumpToNextFrame", {});
+    Scheduler::ProcessEventsToIdle();
+    dispatchCommand(mxComponent, ".uno:SetAnchorToChar", {});
+    Scheduler::ProcessEventsToIdle();
+
+    // Get the layout of the textbox
+    auto pExportDump = parseLayoutDump();
+    CPPUNIT_ASSERT(pExportDump);
+
+    const sal_Int32 nShpTop
+        = getXPath(pExportDump, 
"/root/page/body/txt[4]/anchored/SwAnchoredDrawObject/bounds",
+                   "top")
+              .toInt32();
+    const sal_Int32 nFrmTop
+        = getXPath(pExportDump, 
"/root/page/body/txt[4]/anchored/fly/infos/bounds", "top")
+              .toInt32();
+
+    // Without the fix in place, the frame has less value for Top than
+    // the shape. This means the frame is outside from the shape.
+    CPPUNIT_ASSERT_GREATER(nShpTop, nFrmTop);
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf76636)
 {
     load(DATA_DIRECTORY, "tdf76636.doc");
diff --git a/sw/qa/uitest/data/tdf141557.docx b/sw/qa/uitest/data/tdf141557.docx
new file mode 100644
index 000000000000..9b0c6849bd44
Binary files /dev/null and b/sw/qa/uitest/data/tdf141557.docx differ
diff --git a/sw/qa/uitest/writer_tests7/tdf141557.py 
b/sw/qa/uitest/writer_tests7/tdf141557.py
new file mode 100644
index 000000000000..c641cd3e23f3
--- /dev/null
+++ b/sw/qa/uitest/writer_tests7/tdf141557.py
@@ -0,0 +1,40 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+from uitest.framework import UITestCase
+from com.sun.star.text.TextContentAnchorType import AS_CHARACTER, AT_PARAGRAPH
+import org.libreoffice.unotest
+from uitest.uihelper.common import get_url_for_data_file
+
+class tdf141557(UITestCase):
+    def test_tdf141557(self):
+        # load the sample file
+        self.ui_test.load_file(get_url_for_data_file("tdf141557.docx"))
+        xWriterDoc = self.xUITest.getTopFocusWindow()
+        xWriterEdit = xWriterDoc.getChild("writer_edit")
+        document = self.ui_test.get_component()
+
+        self.assertEqual(AS_CHARACTER, 
document.DrawPage.getByIndex(0).AnchorType)
+
+        self.xUITest.executeCommand(".uno:JumpToNextFrame")
+
+        self.ui_test.wait_until_child_is_available('metricfield')
+
+        self.ui_test.execute_dialog_through_command(".uno:TransformDialog")
+
+        xDialog = self.xUITest.getTopFocusWindow()
+
+        xDialog.getChild('topara').executeAction("CLICK", tuple())
+
+        xOkBtn = xDialog.getChild("ok")
+        xOkBtn.executeAction("CLICK", tuple())
+
+        # Without the fix in place, at this point crash occurs.
+        self.assertEqual(AT_PARAGRAPH, 
document.DrawPage.getByIndex(0).AnchorType)
+
+        self.ui_test.close_doc()
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/doc/textboxhelper.cxx 
b/sw/source/core/doc/textboxhelper.cxx
index 08fccb737b6c..f093b2370a22 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -622,7 +622,10 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, 
sal_uInt16 nWID, sal_u
                     aPropertyName = UNO_NAME_HORI_ORIENT;
                     break;
                 case MID_HORIORIENT_RELATION:
-                    aPropertyName = UNO_NAME_HORI_ORIENT_RELATION;
+                    if (pShape->GetAnchor().GetAnchorId() != 
RndStdIds::FLY_AS_CHAR)
+                        aPropertyName = UNO_NAME_HORI_ORIENT_RELATION;
+                    else
+                        return;
                     break;
                 case MID_HORIORIENT_POSITION:
                     aPropertyName = UNO_NAME_HORI_ORIENT_POSITION;
@@ -660,7 +663,10 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, 
sal_uInt16 nWID, sal_u
                     aPropertyName = UNO_NAME_VERT_ORIENT;
                     break;
                 case MID_VERTORIENT_RELATION:
-                    aPropertyName = UNO_NAME_VERT_ORIENT_RELATION;
+                    if (pShape->GetAnchor().GetAnchorId() != 
RndStdIds::FLY_AS_CHAR)
+                        aPropertyName = UNO_NAME_VERT_ORIENT_RELATION;
+                    else
+                        return;
                     break;
                 case MID_VERTORIENT_POSITION:
                     aPropertyName = UNO_NAME_VERT_ORIENT_POSITION;
@@ -699,110 +705,10 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* 
pShape, sal_uInt16 nWID, sal_u
             {
                 case MID_ANCHOR_ANCHORTYPE:
                 {
-                    uno::Reference<beans::XPropertySet> const xPropertySet(
-                        SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), 
pFormat),
-                        uno::UNO_QUERY);
-                    // Surround (Wrap) has to be THROUGH always:
-                    xPropertySet->setPropertyValue(UNO_NAME_SURROUND,
-                                                   
uno::makeAny(text::WrapTextMode_THROUGH));
-                    // Use At_Char anchor instead of As_Char anchoring:
-                    if (aValue.get<text::TextContentAnchorType>()
-                        == 
text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER)
-                    {
-                        if (const auto aPos = 
pShape->GetAnchor().GetContentAnchor())
-                        {
-                            xPropertySet->setPropertyValue(
-                                UNO_NAME_ANCHOR_TYPE,
-                                uno::makeAny(text::TextContentAnchorType::
-                                                 
TextContentAnchorType_AT_CHARACTER));
-                            xPropertySet->setPropertyValue(
-                                UNO_NAME_HORI_ORIENT_RELATION,
-                                uno::makeAny(text::RelOrientation::CHAR));
-
-                            auto pAnch = pFormat->GetAnchor();
-                            
pAnch.SetAnchor(pShape->GetAnchor().GetContentAnchor());
-                            tools::Rectangle aRect(getTextRectangle(pShape, 
false));
-
-                            SwFormatHoriOrient 
aNewHOri(pFormat->GetHoriOrient());
-                            aNewHOri.SetPos(aRect.getX());
-
-                            SwFormatVertOrient 
aNewVOri(pFormat->GetVertOrient());
-                            aNewVOri.SetPos(aRect.getY());
-
-                            pFormat->SetFormatAttr(pAnch);
-                            // tdf#140598: Do not apply wrong rectangle 
position.
-                            if (aRect.TopLeft() != Point(0, 0))
-                            {
-                                pFormat->SetFormatAttr(aNewHOri);
-                                pFormat->SetFormatAttr(aNewVOri);
-                            }
-                            else
-                                SAL_WARN("sw.core",
-                                         "SwTextBoxHelper::syncProperty: 
Repositioning failed!");
-                        }
+                    setWrapThrough(pShape);
+                    changeAnchor(pShape);
+                    doTextBoxPositioning(pShape);
 
-                        return;
-                    }
-                    else // Otherwise copy the anchor type of the shape
-                    {
-                        // tdf#140828: Do not keep CHAR rel-orientation:
-                        
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
-                                                       
uno::Any(text::RelOrientation::FRAME));
-                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, 
aValue);
-                    }
-                    // After anchoring the position must be set as well:
-                    // At-Page anchor this will be the following:
-                    if (aValue.get<text::TextContentAnchorType>()
-                        == 
text::TextContentAnchorType::TextContentAnchorType_AT_PAGE)
-                    {
-                        if (pShape->GetAnchor().GetPageNum())
-                            xPropertySet->setPropertyValue(
-                                UNO_NAME_ANCHOR_PAGE_NO,
-                                
uno::makeAny(pShape->GetAnchor().GetPageNum()));
-                        else
-                        {
-                            SAL_WARN("sw.core", 
"SwTextBoxHelper::syncProperty: Invalid Page Num!");
-                            return;
-                        }
-                    }
-                    // At-Content Anchors have to be synced:
-                    if (aValue.get<text::TextContentAnchorType>()
-                            == 
text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH
-                        || aValue.get<text::TextContentAnchorType>()
-                               == 
text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER)
-                    {
-                        // If the shape has content...
-                        if (auto aPos = pShape->GetAnchor().GetContentAnchor())
-                        {
-                            SwFormatAnchor aAnch(pFormat->GetAnchor());
-                            // ...set it for the textframe too.
-                            aAnch.SetAnchor(aPos);
-                            pFormat->SetFormatAttr(aAnch);
-                        }
-                        else
-                            SAL_WARN("sw.core",
-                                     "SwTextBoxHelper::syncProperty: Anchor 
without content!");
-                    }
-                    // And the repositioning:
-                    if (pShape->GetAnchor().GetAnchorId() != 
RndStdIds::FLY_AS_CHAR)
-                    {
-                        tools::Rectangle aRect(getTextRectangle(pShape, 
false));
-
-                        // tdf#140598: Do not apply wrong rectangle position.
-                        if (aRect.TopLeft() != Point(0, 0))
-                        {
-                            SwFormatHoriOrient 
aNewHOri(pShape->GetHoriOrient());
-                            aNewHOri.SetPos(aNewHOri.GetPos() + aRect.getX());
-                            SwFormatVertOrient 
aNewVOri(pShape->GetVertOrient());
-                            aNewVOri.SetPos(aNewVOri.GetPos() + aRect.getY());
-
-                            pFormat->SetFormatAttr(aNewHOri);
-                            pFormat->SetFormatAttr(aNewVOri);
-                        }
-                        else
-                            SAL_WARN("sw.core",
-                                     "SwTextBoxHelper::syncProperty: 
Repositioning failed!");
-                    }
                     return;
                 }
                 break;
@@ -1112,6 +1018,16 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& 
rShape, SfxItemSet const&
         pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
 }
 
+SwFrameFormat* SwTextBoxHelper::getShapeFormat(uno::Reference<drawing::XShape> 
xShape)
+{
+    if (xShape)
+        if (auto pShape = dynamic_cast<SwXShape*>(xShape.get()))
+            if (SwFrameFormat* pFormat = pShape->GetFrameFormat())
+                return pFormat;
+    SAL_WARN("sw.core", "SwTextBoxHelper::getShapeFormat: No Shape Format!");
+    return nullptr;
+}
+
 void SwTextBoxHelper::updateTextBoxMargin(SdrObject* pObj)
 {
     if (!pObj)
@@ -1152,4 +1068,240 @@ void SwTextBoxHelper::updateTextBoxMargin(SdrObject* 
pObj)
                  uno::Any(bIsAutoWrap ? text::SizeType::FIX : 
text::SizeType::MIN));
 }
 
+bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape)
+{
+    OUString sErrMsg;
+    if (isTextBoxShapeHasValidTextFrame(pShape))
+    {
+        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+        {
+            if (auto xFrame = 
SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat))
+                try
+                {
+                    uno::Reference<beans::XPropertySet> const 
xPropertySet(xFrame, uno::UNO_QUERY);
+                    xPropertySet->setPropertyValue(UNO_NAME_SURROUND,
+                                                   
uno::makeAny(text::WrapTextMode_THROUGH));
+                    return true;
+                }
+                catch (uno::Exception& e)
+                {
+                    sErrMsg = "Exception caught: " + e.Message;
+                }
+            else
+                sErrMsg = "No XTextFrame!";
+        }
+        else
+            sErrMsg = "No Other TextBox Format!";
+    }
+    else
+        sErrMsg = "Not a Valid TextBox object!";
+
+    SAL_WARN("sw.core", "SwTextBoxHelper::setWrapThrough: " << sErrMsg);
+    return false;
+}
+
+bool SwTextBoxHelper::setWrapThrough(uno::Reference<drawing::XShape> xShape)
+{
+    if (auto pShape = getShapeFormat(xShape))
+        return setWrapThrough(pShape);
+    return false;
+}
+
+bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape)
+{
+    if (isTextBoxShapeHasValidTextFrame(pShape))
+    {
+        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+        {
+            const SwFormatAnchor& rOldAnch = pFormat->GetAnchor();
+            const SwFormatAnchor& rNewAnch = pShape->GetAnchor();
+
+            const auto pOldCnt = rOldAnch.GetContentAnchor();
+            const auto pNewCnt = rNewAnch.GetContentAnchor();
+
+            const uno::Any aShapeHorRelOrient
+                = uno::makeAny(pShape->GetHoriOrient().GetRelationOrient());
+
+            if (isAnchorTypeDifferent(pShape))
+            {
+                try
+                {
+                    uno::Reference<beans::XPropertySet> const xPropertySet(
+                        SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), 
pFormat),
+                        uno::UNO_QUERY);
+                    if (pOldCnt && rNewAnch.GetAnchorId() == 
RndStdIds::FLY_AT_PAGE
+                        && rNewAnch.GetPageNum())
+                    {
+                        uno::Any aValue(text::TextContentAnchorType_AT_PAGE);
+                        
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
+                                                       aShapeHorRelOrient);
+                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, 
aValue);
+                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
+                                                       
uno::Any(rNewAnch.GetPageNum()));
+                    }
+                    else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE 
&& pNewCnt)
+                    {
+                        if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+                        {
+                            uno::Any 
aValue(text::TextContentAnchorType_AT_CHARACTER);
+                            
xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
+                            
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
+                                                           
uno::Any(text::RelOrientation::CHAR));
+                            xPropertySet->setPropertyValue(
+                                UNO_NAME_VERT_ORIENT_RELATION,
+                                uno::Any(text::RelOrientation::PRINT_AREA));
+                            SwFormatAnchor aPos(pFormat->GetAnchor());
+                            aPos.SetAnchor(pNewCnt);
+                            pFormat->SetFormatAttr(aPos);
+                        }
+                        else
+                        {
+                            uno::Any 
aValue(mapAnchorType(rNewAnch.GetAnchorId()));
+                            
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
+                                                           aShapeHorRelOrient);
+                            
xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
+                            pFormat->SetFormatAttr(rNewAnch);
+                        }
+                    }
+                    else
+                    {
+                        if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+                        {
+                            uno::Any 
aValue(text::TextContentAnchorType_AT_CHARACTER);
+                            
xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
+                            
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
+                                                           
uno::Any(text::RelOrientation::CHAR));
+                            xPropertySet->setPropertyValue(
+                                UNO_NAME_VERT_ORIENT_RELATION,
+                                uno::Any(text::RelOrientation::PRINT_AREA));
+                            SwFormatAnchor aPos(pFormat->GetAnchor());
+                            aPos.SetAnchor(pNewCnt);
+                            pFormat->SetFormatAttr(aPos);
+                        }
+                        else
+                        {
+                            
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
+                                                           aShapeHorRelOrient);
+                            pFormat->SetFormatAttr(pShape->GetAnchor());
+                        }
+                    }
+                }
+                catch (uno::Exception& e)
+                {
+                    SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << 
e.Message);
+                }
+            }
+
+            return doTextBoxPositioning(pShape);
+        }
+    }
+    return false;
+}
+
+bool SwTextBoxHelper::changeAnchor(uno::Reference<drawing::XShape> xShape)
+{
+    if (auto pShape = getShapeFormat(xShape))
+        return changeAnchor(pShape);
+    return false;
+}
+
+bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape)
+{
+    if (isTextBoxShapeHasValidTextFrame(pShape))
+    {
+        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+        {
+            if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+            {
+                tools::Rectangle aRect(getTextRectangle(pShape, false));
+
+                SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient());
+                aNewHOri.SetPos(aRect.getX());
+
+                SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
+                aNewVOri.SetPos(aRect.getY() + 
pShape->GetVertOrient().GetPos());
+
+                // tdf#140598: Do not apply wrong rectangle position.
+                if (aRect.TopLeft() != Point(0, 0))
+                {
+                    pFormat->SetFormatAttr(aNewHOri);
+                    pFormat->SetFormatAttr(aNewVOri);
+                }
+                else
+                    SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: 
Repositioning failed!");
+            }
+            else
+            {
+                tools::Rectangle aRect(getTextRectangle(pShape, false));
+
+                // tdf#140598: Do not apply wrong rectangle position.
+                if (aRect.TopLeft() != Point(0, 0))
+                {
+                    SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
+                    aNewHOri.SetPos(aNewHOri.GetPos() + aRect.getX());
+                    SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
+                    aNewVOri.SetPos(aNewVOri.GetPos() + aRect.getY());
+
+                    pFormat->SetFormatAttr(aNewHOri);
+                    pFormat->SetFormatAttr(aNewVOri);
+                }
+                else
+                    SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: 
Repositioning failed!");
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
+bool SwTextBoxHelper::doTextBoxPositioning(uno::Reference<drawing::XShape> 
xShape)
+{
+    if (auto pShape = getShapeFormat(xShape))
+        return doTextBoxPositioning(pShape);
+    return false;
+}
+
+std::optional<bool> SwTextBoxHelper::isAnchorTypeDifferent(SwFrameFormat* 
pShape)
+{
+    std::optional<bool> bRet;
+    if (isTextBoxShapeHasValidTextFrame(pShape))
+    {
+        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+        {
+            if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+                bRet = (pFormat->GetAnchor().GetAnchorId() != 
RndStdIds::FLY_AT_CHAR
+                        && pFormat->GetAnchor().GetAnchorId() != 
RndStdIds::FLY_AS_CHAR);
+            else
+                bRet = pFormat->GetAnchor().GetAnchorId() != 
pShape->GetAnchor().GetAnchorId();
+        }
+    }
+    return bRet;
+}
+
+bool SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(SwFrameFormat* pShape)
+{
+    OUString sErrMsg;
+    if (pShape && pShape->Which() == RES_DRAWFRMFMT)
+        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+            if (pFormat && pFormat->Which() == RES_FLYFRMFMT)
+                return true;
+            else
+                sErrMsg = "Shape do not have valid textframe!";
+        else
+            sErrMsg = "Shape do not have associated frame!";
+    else
+        sErrMsg = "Not valid shape!";
+
+    SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: " 
<< sErrMsg);
+    return false;
+}
+
+bool 
SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(uno::Reference<drawing::XShape>
 xShape)
+{
+    if (auto pShape = getShapeFormat(xShape))
+        return isTextBoxShapeHasValidTextFrame(pShape);
+
+    return false;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/porfly.cxx b/sw/source/core/text/porfly.cxx
index cb071be3c512..212de1db0288 100644
--- a/sw/source/core/text/porfly.cxx
+++ b/sw/source/core/text/porfly.cxx
@@ -363,6 +363,7 @@ void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, 
const Point &rBase,
             if (!aPos->nNode.GetNode().FindFooterStartNode())
             {
                 aVert.SetVertOrient(css::text::VertOrientation::NONE);
+                aVert.SetRelationOrient(css::text::RelOrientation::FRAME);
                 sal_Int32 const nTop = aTextRectangle.getY() - 
rFrame.getFrameArea().Top()
                                        - rFrame.getFramePrintArea().Top();
                 aVert.SetPos(nTop);
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to