summaryrefslogtreecommitdiff
path: root/writerfilter
diff options
context:
space:
mode:
authorRegina Henschel <rb.henschel@t-online.de>2021-05-15 23:40:34 +0200
committerMiklos Vajna <vmiklos@collabora.com>2021-06-28 09:49:00 +0200
commit3262fc5ef3bde5b158909d11ccb008161ea95519 (patch)
treeaa2b4926146eaddaa60878b920da77bd5871f67d /writerfilter
parent2ffdd37067926ddb841c6055205f267b96706945 (diff)
tdf#142304 a.o. Improve wrap margins in docx filters
LO uses the bounding box of the shape in case of type 'Parallel'. Word uses in the corresponding wrap 'square' a box based on the full size of the shape. That will be very different in some cases, e.g. for an arc. And Word exchanges width and height in case of rotation angle in [45°;135°[ and [225°; 315°[. To get the same appearance as in Word, the wrap margins are suitable expanded on import. Word puts the additional space needed for fat strokes into effectExtent in case of wrap 'inline', so there is no need to add the half strokes width in addition. Word determines the area for the shape depending on rotation angle. Both are now considered. Total same appearance is not possible because it would need negative vertical wrap margins, which are currently faulty in LO, see tdf#141880. Patch solves in addition tdf#142486, tdf#142305 The export to Word would require negative values in effectExtent in some cases. They are allowed in OOXML but not supported in Word. My idea is to switch to wrap mode 'Tight' if needed. But export of wrap has so many bad parts, that it needs separate work and is not included here. Handling of border width for export of own frames is missing. Unittest changes ---------------- testDmlTextshapeB and TestDmlTextshape in ooxmlexport6.cxx are set to current values. Import and Export still have large errors with these shapes and correct value from file is unknown. So an exact value is pointless. Only the original problem needs to be still fixed, which is the case. testWpsOnly in ooxmlexport10.cxx. I have removed the test for LeftMargin equals 0. The test makes no sense, because the original file has distL=114300. testTdf124600 in ooxmlimport2.cxx. I have added a tolerance. It would fail with Expected: 2029, Actual:2028, likely a rounding problem somewhere. testTdf124600 in ooxmlimport2.cxx Word refers to outer edge of the border for align='left', LO aligns at snap rectangle. The different intepretations become visible if a thick line is used. LO needs a margin to get the same rendering as in Word. So an expected value of 0 is wrong and I have disabled the test for now. ToDo: tdf#142798. Get the correct margin and activate the test then. testTextframeGradient in ooxmlexport2.cxx. I didn't find any reference for a default value. The test is not reliable, I get both 316 and 318 as actual value. Handling of shadow in VML shapes is buggy, the values for margin and shadow are wrong anyway. Reports are e.g. tdf#142486, tdf#142558. For now I have added a tolerance of 2. testDMLGroupShapeChildPosition in ooxmlexport6.cxx. The accuracy has become better. After reload we get the same values as before. testEffectExtent in ooxmlexport.cxx. tdf#142805. I have disabled the test, because the image is not loaded at all, and therefore it makes no sense to test a margin of it. And you can only test the sum of distL and effectExtent l, because LO has only one property 'LeftMargin' for it. testEffectExtentInline in ooxmlexport.cxx. To get the same vertical alignment as in Word, it would be necessary to have negative margins, but those are not implemented yet. tdf#141880. Currently the patch contains a heuristic to detect unchanged objects and write the grab-Bag values then. testEffectExtentLineWidth in ooxmlexport16.cxx. I have changed the expected value from 508 to 506. That is still away from the to be fixed faulty 561. It is a VML shape and import of connectors in VML shapes is faulty. testRelorientation in ooxmlexport4.cxx. Changed to 8662, the original problem is still fixed. I don't know the reason for the difference to the values from file. Change-Id: I28f156637f6ae64975cf2917f0e5cc89e689aff5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115668 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'writerfilter')
-rw-r--r--writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx60
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docxbin0 -> 20932 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docxbin0 -> 23700 bytes
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docxbin0 -> 74805 bytes
-rw-r--r--writerfilter/source/dmapper/GraphicImport.cxx290
-rw-r--r--writerfilter/source/dmapper/GraphicImport.hxx2
6 files changed, 256 insertions, 96 deletions
diff --git a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
index 40bc31c498ed..6ef6cf1da6e6 100644
--- a/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/GraphicImport.cxx
@@ -18,6 +18,8 @@
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/text/RelOrientation.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/view/XViewCursor.hpp>
#include <com/sun/star/drawing/PointSequenceSequence.hpp>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
@@ -55,6 +57,64 @@ void Test::tearDown()
constexpr OUStringLiteral DATA_DIRECTORY = u"/writerfilter/qa/cppunittests/dmapper/data/";
+CPPUNIT_TEST_FIXTURE(Test, testTdf142305StrokeGlowMargin)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142305StrokeGlowMargin.docx";
+ // The document has an arc with fat stroke and glow. Its bounding rectangle differs much
+ // from the snap rectangle. Error was, that the margins were not set in a way, that the shape
+ // would render similar to Word.
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nTopMargin = 0;
+ xShape->getPropertyValue("TopMargin") >>= nTopMargin;
+ // Without fix in place top margin was 0, so that the text comes near to the shape.
+ // The test would have failed with Expected: 838, Actual: 0
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(838), nTopMargin);
+ sal_Int32 nBottomMargin = 0;
+ // Without fix in place bottom margin was >0, so that the text was far from to the shape.
+ // The test would have failed with Expected: 0, Actual: 637
+ xShape->getPropertyValue("BottomMargin") >>= nBottomMargin;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), nBottomMargin);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf142305SquareWrapMargin)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142305SquareWrapMargin.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<frame::XModel> xModel(getComponent(), uno::UNO_QUERY);
+ uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
+ xModel->getCurrentController(), uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextViewCursor> xViewCursor(xTextViewCursorSupplier->getViewCursor());
+ xViewCursor->gotoStart(/*bExpand=*/false);
+ uno::Reference<view::XViewCursor> xCursor(xViewCursor, uno::UNO_QUERY);
+ xCursor->goDown(/*nCount=*/10, /*bExpand=*/false);
+ xViewCursor->goRight(/*nCount=*/1, /*bExpand=*/true);
+ OUString sText = xViewCursor->getString();
+ // Without fix in place, wrap was tight to the bounding box and not around the full shape as in
+ // Word. That results in different text at start of line, here "u" instead of expected "m".
+ CPPUNIT_ASSERT(sText.startsWith("m"));
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf142304GroupPosition)
+{
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142304GroupPosition.docx";
+ getComponent() = loadFromDesktop(aURL);
+ uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
+ uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
+ uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nVertPosition = 0;
+ xShape->getPropertyValue("VertOrientPosition") >>= nVertPosition;
+ // Without fix in place the group was shifted left and down
+ // The test would have failed with Expected: 2178, Actual: 2521
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2178), nVertPosition);
+ sal_Int32 nHoriPosition = 0;
+ // The test would have failed with Expected: 4304, Actual: 3874
+ xShape->getPropertyValue("HoriOrientPosition") >>= nHoriPosition;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4304), nHoriPosition);
+}
+
CPPUNIT_TEST_FIXTURE(Test, testTdf141540ChildRotation)
{
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf141540ChildRotation.docx";
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docx
new file mode 100644
index 000000000000..681a6e3b7943
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf142304GroupPosition.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docx
new file mode 100644
index 000000000000..9a0fc8a2b5c1
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf142305SquareWrapMargin.docx
Binary files differ
diff --git a/writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docx b/writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docx
new file mode 100644
index 000000000000..3adc2d91b6f1
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/tdf142305StrokeGlowMargin.docx
Binary files differ
diff --git a/writerfilter/source/dmapper/GraphicImport.cxx b/writerfilter/source/dmapper/GraphicImport.cxx
index bb86c1e7a7a1..86a6ebabe3e4 100644
--- a/writerfilter/source/dmapper/GraphicImport.cxx
+++ b/writerfilter/source/dmapper/GraphicImport.cxx
@@ -71,6 +71,7 @@
#include "util.hxx"
#include <comphelper/propertysequence.hxx>
+#include <algorithm> // std::swap
using namespace css;
@@ -510,7 +511,7 @@ void GraphicImport::putPropertyToFrameGrabBag( const OUString& sPropertyName, co
}
}
-static bool lcl_bHasGroupSlantedChild (const SdrObject* pObj)
+static bool lcl_bHasGroupSlantedChild(const SdrObject* pObj)
{
// Returns true, if a child object differs more than 0.02deg from horizontal or vertical.
// Because lines sometimes are imported as customshapes, a horizontal or vertical line
@@ -525,16 +526,56 @@ static bool lcl_bHasGroupSlantedChild (const SdrObject* pObj)
SdrObjListIter aIterator(pSubList, SdrIterMode::DeepNoGroups);
while (aIterator.IsMore())
{
- const SdrObject* pSubObj = aIterator.Next();
- const Degree100 nRotateAngle = NormAngle36000(pSubObj->GetRotateAngle());
- const sal_uInt16 nRot = nRotateAngle.get();
- if ((3 < nRot && nRot < 8997) || (9003 < nRot && nRot < 17997)
- || (18003 < nRot && nRot < 26997) || (27003 < nRot && nRot < 35997))
- return true;
+ const SdrObject* pSubObj = aIterator.Next();
+ const Degree100 nRotateAngle = NormAngle36000(pSubObj->GetRotateAngle());
+ const sal_uInt16 nRot = nRotateAngle.get();
+ if ((3 < nRot && nRot < 8997) || (9003 < nRot && nRot < 17997)
+ || (18003 < nRot && nRot < 26997) || (27003 < nRot && nRot < 35997))
+ return true;
}
return false;
}
+static void lcl_doMSOWidthHeightSwap(awt::Point& rLeftTop, awt::Size& rSize,
+ const sal_Int32 nMSOAngle)
+{
+ if (nMSOAngle == 0)
+ return;
+ // convert nMSOAngle to degree in [0°,180°[
+ sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
+ if (nAngleDeg >= 45 && nAngleDeg < 135)
+ {
+ // keep center of rectangle given in rLeftTop and rSize
+ sal_Int32 aTemp = rSize.Width - rSize.Height;
+ rLeftTop.X += aTemp / 2;
+ rLeftTop.Y -= aTemp / 2;
+ std::swap(rSize.Width, rSize.Height);
+ }
+ return;
+}
+
+void GraphicImport::lcl_expandRectangleByEffectExtent(awt::Point& rLeftTop, awt::Size& rSize)
+{
+ sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
+ : 0;
+ rLeftTop.X -= nEffectExtent;
+ rSize.Width += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentRight)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight)
+ : 0;
+ rSize.Width += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentTop)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop)
+ : 0;
+ rLeftTop.Y -= nEffectExtent;
+ rSize.Height += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom)
+ : 0;
+ rSize.Height += nEffectExtent;
+}
+
void GraphicImport::lcl_attribute(Id nName, Value& rValue)
{
sal_Int32 nIntValue = rValue.getInt();
@@ -846,7 +887,7 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue)
Degree100 nRotation;
if (bKeepRotation)
{
- // Use internal API, getPropertyValue(RotateAngle)
+ // Use internal API, getPropertyValue("RotateAngle")
// would use GetObjectRotation(), which is not what
// we want.
if (pShape)
@@ -856,58 +897,6 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue)
if (bKeepRotation)
{
xShapeProps->setPropertyValue("RotateAngle", uno::makeAny(nRotation.get()));
- if (nRotation == 0_deg100)
- {
- // Include effect extent in the margin to bring Writer layout closer
- // to Word. But do this for non-rotated shapes only, where effect
- // extents map to increased margins as-is.
-
- sal_Int32 nLineWidth{};
- if (xShapeProps->getPropertySetInfo()->hasPropertyByName("LineWidth"))
- {
- xShapeProps->getPropertyValue("LineWidth") >>= nLineWidth;
- }
-
- if (m_pImpl->m_oEffectExtentLeft)
- {
- sal_Int32 nLeft = oox::drawingml::convertEmuToHmm(
- *m_pImpl->m_oEffectExtentLeft);
- if (nLeft >= nLineWidth / 2)
- {
- nLeft -= nLineWidth / 2;
- }
- m_pImpl->nLeftMargin += nLeft;
- }
- if (m_pImpl->m_oEffectExtentTop)
- {
- sal_Int32 nTop = oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop);
- if (nTop >= nLineWidth / 2)
- {
- nTop -= nLineWidth / 2;
- }
- m_pImpl->nTopMargin += nTop;
- }
- if (m_pImpl->m_oEffectExtentRight)
- {
- sal_Int32 nRight = oox::drawingml::convertEmuToHmm(
- *m_pImpl->m_oEffectExtentRight);
- if (nRight >= nLineWidth / 2)
- {
- nRight -= nLineWidth / 2;
- }
- m_pImpl->nRightMargin += nRight;
- }
- if (m_pImpl->m_oEffectExtentBottom)
- {
- sal_Int32 nBottom = oox::drawingml::convertEmuToHmm(
- *m_pImpl->m_oEffectExtentBottom);
- if (nBottom >= nLineWidth / 2)
- {
- nBottom -= nLineWidth / 2;
- }
- m_pImpl->nBottomMargin += nBottom;
- }
- }
}
m_pImpl->bIsGraphic = true;
@@ -924,56 +913,165 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue)
if (m_pImpl->isYSizeValid())
aImportSize.Height = m_pImpl->getYSize(); // Hmm
const awt::Point aImportPosition(GetGraphicObjectPosition()); // Hmm
- const awt::Point aCentrum(aImportPosition.X + aImportSize.Width / 2,
- aImportPosition.Y + aImportSize.Height / 2);
-
- // In case of group and lines, rotations are incorporated in the child shapes or
- // points respectively in LO. MSO has rotation as separate property. The
- // position refers to the unrotated rectangle of MSO. We need to adapt it to
- // the left-top of the rotated shape.
- if (bIsGroupOrLine)
+ double fCentrumX = aImportPosition.X + aImportSize.Width / 2.0;
+ double fCentrumY = aImportPosition.Y + aImportSize.Height / 2.0;
+
+ // In case of group and lines, transformations are incorporated in the child
+ // shapes or points respectively in LO. MSO has rotation as separate property.
+ // The position refers to the unrotated rectangle of MSO. We need to adapt it
+ // to the left-top of the transformed shape.
+ awt::Size aLOSize(m_xShape->getSize()); // LO snap rectangle size in Hmm
+ if (bIsGroupOrLine && !(m_pImpl->mpWrapPolygon))
{
- // Get actual LO snap rectangle size of group or line.
- awt::Size aLOSize(m_xShape->getSize()); //Hmm
-
// Set LO position. MSO rotation is done on shape center.
- m_pImpl->nLeftPosition = aCentrum.X - aLOSize.Width / 2;
- m_pImpl->nTopPosition = aCentrum.Y - aLOSize.Height / 2;
+ if(pShape && pShape->IsGroupObject())
+ {
+ tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twips
+ m_pImpl->nLeftPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
+ m_pImpl->nTopPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
+ aLOSize.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getWidth());
+ aLOSize.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getHeight());
+ }
+ else
+ {
+ m_pImpl->nLeftPosition = fCentrumX - aLOSize.Width / 2.0;
+ m_pImpl->nTopPosition = fCentrumY - aLOSize.Height / 2.0;
+ }
m_xShape->setPosition(GetGraphicObjectPosition());
}
// Margin correction
- // In case of wrap "Square" or "in Line", MSO uses special rules to
- // determine the rectangle into which the shape is placed, depending on
- // rotation angle.
- // If angle is smaller to horizontal than 45deg, the unrotated mso shape
- // rectangle is used, whereby the height is expanded to the bounding
- // rectangle height of the shape.
- // If angle is larger to horizontal than 45deg, the 90deg rotated rectangle
- // is used, whereby the width is expanded to the bounding width of the
- // shape.
- if (bIsGroupOrLine && (m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_INLINE
- || (m_pImpl->nWrap == text::WrapTextMode_PARALLEL && !(m_pImpl->mpWrapPolygon))))
+ if (m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_INLINE)
{
+ if (nOOXAngle == 0)
+ {
+ // EffectExtent contains all needed additional space, including fat
+ // stroke and shadow. Simple add it to the margins.
+ sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
+ : 0;
+ m_pImpl->nLeftMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentRight)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight) : 0;
+ m_pImpl->nRightMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentTop)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop) : 0;
+ m_pImpl->nTopMargin += nEffectExtent;
+ nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
+ ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom) : 0;
+ m_pImpl->nBottomMargin += nEffectExtent;
+ }
+ else
+ {
+ // As of June 2021 LibreOffice uses an area, which is large enough to
+ // contain the rotated snap rectangle. MSO uses a smaller area, so
+ // that the rotated snap rectangle covers text.
+ awt::Point aMSOBaseLeftTop = aImportPosition;
+ awt::Size aMSOBaseSize = aImportSize;
+ lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
+ lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
+
+ // Get LO SnapRect from SdrObject if possible
+ awt::Rectangle aLOSnapRect;
+ // For case we have no SdrObject, initialize with values from m_pImpl
+ aLOSnapRect.X = m_pImpl->nLeftPosition;
+ aLOSnapRect.Y = m_pImpl->nTopPosition;
+ aLOSnapRect.Width = aLOSize.Width;
+ aLOSnapRect.Height = aLOSize.Height;
+ if (pShape)
+ {
+ tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twip
+ aLOSnapRect.X = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
+ aLOSnapRect.Y = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
+ aLOSnapRect.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getWidth());
+ aLOSnapRect.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getHeight());
+ }
- nOOXAngle = (nOOXAngle / 60000) % 180; // convert to degree in [0°,180°[
+ m_pImpl->nLeftMargin += aLOSnapRect.X - aMSOBaseLeftTop.X;
+ m_pImpl->nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
+ - (aLOSnapRect.X + aLOSnapRect.Width);
+ m_pImpl->nTopMargin += aLOSnapRect.Y - aMSOBaseLeftTop.Y;
+ m_pImpl->nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
+ - (aLOSnapRect.Y + aLOSnapRect.Height);
+ // tdf#141880 LibreOffice cannot handle negative vertical margins.
+ // Those cases are catched below at common place.
+ }
+ } // end IMPORT_AS_DETECTED_INLINE
+ else if ((m_pImpl->nWrap == text::WrapTextMode_PARALLEL
+ || m_pImpl->nWrap == text::WrapTextMode_DYNAMIC
+ || m_pImpl->nWrap == text::WrapTextMode_LEFT
+ || m_pImpl->nWrap == text::WrapTextMode_RIGHT
+ || m_pImpl->nWrap == text::WrapTextMode_NONE)
+ && !(m_pImpl->mpWrapPolygon))
+ {
+ // For wrap "Square" an area is defined around which the text wraps. MSO
+ // describes the area by a base rectangle and effectExtent. LO uses the
+ // shape bounding box and margins. We adapt the margins to get the same
+ // area as MSO.
+ awt::Point aMSOBaseLeftTop = aImportPosition;
+ awt::Size aMSOBaseSize = aImportSize;
+ lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
+ lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
+
+ // Get LO bound rectangle from SdrObject if possible
+ awt::Rectangle aLOBoundRect;
+ // For case we have no SdrObject, initialize with values from m_pImpl
+ aLOBoundRect.X = m_pImpl->nLeftPosition;
+ aLOBoundRect.Y = m_pImpl->nTopPosition;
+ aLOBoundRect.Width = aLOSize.Width;
+ aLOBoundRect.Height = aLOSize.Height;
+ if (pShape)
+ {
+ tools::Rectangle aBoundRect = pShape->GetCurrentBoundRect(); // Twip
+ aLOBoundRect.X = ConversionHelper::convertTwipToMM100(aBoundRect.Left());
+ aLOBoundRect.Y = ConversionHelper::convertTwipToMM100(aBoundRect.Top());
+ aLOBoundRect.Width = ConversionHelper::convertTwipToMM100(aBoundRect.getWidth());
+ aLOBoundRect.Height = ConversionHelper::convertTwipToMM100(aBoundRect.getHeight());
+ }
- if (nOOXAngle >= 45 && nOOXAngle < 135)
+ m_pImpl->nLeftMargin += aLOBoundRect.X - aMSOBaseLeftTop.X;
+ m_pImpl->nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
+ - (aLOBoundRect.X + aLOBoundRect.Width);
+ m_pImpl->nTopMargin += aLOBoundRect.Y - aMSOBaseLeftTop.Y;
+ m_pImpl->nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
+ - (aLOBoundRect.Y + aLOBoundRect.Height);
+ }
+ else // WrapTextMode_THROUGH(T) or mpWrapPolygon exists
+ {
+ // Word uses a wrap polygon in case of wrapTight or wrapThrough, which the
+ // user can manipulate. Word writes values to effectExtent which would
+ // be uses in case of wrapSquare, but ignores them for wrapTight or
+ // wrapThrough. But they contain the information about the needed extent
+ // for effects, rotation and fat stroke. So use them in that cases too
+ // although LibreOffice has its own methods for contour.
+ if (m_pImpl->m_oEffectExtentLeft)
{
- const sal_Int32 nImportRot90Top(aCentrum.Y - aImportSize.Width / 2);
- sal_Int32 nVertMarginOffset(m_pImpl->nTopPosition - nImportRot90Top);
- nVertMarginOffset = std::max<sal_Int32>(nVertMarginOffset, 0);
- m_pImpl->nTopMargin += nVertMarginOffset;
- m_pImpl->nBottomMargin += nVertMarginOffset;
+ m_pImpl->nLeftMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft);
}
- else
+ if (m_pImpl->m_oEffectExtentTop)
+ {
+ m_pImpl->nTopMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop);
+ }
+ if (m_pImpl->m_oEffectExtentRight)
{
- sal_Int32 nHoriMarginOffset(m_pImpl->nLeftPosition - aImportPosition.X);
- nHoriMarginOffset = std::max<sal_Int32>(nHoriMarginOffset, 0);
- m_pImpl->nLeftMargin += nHoriMarginOffset;
- m_pImpl->nRightMargin += nHoriMarginOffset;
+ m_pImpl->nRightMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight);
+ }
+ if (m_pImpl->m_oEffectExtentBottom)
+ {
+ m_pImpl->nBottomMargin
+ += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom);
}
}
+
+ // FixMe: tdf#141880 LibreOffice cannot handle negative vertical margins
+ // although they are allowed in ODF.
+ if (m_pImpl->nTopMargin < 0)
+ m_pImpl->nTopMargin = 0;
+ if (m_pImpl->nBottomMargin < 0)
+ m_pImpl->nBottomMargin = 0;
}
if (bUseShape && m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
diff --git a/writerfilter/source/dmapper/GraphicImport.hxx b/writerfilter/source/dmapper/GraphicImport.hxx
index d1030b983d82..bea911eef8bb 100644
--- a/writerfilter/source/dmapper/GraphicImport.hxx
+++ b/writerfilter/source/dmapper/GraphicImport.hxx
@@ -23,6 +23,7 @@
#include "LoggedResources.hxx"
+#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
@@ -124,6 +125,7 @@ public:
virtual void lcl_endShape() override;
void handleWrapTextValue(sal_uInt32 nVal);
+ void lcl_expandRectangleByEffectExtent(css::awt::Point& rLeftTop, css::awt::Size& rSize);
};
typedef tools::SvRef<GraphicImport> GraphicImportPtr;