tdf#106153 sw compatibility: fix textboxes exceeding the page

In compatibility mode DISABLE_OFF_PAGE_POSITIONING, textboxes
fell apart by exceeding the page. Now text content stay inside
the textboxes instead of the page area.

Main Developer: Dániel Arató (NISZ).

Commit a4dee94afed9ade6ac50237c8d99a6e49d3bebc1 (tdf#91260: allow
textboxes extending beyond the page bottom) is reverted partially,
according to this and the following commits:

Commit 8d62b79f168180c6992eb483ec864d473050635f
(tdf#112443 disable off-page content positioning) and
commit ee6cd34eb3a2bd1f1340063ee4b90a72ff0c9532
(tdf#123621 sw: fix textbox position according to DOCX).

Change-Id: Icb8fba161f7e8830cdb6bf6e299cccde09e7e008
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/100239
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/inc/anchoredobject.hxx b/sw/inc/anchoredobject.hxx
index 0c5c249..bb65029 100644
--- a/sw/inc/anchoredobject.hxx
+++ b/sw/inc/anchoredobject.hxx
@@ -408,6 +408,12 @@ class SW_DLLPUBLIC SwAnchoredObject
        */
        virtual bool IsFormatPossible() const;

        /** method to determine if dragging objects off page is allowed

            Returns true if editor objects can be dragged off page, false otherwise
        */
        static bool IsDraggingOffPageAllowed(const SwFrameFormat*);

        // accessors to member <mbTmpConsiderWrapInfluence>
        void SetTmpConsiderWrapInfluence( const bool _bTmpConsiderWrapInfluence );
        bool IsTmpConsiderWrapInfluence() const { return mbTmpConsiderWrapInfluence;}
diff --git a/sw/qa/extras/layout/data/tdf106153.docx b/sw/qa/extras/layout/data/tdf106153.docx
new file mode 100644
index 0000000..cba0723
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf106153.docx
Binary files differ
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 0ce8608..438a60b 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -1239,6 +1239,35 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testNoLineBreakAtSlash)
    assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[3]", "Portion", "13/c/2, etc.");
}

CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf106153)
{
    load(DATA_DIRECTORY, "tdf106153.docx");
    xmlDocUniquePtr pDump = parseLayoutDump();

    const sal_Int64 nPageValLeft = getXPath(pDump, "/root/page/infos/bounds", "left").toInt64();
    const sal_Int64 nPageValTop = getXPath(pDump, "/root/page/infos/bounds", "top").toInt64();
    const sal_Int64 nPageValRight = getXPath(pDump, "/root/page/infos/bounds", "right").toInt64();
    const sal_Int64 nPageValBottom = getXPath(pDump, "/root/page/infos/bounds", "bottom").toInt64();

    const sal_Int64 nShape1ValTop
        = getXPath(pDump, "/root/page/body/txt/anchored/fly[1]/infos/bounds", "top").toInt64();
    const sal_Int64 nShape2ValLeft
        = getXPath(pDump, "/root/page/body/txt/anchored/fly[2]/infos/bounds", "left").toInt64();
    const sal_Int64 nShape3ValRight
        = getXPath(pDump, "/root/page/body/txt/anchored/fly[3]/infos/bounds", "right").toInt64();
    const sal_Int64 nShape4ValBottom
        = getXPath(pDump, "/root/page/body/txt/anchored/fly[4]/infos/bounds", "bottom").toInt64();

    CPPUNIT_ASSERT_MESSAGE("The whole top textbox is inside the page!",
                           nPageValTop > nShape1ValTop);
    CPPUNIT_ASSERT_MESSAGE("The whole left textbox is inside the page!",
                           nPageValLeft > nShape2ValLeft);
    CPPUNIT_ASSERT_MESSAGE("The whole right textbox is inside the page!",
                           nPageValRight < nShape3ValRight);
    CPPUNIT_ASSERT_MESSAGE("The whole bottom textbox is inside the page!",
                           nPageValBottom < nShape4ValBottom);
}

CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInFlys)
{
    loadURL("private:factory/swriter", nullptr);
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
index a5e11ec..7d7d5c0 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
@@ -506,17 +506,6 @@ DECLARE_OOXMLEXPORT_TEST(testTDF91122, "tdf91122.docx")
    }
}

DECLARE_OOXMLEXPORT_TEST(testTDF91260, "tdf91260.docx")
{
    /*
     * textbox can't extend beyond the page bottom
     * solution: shrinking textbox (its text frame) height, if needed
     */
    uno::Reference<text::XTextRange> xFrame(getShape(1), uno::UNO_QUERY);
    CPPUNIT_ASSERT(xFrame->getString().startsWith( "Lorem ipsum" ) );
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3454), getProperty<sal_Int32>(xFrame, "Height"));
}

