From bfa0e40e2e7182928f354ce0bfaa11152080ad5b Mon Sep 17 00:00:00 2001 From: Szymon Kłos Date: Fri, 20 Jul 2018 17:21:43 +0200 Subject: tdf#116350 Import preset text geometry (text effects) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Font effect" implementation, instead of normal text, content is converted to "fontwork". Change-Id: I5d02c7faedb66a4b919e64ae1b830bffb69984c1 Reviewed-on: https://gerrit.libreoffice.org/58358 Tested-by: Jenkins Reviewed-by: Szymon Kłos --- oox/source/drawingml/presetgeometrynames.cxx | 108 ++++++++++++ oox/source/drawingml/shape.cxx | 185 +++++++++++++++++++++ oox/source/drawingml/shapecontext.cxx | 4 +- oox/source/drawingml/textbodycontext.cxx | 12 +- oox/source/drawingml/textbodyproperties.cxx | 1 + oox/source/drawingml/textbodypropertiescontext.cxx | 32 +++- oox/source/ppt/pptshapecontext.cxx | 2 +- 7 files changed, 339 insertions(+), 5 deletions(-) create mode 100644 oox/source/drawingml/presetgeometrynames.cxx (limited to 'oox/source') diff --git a/oox/source/drawingml/presetgeometrynames.cxx b/oox/source/drawingml/presetgeometrynames.cxx new file mode 100644 index 000000000000..4939cfcf0a3f --- /dev/null +++ b/oox/source/drawingml/presetgeometrynames.cxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +typedef std::unordered_map + PresetGeometryHashMap; + +static PresetGeometryHashMap* pHashMap = nullptr; +::osl::Mutex& getHashMapMutex() +{ + static osl::Mutex s_aHashMapProtection; + return s_aHashMapProtection; +} + +struct PresetGeometryName +{ + const char* pMsoName; + const char* pFontworkType; +}; + +static const PresetGeometryName pPresetGeometryNameArray[] + = { { "textNoShape", "" }, + { "textPlain", "fontwork-plain-text" }, + { "textStop", "fontwork-stop" }, + { "textTriangle", "fontwork-triangle-up" }, + { "textTriangleInverted", "fontwork-triangle-down" }, + { "textChevron", "fontwork-chevron-up" }, + { "textChevronInverted", "fontwork-chevron-down" }, + { "textRingInside", "mso-spt142" }, + { "textRingOutside", "mso-spt143" }, + { "textArchUp", "fontwork-arch-up-curve" }, + { "textArchDown", "fontwork-arch-down-curve" }, + { "textCircle", "fontwork-circle-curve" }, + { "textButton", "fontwork-open-circle-curve" }, + { "textArchUpPour", "fontwork-arch-up-pour" }, + { "textArchDownPour", "fontwork-arch-down-pour" }, + { "textCirclePour", "fontwork-circle-pour" }, + { "textButtonPour", "fontwork-open-circle-pour" }, + { "textCurveUp", "fontwork-curve-up" }, + { "textCurveDown", "fontwork-curve-down" }, + { "textCanUp", "mso-spt174" }, + { "textCanDown", "mso-spt175" }, + { "textWave1", "fontwork-wave" }, + { "textWave2", "mso-spt157" }, + { "textDoubleWave1", "mso-spt158" }, + { "textWave4", "mso-spt159" }, + { "textInflate", "fontwork-inflate" }, + { "textDeflate", "fontwork-inflate" }, + { "textInflateBottom", "mso-spt162" }, + { "textDeflateBottom", "mso-spt163" }, + { "textInflateTop", "mso-spt163" }, + { "textDeflateTop", "mso-spt165" }, + { "textDeflateInflate", "mso-spt166" }, + { "textDeflateInflateDeflate", "mso-spt167" }, + { "textFadeRight", "fontwork-fade-right" }, + { "textFadeLeft", "fontwork-fade-left" }, + { "textFadeUp", "fontwork-fade-up" }, + { "textFadeDown", "fontwork-fade-down" }, + { "textSlantUp", "fontwork-slant-up" }, + { "textSlantDown", "fontwork-slant-down" }, + { "textCascadeUp", "fontwork-fade-up-and-right" }, + { "textCascadeDown", "fontwork-fade-up-and-left" } }; +} + +OUString PresetGeometryTypeNames::GetFontworkType(const OUString& rMsoType) +{ + if (!pHashMap) + { // init hash map + ::osl::MutexGuard aGuard(getHashMapMutex()); + if (!pHashMap) + { + PresetGeometryHashMap* pH = new PresetGeometryHashMap; + const PresetGeometryName* pPtr = pPresetGeometryNameArray; + const PresetGeometryName* pEnd = pPtr + SAL_N_ELEMENTS(pPresetGeometryNameArray); + for (; pPtr < pEnd; pPtr++) + (*pH)[pPtr->pMsoName] = pPtr->pFontworkType; + pHashMap = pH; + } + } + const char* pRetValue = ""; + int i, nLen = rMsoType.getLength(); + std::unique_ptr pBuf(new char[nLen + 1]); + for (i = 0; i < nLen; i++) + pBuf[i] = static_cast(rMsoType[i]); + pBuf[i] = 0; + PresetGeometryHashMap::const_iterator aHashIter(pHashMap->find(pBuf.get())); + if (aHashIter != pHashMap->end()) + pRetValue = (*aHashIter).second; + + return OUString(pRetValue, strlen(pRetValue), RTL_TEXTENCODING_ASCII_US); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 82498730ccde..a7ac4751bf59 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -24,6 +24,7 @@ #include #include #include +#include #include "effectproperties.hxx" #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +67,8 @@ #include #include #include +#include +#include #include #include #include @@ -85,6 +89,8 @@ #include #include #include +#include +#include #include @@ -392,6 +398,172 @@ void Shape::addChildren( } } +static inline void lcl_resetPropertyValue( std::vector& rPropVec, const OUString& rName ) +{ + auto aIterator = std::find_if( rPropVec.begin(), rPropVec.end(), + [rName]( const beans::PropertyValue& rValue ) { return rValue.Name == rName; } ); + + if (aIterator != rPropVec.end()) + rPropVec.erase( aIterator ); +} + +static inline void lcl_setPropertyValue( std::vector& rPropVec, + const OUString& rName, + const beans::PropertyValue& rPropertyValue ) +{ + auto aIterator = std::find_if( + rPropVec.begin(), rPropVec.end(), + [rName]( const beans::PropertyValue& rValue ) { return rValue.Name == rName; } ); + + if (aIterator != rPropVec.end()) + rPropVec.erase( aIterator ); + + rPropVec.push_back( rPropertyValue ); +} + +static inline SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust ) +{ + if (eAdjust == ParagraphAdjust_LEFT) + return SDRTEXTHORZADJUST_LEFT; + else if (eAdjust == ParagraphAdjust_RIGHT) + return SDRTEXTHORZADJUST_RIGHT; + else if (eAdjust == ParagraphAdjust_CENTER) + return SDRTEXTHORZADJUST_CENTER; + return SDRTEXTHORZADJUST_LEFT; +} + +static inline void lcl_createPresetShape( uno::Reference& xShape, + const OUString& rClass, + const CustomShapePropertiesPtr pCustomShapePropertiesPtr, + const TextBodyPtr pTextBody, + const GraphicHelper& rGraphicHelper ) +{ + if (!xShape.is() || !pCustomShapePropertiesPtr || !pTextBody) + return; + + uno::Reference xDefaulter( xShape, + uno::UNO_QUERY ); + + if (!xDefaulter.is() || rClass.isEmpty()) + return; + + Reference xSet( xShape, UNO_QUERY ); + if (!xSet.is()) + return; + + auto aGdList = pCustomShapePropertiesPtr->getAdjustmentGuideList(); + Sequence aAdjustment( + aGdList.size() ? aGdList.size() : 1 ); + + int nIndex = 0; + for (auto& aEntry : aGdList) + { + double fAngle = NormAngle360( aEntry.maFormula.toDouble() / -600.0 ); + fAngle = 360.0 - fAngle / 100.0; + + aAdjustment[nIndex].Value <<= fAngle; + aAdjustment[nIndex++].State = css::beans::PropertyState_DIRECT_VALUE; + } + + if (!aGdList.size()) + { + // Default angle + double fAngle = 0; + if (rClass == "fontwork-arch-up-curve") + fAngle = 180; + + aAdjustment[0].Value <<= fAngle; + aAdjustment[0].State = css::beans::PropertyState_DIRECT_VALUE; + } + + // Set properties + xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::makeAny( false ) ); + xSet->setPropertyValue( UNO_NAME_TEXT_AUTOGROWWIDTH, uno::makeAny( false ) ); + xSet->setPropertyValue( UNO_NAME_FILLSTYLE, uno::makeAny( drawing::FillStyle_SOLID ) ); + + const TextParagraphVector& rParagraphs = pTextBody->getParagraphs(); + if (rParagraphs.size() && rParagraphs[0]->getRuns().size()) + { + std::shared_ptr pParagraph = rParagraphs[0]; + std::shared_ptr pRun = pParagraph->getRuns()[0]; + TextCharacterProperties& pProperties = pRun->getTextCharacterProperties(); + + if (pProperties.moBold.has() && pProperties.moBold.get()) + { + xSet->setPropertyValue( UNO_NAME_CHAR_WEIGHT, uno::makeAny( css::awt::FontWeight::BOLD ) ); + } + if (pProperties.moItalic.has() && pProperties.moItalic.get()) + { + xSet->setPropertyValue( UNO_NAME_CHAR_POSTURE, uno::makeAny( css::awt::FontSlant::FontSlant_ITALIC ) ); + } + if (pProperties.moHeight.has()) + { + sal_Int32 nHeight = pProperties.moHeight.get() / 100; + xSet->setPropertyValue( UNO_NAME_CHAR_HEIGHT, uno::makeAny( nHeight ) ); + } + if (pProperties.maFillProperties.maFillColor.isUsed()) + { + const sal_Int32 aFillColor = static_cast( + pProperties.maFillProperties.maFillColor.getColor( rGraphicHelper ) ); + xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::makeAny( aFillColor ) ); + } + else + { + // Set default color + xSet->setPropertyValue( UNO_NAME_FILLCOLOR, uno::makeAny( COL_BLACK ) ); + } + { + ParagraphAdjust eAdjust = ParagraphAdjust_LEFT; + if (pParagraph->getProperties().getParaAdjust()) + eAdjust = pParagraph->getProperties().getParaAdjust().get(); + xSet->setPropertyValue( "ParaAdjust", uno::makeAny( eAdjust ) ); + SvxShape* pShape = SvxShape::getImplementation( xShape ); + SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust( eAdjust ); + pShape->GetSdrObject()->SetMergedItem( SdrTextHorzAdjustItem( eHorzAdjust ) ); + } + } + + // Apply preset shape + xDefaulter->createCustomShapeDefaults( rClass ); + + auto aGeomPropSeq = xSet->getPropertyValue( "CustomShapeGeometry" ) + .get>(); + auto aGeomPropVec + = comphelper::sequenceToContainer>( + aGeomPropSeq ); + + // Reset old properties + const OUString sCoordinateSize( "CoordinateSize" ); + const OUString sEquations( "Equations" ); + const OUString sPath( "Path" ); + const OUString sTextPath( "TextPath" ); + const OUString sAdjustmentValues( "AdjustmentValues" ); + + lcl_resetPropertyValue( aGeomPropVec, sCoordinateSize ); + lcl_resetPropertyValue( aGeomPropVec, sEquations ); + lcl_resetPropertyValue( aGeomPropVec, sPath ); + + // Apply geometry properties + uno::Sequence aPropertyValues( + comphelper::InitPropertySequence( + { { sTextPath, uno::makeAny( true ) }, + { "TextPathMode", + uno::Any( drawing::EnhancedCustomShapeTextPathMode_PATH ) }, + { "ScaleX", uno::Any( false ) } } ) ); + + lcl_setPropertyValue( aGeomPropVec, sTextPath, + comphelper::makePropertyValue( sTextPath, aPropertyValues ) ); + + if ( rClass == "fontwork-arch-up-curve" || rClass == "fontwork-circle-curve" + || rClass == "fontwork-arch-down-curve" || rClass == "fontwork-open-circle-curve" ) + lcl_setPropertyValue( aGeomPropVec, sAdjustmentValues, + comphelper::makePropertyValue( sAdjustmentValues, aAdjustment ) ); + + xSet->setPropertyValue( + "CustomShapeGeometry", + uno::makeAny(comphelper::containerToSequence(aGeomPropVec))); +} + Reference< XShape > const & Shape::createAndInsert( ::oox::core::XmlFilterBase& rFilterBase, const OUString& rServiceName, @@ -1124,6 +1296,19 @@ Reference< XShape > const & Shape::createAndInsert( SAL_INFO("oox.cscode", "==cscode== shape name: '" << msName << "'"); SAL_INFO("oox.csdata", "==csdata== shape name: '" << msName << "'"); mpCustomShapePropertiesPtr->pushToPropSet( xSet, mxShape, maSize ); + + if (mpTextBody) + { + bool bIsPresetShape = !mpTextBody->getTextProperties().msPrst.isEmpty(); + if (bIsPresetShape) + { + OUString sClass; + const OUString sPresetType = mpTextBody->getTextProperties().msPrst; + sClass = PresetGeometryTypeNames::GetFontworkType( sPresetType ); + + lcl_createPresetShape( mxShape, sClass, mpCustomShapePropertiesPtr, mpTextBody, rGraphicHelper ); + } + } } else if( getTextBody() ) getTextBody()->getTextProperties().pushVertSimulation(); diff --git a/oox/source/drawingml/shapecontext.cxx b/oox/source/drawingml/shapecontext.cxx index 03ae290cc1ea..dfa2d1f74183 100644 --- a/oox/source/drawingml/shapecontext.cxx +++ b/oox/source/drawingml/shapecontext.cxx @@ -96,7 +96,7 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 aElementToken, const { if (!mpShapePtr->getTextBody()) mpShapePtr->setTextBody( std::make_shared() ); - return new TextBodyContext( *this, *mpShapePtr->getTextBody() ); + return new TextBodyContext( *this, mpShapePtr ); } case XML_txXfrm: { @@ -110,7 +110,7 @@ ContextHandlerRef ShapeContext::onCreateContext( sal_Int32 aElementToken, const case XML_bodyPr: if (!mpShapePtr->getTextBody()) mpShapePtr->setTextBody( std::make_shared() ); - return new TextBodyPropertiesContext( *this, rAttribs, mpShapePtr->getTextBody()->getTextProperties() ); + return new TextBodyPropertiesContext( *this, rAttribs, mpShapePtr ); break; case XML_txbx: break; diff --git a/oox/source/drawingml/textbodycontext.cxx b/oox/source/drawingml/textbodycontext.cxx index ea985f6b78a0..84cf4d4b071b 100644 --- a/oox/source/drawingml/textbodycontext.cxx +++ b/oox/source/drawingml/textbodycontext.cxx @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -161,12 +162,21 @@ TextBodyContext::TextBodyContext( ContextHandler2Helper const & rParent, TextBod { } +TextBodyContext::TextBodyContext( ContextHandler2Helper const & rParent, ShapePtr pShapePtr ) +: TextBodyContext( rParent, *pShapePtr->getTextBody() ) +{ + mpShapePtr = pShapePtr; +} + ContextHandlerRef TextBodyContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) { switch( aElementToken ) { case A_TOKEN( bodyPr ): // CT_TextBodyPropertyBag - return new TextBodyPropertiesContext( *this, rAttribs, mrTextBody.getTextProperties() ); + if ( mpShapePtr ) + return new TextBodyPropertiesContext( *this, rAttribs, mpShapePtr ); + else + return new TextBodyPropertiesContext( *this, rAttribs, mrTextBody.getTextProperties() ); case A_TOKEN( lstStyle ): // CT_TextListStyle return new TextListStyleContext( *this, mrTextBody.getTextListStyle() ); case A_TOKEN( p ): // CT_TextParagraph diff --git a/oox/source/drawingml/textbodyproperties.cxx b/oox/source/drawingml/textbodyproperties.cxx index 71f8c8c3f1bd..5998c429b494 100644 --- a/oox/source/drawingml/textbodyproperties.cxx +++ b/oox/source/drawingml/textbodyproperties.cxx @@ -33,6 +33,7 @@ namespace drawingml { TextBodyProperties::TextBodyProperties() : mbAnchorCtr(false) , meVA( TextVerticalAdjust_TOP ) + , msPrst() { } diff --git a/oox/source/drawingml/textbodypropertiescontext.cxx b/oox/source/drawingml/textbodypropertiescontext.cxx index 13c50aa1b07a..e564cf04d149 100644 --- a/oox/source/drawingml/textbodypropertiescontext.cxx +++ b/oox/source/drawingml/textbodypropertiescontext.cxx @@ -22,13 +22,22 @@ #include #include #include +#include +#include #include +#include +#include #include #include #include #include #include #include +#include +#include +#include +#include +#include using namespace ::oox::core; using namespace ::com::sun::star; @@ -40,10 +49,18 @@ using namespace ::com::sun::star::xml::sax; namespace oox { namespace drawingml { // CT_TextBodyProperties +TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper const & rParent, + const AttributeList& rAttribs, ShapePtr pShapePtr ) +: TextBodyPropertiesContext( rParent, rAttribs, pShapePtr->getTextBody()->getTextProperties() ) +{ + mpShapePtr = pShapePtr; +} + TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper const & rParent, const AttributeList& rAttribs, TextBodyProperties& rTextBodyProp ) : ContextHandler2( rParent ) , mrTextBodyProp( rTextBodyProp ) +, mpShapePtr( nullptr ) { // ST_TextWrappingType sal_Int32 nWrappingType = rAttribs.getToken( XML_wrap, XML_square ); @@ -111,12 +128,25 @@ TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper cons mrTextBodyProp.maPropertyMap.setProperty( PROP_TextFitToSize, drawing::TextFitToSizeType_NONE); } -ContextHandlerRef TextBodyPropertiesContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/) +ContextHandlerRef TextBodyPropertiesContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) { switch( aElementToken ) { // Sequence case A_TOKEN( prstTxWarp ): // CT_PresetTextShape + if( mpShapePtr ) + { + const OptValue sPrst = rAttribs.getString( XML_prst ); + if( sPrst.has() ) + { + mrTextBodyProp.msPrst = sPrst.get(); + if( mrTextBodyProp.msPrst != "textNoShape" ) + return new PresetTextShapeContext( *this, rAttribs, + *( mpShapePtr->getCustomShapeProperties() ) ); + } + } + break; + case A_TOKEN( prot ): // CT_TextProtectionProperty break; diff --git a/oox/source/ppt/pptshapecontext.cxx b/oox/source/ppt/pptshapecontext.cxx index 304fdb933860..6b4a7fb60631 100644 --- a/oox/source/ppt/pptshapecontext.cxx +++ b/oox/source/ppt/pptshapecontext.cxx @@ -173,7 +173,7 @@ ContextHandlerRef PPTShapeContext::onCreateContext( sal_Int32 aElementToken, con oox::drawingml::TextBodyPtr xTextBody( new oox::drawingml::TextBody( mpShapePtr->getTextBody() ) ); xTextBody->getTextProperties().maPropertyMap.setProperty( PROP_FontIndependentLineSpacing, true ); mpShapePtr->setTextBody( xTextBody ); - return new oox::drawingml::TextBodyContext( *this, *xTextBody ); + return new oox::drawingml::TextBodyContext( *this, mpShapePtr ); } case PPT_TOKEN( txXfrm ): { -- cgit