/* -*- 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 .
*/
#include <sal/config.h>
#include <o3tl/string_view.hxx>
#include <svx/EnhancedCustomShape2d.hxx>
#include <svx/EnhancedCustomShapeGeometry.hxx>
#include <svx/EnhancedCustomShapeTypeNames.hxx>
#include <svx/svdoashp.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdogrp.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdpage.hxx>
#include <svx/xflclit.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnstit.hxx>
#include <svx/xlnedit.hxx>
#include <svx/xlnstwit.hxx>
#include <svx/xlnedwit.hxx>
#include <svx/xlnstcit.hxx>
#include <svx/xlnedcit.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xflhtit.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xhatch.hxx>
#include <svx/sdshitm.hxx>
#include <comphelper/configuration.hxx>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/color/bcolortools.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <sal/log.hxx>
#include <algorithm>
#include <cstdlib>
#include <string_view>
#include <unordered_set>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::drawing::EnhancedCustomShapeSegmentCommand;
void EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( EnhancedCustomShapePa
rameter& rParameter, const sal_Int32 nValue )
{
sal_uInt32 nDat = static_cast <sal_uInt32>(nValue);
sal_Int32 nNewValue = nValue;
// check if this is a special point
if ( ( nDat >> 16 ) == 0x8000 )
{
nNewValue = static_cast <sal_uInt16>(nDat);
rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
}
else
rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
rParameter.Value <<= nNewValue;
}
OUString EnhancedCustomShape2d::GetEquation( const sal_uInt16 nFlags, sal_Int32 nP1, sal_Int32 nP2, sal_Int32 nP3 )
{
OUString aEquation;
bool b1Special = ( nFlags & 0x2000 ) != 0;
bool b2Special = ( nFlags & 0x4000 ) != 0;
bool b3Special = ( nFlags & 0x8000 ) != 0;
switch ( nFlags & 0xff )
{
case 0 :
case 14 :
{
sal_Int32 nOptimize = 0;
if ( nP1 )
nOptimize |= 1;
if ( nP2 )
nOptimize |= 2;
if ( b1Special )
nOptimize |= 4;
if ( b2Special )
nOptimize |= 8;
switch ( nOptimize )
{
case 0 :
break ;
case 1 :
case 4 :
case 5 :
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
break ;
case 2 :
case 8 :
case 10:
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
break ;
default :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "+" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
}
break ;
}
if ( b3Special || nP3 )
{
aEquation += "-" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
}
}
break ;
case 1 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
if ( b2Special || ( nP2 != 1 ) )
{
aEquation += "*" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
}
if ( b3Special || ( ( nP3 != 1 ) && ( nP3 != 0 ) ) )
{
aEquation += "/" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
}
}
break ;
case 2 :
{
aEquation += "(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "+" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += ")/2" ;
}
break ;
case 3 :
{
aEquation += "abs(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += ")" ;
}
break ;
case 4 :
{
aEquation += "min(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += ")" ;
}
break ;
case 5 :
{
aEquation += "max(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += ")" ;
}
break ;
case 6 :
{
aEquation += "if(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += ")" ;
}
break ;
case 7 :
{
aEquation += "sqrt(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "+" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "*" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "+" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += ")" ;
}
break ;
case 8 :
{
aEquation += "atan2(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += ")/(pi/180)" ;
}
break ;
case 9 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*sin(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "*(pi/180))" ;
}
break ;
case 10 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*cos(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "*(pi/180))" ;
}
break ;
case 11 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*cos(atan2(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "))" ;
}
break ;
case 12 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*sin(atan2(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "," ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "))" ;
}
break ;
case 13 :
{
aEquation += "sqrt(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += ")" ;
}
break ;
case 15 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*sqrt(1-(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "/" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += ")"
"*(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "/" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "))" ;
}
break ;
case 16 :
{
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*tan(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += ")" ;
}
break ;
case 0x80 :
{
aEquation += "sqrt(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "-" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "*" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += ")" ;
}
break ;
case 0x81 :
{
aEquation += "(cos(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*(pi/180))*(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "-10800)+sin(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*(pi/180))*(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "-10800))+10800" ;
}
break ;
case 0x82 :
{
aEquation += "-(sin(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*(pi/180))*(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP1, b1Special );
aEquation += "-10800)-cos(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP3, b3Special );
aEquation += "*(pi/180))*(" ;
EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( aEquation, nP2, b2Special );
aEquation += "-10800))+10800" ;
}
break ;
}
return aEquation;
}
void EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter( OUString& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue )
{
if ( bIsSpecialValue )
{
if ( nPara & 0x400 )
{
rParameter += "?" ;
rParameter += OUString::number( nPara & 0xff );
rParameter += " " ;
}
else
{
switch ( nPara )
{
case DFF_Prop_adjustValue :
case DFF_Prop_adjust2Value :
case DFF_Prop_adjust3Value :
case DFF_Prop_adjust4Value :
case DFF_Prop_adjust5Value :
case DFF_Prop_adjust6Value :
case DFF_Prop_adjust7Value :
case DFF_Prop_adjust8Value :
case DFF_Prop_adjust9Value :
case DFF_Prop_adjust10Value :
{
rParameter += "$" ;
rParameter += OUString::number( nPara - DFF_Prop_adjustValue );
rParameter += " " ;
}
break ;
case DFF_Prop_geoLeft :
{
rParameter += "left" ;
}
break ;
case DFF_Prop_geoTop :
{
rParameter += "top" ;
}
break ;
case DFF_Prop_geoRight :
{
rParameter += "right" ;
}
break ;
case DFF_Prop_geoBottom :
{
rParameter += "bottom" ;
}
break ;
}
}
}
else
{
rParameter += OUString::number( nPara );
}
}
void EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( EnhancedCustomShapeParameter& rParameter, const sal_Int32 nPara, const bool bIsSpecialValue, bool bHorz )
{
sal_Int32 nValue = 0;
if ( bIsSpecialValue )
{
if ( ( nPara >= 0x100 ) && ( nPara <= 0x107 ) )
{
nValue = nPara & 0xff;
rParameter.Type = EnhancedCustomShapeParameterType::ADJUSTMENT;
}
else if ( ( nPara >= 3 ) && ( nPara <= 0x82 ) )
{
nValue = nPara - 3;
rParameter.Type = EnhancedCustomShapeParameterType::EQUATION;
}
else if ( nPara == 0 )
{
nValue = 0;
if ( bHorz )
rParameter.Type = EnhancedCustomShapeParameterType::LEFT;
else
rParameter.Type = EnhancedCustomShapeParameterType::TOP;
}
else if ( nPara == 1 )
{
nValue = 0;
if ( bHorz )
rParameter.Type = EnhancedCustomShapeParameterType::RIGHT;
else
rParameter.Type = EnhancedCustomShapeParameterType::BOTTOM;
}
else if ( nPara == 2 ) // means to be centered, but should not be
{ // used in our implementation
nValue = 5600;
rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
}
else
{
nValue = nPara;
rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
}
}
else
{
nValue = nPara;
rParameter.Type = EnhancedCustomShapeParameterType::NORMAL;
}
rParameter.Value <<= nValue;
}
bool EnhancedCustomShape2d::ConvertSequenceToEnhancedCustomShape2dHandle(
const css::beans::PropertyValues& rHandleProperties,
EnhancedCustomShape2d::Handle& rDestinationHandle )
{
bool bRetValue = false ;
if ( rHandleProperties.hasElements() )
{
rDestinationHandle.nFlags = HandleFlags::NONE;
for ( const css::beans::PropertyValue& rPropVal : rHandleProperties )
{
if ( rPropVal.Name == "Position" )
{
if ( rPropVal.Value >>= rDestinationHandle.aPosition )
bRetValue = true ;
}
else if ( rPropVal.Name == "MirroredX" )
{
bool bMirroredX;
if ( rPropVal.Value >>= bMirroredX )
{
if ( bMirroredX )
rDestinationHandle.nFlags |= HandleFlags::MIRRORED_X;
}
}
else if ( rPropVal.Name == "MirroredY" )
{
bool bMirroredY;
if ( rPropVal.Value >>= bMirroredY )
{
if ( bMirroredY )
rDestinationHandle.nFlags |= HandleFlags::MIRRORED_Y;
}
}
else if ( rPropVal.Name == "Switched" )
{
bool bSwitched;
if ( rPropVal.Value >>= bSwitched )
{
if ( bSwitched )
rDestinationHandle.nFlags |= HandleFlags::SWITCHED;
}
}
else if ( rPropVal.Name == "Polar" )
{
if ( rPropVal.Value >>= rDestinationHandle.aPolar )
rDestinationHandle.nFlags |= HandleFlags::POLAR;
}
else if ( rPropVal.Name == "RefX" )
{
if ( rPropVal.Value >>= rDestinationHandle.nRefX )
rDestinationHandle.nFlags |= HandleFlags::REFX;
}
else if ( rPropVal.Name == "RefY" )
{
if ( rPropVal.Value >>= rDestinationHandle.nRefY )
rDestinationHandle.nFlags |= HandleFlags::REFY;
}
else if ( rPropVal.Name == "RefAngle" )
{
if ( rPropVal.Value >>= rDestinationHandle.nRefAngle )
rDestinationHandle.nFlags |= HandleFlags::REFANGLE;
}
else if ( rPropVal.Name == "RefR" )
{
if ( rPropVal.Value >>= rDestinationHandle.nRefR )
rDestinationHandle.nFlags |= HandleFlags::REFR;
}
else if ( rPropVal.Name == "RadiusRangeMinimum" )
{
if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMinimum )
rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MINIMUM;
}
else if ( rPropVal.Name == "RadiusRangeMaximum" )
{
if ( rPropVal.Value >>= rDestinationHandle.aRadiusRangeMaximum )
rDestinationHandle.nFlags |= HandleFlags::RADIUS_RANGE_MAXIMUM;
}
else if ( rPropVal.Name == "RangeXMinimum" )
{
if ( rPropVal.Value >>= rDestinationHandle.aXRangeMinimum )
rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MINIMUM;
}
else if ( rPropVal.Name == "RangeXMaximum" )
{
if ( rPropVal.Value >>= rDestinationHandle.aXRangeMaximum )
rDestinationHandle.nFlags |= HandleFlags::RANGE_X_MAXIMUM;
}
else if ( rPropVal.Name == "RangeYMinimum" )
{
if ( rPropVal.Value >>= rDestinationHandle.aYRangeMinimum )
rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MINIMUM;
}
else if ( rPropVal.Name == "RangeYMaximum" )
{
if ( rPropVal.Value >>= rDestinationHandle.aYRangeMaximum )
rDestinationHandle.nFlags |= HandleFlags::RANGE_Y_MAXIMUM;
}
}
}
return bRetValue;
}
void EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryItem& rGeometryItem )
{
// AdjustmentValues
static constexpr OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
const Any* pAny = rGeometryItem.GetPropertyValueByName( sAdjustmentValues );
if ( pAny )
*pAny >>= m_seqAdjustmentValues;
// Coordsize
static constexpr OUStringLiteral sViewBox( u"ViewBox" );
const Any* pViewBox = rGeometryItem.GetPropertyValueByName( sViewBox );
css::awt::Rectangle aViewBox;
if ( pViewBox && (*pViewBox >>= aViewBox ) )
{
m_nCoordLeft = aViewBox.X;
m_nCoordTop = aViewBox.Y;
m_nCoordWidthG = aViewBox.Width;
if (m_nCoordWidthG < 0)
m_nCoordWidthG = o3tl::saturating_toggle_sign(m_nCoordWidthG);
m_nCoordHeightG = aViewBox.Height;
if (m_nCoordHeightG < 0)
m_nCoordHeightG = o3tl::saturating_toggle_sign(m_nCoordHeightG);
}
static constexpr OUString sPath( u"Path" _ustr );
static constexpr OUStringLiteral sCoordinates( u"Coordinates" );
static constexpr OUStringLiteral sGluePoints( u"GluePoints" );
static constexpr OUStringLiteral sGluePointLeavingDirections( u"GluePointLeavingDirections" );
static constexpr OUStringLiteral sSegments( u"Segments" );
static constexpr OUStringLiteral sSubViewSize( u"SubViewSize" );
static constexpr OUStringLiteral sStretchX( u"StretchX" );
static constexpr OUStringLiteral sStretchY( u"StretchY" );
static constexpr OUStringLiteral sTextFrames( u"TextFrames" );
static constexpr OUStringLiteral sEquations( u"Equations" );
static constexpr OUStringLiteral sHandles( u"Handles" );
// Path/Coordinates
pAny = rGeometryItem.GetPropertyValueByName( sPath, sCoordinates );
if ( pAny )
*pAny >>= m_seqCoordinates;
// Path/GluePoints
pAny = rGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
if ( pAny )
*pAny >>= m_seqGluePoints;
// Path/GluePointLeavingDirections
pAny = rGeometryItem.GetPropertyValueByName(sPath, sGluePointLeavingDirections);
if (pAny)
*pAny >>= m_seqGluePointLeavingDirections;
// Path/Segments
pAny = rGeometryItem.GetPropertyValueByName( sPath, sSegments );
if ( pAny )
*pAny >>= m_seqSegments;
// Path/SubViewSize
pAny = rGeometryItem.GetPropertyValueByName( sPath, sSubViewSize );
if ( pAny )
*pAny >>= m_seqSubViewSize;
// Path/StretchX
pAny = rGeometryItem.GetPropertyValueByName( sPath, sStretchX );
if ( pAny )
{
sal_Int32 nStretchX = 0;
if ( *pAny >>= nStretchX )
m_nXRef = nStretchX;
}
// Path/StretchY
pAny = rGeometryItem.GetPropertyValueByName( sPath, sStretchY );
if ( pAny )
{
sal_Int32 nStretchY = 0;
if ( *pAny >>= nStretchY )
m_nYRef = nStretchY;
}
// Path/TextFrames
pAny = rGeometryItem.GetPropertyValueByName( sPath, sTextFrames );
if ( pAny )
*pAny >>= m_seqTextFrames;
// Equations
pAny = rGeometryItem.GetPropertyValueByName( sEquations );
if ( pAny )
*pAny >>= m_seqEquations;
// Handles
pAny = rGeometryItem.GetPropertyValueByName( sHandles );
if ( pAny )
*pAny >>= m_seqHandles;
}
EnhancedCustomShape2d::~EnhancedCustomShape2d()
{
}
void EnhancedCustomShape2d::SetPathSize( sal_Int32 nIndex )
{
sal_Int32 nWidth = 0;
sal_Int32 nHeight = 0;
if ( m_seqSubViewSize.hasElements() && nIndex < m_seqSubViewSize.getLength() ) {
nWidth = m_seqSubViewSize[ nIndex ].Width;
nHeight = m_seqSubViewSize[ nIndex ].Height;
SAL_INFO(
"svx" ,
"set subpath " << nIndex << " size: " << nWidth << " x "
<< nHeight);
}
if ( nWidth && nHeight ) {
m_nCoordWidth = nWidth;
m_nCoordHeight = nHeight;
} else {
m_nCoordWidth = m_nCoordWidthG;
m_nCoordHeight = m_nCoordHeightG;
}
m_fXScale = m_nCoordWidth == 0 ? 0.0 : static_cast <double >(m_aLogicRect.GetWidth()) / static_cast <double >(m_nCoordWidth);
m_fYScale = m_nCoordHeight == 0 ? 0.0 : static_cast <double >(m_aLogicRect.GetHeight()) / static_cast <double >(m_nCoordHeight);
if ( m_bOOXMLShape )
{
SAL_INFO(
"svx" ,
"ooxml shape, path width: " << m_nCoordWidth << " height: "
<< m_nCoordHeight);
// Try to set up scale separately, if given only width or height
// This is possible case in OOXML when only width or height is non-zero
if ( m_nCoordWidth == 0 )
{
if ( nWidth )
m_fXScale = static_cast <double >(m_aLogicRect.GetWidth()) / static_cast <double >(nWidth);
else
m_fXScale = 1.0;
}
if ( m_nCoordHeight == 0 )
{
if ( nHeight )
m_fYScale = static_cast <double >(m_aLogicRect.GetHeight()) / static_cast <double >(nHeight);
else
m_fYScale = 1.0;
}
}
if ( static_cast <sal_uInt32>(m_nXRef) != 0x80000000 && m_aLogicRect.GetHeight() )
{
m_fXRatio = static_cast <double >(m_aLogicRect.GetWidth()) / static_cast <double >(m_aLogicRect.GetHeight());
if ( m_fXRatio > 1 )
m_fXScale /= m_fXRatio;
else
m_fXRatio = 1.0;
}
else
m_fXRatio = 1.0;
if ( static_cast <sal_uInt32>(m_nYRef) != 0x80000000 && m_aLogicRect.GetWidth() )
{
m_fYRatio = static_cast <double >(m_aLogicRect.GetHeight()) / static_cast <double >(m_aLogicRect.GetWidth());
if ( m_fYRatio > 1 )
m_fYScale /= m_fYRatio;
else
m_fYRatio = 1.0;
}
else
m_fYRatio = 1.0;
if (comphelper::IsFuzzing())
{
if (fabs(m_fXScale) > 100000)
{
SAL_WARN("svx" , "unreasonable X Scale of: " << m_fXScale);
m_fXScale = 1.0;
}
if (fabs(m_fYScale) > 100000)
{
SAL_WARN("svx" , "unreasonable Y Scale of: " << m_fYScale);
m_fYScale = 1.0;
}
}
}
EnhancedCustomShape2d::EnhancedCustomShape2d(SdrObjCustomShape& rSdrObjCustomShape)
: SfxItemSet ( rSdrObjCustomShape.GetMergedItemSet() ),
mrSdrObjCustomShape ( rSdrObjCustomShape ),
m_eSpType ( mso_sptNil ),
m_nCoordLeft ( 0 ),
m_nCoordTop ( 0 ),
m_nCoordWidthG ( 21600 ),
m_nCoordHeightG ( 21600 ),
m_bOOXMLShape ( false ),
m_nXRef ( 0x80000000 ),
m_nYRef ( 0x80000000 ),
m_nColorData ( 0 ),
m_bFilled ( rSdrObjCustomShape.GetMergedItem( XATTR_FILLSTYLE ).GetValue() != drawing::FillStyle_NONE ),
m_bStroked ( rSdrObjCustomShape.GetMergedItem( XATTR_LINESTYLE ).GetValue() != drawing::LineStyle_NONE ),
m_bFlipH ( false ),
m_bFlipV ( false )
{
// bTextFlow needs to be set before clearing the TextDirection Item
ClearItem( SDRATTR_TEXTDIRECTION ); //SJ: vertical writing is not required, by removing this item no outliner is created
// #i105323# For 2D AutoShapes, the shadow attribute does not need to be applied to any
// of the constructed helper SdrObjects. This would lead to problems since the shadow
// of one helper object would fall on one helper object behind it (e.g. with the
// eyes of the smiley shape). This is not wanted; instead a single shadow 'behind'
// the AutoShape visualisation is wanted. This is done with primitive functionality
// now in SdrCustomShapePrimitive2D::create2DDecomposition, but only for 2D objects
// (see there and in EnhancedCustomShape3d::Create3DObject to read more).
// This exception may be removed later when AutoShapes will create primitives directly.
// So, currently remove the ShadowAttribute from the ItemSet to not apply it to any
// 2D helper shape.
ClearItem(SDRATTR_SHADOW);
Point aP( mrSdrObjCustomShape.GetSnapRect().Center() );
Size aS( mrSdrObjCustomShape.GetLogicRect().GetSize() );
aP.AdjustX( -(aS.Width() / 2) );
aP.AdjustY( -(aS.Height() / 2) );
m_aLogicRect = tools::Rectangle( aP, aS );
OUString sShapeType;
const SdrCustomShapeGeometryItem& rGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
static constexpr OUStringLiteral sType = u"Type" ;
const Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
if ( pAny ) {
*pAny >>= sShapeType;
m_bOOXMLShape = sShapeType.startsWith("ooxml-" );
SAL_INFO("svx" , "shape type: " << sShapeType << " " << m_bOOXMLShape);
}
m_eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
static constexpr OUStringLiteral sMirroredX = u"MirroredX" ;
static constexpr OUStringLiteral sMirroredY = u"MirroredY" ;
pAny = rGeometryItem.GetPropertyValueByName( sMirroredX );
if ( pAny )
*pAny >>= m_bFlipH;
pAny = rGeometryItem.GetPropertyValueByName( sMirroredY );
if ( pAny )
*pAny >>= m_bFlipV;
m_nRotateAngle = Degree100(static_cast <sal_Int32>(mrSdrObjCustomShape.GetObjectRotation() * 100.0));
/*const sal_Int32* pDefData =*/ ApplyShapeAttributes( rGeometryItem );
SetPathSize();
switch ( m_eSpType )
{
case mso_sptCan : m_nColorData = 0x20400000; break ;
case mso_sptCube : m_nColorData = 0x302e0000; break ;
case mso_sptActionButtonBlank : m_nColorData = 0x502ce400; break ;
case mso_sptActionButtonHome : m_nColorData = 0x702ce4ce; break ;
case mso_sptActionButtonHelp : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonInformation : m_nColorData = 0x702ce4c5; break ;
case mso_sptActionButtonBackPrevious : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonForwardNext : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonBeginning : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonEnd : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonReturn : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonDocument : m_nColorData = 0x702ce4ec; break ;
case mso_sptActionButtonSound : m_nColorData = 0x602ce4c0; break ;
case mso_sptActionButtonMovie : m_nColorData = 0x602ce4c0; break ;
case mso_sptBevel : m_nColorData = 0x502ce400; break ;
case mso_sptFoldedCorner : m_nColorData = 0x20e00000; break ;
case mso_sptSmileyFace : m_nColorData = 0x20e00000; break ;
case mso_sptNil :
{
// Because calculation method has changed in #i102797 original color encoding for
// Octagon Bevel and Diamond Bevel can no longer be used. We keep the color coding
// only for self-created shapes, as authors may have already considered the change.
// We use ColorData compatible to OOXML.
if (sShapeType == "col-60da8460" ) // Octagon Bevel
{
m_nColorData = 0x60ecc240;
}
else if (sShapeType == "col-502ad400" ) // Diamond Bevel
{
m_nColorData = 0x502ce400;
}
else if (sShapeType.getLength() > 4 && sShapeType.match( "col-" ))
{
m_nColorData = o3tl::toUInt32(sShapeType.subView( 4 ), 16);
}
}
break ;
case mso_sptCurvedLeftArrow :
case mso_sptCurvedRightArrow :
case mso_sptCurvedUpArrow :
case mso_sptCurvedDownArrow : m_nColorData = 0x20d00000; break ;
case mso_sptRibbon2 : m_nColorData = 0x30ee0000; break ;
case mso_sptRibbon : m_nColorData = 0x30ee0000; break ;
case mso_sptEllipseRibbon2 : m_nColorData = 0x30ee0000; break ;
case mso_sptEllipseRibbon : m_nColorData = 0x30ee0000; break ;
case mso_sptVerticalScroll : m_nColorData = 0x30ee0000; break ;
case mso_sptHorizontalScroll : m_nColorData = 0x30ee0000; break ;
default :
break ;
}
sal_Int32 nLength = m_seqEquations.getLength();
if ( !nLength )
return ;
m_vEquationResults.resize( nLength );
}
using EnhancedCustomShape::ExpressionFunct;
double EnhancedCustomShape2d::GetEnumFunc( const ExpressionFunct eFunc ) const
{
double fRet = 0.0;
switch ( eFunc )
{
case ExpressionFunct::EnumPi : fRet = M_PI; break ;
case ExpressionFunct::EnumLeft : fRet = static_cast <double >(m_nCoordLeft); break ;
case ExpressionFunct::EnumTop : fRet = static_cast <double >(m_nCoordTop); break ;
case ExpressionFunct::EnumRight : fRet = (static_cast <double >(m_nCoordLeft) + static_cast <double >(m_nCoordWidth)) * m_fXRatio; break ;
case ExpressionFunct::EnumBottom : fRet = (static_cast <double >(m_nCoordTop) + static_cast <double >(m_nCoordHeight)) * m_fYRatio; break ;
case ExpressionFunct::EnumXStretch : fRet = m_nXRef; break ;
case ExpressionFunct::EnumYStretch : fRet = m_nYRef; break ;
case ExpressionFunct::EnumHasStroke : fRet = m_bStroked ? 1.0 : 0.0; break ;
case ExpressionFunct::EnumHasFill : fRet = m_bFilled ? 1.0 : 0.0; break ;
case ExpressionFunct::EnumWidth : fRet = m_nCoordWidth; break ;
case ExpressionFunct::EnumHeight : fRet = m_nCoordHeight; break ;
case ExpressionFunct::EnumLogWidth : fRet = m_aLogicRect.GetWidth(); break ;
case ExpressionFunct::EnumLogHeight : fRet = m_aLogicRect.GetHeight(); break ;
default : break ;
}
return fRet;
}
double EnhancedCustomShape2d::GetAdjustValueAsDouble( const sal_Int32 nIndex ) const
{
double fNumber = 0.0;
if ( nIndex < m_seqAdjustmentValues.getLength() )
{
if ( m_seqAdjustmentValues[ nIndex ].Value.getValueTypeClass() == TypeClass_DOUBLE )
m_seqAdjustmentValues[ nIndex ].Value >>= fNumber;
else
{
sal_Int32 nNumber = 0;
m_seqAdjustmentValues[ nIndex ].Value >>= nNumber;
fNumber = static_cast <double >(nNumber);
}
}
return fNumber;
}
double EnhancedCustomShape2d::GetEquationValueAsDouble( const sal_Int32 nIndex ) const
{
double fNumber = 0.0;
static sal_uInt32 nLevel = 0;
if ( nIndex >= static_cast <sal_Int32>(m_vEquationResults.size()) )
return fNumber;
if (!m_vEquationResults[nIndex].bParsed)
{
m_vEquationResults[nIndex].bParsed = true ;
try
{
m_vEquationResults[nIndex].xNode = EnhancedCustomShape::FunctionParser::parseFunction( m_seqEquations[ nIndex ], *this );
}
catch ( EnhancedCustomShape::ParseError& )
{
SAL_INFO(
"svx" ,
"error: equation number: " << nIndex << ", parser failed ("
<< m_seqEquations[nIndex] << ")" );
}
}
if ( m_vEquationResults[ nIndex ].xNode )
{
nLevel ++;
try
{
if ( m_vEquationResults[ nIndex ].bReady )
fNumber = m_vEquationResults[ nIndex ].fValue;
else {
// cast to non const, so that we can optimize by caching
// equation results, without changing all the const in the stack
struct EquationResult &aResult = const_cast <EnhancedCustomShape2d*>(this )->m_vEquationResults[ nIndex ];
fNumber = aResult.fValue = (*m_vEquationResults[ nIndex ].xNode)();
aResult.bReady = true ;
SAL_INFO("svx" , "equation " << nLevel << " (level: " << m_seqEquations[nIndex] << "): "
<< fNumber << " --> " << 180.0*fNumber/10800000.0);
}
if ( !std::isfinite( fNumber ) )
fNumber = 0.0;
}
catch ( ... )
{
SAL_WARN("svx" , "EnhancedCustomShape2d::GetEquationValueAsDouble failed" );
}
nLevel --;
}
SAL_INFO(
"svx" ,
"?" << nIndex << " --> " << fNumber << " (angle: "
<< 180.0*fNumber/10800000.0 << ")" );
return fNumber;
}
bool EnhancedCustomShape2d::SetAdjustValueAsDouble( const double & rValue, const sal_Int32 nIndex )
{
bool bRetValue = false ;
if ( nIndex < m_seqAdjustmentValues.getLength() )
{
// updating our local adjustment sequence
auto pseqAdjustmentValues = m_seqAdjustmentValues.getArray();
pseqAdjustmentValues[ nIndex ].Value <<= rValue;
pseqAdjustmentValues[ nIndex ].State = css::beans::PropertyState_DIRECT_VALUE;
bRetValue = true ;
}
return bRetValue;
}
basegfx::B2DPoint EnhancedCustomShape2d::GetPointAsB2DPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair,
const bool bScale, const bool bReplaceGeoSize ) const
{
double fValX, fValY;
// width
GetParameter(fValX, rPair.First, bReplaceGeoSize, false );
fValX -= m_nCoordLeft;
if (bScale)
{
fValX *= m_fXScale;
}
// height
GetParameter(fValY, rPair.Second, false , bReplaceGeoSize);
fValY -= m_nCoordTop;
if (bScale)
{
fValY *= m_fYScale;
}
return basegfx::B2DPoint(fValX,fValY);
}
Point EnhancedCustomShape2d::GetPoint( const css::drawing::EnhancedCustomShapeParameterPair& rPair,
const bool bScale, const bool bReplaceGeoSize ) const
{
basegfx::B2DPoint aPoint(GetPointAsB2DPoint(rPair, bScale, bReplaceGeoSize));
return Point(static_cast <tools::Long >(aPoint.getX()), static_cast <tools::Long >(aPoint.getY()));
}
void EnhancedCustomShape2d::GetParameter( double & rRetValue, const EnhancedCustomShapeParameter& rParameter,
const bool bReplaceGeoWidth, const bool bReplaceGeoHeight ) const
{
rRetValue = 0.0;
switch ( rParameter.Type )
{
case EnhancedCustomShapeParameterType::ADJUSTMENT :
{
sal_Int32 nAdjustmentIndex = 0;
if ( rParameter.Value >>= nAdjustmentIndex )
{
rRetValue = GetAdjustValueAsDouble( nAdjustmentIndex );
}
}
break ;
case EnhancedCustomShapeParameterType::EQUATION :
{
sal_Int32 nEquationIndex = 0;
if ( rParameter.Value >>= nEquationIndex )
{
rRetValue = GetEquationValueAsDouble( nEquationIndex );
}
}
break ;
case EnhancedCustomShapeParameterType::NORMAL :
{
if ( rParameter.Value.getValueTypeClass() == TypeClass_DOUBLE )
{
double fValue(0.0);
if ( rParameter.Value >>= fValue )
{
rRetValue = fValue;
}
}
else
{
sal_Int32 nValue = 0;
if ( rParameter.Value >>= nValue )
{
rRetValue = nValue;
if ( bReplaceGeoWidth && ( nValue == m_nCoordWidth ) )
rRetValue *= m_fXRatio;
else if ( bReplaceGeoHeight && ( nValue == m_nCoordHeight ) )
rRetValue *= m_fYRatio;
}
}
}
break ;
case EnhancedCustomShapeParameterType::LEFT :
case EnhancedCustomShapeParameterType::TOP :
{
rRetValue = 0.0;
}
break ;
case EnhancedCustomShapeParameterType::RIGHT :
{
rRetValue = m_nCoordWidth;
}
break ;
case EnhancedCustomShapeParameterType::BOTTOM :
{
rRetValue = m_nCoordHeight;
}
break ;
}
}
// nLumDat 28-31 = number of luminance entries in nLumDat
// nLumDat 27-24 = nLumDatEntry 0
// nLumDat 23-20 = nLumDatEntry 1 ...
// each 4bit entry is to be interpreted as a 10 percent signed luminance changing
sal_Int32 EnhancedCustomShape2d::GetLuminanceChange( sal_uInt32 nIndex ) const
{
const sal_uInt32 nCount = m_nColorData >> 28;
if ( !nCount )
return 0;
if ( nIndex >= nCount )
nIndex = nCount - 1;
const sal_Int32 nLumDat = m_nColorData << ( ( 1 + nIndex ) << 2 );
return ( nLumDat >> 28 ) * 10;
}
Color EnhancedCustomShape2d::GetColorData( const Color& rFillColor, sal_uInt32 nIndex, double dBrightness ) const
{
if ( m_bOOXMLShape || ( mso_sptMin == m_eSpType /* ODF "non-primitive" */ ) )
{ //do LibreOffice way, using dBrightness
if ( dBrightness == 0.0)
{
return rFillColor;
}
else
{
if (dBrightness >=0.0)
{ //lighten, blending with white
return Color( static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )),
static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )),
static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(rFillColor.GetBlue() * (1.0-dBrightness) + dBrightness * 255.0, 0.0, 255.0) )) );
}
else
{ //darken (indicated by negative sign), blending with black
return Color( static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(rFillColor.GetRed() * (1.0+dBrightness), 0.0, 255.0) )),
static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(rFillColor.GetGreen() * (1.0+dBrightness), 0.0, 255.0) )),
static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(rFillColor.GetBlue() * (1.0+dBrightness), 0.0, 255.0) )) );
}
}
}
else
{ //do OpenOffice way, using nColorData
const sal_Int32 nLuminance = GetLuminanceChange(nIndex);
if ( !nLuminance )
return rFillColor;
basegfx::BColor aHSVColor=
basegfx::utils::rgb2hsv(
basegfx::BColor(rFillColor.GetRed()/255.0,
rFillColor.GetGreen()/255.0,
rFillColor.GetBlue()/255.0));
if ( nLuminance > 0 )
{
aHSVColor.setGreen(
aHSVColor.getGreen() * (1.0-nLuminance/100.0));
aHSVColor.setBlue(
nLuminance/100.0 +
(1.0-nLuminance/100.0)*aHSVColor.getBlue());
}
else if ( nLuminance < 0 )
{
aHSVColor.setBlue(
(1.0+nLuminance/100.0)*aHSVColor.getBlue());
}
aHSVColor = basegfx::utils::hsv2rgb(aHSVColor);
return Color( static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(aHSVColor.getRed(),0.0,1.0) * 255.0 + 0.5 )),
static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(aHSVColor.getGreen(),0.0,1.0) * 255.0 + 0.5 )),
static_cast <sal_uInt8>(static_cast < sal_Int32 >( std::clamp(aHSVColor.getBlue(),0.0,1.0) * 255.0 + 0.5 )) );
}
}
tools::Rectangle EnhancedCustomShape2d::GetTextRect() const
{
if ( !m_seqTextFrames.hasElements() )
return m_aLogicRect;
sal_Int32 nIndex = 0;
Point aTopLeft( GetPoint( m_seqTextFrames[ nIndex ].TopLeft, !m_bOOXMLShape, true ) );
Point aBottomRight( GetPoint( m_seqTextFrames[ nIndex ].BottomRight, !m_bOOXMLShape, true ) );
tools::Rectangle aRect( aTopLeft, aBottomRight );
if ( m_bFlipH )
{
aRect.SetLeft(m_aLogicRect.GetWidth() - 1 - aBottomRight.X());
aRect.SetRight( m_aLogicRect.GetWidth() - 1 - aTopLeft.X());
}
if ( m_bFlipV )
{
aRect.SetTop(m_aLogicRect.GetHeight() - 1 - aBottomRight.Y());
aRect.SetBottom(m_aLogicRect.GetHeight() - 1 - aTopLeft.Y());
}
SAL_INFO("svx" , aRect.GetWidth() << " x " << aRect.GetHeight());
if ( aRect.GetWidth() <= 1 || aRect.GetHeight() <= 1 )
return m_aLogicRect;
aRect.Move( m_aLogicRect.Left(), m_aLogicRect.Top() );
aRect.Normalize();
return aRect;
}
sal_uInt32 EnhancedCustomShape2d::GetHdlCount() const
{
return m_seqHandles.getLength();
}
bool EnhancedCustomShape2d::GetHandlePosition( const sal_uInt32 nIndex, Point& rReturnPosition ) const
{
bool bRetValue = false ;
if ( nIndex < GetHdlCount() )
{
Handle aHandle;
if ( ConvertSequenceToEnhancedCustomShape2dHandle( m_seqHandles[ nIndex ], aHandle ) )
{
if ( aHandle.nFlags & HandleFlags::POLAR )
{
Point aReferencePoint( GetPoint( aHandle.aPolar ) );
double fAngle;
double fRadius;
GetParameter( fRadius, aHandle.aPosition.First, false , false );
GetParameter( fAngle, aHandle.aPosition.Second, false , false );
double a = basegfx::deg2rad(360.0 - fAngle);
double dx = fRadius * m_fXScale;
double fX = dx * cos( a );
double fY =-dx * sin( a );
rReturnPosition =
Point(
basegfx::fround<tools::Long >( fX + aReferencePoint.X() ),
basegfx::fTools::equalZero(m_fXScale) ? aReferencePoint.Y() :
basegfx::fround<tools::Long >( ( fY * m_fYScale ) / m_fXScale + aReferencePoint.Y() ) );
}
else
{
if ( aHandle.nFlags & HandleFlags::SWITCHED )
{
if ( m_aLogicRect.GetHeight() > m_aLogicRect.GetWidth() )
{
std::swap(aHandle.aPosition.First, aHandle.aPosition.Second);
}
}
if (m_bOOXMLShape)
rReturnPosition = GetPoint(aHandle.aPosition, false /*bScale*/);
else
rReturnPosition = GetPoint(aHandle.aPosition, true /*bScale*/);
}
const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat());
if ( aGeoStat.m_nShearAngle )
{
double nTan = aGeoStat.mfTanShearAngle;
if (m_bFlipV != m_bFlipH)
nTan = -nTan;
ShearPoint( rReturnPosition, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), nTan );
}
if ( m_nRotateAngle )
{
double a = toRadians(m_nRotateAngle);
RotatePoint( rReturnPosition, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
}
if ( m_bFlipH )
rReturnPosition.setX( m_aLogicRect.GetWidth() - rReturnPosition.X() );
if ( m_bFlipV )
rReturnPosition.setY( m_aLogicRect.GetHeight() - rReturnPosition.Y() );
rReturnPosition.Move( m_aLogicRect.Left(), m_aLogicRect.Top() );
bRetValue = true ;
}
}
return bRetValue;
}
static double lcl_getXAdjustmentValue(std::u16string_view rShapeType, const sal_uInt32 nHandleIndex,
const double fX, const double fW, const double fH)
{
// degenerated shapes are not worth to calculate special case for each shape type
if (fW <= 0.0 || fH <= 0.0)
return 50000;
// pattern (w - x) / ss * 100000 or (r - x) / ss * 100000
if ((rShapeType == u"ooxml-bentArrow" && nHandleIndex == 2) || (rShapeType == u"ooxml-chevron" )
|| (rShapeType == u"ooxml-curvedRightArrow" ) || (rShapeType == u"ooxml-foldedCorner" )
|| (rShapeType == u"ooxml-homePlate" ) || (rShapeType == u"ooxml-notchedRightArrow" )
|| (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-rightArrow" )
|| (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-round1Rect" )
|| (rShapeType == u"ooxml-round2DiagRect" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-round2SameRect" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-snip1Rect" )
|| (rShapeType == u"ooxml-snip2DiagRect" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-snip2SameRect" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-snipRoundRect" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-swooshArrow" ) || (rShapeType == u"ooxml-stripedRightArrow" ))
return (fW - fX) / std::min(fW, fH) * 100000.0;
// pattern x / ss * 100000 or (x - l) / ss * 100000
if ((rShapeType == u"ooxml-bentArrow" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-bentArrow" && nHandleIndex == 3)
|| (rShapeType == u"ooxml-corner" )
|| (rShapeType == u"ooxml-curvedDownArrow" ) || (rShapeType == u"ooxml-curvedLeftArrow" )
|| (rShapeType == u"ooxml-curvedUpArrow" ) || (rShapeType == u"ooxml-leftArrow" )
|| (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-leftRightArrow" )
|| (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-leftRightRibbon" )
|| (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-parallelogram" )
|| (rShapeType == u"ooxml-round2DiagRect" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-round2SameRect" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-roundRect" )
|| (rShapeType == u"ooxml-snip2DiagRect" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-snip2SameRect" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-snipRoundRect" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 3))
return fX / std::min(fW, fH) * 100000.0;
// pattern (hc - x) / ss * 200000
if ((rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-leftRightUpArrow" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-quadArrow" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 0))
return (fW / 2.0 - fX) / std::min(fW, fH) * 200000.0;
// pattern (hc - x) / ss * 100000
if ((rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-leftRightUpArrow" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-quadArrow" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 1))
return (fW / 2.0 - fX) / std::min(fW, fH) * 100000.0;
// pattern (w - x) / ss * 50000 or (r - x) / ss * 50000
if ((rShapeType == u"ooxml-bentUpArrow" ) || (rShapeType == u"ooxml-leftUpArrow" )
|| (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 1))
return (fW - fX) / std::min(fW, fH) * 50000.0;
// pattern x / ss * 200000
if (rShapeType == u"ooxml-nonIsoscelesTrapezoid" && nHandleIndex == 0)
return fX / std::min(fW, fH) * 200000.0;
// pattern (hc - x) / w * 200000
if ((rShapeType == u"ooxml-downArrow" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-ellipseRibbon" ) || (rShapeType == u"ooxml-ellipseRibbon2" )
|| (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 3)
|| (rShapeType == u"ooxml-ribbon" ) || (rShapeType == u"ooxml-ribbon2" )
|| (rShapeType == u"ooxml-upArrow" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-upDownArrow" && nHandleIndex == 0))
return (fW / 2.0 - fX) / fW * 200000.0;
// pattern (x - hc) / w * 100000
if ((rShapeType == u"ooxml-cloudCallout" ) || (rShapeType == u"ooxml-doubleWave" )
|| (rShapeType == u"ooxml-wave" ) || (rShapeType == u"ooxml-wedgeEllipseCallout" )
|| (rShapeType == u"ooxml-wedgeRectCallout" )
|| (rShapeType == u"ooxml-wedgeRoundRectCallout" ))
return (fX - fW / 2.0) / fW * 100000.0;
// pattern (x - hc) / w * 200000
if (rShapeType == u"ooxml-teardrop" )
return (fX - fW / 2.0) / fW * 200000.0;
// pattern (w - x) / w * 100000 or (r - x) / w * 100000
if (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 3)
return (fW - fX) / fW * 100000.0;
// pattern (hc - x) / h * 100000
if (rShapeType == u"ooxml-mathDivide" )
return (fW / 2.0 - fX) / fH * 100000.0;
// pattern x / w * 100000, simple scaling
if (o3tl::starts_with(rShapeType, u"ooxml-" ))
return fX / fW * 100000.0;
return fX; // method is unknown
}
static double lcl_getYAdjustmentValue(std::u16string_view rShapeType, const sal_uInt32 nHandleIndex,
const double fY, const double fW, const double fH)
{
// degenerated shapes are not worth to calculate a special case for each shape type
if (fW <= 0.0 || fH <= 0.0)
return 50000;
// pattern (vc - y) / ss * 100000
if ((rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 1))
return (fH / 2.0 - fY) / std::min(fW, fH) * 100000.0;
// pattern (vc - y) / ss * 200000
if ((rShapeType == u"ooxml-curvedLeftArrow" ) || (rShapeType == u"ooxml-curvedRightArrow" )
|| (rShapeType == u"ooxml-leftArrowCallout" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-leftRightArrowCallout" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-mathPlus" )
|| (rShapeType == u"ooxml-rightArrowCallout" && nHandleIndex == 0))
return (fH / 2.0 - fY) / std::min(fW, fH) * 200000.0;
// pattern (h - y) / ss * 100000 or (b - y) / ss * 100000
if ((rShapeType == u"ooxml-bentUpArrow" && nHandleIndex == 0) || (rShapeType == u"ooxml-corner" )
|| (rShapeType == u"ooxml-curvedDownArrow" ) || (rShapeType == u"ooxml-downArrow" )
|| (rShapeType == u"ooxml-downArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-uturnArrow" && nHandleIndex == 2))
return (fH - fY) / std::min(fW, fH) * 100000.0;
// pattern (h - y) / ss * 200000 or (b - y) / ss * 200000
if (rShapeType == u"ooxml-leftUpArrow" && nHandleIndex == 0) // - adj2 * 2 outside
return (fH - fY) / std::min(fW, fH) * 200000.0;
// pattern y / ss * 100000 or (y - t) / ss * 100000
if ((rShapeType == u"ooxml-bentUpArrow" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-bracePair" ) || (rShapeType == u"ooxml-bracketPair" )
|| (rShapeType == u"ooxml-can" ) || (rShapeType == u"ooxml-cube" )
|| (rShapeType == u"ooxml-curvedUpArrow" ) || (rShapeType == u"ooxml-halfFrame" )
|| (rShapeType == u"ooxml-leftBrace" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-leftBracket" ) || (rShapeType == u"ooxml-leftRightUpArrow" )
|| (rShapeType == u"ooxml-leftUpArrow" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-mathMultiply" ) || (rShapeType == u"ooxml-quadArrow" )
|| (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-rightBrace" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-rightBracket" ) || (rShapeType == u"ooxml-upArrow" )
|| (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-upDownArrow" )
|| (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-verticalScroll" ))
return fY / std::min(fW, fH) * 100000.0;
// pattern y / ss * 50000
if (rShapeType == u"ooxml-bentArrow" )
return fY / std::min(fW, fH) * 50000.0;
// pattern (vc - y) / h * 100000
if ((rShapeType == u"ooxml-mathDivide" && nHandleIndex == 1) // -adj1 / 2 - adj3 outside
|| (rShapeType == u"ooxml-mathEqual" && nHandleIndex == 0) // -adj2 / 2 outside
|| (rShapeType == u"ooxml-mathNotEqual" && nHandleIndex == 0) // -adj3 / 2 outside
|| (rShapeType == u"ooxml-star4" ) || (rShapeType == u"ooxml-star6" )
|| (rShapeType == u"ooxml-star8" ) || (rShapeType == u"ooxml-star10" )
|| (rShapeType == u"ooxml-star12" ) || (rShapeType == u"ooxml-star16" )
|| (rShapeType == u"ooxml-star24" ) || (rShapeType == u"ooxml-star32" ))
return (fH / 2.0 - fY) / fH * 100000.0;
// pattern (vc - y) / h * 200000
if ((rShapeType == u"ooxml-leftArrow" ) || (rShapeType == u"ooxml-leftRightArrow" )
|| (rShapeType == u"ooxml-mathDivide" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-mathEqual" && nHandleIndex == 1)
|| (rShapeType == u"ooxml-mathMinus" ) || (rShapeType == u"ooxml-notchedRightArrow" )
|| (rShapeType == u"ooxml-mathNotEqual" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-quadArrowCallout" && nHandleIndex == 3)
|| (rShapeType == u"ooxml-rightArrow" ) || (rShapeType == u"ooxml-stripedRightArrow" )
|| (rShapeType == u"ooxml-upDownArrowCallout" && nHandleIndex == 3))
return (fH / 2.0 - fY) / fH * 200000.0;
// pattern (y - vc) / h * 100000
if ((rShapeType == u"ooxml-cloudCallout" ) || (rShapeType == u"ooxml-wedgeEllipseCallout" )
|| (rShapeType == u"ooxml-wedgeRectCallout" )
|| (rShapeType == u"ooxml-wedgeRoundRectCallout" ))
return (fY - fH / 2.0) / fH * 100000.0;
// pattern (h - y) / h * 100000 or (b - y) / h * 100000
if ((rShapeType == u"ooxml-ellipseRibbon" && nHandleIndex == 2)
|| (rShapeType == u"ooxml-ellipseRibbon2" && nHandleIndex == 0)
|| (rShapeType == u"ooxml-ribbon2" )
|| (rShapeType == u"ooxml-upArrowCallout" && nHandleIndex == 3))
return (fH - fY) / fH * 100000.0;
// special pattern smiley
if (rShapeType == u"ooxml-smileyFace" )
return (fY - fH * 16515.0 / 21600.0) / fH * 100000.0;
// special pattern for star with odd number of tips, because center of star not center of shape
if (rShapeType == u"ooxml-star5" )
return (fH / 2.0 - fY * 100000.0 / 110557.0) / fH * 100000.0;
if (rShapeType == u"ooxml-star7" )
return (fH / 2.0 - fY * 100000.0 / 105210.0) / fH * 100000.0;
// special pattern swooshArrow
if (rShapeType == u"ooxml-swooshArrow" )
return (fY - std::min(fW, fH) / 8.0) / fH * 100000.0;
// special pattern leftRightRibbon
if (rShapeType == u"ooxml-leftRightRibbon" )
return fY / fH * 200000 - 100000;
// pattern y / h * 100000, simple scaling
if (o3tl::starts_with(rShapeType, u"ooxml-" ))
return fY / fH * 100000.0;
return fY; // method is unknown
}
static double lcl_getAngleInOOXMLUnit(double fDY, double fDX)
{
if (fDX != 0.0 || fDY != 0.0)
{
double fAngleRad(atan2(fDY, fDX));
double fAngle = basegfx::rad2deg(fAngleRad);
// atan2 returns angle in ]-pi; pi], OOXML preset shapes use [0;360[.
if (fAngle < 0.0)
fAngle += 360.0;
// OOXML uses angle unit 1/60000 degree.
fAngle *= 60000.0;
return fAngle;
}
return 0.0; // no angle defined for origin in polar coordinate system
}
static double lcl_getRadiusDistance(double fWR, double fHR, double fX, double fY)
{
// Get D so, that point (fX|fY) is on the ellipse, that has width fWR-D and
// height fHR-D and center in origin.
// Get solution of ellipse equation (fX/(fWR-D))^2 + (fY/(fHR-D)^2 = 1 by solving
// fX^2*(fHR-D)^2 + fY^2*(fWR-D)^2 - (fWR-D)^2 * (fHR-D)^2 = 0 with Newton-method.
if (fX == 0.0)
return std::min(fHR - fY, fWR);
else if (fY == 0.0)
return std::min(fWR - fX, fHR);
double fD = std::min(fWR, fHR) - std::hypot(fX, fY); // iteration start value
sal_uInt8 nIter(0);
bool bFound(false );
do
{
++nIter;
const double fOldD(fD);
const double fWRmD(fWR - fD);
const double fHRmD(fHR - fD);
double fNumerator
= fX * fX * fHRmD * fHRmD + fY * fY * fWRmD * fWRmD - fWRmD * fWRmD * fHRmD * fHRmD;
double fDenominator
= 2.0 * (fHRmD * (fWRmD * fWRmD - fX * fX) + fWRmD * (fHRmD * fHRmD - fY * fY));
if (fDenominator != 0.0)
{
fD = fD - fNumerator / fDenominator;
bFound = fabs(fOldD - fD) < 1.0E-12;
}
else
fD = fD * 0.9; // new start value
} while (nIter < 50 && !bFound);
return fD;
}
bool EnhancedCustomShape2d::SetHandleControllerPosition( const sal_uInt32 nIndex, const css::awt::Point& rPosition )
{
// The method name is misleading. Essentially it calculates the adjustment values from a given
// handle position.
// For ooxml-foo shapes, the way to calculate the adjustment value from the handle position depends on
// the type of the shape, therefore need 'Type'.
OUString sShapeType(u"non-primitive" _ustr); // default for ODF
const SdrCustomShapeGeometryItem& rGeometryItem(mrSdrObjCustomShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
const Any* pAny = rGeometryItem.GetPropertyValueByName(u"Type" _ustr);
if (pAny)
*pAny >>= sShapeType;
bool bRetValue = false ;
if ( nIndex < GetHdlCount() )
{
Handle aHandle;
if ( ConvertSequenceToEnhancedCustomShape2dHandle( m_seqHandles[ nIndex ], aHandle ) )
{
Point aP( rPosition.X, rPosition.Y );
// apply the negative object rotation to the controller position
aP.Move( -m_aLogicRect.Left(), -m_aLogicRect.Top() );
if ( m_bFlipH )
aP.setX( m_aLogicRect.GetWidth() - aP.X() );
if ( m_bFlipV )
aP.setY( m_aLogicRect.GetHeight() - aP.Y() );
if ( m_nRotateAngle )
{
double a = -toRadians(m_nRotateAngle);
RotatePoint( aP, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), sin( a ), cos( a ) );
}
const GeoStat aGeoStat(mrSdrObjCustomShape.GetGeoStat());
if ( aGeoStat.m_nShearAngle )
{
double nTan = -aGeoStat.mfTanShearAngle;
if (m_bFlipV != m_bFlipH)
nTan = -nTan;
ShearPoint( aP, Point( m_aLogicRect.GetWidth() / 2, m_aLogicRect.GetHeight() / 2 ), nTan );
}
double fPos1 = aP.X(); //( bFlipH ) ? aLogicRect.GetWidth() - aP.X() : aP.X();
double fPos2 = aP.Y(); //( bFlipV ) ? aLogicRect.GetHeight() -aP.Y() : aP.Y();
fPos1 = !basegfx::fTools::equalZero(m_fXScale) ? (fPos1 / m_fXScale) : SAL_MAX_INT32;
fPos2 = !basegfx::fTools::equalZero(m_fYScale) ? (fPos2 / m_fYScale) : SAL_MAX_INT32;
// revert -nCoordLeft and -nCoordTop aus GetPoint()
fPos1 += m_nCoordLeft;
fPos2 += m_nCoordTop;
// Used for scaling the adjustment values based on handle positions
double fWidth;
double fHeight;
if ( m_nCoordWidth || m_nCoordHeight )
{
fWidth = m_nCoordWidth;
fHeight = m_nCoordHeight;
}
else
{
fWidth = m_aLogicRect.GetWidth();
fHeight = m_aLogicRect.GetHeight();
}
if ( aHandle.nFlags & HandleFlags::SWITCHED )
{
if ( m_aLogicRect.GetHeight() > m_aLogicRect.GetWidth() )
{
double fX = fPos1;
double fY = fPos2;
double fTmp = fWidth;
fPos1 = fY;
fPos2 = fX;
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5 C=91 H=96 G=93
¤ Dauer der Verarbeitung: 0.22 Sekunden
¤
*© Formatika GbR, Deutschland