include/xmloff/txtparae.hxx                |    6 ++
 xmloff/source/text/XMLTextFrameContext.cxx |   57 ++++++++++++++-----
 xmloff/source/text/txtparae.cxx            |   87 ++++++++++++++++++++++++-----
 3 files changed, 120 insertions(+), 30 deletions(-)

New commits:
commit d45631314cef00008a538900800561b435202917
Author: Armin Le Grand <armin.le.gr...@cib.de>
Date:   Wed Jan 10 18:13:41 2018 +0100

    RotateFlyFrameFix: Add RotCenter info to ODF export
    
    Since the WriterFlyFrames are implicitly rotated around
    their center in the Writer UI this has to be added to the
    transformation in ODF expressing this. The saved data
    now contains the shape data in svg:x/y/width/height statements
    (and thus back-compatible AFAP) and a draw:transform statement
    (that is to be applied to the defined shape) containing the
    rotation around the object's center.
    
    Change-Id: Iccfc70924364f1d58995fce180bce9b6e7643ff4
    Reviewed-on: https://gerrit.libreoffice.org/47742
    Tested-by: Jenkins <c...@libreoffice.org>
    Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de>

diff --git a/include/xmloff/txtparae.hxx b/include/xmloff/txtparae.hxx
index c62a25d0b6f3..6e65e1082e03 100644
--- a/include/xmloff/txtparae.hxx
+++ b/include/xmloff/txtparae.hxx
@@ -64,6 +64,11 @@ namespace xmloff
 
 }
 
