/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// If propagation failed, delete/cleanup here. Since the DiagramHelper // holds a Diagram and that this Shape it is necessary - the destructor // will not be called and will be too late if (nullptr != mpDiagramHelper)
{ delete mpDiagramHelper;
mpDiagramHelper = nullptr;
}
}
if(!pTarget)
{ // no migrate target, but cleanup helper delete mpDiagramHelper;
mpDiagramHelper = nullptr; return;
}
if(pTarget->mpDiagramHelper)
{ // this should no happen, but if there is already a helper, clean it up delete pTarget->mpDiagramHelper;
pTarget->mpDiagramHelper = nullptr;
}
// exchange and reset to nullptr
pTarget->mpDiagramHelper = mpDiagramHelper;
mpDiagramHelper = nullptr;
}
// if this is a group shape, we have to add also each child shape
Reference< XShapes > xShapes( xShape, UNO_QUERY ); if ( xShapes.is() )
addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aMatrix );
if (mbWordprocessingCanvas && !mbWPGChild)
{ // This is a drawing canvas. In case the canvas has no fill and no stroke, Word does // not render shadow or glow, even if it is set for the canvas. Thus we disable shadow // and glow in this case for the ersatz background shape of the drawing canvas. try
{
oox::drawingml::ShapePtr pBgShape = getChildren().front(); const Reference<css::drawing::XShape>& xBgShape = pBgShape->getXShape();
Reference<XPropertySet> xBgProps(xBgShape, uno::UNO_QUERY);
drawing::FillStyle eFillStyle = drawing::FillStyle_NONE;
xBgProps->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle;
drawing::LineStyle eLineStyle = drawing::LineStyle_NONE;
xBgProps->getPropertyValue(u"LineStyle"_ustr) >>= eLineStyle; if (eFillStyle == drawing::FillStyle_NONE
&& eLineStyle == drawing::LineStyle_NONE)
{
xBgProps->setPropertyValue(UNO_NAME_SHADOW, uno::Any(false));
xBgProps->setPropertyValue(u"GlowEffectRadius"_ustr, uno::Any(sal_Int32(0)));
}
} catch (const Exception&)
{
TOOLS_WARN_EXCEPTION("oox.drawingml", "Shape::addShape mbWordprocessingCanvas");
}
}
if (isWPGChild() && xShape)
{ // This is a wps shape and it is the child of the WPG, now copy the // the text body properties to the xshape.
Reference<XPropertySet> xChildWPSProperties(xShape, uno::UNO_QUERY);
if (getTextBody() && xChildWPSProperties)
{
xChildWPSProperties->setPropertyValue(
UNO_NAME_TEXT_VERTADJUST,
uno::Any(getTextBody()->getTextProperties().meVA));
// set DiagramHelper at SdrObjGroup
propagateDiagramHelper();
// Check if this is the PPTX import, so far converting SmartArt to a non-editable // metafile is only implemented for DOCX. bool bPowerPoint = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilterBase) != nullptr;
if (!officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::get() && !bPowerPoint)
convertSmartArtToMetafile( rFilterBase );
}
NamedShapePairs* pNamedShapePairs = rFilterBase.getDiagramFontHeights(); if (xShape.is() && pNamedShapePairs)
{ auto itPairs = pNamedShapePairs->find(getInternalName()); if (itPairs != pNamedShapePairs->end())
{ auto it = itPairs->second.find(shared_from_this()); if (it != itPairs->second.end())
{ // Our drawingml::Shape is in the list of an internal name, remember the now // inserted XShape.
it->second = std::move(xShape);
}
}
}
}
} catch( const Exception& )
{
TOOLS_WARN_EXCEPTION( "oox.drawingml", "Shape::addShape" );
}
}
// LO does not interpret properties in styles belonging to the text content of a FontWork shape, // but only those in the shape style. This method copies properties from the text content styles to // the shape style. staticvoid lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape>& xShape, const TextBodyPtr& pTextBody, const ::oox::core::XmlFilterBase& rFilter)
{ if (!xShape.is() || !pTextBody) return;
Reference<XPropertySet> xSet(xShape, UNO_QUERY); if (!xSet.is()) return;
// Content stretches or scales to given width and height, thus disable autogrow.
xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any(false));
xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any(false));
// LibreOffice is not able (as of Nov 2022) to use different styles for the paragraphs or // characters in FontWork, since that was not allowed in old binary WordArt. We use the // properties of the first non empty paragraph for now. const TextParagraphVector& rParagraphs = pTextBody->getParagraphs(); auto aParaIt = std::find_if_not(rParagraphs.cbegin(), rParagraphs.cend(),
[](const std::shared_ptr<TextParagraph> pParagraph) { return pParagraph->getRuns().empty();
}); if (aParaIt != rParagraphs.cend())
{ const std::shared_ptr<TextParagraph>& pParagraph = *aParaIt; const TextRunVector& rRuns = pParagraph->getRuns(); auto aRunIt = std::find_if_not(rRuns.cbegin(), rRuns.cend(),
[](const std::shared_ptr<TextRun> pRun)
{ return pRun->getText().isEmpty()
|| pRun->getText() == " "
|| pRun->getText().toChar() == 0xA0; // NBSP
}); if (aRunIt != rRuns.cend())
{ const std::shared_ptr<TextRun>& pRun = *aRunIt;
TextCharacterProperties& rCharProps = pRun->getTextCharacterProperties();
// set language if (rCharProps.moLang.has_value() && !rCharProps.moLang.value().isEmpty())
{
LanguageTag aTag(rCharProps.moLang.value()); const css::lang::Locale& aLocale(aTag.getLocale(false)); switch (MsLangId::getScriptType(aTag.getLanguageType()))
{ case css::i18n::ScriptType::LATIN:
xSet->setPropertyValue(u"CharLocale"_ustr, uno::Any(aLocale)); break; case css::i18n::ScriptType::ASIAN:
xSet->setPropertyValue(u"CharLocaleAsian"_ustr, uno::Any(aLocale)); break; case css::i18n::ScriptType::COMPLEX:
xSet->setPropertyValue(u"CharLocaleComplex"_ustr, uno::Any(aLocale)); break; default:;
}
}
// Font Weight, Posture, Height if (rCharProps.moBold.has_value() && rCharProps.moBold.value())
{
xSet->setPropertyValue(UNO_NAME_CHAR_WEIGHT, uno::Any(css::awt::FontWeight::BOLD));
} if (rCharProps.moItalic.has_value() && rCharProps.moItalic.value())
{
xSet->setPropertyValue(UNO_NAME_CHAR_POSTURE,
uno::Any(css::awt::FontSlant::FontSlant_ITALIC));
} if (rCharProps.moHeight.has_value())
{
sal_Int32 nHeight = rCharProps.moHeight.value() / 100;
xSet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::Any(nHeight));
}
// Put theme fonts into shape properties
OUString sFontName;
sal_Int16 nFontPitch = 0;
sal_Int16 nFontFamily = 0; bool bRet(false); if (const Theme* pTheme = rFilter.getCurrentTheme())
{ // minor Latin if (const TextFont* pFont = pTheme->resolveFont(u"+mn-lt"))
{
bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter); if (bRet)
{
xSet->setPropertyValue(u"CharFontName"_ustr, uno::Any(sFontName));
xSet->setPropertyValue(u"CharFontPitch"_ustr, uno::Any(nFontPitch));
xSet->setPropertyValue(u"CharFontFamily"_ustr, uno::Any(nFontFamily));
}
} // minor Asian if (const TextFont* pFont = pTheme->resolveFont(u"+mn-ea"))
{
bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter); if (bRet)
{
xSet->setPropertyValue(u"CharFontNameAsian"_ustr, uno::Any(sFontName));
xSet->setPropertyValue(u"CharFontPitchAsian"_ustr, uno::Any(nFontPitch));
xSet->setPropertyValue(u"CharFontFamilyAsian"_ustr, uno::Any(nFontFamily));
}
} // minor Complex if (const TextFont* pFont = pTheme->resolveFont(u"+mn-cs"))
{
bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter); if (bRet)
{
xSet->setPropertyValue(u"CharFontNameComplex"_ustr, uno::Any(sFontName));
xSet->setPropertyValue(u"CharFontPitchComplex"_ustr, uno::Any(nFontPitch));
xSet->setPropertyValue(u"CharFontFamilyComplex"_ustr, uno::Any(nFontFamily));
}
}
}
// Replace theme fonts with formatting at run if any. ToDo: Inspect paragraph too? // Latin
bRet = rCharProps.maLatinFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter); if (!bRet) // In case there is no direct font, try to look it up as a theme reference.
bRet = rCharProps.maLatinThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
rFilter);
if (bRet)
{
xSet->setPropertyValue(u"CharFontName"_ustr, uno::Any(sFontName));
xSet->setPropertyValue(u"CharFontPitch"_ustr, uno::Any(nFontPitch));
xSet->setPropertyValue(u"CharFontFamily"_ustr, uno::Any(nFontFamily));
} // Asian
bRet = rCharProps.maAsianFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter); if (!bRet) // In case there is no direct font, try to look it up as a theme reference.
bRet = rCharProps.maAsianThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
rFilter); if (bRet)
{
xSet->setPropertyValue(u"CharFontNameAsian"_ustr, uno::Any(sFontName));
xSet->setPropertyValue(u"CharFontPitchAsian"_ustr, uno::Any(nFontPitch));
xSet->setPropertyValue(u"CharFontFamilyAsian"_ustr, uno::Any(nFontFamily));
} // Complex
bRet
= rCharProps.maComplexFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter); if (!bRet) // In case there is no direct font, try to look it up as a theme reference.
bRet = rCharProps.maComplexThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
rFilter); if (bRet)
{
xSet->setPropertyValue(u"CharFontNameComplex"_ustr, uno::Any(sFontName));
xSet->setPropertyValue(u"CharFontPitchComplex"_ustr, uno::Any(nFontPitch));
xSet->setPropertyValue(u"CharFontFamilyComplex"_ustr, uno::Any(nFontFamily));
}
// LO uses shape properties, MS Office character properties. Copy them from char to shape. // Outline if (rCharProps.moTextOutlineProperties.has_value())
{
oox::drawingml::ShapePropertyMap aStrokeShapeProps(rFilter.getModelObjectHelper());
rCharProps.moTextOutlineProperties.value().pushToPropMap(
aStrokeShapeProps, rFilter.getGraphicHelper()); for (constauto& rProp : aStrokeShapeProps.makePropertyValueSequence())
{
xSet->setPropertyValue(rProp.Name, rProp.Value);
}
} else
{
xSet->setPropertyValue(UNO_NAME_LINESTYLE, uno::Any(drawing::LineStyle_NONE));
}
// Fill // ToDo: Replace flip and rotate constants in parameters with actual values. // tdf#155327 If color is not explicitly set, MS Office uses scheme color 'tx1'.
oox::drawingml::ShapePropertyMap aFillShapeProps(rFilter.getModelObjectHelper()); if (!rCharProps.maFillProperties.moFillType.has_value())
rCharProps.maFillProperties.moFillType = XML_solidFill; if (!rCharProps.maFillProperties.maFillColor.isUsed())
rCharProps.maFillProperties.maFillColor.setSchemeClr(XML_tx1);
rCharProps.maFillProperties.pushToPropMap(aFillShapeProps, rFilter.getGraphicHelper(), /*nShapeRotation*/ 0, /*nPhClr*/ API_RGB_TRANSPARENT, /*aShapeSize*/ css::awt::Size(0, 0), /*nPhClrTheme*/ -1, /*bFlipH*/ false, /*bFlipV*/ false, /*bIsCustomShape*/ true); for (constauto& rProp : aFillShapeProps.makePropertyValueSequence())
{
xSet->setPropertyValue(rProp.Name, rProp.Value);
}
// ToDo: Import WordArt glow and simple shadow effects. They are available in LO.
}
// LO does not evaluate paragraph alignment in text path mode. Use text area anchor instead.
{
ParagraphAdjust eAdjust = ParagraphAdjust_LEFT; if (pParagraph->getProperties().getParaAdjust())
eAdjust = *pParagraph->getProperties().getParaAdjust();
xSet->setPropertyValue(u"ParaAdjust"_ustr, uno::Any(eAdjust));
SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
assert(pShape);
SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust(eAdjust);
pShape->SetMergedItem(SdrTextHorzAdjustItem(eHorzAdjust));
}
}
// Vertical adjustment is only meaningful for OOXML WordArt shapes of 'Follow Path' kinds. We set // it so, that text position is approximately same as in MS Office. const OUString sMSPresetType = pTextBody->getTextProperties().msPrst; const OUString sFontworkType = PresetGeometryTypeNames::GetFontworkType(sMSPresetType);
SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
assert(pShape); if (sFontworkType == "fontwork-arch-up-curve" || sFontworkType == "fontwork-circle-curve")
pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM)); elseif (sFontworkType == "fontwork-arch-down-curve")
pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP)); else
pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_CENTER));
}
// Some helper methods for createAndInsert namespace
{ // mirrors aTransformation at its center axis // only valid if neither rotation or shear included void lcl_mirrorAtCenter(basegfx::B2DHomMatrix& aTransformation, bool bFlipH, boolbFlipV)
{ if (!bFlipH && !bFlipV) return;
basegfx::B2DPoint aCenter(0.5, 0.5);
aCenter *= aTransformation;
aTransformation.translate(-aCenter);
aTransformation.scale(bFlipH ? -1.0 : 1.0, bFlipV ? -1.0 : 1.0);
aTransformation.translate(aCenter); return;
}
// only valid if neither rotation or shear included void lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix& aTransformation)
{ // The values are directly set at the matrix without any matrix multiplication. // That way it is valid for lines too. Those have zero width or height. constdouble fSx(aTransformation.get(0, 0)); constdouble fSy(aTransformation.get(1, 1)); constdouble fTx(aTransformation.get(0, 2)); constdouble fTy(aTransformation.get(1, 2));
aTransformation.set(0, 0, fSy);
aTransformation.set(1, 1, fSx);
aTransformation.set(0, 2, fTx + 0.5 * (fSx - fSy));
aTransformation.set(1, 2, fTy + 0.5 * (fSy - fSx)); return;
}
Degree100 lcl_MSORotateAngleToAPIAngle(const sal_Int32 nMSORotationAngle)
{ // Converts a shape rotation angle from MSO to angle for API property RotateAngle // from unit 1/60000 deg to unit 1/100 deg
Degree100 nAngle(nMSORotationAngle / 600); // API RotateAngle has opposite direction than nMSORotationAngle, thus 'minus'. return NormAngle36000(-nAngle);
}
}
formulaimport::XmlStreamBuilder * pMathXml(nullptr); if (mpTextBody)
{ for (autoconst& it : mpTextBody->getParagraphs())
{ if (it->HasMathXml())
{ if (!mpTextBody->isEmpty() || pMathXml != nullptr)
{
SAL_WARN("oox.drawingml", "losing a Math object...");
} else
{
pMathXml = &it->GetMathXml();
}
}
}
}
// tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height if ( mpTablePropertiesPtr && rServiceName == "com.sun.star.drawing.TableShape" )
{
maSize.Width = 0; for (autoconst& elem : mpTablePropertiesPtr->getTableGrid())
{
maSize.Width = o3tl::saturating_add(maSize.Width, static_cast<sal_Int32>(elem));
}
maSize.Height = 0; for (autoconst& elem : mpTablePropertiesPtr->getTableRows())
{ // WARN: If some rows can't fit the content, this is not the final height
maSize.Height = o3tl::saturating_add(maSize.Height, elem.getHeight());
}
}
// Look for 3D. Its z-rotation and extrusion color become shape properties. We consider a // z-rotation of an image even we currently do not extrude an image to 3D-scene. bool bBlockExtrusion = !bIsCustomShape && mp3DPropertiesPtr->mnPreset.has_value(); double fShapeRotateInclCamera = 0.0; // unit rad; same orientation as shape property RotateAngle
Color aExtrusionColor;
Scene3DHelper aScene3DHelper; bool bHas3DEffect = aScene3DHelper.setExtrusionProperties(
mp3DPropertiesPtr, mnRotation, getCustomShapeProperties()->getExtrusionPropertyMap(),
fShapeRotateInclCamera, aExtrusionColor, bBlockExtrusion); // Currently the other places use unit 1/60000deg and MSO shape rotate orientation.
sal_Int32 nShapeRotateInclCamera = -basegfx::rad2deg<60000>(fShapeRotateInclCamera); bool bIs3DGraphic = aServiceName == "com.sun.star.drawing.GraphicObjectShape" && bHas3DEffect;
bIsCustomShape |= bIs3DGraphic;
// The extrusion color does not belong to the extrusion properties but is secondary color in // the style of the shape, FillColor2 in API. The case that no extrusion color was set is handled // further down when FillProperties and LineProperties are handled. if (aExtrusionColor.isUsed())
{ // FillColor2 is not yet transformed to ComplexColor.
::Color aColor = aExtrusionColor.getColor(rFilterBase.getGraphicHelper());
maShapeProperties.setProperty(PROP_FillColor2, aColor);
}
if (bHas3DEffect)
{
aScene3DHelper.setLightingProperties(mp3DPropertiesPtr, fShapeRotateInclCamera,
getCustomShapeProperties()->getExtrusionPropertyMap());
oox::Scene3DHelper::setMaterialProperties(
mp3DPropertiesPtr, getCustomShapeProperties()->getExtrusionPropertyMap());
}
basegfx::B2DHomMatrix aTransformation; // will be cumulative transformation of this object
// Special for SmartArt import. Rotate diagram's shape around object's center before sizing. if (bUseRotationTransform && mnDiagramRotation != 0)
{
aTransformation.translate(-0.5, -0.5);
aTransformation.rotate(basegfx::deg2rad<60000>(mnDiagramRotation));
aTransformation.translate(0.5, 0.5);
}
bool bLineShape = aServiceName == "com.sun.star.drawing.LineShape"; bool bTopWriterLine = !pParentGroupShape && mbWps && bLineShape; // Build object matrix from shape size and position; corresponds to MSO ext and off // Only LineShape and ConnectorShape may have zero width or height. if (bLineShape || aServiceName == "com.sun.star.drawing.ConnectorShape")
{ // For toplevel Writer lines, size is included in the point coordinates. if (!bTopWriterLine)
{
aTransformation.scale(maSize.Width, maSize.Height);
}
} else
{
aTransformation.scale(maSize.Width ? maSize.Width : 1.0,
maSize.Height ? maSize.Height : 1.0);
}
// Evaluate object flip. Other shapes than custom shapes have no attribute for flip but use // negative scale. Flip in MSO is at object center. if (!bIsCustomShape && (mbFlipH || mbFlipV))
lcl_mirrorAtCenter(aTransformation, mbFlipH, mbFlipV);
// Evaluate parent flip. // A CustomShape has mirror not as negative scale, but as attributes.
basegfx::B2DVector aParentScale(1.0, 1.0);
basegfx::B2DVector aParentTranslate(0.0, 0.0); double fParentRotate(0.0); double fParentShearX(0.0); if (pParentGroupShape)
{
aParentTransformation.decompose(aParentScale, aParentTranslate, fParentRotate, fParentShearX); if (bIsCustomShape)
{
lcl_mirrorAtCenter(aTransformation, aParentScale.getX() < 0, aParentScale.getY() < 0); if(aParentScale.getX() < 0)
mbFlipH = !mbFlipH; if(aParentScale.getY() < 0)
mbFlipV = !mbFlipV;
}
}
if (maPosition.X != 0 || maPosition.Y != 0)
{ // if global position is used, add it to transformation if (mbWps && pParentGroupShape == nullptr)
aTransformation.translate(
o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu)); else
aTransformation.translate(maPosition.X, maPosition.Y);
}
// Apply further parent transformations. First scale object then rotate. Other way round would // introduce shearing.
// The attributes chExt and chOff of the group in oox file contain the values on which the size // and position of the child is based on. If they differ from the actual size of the group as // given in its ext and off attributes, the child has to be transformed according the new values. if (pParentGroupShape)
{ // ToDo: A diagram in a group might need special handling because it cannot flip and only // resize uniformly. But currently it is imported with zero size, see tdf#139575. That needs // to be fixed beforehand.
// Scaling is done from left/top edges of the group. So these need to become coordinate axes.
aTransformation.translate(-pParentGroupShape->maChPosition.X,
-pParentGroupShape->maChPosition.Y);
// oox allows zero or missing attribute chExt. In that case the scaling factor is 1. // Transform2DContext::onCreateContext has set maChSize to maSize for groups in oox file in // such cases. For own made groups (e.g. diagrams) that is missing. // The factors cumulate on the way through the parent groups, so we do not use maSize of the // direct parent group but the cumulated value from aParentScale. double fFactorX = 1.0; double fFactorY = 1.0; if (pParentGroupShape->maChSize.Width != 0)
fFactorX = aParentScale.getX() / pParentGroupShape->maChSize.Width; if (pParentGroupShape->maChSize.Height != 0)
fFactorY = aParentScale.getY() / pParentGroupShape->maChSize.Height; if (fFactorX != 1 || fFactorY != 1)
{ // It depends on the object rotation angle whether scaling is applied to switched // width and height. MSO acts strange in that case (as of May 2021). const sal_Int32 nDeg(mnRotation / 60000); constbool bNeedsMSOWidthHeightToggle
= (nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315); if (bNeedsMSOWidthHeightToggle)
lcl_doSpecialMSOWidthHeightToggle(aTransformation);
aTransformation.scale(fFactorX, fFactorY);
if (bNeedsMSOWidthHeightToggle)
{
lcl_doSpecialMSOWidthHeightToggle(aTransformation); // In case of flip the special case needs an additional 180deg rotation. if ((aParentScale.getX() < 0) != (aParentScale.getY() < 0))
lcl_RotateAtCenter(aTransformation, 10800000);
}
}
}
// Apply object rotation at current object center // The flip contained in aParentScale will affect orientation of object rotation angle.
sal_Int16 nOrientation = ((aParentScale.getX() < 0) != (aParentScale.getY() < 0)) ? -1 : 1; // ToDo: Not sure about the restrictions given by bUseRotationTransform. if (bUseRotationTransform && nShapeRotateInclCamera != 0)
{
lcl_RotateAtCenter(aTransformation, nOrientation * nShapeRotateInclCamera);
}
if (fParentRotate != 0.0)
aTransformation.rotate(fParentRotate); if (!aParentTranslate.equalZero())
aTransformation.translate(aParentTranslate);
maShapeProperties.setProperty(PROP_StartPosition, aAWTStartPosition);
maShapeProperties.setProperty(PROP_EndPosition, aAWTEndPosition);
} elseif (!bLineShape || bTopWriterLine)
{ // now set transformation for this object
Reference< XPropertySet > xSet( mxShape, UNO_QUERY ); if (xSet.is())
{ if (bTopWriterLine && !maSize.Width)
{ // Entirely vertical line, set the points and the transform separately to match the ODF // import.
xSet->setPropertyValue(u"PolyPolygon"_ustr, Any(aPolyPolySequence));
xSet->setPropertyValue(u"Transformation"_ustr, Any(aMatrix));
}
if( !msName.isEmpty() )
{
Reference< container::XNamed > xNamed( mxShape, UNO_QUERY ); if( xNamed.is() )
xNamed->setName( msName );
} if( !msDescription.isEmpty() )
{
xSet->setPropertyValue( u"Description"_ustr, Any( msDescription ) );
} if (m_isDecorative)
{
xSet->setPropertyValue(u"Decorative"_ustr, Any(m_isDecorative));
} if (!msMacro.isEmpty())
{
putPropertyToGrabBag(u"mso-sp-macro"_ustr, Any(msMacro));
} if (!msTextLink.isEmpty())
{
putPropertyToGrabBag(u"mso-sp-textlink"_ustr, Any(msTextLink));
} if (!mbFLocksText) // set only if "false", otherwise it will use "true" by default
{
putPropertyToGrabBag(u"mso-sp-fLocksText"_ustr, Any(mbFLocksText));
} if (mbFPublished)
{
putPropertyToGrabBag(u"mso-sp-fPublished"_ustr, Any(mbFPublished));
} if (!msTitle.isEmpty())
{
xSet->setPropertyValue(u"Title"_ustr, Any(msTitle));
}
// get tooltip attribute of <hlinkClick>
OUString sTooltip;
getShapeProperties().getProperty(PROP_Representation) >>= sTooltip; if (!sTooltip.isEmpty())
putPropertyToGrabBag(u"mso-hlinkClick-tooltip"_ustr, Any(sTooltip));
// Placeholder uses the height set on the slide instead of the height from the master slide, // if it has the "TextAutoGrowHeight" property if (getTextBody() && mxShape->getShapeType().startsWith("com.sun.star.presentation."))
{ bool bAutoGrowHeight = getTextBody()
->getTextProperties()
.maPropertyMap.getProperty(PROP_TextAutoGrowHeight)
.get<bool>(); if (bAutoGrowHeight)
{
ppt::PowerPointImport* pPPT = dynamic_cast<ppt::PowerPointImport*>(&rFilterBase); if (!pPPT->getActualSlidePersist()->isMasterPage())
{
sal_Int32 nUpper = 0;
sal_Int32 nLower = 0;
sal_Int32 nHeight = maSize.Height / 360; if (getTextBody()->getTextProperties().moInsets[1].has_value()
&& getTextBody()->getTextProperties().moInsets[3].has_value())
{
nUpper = *getTextBody()->getTextProperties().moInsets[1];
nLower = *getTextBody()->getTextProperties().moInsets[3];
} else
{
maDefaultShapeProperties.getProperty(PROP_TextUpperDistance) >>= nUpper;
maDefaultShapeProperties.getProperty(PROP_TextLowerDistance) >>= nLower;
}
nHeight -= (nUpper + nLower);
mxShape->setSize(awt::Size(0, nHeight));
}
} else// the placeholder uses the height set on the master slide
mxShape->setSize(awt::Size(0, 0));
}
if (aServiceName != "com.sun.star.text.TextFrame")
rxShapes->add( mxShape );
if ( mbHidden || mbHiddenMasterShape )
{
SAL_INFO("oox.drawingml", "Shape::createAndInsert: invisible shape with id='" << msId << "'");
xSet->setPropertyValue( u"Visible"_ustr, Any( false ) ); // In Excel hidden means not printed, let's use visibility for now until that's handled separately
xSet->setPropertyValue( u"Printable"_ustr, Any( false ) );
}
if (mbLocked)
{
xSet->setPropertyValue(u"MoveProtect"_ustr, Any(true));
xSet->setPropertyValue(u"SizeProtect"_ustr, Any(true));
}
ActionLockGuard const alg(mxShape);
// sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape if ( bClearText )
{
uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); if ( xText.is() )
{
xText->setString( u""_ustr );
}
}
if (pMathXml)
{ // the "EmbeddedObject" property is read-only, so we have to create // the shape first, and it can be read only after the shape is // inserted into the document, so delay the actual import until here
SvGlobalName name(SO3_SM_CLASSID);
xSet->setPropertyValue(u"CLSID"_ustr, uno::Any(name.GetHexName()));
uno::Reference<embed::XEmbeddedObject> const xObj(
xSet->getPropertyValue(u"EmbeddedObject"_ustr), uno::UNO_QUERY); if (xObj.is())
{
uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent());
oox::FormulaImExportBase *const pMagic( dynamic_cast<oox::FormulaImExportBase*>(xMathModel.get()));
assert(pMagic);
pMagic->readFormulaOoxml(*pMathXml);
}
}
::Color nLinePhClr(ColorTransparency, 0xffffffff);
::Color nFillPhClr(ColorTransparency, 0xffffffff);
sal_Int16 nFillPhClrTheme = -1;
sal_Int16 nLinePhClrTheme = -1; // TODO: use ph color when applying effect properties //sal_Int32 nEffectPhClr = -1;
// dmapper needs the original rotation angle for calculating square wrap. This angle is not // available as property there, so store it in InteropGrabBag.
putPropertyToGrabBag(u"mso-rotation-angle"_ustr, Any(mnRotation));
// Store style-related properties to InteropGrabBag to be able to export them back
uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
{
{"SchemeClr", uno::Any(pEffectRef->maPhClr.getSchemeColorName())},
{"Idx", uno::Any(pEffectRef->mnThemedIdx)},
{"Transformations", uno::Any(pEffectRef->maPhClr.getTransformations())}
});
putPropertyToGrabBag( u"StyleEffectRef"_ustr, Any( aProperties ) );
}
}
ShapePropertyMap aShapeProps( rFilterBase.getModelObjectHelper() );
// add properties from textbody to shape properties if( mpTextBody )
{ // tdf#67347: In case of Stacked, PP calculates in the vertical direction with the // horizontal alignment. // In LO, we simulate it by setting TextVerticalAdjust based on the ParagraphAdjust // of the 1. paragraph // It is not perfect, because we have 1 TextVerticalAdjust / 1 shape, and it // does not support justified, while we can have many ParagraphAdjust / 1 shape // (if the shape have more paragraphs) if (mpTextBody->getTextProperties().maPropertyMap.hasProperty(PROP_WritingMode)
&& mpTextBody->getTextProperties().maPropertyMap.getProperty(PROP_WritingMode)
== uno::Any(text::WritingMode2::STACKED)
&& mpTextBody->getParagraphs().size() > 0
&& aServiceName != "com.sun.star.drawing.GroupShape")
{
std::optional<css::style::ParagraphAdjust>& oParaAdjust
= mpTextBody->getParagraphs()[0]->getProperties().getParaAdjust();
if (oParaAdjust)
{ switch (*oParaAdjust)
{ case ParagraphAdjust::ParagraphAdjust_LEFT:
mpTextBody->getTextProperties().meVA
= TextVerticalAdjust::TextVerticalAdjust_TOP; break; case ParagraphAdjust::ParagraphAdjust_CENTER:
mpTextBody->getTextProperties().meVA
= TextVerticalAdjust::TextVerticalAdjust_CENTER; break; case ParagraphAdjust::ParagraphAdjust_RIGHT:
mpTextBody->getTextProperties().meVA
= TextVerticalAdjust::TextVerticalAdjust_BOTTOM; break; default: break;
}
mpTextBody->getTextProperties().maPropertyMap.setProperty(
PROP_TextVerticalAdjust, mpTextBody->getTextProperties().meVA);
}
}
// tdf#162571: In case of shapes with TextAutoGrowHeight, PP calculates/grow the // shapes size in edit mode (typing) based on the text horizontal alignment. // In LO, we simulate it by setting TextHorizontalAdjust based on the ParagraphAdjust // of the 1. paragraph // It is not perfect, because we have 1 TextHorizontalAdjust / 1 shape, // while we can have many ParagraphAdjust / 1 shape if (!mpTextBody->getTextProperties().maPropertyMap.hasProperty(PROP_WritingMode)
&& mpTextBody->getParagraphs().size() > 0)
{
std::optional<css::style::ParagraphAdjust>& oParaAdjust
= mpTextBody->getParagraphs()[0]->getProperties().getParaAdjust();
mpTextBody->getTextProperties().pushTextDistances(Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
aShapeProps.assignUsed( mpTextBody->getTextProperties().maPropertyMap ); // Push char properties as well - specifically useful when this is a placeholder if( mpMasterTextListStyle && mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.has_value() )
aShapeProps.setProperty(PROP_CharHeight, GetFontHeight( mpMasterTextListStyle->getListStyle()[0].getTextCharacterProperties().moHeight.value() ));
}
LineProperties aLineProperties = getActualLineProperties(pTheme);
aLineProperties.pushToPropMap( aShapeProps, rGraphicHelper, nLinePhClr, nLinePhClrTheme);
EffectProperties aEffectProperties = getActualEffectProperties(pTheme); // TODO: use ph color when applying effect properties
aEffectProperties.pushToPropMap( aShapeProps, rGraphicHelper );
// applying autogrowheight property before setting shape size, because // the shape size might be changed if currently autogrowheight is true // we must also check that the PropertySet supports the property.
Reference< XPropertySetInfo > xSetInfo( xSet->getPropertySetInfo() ); const OUString& rPropName = PropertyMap::getPropertyName( PROP_TextAutoGrowHeight ); if( xSetInfo.is() && xSetInfo->hasPropertyByName( rPropName ) ) if( aShapeProps.hasProperty( PROP_TextAutoGrowHeight ) )
xSet->setPropertyValue( rPropName, Any( false ) );
// For extruded shapes, MSO uses the line color if no extrusion color is specified. LO uses // fill color in 'automatic' case. Thus we set extrusion color explicitly. if (bHas3DEffect && !aExtrusionColor.isUsed())
{ const OUString& rFillColor2PropName = PropertyMap::getPropertyName(PROP_FillColor2); if (xSetInfo.is() && xSetInfo->hasPropertyByName(rFillColor2PropName))
{
Color aComplexColor; if (aLineProperties.maLineFill.moFillType.has_value()
&& aLineProperties.maLineFill.moFillType.value() != XML_noFill)
aComplexColor = aLineProperties.maLineFill.getBestSolidColor(); elseif (aFillProperties.moFillType.has_value()
&& aFillProperties.moFillType.value() != XML_noFill)
aComplexColor = aFillProperties.getBestSolidColor(); if (aComplexColor.isUsed())
{ const ::Color aSimpleColor = aComplexColor.getColor(rFilterBase.getGraphicHelper());
xSet->setPropertyValue(rFillColor2PropName, Any(aSimpleColor));
}
}
}
// do not set properties at a group shape (this causes // assertions from svx) ... if( aServiceName != "com.sun.star.drawing.GroupShape" )
{ if (aServiceName == "com.sun.star.text.TextFrame")
{ if (mpCustomShapePropertiesPtr && mpCustomShapePropertiesPtr->getShapeTypeOverride())
{
uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
uno::Sequence<beans::PropertyValue> aGrabBag;
propertySet->getPropertyValue(u"FrameInteropGrabBag"_ustr) >>= aGrabBag;
sal_Int32 length = aGrabBag.getLength();
aGrabBag.realloc( length+1); auto pGrabBag = aGrabBag.getArray();
pGrabBag[length].Name = "mso-orig-shape-type";
pGrabBag[length].Value <<= mpCustomShapePropertiesPtr->getShapePresetTypeName();
propertySet->setPropertyValue(u"FrameInteropGrabBag"_ustr,uno::Any(aGrabBag));
} //If the text box has links then save the link information so that //it can be accessed in DomainMapper_Impl.cxx while chaining the text frames. if (isLinkedTxbx())
{
uno::Reference<beans::XPropertySet> propertySet (mxShape, uno::UNO_QUERY);
uno::Sequence<beans::PropertyValue> aGrabBag;
propertySet->getPropertyValue(u"FrameInteropGrabBag"_ustr) >>= aGrabBag;
sal_Int32 length = aGrabBag.getLength();
aGrabBag.realloc( length + 3 ); auto pGrabBag = aGrabBag.getArray();
pGrabBag[length].Name = "TxbxHasLink";
pGrabBag[length].Value <<= isLinkedTxbx();
pGrabBag[length + 1 ].Name = "Txbx-Id";
pGrabBag[length + 1 ].Value <<= getLinkedTxbxAttributes().id;
pGrabBag[length + 2 ].Name = "Txbx-Seq";
pGrabBag[length + 2 ].Value <<= getLinkedTxbxAttributes().seq;
propertySet->setPropertyValue(u"FrameInteropGrabBag"_ustr,uno::Any(aGrabBag));
}
// TextFrames have BackColor, not FillColor if (aShapeProps.hasProperty(PROP_FillColor))
{
aShapeProps.setAnyProperty(PROP_BackColor, aShapeProps.getProperty(PROP_FillColor));
aShapeProps.erase(PROP_FillColor);
} // TextFrames have BackColorTransparency, not FillTransparence if (aShapeProps.hasProperty(PROP_FillTransparence))
{
aShapeProps.setAnyProperty(PROP_BackColorTransparency, aShapeProps.getProperty(PROP_FillTransparence));
aShapeProps.erase(PROP_FillTransparence);
} // TextFrames have BackGraphic, not FillBitmap if (aShapeProps.hasProperty(PROP_FillBitmap))
{
aShapeProps.setAnyProperty(PROP_BackGraphic, aShapeProps.getProperty(PROP_FillBitmap));
aShapeProps.erase(PROP_FillBitmap);
} if (aShapeProps.hasProperty(PROP_FillBitmapName))
{
uno::Any aAny = aShapeProps.getProperty(PROP_FillBitmapName);
OUString aFillBitmapName = aAny.get<OUString>();
uno::Reference<awt::XBitmap> xBitmap = rFilterBase.getModelObjectHelper().getFillBitmap(aFillBitmapName);
uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY);
aShapeProps.setProperty(PROP_BackGraphic, xGraphic); // aShapeProps.erase(PROP_FillBitmapName); // Maybe, leave the name as well
} // And no LineColor property; individual borders can have colors if (aShapeProps.hasProperty(PROP_LineColor))
{
uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY); staticconst sal_Int32 aBorders[] =
{
PROP_TopBorder, PROP_LeftBorder, PROP_BottomBorder, PROP_RightBorder
}; for (sal_Int32 nBorder : aBorders)
{
css::table::BorderLine2 aBorderLine = xPropertySet->getPropertyValue(PropertyMap::getPropertyName(nBorder)).get<css::table::BorderLine2>();
aBorderLine.Color = aShapeProps.getProperty(PROP_LineColor).get<sal_Int32>(); if (aLineProperties.moLineWidth.has_value())
aBorderLine.LineWidth = convertEmuToHmm(aLineProperties.moLineWidth.value());
aShapeProps.setProperty(nBorder, aBorderLine);
}
aShapeProps.erase(PROP_LineColor);
} if(mnRotation)
{
uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY); static constexpr OUString aGrabBagPropName = u"FrameInteropGrabBag"_ustr;
uno::Sequence<beans::PropertyValue> aGrabBag;
xPropertySet->getPropertyValue(aGrabBagPropName) >>= aGrabBag;
beans::PropertyValue aPair(comphelper::makePropertyValue(u"mso-rotation-angle"_ustr,
mnRotation)); if (aGrabBag.hasElements())
{
sal_Int32 nLength = aGrabBag.getLength();
aGrabBag.realloc(nLength + 1);
aGrabBag.getArray()[nLength] = std::move(aPair);
} else
{
aGrabBag = { std::move(aPair) };
}
xPropertySet->setPropertyValue(aGrabBagPropName, uno::Any(aGrabBag));
} // TextFrames have ShadowFormat, not individual shadow properties.
std::optional<sal_Int32> oShadowDistance; if (aShapeProps.hasProperty(PROP_ShadowXDistance))
{
oShadowDistance = aShapeProps.getProperty(PROP_ShadowXDistance).get<sal_Int32>();
aShapeProps.erase(PROP_ShadowXDistance);
} if (aShapeProps.hasProperty(PROP_ShadowYDistance))
{ // There is a single 'dist' attribute, so no need to count the avg of x and y.
aShapeProps.erase(PROP_ShadowYDistance);
}
std::optional<sal_Int32> oShadowColor; if (aShapeProps.hasProperty(PROP_ShadowColor))
{
oShadowColor = aShapeProps.getProperty(PROP_ShadowColor).get<sal_Int32>();
aShapeProps.erase(PROP_ShadowColor);
} if (aShapeProps.hasProperty(PROP_Shadow))
aShapeProps.erase(PROP_Shadow);
if (oShadowDistance || oShadowColor || aEffectProperties.maShadow.moShadowDir.has_value())
{
css::table::ShadowFormat aFormat; if (oShadowColor)
aFormat.Color = *oShadowColor; if (aEffectProperties.maShadow.moShadowDir.has_value())
{
css::table::ShadowLocation nLocation = css::table::ShadowLocation_NONE; switch (aEffectProperties.maShadow.moShadowDir.value())
{ case 13500000:
nLocation = css::table::ShadowLocation_TOP_LEFT; break; case 18900000:
nLocation = css::table::ShadowLocation_TOP_RIGHT; break; case 8100000:
nLocation = css::table::ShadowLocation_BOTTOM_LEFT; break; case 2700000:
nLocation = css::table::ShadowLocation_BOTTOM_RIGHT; break;
}
aFormat.Location = nLocation;
}
aFormat.ShadowWidth = *oShadowDistance;
aShapeProps.setProperty(PROP_ShadowFormat, aFormat);
}
} elseif (mbTextBox)
{ // This introduces a TextBox in a shape in Writer. ToDo: Can we restrict it to cases // where the TextBox edit engine is really needed? tdf#82627
aShapeProps.setProperty(PROP_TextBox, true);
}
if (mpTablePropertiesPtr && aServiceName == "com.sun.star.drawing.TableShape")
{ // Powerpoint exports desired row heights (i.e. what user attempted to set it as, not how it appears visually) // Expand table height if there are rows that can't fit the content if (auto* pTableShape = dynamic_cast<sdr::table::SdrTableObj*>(SdrObject::getSdrObjectFromXShape(mxShape)))
{
tools::Rectangle aArea{};
pTableShape->LayoutTableHeight(aArea);
sal_Int32 nCorrectedHeight = aArea.GetHeight(); constauto aShapeSize = mxShape->getSize(); if( nCorrectedHeight > aShapeSize.Height )
mxShape->setSize( {aShapeSize.Width, nCorrectedHeight} );
pTableShape->SetSkipChangeLayout(false);
}
}
if (mbLockedCanvas)
{
putPropertyToGrabBag( u"LockedCanvas"_ustr, Any( true ) ); if (aServiceName == "com.sun.star.drawing.LineShape")
{ // It seems the position and size for lines inside a locked canvas is absolute.
mxShape->setPosition(awt::Point(aShapeRectHmm.X, aShapeRectHmm.Y));
mxShape->setSize(awt::Size(aShapeRectHmm.Width, aShapeRectHmm.Height));
}
}
if (mbWordprocessingCanvas)
{
putPropertyToGrabBag(u"WordprocessingCanvas"_ustr, Any(true));
}
// Store original fill and line colors of the shape and the theme color name to InteropGrabBag
std::vector<beans::PropertyValue> aProperties
{
comphelper::makePropertyValue(u"EmuLineWidth"_ustr, aLineProperties.moLineWidth.value_or(0)),
comphelper::makePropertyValue(u"OriginalSolidFillClr"_ustr, aShapeProps.getProperty(PROP_FillColor)),
comphelper::makePropertyValue(u"OriginalLnSolidFillClr"_ustr, aShapeProps.getProperty(PROP_LineColor))
};
OUString sColorFillScheme = aFillProperties.maFillColor.getSchemeColorName(); if( !aFillProperties.maFillColor.isPlaceHolder() && !sColorFillScheme.isEmpty() )
{
aProperties.push_back(comphelper::makePropertyValue(u"SpPrSolidFillSchemeClr"_ustr, sColorFillScheme));
aProperties.push_back(comphelper::makePropertyValue(u"SpPrSolidFillSchemeClrTransformations"_ustr, aFillProperties.maFillColor.getTransformations()));
}
OUString sLnColorFillScheme = aLineProperties.maLineFill.maFillColor.getSchemeColorName(); if( !aLineProperties.maLineFill.maFillColor.isPlaceHolder() && !sLnColorFillScheme.isEmpty() )
{
aProperties.push_back(comphelper::makePropertyValue(u"SpPrLnSolidFillSchemeClr"_ustr, sLnColorFillScheme)); auto aResolvedSchemeClr = aLineProperties.maLineFill.maFillColor;
aResolvedSchemeClr.clearTransformations();
aProperties.push_back(comphelper::makePropertyValue(u"SpPrLnSolidFillResolvedSchemeClr"_ustr, aResolvedSchemeClr.getColor(rGraphicHelper, nFillPhClr)));
aProperties.push_back(comphelper::makePropertyValue(u"SpPrLnSolidFillSchemeClrTransformations"_ustr, aLineProperties.maLineFill.maFillColor.getTransformations()));
}
putPropertiesToGrabBag(comphelper::containerToSequence(aProperties));
// Store original gradient fill of the shape to InteropGrabBag // LibreOffice doesn't support all the kinds of gradient so we save its complete definition if( aShapeProps.hasProperty( PROP_FillGradient ) )
{
std::vector<beans::PropertyValue> aGradientStops;
size_t i = 0; for( constauto& [rPos, rColor] : aFillProperties.maGradientProps.maGradientStops )
{ // for each stop in the gradient definition:
// save position
std::vector<beans::PropertyValue> aGradientStop
{
comphelper::makePropertyValue(u"Pos"_ustr, rPos)
};
OUString sStopColorScheme = rColor.getSchemeColorName(); if( sStopColorScheme.isEmpty() )
{ // save RGB color
aGradientStop.push_back(comphelper::makePropertyValue(u"RgbClr"_ustr, rColor.getColor(rGraphicHelper, nFillPhClr))); // in the case of a RGB color, transformations are already applied to // the color with the exception of alpha transformations. We only need // to keep the transparency value to calculate the alpha value later. if( rColor.hasTransparency() )
aGradientStop.push_back(comphelper::makePropertyValue(u"Transparency"_ustr, rColor.getTransparency()));
} else
{ // save color with scheme name
aGradientStop.push_back(comphelper::makePropertyValue(u"SchemeClr"_ustr, sStopColorScheme)); // save all color transformations
aGradientStop.push_back(comphelper::makePropertyValue(u"Transformations"_ustr, rColor.getTransformations()));
}
aGradientStops.push_back(comphelper::makePropertyValue(OUString::number(i), comphelper::containerToSequence(aGradientStop)));
++i;
} // If getFillProperties.moFillType is unused that means gradient is defined by a theme // which is already saved into StyleFillRef property, so no need to save the explicit values too if( getFillProperties().moFillType.has_value() )
putPropertyToGrabBag( u"GradFillDefinition"_ustr, uno::Any(comphelper::containerToSequence(aGradientStops)));
putPropertyToGrabBag( u"OriginalGradFill"_ustr, aShapeProps.getProperty(PROP_FillGradient) );
}
// store unsupported effect attributes in the grab bag if (!aEffectProperties.m_Effects.empty())
{
std::vector<beans::PropertyValue> aEffects; for (autoconst& it : aEffectProperties.m_Effects)
{
PropertyValue aEffect = it->getEffect(); if( !aEffect.Name.isEmpty() )
{
std::vector<beans::PropertyValue> aEffectsGrabBag
{
comphelper::makePropertyValue(u"Attribs"_ustr, aEffect.Value)
};
Color& aColor( it->moColor );
OUString sColorScheme = aColor.getSchemeColorName(); if( sColorScheme.isEmpty() )
{ // RGB color and transparency value
aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"RgbClr"_ustr, aColor.getColor(rGraphicHelper, nFillPhClr)));
aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"RgbClrTransparency"_ustr, aColor.getTransparency()));
} else
{ // scheme color with name and transformations
aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"SchemeClr"_ustr, sColorScheme));
aEffectsGrabBag.push_back(comphelper::makePropertyValue(u"SchemeClrTransformations"_ustr, aColor.getTransformations()));
}
aEffects.push_back(comphelper::makePropertyValue(aEffect.Name, comphelper::containerToSequence(aEffectsGrabBag)));
}
}
putPropertyToGrabBag(u"EffectProperties"_ustr, uno::Any(comphelper::containerToSequence(aEffects)));
}
// add 3D effects if any to GrabBag. They are still used in export.
Sequence< PropertyValue > aCamera3DEffects = get3DProperties().getCameraAttributes();
Sequence< PropertyValue > aLightRig3DEffects = get3DProperties().getLightRigAttributes();
Sequence< PropertyValue > aShape3DEffects = get3DProperties().getShape3DAttributes( rGraphicHelper, nFillPhClr ); if( aCamera3DEffects.hasElements() || aLightRig3DEffects.hasElements() || aShape3DEffects.hasElements() )
{
uno::Sequence<beans::PropertyValue> a3DEffectsGrabBag = comphelper::InitPropertySequence(
{
{"Camera", uno::Any(aCamera3DEffects)},
{"LightRig", uno::Any(aLightRig3DEffects)},
{"Shape3D", uno::Any(aShape3DEffects)}
});
putPropertyToGrabBag( u"3DEffectProperties"_ustr, Any( a3DEffectsGrabBag ) );
}
// store bitmap artistic effects in the grab bag if( !mpGraphicPropertiesPtr->maBlipProps.maEffect.isEmpty() )
putPropertyToGrabBag( u"ArtisticEffectProperties"_ustr,
Any( mpGraphicPropertiesPtr->maBlipProps.maEffect.getEffect() ) );
}
elseif( mbLockedCanvas )
{ //If we have aServiceName as "com.sun.star.drawing.GroupShape" and lockedCanvas
putPropertyToGrabBag( u"LockedCanvas"_ustr, Any( true ) );
} elseif (mbWordprocessingCanvas)
{
putPropertyToGrabBag(u"WordprocessingCanvas"_ustr, Any(true));
putPropertyToGrabBag(u"mso-edit-as"_ustr, Any(u"canvas"_ustr)); // for export VML Fallback
}
// These can have a custom geometry, so position should be set here, // after creation but before custom shape handling, using the position // we got from the caller. if (mbWps && aServiceName == "com.sun.star.drawing.LineShape" && !pParentGroupShape)
mxShape->setPosition(maPosition);
SdrObject* pShape = SdrObject::getSdrObjectFromXShape(mxShape); if (pShape)
aOrigSize = pShape->GetLogicRect();
if (bIsConnectorShape)
{
msConnectorName = mpCustomShapePropertiesPtr->getShapePresetTypeName();
constauto& aAdjustmentList = mpCustomShapePropertiesPtr->getAdjustmentGuideList(); for (size_t i = 0; i < aAdjustmentList.size(); i++)
maConnectorAdjustmentList.push_back(aAdjustmentList[i].maFormula);
sal_Int32 nType = mpCustomShapePropertiesPtr->getShapePresetType(); switch (nType)
{ case XML_line: case XML_straightConnector1:
xSet->setPropertyValue(u"EdgeKind"_ustr, Any(ConnectorType_LINE)); break; case XML_bentConnector2: case XML_bentConnector3: case XML_bentConnector4: case XML_bentConnector5:
xSet->setPropertyValue(u"EdgeKind"_ustr, Any(ConnectorType_STANDARD)); break; case XML_curvedConnector2: case XML_curvedConnector3: case XML_curvedConnector4: case XML_curvedConnector5:
xSet->setPropertyValue(u"EdgeKind"_ustr, Any(ConnectorType_CURVE)); break; default: break;
}
}
// TextPreRotateAngle. Text rotates inside the text area. Might be used for diagram layout 'upr' and 'grav'.
sal_Int32 nTextPreRotateAngle = static_cast< sal_Int32 >( getTextBody()->getTextProperties().moTextPreRotation.value_or( 0 ) );
nTextPreRotateAngle -= mnDiagramRotation; // Use of mnDiagramRotation is unclear. It seems to be always 0 here.
// TextRotateAngle. The text area rotates.
sal_Int32 nTextAreaRotateAngle = getTextBody()->getTextProperties().moTextAreaRotation.value_or(0); if (getTextBody()->getTextProperties().moUpright)
{ // When upright is set, any text area transformation and shape rotation is ignored // in MS Office. To simulate this behaviour, we rotate the text area into the // opposite direction of the shape rotation by as much as the shape was rotated // and so compensate the shape rotation, which is added in rendering.
nTextAreaRotateAngle = -mnRotation; // If 45° <= shape rotation < 135° or 225° <= shape rotation < 315°, // then MS Office adds an additional 90° rotation to the text area. const sal_Int32 nDeg(mnRotation / 60000); if ((nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315))
{
nTextAreaRotateAngle += 5400000;
nTextPreRotateAngle -= 5400000; // compensate the additional text area rotation
}
putPropertyToGrabBag(u"Upright"_ustr, Any(true));
} /* OOX measures text rotation clockwise in 1/60000th degrees,
relative to the containing shape. set*Angle wants degrees counter-clockwise. */
mpCustomShapePropertiesPtr->setTextPreRotateAngle(-nTextPreRotateAngle / 60000); if (nTextAreaRotateAngle != 0)
mpCustomShapePropertiesPtr->setTextAreaRotateAngle(-nTextAreaRotateAngle / 60000);
auto sHorzOverflow = getTextBody()->getTextProperties().msHorzOverflow; if (!sHorzOverflow.isEmpty())
putPropertyToGrabBag(u"horzOverflow"_ustr, uno::Any(getTextBody()->getTextProperties().msHorzOverflow)); if (XML_ellipsis == getTextBody()->getTextProperties().moVertOverflow)
putPropertyToGrabBag(u"vertOverflow"_ustr, uno::Any(u"ellipsis"_ustr));
}
// Note that the script oox/source/drawingml/customshapes/generatePresetsData.pl looks // for these ==cscode== and ==csdata== markers, so don't "clean up" these SAL_INFOs
SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'");
SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'");
// tdf#133037: a bit hackish: force Shape to rotate in the opposite direction the camera would rotate
PropertySet aPropertySet(mxShape); if ( !bUseRotationTransform && (nShapeRotateInclCamera !=0) )
{
Degree100 nAngle(lcl_MSORotateAngleToAPIAngle(nShapeRotateInclCamera));
aPropertySet.setAnyProperty(PROP_RotateAngle, Any( sal_Int32(nAngle)));
aPropertySet.setAnyProperty( PROP_HoriOrientPosition, Any( maPosition.X ) );
aPropertySet.setAnyProperty( PROP_VertOrientPosition, Any( maPosition.Y ) );
}
// Make sure to not set text to placeholders. Doing it here would eventually call // SvxTextEditSourceImpl::UpdateData, SdrObject::SetEmptyPresObj(false), and that // would make the object behave like a standard outline object. // TODO/FIXME: support custom prompt text in placeholders. if (rServiceName == "com.sun.star.presentation.GraphicObjectShape")
mpTextBody.reset();
// in some cases, we don't have any text body. if( mpTextBody && ( !bDoNotInsertEmptyTextBody || !mpTextBody->isEmpty() ) )
{
Reference < XText > xText( mxShape, UNO_QUERY ); if ( xText.is() ) // not every shape is supporting an XText interface (e.g. GroupShape)
{
TextCharacterProperties aCharStyleProperties; if( const ShapeStyleRef* pFontRef = getShapeStyleRef( XML_fontRef ) )
{ if( pFontRef->mnThemedIdx != 0 )
{ if( pTheme ) if( const TextCharacterProperties* pCharProps = pTheme->getFontStyle( pFontRef->mnThemedIdx ) )
aCharStyleProperties.assignUsed( *pCharProps );
SAL_INFO("oox.drawingml", "Shape::createAndInsert: use font color"); if ( pFontRef->maPhClr.isUsed() )
{
aCharStyleProperties.maFillProperties.maFillColor = pFontRef->maPhClr;
aCharStyleProperties.maFillProperties.moFillType = XML_solidFill;
}
}
}
xText->setString(u""_ustr);
Reference < XTextCursor > xAt = xText->createTextCursor();
getTextBody()->insertAt( rFilterBase, xText, xAt, aCharStyleProperties, mpMasterTextListStyle );
const TextParagraphVector& rParagraphs = getTextBody()->getParagraphs(); if (!rParagraphs.empty())
{ const std::shared_ptr<TextParagraph>& pParagraph = rParagraphs[0]; if (pParagraph->getProperties().getParaAdjust())
{
style::ParagraphAdjust eAdjust = *pParagraph->getProperties().getParaAdjust(); if (eAdjust == style::ParagraphAdjust_CENTER)
{ // If the first paragraph is centered, then set the para adjustment of // the shape itself to centered as well.
aPropertySet.setAnyProperty(PROP_ParaAdjust, uno::Any(eAdjust));
}
}
// tdf#144092 For empty textboxes push character styles & // endParaRPr into the Shape's properties if (rParagraphs.size() == 1 && pParagraph->getRuns().empty())
{
TextCharacterProperties aTextCharacterProps{ pParagraph->getCharacterStyle(
aCharStyleProperties, *mpMasterTextListStyle,
getTextBody()->getTextListStyle()) };
aTextCharacterProps.assignUsed(pParagraph->getEndProperties());
aTextCharacterProps.pushToPropSet(aPropertySet, rFilterBase);
}
}
// MS Office has e.g. fill and stroke of WordArt in the character properties, // LibreOffice uses shape properties. if (!mpTextBody->getTextProperties().msPrst.isEmpty()
&& mpTextBody->getTextProperties().msPrst != u"textNoShape")
{
lcl_copyCharPropsToShape(mxShape, mpTextBody, rFilterBase);
}
}
} elseif (mbTextBox)
{ // No drawingML text, but WPS text is expected: save the theme // character color on the shape, then. if(const ShapeStyleRef* pFontRef = getShapeStyleRef(XML_fontRef))
{
::Color nCharColor = pFontRef->maPhClr.getColor(rGraphicHelper);
aPropertySet.setAnyProperty(PROP_CharColor, uno::Any(nCharColor));
}
}
// Set the stroke and fill-color properties of the OLE shape if (aServiceName == "com.sun.star.drawing.OLE2Shape" && mxOleObjectInfo
&& !mxOleObjectInfo->maShapeId.isEmpty()) if (::oox::vml::Drawing* pVmlDrawing = rFilterBase.getVmlDrawing()) if (const ::oox::vml::ShapeBase* pVmlShape
= pVmlDrawing->getShapes().getShapeById(mxOleObjectInfo->maShapeId))
{ // Apply stroke props from the type model of the related VML shape.
ShapePropertyMap aPropMap(rFilterBase.getModelObjectHelper());
pVmlShape->getTypeModel().maStrokeModel.pushToPropMap(
aPropMap, rFilterBase.getGraphicHelper()); // And, fill-color properties as well...
pVmlShape->getTypeModel().maFillModel.pushToPropMap(
aPropMap, rFilterBase.getGraphicHelper());
PropertySet(xSet).setProperties(aPropMap);
}
}
if (mxShape.is())
{
finalizeXShape( rFilterBase, rxShapes );
if (mpTextBody)
{ // tdf#151518. The method readjustTextDistances is fix for tdf#148321, but conflicts with // text position in some of the SmartArt types in Writer. So exclude Writer here.
OUString sDocumentService;
rFilterBase.getMediaDescriptor()[utl::MediaDescriptor::PROP_DOCUMENTSERVICE] >>= sDocumentService; if (sDocumentService != u"com.sun.star.text.TextDocument")
mpTextBody->getTextProperties().readjustTextDistances(mxShape);
// tdf#156857: ooxml files can have shape size with spAutoFit=true and the first priority of // shape size is the fix size even if TextAutoGrowHeight is true. bool bAutoHeight = false;
Reference< XPropertySetInfo > xSetInfo(xSet->getPropertySetInfo()); const OUString& rPropName = PropertyMap::getPropertyName(PROP_TextAutoGrowHeight); if (xSetInfo.is() && xSetInfo->hasPropertyByName(rPropName))
{
uno::Any aTextAutoGrowHeight = xSet->getPropertyValue(u"TextAutoGrowHeight"_ustr);
aTextAutoGrowHeight >>= bAutoHeight;
}
SdrObject* pShape = SdrObject::getSdrObjectFromXShape(mxShape); if (pShape && bAutoHeight)
{
tools::Rectangle aAutoSize = pShape->GetLogicRect(); // little tolerance same as in \svx\source\svdraw\svdoashp.cxx:AdjustTextFrameWidthAndHeight if (!aOrigSize.IsEmpty() && (std::abs(aOrigSize.GetHeight() - aAutoSize.GetHeight()) > 1 ||
std::abs(aOrigSize.GetWidth() - aAutoSize.GetWidth()) > 1))
{
pShape->NbcSetLogicRect(aOrigSize, false);
}
}
}
} return mxShape;
}
// Stream in which to place the rendered shape
SvMemoryStream aTempStream;
Reference < io::XStream > xStream( new utl::OStreamWrapper( aTempStream ) );
Reference < io::XOutputStream > xOutputStream( xStream->getOutputStream() );
// get the path to the representation graphic
OUString aGraphicPath; if( !mxOleObjectInfo->maShapeId.isEmpty() ) if( ::oox::vml::Drawing* pVmlDrawing = rFilter.getVmlDrawing() ) if( const ::oox::vml::ShapeBase* pVmlShape = pVmlDrawing->getShapes().getShapeById( mxOleObjectInfo->maShapeId ) )
aGraphicPath = pVmlShape->getGraphicPath();
// import and store the graphic if( !aGraphicPath.isEmpty() )
{ // Transfer shape's width and height to graphicsfilter (can be used by WMF/EMF)
WmfExternal aExtHeader;
aExtHeader.mapMode = 8; // MM_ANISOTROPIC
aExtHeader.xExt = rShapeRect.Width;
aExtHeader.yExt = rShapeRect.Height;
void Shape::finalizeXShape( XmlFilterBase& rFilter, const Reference< XShapes >& rxShapes )
{ switch( meFrameType )
{ case FRAMETYPE_CHART:
{
OSL_ENSURE( !mxChartShapeInfo->maFragmentPath.isEmpty(), "Shape::finalizeXShape - missing chart fragment" ); if( mxShape.is() && !mxChartShapeInfo->maFragmentPath.isEmpty() ) try
{ // set the chart2 OLE class ID at the OLE shape
PropertySet aShapeProp( mxShape );
aShapeProp.setProperty( PROP_CLSID, u"12dcae26-281f-416f-a234-c3086127382e"_ustr );
// get the XModel interface of the embedded object from the OLE shape
Reference< frame::XModel > xDocModel;
aShapeProp.getProperty( xDocModel, PROP_Model );
Reference< chart2::XChartDocument > xChartDoc( xDocModel, UNO_QUERY_THROW );
// load the chart data from the XML fragment #if ENABLE_WASM_STRIP_CHART
(void) rFilter;
(void) rxShapes; #else // WASM_CHART change // TODO: Instead of using convertFromModel an alternative may be // added to convert not to Chart/OLE SdrObejct, but to GraphicObject // with the Chart visualization. There should be a preview available // in the imported chart data bool bMSO2007Doc = rFilter.isMSO2007Document();
chart::ChartSpaceModel aModel(bMSO2007Doc);
oox::ppt::PowerPointImport* pPowerPointImport
= dynamic_cast<oox::ppt::PowerPointImport*>(&rFilter);
ClrMapPtr pClrMap; // The original color map if (pPowerPointImport)
{ // Use a copy of current color map, which the fragment may override locally
pClrMap = pPowerPointImport->getActualSlidePersist()->getClrMap();
aModel.mpClrMap = pClrMap ? std::make_shared<ClrMap>(*pClrMap)
: std::make_shared<ClrMap>();
pPowerPointImport->getActualSlidePersist()->setClrMap(aModel.mpClrMap);
}
if (pPowerPointImport)
{ if (!aThemeOverrideFragmentPath.isEmpty())
{ // Restore the original theme.
pPowerPointImport->getActualSlidePersist()->setTheme(pTheme);
} // Restore the original color map
pPowerPointImport->getActualSlidePersist()->setClrMap(std::move(pClrMap));
} #endif
} catch( Exception& )
{
}
} break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.