DECLARE_OOXMLEXPORT_TEST(testFdo74357, "fdo74357.docx")
{
    // Floating table wasn't converted to a textframe.
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index 02d4cfe..94d566d 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -527,7 +527,7 @@ void SwVirtFlyDrawObj::wrap_DoPaintObject(
    RestoreMapMode aRestoreMapModeIfNeeded( pShell );

    // paint the FlyFrame (use standard VCL-Paint)
    m_pFlyFrame->PaintSwFrame( *pShell->GetOut(), GetFlyFrame()->getFrameArea() );
    m_pFlyFrame->PaintSwFrame( *pShell->GetOut(), m_pFlyFrame->GetPageFrame()->getFrameArea());
}

void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
diff --git a/sw/source/core/layout/anchoredobject.cxx b/sw/source/core/layout/anchoredobject.cxx
index 0c21a53..5492832 100644
--- a/sw/source/core/layout/anchoredobject.cxx
+++ b/sw/source/core/layout/anchoredobject.cxx
@@ -736,6 +736,15 @@ bool SwAnchoredObject::IsFormatPossible() const
    return GetFrameFormat().GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetDrawObj()->GetLayer() );
}

bool SwAnchoredObject::IsDraggingOffPageAllowed(const SwFrameFormat* pFrameFormat)
{
    OSL_ASSERT(pFrameFormat);
    const bool bDisablePositioning = pFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
    const bool bIsWrapThrough = pFrameFormat->GetSurround().GetSurround() == text::WrapTextMode::WrapTextMode_THROUGH;

    return bDisablePositioning && bIsWrapThrough;
}

// --> #i3317#
void SwAnchoredObject::SetTmpConsiderWrapInfluence( const bool _bTmpConsiderWrapInfluence )
{
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index a5d3e39..e25d805 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -493,7 +493,7 @@ void SwFlyFreeFrame::CheckClip( const SwFormatFrameSize &rSz )

    const bool bBot = nBot > nClipBot;
    const bool bRig = nRig > nClipRig;
    if ( bBot || bRig )
    if (( bBot || bRig ) && !IsDraggingOffPageAllowed(FindFrameFormat(GetDrawObj())))
    {
        bool bAgain = false;
        // #i37068# - no move, if it's requested
diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
index a547ddd..236e4fa 100644
--- a/sw/source/core/objectpositioning/anchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
@@ -38,6 +38,7 @@
#include <IDocumentSettingAccess.hxx>
#include <textboxhelper.hxx>
#include <fmtsrnd.hxx>
#include <svx/sdtagitm.hxx>

using namespace ::com::sun::star;
using namespace objectpositioning;
@@ -417,9 +418,10 @@ SwTwips SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch
                                                         const bool bCheckBottom ) const
{
    SwTwips nAdjustedRelPosY = nProposedRelPosY;
    if (SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)))
        return nAdjustedRelPosY;

    const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() );

    const Size aObjSize(GetAnchoredObj().GetObjRect().SSize());
    // determine the area of 'page' alignment frame, to which the vertical
    // position is restricted.
    // #i28701# - Extend restricted area for the vertical
@@ -468,8 +470,7 @@ SwTwips SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch
            // tdf#112443 if position is completely off-page
            // return the proposed position and do not adjust it...
            // tdf#120839 .. unless anchored to char (anchor can jump on other page)
            bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);

            const bool bDisablePositioning =  mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
            if ( bDisablePositioning && !IsAnchoredToChar() && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Right() )
            {
                return nProposedRelPosY;
@@ -518,30 +519,6 @@ SwTwips SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch
        {
            nAdjustedRelPosY = aPgAlignArea.Top() - nTopOfAnch;
        }

        // tdf#91260  - allow textboxes extending beyond the page bottom
        // tdf#101627 - the patch a4dee94afed9ade6ac50237c8d99a6e49d3bebc1
        //              for tdf#91260 causes problems if the textbox
        //              is anchored in the footer, so exclude this case
        if ( !( GetAnchorFrame().GetUpper() && GetAnchorFrame().GetUpper()->IsFooterFrame() )
             && nAdjustedRelPosY < nProposedRelPosY )
        {
            const SwFrameFormat* pFormat = &(GetFrameFormat());
            if ( GetObject().IsTextBox() )
            {
                // shrink textboxes to extend beyond the page bottom
                SwFrameFormat* pFrameFormat = ::FindFrameFormat(&GetObject());
                SwFormatFrameSize aSize(pFormat->GetFrameSize());
                SwTwips nShrinked = aSize.GetHeight() - (nProposedRelPosY - nAdjustedRelPosY);
                if (nShrinked >= 0) {
                    aSize.SetHeight( nShrinked );
                    pFrameFormat->SetFormatAttr(aSize);
                }
                nAdjustedRelPosY = nProposedRelPosY;
            } else if ( SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT) )
                // when the shape has a textbox, use only the proposed vertical position
                nAdjustedRelPosY = nProposedRelPosY;
        }
    }
    return nAdjustedRelPosY;
}
@@ -557,6 +534,9 @@ SwTwips SwAnchoredObjectPosition::ImplAdjustHoriRelPos(
{
    SwTwips nAdjustedRelPosX = _nProposedRelPosX;

    if (SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)))
        return nAdjustedRelPosX;

    const SwFrame& rAnchorFrame = GetAnchorFrame();
    const bool bVert = rAnchorFrame.IsVertical();