+namespace basegfx
+{
+    class B2DPoint;
+}
+
 enum class TextPNS
 {
     ODF,
@@ -253,6 +258,7 @@ protected:
     XMLShapeExportFlags addTextFrameAttributes(
         const css::uno::Reference< css::beans::XPropertySet >& rPropSet,
         bool bShape,
+        basegfx::B2DPoint* pCenter = nullptr,
         OUString *pMinHeightValue = nullptr,
         OUString *pMinWidthValue = nullptr );
 
diff --git a/xmloff/source/text/XMLTextFrameContext.cxx 
b/xmloff/source/text/XMLTextFrameContext.cxx
index 7aed805e47dc..14107cf65e65 100644
--- a/xmloff/source/text/XMLTextFrameContext.cxx
+++ b/xmloff/source/text/XMLTextFrameContext.cxx
@@ -982,23 +982,50 @@ XMLTextFrameContext_Impl::XMLTextFrameContext_Impl(
             break;
         case XML_TOK_TEXT_FRAME_TRANSFORM:
             {
-                OUString sValue( rValue );
-                sValue = sValue.trim();
-                const OUString& aRotate(GetXMLToken(XML_ROTATE));
-                const sal_Int32 nRotateLen(aRotate.getLength());
-                sal_Int32 nLen = sValue.getLength();
-                if( nLen >= nRotateLen+3 &&
-                    sValue.startsWith(aRotate) &&
-                    '(' == sValue[nRotateLen] &&
-                    ')' == sValue[nLen-1] )
+                // RotateFlyFrameFix: im/export full 'draw:transform' using 
existing tooling
+                // Currently only rotation is used, but combinations with 
'draw:transform'
+                // may be necessary in the future, so that 
svg:x/svg:y/svg:width/svg:height
+                // may be extended/replaced with 'draw:transform' (see draw 
objects)
+                SdXMLImExTransform2D aSdXMLImExTransform2D;
+                basegfx::B2DHomMatrix aFullTransform;
+
+                // Use SdXMLImExTransform2D to convert to transformation
+                // Note: using GetTwipUnitConverter instead of 
GetMM100UnitConverter may be needed,
+                // but is not generally available (as it should be, a 
'current' UnitConverter should
+                // be available at GetExport() - and maybe was once). May have 
to be addressed as soon
+                // as translate transformations are used here.
+                aSdXMLImExTransform2D.SetString(rValue, 
GetImport().GetMM100UnitConverter());
+                aSdXMLImExTransform2D.GetFullTransform(aFullTransform);
+
+                if(!aFullTransform.isIdentity())
                 {
-                    sValue = sValue.copy( nRotateLen+1, nLen-(nRotateLen+2) );
-                    sValue = sValue.trim();
-                    sal_Int32 nVal;
-                    if (::sax::Converter::convertNumber( nVal, sValue ))
+                    const basegfx::utils::B2DHomMatrixBufferedDecompose 
aDecomposedTransform(aFullTransform);
+
+                    // currently we *only* use rotation (and translation 
indirectly), so warn if *any*
+                    // of the other transform parts is used
+                    SAL_WARN_IF(!basegfx::fTools::equal(1.0, 
aDecomposedTransform.getScale().getX()), "xmloff.text", "draw:transform uses 
scaleX" );
+                    SAL_WARN_IF(!basegfx::fTools::equal(1.0, 
aDecomposedTransform.getScale().getY()), "xmloff.text", "draw:transform uses 
scaleY" );
+                    
SAL_WARN_IF(!basegfx::fTools::equalZero(aDecomposedTransform.getShearX()), 
"xmloff.text", "draw:transform uses shearX" );
+
+                    // Translation comes from the translate to RotCenter, rot 
and BackTranslate.
+                    // This means that it represents the translation between 
unrotated TopLeft
+                    // and rotated TopLeft. This may be checked here now, but 
currently we only
+                    // use rotation around center and assume that this *was* a 
rotation around
+                    // center. The check would compare the object's center 
with the RotCenter
+                    // that can be extracted from the transformation in 
aFullTransform.
+                    // The definition contains implicitely the RotationCenter 
absolute
+                    // to the scaled and translated object, so this may be 
used if needed (see
+                    // _exportTextGraphic how the -trans/rot/trans is composed)
+
+                    
if(!basegfx::fTools::equalZero(aDecomposedTransform.getRotate()))
                     {
-                        // RotGrfFlyFrame: is in 10th degrees
-                        nRotation = (sal_Int16)(nVal % 3600 );
+                        // rotation is used, set it. Convert from deg to 10th 
degree integer
+                        // CAUTION: due to #i78696# (rotation mirrored using 
API) the rotate
+                        // value is already mirrored, so do not do it again 
here (to be in sync
+                        // with XMLTextParagraphExport::_exportTextGraphic 
normally it would need
+                        // to me mirrored using * -1.0, see conversion there)
+                        const double fRotate(aDecomposedTransform.getRotate() 
* (1800.0/M_PI));
+                        nRotation = static_cast< sal_Int16 >(fRotate) % 3600;
                     }
                 }
             }
diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx
index 932505961e75..cb9fdde48625 100644
--- a/xmloff/source/text/txtparae.cxx
+++ b/xmloff/source/text/txtparae.cxx
@@ -2530,8 +2530,9 @@ static bool lcl_txtpara_isBoundAsChar(
 XMLShapeExportFlags XMLTextParagraphExport::addTextFrameAttributes(
     const Reference < XPropertySet >& rPropSet,
     bool bShape,
-    OUString *pMinHeightValue,
-    OUString *pMinWidthValue)
+    basegfx::B2DPoint* pCenter,
+    OUString* pMinHeightValue,
+    OUString* pMinWidthValue)
 {
     XMLShapeExportFlags nShapeFeatures = SEF_DEFAULT;
 
@@ -2593,6 +2594,11 @@ XMLShapeExportFlags 
XMLTextParagraphExport::addTextFrameAttributes(
                     sValue, nPos );
             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_X,
                                       sValue.makeStringAndClear() );
+            if(nullptr != pCenter)
+            {
+                // add left edge to Center
+                pCenter->setX(pCenter->getX() + nPos);
+            }
         }
     }
     else if( TextContentAnchorType_AS_CHARACTER == eAnchor )
@@ -2611,6 +2617,11 @@ XMLShapeExportFlags 
XMLTextParagraphExport::addTextFrameAttributes(
                     sValue, nPos );
             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_Y,
                                       sValue.makeStringAndClear() );
+            if(nullptr != pCenter)
+            {
+                // add top edge to Center
+                pCenter->setY(pCenter->getY() + nPos);
+            }
         }
         if( bShape )
             nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::Y);
@@ -2642,8 +2653,15 @@ XMLShapeExportFlags 
XMLTextParagraphExport::addTextFrameAttributes(
             }
         }
         else
+        {
             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH,
                                       sValue.makeStringAndClear() );
+            if(nullptr != pCenter)
+            {
+                // add half width to Center
+                pCenter->setX(pCenter->getX() + (0.5 * nWidth));
+            }
+        }
     }
     bool bSyncWidth = false;
     if( xPropSetInfo->hasPropertyByName( sIsSyncWidthToHeight ) )
