tdf#133045 sw: add shape alignment to the top page border

Allow relative alignment to the top page border (the area
over PAGE_PRINT_AREA) by adding constant PAGE_PRINT_AREA_TOP
to com::sun::star::text::RelOrientation.

Fix DOCX shape import of <wp:positionV relativeFrom="topMargin">.

Follow-up of commit 6788133b3bdf02097d66a99047aa7bcba3a99a66
(tdf#135720 sw: fix PAGE_PRINT_AREA_BOTTOM alignment with footer)
and commit 79107d3f8d10aa0f38641775c5eb47dcfd4fd37e
(sw from-bottom relative orientation: add UNO API).

Co-authored-by: Balázs Regényi

Change-Id: I3a3f7324c0ef8d448526982d3e2f09b67f5fd4d4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104113
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/offapi/com/sun/star/text/RelOrientation.idl b/offapi/com/sun/star/text/RelOrientation.idl
index 59f39a0..3ce3160 100644
--- a/offapi/com/sun/star/text/RelOrientation.idl
+++ b/offapi/com/sun/star/text/RelOrientation.idl
@@ -73,12 +73,18 @@ published constants RelOrientation
         */
        const short TEXT_LINE = 9;

    /** Similar to PAGE_PRINT_AREA, but count from bottom, not from top.
    /** Bottom page border (page area below PAGE_PRINT_AREA).

        @since LibreOffice 7.0
     */
    const short PAGE_PRINT_AREA_BOTTOM = 10;

    /** Top page border (page area above PAGE_PRINT_AREA).

        @since LibreOffice 7.1
     */
    const short PAGE_PRINT_AREA_TOP = 11;

};


diff --git a/sw/qa/extras/ooxmlexport/data/tdf133045_TestShapeAlignmentRelativeFromTopMargin.docx b/sw/qa/extras/ooxmlexport/data/tdf133045_TestShapeAlignmentRelativeFromTopMargin.docx
new file mode 100644
index 0000000..2cd299f
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf133045_TestShapeAlignmentRelativeFromTopMargin.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
index 44d0bc8..cb00fff 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
@@ -998,6 +998,21 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf133924, "tdf133924.docx")
    assertXPath(pXmlDocument, "/w:document/w:body/w:p[2]/w:pPr/w:framePr", "wrap", "notBeside");
}

DECLARE_OOXMLEXPORT_TEST(testRelativeAlignmentFromTopMargin,
                         "tdf133045_TestShapeAlignmentRelativeFromTopMargin.docx")
{
    // tdf#133045 These shapes are relatively aligned from top margin, vertically to
    // top, center and bottom.

    if (mbExported)
        return;

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "//SwAnchoredDrawObject[1]/bounds", "top", "1487"); // center
    assertXPath(pXmlDoc, "//SwAnchoredDrawObject[2]/bounds", "top", "2668"); // bottom
    assertXPath(pXmlDoc, "//SwAnchoredDrawObject[3]/bounds", "top", "298");  // top
}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
index bfcd075..a5180ac 100644
--- a/sw/source/core/objectpositioning/anchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
@@ -250,6 +250,7 @@ void SwAnchoredObjectPosition::GetVertAlignmentValues(
        }
        break;
        case text::RelOrientation::PAGE_FRAME:
        case text::RelOrientation::PAGE_PRINT_AREA_TOP:
        {
            nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFrameArea());
            nOffset = aRectFnSet.YDiff(
diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
index e115ed5..dea6424 100644
--- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -249,6 +249,14 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                                     aVert.GetRelationOrient(),
                                     nAlignAreaHeight, nAlignAreaOffset );

            SwRect aHeaderRect;
            const SwPageFrame* aPageFrame = pOrientFrame->FindPageFrame();
            const SwHeaderFrame* pHeaderFrame = aPageFrame->GetHeaderFrame();
            if (pHeaderFrame)
                aHeaderRect = pHeaderFrame->GetPaintArea();
            const SwTwips nTopMarginHeight = aPageFrame->GetTopMargin() + aHeaderRect.Height();
            const SwTwips nHeightBetweenOffsetAndMargin = nAlignAreaOffset + nTopMarginHeight;

            // determine relative vertical position
            SwTwips nRelPosY = nAlignAreaOffset;
            const SwTwips nObjHeight = aRectFnSet.GetHeight(aObjBoundRect);
@@ -310,7 +318,10 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                break;
                case text::VertOrientation::CENTER:
                {
                    nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
                    if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
                        nRelPosY = (nAlignAreaOffset / 2) - (nObjHeight / 2) + (nHeightBetweenOffsetAndMargin / 2);
                    else
                        nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
                }
                break;
                // #i22341#
@@ -347,8 +358,10 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                        }
                        else
                        {
                            nRelPosY += nAlignAreaHeight -
                                        ( nObjHeight + nLowerSpace );
                            if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
                                nRelPosY = 0 - (nObjHeight + nLowerSpace) + nHeightBetweenOffsetAndMargin;
                            else
                                nRelPosY += nAlignAreaHeight - (nObjHeight + nLowerSpace);
                        }
                    }
                }
@@ -525,7 +538,8 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                // #i18732# - adjust <nRelPosY> by difference
                // between 'page area' and 'anchor' frame, if position is
                // vertical aligned to 'page areas'
                else if ( aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME )
                else if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME
                         || aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
                {
                    nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(
                                    aRectFnSet.GetTop(rPageAlignLayFrame.getFrameArea()),
diff --git a/writerfilter/source/dmapper/GraphicHelpers.cxx b/writerfilter/source/dmapper/GraphicHelpers.cxx
index 54933b2..0bd7354 100644
--- a/writerfilter/source/dmapper/GraphicHelpers.cxx
+++ b/writerfilter/source/dmapper/GraphicHelpers.cxx
@@ -68,8 +68,11 @@ void PositionHandler::lcl_attribute( Id aName, Value& rVal )
                        break;

                    case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_page:
                    case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_topMargin: // fallthrough intended
                        m_nRelation =  text::RelOrientation::PAGE_FRAME;
                        m_nRelation = text::RelOrientation::PAGE_FRAME;
                        break;

                    case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_topMargin:
                        m_nRelation = text::RelOrientation::PAGE_PRINT_AREA_TOP;
                        break;

                    case NS_ooxml::LN_Value_wordprocessingDrawing_ST_RelFromV_bottomMargin: