diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2021-07-05 22:21:23 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2021-07-14 11:34:43 +0200 |
commit | af99c01570adc0c9205e1650d10866f80bb8118a (patch) | |
tree | 97d146fc8e1904efccd00552d427554bcdd8dd03 /writerfilter | |
parent | 3f618170b8474b4a4e97aa7685daf064d0413a57 (diff) |
tdf#143219 improve docx import/export of contour wrap
The current solution has some problems:
(1)
Currently effectExtent is used on import to increase the wrap margins
for fat stroke and effects like shadow and glow in case of contour
wrap.
Problems:
Word writes these values, but actually the wrap polygon is authorative
and third party applications might not write these values at all.
The wrap margins were increased on import, but not decreased on export.
The effectExtent values by Word contain in addition the amount for
rotation as needed in wrapSquare. That part was not removed.
(2)
To avoid negative values in dist* values they were compensated with
effectExtent. For that, the complete effectExtent was shifted to dist*
and effectExtent was set to zero.
Problems:
Contour wrap does not use effectExtent but a wrap polygon. This is set
by Word in a way, that it includes the effect extents. LO uses the
original wrap polygon if available. So moving the effectExtent values
to dist* gives too large 'distance to text' in case of contour wrap,
because effects were considered twice.
The solution here replaces the way, how the margins are calculated in
case of contour wrap. Now the range used by the wrap polygon is
compared with the range used by the shape geometry. The difference is
added to 'distance to text'. To be able to remove these values on
export, they are put into the InteropGrabBag.
LO and Word use different concepts for contour wrap. Any solution gives
only an approximation. But adapting 'distance to text' brings
rendering in LO nearer to the way Word renders contour wrap.
Change-Id: Ic3c1c075fedfa7f79e4fe1f3c095da12cf274e36
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/118538
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'writerfilter')
-rw-r--r-- | writerfilter/source/dmapper/GraphicImport.cxx | 112 |
1 files changed, 99 insertions, 13 deletions
diff --git a/writerfilter/source/dmapper/GraphicImport.cxx b/writerfilter/source/dmapper/GraphicImport.cxx index 0b0176516745..69bbc94f1225 100644 --- a/writerfilter/source/dmapper/GraphicImport.cxx +++ b/writerfilter/source/dmapper/GraphicImport.cxx @@ -71,7 +71,13 @@ #include "util.hxx" #include <comphelper/propertysequence.hxx> -#include <algorithm> // std::swap +#include <algorithm> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> using namespace css; @@ -939,6 +945,9 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue) } m_xShape->setPosition(GetGraphicObjectPosition()); } + // ToDo: Rotated shapes with position type "Alignment" (UI of Word) have + // wrong position. Word aligns the unrotated logic rectangle, LO the rotated + // snap rectangle. // Margin correction if (m_pImpl->eGraphicImportType == IMPORT_AS_DETECTED_INLINE) @@ -949,14 +958,14 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue) // 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; + : 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; + m_pImpl->nTopMargin += nEffectExtent; nEffectExtent = (m_pImpl->m_oEffectExtentBottom) ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom) : 0; m_pImpl->nBottomMargin += nEffectExtent; @@ -1029,21 +1038,98 @@ void GraphicImport::lcl_attribute(Id nName, Value& rValue) aLOBoundRect.Height = ConversionHelper::convertTwipToMM100(aBoundRect.getHeight()); } - m_pImpl->nLeftMargin += aLOBoundRect.X - aMSOBaseLeftTop.X; + 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->nTopMargin += aLOBoundRect.Y - aMSOBaseLeftTop.Y; m_pImpl->nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height - (aLOBoundRect.Y + aLOBoundRect.Height); } - else // WrapTextMode_THROUGH(T) or mpWrapPolygon exists + else if (m_pImpl->mpWrapPolygon) // with contour { - // 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. + // Word uses a wrap polygon, LibreOffice has no explicit wrap polygon + // but creates the wrap contour based on the shape geometry, without + // stroke width and shadow, but with rotation and flip. The concepts + // are not compatible. We approximate Word's rendering by setting + // wrap margins. + + // Build a range from the wrap polygon from Word. + const drawing::PointSequenceSequence aWrapPolygon + = m_pImpl->mpWrapPolygon->getPointSequenceSequence(); + basegfx::B2DPolyPolygon aB2DWrapPolyPolygon + = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon( + aWrapPolygon); + // Wrap polygon values are relative to 0..21600|0..21600. + // Scale to shape size (in Hmm). + basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleB2DHomMatrix( + aImportSize.Width / 21600.0, aImportSize.Height / 21600.0); + aB2DWrapPolyPolygon.transform(aMatrix); + + // Shape geometry will be rotated, rotate wrap polygon too. + if (nOOXAngle != 0) + { + aMatrix = basegfx::utils::createRotateAroundPoint( + aImportSize.Width / 2.0, aImportSize.Height / 2.0, + basegfx::deg2rad( nOOXAngle / 60000.0)); + aB2DWrapPolyPolygon.transform(aMatrix); + } + basegfx::B2DRange aB2DWrapRange = aB2DWrapPolyPolygon.getB2DRange(); + + // Build a range from shape geometry + basegfx::B2DRange aShapeRange; + if (pShape) + { + basegfx::B2DPolyPolygon aShapePolygon = pShape->TakeXorPoly(); // Twips + constexpr double fTwips2Hmm = 127.0 / 72.0; + aMatrix = basegfx::utils::createScaleB2DHomMatrix(fTwips2Hmm, fTwips2Hmm); + aShapePolygon.transform(aMatrix); + // Wrap polygon treats left/top of shape as origin, shift shape polygon accordingly + aMatrix = basegfx::utils::createTranslateB2DHomMatrix( + -aImportPosition.X, -aImportPosition.Y); + aShapePolygon.transform(aMatrix); + aShapeRange = aShapePolygon.getB2DRange(); + } + else // can this happen? + { + aShapeRange + = basegfx::B2DRange(0, 0, aImportSize.Width, aImportSize.Height); + if (nOOXAngle != 0) + { + aMatrix = basegfx::utils::createRotateB2DHomMatrix( + basegfx::deg2rad(nOOXAngle / 60000.0)); + aShapeRange.transform(aMatrix); + } + } + + // Add difference between shape and wrap range to margin and remember + // difference in Twips for export. + comphelper::SequenceAsHashMap aAnchorDistDiff; + constexpr double fHmm2Twips = 72.0 / 127.0; + const double fTopDiff = aShapeRange.getMinY() - aB2DWrapRange.getMinY(); + m_pImpl->nTopMargin += basegfx::fround(fTopDiff); + aAnchorDistDiff["distTDiff"] <<= basegfx::fround(fTopDiff * fHmm2Twips); + const double fBottomDiff = aB2DWrapRange.getMaxY() - aShapeRange.getMaxY(); + m_pImpl->nBottomMargin += basegfx::fround(fBottomDiff); + aAnchorDistDiff["distBDiff"] <<= basegfx::fround(fBottomDiff * fHmm2Twips); + const double fLeftDiff = aShapeRange.getMinX() - aB2DWrapRange.getMinX(); + m_pImpl->nLeftMargin += basegfx::fround(fLeftDiff); + aAnchorDistDiff["distLDiff"] <<= basegfx::fround(fLeftDiff * fHmm2Twips); + const double fRightDiff = aB2DWrapRange.getMaxX() - aShapeRange.getMaxX(); + m_pImpl->nRightMargin += basegfx::fround(fRightDiff); + aAnchorDistDiff["distRDiff"] <<= basegfx::fround(fRightDiff * fHmm2Twips); + m_pImpl->m_aInteropGrabBag["AnchorDistDiff"] <<= aAnchorDistDiff.getAsConstPropertyValueList(); + + // FixMe: tdf#141880. LibreOffice cannot handle negative horizontal margin in contour wrap + if (m_pImpl->nLeftMargin < 0) + m_pImpl->nLeftMargin = 0; + if (m_pImpl->nRightMargin < 0) + m_pImpl->nRightMargin = 0; + } + else // text::WrapTextMode_THROUGH + { + // Word writes and evaluates the effectExtent in case of position + // type 'Alignment' (UI). We move these values to margin to approximate + // Word's rendering. if (m_pImpl->m_oEffectExtentLeft) { m_pImpl->nLeftMargin |