@@ -2694,10 +2712,19 @@ XMLShapeExportFlags 
XMLTextParagraphExport::addTextFrameAttributes(
                                                             nHeight );
         if( SizeType::FIX != nSizeType && 0==nRelHeight && !bSyncHeight &&
              pMinHeightValue )
+        {
             *pMinHeightValue = sValue.makeStringAndClear();
+        }
         else
+        {
             GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT,
                                       sValue.makeStringAndClear() );
+            if(nullptr != pCenter)
+            {
+                // add half height to Center
+                pCenter->setY(pCenter->getY() + (0.5 * nHeight));
+            }
+        }
     }
     if( bSyncHeight )
     {
@@ -2870,7 +2897,7 @@ void XMLTextParagraphExport::_exportTextFrame(
     if( !sAutoStyle.isEmpty() )
         GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME,
                               GetExport().EncodeStyleName( sAutoStyle ) );
-    addTextFrameAttributes(rPropSet, false, &aMinHeightValue, &sMinWidthValue);
+    addTextFrameAttributes(rPropSet, false, nullptr, &aMinHeightValue, 
&sMinWidthValue);
 
     SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
                               XML_FRAME, false, true );
@@ -3030,20 +3057,50 @@ void XMLTextParagraphExport::_exportTextGraphic(
     if( !sAutoStyle.isEmpty() )
         GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME,
                                   GetExport().EncodeStyleName( sAutoStyle ) );
-    addTextFrameAttributes( rPropSet, false );
+
+    // check if we need to use svg:transform
+    sal_Int16 nRotation(0);
+    rPropSet->getPropertyValue( sGraphicRotation ) >>= nRotation;
+    const bool bUseRotation(0 != nRotation);
+    basegfx::B2DPoint aCenter(0.0, 0.0);
+
+    // add TextFrame attributes like svg:x/y/width/height, also get back
+    // object's center point if rotation is used and has to be exported
+    addTextFrameAttributes(rPropSet, false, bUseRotation ? &aCenter : nullptr);
 
     // svg:transform
-    sal_Int16 nVal = 0;
-    rPropSet->getPropertyValue( sGraphicRotation ) >>= nVal;
-    if( nVal != 0 )
-    {
-        OUStringBuffer sRet( GetXMLToken(XML_ROTATE).getLength()+4 );
-        sRet.append( GetXMLToken(XML_ROTATE));
-        sRet.append( '(' );
-        sRet.append( (sal_Int32)nVal );
-        sRet.append( ')' );
-        GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_TRANSFORM,
-                                  sRet.makeStringAndClear() );
+    if(bUseRotation)
+    {
+        // RotateFlyFrameFix: im/export full 'draw:transform' using existing 
tooling.
+        // Currently only rotation is used, but combinations with 
'draw:transform'
+        // may be necessary in the future, so that 
svg:x/svg:y/svg:width/svg:height
+        // may be extended/replaced with 'draw:transform' (see draw objects)
+        SdXMLImExTransform2D aSdXMLImExTransform2D;
+
+        // Convert from 10th degree integer to deg.
+        // CAUTION: Internal rotation is classically mathematically 'wrong' 
defined by ignoring that
+        // we have a right-handed coordinate system, so need to correct this 
by mirroring
+        // the rotation to get the correct transformation. See also case 
XML_TOK_TEXT_FRAME_TRANSFORM
+        // in XMLTextFrameContext_Impl::XMLTextFrameContext_Impl and #i78696#
+        const double fRotate(static_cast< double >(-nRotation) * 
(M_PI/1800.0));
+
+        // transform to rotation center which is the object's center
+        aSdXMLImExTransform2D.AddTranslate(-aCenter);
+
+        // add rotation itself
+        aSdXMLImExTransform2D.AddRotate(fRotate);
+
+        // back-transform after rotation
+        aSdXMLImExTransform2D.AddTranslate(aCenter);
+
+        // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter 
may be needed,
+        // but is not generally available (as it should be, a 'current' 
UnitConverter should
+        // be available at GetExport() - and maybe was once). May have to be 
addressed as soon
+        // as translate transformations are used here.
+        GetExport().AddAttribute(
+            XML_NAMESPACE_DRAW,
+            XML_TRANSFORM,
+            
aSdXMLImExTransform2D.GetExportString(GetExport().GetMM100UnitConverter()));
     }
 
     // original content
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to