android: Update app-specific/MIME type icons
[LibreOffice.git] / writerfilter / source / dmapper / GraphicImport.cxx
blobc6dd379e94815630a1e407ec1e1c4c0a5bdfc0f9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <string.h>
22 #include <com/sun/star/awt/Size.hpp>
23 #include <com/sun/star/container/XNamed.hpp>
24 #include <com/sun/star/drawing/ColorMode.hpp>
25 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
26 #include <com/sun/star/drawing/XShape.hpp>
27 #include <com/sun/star/drawing/LineStyle.hpp>
28 #include <com/sun/star/graphic/XGraphic.hpp>
29 #include <com/sun/star/graphic/GraphicProvider.hpp>
30 #include <com/sun/star/graphic/XGraphicProvider.hpp>
31 #include <com/sun/star/io/BufferSizeExceededException.hpp>
32 #include <com/sun/star/io/XInputStream.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <com/sun/star/lang/XServiceInfo.hpp>
35 #include <com/sun/star/table/BorderLine2.hpp>
36 #include <com/sun/star/text/GraphicCrop.hpp>
37 #include <com/sun/star/text/HoriOrientation.hpp>
38 #include <com/sun/star/text/RelOrientation.hpp>
39 #include <com/sun/star/text/TextContentAnchorType.hpp>
40 #include <com/sun/star/text/VertOrientation.hpp>
41 #include <com/sun/star/text/WrapTextMode.hpp>
42 #include <com/sun/star/text/XTextContent.hpp>
43 #include <com/sun/star/uno/XComponentContext.hpp>
44 #include <com/sun/star/table/ShadowFormat.hpp>
46 #include <svx/svditer.hxx>
47 #include <svx/svdobj.hxx>
48 #include <svx/svdogrp.hxx>
49 #include <svx/svdtrans.hxx>
50 #include <svx/unoapi.hxx>
51 #include <cppuhelper/implbase.hxx>
52 #include <rtl/ustrbuf.hxx>
53 #include <sal/log.hxx>
54 #include <rtl/math.hxx>
55 #include <comphelper/diagnose_ex.hxx>
56 #include <comphelper/propertyvalue.hxx>
57 #include <comphelper/string.hxx>
58 #include <comphelper/sequenceashashmap.hxx>
59 #include <comphelper/sequence.hxx>
61 #include <oox/drawingml/drawingmltypes.hxx>
63 #include "DomainMapper.hxx"
64 #include <dmapper/GraphicZOrderHelper.hxx>
65 #include <ooxml/resourceids.hxx>
67 #include "ConversionHelper.hxx"
68 #include "GraphicHelpers.hxx"
69 #include "GraphicImport.hxx"
70 #include "PropertyMap.hxx"
71 #include "TagLogger.hxx"
72 #include "WrapPolygonHandler.hxx"
73 #include "util.hxx"
75 #include <comphelper/propertysequence.hxx>
76 #include <algorithm>
77 #include <basegfx/matrix/b2dhommatrixtools.hxx>
78 #include <basegfx/matrix/b2dhommatrix.hxx>
79 #include <basegfx/range/b2drange.hxx>
80 #include <basegfx/numeric/ftools.hxx>
81 #include <basegfx/polygon/b2dpolypolygontools.hxx>
82 #include <basegfx/polygon/b2dpolypolygon.hxx>
83 #include <o3tl/unit_conversion.hxx>
84 #include <oox/export/drawingml.hxx>
85 #include <utility>
87 using namespace css;
89 namespace
91 bool isTopGroupObj(const uno::Reference<drawing::XShape>& xShape)
93 SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShape);
94 if (!pObject)
95 return false;
97 if (pObject->getParentSdrObjectFromSdrObject())
98 return false;
100 return pObject->IsGroupObject();
104 namespace writerfilter::dmapper
107 namespace {
109 class XInputStreamHelper : public cppu::WeakImplHelper<io::XInputStream>
111 const sal_uInt8* m_pBuffer;
112 const sal_Int32 m_nLength;
113 sal_Int32 m_nPosition;
114 public:
115 XInputStreamHelper(const sal_uInt8* buf, size_t len);
117 virtual ::sal_Int32 SAL_CALL readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) override;
118 virtual ::sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) override;
119 virtual void SAL_CALL skipBytes( ::sal_Int32 nBytesToSkip ) override;
120 virtual ::sal_Int32 SAL_CALL available( ) override;
121 virtual void SAL_CALL closeInput( ) override;
126 XInputStreamHelper::XInputStreamHelper(const sal_uInt8* buf, size_t len) :
127 m_pBuffer( buf ),
128 m_nLength( len ),
129 m_nPosition( 0 )
133 sal_Int32 XInputStreamHelper::readBytes( uno::Sequence<sal_Int8>& aData, sal_Int32 nBytesToRead )
135 return readSomeBytes( aData, nBytesToRead );
138 sal_Int32 XInputStreamHelper::readSomeBytes( uno::Sequence<sal_Int8>& aData, sal_Int32 nMaxBytesToRead )
140 sal_Int32 nRet = 0;
141 if( nMaxBytesToRead > 0 )
143 if( nMaxBytesToRead > m_nLength - m_nPosition )
144 nRet = m_nLength - m_nPosition;
145 else
146 nRet = nMaxBytesToRead;
147 aData.realloc( nRet );
148 sal_Int8* pData = aData.getArray();
149 if( nRet )
151 memcpy( pData, m_pBuffer + m_nPosition, nRet );
152 m_nPosition += nRet;
155 return nRet;
159 void XInputStreamHelper::skipBytes( sal_Int32 nBytesToSkip )
161 if( nBytesToSkip < 0 || m_nPosition + nBytesToSkip > m_nLength)
162 throw io::BufferSizeExceededException();
163 m_nPosition += nBytesToSkip;
167 sal_Int32 XInputStreamHelper::available( )
169 return m_nLength - m_nPosition;
173 void XInputStreamHelper::closeInput( )
177 namespace {
179 struct GraphicBorderLine
181 sal_Int32 nLineWidth;
182 bool bHasShadow;
184 GraphicBorderLine() :
185 nLineWidth(0)
186 ,bHasShadow(false)
189 bool isEmpty() const
191 return nLineWidth == 0 && !bHasShadow;
198 class GraphicImport_Impl
200 private:
201 sal_Int32 m_nXSize;
202 bool m_bXSizeValid;
203 sal_Int32 m_nYSize;
204 bool m_bYSizeValid;
206 public:
207 GraphicImportType & m_rGraphicImportType;
208 DomainMapper& m_rDomainMapper;
210 sal_Int32 m_nLeftPosition;
211 sal_Int32 m_nTopPosition;
213 bool m_bUseSimplePos;
214 sal_Int32 m_zOrder;
216 sal_Int16 m_nHoriOrient;
217 sal_Int16 m_nHoriRelation;
218 bool m_bPageToggle = false;
219 sal_Int16 m_nVertOrient;
220 sal_Int16 m_nVertRelation;
221 text::WrapTextMode m_nWrap;
222 bool m_bLayoutInCell;
223 bool m_bCompatForcedLayoutInCell;
224 bool m_bAllowOverlap = true;
225 bool m_bOpaque;
226 bool m_bBehindDoc;
227 bool m_bContour;
228 bool m_bContourOutside;
229 WrapPolygon::Pointer_t mpWrapPolygon;
231 sal_Int32 m_nLeftMargin;
232 sal_Int32 m_nLeftMarginOrig = 0;
233 sal_Int32 m_nRightMargin;
234 sal_Int32 m_nTopMargin;
235 sal_Int32 m_nBottomMargin;
237 bool m_bShadow;
238 sal_Int32 m_nShadowXDistance;
239 sal_Int32 m_nShadowYDistance;
240 sal_Int32 m_nShadowColor;
241 sal_Int32 m_nShadowTransparence;
243 sal_Int32 m_nContrast;
244 sal_Int32 m_nBrightness;
246 static constexpr sal_Int32 nFillColor = 0xffffffff;
248 drawing::ColorMode m_eColorMode;
250 GraphicBorderLine m_aBorders[4];
252 bool m_bIsGraphic;
254 bool m_bSizeProtected;
255 bool m_bPositionProtected;
256 bool m_bHidden;
257 bool m_bDecorative = false;
259 sal_Int32 m_nShapeOptionType;
261 OUString m_sName;
262 OUString m_sAlternativeText;
263 OUString m_title;
264 OUString m_sHyperlinkURL;
265 std::pair<OUString, OUString>& m_rPositionOffsets;
266 std::pair<OUString, OUString>& m_rAligns;
267 std::queue<OUString>& m_rPositivePercentages;
268 OUString m_sAnchorId;
269 comphelper::SequenceAsHashMap m_aInteropGrabBag;
270 std::optional<sal_Int32> m_oEffectExtentLeft;
271 std::optional<sal_Int32> m_oEffectExtentTop;
272 std::optional<sal_Int32> m_oEffectExtentRight;
273 std::optional<sal_Int32> m_oEffectExtentBottom;
275 GraphicImport_Impl(GraphicImportType & rImportType, DomainMapper& rDMapper,
276 std::pair<OUString, OUString>& rPositionOffsets,
277 std::pair<OUString, OUString>& rAligns,
278 std::queue<OUString>& rPositivePercentages)
279 : m_nXSize(0)
280 ,m_bXSizeValid(false)
281 ,m_nYSize(0)
282 ,m_bYSizeValid(false)
283 ,m_rGraphicImportType(rImportType)
284 ,m_rDomainMapper( rDMapper )
285 ,m_nLeftPosition(0)
286 ,m_nTopPosition(0)
287 ,m_bUseSimplePos(false)
288 ,m_zOrder(-1)
289 ,m_nHoriOrient( text::HoriOrientation::NONE )
290 ,m_nHoriRelation( text::RelOrientation::FRAME )
291 ,m_nVertOrient( text::VertOrientation::NONE )
292 ,m_nVertRelation( text::RelOrientation::FRAME )
293 ,m_nWrap(text::WrapTextMode_NONE)
294 ,m_bLayoutInCell(true)
295 ,m_bCompatForcedLayoutInCell(false)
296 ,m_bOpaque( !rDMapper.IsInHeaderFooter() )
297 ,m_bBehindDoc(false)
298 ,m_bContour(false)
299 ,m_bContourOutside(true)
300 ,m_nLeftMargin(319)
301 ,m_nRightMargin(319)
302 ,m_nTopMargin(0)
303 ,m_nBottomMargin(0)
304 ,m_bShadow(false)
305 ,m_nShadowXDistance(0)
306 ,m_nShadowYDistance(0)
307 ,m_nShadowColor(0)
308 ,m_nShadowTransparence(0)
309 ,m_nContrast(0)
310 ,m_nBrightness(0)
311 ,m_eColorMode( drawing::ColorMode_STANDARD )
312 ,m_bIsGraphic(false)
313 ,m_bSizeProtected(false)
314 ,m_bPositionProtected(false)
315 ,m_bHidden(false)
316 ,m_nShapeOptionType(0)
317 ,m_rPositionOffsets(rPositionOffsets)
318 ,m_rAligns(rAligns)
319 ,m_rPositivePercentages(rPositivePercentages)
323 void setXSize(sal_Int32 _nXSize)
325 m_nXSize = _nXSize;
326 m_bXSizeValid = true;
329 sal_uInt32 getXSize() const
331 return m_nXSize;
334 bool isXSizeValid() const
336 return m_bXSizeValid;
339 void setYSize(sal_Int32 _nYSize)
341 m_nYSize = _nYSize;
342 m_bYSizeValid = true;
345 sal_uInt32 getYSize() const
347 return m_nYSize;
350 bool isYSizeValid() const
352 return m_bYSizeValid;
355 void applyMargins(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const
357 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_LEFT_MARGIN ), uno::Any(m_nLeftMargin));
358 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_RIGHT_MARGIN ), uno::Any(m_nRightMargin));
359 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TOP_MARGIN ), uno::Any(m_nTopMargin));
360 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BOTTOM_MARGIN ), uno::Any(m_nBottomMargin));
363 void applyPosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties) const
365 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT ),
366 uno::Any(m_nHoriOrient));
367 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT ),
368 uno::Any(m_nVertOrient));
371 void applyRelativePosition(const uno::Reference< beans::XPropertySet >& xGraphicObjectProperties, bool bRelativeOnly = false) const
373 if (!bRelativeOnly)
374 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_POSITION),
375 uno::Any(m_nLeftPosition));
376 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_HORI_ORIENT_RELATION ),
377 uno::Any(m_nHoriRelation));
378 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_PAGE_TOGGLE),
379 uno::Any(m_bPageToggle));
380 if (!bRelativeOnly)
381 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_POSITION),
382 uno::Any(m_nTopPosition));
383 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_VERT_ORIENT_RELATION ),
384 uno::Any(m_nVertRelation));
387 void applyZOrder(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const
389 sal_Int32 nZOrder = m_zOrder;
390 if (m_rGraphicImportType == GraphicImportType::IMPORT_AS_DETECTED_INLINE
391 && !m_rDomainMapper.IsInShape())
393 nZOrder = 0;
395 if (nZOrder >= 0)
397 // tdf#120760 Send objects with behinddoc=true to the back.
398 if (m_bBehindDoc && m_rDomainMapper.IsInHeaderFooter())
399 nZOrder -= SAL_MAX_INT32;
400 GraphicZOrderHelper* pZOrderHelper = m_rDomainMapper.graphicZOrderHelper();
401 bool const bOldStyle(m_rGraphicImportType == GraphicImportType::IMPORT_AS_DETECTED_INLINE);
402 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_Z_ORDER),
403 uno::Any(pZOrderHelper->findZOrder(nZOrder, bOldStyle)));
404 pZOrderHelper->addItem(xGraphicObjectProperties, nZOrder);
408 void applyName(uno::Reference<beans::XPropertySet> const & xGraphicObjectProperties) const
412 if (!m_sName.isEmpty())
414 uno::Reference<container::XNamed> const xNamed(xGraphicObjectProperties, uno::UNO_QUERY_THROW);
415 xNamed->setName(m_sName);
417 // else: name is automatically generated by SwDoc::MakeFlySection_()
419 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_DESCRIPTION ),
420 uno::Any( m_sAlternativeText ));
421 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_TITLE ),
422 uno::Any( m_title ));
424 catch( const uno::Exception& )
426 TOOLS_WARN_EXCEPTION("writerfilter", "failed");
430 void applyHyperlink(uno::Reference<beans::XPropertySet> const & xShapeProps, bool bIsShape)
432 // Graphic objects have a different hyperlink prop than shapes
433 auto aHyperlinkProp = bIsShape ? PROP_HYPERLINK : PROP_HYPER_LINK_U_R_L;
434 if (!m_sHyperlinkURL.isEmpty())
436 xShapeProps->setPropertyValue(
437 getPropertyName(aHyperlinkProp), uno::Any(m_sHyperlinkURL));
441 /// Getter for m_aInteropGrabBag, but also merges in the values from other members if they are set.
442 comphelper::SequenceAsHashMap const & getInteropGrabBag()
444 comphelper::SequenceAsHashMap aEffectExtent;
445 if (m_oEffectExtentLeft)
446 aEffectExtent["l"] <<= *m_oEffectExtentLeft;
447 if (m_oEffectExtentTop)
448 aEffectExtent["t"] <<= *m_oEffectExtentTop;
449 if (m_oEffectExtentRight)
450 aEffectExtent["r"] <<= *m_oEffectExtentRight;
451 if (m_oEffectExtentBottom)
452 aEffectExtent["b"] <<= *m_oEffectExtentBottom;
453 if (!aEffectExtent.empty())
454 m_aInteropGrabBag["CT_EffectExtent"] <<= aEffectExtent.getAsConstPropertyValueList();
455 return m_aInteropGrabBag;
459 GraphicImport::GraphicImport(uno::Reference<uno::XComponentContext> xComponentContext,
460 uno::Reference<lang::XMultiServiceFactory> xTextFactory,
461 DomainMapper& rDMapper,
462 GraphicImportType & rImportType,
463 std::pair<OUString, OUString>& rPositionOffsets,
464 std::pair<OUString, OUString>& rAligns,
465 std::queue<OUString>& rPositivePercentages)
466 : LoggedProperties("GraphicImport")
467 , LoggedTable("GraphicImport")
468 , LoggedStream("GraphicImport")
469 , m_pImpl(new GraphicImport_Impl(rImportType, rDMapper, rPositionOffsets, rAligns, rPositivePercentages))
470 , m_xComponentContext(std::move(xComponentContext))
471 , m_xTextFactory(std::move(xTextFactory))
475 GraphicImport::~GraphicImport()
479 com::sun::star::awt::Point GraphicImport::GetGraphicObjectPosition() const
481 return (com::sun::star::awt::Point(m_pImpl->m_nLeftPosition, m_pImpl->m_nTopPosition));
484 bool GraphicImport::GetLayoutInCell() const
486 return m_pImpl->m_bLayoutInCell;
489 void GraphicImport::handleWrapTextValue(sal_uInt32 nVal)
491 switch (nVal)
493 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_bothSides: // 90920;
494 m_pImpl->m_nWrap = text::WrapTextMode_PARALLEL;
495 break;
496 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_left: // 90921;
497 m_pImpl->m_nWrap = text::WrapTextMode_LEFT;
498 break;
499 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_right: // 90922;
500 m_pImpl->m_nWrap = text::WrapTextMode_RIGHT;
501 break;
502 case NS_ooxml::LN_Value_wordprocessingDrawing_ST_WrapText_largest: // 90923;
503 m_pImpl->m_nWrap = text::WrapTextMode_DYNAMIC;
504 break;
505 default:;
509 void GraphicImport::putPropertyToFrameGrabBag( const OUString& sPropertyName, const uno::Any& aPropertyValue )
511 beans::PropertyValue aProperty;
512 aProperty.Name = sPropertyName;
513 aProperty.Value = aPropertyValue;
515 if (!m_xShape.is())
516 return;
518 uno::Reference< beans::XPropertySet > xSet(m_xShape, uno::UNO_QUERY_THROW);
520 uno::Reference< beans::XPropertySetInfo > xSetInfo(xSet->getPropertySetInfo());
521 if (!xSetInfo.is())
522 return;
524 OUString aGrabBagPropName;
525 uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
526 if (xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
527 aGrabBagPropName = "FrameInteropGrabBag";
528 else
529 aGrabBagPropName = "InteropGrabBag";
531 if (xSetInfo->hasPropertyByName(aGrabBagPropName))
533 //Add pProperty to the end of the Sequence for aGrabBagPropName
534 uno::Sequence<beans::PropertyValue> aTmp;
535 xSet->getPropertyValue(aGrabBagPropName) >>= aTmp;
536 std::vector<beans::PropertyValue> aGrabBag(comphelper::sequenceToContainer<std::vector<beans::PropertyValue> >(aTmp));
537 aGrabBag.push_back(aProperty);
539 xSet->setPropertyValue(aGrabBagPropName, uno::Any(comphelper::containerToSequence(aGrabBag)));
543 static bool lcl_bHasGroupSlantedChild(const SdrObject* pObj)
545 // Returns true, if a child object differs more than 0.02deg from horizontal or vertical.
546 // Because lines sometimes are imported as customshapes, a horizontal or vertical line
547 // might not have exactly 0, 90, 180, or 270 degree as rotate angle.
548 if (!pObj)
549 return false;
550 if (!pObj->IsGroupObject())
551 return false;
552 SdrObjList* pSubList = pObj->GetSubList();
553 if (!pSubList)
554 return false;
555 SdrObjListIter aIterator(pSubList, SdrIterMode::DeepNoGroups);
556 while (aIterator.IsMore())
558 const SdrObject* pSubObj = aIterator.Next();
559 const Degree100 nRotateAngle = NormAngle36000(pSubObj->GetRotateAngle());
560 const sal_uInt16 nRot = nRotateAngle.get();
561 if ((3 < nRot && nRot < 8997) || (9003 < nRot && nRot < 17997)
562 || (18003 < nRot && nRot < 26997) || (27003 < nRot && nRot < 35997))
563 return true;
565 return false;
568 void GraphicImport::lcl_correctWord2007EffectExtent(const sal_Int32 nMSOAngle)
570 // Word versions older than 14 do not swap width and height (see lcl_doMSOWidthHeightSwap)
571 // and therefore generate different effectExtent. We correct them here.
572 sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
573 if (nAngleDeg < 45 || nAngleDeg >= 135)
574 return;
576 sal_Int32 nDiff = o3tl::convert(
577 (double(m_pImpl->getXSize()) - double(m_pImpl->getYSize())) / 2.0,
578 o3tl::Length::mm100, o3tl::Length::emu);
579 if (m_pImpl->m_oEffectExtentLeft)
580 *m_pImpl->m_oEffectExtentLeft += nDiff;
581 if (m_pImpl->m_oEffectExtentRight)
582 *m_pImpl->m_oEffectExtentRight += nDiff;
583 if (m_pImpl->m_oEffectExtentTop)
584 *m_pImpl->m_oEffectExtentTop -= nDiff;
585 if (m_pImpl->m_oEffectExtentBottom)
586 *m_pImpl->m_oEffectExtentBottom -= nDiff;
589 static void lcl_doMSOWidthHeightSwap(awt::Point& rLeftTop, awt::Size& rSize,
590 const sal_Int32 nMSOAngle)
592 if (nMSOAngle == 0)
593 return;
594 // convert nMSOAngle to degree in [0°,180°[
595 sal_Int16 nAngleDeg = (nMSOAngle / 60000) % 180;
596 if (nAngleDeg >= 45 && nAngleDeg < 135)
598 // keep center of rectangle given in rLeftTop and rSize
599 sal_Int32 aTemp = rSize.Width - rSize.Height;
600 rLeftTop.X += aTemp / 2;
601 rLeftTop.Y -= aTemp / 2;
602 std::swap(rSize.Width, rSize.Height);
604 return;
607 void GraphicImport::lcl_expandRectangleByEffectExtent(awt::Point& rLeftTop, awt::Size& rSize)
609 sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
610 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
611 : 0;
612 rLeftTop.X -= nEffectExtent;
613 rSize.Width += nEffectExtent;
614 nEffectExtent = (m_pImpl->m_oEffectExtentRight)
615 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight)
616 : 0;
617 rSize.Width += nEffectExtent;
618 nEffectExtent = (m_pImpl->m_oEffectExtentTop)
619 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop)
620 : 0;
621 rLeftTop.Y -= nEffectExtent;
622 rSize.Height += nEffectExtent;
623 nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
624 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom)
625 : 0;
626 rSize.Height += nEffectExtent;
629 void GraphicImport::lcl_attribute(Id nName, Value& rValue)
631 sal_Int32 nIntValue = rValue.getInt();
632 switch( nName )
634 case NS_ooxml::LN_OfficeArtExtension_Decorative_val:
635 m_pImpl->m_bDecorative = true;
636 break;
637 case NS_ooxml::LN_CT_Hyperlink_URL://90682;
638 m_pImpl->m_sHyperlinkURL = rValue.getString();
639 break;
640 case NS_ooxml::LN_blip: //the binary graphic data in a shape
642 writerfilter::Reference<Properties>::Pointer_t pProperties = rValue.getProperties();
643 if( pProperties )
645 pProperties->resolve(*this);
648 break;
649 case NS_ooxml::LN_payload :
651 writerfilter::Reference<BinaryObj>::Pointer_t pPictureData = rValue.getBinary();
652 if( pPictureData )
653 pPictureData->resolve(*this);
655 break;
657 //border properties
658 case NS_ooxml::LN_CT_Border_sz:
659 m_pImpl->m_aBorders[BORDER_TOP].nLineWidth = nIntValue;
660 break;
661 case NS_ooxml::LN_CT_Border_val:
662 //graphic borders don't support different line types
663 break;
664 case NS_ooxml::LN_CT_Border_space:
665 break;
666 case NS_ooxml::LN_CT_Border_shadow:
667 m_pImpl->m_aBorders[BORDER_TOP].bHasShadow = nIntValue != 0;
668 break;
669 case NS_ooxml::LN_CT_Border_frame:
670 break;
671 case NS_ooxml::LN_CT_PositiveSize2D_cx:
672 case NS_ooxml::LN_CT_PositiveSize2D_cy:
674 sal_Int32 nDim = oox::drawingml::convertEmuToHmm(nIntValue);
675 // drawingML equivalent of oox::vml::ShapeType::getAbsRectangle():
676 // make sure a shape isn't hidden implicitly just because it has
677 // zero height or width.
678 if (nDim == 0)
679 nDim = 1;
681 if( nName == NS_ooxml::LN_CT_PositiveSize2D_cx )
682 m_pImpl->setXSize(nDim);
683 else
684 m_pImpl->setYSize(nDim);
686 break;
687 case NS_ooxml::LN_CT_EffectExtent_l:
688 m_pImpl->m_oEffectExtentLeft = nIntValue;
689 break;
690 case NS_ooxml::LN_CT_EffectExtent_t:
691 m_pImpl->m_oEffectExtentTop = nIntValue;
692 break;
693 case NS_ooxml::LN_CT_EffectExtent_r:
694 m_pImpl->m_oEffectExtentRight = nIntValue;
695 break;
696 case NS_ooxml::LN_CT_EffectExtent_b:
697 m_pImpl->m_oEffectExtentBottom = nIntValue;
698 break;
699 case NS_ooxml::LN_CT_NonVisualDrawingProps_id:// 90650;
700 //id of the object - ignored
701 break;
702 case NS_ooxml::LN_CT_NonVisualDrawingProps_name:// 90651;
703 //name of the object
704 m_pImpl->m_sName = rValue.getString();
705 break;
706 case NS_ooxml::LN_CT_NonVisualDrawingProps_descr:// 90652;
707 //alternative text
708 m_pImpl->m_sAlternativeText = rValue.getString();
709 break;
710 case NS_ooxml::LN_CT_NonVisualDrawingProps_title:
711 //alternative text
712 m_pImpl->m_title = rValue.getString();
713 break;
714 case NS_ooxml::LN_CT_NonVisualDrawingProps_hidden:
715 m_pImpl->m_bHidden = (nIntValue == 1);
716 break;
717 case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noChangeAspect://90644;
718 //disallow aspect ratio change - ignored
719 break;
720 case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noMove:// 90645;
721 m_pImpl->m_bPositionProtected = true;
722 break;
723 case NS_ooxml::LN_CT_GraphicalObjectFrameLocking_noResize: // 90646;
724 m_pImpl->m_bSizeProtected = true;
725 break;
726 case NS_ooxml::LN_CT_Anchor_distT: // 90983;
727 case NS_ooxml::LN_CT_Anchor_distB: // 90984;
728 case NS_ooxml::LN_CT_Anchor_distL: // 90985;
729 case NS_ooxml::LN_CT_Anchor_distR: // 90986;
731 m_pImpl->m_nShapeOptionType = nName;
732 ProcessShapeOptions(rValue);
734 break;
735 case NS_ooxml::LN_CT_Anchor_simplePos_attr: // 90987;
736 m_pImpl->m_bUseSimplePos = nIntValue > 0;
737 break;
738 case NS_ooxml::LN_CT_Anchor_relativeHeight: // 90988;
739 m_pImpl->m_zOrder = nIntValue;
740 break;
741 case NS_ooxml::LN_CT_Anchor_behindDoc: // 90989; - in background
742 if (nIntValue > 0)
744 m_pImpl->m_bOpaque = false;
745 m_pImpl->m_bBehindDoc = true;
747 break;
748 case NS_ooxml::LN_CT_Anchor_locked: // 90990; - ignored
749 break;
750 case NS_ooxml::LN_CT_Anchor_layoutInCell: // 90991; - ignored
751 // Starting in MSO 2013, anchors are ALWAYS considered to be laid out in table cell.
752 m_pImpl->m_bCompatForcedLayoutInCell = !nIntValue
753 && m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14
754 && m_pImpl->m_rDomainMapper.IsInTable();
755 m_pImpl->m_bLayoutInCell = m_pImpl->m_bCompatForcedLayoutInCell || nIntValue;
756 break;
757 case NS_ooxml::LN_CT_Anchor_hidden: // 90992; - ignored
758 break;
759 case NS_ooxml::LN_CT_Anchor_allowOverlap:
760 m_pImpl->m_bAllowOverlap = nIntValue != 0;
761 break;
762 case NS_ooxml::LN_CT_Anchor_wp14_anchorId:
763 case NS_ooxml::LN_CT_Inline_wp14_anchorId:
765 OUStringBuffer aBuffer = OUString::number(nIntValue, 16);
766 OUStringBuffer aString;
767 comphelper::string::padToLength(aString, 8 - aBuffer.getLength(), '0');
768 aString.append(aBuffer.getStr());
769 m_pImpl->m_sAnchorId = aString.makeStringAndClear().toAsciiUpperCase();
771 break;
772 case NS_ooxml::LN_CT_Point2D_x: // 90405;
773 m_pImpl->m_nLeftPosition = ConversionHelper::convertTwipToMM100(nIntValue);
774 m_pImpl->m_nHoriRelation = text::RelOrientation::PAGE_FRAME;
775 m_pImpl->m_nHoriOrient = text::HoriOrientation::NONE;
776 break;
777 case NS_ooxml::LN_CT_Point2D_y: // 90406;
778 m_pImpl->m_nTopPosition = ConversionHelper::convertTwipToMM100(nIntValue);
779 m_pImpl->m_nVertRelation = text::RelOrientation::PAGE_FRAME;
780 m_pImpl->m_nVertOrient = text::VertOrientation::NONE;
781 break;
782 case NS_ooxml::LN_CT_WrapTight_wrapText: // 90934;
783 m_pImpl->m_bContour = true;
784 m_pImpl->m_bContourOutside = true;
786 handleWrapTextValue(rValue.getInt());
788 break;
789 case NS_ooxml::LN_CT_WrapThrough_wrapText:
790 m_pImpl->m_bContour = true;
791 m_pImpl->m_bContourOutside = false;
793 handleWrapTextValue(rValue.getInt());
795 break;
796 case NS_ooxml::LN_CT_WrapSquare_wrapText: //90928;
797 handleWrapTextValue(rValue.getInt());
798 break;
799 case NS_ooxml::LN_shape:
801 uno::Reference< drawing::XShape> xShape;
802 rValue.getAny( ) >>= xShape;
803 if ( xShape.is( ) )
805 // Is it a graphic image
806 bool bUseShape = true;
809 uno::Reference< beans::XPropertySet > xShapeProps
810 ( xShape, uno::UNO_QUERY_THROW );
812 uno::Reference<graphic::XGraphic> xGraphic;
813 xShapeProps->getPropertyValue("Graphic") >>= xGraphic;
815 sal_Int32 nRotation = 0;
816 xShapeProps->getPropertyValue("RotateAngle") >>= nRotation;
818 css::beans::PropertyValues aGrabBag;
819 xShapeProps->getPropertyValue("InteropGrabBag") >>= aGrabBag;
820 // if the shape contains effects in the grab bag, we should not transform it
821 // in a XTextContent so those effects can be preserved
822 bool bContainsEffects = std::any_of(std::cbegin(aGrabBag), std::cend(aGrabBag), [](const auto& rProp) {
823 return rProp.Name == "EffectProperties"
824 || rProp.Name == "3DEffectProperties"
825 || rProp.Name == "ArtisticEffectProperties";
828 xShapeProps->getPropertyValue("Shadow") >>= m_pImpl->m_bShadow;
829 if (m_pImpl->m_bShadow)
831 xShapeProps->getPropertyValue("ShadowXDistance") >>= m_pImpl->m_nShadowXDistance;
832 xShapeProps->getPropertyValue("ShadowYDistance") >>= m_pImpl->m_nShadowYDistance;
833 xShapeProps->getPropertyValue("ShadowColor") >>= m_pImpl->m_nShadowColor;
834 xShapeProps->getPropertyValue("ShadowTransparence") >>= m_pImpl->m_nShadowTransparence;
837 xShapeProps->getPropertyValue("GraphicColorMode") >>= m_pImpl->m_eColorMode;
838 xShapeProps->getPropertyValue("AdjustLuminance") >>= m_pImpl->m_nBrightness;
839 xShapeProps->getPropertyValue("AdjustContrast") >>= m_pImpl->m_nContrast;
841 // fdo#70457: transform XShape into a SwXTextGraphicObject only if there's no rotation
842 if ( nRotation == 0 && !bContainsEffects )
843 m_xGraphicObject = createGraphicObject( xGraphic, xShapeProps );
845 bUseShape = !m_xGraphicObject.is( );
847 if ( !bUseShape )
849 // Define the object size
850 uno::Reference< beans::XPropertySet > xGraphProps( m_xGraphicObject,
851 uno::UNO_QUERY );
852 awt::Size aSize = xShape->getSize( );
853 xGraphProps->setPropertyValue("Height",
854 uno::Any( aSize.Height ) );
855 xGraphProps->setPropertyValue("Width",
856 uno::Any( aSize.Width ) );
858 text::GraphicCrop aGraphicCrop( 0, 0, 0, 0 );
859 uno::Reference< beans::XPropertySet > xSourceGraphProps( xShape, uno::UNO_QUERY );
860 uno::Any aAny = xSourceGraphProps->getPropertyValue("GraphicCrop");
861 if(aAny >>= aGraphicCrop) {
862 xGraphProps->setPropertyValue("GraphicCrop",
863 uno::Any( aGraphicCrop ) );
866 // We need to drop the shape here somehow
867 uno::Reference< lang::XComponent > xShapeComponent( xShape, uno::UNO_QUERY );
868 xShapeComponent->dispose( );
871 catch( const beans::UnknownPropertyException & )
873 // It isn't a graphic image
876 if ( bUseShape )
877 m_xShape = xShape;
879 if ( m_xShape.is( ) )
881 uno::Reference< beans::XPropertySet > xShapeProps
882 (m_xShape, uno::UNO_QUERY_THROW);
885 xShapeProps->setPropertyValue
886 (getPropertyName(PROP_ANCHOR_TYPE),
887 uno::Any
888 (text::TextContentAnchorType_AS_CHARACTER));
890 // In Word, if a shape is anchored inline, that
891 // excludes being in the background.
892 xShapeProps->setPropertyValue("Opaque", uno::Any(true));
894 uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
896 // TextFrames can't be rotated. But for anything else,
897 // make sure that setting size doesn't affect rotation,
898 // that would not match Word's definition of rotation.
899 bool bKeepRotation = false;
900 if (!xServiceInfo->supportsService("com.sun.star.text.TextFrame"))
902 bKeepRotation = true;
903 xShapeProps->setPropertyValue
904 (getPropertyName(PROP_TEXT_RANGE),
905 uno::Any
906 (m_pImpl->m_rDomainMapper.GetCurrentTextRange()));
909 awt::Size aSize(m_xShape->getSize());
911 // One purpose of the next part is, to set the logic rectangle of the SdrObject
912 // to nXSize and nYSize from import. That doesn't work for groups or lines,
913 // because they do not have a logic rectangle and m_xShape->getSize and
914 // m_xShape->setSize would work on the snap rectangle. In case a shape is
915 // rotated, non-uniform scaling the snap rectangle will introduce shearing on
916 // the shape. In case group or line is rotated, nXSize and nYSize contain the
917 // unrotated size from oox. The rotation is already incorporated into group
918 // children and line points. We must not scale them to unrotated size. Exclude
919 // those shapes here.
921 // Get MSO rotation angle. GetRotateAngle from SdrObject is not suitable
922 // here, because it returns the rotate angle of the first child for groups
923 // and slope angle for lines, even if line or group had not been rotated.
924 // Import in oox has put the rotation from oox file into InteropGrabBag.
925 comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
926 sal_Int32 nOOXAngle(0);
927 aInteropGrabBag.getValue("mso-rotation-angle") >>= nOOXAngle; // 1/60000 deg
928 // tdf#143455: A diagram is imported as group, but has no valid object list
929 // and contour wrap is different to Word. As workaround diagrams are excluded
930 // here in various places.
931 const SdrObject* pDiagramCandidate(SdrObject::getSdrObjectFromXShape(m_xShape));
932 const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram());
933 // tdf#143476: A lockedCanvas (Word2007) is imported as group, but has not
934 // got size and position. Values from m_Impl has to be used.
935 bool bIsLockedCanvas(false);
936 aInteropGrabBag.getValue("LockedCanvas") >>= bIsLockedCanvas;
937 const bool bIsGroupOrLine = (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape")
938 && !bIsDiagram && !bIsLockedCanvas)
939 || xServiceInfo->supportsService("com.sun.star.drawing.LineShape");
940 SdrObject* pShape = SdrObject::getSdrObjectFromXShape(m_xShape);
941 if ((bIsGroupOrLine && !lcl_bHasGroupSlantedChild(pShape) && nOOXAngle == 0)
942 || !bIsGroupOrLine)
944 if (m_pImpl->isXSizeValid())
945 aSize.Width = m_pImpl->getXSize();
946 if (m_pImpl->isYSizeValid())
947 aSize.Height = m_pImpl->getYSize();
950 Degree100 nRotation;
951 if (bKeepRotation)
953 // Use internal API, getPropertyValue("RotateAngle")
954 // would use GetObjectRotation(), which is not what
955 // we want.
956 if (pShape)
957 nRotation = pShape->GetRotateAngle();
959 m_xShape->setSize(aSize);
960 if (bKeepRotation)
962 xShapeProps->setPropertyValue("RotateAngle", uno::Any(nRotation.get()));
965 m_pImpl->m_bIsGraphic = true;
967 if (!m_pImpl->m_sAnchorId.isEmpty())
969 putPropertyToFrameGrabBag("AnchorId", uno::Any(m_pImpl->m_sAnchorId));
972 // Calculate mso unrotated rectangle and its center, needed below
973 awt::Size aImportSize(m_xShape->getSize()); // here only fallback
974 if (m_pImpl->isXSizeValid())
975 aImportSize.Width = m_pImpl->getXSize(); // Hmm
976 if (m_pImpl->isYSizeValid())
977 aImportSize.Height = m_pImpl->getYSize(); // Hmm
978 const awt::Point aImportPosition(GetGraphicObjectPosition()); // Hmm
979 double fCentrumX = aImportPosition.X + aImportSize.Width / 2.0;
980 double fCentrumY = aImportPosition.Y + aImportSize.Height / 2.0;
982 // In case of group and lines, transformations are incorporated in the child
983 // shapes or points respectively in LO. MSO has rotation as separate property.
984 // The position refers to the unrotated rectangle of MSO. We need to adapt it
985 // to the left-top of the transformed shape.
986 awt::Size aLOSize(m_xShape->getSize()); // LO snap rectangle size in Hmm
987 if (bIsGroupOrLine && !(m_pImpl->mpWrapPolygon))
989 // Set LO position. MSO rotation is done on shape center.
990 if(pShape && pShape->IsGroupObject())
992 tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twips
993 m_pImpl->m_nLeftPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
994 m_pImpl->m_nTopPosition = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
995 aLOSize.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenWidth());
996 aLOSize.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenHeight());
998 else
1000 m_pImpl->m_nLeftPosition = fCentrumX - aLOSize.Width / 2.0;
1001 m_pImpl->m_nTopPosition = fCentrumY - aLOSize.Height / 2.0;
1003 m_xShape->setPosition(GetGraphicObjectPosition());
1005 // ToDo: Rotated shapes with position type "Alignment" (UI of Word) have
1006 // wrong position. Word aligns the unrotated logic rectangle, LO the rotated
1007 // snap rectangle.
1009 // Margin correction
1011 // tdf#143475: Word 2007 (vers 12) calculates effectExtent for rotated images
1012 // based on the unrotated image without width-height-swap. We correct this to
1013 // those values, which would be calculated if width-height-swap was used.
1014 if (m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() < 14
1015 && xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")
1016 && nOOXAngle != 0)
1018 lcl_correctWord2007EffectExtent(nOOXAngle);
1021 if (m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_INLINE)
1023 if (nOOXAngle == 0)
1025 // EffectExtent contains all needed additional space, including fat
1026 // stroke and shadow. Simple add it to the margins.
1027 sal_Int32 nEffectExtent = (m_pImpl->m_oEffectExtentLeft)
1028 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft)
1029 : 0;
1030 m_pImpl->m_nLeftMargin += nEffectExtent;
1031 nEffectExtent = (m_pImpl->m_oEffectExtentRight)
1032 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight) : 0;
1033 m_pImpl->m_nRightMargin += nEffectExtent;
1034 nEffectExtent = (m_pImpl->m_oEffectExtentTop)
1035 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop) : 0;
1036 m_pImpl->m_nTopMargin += nEffectExtent;
1037 nEffectExtent = (m_pImpl->m_oEffectExtentBottom)
1038 ? oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom) : 0;
1039 m_pImpl->m_nBottomMargin += nEffectExtent;
1041 else
1043 // As of June 2021 LibreOffice uses an area, which is large enough to
1044 // contain the rotated snap rectangle. MSO uses a smaller area, so
1045 // that the rotated snap rectangle covers text.
1046 awt::Point aMSOBaseLeftTop = aImportPosition;
1047 awt::Size aMSOBaseSize = aImportSize;
1048 lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
1049 lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
1051 // Get LO SnapRect from SdrObject if possible
1052 awt::Rectangle aLOSnapRect;
1053 // For case we have no SdrObject, initialize with values from m_pImpl
1054 aLOSnapRect.X = m_pImpl->m_nLeftPosition;
1055 aLOSnapRect.Y = m_pImpl->m_nTopPosition;
1056 aLOSnapRect.Width = aLOSize.Width;
1057 aLOSnapRect.Height = aLOSize.Height;
1058 if (pShape)
1060 tools::Rectangle aSnapRect = pShape->GetSnapRect(); // Twip
1061 aLOSnapRect.X = ConversionHelper::convertTwipToMM100(aSnapRect.Left());
1062 aLOSnapRect.Y = ConversionHelper::convertTwipToMM100(aSnapRect.Top());
1063 aLOSnapRect.Width = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenWidth());
1064 aLOSnapRect.Height = ConversionHelper::convertTwipToMM100(aSnapRect.getOpenHeight());
1067 m_pImpl->m_nLeftMargin += aLOSnapRect.X - aMSOBaseLeftTop.X;
1068 m_pImpl->m_nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
1069 - (aLOSnapRect.X + aLOSnapRect.Width);
1070 m_pImpl->m_nTopMargin += aLOSnapRect.Y - aMSOBaseLeftTop.Y;
1071 m_pImpl->m_nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
1072 - (aLOSnapRect.Y + aLOSnapRect.Height);
1073 // tdf#141880 LibreOffice cannot handle negative vertical margins.
1074 // Those cases are caught below at common place.
1076 } // end IMPORT_AS_DETECTED_INLINE
1077 else if ((m_pImpl->m_nWrap == text::WrapTextMode_PARALLEL
1078 || m_pImpl->m_nWrap == text::WrapTextMode_DYNAMIC
1079 || m_pImpl->m_nWrap == text::WrapTextMode_LEFT
1080 || m_pImpl->m_nWrap == text::WrapTextMode_RIGHT
1081 || m_pImpl->m_nWrap == text::WrapTextMode_NONE)
1082 && !(m_pImpl->mpWrapPolygon) && !bIsDiagram)
1084 // For wrap "Square" an area is defined around which the text wraps. MSO
1085 // describes the area by a base rectangle and effectExtent. LO uses the
1086 // shape bounding box and margins. We adapt the margins to get the same
1087 // area as MSO.
1088 awt::Point aMSOBaseLeftTop = aImportPosition;
1089 awt::Size aMSOBaseSize = aImportSize;
1090 lcl_doMSOWidthHeightSwap(aMSOBaseLeftTop, aMSOBaseSize, nOOXAngle);
1091 lcl_expandRectangleByEffectExtent(aMSOBaseLeftTop, aMSOBaseSize);
1093 // Get LO bound rectangle from SdrObject if possible
1094 awt::Rectangle aLOBoundRect;
1095 // For case we have no SdrObject, initialize with values from m_pImpl
1096 aLOBoundRect.X = m_pImpl->m_nLeftPosition;
1097 aLOBoundRect.Y = m_pImpl->m_nTopPosition;
1098 aLOBoundRect.Width = aLOSize.Width;
1099 aLOBoundRect.Height = aLOSize.Height;
1100 if (pShape)
1102 tools::Rectangle aBoundRect = pShape->GetCurrentBoundRect(); // Twip
1103 aLOBoundRect.X = ConversionHelper::convertTwipToMM100(aBoundRect.Left());
1104 aLOBoundRect.Y = ConversionHelper::convertTwipToMM100(aBoundRect.Top());
1105 aLOBoundRect.Width = ConversionHelper::convertTwipToMM100(aBoundRect.getOpenWidth());
1106 aLOBoundRect.Height = ConversionHelper::convertTwipToMM100(aBoundRect.getOpenHeight());
1109 m_pImpl->m_nLeftMargin += aLOBoundRect.X - aMSOBaseLeftTop.X;
1110 m_pImpl->m_nRightMargin += aMSOBaseLeftTop.X + aMSOBaseSize.Width
1111 - (aLOBoundRect.X + aLOBoundRect.Width);
1112 m_pImpl->m_nTopMargin += aLOBoundRect.Y - aMSOBaseLeftTop.Y;
1113 m_pImpl->m_nBottomMargin += aMSOBaseLeftTop.Y + aMSOBaseSize.Height
1114 - (aLOBoundRect.Y + aLOBoundRect.Height);
1116 else if (m_pImpl->mpWrapPolygon && !bIsDiagram)
1118 // Word uses a wrap polygon, LibreOffice has no explicit wrap polygon
1119 // but creates the wrap contour based on the shape geometry, without
1120 // stroke width and shadow, but with rotation and flip. The concepts
1121 // are not compatible. We approximate Word's rendering by setting
1122 // wrap margins.
1124 // Build a range from the wrap polygon from Word.
1125 const drawing::PointSequenceSequence aWrapPolygon
1126 = m_pImpl->mpWrapPolygon->getPointSequenceSequence();
1127 basegfx::B2DPolyPolygon aB2DWrapPolyPolygon
1128 = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(
1129 aWrapPolygon);
1130 // Wrap polygon values are relative to 0..21600|0..21600.
1131 // Scale to shape size (in Hmm).
1132 basegfx::B2DHomMatrix aMatrix = basegfx::utils::createScaleB2DHomMatrix(
1133 aImportSize.Width / 21600.0, aImportSize.Height / 21600.0);
1134 aB2DWrapPolyPolygon.transform(aMatrix);
1136 // Shape geometry will be rotated, rotate wrap polygon too.
1137 if (nOOXAngle != 0)
1139 aMatrix = basegfx::utils::createRotateAroundPoint(
1140 aImportSize.Width / 2.0, aImportSize.Height / 2.0,
1141 basegfx::deg2rad<60000>(nOOXAngle));
1142 aB2DWrapPolyPolygon.transform(aMatrix);
1144 basegfx::B2DRange aB2DWrapRange = aB2DWrapPolyPolygon.getB2DRange();
1146 // Build a range from shape geometry
1147 basegfx::B2DRange aShapeRange;
1148 if (pShape)
1150 basegfx::B2DPolyPolygon aShapePolygon = pShape->TakeXorPoly(); // Twips
1151 aMatrix = basegfx::utils::createScaleB2DHomMatrix(
1152 o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100),
1153 o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100));
1154 aShapePolygon.transform(aMatrix);
1155 // Wrap polygon treats left/top of shape as origin, shift shape polygon accordingly
1156 aMatrix = basegfx::utils::createTranslateB2DHomMatrix(
1157 -aImportPosition.X, -aImportPosition.Y);
1158 aShapePolygon.transform(aMatrix);
1159 aShapeRange = aShapePolygon.getB2DRange();
1161 else // can this happen?
1163 aShapeRange
1164 = basegfx::B2DRange(0, 0, aImportSize.Width, aImportSize.Height);
1165 if (nOOXAngle != 0)
1167 aMatrix = basegfx::utils::createRotateB2DHomMatrix(
1168 basegfx::deg2rad<60000>(nOOXAngle));
1169 aShapeRange.transform(aMatrix);
1173 // Add difference between shape and wrap range to margin and remember
1174 // difference in Twips for export.
1175 comphelper::SequenceAsHashMap aAnchorDistDiff;
1177 const double fTopDiff = aShapeRange.getMinY() - aB2DWrapRange.getMinY();
1178 m_pImpl->m_nTopMargin += basegfx::fround(fTopDiff);
1179 aAnchorDistDiff["distTDiff"] <<= basegfx::fround(
1180 o3tl::convert(fTopDiff, o3tl::Length::mm100, o3tl::Length::twip));
1182 const double fBottomDiff = aB2DWrapRange.getMaxY() - aShapeRange.getMaxY();
1183 m_pImpl->m_nBottomMargin += basegfx::fround(fBottomDiff);
1184 aAnchorDistDiff["distBDiff"] <<= basegfx::fround(
1185 o3tl::convert(fBottomDiff, o3tl::Length::mm100, o3tl::Length::twip));
1187 const double fLeftDiff = aShapeRange.getMinX() - aB2DWrapRange.getMinX();
1188 m_pImpl->m_nLeftMargin += basegfx::fround(fLeftDiff);
1189 aAnchorDistDiff["distLDiff"] <<= basegfx::fround(
1190 o3tl::convert(fLeftDiff, o3tl::Length::mm100, o3tl::Length::twip));
1192 const double fRightDiff = aB2DWrapRange.getMaxX() - aShapeRange.getMaxX();
1193 m_pImpl->m_nRightMargin += basegfx::fround(fRightDiff);
1194 aAnchorDistDiff["distRDiff"] <<= basegfx::fround(
1195 o3tl::convert(fRightDiff, o3tl::Length::mm100, o3tl::Length::twip));
1197 m_pImpl->m_aInteropGrabBag["AnchorDistDiff"]
1198 <<= aAnchorDistDiff.getAsConstPropertyValueList();
1200 // FixMe: tdf#141880. LibreOffice cannot handle negative horizontal margin in contour wrap
1201 if (m_pImpl->m_nLeftMargin < 0)
1202 m_pImpl->m_nLeftMargin = 0;
1203 if (m_pImpl->m_nRightMargin < 0)
1204 m_pImpl->m_nRightMargin = 0;
1206 else if (!bIsDiagram) // text::WrapTextMode_THROUGH
1208 // Word writes and evaluates the effectExtent in case of position
1209 // type 'Alignment' (UI). We move these values to margin to approximate
1210 // Word's rendering.
1211 if (m_pImpl->m_oEffectExtentLeft)
1213 m_pImpl->m_nLeftMargin
1214 += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentLeft);
1216 if (m_pImpl->m_oEffectExtentTop)
1218 m_pImpl->m_nTopMargin
1219 += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentTop);
1221 if (m_pImpl->m_oEffectExtentRight)
1223 m_pImpl->m_nRightMargin
1224 += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentRight);
1226 if (m_pImpl->m_oEffectExtentBottom)
1228 m_pImpl->m_nBottomMargin
1229 += oox::drawingml::convertEmuToHmm(*m_pImpl->m_oEffectExtentBottom);
1233 // FixMe: tdf#141880 LibreOffice cannot handle negative vertical margins
1234 // although they are allowed in ODF.
1235 if (m_pImpl->m_nTopMargin < 0)
1236 m_pImpl->m_nTopMargin = 0;
1237 if (m_pImpl->m_nBottomMargin < 0)
1238 m_pImpl->m_nBottomMargin = 0;
1241 if (bUseShape && m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
1243 // If we are here, this is a drawingML shape. For those, only dmapper (and not oox) knows the anchoring infos (just like for Writer pictures).
1244 // But they aren't Writer pictures, either (which are already handled above).
1245 uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
1247 if (m_pImpl->m_nWrap == text::WrapTextMode_THROUGH && m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME)
1249 // text::RelOrientation::FRAME is OOXML's "column", which behaves as if
1250 // layout-in-cell would be always off.
1251 m_pImpl->m_bLayoutInCell = false;
1254 // Anchored: Word only supports at-char in that case.
1255 text::TextContentAnchorType eAnchorType = text::TextContentAnchorType_AT_CHARACTER;
1257 if (m_pImpl->m_bHidden)
1259 xShapeProps->setPropertyValue("Visible", uno::Any(false));
1260 xShapeProps->setPropertyValue("Printable", uno::Any(false));
1263 // Avoid setting AnchorType for TextBoxes till SwTextBoxHelper::syncProperty() doesn't handle transition.
1264 bool bTextBox = false;
1265 xShapeProps->getPropertyValue("TextBox") >>= bTextBox;
1267 // The positioning change caused by LayoutInCell doesn't sync well
1268 // in the text / frame duo. So the compatibility fix only correctly
1269 // positions the frame and not the text currently.
1270 // tdf#135943: Instead of half-fixing and making a complete mess,
1271 // just avoid until layout's repositioning is sync'd to the text frame.
1272 if (m_pImpl->m_bLayoutInCell && bTextBox)
1273 m_pImpl->m_bLayoutInCell = !m_pImpl->m_bCompatForcedLayoutInCell;
1275 xShapeProps->setPropertyValue("AnchorType", uno::Any(eAnchorType));
1277 if (m_pImpl->m_nVertRelation == text::RelOrientation::TEXT_LINE)
1279 // Word's "line" is "below the bottom of the line", our TEXT_LINE is
1280 // "towards top, from the bottom of the line", so invert the vertical
1281 // position.
1282 awt::Point aPoint = xShape->getPosition();
1283 aPoint.Y *= -1;
1284 xShape->setPosition(aPoint);
1287 if (m_pImpl->m_bLayoutInCell && bTextBox && m_pImpl->m_rDomainMapper.IsInTable()
1288 && m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_FRAME)
1289 m_pImpl->m_nHoriRelation = text::RelOrientation::FRAME;
1290 if(m_pImpl->m_rDomainMapper.IsInTable())
1291 xShapeProps->setPropertyValue(getPropertyName(PROP_FOLLOW_TEXT_FLOW),
1292 uno::Any(m_pImpl->m_bLayoutInCell));
1293 //only the position orientation is handled in applyPosition()
1294 m_pImpl->applyPosition(xShapeProps);
1296 uno::Reference<lang::XServiceInfo> xServiceInfo(m_xShape, uno::UNO_QUERY_THROW);
1297 if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape") ||
1298 xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
1300 // You would expect that position and rotation are
1301 // independent, but they are not. Till we are not
1302 // there yet to handle all scaling, translation and
1303 // rotation with a single transformation matrix,
1304 // make sure there is no graphic rotation set when we set
1305 // the position.
1306 sal_Int32 nRotation = 0;
1307 if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
1309 xShapeProps->getPropertyValue("RotateAngle") >>= nRotation;
1311 if (nRotation)
1312 xShapeProps->setPropertyValue("RotateAngle", uno::Any(sal_Int32(0)));
1314 // Position of the groupshape should be set after children have been added.
1315 // Long-term we should get rid of positioning group
1316 // shapes, though. Do it for top-level ones with
1317 // absolute page position as a start.
1318 // fdo#80555: also set position for graphic shapes here
1319 if (!isTopGroupObj(m_xShape)
1320 || m_pImpl->m_nHoriRelation != text::RelOrientation::PAGE_FRAME
1321 || m_pImpl->m_nVertRelation != text::RelOrientation::PAGE_FRAME)
1322 m_xShape->setPosition(
1323 awt::Point(m_pImpl->m_nLeftPosition, m_pImpl->m_nTopPosition));
1325 if (nRotation)
1326 xShapeProps->setPropertyValue("RotateAngle", uno::Any(nRotation));
1330 m_pImpl->applyRelativePosition(xShapeProps, /*bRelativeOnly=*/true);
1332 xShapeProps->setPropertyValue("SurroundContour", uno::Any(m_pImpl->m_bContour));
1333 xShapeProps->setPropertyValue("ContourOutside", uno::Any(m_pImpl->m_bContourOutside));
1334 m_pImpl->applyMargins(xShapeProps);
1335 xShapeProps->setPropertyValue("Opaque", uno::Any(m_pImpl->m_bOpaque));
1336 xShapeProps->setPropertyValue("Surround", uno::Any(static_cast<sal_Int32>(m_pImpl->m_nWrap)));
1337 m_pImpl->applyZOrder(xShapeProps);
1338 m_pImpl->applyName(xShapeProps);
1339 m_pImpl->applyHyperlink(xShapeProps, bUseShape);
1340 xShapeProps->setPropertyValue("AllowOverlap",
1341 uno::Any(m_pImpl->m_bAllowOverlap));
1343 // Get the grab-bag set by oox, merge with our one and then put it back.
1344 comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
1345 aInteropGrabBag.update(m_pImpl->getInteropGrabBag());
1346 xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag.getAsConstPropertyValueList()));
1348 else if (bUseShape && m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_INLINE)
1350 uno::Reference< beans::XPropertySet > xShapeProps(m_xShape, uno::UNO_QUERY_THROW);
1351 m_pImpl->applyMargins(xShapeProps);
1352 m_pImpl->applyZOrder(xShapeProps);
1353 m_pImpl->applyName(xShapeProps);
1354 comphelper::SequenceAsHashMap aInteropGrabBag(xShapeProps->getPropertyValue("InteropGrabBag"));
1355 aInteropGrabBag.update(m_pImpl->getInteropGrabBag());
1356 xShapeProps->setPropertyValue("InteropGrabBag", uno::Any(aInteropGrabBag.getAsConstPropertyValueList()));
1360 break;
1361 case NS_ooxml::LN_CT_Inline_distT:
1362 m_pImpl->m_nTopMargin = 0;
1363 break;
1364 case NS_ooxml::LN_CT_Inline_distB:
1365 m_pImpl->m_nBottomMargin = 0;
1366 break;
1367 case NS_ooxml::LN_CT_Inline_distL:
1368 m_pImpl->m_nLeftMargin = 0;
1369 break;
1370 case NS_ooxml::LN_CT_Inline_distR:
1371 m_pImpl->m_nRightMargin = 0;
1372 break;
1373 case NS_ooxml::LN_CT_GraphicalObjectData_uri:
1374 rValue.getString();
1375 //TODO: does it need to be handled?
1376 break;
1377 case NS_ooxml::LN_CT_SizeRelH_relativeFrom:
1379 switch (nIntValue)
1381 case NS_ooxml::LN_ST_SizeRelFromH_margin:
1382 if (m_xShape.is())
1384 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1385 xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::FRAME));
1387 break;
1388 case NS_ooxml::LN_ST_SizeRelFromH_leftMargin:
1389 case NS_ooxml::LN_ST_SizeRelFromH_outsideMargin:
1390 if (m_xShape.is())
1392 // Here we handle the relative size of the width of some shape.
1393 // The size of the shape's width is going to be relative to the size of the left margin.
1394 // E.g.: (left margin = 8 && relative size = 150%) -> width of some shape = 12.
1395 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1396 xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_LEFT));
1398 break;
1399 case NS_ooxml::LN_ST_SizeRelFromH_rightMargin:
1400 case NS_ooxml::LN_ST_SizeRelFromH_insideMargin:
1401 if (m_xShape.is())
1403 // Same as the left margin above.
1404 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1405 xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_RIGHT));
1407 break;
1408 case NS_ooxml::LN_ST_SizeRelFromH_page:
1409 if (m_xShape.is())
1411 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1412 xPropertySet->setPropertyValue("RelativeWidthRelation", uno::Any(text::RelOrientation::PAGE_FRAME));
1414 break;
1415 default:
1416 SAL_WARN("writerfilter", "GraphicImport::lcl_attribute: unhandled NS_ooxml::LN_CT_SizeRelH_relativeFrom value: " << nIntValue);
1417 break;
1420 break;
1421 case NS_ooxml::LN_CT_SizeRelV_relativeFrom:
1423 switch (nIntValue)
1425 case NS_ooxml::LN_ST_SizeRelFromV_margin:
1426 if (m_xShape.is())
1428 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1429 xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::FRAME));
1431 break;
1432 case NS_ooxml::LN_ST_SizeRelFromV_page:
1433 if (m_xShape.is())
1435 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1436 xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_FRAME));
1438 break;
1439 case NS_ooxml::LN_ST_SizeRelFromV_topMargin:
1440 if (m_xShape.is())
1442 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1443 xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_PRINT_AREA));
1445 break;
1446 case NS_ooxml::LN_ST_SizeRelFromV_bottomMargin:
1447 if (m_xShape.is())
1449 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1450 xPropertySet->setPropertyValue("RelativeHeightRelation", uno::Any(text::RelOrientation::PAGE_PRINT_AREA_BOTTOM));
1452 break;
1453 default:
1454 SAL_WARN("writerfilter", "GraphicImport::lcl_attribute: unhandled NS_ooxml::LN_CT_SizeRelV_relativeFrom value: " << nIntValue);
1455 break;
1458 break;
1459 default:
1460 #ifdef DBG_UTIL
1461 TagLogger::getInstance().element("unhandled");
1462 #endif
1463 break;
1467 uno::Reference<text::XTextContent> GraphicImport::GetGraphicObject()
1469 uno::Reference<text::XTextContent> xResult;
1471 if (m_xGraphicObject.is())
1472 xResult = m_xGraphicObject;
1473 else if (m_xShape.is())
1475 xResult.set(m_xShape, uno::UNO_QUERY_THROW);
1478 return xResult;
1482 void GraphicImport::ProcessShapeOptions(Value const & rValue)
1484 sal_Int32 nIntValue = rValue.getInt();
1485 switch( m_pImpl->m_nShapeOptionType )
1487 case NS_ooxml::LN_CT_Anchor_distL:
1488 m_pImpl->m_nLeftMargin = nIntValue / 360;
1489 m_pImpl->m_nLeftMarginOrig = m_pImpl->m_nLeftMargin;
1490 break;
1491 case NS_ooxml::LN_CT_Anchor_distT:
1492 //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustULWrapForWordMargins()
1493 m_pImpl->m_nTopMargin = nIntValue / 360;
1494 break;
1495 case NS_ooxml::LN_CT_Anchor_distR:
1496 //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustLRWrapForWordMargins()
1497 m_pImpl->m_nRightMargin = nIntValue / 360;
1498 break;
1499 case NS_ooxml::LN_CT_Anchor_distB:
1500 //todo: changes have to be applied depending on the orientation, see SwWW8ImplReader::AdjustULWrapForWordMargins()
1501 m_pImpl->m_nBottomMargin = nIntValue / 360;
1502 break;
1503 default:
1504 OSL_FAIL( "shape option unsupported?");
1509 void GraphicImport::lcl_sprm(Sprm& rSprm)
1511 sal_uInt32 nSprmId = rSprm.getId();
1513 switch(nSprmId)
1515 case NS_ooxml::LN_CT_Inline_extent: // 90911;
1516 case NS_ooxml::LN_CT_Inline_effectExtent: // 90912;
1517 case NS_ooxml::LN_CT_Inline_docPr: // 90913;
1518 case NS_ooxml::LN_CT_Inline_cNvGraphicFramePr: // 90914;
1519 case NS_ooxml::LN_CT_NonVisualGraphicFrameProperties_graphicFrameLocks:// 90657
1520 case NS_ooxml::LN_CT_Inline_a_graphic:// 90915
1521 case NS_ooxml::LN_CT_Anchor_simplePos_elem: // 90975;
1522 case NS_ooxml::LN_CT_Anchor_extent: // 90978;
1523 case NS_ooxml::LN_CT_Anchor_effectExtent: // 90979;
1524 case NS_ooxml::LN_EG_WrapType_wrapSquare: // 90945;
1525 case NS_ooxml::LN_EG_WrapType_wrapTight: // 90946;
1526 case NS_ooxml::LN_EG_WrapType_wrapThrough:
1527 case NS_ooxml::LN_CT_Anchor_docPr: // 90980;
1528 case NS_ooxml::LN_CT_NonVisualDrawingProps_extLst:
1529 case NS_ooxml::LN_CT_Anchor_cNvGraphicFramePr: // 90981;
1530 case NS_ooxml::LN_CT_Anchor_a_graphic: // 90982;
1531 case NS_ooxml::LN_CT_WrapPath_start: // 90924;
1532 case NS_ooxml::LN_CT_WrapPath_lineTo: // 90925;
1533 case NS_ooxml::LN_graphic_graphic:
1534 case NS_ooxml::LN_pic_pic:
1535 case NS_ooxml::LN_dgm_relIds:
1536 case NS_ooxml::LN_lc_lockedCanvas:
1537 case NS_ooxml::LN_c_chart:
1538 case NS_ooxml::LN_wps_wsp:
1539 case NS_ooxml::LN_wpg_wgp:
1540 case NS_ooxml::LN_sizeRelH_sizeRelH:
1541 case NS_ooxml::LN_sizeRelV_sizeRelV:
1542 case NS_ooxml::LN_hlinkClick_hlinkClick:
1544 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1545 if( pProperties )
1547 pProperties->resolve(*this);
1550 // We'll map these to PARALLEL, save the original wrap type.
1551 if (nSprmId == NS_ooxml::LN_EG_WrapType_wrapTight)
1552 m_pImpl->m_aInteropGrabBag["EG_WrapType"] <<= OUString("wrapTight");
1553 else if (nSprmId == NS_ooxml::LN_EG_WrapType_wrapThrough)
1554 m_pImpl->m_aInteropGrabBag["EG_WrapType"] <<= OUString("wrapThrough");
1556 switch (nSprmId)
1558 case NS_ooxml::LN_EG_WrapType_wrapSquare:
1559 case NS_ooxml::LN_EG_WrapType_wrapThrough:
1560 case NS_ooxml::LN_EG_WrapType_wrapTight:
1562 // tdf#137850: Word >= 2013 seems to ignore bBehindDoc except for wrapNone, but older versions honour it.
1563 if (m_pImpl->m_bBehindDoc && m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14)
1564 m_pImpl->m_bOpaque = true;
1566 break;
1570 break;
1571 case NS_ooxml::LN_CT_WrapTight_wrapPolygon:
1572 case NS_ooxml::LN_CT_WrapThrough_wrapPolygon:
1574 WrapPolygonHandler aHandler;
1576 resolveSprmProps(aHandler, rSprm);
1578 m_pImpl->mpWrapPolygon = aHandler.getPolygon();
1580 // Save the wrap path in case we can't handle it natively: drawinglayer shapes, TextFrames.
1581 m_pImpl->m_aInteropGrabBag["CT_WrapPath"] <<= m_pImpl->mpWrapPolygon->getPointSequenceSequence();
1583 break;
1584 case NS_ooxml::LN_CT_Anchor_positionH: // 90976;
1586 // Use a special handler for the positioning
1587 auto pHandler = std::make_shared<PositionHandler>( m_pImpl->m_rPositionOffsets, m_pImpl->m_rAligns );
1588 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1589 if( pProperties )
1591 pProperties->resolve( *pHandler );
1592 if( !m_pImpl->m_bUseSimplePos )
1594 m_pImpl->m_nHoriRelation = pHandler->relation();
1595 m_pImpl->m_bPageToggle = pHandler->GetPageToggle();
1596 m_pImpl->m_nHoriOrient = pHandler->orientation();
1597 m_pImpl->m_nLeftPosition = pHandler->position();
1599 // Left adjustments: if horizontally aligned to left of margin, then remove the
1600 // left wrapping.
1601 if (m_pImpl->m_nHoriOrient == text::HoriOrientation::LEFT)
1603 if (m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA)
1605 m_pImpl->m_nLeftMargin = 0;
1611 break;
1612 case NS_ooxml::LN_CT_Anchor_positionV: // 90977;
1614 // Use a special handler for the positioning
1615 auto pHandler = std::make_shared<PositionHandler>( m_pImpl->m_rPositionOffsets, m_pImpl->m_rAligns);
1616 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1617 if( pProperties )
1619 pProperties->resolve( *pHandler );
1620 if( !m_pImpl->m_bUseSimplePos )
1622 m_pImpl->m_nVertRelation = pHandler->relation();
1623 m_pImpl->m_nVertOrient = pHandler->orientation();
1624 m_pImpl->m_nTopPosition = pHandler->position();
1628 break;
1629 case NS_ooxml::LN_CT_SizeRelH_pctWidth:
1630 case NS_ooxml::LN_CT_SizeRelV_pctHeight:
1631 if (m_pImpl->m_rPositivePercentages.empty())
1632 break;
1634 if (m_xShape.is())
1636 sal_Int16 nPositivePercentage = rtl::math::round(m_pImpl->m_rPositivePercentages.front().toDouble() / oox::drawingml::PER_PERCENT);
1638 if (nPositivePercentage)
1640 uno::Reference<beans::XPropertySet> xPropertySet(m_xShape, uno::UNO_QUERY);
1641 OUString aProperty = nSprmId == NS_ooxml::LN_CT_SizeRelH_pctWidth ? OUString("RelativeWidth") : OUString("RelativeHeight");
1643 sal_Int32 nTextPreRotateAngle = 0;
1644 uno::Any aAny;
1645 if (xPropertySet->getPropertySetInfo()->hasPropertyByName(
1646 "CustomShapeGeometry"))
1648 aAny = xPropertySet->getPropertyValue("CustomShapeGeometry");
1650 comphelper::SequenceAsHashMap aCustomShapeGeometry(aAny);
1651 auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
1652 if (it != aCustomShapeGeometry.end())
1654 nTextPreRotateAngle = it->second.get<sal_Int32>();
1656 if (nTextPreRotateAngle == 0)
1658 xPropertySet->setPropertyValue(aProperty,
1659 uno::Any(nPositivePercentage));
1664 // Make sure the token is consumed even if xShape is an empty
1665 // reference.
1666 m_pImpl->m_rPositivePercentages.pop();
1667 break;
1668 case NS_ooxml::LN_EG_WrapType_wrapNone: // 90944; - doesn't contain attributes
1669 //depending on the behindDoc attribute text wraps through behind or in front of the object
1670 m_pImpl->m_nWrap = text::WrapTextMode_THROUGH;
1672 // Wrap though means the margins defined earlier should not be
1673 // respected.
1674 m_pImpl->m_nLeftMargin = 0;
1675 m_pImpl->m_nTopMargin = 0;
1676 m_pImpl->m_nRightMargin = 0;
1677 m_pImpl->m_nBottomMargin = 0;
1678 break;
1679 case NS_ooxml::LN_EG_WrapType_wrapTopAndBottom: // 90948;
1680 // tdf#137850: Word >= 2013 seems to ignore bBehindDoc except for wrapNone, but older versions honour it.
1681 if (m_pImpl->m_bBehindDoc && m_pImpl->m_rDomainMapper.GetSettingsTable()->GetWordCompatibilityMode() > 14)
1682 m_pImpl->m_bOpaque = true;
1683 m_pImpl->m_nWrap = text::WrapTextMode_NONE;
1684 break;
1685 case NS_ooxml::LN_CT_GraphicalObject_graphicData:// 90660;
1687 m_pImpl->m_bIsGraphic = true;
1689 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1690 if( pProperties )
1691 pProperties->resolve(*this);
1693 break;
1694 case NS_ooxml::LN_CT_NonVisualDrawingProps_a_hlinkClick: // 90689;
1696 writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
1697 if( pProperties )
1698 pProperties->resolve( *this );
1700 break;
1701 default:
1702 SAL_WARN("writerfilter", "GraphicImport::lcl_sprm: unhandled token: " << nSprmId);
1703 break;
1707 void GraphicImport::lcl_entry(writerfilter::Reference<Properties>::Pointer_t /*ref*/)
1711 uno::Reference<text::XTextContent> GraphicImport::createGraphicObject(uno::Reference<graphic::XGraphic> const & rxGraphic,
1712 uno::Reference<beans::XPropertySet> const & xShapeProps)
1714 uno::Reference<text::XTextContent> xGraphicObject;
1717 if (rxGraphic.is())
1719 uno::Reference< beans::XPropertySet > xGraphicObjectProperties(
1720 m_xTextFactory->createInstance("com.sun.star.text.TextGraphicObject"),
1721 uno::UNO_QUERY_THROW);
1722 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_GRAPHIC), uno::Any(rxGraphic));
1723 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_ANCHOR_TYPE),
1724 uno::Any( m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR ?
1725 text::TextContentAnchorType_AT_CHARACTER :
1726 text::TextContentAnchorType_AS_CHARACTER ));
1727 xGraphicObject.set( xGraphicObjectProperties, uno::UNO_QUERY_THROW );
1729 //shapes have only one border
1730 table::BorderLine2 aBorderLine;
1731 GraphicBorderLine& rBorderLine = m_pImpl->m_aBorders[0];
1732 if (rBorderLine.isEmpty() && xShapeProps.is() && xShapeProps->getPropertyValue("LineStyle").get<drawing::LineStyle>() != drawing::LineStyle_NONE)
1734 // In case we got no border tokens and we have the
1735 // original shape, then use its line properties as the
1736 // border.
1737 aBorderLine.Color = xShapeProps->getPropertyValue("LineColor").get<sal_Int32>();
1738 aBorderLine.LineWidth = xShapeProps->getPropertyValue("LineWidth").get<sal_Int32>();
1740 else
1742 aBorderLine.Color = 0;
1743 aBorderLine.InnerLineWidth = 0;
1744 aBorderLine.OuterLineWidth = static_cast<sal_Int16>(rBorderLine.nLineWidth);
1745 aBorderLine.LineDistance = 0;
1747 PropertyIds const aBorderProps[] =
1749 PROP_LEFT_BORDER,
1750 PROP_RIGHT_BORDER,
1751 PROP_TOP_BORDER,
1752 PROP_BOTTOM_BORDER
1755 for(PropertyIds const & rBorderProp : aBorderProps)
1756 xGraphicObjectProperties->setPropertyValue(getPropertyName(rBorderProp), uno::Any(aBorderLine));
1758 // setting graphic object shadow properties
1759 if (m_pImpl->m_bShadow)
1761 // Shadow width is approximated by average of X and Y
1762 table::ShadowFormat aShadow;
1763 sal_uInt32 nShadowColor = m_pImpl->m_nShadowColor & 0x00FFFFFF; // The shadow color we get is RGB only.
1764 sal_Int32 nShadowWidth = (abs(m_pImpl->m_nShadowXDistance)
1765 + abs(m_pImpl->m_nShadowYDistance)) / 2;
1767 aShadow.ShadowWidth = nShadowWidth;
1768 sal_uInt8 nShadowTransparence = float(m_pImpl->m_nShadowTransparence) * 2.55;
1769 nShadowColor |= (nShadowTransparence << 24); // Add transparence to the color.
1770 aShadow.Color = nShadowColor;
1771 // Distances -ve for top and right, +ve for bottom and left
1772 if (m_pImpl->m_nShadowXDistance > 0)
1774 if (m_pImpl->m_nShadowYDistance > 0)
1775 aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT;
1776 else
1777 aShadow.Location = table::ShadowLocation_TOP_RIGHT;
1779 else
1781 if (m_pImpl->m_nShadowYDistance > 0)
1782 aShadow.Location = table::ShadowLocation_BOTTOM_LEFT;
1783 else
1784 aShadow.Location = table::ShadowLocation_TOP_LEFT;
1787 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_SHADOW_FORMAT), uno::Any(aShadow));
1790 // setting properties for all types
1791 if( m_pImpl->m_bPositionProtected )
1792 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_POSITION_PROTECTED ),
1793 uno::Any(true));
1794 if( m_pImpl->m_bSizeProtected )
1795 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SIZE_PROTECTED ),
1796 uno::Any(true));
1798 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_DECORATIVE), uno::Any(m_pImpl->m_bDecorative));
1799 sal_Int32 nWidth = - m_pImpl->m_nLeftPosition;
1800 if (m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
1802 //adjust margins
1803 if( (m_pImpl->m_nHoriOrient == text::HoriOrientation::LEFT &&
1804 (m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ||
1805 m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME) ) ||
1806 (m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE &&
1807 m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ))
1808 m_pImpl->m_nLeftMargin = 0;
1809 if((m_pImpl->m_nHoriOrient == text::HoriOrientation::RIGHT &&
1810 (m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ||
1811 m_pImpl->m_nHoriRelation == text::RelOrientation::FRAME) ) ||
1812 (m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE &&
1813 m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_PRINT_AREA ))
1814 m_pImpl->m_nRightMargin = 0;
1815 // adjust top/bottom margins
1816 if( m_pImpl->m_nVertOrient == text::VertOrientation::TOP &&
1817 ( m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA ||
1818 m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_FRAME))
1819 m_pImpl->m_nTopMargin = 0;
1820 if( m_pImpl->m_nVertOrient == text::VertOrientation::BOTTOM &&
1821 ( m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA ||
1822 m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_FRAME))
1823 m_pImpl->m_nBottomMargin = 0;
1824 if( m_pImpl->m_nVertOrient == text::VertOrientation::BOTTOM &&
1825 m_pImpl->m_nVertRelation == text::RelOrientation::PAGE_PRINT_AREA )
1826 m_pImpl->m_nBottomMargin = 0;
1827 //adjust alignment
1828 if( m_pImpl->m_nHoriOrient == text::HoriOrientation::INSIDE &&
1829 m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_FRAME )
1831 // convert 'left to page' to 'from left -<width> to page text area'
1832 m_pImpl->m_nHoriOrient = text::HoriOrientation::NONE;
1833 m_pImpl->m_nHoriRelation = text::RelOrientation::PAGE_PRINT_AREA;
1834 m_pImpl->m_nLeftPosition = - nWidth;
1836 else if( m_pImpl->m_nHoriOrient == text::HoriOrientation::OUTSIDE &&
1837 m_pImpl->m_nHoriRelation == text::RelOrientation::PAGE_FRAME )
1839 // convert 'right to page' to 'from left 0 to right page border'
1840 m_pImpl->m_nHoriOrient = text::HoriOrientation::NONE;
1841 m_pImpl->m_nHoriRelation = text::RelOrientation::PAGE_RIGHT;
1842 m_pImpl->m_nLeftPosition = 0;
1845 m_pImpl->applyPosition(xGraphicObjectProperties);
1846 m_pImpl->applyRelativePosition(xGraphicObjectProperties);
1847 if( !m_pImpl->m_bOpaque )
1849 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_OPAQUE ), uno::Any(m_pImpl->m_bOpaque));
1851 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND ),
1852 uno::Any(static_cast<sal_Int32>(m_pImpl->m_nWrap)));
1853 if( m_pImpl->m_rDomainMapper.IsInTable())
1854 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_FOLLOW_TEXT_FLOW ),
1855 uno::Any(m_pImpl->m_bLayoutInCell));
1857 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_ALLOW_OVERLAP),
1858 uno::Any(m_pImpl->m_bAllowOverlap));
1860 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_SURROUND_CONTOUR ),
1861 uno::Any(m_pImpl->m_bContour));
1862 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_CONTOUR_OUTSIDE ),
1863 uno::Any(m_pImpl->m_bContourOutside));
1864 m_pImpl->applyMargins(xGraphicObjectProperties);
1867 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_CONTRAST ),
1868 uno::Any(static_cast<sal_Int16>(m_pImpl->m_nContrast)));
1869 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_ADJUST_LUMINANCE ),
1870 uno::Any(static_cast<sal_Int16>(m_pImpl->m_nBrightness)));
1871 if(m_pImpl->m_eColorMode != drawing::ColorMode_STANDARD)
1873 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_GRAPHIC_COLOR_MODE ),
1874 uno::Any(m_pImpl->m_eColorMode));
1877 xGraphicObjectProperties->setPropertyValue(getPropertyName( PROP_BACK_COLOR ),
1878 uno::Any( GraphicImport_Impl::nFillColor ));
1879 m_pImpl->applyZOrder(xGraphicObjectProperties);
1881 //there seems to be no way to detect the original size via _real_ API
1882 uno::Reference< beans::XPropertySet > xGraphicProperties(rxGraphic, uno::UNO_QUERY_THROW);
1884 if (m_pImpl->mpWrapPolygon)
1886 uno::Any aContourPolyPolygon;
1887 awt::Size aGraphicSize;
1888 WrapPolygon::Pointer_t pCorrected;
1889 xGraphicProperties->getPropertyValue(getPropertyName(PROP_SIZE100th_M_M)) >>= aGraphicSize;
1890 if (aGraphicSize.Width && aGraphicSize.Height)
1892 pCorrected = m_pImpl->mpWrapPolygon->correctWordWrapPolygon(aGraphicSize);
1894 else
1896 xGraphicProperties->getPropertyValue(getPropertyName(PROP_SIZE_PIXEL)) >>= aGraphicSize;
1897 if (aGraphicSize.Width && aGraphicSize.Height)
1899 pCorrected = m_pImpl->mpWrapPolygon->correctWordWrapPolygonPixel(aGraphicSize);
1903 text::GraphicCrop aGraphicCrop;
1904 xShapeProps->getPropertyValue("GraphicCrop") >>= aGraphicCrop;
1905 if (aGraphicCrop.Top != 0 || aGraphicCrop.Bottom != 0 || aGraphicCrop.Left != 0
1906 || aGraphicCrop.Right != 0)
1908 // Word's wrap polygon deals with a canvas which has the size of the already
1909 // cropped graphic, correct our polygon to have the same render result.
1910 pCorrected = pCorrected->correctCrop(aGraphicSize, aGraphicCrop);
1913 if (pCorrected)
1915 aContourPolyPolygon <<= pCorrected->getPointSequenceSequence();
1916 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_CONTOUR_POLY_POLYGON),
1917 aContourPolyPolygon);
1918 // We should bring it to front, even if wp:anchor's behindDoc="1",
1919 // because otherwise paragraph background (if set) overlaps the graphic
1920 // TODO: if paragraph's background becomes bottommost, then remove this hack
1921 xGraphicObjectProperties->setPropertyValue("Opaque", uno::Any(true));
1926 if (m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_INLINE
1927 || m_pImpl->m_rGraphicImportType == IMPORT_AS_DETECTED_ANCHOR)
1929 if( m_pImpl->getXSize() && m_pImpl->getYSize() )
1930 xGraphicObjectProperties->setPropertyValue(getPropertyName(PROP_SIZE),
1931 uno::Any( awt::Size( m_pImpl->getXSize(), m_pImpl->getYSize() )));
1932 m_pImpl->applyMargins(xGraphicObjectProperties);
1933 m_pImpl->applyName(xGraphicObjectProperties);
1934 m_pImpl->applyHyperlink(xGraphicObjectProperties, false);
1937 // Handle horizontal flip.
1938 bool bMirrored = false;
1939 xShapeProps->getPropertyValue("IsMirrored") >>= bMirrored;
1940 if (bMirrored)
1942 xGraphicObjectProperties->setPropertyValue("HoriMirroredOnEvenPages",
1943 uno::Any(true));
1944 xGraphicObjectProperties->setPropertyValue("HoriMirroredOnOddPages",
1945 uno::Any(true));
1949 catch( const uno::Exception& )
1951 TOOLS_WARN_EXCEPTION("writerfilter", "");
1953 return xGraphicObject;
1957 void GraphicImport::data(const sal_uInt8* buf, size_t len)
1959 uno::Reference< io::XInputStream > xIStream = new XInputStreamHelper( buf, len );
1960 beans::PropertyValues aMediaProperties{ comphelper::makePropertyValue(
1961 getPropertyName(PROP_INPUT_STREAM), xIStream) };
1963 uno::Reference<beans::XPropertySet> xPropertySet;
1964 uno::Reference<graphic::XGraphicProvider> xGraphicProvider(graphic::GraphicProvider::create(m_xComponentContext));
1965 uno::Reference<graphic::XGraphic> xGraphic = xGraphicProvider->queryGraphic(aMediaProperties);
1966 m_xGraphicObject = createGraphicObject(xGraphic, xPropertySet);
1970 void GraphicImport::lcl_startSectionGroup()
1975 void GraphicImport::lcl_endSectionGroup()
1980 void GraphicImport::lcl_startParagraphGroup()
1985 void GraphicImport::lcl_endParagraphGroup()
1990 void GraphicImport::lcl_startCharacterGroup()
1995 void GraphicImport::lcl_endCharacterGroup()
2000 void GraphicImport::lcl_text(const sal_uInt8 * /*_data*/, size_t /*len*/)
2005 void GraphicImport::lcl_utext(const sal_uInt8 * /*_data*/, size_t /*len*/)
2010 void GraphicImport::lcl_props(writerfilter::Reference<Properties>::Pointer_t /*ref*/)
2015 void GraphicImport::lcl_table(Id /*name*/, writerfilter::Reference<Table>::Pointer_t /*ref*/)
2020 void GraphicImport::lcl_substream(Id /*name*/, ::writerfilter::Reference<Stream>::Pointer_t /*ref*/)
2024 void GraphicImport::lcl_startShape(uno::Reference<drawing::XShape> const&)
2028 void GraphicImport::lcl_endShape( )
2032 bool GraphicImport::IsGraphic() const
2034 return m_pImpl->m_bIsGraphic;
2037 sal_Int32 GraphicImport::GetLeftMarginOrig() const
2039 return m_pImpl->m_nLeftMarginOrig;
2044 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */