tdf#114308 Export Watermark size as is

* refactoring
* removed size hack
* export/import "trim" attribute
* DOC: export set of parameters to fit shape & frame

Change-Id: Ib00654626ae1e10ac5110d22eada7528e03357e7
Reviewed-on: https://gerrit.libreoffice.org/46036
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Szymon Kłos <szymon.klos@collabora.com>
diff --git a/filter/source/msfilter/escherex.cxx b/filter/source/msfilter/escherex.cxx
index 128d155..6346415 100644
--- a/filter/source/msfilter/escherex.cxx
+++ b/filter/source/msfilter/escherex.cxx
@@ -3475,7 +3475,9 @@ void EscherPropertyContainer::CreateCustomShapeProperties( const MSO_SPT eShapeT
                        }

                        // Use gtextFStretch for Watermark like MSO does
                        nTextPathFlags |= use_gtextFStretch | gtextFStretch;
                        nTextPathFlags |= use_gtextFBestFit | gtextFBestFit
                                        | use_gtextFStretch | gtextFStretch
                                        | use_gtextFShrinkFit | gtextFShrinkFit;

                        if ( nTextPathFlags != nTextPathFlagsOrg )
                            AddOpt( DFF_Prop_gtextFStrikethrough, nTextPathFlags );
diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx
index 9c87dd4..c3b1a95 100644
--- a/filter/source/msfilter/msdffimp.cxx
+++ b/filter/source/msfilter/msdffimp.cxx
@@ -4441,13 +4441,7 @@ SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& r
                            sal_Int32 nPaddingY = aObjData.aBoundRect.getHeight() - nNewHeight;

                            if ( nPaddingY > 0 )
                            {
                                // Remember that value because original size have to be exported
                                aSet.Put( SdrMetricItem( SDRATTR_TEXT_UPPERDIST, nPaddingY ) );
                                aObjData.aBoundRect.setHeight( nNewHeight );
                            }
                            else
                                aSet.Put( SdrMetricItem( SDRATTR_TEXT_UPPERDIST, 0 ) );
                        }
                    }
                    pRet->SetMergedItemSet( aSet );
