/* -*- 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 .
*/
/// Count the crop value based on a crop fraction and a reference size.
sal_Int32 lclConvertCrop(std::u16string_view rCrop, sal_uInt32 nSize)
{ if (o3tl::ends_with(rCrop, u"f"))
{ // Numeric value is specified in 1/65536-ths.
sal_uInt32 nCrop = o3tl::toUInt32(rCrop.substr(0, rCrop.size() - 1)); return (nCrop * nSize) / 65536;
}
OUString aType = maShapeModel.maType; if (aType[ 0 ] == '#')
aType = aType.copy(1); if( const ShapeType* pShapeType = mrDrawing.getShapes().getShapeTypeById( aType ) )
{ // Make sure that the props from maTypeModel have priority over the props from // the shape type.
StrokeModel aMergedStrokeModel;
aMergedStrokeModel.assignUsed(pShapeType->getTypeModel().maStrokeModel);
aMergedStrokeModel.assignUsed(maTypeModel.maStrokeModel);
FillModel aMergedFillModel;
aMergedFillModel.assignUsed(pShapeType->getTypeModel().maFillModel);
aMergedFillModel.assignUsed(maTypeModel.maFillModel);
maTypeModel.assignUsed( pShapeType->getTypeModel() );
maTypeModel.maStrokeModel = std::move(aMergedStrokeModel);
maTypeModel.maFillModel = std::move(aMergedFillModel);
} else { // Temporary fix, shapetype not found if referenced from different substream // FIXME: extend scope of ShapeContainer to store all shapetypes from the document static constexpr OUString sShapeTypePrefix = u"shapetype_"_ustr;
std::u16string_view tmp; if (aType.startsWith(sShapeTypePrefix)) {
maTypeModel.moShapeType = o3tl::toInt32(aType.subView(sShapeTypePrefix.getLength()));
} elseif (aType.startsWith("_x0000_t", &tmp)) {
maTypeModel.moShapeType = o3tl::toInt32(tmp);
}
}
}
xShape = finalImplConvertAndInsert(xShape); /* Notify the drawing that a new shape has been inserted. For convenience, pass the rectangle that contains position and
size of the shape. */ bool bGroupChild = pParentAnchor != nullptr;
mrDrawing.notifyXShapeInserted( xShape, aShapeRect, *this, bGroupChild );
}
} else
SAL_WARN("oox", "not converting shape, as calculated rectangle is empty");
} return xShape;
}
awt::Rectangle ShapeBase::getShapeRectangle() const
{ /* Calculate shape rectangle. Applications may do something special
according to some imported shape client data (e.g. Excel cell anchor). */ return calcShapeRectangle(nullptr);
}
// Extreme negative top margin? Then the shape will end up at the top of the page, it's pointless to perform any kind of wrapping.
sal_Int32 nMarginTop = ConversionHelper::decodeMeasureToHmm(rGraphicHelper, rTypeModel.maMarginTop, 0, false, true); if (nMarginTop < -35277) // Less than 1000 points.
aWrapType.clear();
staticvoid lcl_SetAnchorType(PropertySet& rPropSet, const ShapeTypeModel& rTypeModel, const GraphicHelper& rGraphicHelper)
{ if ( rTypeModel.maPosition == "absolute" )
{ // Word supports as-character (inline) and at-character only, absolute can't be inline.
rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_CHARACTER); // anchor is set after insertion, so reset to NONE
rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::NONE));
if ( rTypeModel.maPositionVerticalRelative == "page" )
{
rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_FRAME);
} elseif ( rTypeModel.maPositionVerticalRelative == "margin" )
{
rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA);
} elseif (rTypeModel.maPositionVerticalRelative == "top-margin-area")
{
rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA_TOP);
} elseif (rTypeModel.maPositionVerticalRelative == "bottom-margin-area")
{
rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::PAGE_PRINT_AREA_BOTTOM);
} else
{
rPropSet.setProperty(PROP_VertOrientRelation, text::RelOrientation::FRAME);
}
} elseif( rTypeModel.maPosition == "relative" )
{ // I'm not very sure this is correct either.
rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AT_PARAGRAPH); // anchor is set after insertion, so reset to NONE
rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::NONE));
} else// static (is the default) means anchored inline
{
rPropSet.setProperty(PROP_AnchorType, text::TextContentAnchorType_AS_CHARACTER); // Use top orientation, this one seems similar to what MSO uses as inline
rPropSet.setAnyProperty(PROP_VertOrient, Any(text::VertOrientation::TOP));
}
// if the anchor is not inline, and is relative to left or right, then apply the margins bool bHonorMargins = rTypeModel.maPosition == "relative" || rTypeModel.maPosition == "absolute"; if ( rTypeModel.maPositionHorizontal == "center" )
{
rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::CENTER));
bHonorMargins = false;
} elseif ( rTypeModel.maPositionHorizontal == "left" )
rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::LEFT)); elseif ( rTypeModel.maPositionHorizontal == "right" )
rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::RIGHT)); elseif ( rTypeModel.maPositionHorizontal == "inside" )
{
rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::LEFT));
rPropSet.setAnyProperty(PROP_PageToggle, Any(true));
} elseif ( rTypeModel.maPositionHorizontal == "outside" )
{
rPropSet.setAnyProperty(PROP_HoriOrient, Any(text::HoriOrientation::RIGHT));
rPropSet.setAnyProperty(PROP_PageToggle, Any(true));
} else
bHonorMargins = false;
sal_Int16 nWritingMode = text::WritingMode2::LR_TB; if (getTextBox()->maLayoutFlow == "vertical" && maTypeModel.maLayoutFlowAlt.isEmpty())
{
nWritingMode = text::WritingMode2::TB_RL;
} elseif (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
{
nWritingMode = text::WritingMode2::BT_LR;
} if (nWritingMode != text::WritingMode2::LR_TB)
{
PropertySet(xShape).setAnyProperty(PROP_WritingMode, uno::Any(nWritingMode));
} // tdf#123626 if (!maShapeModel.maHyperlink.isEmpty())
PropertySet(xShape).setAnyProperty(PROP_HyperLinkURL, Any(maShapeModel.maHyperlink));
} else
{ // FIXME Setting the relative width/height only for everything but text frames as // TextFrames already have relative width/height feature... but currently not working // in the way we need.
// Set the relative width / height if any if ( !maTypeModel.maWidthPercent.isEmpty( ) )
{ // Only page-relative width is supported ATM if ( maTypeModel.maWidthRelative.isEmpty() || maTypeModel.maWidthRelative == "page" )
{
sal_Int16 nWidth = maTypeModel.maWidthPercent.toInt32() / 10; // Only apply if nWidth != 0 if ( nWidth )
PropertySet( xShape ).setAnyProperty(PROP_RelativeWidth, Any( nWidth ) );
}
} if ( !maTypeModel.maHeightPercent.isEmpty( ) )
{ // Only page-relative height is supported ATM if ( maTypeModel.maHeightRelative.isEmpty() || maTypeModel.maHeightRelative == "page" )
{
sal_Int16 nHeight = maTypeModel.maHeightPercent.toInt32() / 10; // Only apply if nHeight != 0 if ( nHeight )
PropertySet( xShape ).setAnyProperty(PROP_RelativeHeight, Any( nHeight ) );
}
}
// drawinglayer default is center, MSO default is top.
drawing::TextVerticalAdjust eTextVerticalAdjust = drawing::TextVerticalAdjust_TOP; if (maTypeModel.maVTextAnchor == "middle")
eTextVerticalAdjust = drawing::TextVerticalAdjust_CENTER; elseif (maTypeModel.maVTextAnchor == "bottom")
eTextVerticalAdjust = drawing::TextVerticalAdjust_BOTTOM;
PropertySet(xShape).setAnyProperty(PROP_TextVerticalAdjust, Any(eTextVerticalAdjust));
PropertySet aPropertySet(xShape); if (xShape.is())
{ if (oRotation)
{
aPropertySet.setAnyProperty(PROP_RotateAngle, Any((*oRotation).get()));
uno::Reference<lang::XServiceInfo> xServiceInfo(rxShapes, uno::UNO_QUERY); if (!xServiceInfo->supportsService(u"com.sun.star.drawing.GroupShape"_ustr))
{ // If rotation is used, simple setPosition() is not enough.
aPropertySet.setAnyProperty(PROP_HoriOrientPosition, Any(aShapeRect.X));
aPropertySet.setAnyProperty(PROP_VertOrientPosition, Any(aShapeRect.Y));
}
} if (!maTypeModel.mbVisible)
{
aPropertySet.setAnyProperty(PROP_Visible, uno::Any(false));
aPropertySet.setAnyProperty(PROP_Printable, uno::Any(false));
} // custom shape geometry attributes
std::vector<css::beans::PropertyValue> aPropVec;
// When flip has 'x' or 'y', the associated ShapeRect will be changed but direction change doesn't occur. // It might occur internally in SdrObject of "sw" module, not here. // The associated properties "PROP_MirroredX" and "PROP_MirroredY" have to be set here so that direction change will occur internally. if (bFlipX)
aPropVec.push_back(comphelper::makePropertyValue(u"MirroredX"_ustr, true)); if (bFlipY)
aPropVec.push_back(comphelper::makePropertyValue(u"MirroredY"_ustr, true));
if (!maTypeModel.maAdjustments.isEmpty())
{
std::vector<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentValues;
sal_Int32 nIndex = 0; do
{
std::u16string_view aToken = o3tl::getToken(maTypeModel.maAdjustments, 0, ',', nIndex);
drawing::EnhancedCustomShapeAdjustmentValue aAdjustmentValue; if (aToken.empty())
aAdjustmentValue.State = css::beans::PropertyState::PropertyState_DEFAULT_VALUE; else
aAdjustmentValue.Value <<= o3tl::toInt32(aToken);
aAdjustmentValues.push_back(aAdjustmentValue);
} while (nIndex >= 0);
Reference<XShape> SimpleShape::finalImplConvertAndInsert(const css::uno::Reference<css::drawing::XShape>& rxShape) const
{ // tdf#41466 This setting must be done here, because the position of textbox will be set as an // effect of the PROP_TextBox property setting, and if we do this setting earlier (setting of // properties of position and size) then the position of textbox will be set with wrong data. // TODO: TextShape is set if we have rect shape in group; we should use the shape-with-textbox // mechanism to handle this situation if (getTextBox() && maService != "com.sun.star.text.TextFrame" && maService != "com.sun.star.drawing.TextShape"
&& !maShapeModel.mbInGroup)
{ const GraphicHelper& rGraphicHelper = mrDrawing.getFilter().getGraphicHelper(); constauto nLeft = ConversionHelper::decodeMeasureToHmm(
rGraphicHelper, maTypeModel.maMarginLeft, 0, true, true);
PropertySet aPropertySet(rxShape);
aPropertySet.setProperty(PROP_HoriOrientPosition, nLeft); constauto nTop = ConversionHelper::decodeMeasureToHmm(
rGraphicHelper, maTypeModel.maMarginTop, 0, true, true);
aPropertySet.setProperty(PROP_VertOrientPosition, nTop);
aPropertySet.setProperty(PROP_TextBox, true);
// And these properties must be set after textbox creation (set PROP_Textbox property). // Note: if you set a new property then you have to handle it in the proper // SwTextBoxHelper::syncProperty function. if (maTypeModel.maLayoutFlowAlt == "bottom-to-top")
aPropertySet.setAnyProperty(PROP_TextWritingMode, uno::Any(text::WritingMode2::BT_LR));
} return ShapeBase::finalImplConvertAndInsert(rxShape);
}
Reference< XShape > SimpleShape::createEmbeddedPictureObject( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, OUString const & rGraphicPath ) const
{
Reference<XGraphic> xGraphic = mrDrawing.getFilter().getGraphicHelper().importEmbeddedGraphic(rGraphicPath); return SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
}
Reference< XShape > SimpleShape::createPictureObject(const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect,
uno::Reference<graphic::XGraphic> const & rxGraphic) const
{
Reference< XShape > xShape = mrDrawing.createAndInsertXShape( u"com.sun.star.drawing.GraphicObjectShape"_ustr, rxShapes, rShapeRect ); if( xShape.is() )
{
PropertySet aPropSet(xShape); if (rxGraphic.is())
{
aPropSet.setProperty(PROP_Graphic, rxGraphic);
}
uno::Reference< lang::XServiceInfo > xServiceInfo(rxShapes, uno::UNO_QUERY); // If the shape has an absolute position, set the properties accordingly, unless we're inside a group shape. if ( maTypeModel.maPosition == "absolute" && !xServiceInfo->supportsService(u"com.sun.star.drawing.GroupShape"_ustr))
{
aPropSet.setProperty(PROP_HoriOrientPosition, rShapeRect.X);
aPropSet.setProperty(PROP_VertOrientPosition, rShapeRect.Y);
aPropSet.setProperty(PROP_Opaque, false);
} // fdo#70457: preserve rotation information if ( !maTypeModel.maRotation.isEmpty() )
aPropSet.setAnyProperty(PROP_RotateAngle, Any(ConversionHelper::decodeRotation(maTypeModel.maRotation).get()));
Reference< XShape > PolyLineShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
{
::std::vector<awt::Point> aAbsPoints;
awt::Rectangle aCoordSys = getCoordSystem(); if (!maShapeModel.maPoints.empty() && (aCoordSys.Width > 0) && (aCoordSys.Height > 0))
{ for (autoconst& point : maShapeModel.maPoints)
aAbsPoints.push_back(lclGetAbsPoint(point, rShapeRect, aCoordSys)); // A polyline cannot be filled but only a polygon. We treat first point == last point as // indicator for being closed. In that case we force to type PolyPolygonShape. if (aAbsPoints.size() > 2 && aAbsPoints.front().X == aAbsPoints.back().X
&& aAbsPoints.front().Y == aAbsPoints.back().Y)
{ const_cast<PolyLineShape*>(this)->setService(u"com.sun.star.drawing.PolyPolygonShape"_ustr);
}
}
namespace
{ void doMirrorX(SdrObject* pShape)
{
Point aCenter(pShape->GetSnapRect().Center());
Point aPoint2(aCenter);
aPoint2.setY(aPoint2.getY() + 1);
pShape->NbcMirror(aCenter, aPoint2);
}
void doMirrorY(SdrObject* pShape)
{
Point aCenter(pShape->GetSnapRect().Center());
Point aPoint2(aCenter);
aPoint2.setX(aPoint2.getX() + 1);
pShape->NbcMirror(aCenter, aPoint2);
}
void handleMirroring(const ShapeTypeModel& rTypeModel, const Reference<XShape>& rxShape)
{ if (!rTypeModel.maFlip.isEmpty())
{ if (SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rxShape))
{ if (rTypeModel.maFlip.startsWith("x"))
doMirrorX(pShape); if (rTypeModel.maFlip.endsWith("y"))
doMirrorY(pShape);
}
}
}
void handleRotation(const ShapeTypeModel& rTypeModel, const Reference<XShape>& rxShape)
{ if (!rTypeModel.maRotation.isEmpty())
{ if (SdrObject* pShape = SdrObject::getSdrObjectFromXShape(rxShape))
{ // The needed factor -1 for opposite direction and factor 100 for Degree100 is // contained in method decodeRotation().
Degree100 nAngle(ConversionHelper::decodeRotation(rTypeModel.maRotation));
pShape->NbcRotate(pShape->GetSnapRect().Center(), nAngle);
}
}
}
}
Reference<XShape> LineShape::implConvertAndInsert(const Reference<XShapes>& rxShapes, const awt::Rectangle& rShapeRect) const
{
Reference<XShape> xShape = SimpleShape::implConvertAndInsert(rxShapes, rShapeRect); // tdf#137765
handleRotation(maTypeModel, xShape); // tdf#97517 tdf#137678 // The MirroredX and MirroredY properties (in the CustomShapeGeometry property) are not // supported for the LineShape by UNO, so we have to make the mirroring here.
handleMirroring(maTypeModel, xShape); return xShape;
}
Reference< XShape > BezierShape::implConvertAndInsert( const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
{ // If we have an 'x' in the last part of the path it means it is closed...
sal_Int32 nPos = maShapeModel.maVmlPath.lastIndexOf(','); if ( nPos != -1 && maShapeModel.maVmlPath.indexOf('x', nPos) != -1 )
{ const_cast<BezierShape*>( this )->setService( u"com.sun.star.drawing.ClosedBezierShape"_ustr );
}
// Bezier paths may consist of one or more sub-paths typedef ::std::vector< ::std::vector< PolygonFlags > > FlagsList;
std::vector< ::std::vector< awt::Point > > aCoordLists;
FlagsList aFlagLists;
// Curve defined by to, from, control1 and control2 attributes if ( maShapeModel.maVmlPath.isEmpty() )
{
aCoordLists.emplace_back( );
aFlagLists.emplace_back( );
sal_Int32 nIndex = 0;
// First and last points are normals, points 2 and 4 are controls
aFlagLists[ 0 ].resize( aCoordLists[ 0 ].size(), PolygonFlags_CONTROL );
aFlagLists[ 0 ][ 0 ] = PolygonFlags_NORMAL;
aFlagLists[ 0 ].back() = PolygonFlags_NORMAL;
} // Curve defined by path attribute else
{ // Parse VML path string and convert to absolute coordinates
ConversionHelper::decodeVmlPath( aCoordLists, aFlagLists, maShapeModel.maVmlPath );
for (auto & coordList : aCoordLists) for (auto & point : coordList)
{
point = lclGetAbsPoint( point, rShapeRect, aCoordSys );
}
}
aBezierCoords.Coordinates.realloc( aCoordLists.size() ); auto pCoordinates = aBezierCoords.Coordinates.getArray(); for ( size_t i = 0; i < aCoordLists.size(); i++ )
pCoordinates[i] = comphelper::containerToSequence( aCoordLists[i] );
aBezierCoords.Flags.realloc( aFlagLists.size() ); auto pFlags = aBezierCoords.Flags.getArray(); for ( size_t i = 0; i < aFlagLists.size(); i++ )
pFlags[i] = comphelper::containerToSequence( aFlagLists[i] );
if( !aCoordLists.front().empty() && !aCoordLists.back().empty()
&& aCoordLists.front().front().X == aCoordLists.back().back().X
&& aCoordLists.front().front().Y == aCoordLists.back().back().Y )
{ // HACK: If the shape is in fact closed, which can be found out only when the path is known, // force to closed bezier shape (otherwise e.g. fill won't work). const_cast< BezierShape* >( this )->setService( u"com.sun.star.drawing.ClosedBezierShape"_ustr );
}
}
// Try to find matching signature line image - if none exists that is fine, // then the signature line is not digitally signed. auto pSignInfo = std::find_if(xSignatureInfo.begin(), xSignatureInfo.end(),
[this](const security::DocumentSignatureInformation& rSigInfo) { return rSigInfo.SignatureLineId == getShapeModel().maSignatureId; }); if (pSignInfo != xSignatureInfo.end())
{
bIsSigned = true; if (pSignInfo->SignatureIsValid)
{ // Signature is valid, use the 'valid' image
SAL_WARN_IF(!pSignInfo->ValidSignatureLineImage.is(), "oox.vml", "No ValidSignatureLineImage!");
xGraphic = pSignInfo->ValidSignatureLineImage;
} else
{ // Signature is invalid, use the 'invalid' image
SAL_WARN_IF(!pSignInfo->InvalidSignatureLineImage.is(), "oox.vml", "No InvalidSignatureLineImage!");
xGraphic = pSignInfo->InvalidSignatureLineImage;
}
}
} catch (css::uno::Exception&)
{ // DocumentDigitalSignatures service not available. // We continue by rendering the "unsigned" shape instead.
}
Reference< XShape > xShape; if (xGraphic.is())
{ // If available, use the signed image from the signature
xShape = SimpleShape::createPictureObject(rxShapes, rShapeRect, xGraphic);
} else
{ // Create shape with the fallback "unsigned" image
xShape = SimpleShape::createEmbeddedPictureObject(rxShapes, rShapeRect, aGraphicPath);
}
// Store signature line properties
--> --------------------
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.