diff --git a/include/oox/vml/vmlformatting.hxx b/include/oox/vml/vmlformatting.hxx
index 5bfb0c0..1c58989 100644
--- a/include/oox/vml/vmlformatting.hxx
+++ b/include/oox/vml/vmlformatting.hxx
@@ -254,6 +254,7 @@ struct OOX_DLLPUBLIC TextpathModel
{
    OptValue<OUString> moString;                  ///< Specifies the string of the textpath.
    OptValue<OUString> moStyle;                   ///< Specifies the style of the textpath.
    OptValue<bool>     moTrim;                    ///< Specifies whether extra space is removed above and below the text

    TextpathModel();

diff --git a/include/svx/msdffdef.hxx b/include/svx/msdffdef.hxx
index 0c62f5e..238ab52 100644
--- a/include/svx/msdffdef.hxx
+++ b/include/svx/msdffdef.hxx
@@ -848,8 +848,10 @@ enum MSO_SYSCOLORINDEX {

enum MSO_TextGeometryProperties {
    use_gtextFBestFit   = 0x00000100,
    use_gtextFShrinkFit = 0x00000200,
    use_gtextFStretch   = 0x00000400,
    gtextFBestFit       = 0x01000000,
    gtextFShrinkFit     = 0x02000000,
    gtextFStretch       = 0x04000000
};

diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 1c5f62e..498552b 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -924,6 +924,9 @@ void VMLExport::Commit( EscherPropertyContainer& rProps, const tools::Rectangle&
                            OUString aSize = OUString::number(nSizeF);
                            aStyle += ";font-size:" + aSize + "pt";
                        }
                        if (IsWaterMarkShape(m_pSdrObject->GetName()))
                            pAttrList->add(XML_trim, "t");

                        if (!aStyle.isEmpty())
                            pAttrList->add(XML_style, OUStringToOString(aStyle, RTL_TEXTENCODING_UTF8));
                        m_pSerializer->singleElementNS(XML_v, XML_textpath, XFastAttributeListRef(pAttrList));
diff --git a/oox/source/vml/vmlformatting.cxx b/oox/source/vml/vmlformatting.cxx
index 2f9cf34..5861ed8 100644
--- a/oox/source/vml/vmlformatting.cxx
+++ b/oox/source/vml/vmlformatting.cxx
@@ -20,6 +20,7 @@

#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
#include <com/sun/star/table/ShadowFormat.hpp>
#include <com/sun/star/text/XTextRange.hpp>
@@ -36,6 +37,7 @@
#include <oox/token/tokens.hxx>
#include <svx/svdtrans.hxx>
#include <comphelper/propertysequence.hxx>
#include <vcl/virdev.hxx>

namespace oox {
namespace vml {
@@ -897,6 +899,8 @@ beans::PropertyValue lcl_createTextpathProps()

void TextpathModel::pushToPropMap(ShapePropertyMap& rPropMap, const uno::Reference<drawing::XShape>& xShape, const GraphicHelper& rGraphicHelper) const
{
    OUString sFont = "";

    if (moString.has())
    {
        uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
@@ -940,6 +944,7 @@ void TextpathModel::pushToPropMap(ShapePropertyMap& rPropMap, const uno::Referen

                    uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
                    xPropertySet->setPropertyValue("CharFontName", uno::makeAny(aValue));
                    sFont = aValue;
                }
                else if (aName == "font-size")
                {
@@ -952,6 +957,26 @@ void TextpathModel::pushToPropMap(ShapePropertyMap& rPropMap, const uno::Referen
            }
        }
    }
    if (!moTrim.has() || !moTrim.get())
    {
        OUString sText = moString.get();
        double fRatio = 0;
        VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
        vcl::Font aFont = pDevice->GetFont();
        aFont.SetFamilyName(sFont);
        aFont.SetFontSize(Size(0, 96));
        pDevice->SetFont(aFont);

        auto nTextWidth = pDevice->GetTextWidth(sText);
        if (nTextWidth)
        {
            fRatio = pDevice->GetTextHeight();
            fRatio /= nTextWidth;

            sal_Int32 nNewHeight = fRatio * xShape->getSize().Width;
            xShape->setSize(awt::Size(xShape->getSize().Width, nNewHeight));
        }
    }
}

} // namespace vml
diff --git a/oox/source/vml/vmlshape.cxx b/oox/source/vml/vmlshape.cxx
index 6e792d9..8dfadd7 100644
--- a/oox/source/vml/vmlshape.cxx
+++ b/oox/source/vml/vmlshape.cxx
@@ -1143,79 +1143,12 @@ CustomShape::CustomShape( Drawing& rDrawing ) :
{
}

static OUString lcl_getFontFamily( const oox::OptValue<OUString>& rStyle )
{
    OUString sFont = "";

    if( rStyle.has() )
    {
        OUString aStyle = rStyle.get( OUString() );

        sal_Int32 nIndex = 0;
        while( nIndex >= 0 )
        {
            OUString aName;
            if( ConversionHelper::separatePair( aName, sFont, aStyle.getToken( 0, ';', nIndex ), ':' ) )
            {
                if( aName == "font-family" )
                {
                    // remove " (first, and last character)
                    if( sFont.getLength() > 2 )
                        sFont = sFont.copy( 1, sFont.getLength() - 2 );
                }
            }
        }
    }

    return sFont;
}

/// modifies rShapeRect's height and returns difference
sal_Int32 lcl_correctWatermarkRect( awt::Rectangle& rShapeRect, const OUString& sFont, const OUString& sText )
{
    sal_Int32 nPaddingY = 0;
    double fRatio = 0;
    VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
    vcl::Font aFont = pDevice->GetFont();
    aFont.SetFamilyName( sFont );
    aFont.SetFontSize( Size( 0, 96 ) );
    pDevice->SetFont( aFont );

    auto nTextWidth = pDevice->GetTextWidth( sText );
    if( nTextWidth )
    {
        fRatio = pDevice->GetTextHeight();
        fRatio /= nTextWidth;

        sal_Int32 nNewHeight = fRatio * rShapeRect.Width;
        nPaddingY = rShapeRect.Height - nNewHeight;
        rShapeRect.Height = nNewHeight;
    }

    return nPaddingY;
}

Reference< XShape > CustomShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
{
    awt::Rectangle aShapeRect( rShapeRect );

    // Add padding for Watermark like Word does
    sal_Int32 nPaddingY = 0;
    if( getShapeName().match( "PowerPlusWaterMarkObject" ) && maTypeModel.maTextpathModel.moString.has() )
    {
        OUString sText = maTypeModel.maTextpathModel.moString.get();
        OUString sFont = lcl_getFontFamily( maTypeModel.maTextpathModel.moStyle );
        nPaddingY = lcl_correctWatermarkRect( aShapeRect, sFont, sText );
    }

    // try to create a custom shape
    Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, aShapeRect );
    Reference< XShape > xShape = SimpleShape::implConvertAndInsert( rxShapes, rShapeRect );
    if( xShape.is() ) try
    {
        // Remember padding for Watermark
        if( nPaddingY )
            PropertySet( xShape ).setAnyProperty( PROP_TextUpperDistance, makeAny( nPaddingY ) );

        // create the custom shape geometry
        Reference< XEnhancedCustomShapeDefaulter > xDefaulter( xShape, UNO_QUERY_THROW );
        xDefaulter->createCustomShapeDefaults( OUString::number( getShapeType() ) );
diff --git a/oox/source/vml/vmlshapecontext.cxx b/oox/source/vml/vmlshapecontext.cxx
index 8181c98..18dc68d 100644
--- a/oox/source/vml/vmlshapecontext.cxx
+++ b/oox/source/vml/vmlshapecontext.cxx
@@ -396,6 +396,7 @@ ContextHandlerRef ShapeTypeContext::onCreateContext( sal_Int32 nElement, const A
        case VML_TOKEN( textpath ):
            mrTypeModel.maTextpathModel.moString.assignIfUsed(rAttribs.getString(XML_string));
            mrTypeModel.maTextpathModel.moStyle.assignIfUsed(rAttribs.getString(XML_style));
            mrTypeModel.maTextpathModel.moTrim.assignIfUsed(lclDecodeBool(rAttribs, XML_trim));
        break;
    }
    return nullptr;
diff --git a/sw/qa/extras/ooxmlexport/data/tdf114308.docx b/sw/qa/extras/ooxmlexport/data/tdf114308.docx
new file mode 100755
index 0000000..0796200
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf114308.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index 9c29fd4..e5af806 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -1752,14 +1752,25 @@ DECLARE_OOXMLEXPORT_TEST(testWatermark, "watermark.docx")
    uno::Reference<drawing::XShape> xShape(getShape(1), uno::UNO_QUERY);
    uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);

    sal_Int32 nTotalHeight = 0;
    xPropertySet->getPropertyValue(UNO_NAME_TEXT_UPPERDIST) >>= nTotalHeight;
    nTotalHeight += xShape->getSize().Height;
    sal_Int32 nHeight = xShape->getSize().Height;

    // Rounding errors
    sal_Int32 nDifference = 5198 - nTotalHeight;
    sal_Int32 nDifference = 5150 - nHeight;
    std::stringstream ss;
    ss << "Difference: " << nDifference << " TotalHeight: " << nTotalHeight;
    ss << "Difference: " << nDifference << " TotalHeight: " << nHeight;
    CPPUNIT_ASSERT_MESSAGE(ss.str(), nDifference <= 4);
    CPPUNIT_ASSERT_MESSAGE(ss.str(), nDifference >= -4);
}

DECLARE_OOXMLEXPORT_TEST(testWatermarkTrim, "tdf114308.docx")
{
    uno::Reference<drawing::XShape> xShape(getShape(1), uno::UNO_QUERY);

    // Rounding errors
    sal_Int32 nHeight = xShape->getSize().Height;
    sal_Int32 nDifference = 8729 - nHeight;
    std::stringstream ss;
    ss << "Difference: " << nDifference << " TotalHeight: " << nHeight;
    CPPUNIT_ASSERT_MESSAGE(ss.str(), nDifference <= 4);
    CPPUNIT_ASSERT_MESSAGE(ss.str(), nDifference >= -4);
}
diff --git a/sw/qa/extras/ww8export/ww8export2.cxx b/sw/qa/extras/ww8export/ww8export2.cxx
index 9ef0c5f..4805113 100644
--- a/sw/qa/extras/ww8export/ww8export2.cxx
+++ b/sw/qa/extras/ww8export/ww8export2.cxx
@@ -269,12 +269,8 @@ DECLARE_WW8EXPORT_TEST(testTdf91687, "tdf91687.doc")
{
    // Exported Watermarks were resized
    uno::Reference<drawing::XShape> xWatermark = getShape(1);
    uno::Reference<beans::XPropertySet> xWatermarkProperties(xWatermark, uno::UNO_QUERY);

    sal_Int32 nHeight = 0;
    xWatermarkProperties->getPropertyValue(UNO_NAME_TEXT_UPPERDIST) >>= nHeight;

    CPPUNIT_ASSERT_EQUAL((sal_Int32)5172, xWatermark->getSize().Height + nHeight);
    CPPUNIT_ASSERT_EQUAL((sal_Int32)5172, xWatermark->getSize().Height);
    CPPUNIT_ASSERT_EQUAL((sal_Int32)18105, xWatermark->getSize().Width);
}

diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx
index 19db9f1..60bba7d 100644
--- a/sw/source/core/edit/edfcol.cxx
+++ b/sw/source/core/edit/edfcol.cxx
@@ -1463,7 +1463,6 @@ void lcl_placeWatermarkInHeader(const SfxWatermarkItem& rWatermark,

    // Calc the ratio.
    double fRatio = 0;
    double fRatioFrame = 0;

    VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
    vcl::Font aFont = pDevice->GetFont();
@@ -1471,17 +1470,11 @@ void lcl_placeWatermarkInHeader(const SfxWatermarkItem& rWatermark,
    aFont.SetFontSize(Size(0, 96));
    pDevice->SetFont(aFont);

    tools::Rectangle aBoundingRect;
    pDevice->GetTextBoundRect(aBoundingRect, rWatermark.GetText());
    if (aBoundingRect.GetWidth())
    {
        fRatio = (double)aBoundingRect.getHeight() / aBoundingRect.getWidth();
    }
    auto nTextWidth = pDevice->GetTextWidth(rWatermark.GetText());
    if (nTextWidth)
    {
        fRatioFrame = pDevice->GetTextHeight();
        fRatioFrame /= nTextWidth;
        fRatio = pDevice->GetTextHeight();
        fRatio /= nTextWidth;
    }

    // Calc the size.
@@ -1507,13 +1500,12 @@ void lcl_placeWatermarkInHeader(const SfxWatermarkItem& rWatermark,
        nWidth = aSize.Height - nTopMargin - nBottomMargin;
    }
    sal_Int32 nHeight = fRatio * nWidth;
    sal_Int32 nFrameHeight = fRatioFrame * nWidth;

    // Create and insert the shape.
    uno::Reference<drawing::XShape> xShape(xMultiServiceFactory->createInstance(aShapeServiceName), uno::UNO_QUERY);
    basegfx::B2DHomMatrix aTransformation;
    aTransformation.identity();
    aTransformation.scale(nWidth, nFrameHeight);
    aTransformation.scale(nWidth, nHeight);
    aTransformation.rotate(F_PI180 * -1 * nAngle);
    drawing::HomogenMatrix3 aMatrix;
    aMatrix.Line1.Column1 = aTransformation.get(0, 0);
@@ -1540,14 +1532,13 @@ void lcl_placeWatermarkInHeader(const SfxWatermarkItem& rWatermark,
    xPropertySet->setPropertyValue(UNO_NAME_OPAQUE, uno::makeAny(false));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::makeAny(false));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::makeAny(false));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEHEIGHT, uno::makeAny(nFrameHeight));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEHEIGHT, uno::makeAny(nHeight));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_MINFRAMEWIDTH, uno::makeAny(nWidth));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_WRAP, uno::makeAny(text::WrapTextMode_THROUGH));
    xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION, uno::makeAny(static_cast<sal_Int16>(text::RelOrientation::PAGE_PRINT_AREA)));
    xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION, uno::makeAny(static_cast<sal_Int16>(text::RelOrientation::PAGE_PRINT_AREA)));
    xPropertySet->setPropertyValue(UNO_NAME_CHAR_FONT_NAME, uno::makeAny(sFont));
    xPropertySet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::makeAny(WATERMARK_AUTO_SIZE));
    xPropertySet->setPropertyValue(UNO_NAME_TEXT_UPPERDIST, uno::makeAny(sal_Int32(nFrameHeight - nHeight)));
    xPropertySet->setPropertyValue("Transformation", uno::makeAny(aMatrix));

    uno::Reference<text::XTextRange> xTextRange(xShape, uno::UNO_QUERY);
diff --git a/sw/source/filter/ww8/wrtw8esh.cxx b/sw/source/filter/ww8/wrtw8esh.cxx
index d56baa1..0fdb886 100644
--- a/sw/source/filter/ww8/wrtw8esh.cxx
+++ b/sw/source/filter/ww8/wrtw8esh.cxx
@@ -688,16 +688,6 @@ void PlcDrawObj::WritePlc( WW8Export& rWrt ) const
                if (pObj)
                {
                    aRect = pObj->GetLogicRect();

                    // We have to export Watermark original size with padding
                    if (pObj->GetName().match("PowerPlusWaterMarkObject"))
                    {
                        const SfxItemSet& rSet = pObj->GetMergedItemSet();
                        long nHeight = aRect.GetHeight();
                        if (const SdrMetricItem* pItem = rSet.GetItem(SDRATTR_TEXT_UPPERDIST))
                            nHeight += pItem->GetValue();
                        aRect.SetSize(Size(aRect.GetWidth(), nHeight));
                    }
                }
            }