oox/source/core/filterbase.cxx | 34 - oox/source/core/filterdetect.cxx | 32 oox/source/core/xmlfilterbase.cxx | 114 +-- oox/source/docprop/docprophandler.cxx | 126 +-- oox/source/docprop/ooxmldocpropimport.cxx | 42 - oox/source/drawingml/chart/chartdrawingfragment.cxx | 42 - oox/source/drawingml/chart/converterbase.cxx | 85 +- oox/source/drawingml/chart/objectformatter.cxx | 232 +++--- oox/source/drawingml/chart/plotareaconverter.cxx | 10 oox/source/drawingml/chart/seriesconverter.cxx | 86 +- oox/source/drawingml/chart/titleconverter.cxx | 62 + oox/source/drawingml/chart/typegroupconverter.cxx | 158 ++-- oox/source/drawingml/fillproperties.cxx | 680 ++++++++++---------- oox/source/drawingml/lineproperties.cxx | 108 +-- oox/source/drawingml/shape.cxx | 36 - oox/source/drawingml/textbodyproperties.cxx | 31 oox/source/dump/dumperbase.cxx | 48 - oox/source/dump/oledumper.cxx | 96 +- oox/source/export/chartexport.cxx | 511 +++++++-------- oox/source/export/drawingml.cxx | 380 +++++------ oox/source/export/vmlexport.cxx | 64 - oox/source/helper/binaryoutputstream.cxx | 24 oox/source/helper/propertymap.cxx | 22 oox/source/helper/storagebase.cxx | 36 - oox/source/helper/zipstorage.cxx | 5 oox/source/ole/axcontrol.cxx | 5 oox/source/ole/olehelper.cxx | 92 +- oox/source/ole/vbacontrol.cxx | 225 +++--- oox/source/ole/vbaproject.cxx | 16 oox/source/ppt/pptimport.cxx | 35 - oox/source/ppt/pptshapegroupcontext.cxx | 30 oox/source/ppt/presentationfragmenthandler.cxx | 84 +- oox/source/ppt/slidepersist.cxx | 174 ++--- oox/source/ppt/soundactioncontext.cxx | 40 - oox/source/ppt/timenodelistcontext.cxx | 214 +++--- oox/source/shape/ShapeContextHandler.cxx | 26 oox/source/vml/vmlformatting.cxx | 80 +- oox/source/vml/vmlshape.cxx | 52 - oox/source/vml/vmltextbox.cxx | 30 39 files changed, 2104 insertions(+), 2063 deletions(-)
New commits: commit b8f15244054aea276152494ee9f79318a70658e7 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Fri Apr 3 11:09:04 2020 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Fri Apr 3 12:18:17 2020 +0200 loplugin:flatten in oox Change-Id: Ia57944653fa10e864822518372acab83555e0f20 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91618 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/oox/source/core/filterbase.cxx b/oox/source/core/filterbase.cxx index 0cb7f2a264b1..94f7c08c9b20 100644 --- a/oox/source/core/filterbase.cxx +++ b/oox/source/core/filterbase.cxx @@ -407,25 +407,25 @@ void SAL_CALL FilterBase::initialize( const Sequence< Any >& rArgs ) { } - if (rArgs.hasElements()) + if (!rArgs.hasElements()) + return; + + Sequence<css::beans::PropertyValue> aSeq; + rArgs[0] >>= aSeq; + for (const auto& rVal : std::as_const(aSeq)) { - Sequence<css::beans::PropertyValue> aSeq; - rArgs[0] >>= aSeq; - for (const auto& rVal : std::as_const(aSeq)) + if (rVal.Name == "UserData") + { + css::uno::Sequence<OUString> aUserDataSeq; + rVal.Value >>= aUserDataSeq; + if (comphelper::findValue(aUserDataSeq, "macro-enabled") != -1) + mxImpl->mbExportVBA = true; + } + else if (rVal.Name == "Flags") { - if (rVal.Name == "UserData") - { - css::uno::Sequence<OUString> aUserDataSeq; - rVal.Value >>= aUserDataSeq; - if (comphelper::findValue(aUserDataSeq, "macro-enabled") != -1) - mxImpl->mbExportVBA = true; - } - else if (rVal.Name == "Flags") - { - sal_Int32 nFlags(0); - rVal.Value >>= nFlags; - mxImpl->mbExportTemplate = bool(static_cast<SfxFilterFlags>(nFlags) & SfxFilterFlags::TEMPLATE); - } + sal_Int32 nFlags(0); + rVal.Value >>= nFlags; + mxImpl->mbExportTemplate = bool(static_cast<SfxFilterFlags>(nFlags) & SfxFilterFlags::TEMPLATE); } } } diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx index b63d355ed506..c8ce03acb75c 100644 --- a/oox/source/core/filterdetect.cxx +++ b/oox/source/core/filterdetect.cxx @@ -142,25 +142,25 @@ void SAL_CALL FilterDetectDocHandler::characters( const OUString& /*aChars*/ ) void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs ) { OUString aType = rAttribs.getString( XML_Type, OUString() ); - if ( aType == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" // OOXML Transitional - || aType == "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument" ) //OOXML strict + if ( !(aType == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" // OOXML Transitional + || aType == "http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument") ) //OOXML strict + return; + + Reference<XUriReferenceFactory> xFactory = UriReferenceFactory::create( mxContext ); + try { - Reference<XUriReferenceFactory> xFactory = UriReferenceFactory::create( mxContext ); - try - { - // use '/' to representent the root of the zip package ( and provide a 'file' scheme to - // keep the XUriReference implementation happy ) - Reference< XUriReference > xBase = xFactory->parse( "file:///" ); + // use '/' to representent the root of the zip package ( and provide a 'file' scheme to + // keep the XUriReference implementation happy ) + Reference< XUriReference > xBase = xFactory->parse( "file:///" ); - Reference< XUriReference > xPart = xFactory->parse( rAttribs.getString( XML_Target, OUString() ) ); - Reference< XUriReference > xAbs = xFactory->makeAbsolute( xBase, xPart, true, RelativeUriExcessParentSegments_RETAIN ); + Reference< XUriReference > xPart = xFactory->parse( rAttribs.getString( XML_Target, OUString() ) ); + Reference< XUriReference > xAbs = xFactory->makeAbsolute( xBase, xPart, true, RelativeUriExcessParentSegments_RETAIN ); - if ( xAbs.is() ) - maTargetPath = xAbs->getPath(); - } - catch( const Exception& ) - { - } + if ( xAbs.is() ) + maTargetPath = xAbs->getPath(); + } + catch( const Exception& ) + { } } diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx index f59b0cbc5821..84aaef6af9db 100644 --- a/oox/source/core/xmlfilterbase.cxx +++ b/oox/source/core/xmlfilterbase.cxx @@ -963,76 +963,76 @@ OUString XmlFilterBase::getNamespaceURL(sal_Int32 nNSID) const void XmlFilterBase::importCustomFragments(css::uno::Reference<css::embed::XStorage> const & xDocumentStorage) { Reference<XRelationshipAccess> xRelations(xDocumentStorage, UNO_QUERY); - if (xRelations.is()) - { - const uno::Sequence<uno::Sequence<beans::StringPair>> aSeqs = xRelations->getAllRelationships(); + if (!xRelations.is()) + return; + + const uno::Sequence<uno::Sequence<beans::StringPair>> aSeqs = xRelations->getAllRelationships(); - std::vector<StreamDataSequence> aCustomFragments; - std::vector<OUString> aCustomFragmentTypes; - std::vector<OUString> aCustomFragmentTargets; - for (const uno::Sequence<beans::StringPair>& aSeq : aSeqs) + std::vector<StreamDataSequence> aCustomFragments; + std::vector<OUString> aCustomFragmentTypes; + std::vector<OUString> aCustomFragmentTargets; + for (const uno::Sequence<beans::StringPair>& aSeq : aSeqs) + { + OUString sType; + OUString sTarget; + for (const beans::StringPair& aPair : aSeq) { - OUString sType; - OUString sTarget; - for (const beans::StringPair& aPair : aSeq) - { - if (aPair.First == "Target") - sTarget = aPair.Second; - else if (aPair.First == "Type") - sType = aPair.Second; - } + if (aPair.First == "Target") + sTarget = aPair.Second; + else if (aPair.First == "Type") + sType = aPair.Second; + } - // Preserve non-standard (i.e. custom) entries. - if (!sType.match("http://schemas.openxmlformats.org")) + // Preserve non-standard (i.e. custom) entries. + if (!sType.match("http://schemas.openxmlformats.org")) + { + StreamDataSequence aDataSeq; + if (importBinaryData(aDataSeq, sTarget)) { - StreamDataSequence aDataSeq; - if (importBinaryData(aDataSeq, sTarget)) - { - aCustomFragments.emplace_back(aDataSeq); - aCustomFragmentTypes.emplace_back(sType); - aCustomFragmentTargets.emplace_back(sTarget); - } + aCustomFragments.emplace_back(aDataSeq); + aCustomFragmentTypes.emplace_back(sType); + aCustomFragmentTargets.emplace_back(sTarget); } } + } - // Adding the saved custom xml DOM - comphelper::SequenceAsHashMap aGrabBagProperties; - aGrabBagProperties["OOXCustomFragments"] <<= comphelper::containerToSequence(aCustomFragments); - aGrabBagProperties["OOXCustomFragmentTypes"] <<= comphelper::containerToSequence(aCustomFragmentTypes); - aGrabBagProperties["OOXCustomFragmentTargets"] <<= comphelper::containerToSequence(aCustomFragmentTargets); - - std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomList; - std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList; - //FIXME: Ideally, we should get these the relations, but it seems that is not consistently set. - // In some cases it's stored in the workbook relationships, which is unexpected. So we discover them directly. - for (int i = 1; ; ++i) + // Adding the saved custom xml DOM + comphelper::SequenceAsHashMap aGrabBagProperties; + aGrabBagProperties["OOXCustomFragments"] <<= comphelper::containerToSequence(aCustomFragments); + aGrabBagProperties["OOXCustomFragmentTypes"] <<= comphelper::containerToSequence(aCustomFragmentTypes); + aGrabBagProperties["OOXCustomFragmentTargets"] <<= comphelper::containerToSequence(aCustomFragmentTargets); + + std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomList; + std::vector<uno::Reference<xml::dom::XDocument>> aCustomXmlDomPropsList; + //FIXME: Ideally, we should get these the relations, but it seems that is not consistently set. + // In some cases it's stored in the workbook relationships, which is unexpected. So we discover them directly. + for (int i = 1; ; ++i) + { + Reference<XDocument> xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml"); + Reference<XDocument> xCustDocProps = importFragment("customXml/itemProps" + OUString::number(i) + ".xml"); + if (xCustDoc && xCustDocProps) { - Reference<XDocument> xCustDoc = importFragment("customXml/item" + OUString::number(i) + ".xml"); - Reference<XDocument> xCustDocProps = importFragment("customXml/itemProps" + OUString::number(i) + ".xml"); - if (xCustDoc && xCustDocProps) - { - aCustomXmlDomList.emplace_back(xCustDoc); - aCustomXmlDomPropsList.emplace_back(xCustDocProps); - } - else - break; + aCustomXmlDomList.emplace_back(xCustDoc); + aCustomXmlDomPropsList.emplace_back(xCustDocProps); } + else + break; + } - // Adding the saved custom xml DOM - aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList); - aGrabBagProperties["OOXCustomXmlProps"] <<= comphelper::containerToSequence(aCustomXmlDomPropsList); + // Adding the saved custom xml DOM + aGrabBagProperties["OOXCustomXml"] <<= comphelper::containerToSequence(aCustomXmlDomList); + aGrabBagProperties["OOXCustomXmlProps"] <<= comphelper::containerToSequence(aCustomXmlDomPropsList); - // Save the [Content_Types].xml after parsing. - uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypeInfo; - uno::Reference<io::XInputStream> xInputStream = openInputStream("[Content_Types].xml"); - if (xInputStream.is()) - aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream, getComponentContext()); + // Save the [Content_Types].xml after parsing. + uno::Sequence<uno::Sequence<beans::StringPair>> aContentTypeInfo; + uno::Reference<io::XInputStream> xInputStream = openInputStream("[Content_Types].xml"); + if (xInputStream.is()) + aContentTypeInfo = comphelper::OFOPXMLHelper::ReadContentTypeSequence(xInputStream, getComponentContext()); - aGrabBagProperties["OOXContentTypes"] <<= aContentTypeInfo; + aGrabBagProperties["OOXContentTypes"] <<= aContentTypeInfo; - Reference<XComponent> xModel = getModel(); - oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(xModel, aGrabBagProperties); - } + Reference<XComponent> xModel = getModel(); + oox::core::XmlFilterBase::putPropertiesToDocumentGrabBag(xModel, aGrabBagProperties); } void XmlFilterBase::exportCustomFragments() diff --git a/oox/source/docprop/docprophandler.cxx b/oox/source/docprop/docprophandler.cxx index 47882a0749de..67de4a8366bd 100644 --- a/oox/source/docprop/docprophandler.cxx +++ b/oox/source/docprop/docprophandler.cxx @@ -69,26 +69,26 @@ void OOXMLDocPropHandler::InitNew() void OOXMLDocPropHandler::AddCustomProperty( const uno::Any& aAny ) { - if ( !m_aCustomPropertyName.isEmpty() ) - { - const uno::Reference< beans::XPropertyContainer > xUserProps = - m_xDocProp->getUserDefinedProperties(); - if ( !xUserProps.is() ) - throw uno::RuntimeException(); + if ( m_aCustomPropertyName.isEmpty() ) + return; - try - { - xUserProps->addProperty( m_aCustomPropertyName, - beans::PropertyAttribute::REMOVABLE, aAny ); - } - catch( beans::PropertyExistException& ) - { - // conflicts with core and extended properties are possible - } - catch( uno::Exception& ) - { - OSL_FAIL( "Can not add custom property!" ); - } + const uno::Reference< beans::XPropertyContainer > xUserProps = + m_xDocProp->getUserDefinedProperties(); + if ( !xUserProps.is() ) + throw uno::RuntimeException(); + + try + { + xUserProps->addProperty( m_aCustomPropertyName, + beans::PropertyAttribute::REMOVABLE, aAny ); + } + catch( beans::PropertyExistException& ) + { + // conflicts with core and extended properties are possible + } + catch( uno::Exception& ) + { + OSL_FAIL( "Can not add custom property!" ); } } @@ -245,24 +245,24 @@ void OOXMLDocPropHandler::UpdateDocStatistic( const OUString& aChars ) break; } - if ( !aName.isEmpty() ) - { - sal_Int32 nInd = 0; - for ( auto pProp = aSet.getConstArray(); nInd < aSet.getLength(); ++nInd ) - if ( pProp[nInd].Name == aName ) - break; + if ( aName.isEmpty() ) + return; - if (nInd == aSet.getLength()) - aSet.realloc( nInd + 1 ); + sal_Int32 nInd = 0; + for ( auto pProp = aSet.getConstArray(); nInd < aSet.getLength(); ++nInd ) + if ( pProp[nInd].Name == aName ) + break; - beans::NamedValue aProp; - aProp.Name = aName; - aProp.Value <<= aChars.toInt32(); + if (nInd == aSet.getLength()) + aSet.realloc( nInd + 1 ); - aSet[nInd] = aProp; + beans::NamedValue aProp; + aProp.Name = aName; + aProp.Value <<= aChars.toInt32(); - m_xDocProp->setDocumentStatistics( aSet ); - } + aSet[nInd] = aProp; + + m_xDocProp->setDocumentStatistics( aSet ); } // com.sun.star.xml.sax.XFastDocumentHandler @@ -338,41 +338,41 @@ void SAL_CALL OOXMLDocPropHandler::startUnknownElement( const OUString& aNamespa void SAL_CALL OOXMLDocPropHandler::endFastElement( ::sal_Int32 ) { - if ( m_nInBlock ) - { - m_nInBlock--; + if ( !m_nInBlock ) + return; - if ( !m_nInBlock ) - m_nState = 0; - else if ( m_nInBlock == 1 ) - { - m_nBlock = 0; - m_aCustomPropertyName.clear(); - } - else if ( m_nInBlock == 2 ) + m_nInBlock--; + + if ( !m_nInBlock ) + m_nState = 0; + else if ( m_nInBlock == 1 ) + { + m_nBlock = 0; + m_aCustomPropertyName.clear(); + } + else if ( m_nInBlock == 2 ) + { + if ( m_nState == CUSTPR_TOKEN(Properties) + && m_nBlock == CUSTPR_TOKEN(property)) { - if ( m_nState == CUSTPR_TOKEN(Properties) - && m_nBlock == CUSTPR_TOKEN(property)) + switch (m_nType) { - switch (m_nType) - { - case VT_TOKEN(bstr): - case VT_TOKEN(lpstr): - case VT_TOKEN(lpwstr): - if (!m_aCustomPropertyName.isEmpty() && - INSERTED != m_CustomStringPropertyState) - { - // the property has string type, so it is valid - // even with an empty value - characters() has - // not been called in that case - AddCustomProperty(uno::makeAny(OUString())); - } - break; - } + case VT_TOKEN(bstr): + case VT_TOKEN(lpstr): + case VT_TOKEN(lpwstr): + if (!m_aCustomPropertyName.isEmpty() && + INSERTED != m_CustomStringPropertyState) + { + // the property has string type, so it is valid + // even with an empty value - characters() has + // not been called in that case + AddCustomProperty(uno::makeAny(OUString())); + } + break; } - m_CustomStringPropertyState = NONE; - m_nType = 0; } + m_CustomStringPropertyState = NONE; + m_nType = 0; } } diff --git a/oox/source/docprop/ooxmldocpropimport.cxx b/oox/source/docprop/ooxmldocpropimport.cxx index 8731ecf56897..621173b6bdea 100644 --- a/oox/source/docprop/ooxmldocpropimport.cxx +++ b/oox/source/docprop/ooxmldocpropimport.cxx @@ -136,27 +136,27 @@ void SAL_CALL DocumentPropertiesImport::importProperties( if( !aCustomStreams.hasElements() ) aCustomStreams = lclGetRelatedStreams( rxSource, CREATE_OFFICEDOC_RELATION_TYPE_STRICT( "custom-properties" ) ); - if( aCoreStreams.hasElements() || aExtStreams.hasElements() || aCustomStreams.hasElements() ) - { - if( aCoreStreams.getLength() > 1 ) - throw IOException( "Unexpected core properties stream!" ); - - ::oox::core::FastParser aParser; - aParser.registerNamespace( NMSP_packageMetaCorePr ); - aParser.registerNamespace( NMSP_dc ); - aParser.registerNamespace( NMSP_dcTerms ); - aParser.registerNamespace( NMSP_officeExtPr ); - aParser.registerNamespace( NMSP_officeCustomPr ); - aParser.registerNamespace( NMSP_officeDocPropsVT ); - aParser.setDocumentHandler( new OOXMLDocPropHandler( mxContext, rxDocumentProperties ) ); - - if( aCoreStreams.hasElements() ) - aParser.parseStream( aCoreStreams[ 0 ], true ); - for( const auto& rExtStream : std::as_const(aExtStreams) ) - aParser.parseStream( rExtStream, true ); - for( const auto& rCustomStream : std::as_const(aCustomStreams) ) - aParser.parseStream( rCustomStream, true ); - } + if( !(aCoreStreams.hasElements() || aExtStreams.hasElements() || aCustomStreams.hasElements()) ) + return; + + if( aCoreStreams.getLength() > 1 ) + throw IOException( "Unexpected core properties stream!" ); + + ::oox::core::FastParser aParser; + aParser.registerNamespace( NMSP_packageMetaCorePr ); + aParser.registerNamespace( NMSP_dc ); + aParser.registerNamespace( NMSP_dcTerms ); + aParser.registerNamespace( NMSP_officeExtPr ); + aParser.registerNamespace( NMSP_officeCustomPr ); + aParser.registerNamespace( NMSP_officeDocPropsVT ); + aParser.setDocumentHandler( new OOXMLDocPropHandler( mxContext, rxDocumentProperties ) ); + + if( aCoreStreams.hasElements() ) + aParser.parseStream( aCoreStreams[ 0 ], true ); + for( const auto& rExtStream : std::as_const(aExtStreams) ) + aParser.parseStream( rExtStream, true ); + for( const auto& rCustomStream : std::as_const(aCustomStreams) ) + aParser.parseStream( rCustomStream, true ); } } // namespace oox::docprop diff --git a/oox/source/drawingml/chart/chartdrawingfragment.cxx b/oox/source/drawingml/chart/chartdrawingfragment.cxx index af20cd292368..fb775338d90c 100644 --- a/oox/source/drawingml/chart/chartdrawingfragment.cxx +++ b/oox/source/drawingml/chart/chartdrawingfragment.cxx @@ -201,31 +201,31 @@ void ChartDrawingFragment::onCharacters( const OUString& rChars ) void ChartDrawingFragment::onEndElement() { - if( isCurrentElement( CDR_TOKEN( absSizeAnchor ), CDR_TOKEN( relSizeAnchor ) ) ) + if( !isCurrentElement( CDR_TOKEN( absSizeAnchor ), CDR_TOKEN( relSizeAnchor ) ) ) + return; + + if( mxDrawPage.is() && mxShape.get() && mxAnchor.get() ) { - if( mxDrawPage.is() && mxShape.get() && mxAnchor.get() ) + EmuRectangle aShapeRectEmu = mxAnchor->calcAnchorRectEmu( maChartRectEmu ); + if( (aShapeRectEmu.X >= 0) && (aShapeRectEmu.Y >= 0) && (aShapeRectEmu.Width >= 0) && (aShapeRectEmu.Height >= 0) ) { - EmuRectangle aShapeRectEmu = mxAnchor->calcAnchorRectEmu( maChartRectEmu ); - if( (aShapeRectEmu.X >= 0) && (aShapeRectEmu.Y >= 0) && (aShapeRectEmu.Width >= 0) && (aShapeRectEmu.Height >= 0) ) - { - // TODO: DrawingML implementation expects 32-bit coordinates for EMU rectangles (change that to EmuRectangle) - awt::Rectangle aShapeRectEmu32( - getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.X, 0, SAL_MAX_INT32 ), - getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Y, 0, SAL_MAX_INT32 ), - getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Width, 0, SAL_MAX_INT32 ), - getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Height, 0, SAL_MAX_INT32 ) ); - - // Set the position and size before calling addShape(). - mxShape->setPosition(awt::Point(aShapeRectEmu32.X, aShapeRectEmu32.Y)); - mxShape->setSize(awt::Size(aShapeRectEmu32.Width, aShapeRectEmu32.Height)); - - basegfx::B2DHomMatrix aMatrix; - mxShape->addShape( getFilter(), getFilter().getCurrentTheme(), mxDrawPage, aMatrix, mxShape->getFillProperties() ); - } + // TODO: DrawingML implementation expects 32-bit coordinates for EMU rectangles (change that to EmuRectangle) + awt::Rectangle aShapeRectEmu32( + getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.X, 0, SAL_MAX_INT32 ), + getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Y, 0, SAL_MAX_INT32 ), + getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Width, 0, SAL_MAX_INT32 ), + getLimitedValue< sal_Int32, sal_Int64 >( aShapeRectEmu.Height, 0, SAL_MAX_INT32 ) ); + + // Set the position and size before calling addShape(). + mxShape->setPosition(awt::Point(aShapeRectEmu32.X, aShapeRectEmu32.Y)); + mxShape->setSize(awt::Size(aShapeRectEmu32.Width, aShapeRectEmu32.Height)); + + basegfx::B2DHomMatrix aMatrix; + mxShape->addShape( getFilter(), getFilter().getCurrentTheme(), mxDrawPage, aMatrix, mxShape->getFillProperties() ); } - mxShape.reset(); - mxAnchor.reset(); } + mxShape.reset(); + mxAnchor.reset(); } } // namespace oox::drawingml::chart diff --git a/oox/source/drawingml/chart/converterbase.cxx b/oox/source/drawingml/chart/converterbase.cxx index 46494ebd8d8f..e24d6c72821e 100644 --- a/oox/source/drawingml/chart/converterbase.cxx +++ b/oox/source/drawingml/chart/converterbase.cxx @@ -76,7 +76,10 @@ struct TitleLayoutInfo void TitleLayoutInfo::convertTitlePos( ConverterRoot const & rRoot, const Reference< cssc::XChartDocument >& rxChart1Doc ) { - if( mxTitle.is() && mpGetShape ) try + if( !(mxTitle.is() && mpGetShape) ) + return; + + try { // try to get the title shape Reference< XShape > xTitleShape = mpGetShape( rxChart1Doc ); @@ -387,48 +390,48 @@ bool LayoutConverter::convertFromModel( PropertySet& rPropSet ) void LayoutConverter::convertFromModel( const Reference< XShape >& rxShape, double fRotationAngle ) { - if( !mrModel.mbAutoLayout ) + if( mrModel.mbAutoLayout ) + return; + + awt::Size aChartSize = getChartSize(); + if( aChartSize.Width <= 0 || aChartSize.Height <= 0 ) { - awt::Size aChartSize = getChartSize(); - if( aChartSize.Width <= 0 || aChartSize.Height <= 0 ) - { - aChartSize = getDefaultPageSize(); - } - awt::Point aShapePos( - lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode ), - lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode ) ); - if( (aShapePos.X >= 0) && (aShapePos.Y >= 0) ) - { - bool bPropSet = false; - // the call to XShape.getSize() may recalc the chart view - awt::Size aShapeSize = rxShape->getSize(); - // rotated shapes need special handling... - if( aShapeSize.Height > 0 || aShapeSize.Width > 0 ) - { - double fSin = fabs(sin(basegfx::deg2rad(fRotationAngle))); - // add part of height to X direction, if title is rotated down - if( fRotationAngle > 180.0 ) - aShapePos.X += static_cast<sal_Int32>(fSin * aShapeSize.Height + 0.5); - // add part of width to Y direction, if title is rotated up - else if( fRotationAngle > 0.0 ) - aShapePos.Y += static_cast<sal_Int32>(fSin * aShapeSize.Width + 0.5); - } - else if( fRotationAngle == 90.0 || fRotationAngle == 270.0 ) - { - PropertySet aShapeProp( rxShape ); - RelativePosition aPos( - getLimitedValue< double, double >(mrModel.mfX, 0.0, 1.0), - getLimitedValue< double, double >(mrModel.mfY, 0.0, 1.0), - fRotationAngle == 90.0 ? Alignment_TOP_RIGHT : Alignment_BOTTOM_LEFT ); - // set the resulting position at the shape - if( aShapeProp.setProperty(PROP_RelativePosition, aPos) ) - bPropSet = true; - } - // set the resulting position at the shape - if( !bPropSet ) - rxShape->setPosition( aShapePos ); - } + aChartSize = getDefaultPageSize(); + } + awt::Point aShapePos( + lclCalcPosition( aChartSize.Width, mrModel.mfX, mrModel.mnXMode ), + lclCalcPosition( aChartSize.Height, mrModel.mfY, mrModel.mnYMode ) ); + if( !((aShapePos.X >= 0) && (aShapePos.Y >= 0)) ) + return; + + bool bPropSet = false; + // the call to XShape.getSize() may recalc the chart view + awt::Size aShapeSize = rxShape->getSize(); + // rotated shapes need special handling... + if( aShapeSize.Height > 0 || aShapeSize.Width > 0 ) + { + double fSin = fabs(sin(basegfx::deg2rad(fRotationAngle))); + // add part of height to X direction, if title is rotated down + if( fRotationAngle > 180.0 ) + aShapePos.X += static_cast<sal_Int32>(fSin * aShapeSize.Height + 0.5); + // add part of width to Y direction, if title is rotated up + else if( fRotationAngle > 0.0 ) + aShapePos.Y += static_cast<sal_Int32>(fSin * aShapeSize.Width + 0.5); + } + else if( fRotationAngle == 90.0 || fRotationAngle == 270.0 ) + { + PropertySet aShapeProp( rxShape ); + RelativePosition aPos( + getLimitedValue< double, double >(mrModel.mfX, 0.0, 1.0), + getLimitedValue< double, double >(mrModel.mfY, 0.0, 1.0), + fRotationAngle == 90.0 ? Alignment_TOP_RIGHT : Alignment_BOTTOM_LEFT ); + // set the resulting position at the shape + if( aShapeProp.setProperty(PROP_RelativePosition, aPos) ) + bPropSet = true; } + // set the resulting position at the shape + if( !bPropSet ) + rxShape->setPosition( aShapePos ); } } // namespace oox diff --git a/oox/source/drawingml/chart/objectformatter.cxx b/oox/source/drawingml/chart/objectformatter.cxx index 1a43409dbea0..b82fdbe6e026 100644 --- a/oox/source/drawingml/chart/objectformatter.cxx +++ b/oox/source/drawingml/chart/objectformatter.cxx @@ -728,21 +728,21 @@ DetailFormatterBase::DetailFormatterBase( ObjectFormatterData& rData, const Auto mrData( rData ), mnPhClr( 0xffffffff ) { - if( pAutoFormatEntry ) + if( !pAutoFormatEntry ) + return; + + if( pAutoFormatEntry->mpPattern ) { - if( pAutoFormatEntry->mpPattern ) - { - // prepare multi-color pattern - for( const AutoFormatPatternEntry* pPatternEntry = pAutoFormatEntry->mpPattern; pPatternEntry->mnColorToken != XML_TOKEN_INVALID; ++pPatternEntry ) - maColorPattern.push_back( getSchemeColor( pPatternEntry->mnColorToken, pPatternEntry->mnModToken, pPatternEntry->mnModValue ) ); - } - else if( pAutoFormatEntry->mnColorToken != XML_TOKEN_INVALID ) - { - // prepare color or single-color pattern (color fading) - mnPhClr = getSchemeColor( pAutoFormatEntry->mnColorToken, pAutoFormatEntry->mnModToken, pAutoFormatEntry->mnModValue ); - if( pAutoFormatEntry->mbFadedColor ) - maColorPattern.push_back( mnPhClr ); - } + // prepare multi-color pattern + for( const AutoFormatPatternEntry* pPatternEntry = pAutoFormatEntry->mpPattern; pPatternEntry->mnColorToken != XML_TOKEN_INVALID; ++pPatternEntry ) + maColorPattern.push_back( getSchemeColor( pPatternEntry->mnColorToken, pPatternEntry->mnModToken, pPatternEntry->mnModValue ) ); + } + else if( pAutoFormatEntry->mnColorToken != XML_TOKEN_INVALID ) + { + // prepare color or single-color pattern (color fading) + mnPhClr = getSchemeColor( pAutoFormatEntry->mnColorToken, pAutoFormatEntry->mnModToken, pAutoFormatEntry->mnModValue ); + if( pAutoFormatEntry->mbFadedColor ) + maColorPattern.push_back( mnPhClr ); } } @@ -817,25 +817,25 @@ DetailFormatterBase::DetailFormatterBase( ObjectFormatterData& rData, const Auto LineFormatter::LineFormatter( ObjectFormatterData& rData, const AutoFormatEntry* pAutoFormatEntry, const ObjectType eObjType ) : DetailFormatterBase(rData, pAutoFormatEntry) { - if( pAutoFormatEntry ) + if( !pAutoFormatEntry ) + return; + + mxAutoLine = std::make_shared<LineProperties>(); + mxAutoLine->maLineFill.moFillType = XML_noFill; + if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) + if( const LineProperties* pLineProps = pTheme->getLineStyle( pAutoFormatEntry->mnThemedIdx ) ) + *mxAutoLine = *pLineProps; + // set automatic border property for chartarea, because of tdf#81437 and tdf#82217 + if ( eObjType == OBJECTTYPE_CHARTSPACE ) { - mxAutoLine = std::make_shared<LineProperties>(); - mxAutoLine->maLineFill.moFillType = XML_noFill; - if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) - if( const LineProperties* pLineProps = pTheme->getLineStyle( pAutoFormatEntry->mnThemedIdx ) ) - *mxAutoLine = *pLineProps; - // set automatic border property for chartarea, because of tdf#81437 and tdf#82217 - if ( eObjType == OBJECTTYPE_CHARTSPACE ) - { - mxAutoLine->maLineFill.moFillType = oox::GraphicHelper::getDefaultChartAreaLineStyle(); - mxAutoLine->moLineWidth = oox::GraphicHelper::getDefaultChartAreaLineWidth(); - // this value is what MSO 2016 use as a default color for chartspace border - mxAutoLine->maLineFill.maFillColor.setSrgbClr( 0xD9D9D9 ); - } - // change line width according to chart auto style - if( mxAutoLine->moLineWidth.has() ) - mxAutoLine->moLineWidth = mxAutoLine->moLineWidth.get() * pAutoFormatEntry->mnRelLineWidth / 100; + mxAutoLine->maLineFill.moFillType = oox::GraphicHelper::getDefaultChartAreaLineStyle(); + mxAutoLine->moLineWidth = oox::GraphicHelper::getDefaultChartAreaLineWidth(); + // this value is what MSO 2016 use as a default color for chartspace border + mxAutoLine->maLineFill.maFillColor.setSrgbClr( 0xD9D9D9 ); } + // change line width according to chart auto style + if( mxAutoLine->moLineWidth.has() ) + mxAutoLine->moLineWidth = mxAutoLine->moLineWidth.get() * pAutoFormatEntry->mnRelLineWidth / 100; } void LineFormatter::convertFormatting( ShapePropertyMap& rPropMap, const ModelRef< Shape >& rxShapeProp, sal_Int32 nSeriesIdx ) @@ -851,19 +851,19 @@ void LineFormatter::convertFormatting( ShapePropertyMap& rPropMap, const ModelRe FillFormatter::FillFormatter( ObjectFormatterData& rData, const AutoFormatEntry* pAutoFormatEntry, const ObjectType eObjType ) : DetailFormatterBase( rData, pAutoFormatEntry ) { - if( pAutoFormatEntry ) + if( !pAutoFormatEntry ) + return; + + mxAutoFill = std::make_shared<FillProperties>(); + if( eObjType != OBJECTTYPE_CHARTSPACE ) + mxAutoFill->moFillType = XML_noFill; + if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) + if( const FillProperties* pFillProps = pTheme->getFillStyle( pAutoFormatEntry->mnThemedIdx ) ) + *mxAutoFill = *pFillProps; + + if (eObjType == OBJECTTYPE_CHARTSPACE) { - mxAutoFill = std::make_shared<FillProperties>(); - if( eObjType != OBJECTTYPE_CHARTSPACE ) - mxAutoFill->moFillType = XML_noFill; - if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) - if( const FillProperties* pFillProps = pTheme->getFillStyle( pAutoFormatEntry->mnThemedIdx ) ) - *mxAutoFill = *pFillProps; - - if (eObjType == OBJECTTYPE_CHARTSPACE) - { - mxAutoFill->moFillType = rData.mrFilter.getGraphicHelper().getDefaultChartAreaFillStyle(); - } + mxAutoFill->moFillType = rData.mrFilter.getGraphicHelper().getDefaultChartAreaFillStyle(); } } @@ -892,26 +892,26 @@ const TextCharacterProperties* lclGetTextProperties( const ModelRef< TextBody >& TextFormatter::TextFormatter( ObjectFormatterData& rData, const AutoTextEntry* pAutoTextEntry, const ModelRef< TextBody >& rxGlobalTextProp ) : DetailFormatterBase( rData, pAutoTextEntry ) { - if( pAutoTextEntry ) - { - mxAutoText = std::make_shared<TextCharacterProperties>(); - if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) - if( const TextCharacterProperties* pTextProps = pTheme->getFontStyle( pAutoTextEntry->mnThemedFont ) ) - *mxAutoText = *pTextProps; - ::Color nTextColor = getPhColor( -1 ); - if( sal_Int32(nTextColor) >= 0 ) { - mxAutoText->maFillProperties.maFillColor.setSrgbClr( nTextColor ); - mxAutoText->maFillProperties.moFillType.set(XML_solidFill); - } - mxAutoText->moHeight = pAutoTextEntry->mnDefFontSize; - mxAutoText->moBold = pAutoTextEntry->mbBold; + if( !pAutoTextEntry ) + return; + + mxAutoText = std::make_shared<TextCharacterProperties>(); + if( const Theme* pTheme = mrData.mrFilter.getCurrentTheme() ) + if( const TextCharacterProperties* pTextProps = pTheme->getFontStyle( pAutoTextEntry->mnThemedFont ) ) + *mxAutoText = *pTextProps; + ::Color nTextColor = getPhColor( -1 ); + if( sal_Int32(nTextColor) >= 0 ) { + mxAutoText->maFillProperties.maFillColor.setSrgbClr( nTextColor ); + mxAutoText->maFillProperties.moFillType.set(XML_solidFill); + } + mxAutoText->moHeight = pAutoTextEntry->mnDefFontSize; + mxAutoText->moBold = pAutoTextEntry->mbBold; - if( const TextCharacterProperties* pTextProps = lclGetTextProperties( rxGlobalTextProp ) ) - { - mxAutoText->assignUsed( *pTextProps ); - if( pTextProps->moHeight.has() ) - mxAutoText->moHeight = pTextProps->moHeight.get() * pAutoTextEntry->mnRelFontSize / 100; - } + if( const TextCharacterProperties* pTextProps = lclGetTextProperties( rxGlobalTextProp ) ) + { + mxAutoText->assignUsed( *pTextProps ); + if( pTextProps->moHeight.has() ) + mxAutoText->moHeight = pTextProps->moHeight.get() * pAutoTextEntry->mnRelFontSize / 100; } } @@ -1050,77 +1050,77 @@ void ObjectFormatter::convertTextFormatting( PropertySet& rPropSet, const TextCh void ObjectFormatter::convertTextRotation( PropertySet& rPropSet, const ModelRef< TextBody >& rxTextProp, bool bSupportsStacked, sal_Int32 nDefaultRotation ) { - if( rxTextProp.is() ) + if( !rxTextProp.is() ) + return; + + bool bStacked = false; + if( bSupportsStacked ) { - bool bStacked = false; - if( bSupportsStacked ) - { - sal_Int32 nVert = rxTextProp->getTextProperties().moVert.get( XML_horz ); - bStacked = (nVert == XML_wordArtVert) || (nVert == XML_wordArtVertRtl); - rPropSet.setProperty( PROP_StackCharacters, bStacked ); - } + sal_Int32 nVert = rxTextProp->getTextProperties().moVert.get( XML_horz ); + bStacked = (nVert == XML_wordArtVert) || (nVert == XML_wordArtVertRtl); + rPropSet.setProperty( PROP_StackCharacters, bStacked ); + } - /* Chart2 expects rotation angle as double value in range of [0,360). - OOXML counts clockwise, Chart2 counts counterclockwise. */ - double fAngle = static_cast< double >( bStacked ? 0 : rxTextProp->getTextProperties().moRotation.get( nDefaultRotation ) ); - // MS Office UI allows values only in range of [-90,90]. - if ( fAngle < -5400000.0 || fAngle > 5400000.0 ) - { - fAngle = 0.0; - } - fAngle = getDoubleIntervalValue< double >( -fAngle / 60000.0, 0.0, 360.0 ); - rPropSet.setProperty( PROP_TextRotation, fAngle ); + /* Chart2 expects rotation angle as double value in range of [0,360). + OOXML counts clockwise, Chart2 counts counterclockwise. */ + double fAngle = static_cast< double >( bStacked ? 0 : rxTextProp->getTextProperties().moRotation.get( nDefaultRotation ) ); + // MS Office UI allows values only in range of [-90,90]. + if ( fAngle < -5400000.0 || fAngle > 5400000.0 ) + { + fAngle = 0.0; } + fAngle = getDoubleIntervalValue< double >( -fAngle / 60000.0, 0.0, 360.0 ); + rPropSet.setProperty( PROP_TextRotation, fAngle ); } void ObjectFormatter::convertTextWrap( PropertySet& rPropSet, const ModelRef< TextBody >& rxTextProp ) { - if( rxTextProp.is() ) + if( !rxTextProp.is() ) + return; + + PropertyMap& aPropMap = rxTextProp->getTextProperties().maPropertyMap; + if( aPropMap.hasProperty(PROP_TextWordWrap) ) { - PropertyMap& aPropMap = rxTextProp->getTextProperties().maPropertyMap; - if( aPropMap.hasProperty(PROP_TextWordWrap) ) + Any aValue = aPropMap.getProperty( PROP_TextWordWrap ); + if( aValue.hasValue() ) { - Any aValue = aPropMap.getProperty( PROP_TextWordWrap ); - if( aValue.hasValue() ) - { - bool bValue = false; - aValue >>= bValue; - rPropSet.setProperty( PROP_TextWordWrap, bValue ); - } + bool bValue = false; + aValue >>= bValue; + rPropSet.setProperty( PROP_TextWordWrap, bValue ); } } } void ObjectFormatter::convertNumberFormat( PropertySet& rPropSet, const NumberFormat& rNumberFormat, bool bAxis, bool bShowPercent ) { - if( mxData->mxNumFmts.is() ) - { - const bool bGeneral = rNumberFormat.maFormatCode.equalsIgnoreAsciiCase("general"); - const bool bPercent = !bAxis && bShowPercent && !rNumberFormat.mbSourceLinked; - sal_Int32 nPropId = bPercent ? PROP_PercentageNumberFormat : PROP_NumberFormat; - OUString sFormatCode(rNumberFormat.maFormatCode); - if (bPercent && bGeneral) - sFormatCode = "0%"; - try - { - sal_Int32 nIndex = bGeneral && !bPercent ? - mxData->mxNumTypes->getStandardIndex( mxData->maFromLocale ) : - mxData->mxNumFmts->addNewConverted( sFormatCode, mxData->maEnUsLocale, mxData->maFromLocale ); - if( nIndex >= 0 ) - rPropSet.setProperty( nPropId, nIndex ); - } - catch( Exception& ) - { - OSL_FAIL( OStringBuffer( "ObjectFormatter::convertNumberFormat - cannot create number format '" ). - append( OUStringToOString( rNumberFormat.maFormatCode, osl_getThreadTextEncoding() ) ).append( '\'' ).getStr() ); - } + if( !mxData->mxNumFmts.is() ) + return; - // Setting "LinkNumberFormatToSource" does not really work, at least not for axis :-/ - if (!bAxis) - rPropSet.setProperty(PROP_LinkNumberFormatToSource, makeAny(rNumberFormat.mbSourceLinked)); - else - rPropSet.setProperty(PROP_LinkNumberFormatToSource, makeAny(rNumberFormat.maFormatCode.isEmpty())); + const bool bGeneral = rNumberFormat.maFormatCode.equalsIgnoreAsciiCase("general"); + const bool bPercent = !bAxis && bShowPercent && !rNumberFormat.mbSourceLinked; + sal_Int32 nPropId = bPercent ? PROP_PercentageNumberFormat : PROP_NumberFormat; + OUString sFormatCode(rNumberFormat.maFormatCode); + if (bPercent && bGeneral) + sFormatCode = "0%"; + try + { + sal_Int32 nIndex = bGeneral && !bPercent ? + mxData->mxNumTypes->getStandardIndex( mxData->maFromLocale ) : + mxData->mxNumFmts->addNewConverted( sFormatCode, mxData->maEnUsLocale, mxData->maFromLocale ); + if( nIndex >= 0 ) + rPropSet.setProperty( nPropId, nIndex ); } + catch( Exception& ) + { + OSL_FAIL( OStringBuffer( "ObjectFormatter::convertNumberFormat - cannot create number format '" ). + append( OUStringToOString( rNumberFormat.maFormatCode, osl_getThreadTextEncoding() ) ).append( '\'' ).getStr() ); + } + + // Setting "LinkNumberFormatToSource" does not really work, at least not for axis :-/ + if (!bAxis) + rPropSet.setProperty(PROP_LinkNumberFormatToSource, makeAny(rNumberFormat.mbSourceLinked)); + else + rPropSet.setProperty(PROP_LinkNumberFormatToSource, makeAny(rNumberFormat.maFormatCode.isEmpty())); } void ObjectFormatter::convertAutomaticFill( PropertySet& rPropSet, ObjectType eObjType, sal_Int32 nSeriesIdx ) diff --git a/oox/source/drawingml/chart/plotareaconverter.cxx b/oox/source/drawingml/chart/plotareaconverter.cxx index 1862dea1c8cb..e5f337a94193 100644 --- a/oox/source/drawingml/chart/plotareaconverter.cxx +++ b/oox/source/drawingml/chart/plotareaconverter.cxx @@ -114,7 +114,10 @@ void AxesSetConverter::convertFromModel( const Reference< XDiagram >& rxDiagram, aTypeGroups.push_back( std::make_shared<TypeGroupConverter>( *this, *typeGroup ) ); OSL_ENSURE( !aTypeGroups.empty(), "AxesSetConverter::convertFromModel - no type groups in axes set" ); - if( !aTypeGroups.empty() ) try + if( aTypeGroups.empty() ) + return; + + try { // first type group needed for coordinate system and axis conversion TypeGroupConverter& rFirstTypeGroup = *aTypeGroups.front(); @@ -452,7 +455,10 @@ void PlotAreaConverter::convertPositionFromModel() LayoutModel& rLayout = mrModel.mxLayout.getOrCreate(); LayoutConverter aLayoutConv( *this, rLayout ); awt::Rectangle aDiagramRect; - if( aLayoutConv.calcAbsRectangle( aDiagramRect ) ) try + if( !aLayoutConv.calcAbsRectangle( aDiagramRect ) ) + return; + + try { namespace cssc = ::com::sun::star::chart; Reference< cssc::XChartDocument > xChart1Doc( getChartDocument(), UNO_QUERY_THROW ); diff --git a/oox/source/drawingml/chart/seriesconverter.cxx b/oox/source/drawingml/chart/seriesconverter.cxx index f063019b8327..01e004f45c59 100644 --- a/oox/source/drawingml/chart/seriesconverter.cxx +++ b/oox/source/drawingml/chart/seriesconverter.cxx @@ -134,49 +134,50 @@ void lclConvertLabelFormatting( PropertySet& rPropSet, ObjectFormatter& rFormatt rPropSet.setProperty( PROP_Label, aPointLabel ); } - if( !rDataLabel.mbDeleted ) - { - // data label number format (percentage format wins over value format) - rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, false, bShowPercent ); - - // data label text formatting (frame formatting not supported by Chart2) - if( bDataSeriesLabel || (rDataLabel.mxTextProp.is() && !rDataLabel.mxTextProp->getParagraphs().empty()) ) - convertTextProperty(rPropSet, rFormatter, rDataLabel.mxTextProp); - - // data label separator (do not overwrite series separator, if no explicit point separator is present) - // Set the data label separator to "new line" if the value is shown as percentage with a category name, - // just like in MS-Office. In any other case the default separator will be a semicolon. - if( bShowPercent && !bShowValue && ( bDataSeriesLabel || rDataLabel.moaSeparator.has() ) ) - rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "\n" ) ); - else if( bDataSeriesLabel || rDataLabel.moaSeparator.has() ) - rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "; " ) ); - - // data label placement (do not overwrite series placement, if no explicit point placement is present) - if( bDataSeriesLabel || rDataLabel.monLabelPos.has() ) - { - namespace csscd = ::com::sun::star::chart::DataLabelPlacement; - sal_Int32 nPlacement = -1; - switch( rDataLabel.monLabelPos.get( XML_TOKEN_INVALID ) ) - { - case XML_outEnd: nPlacement = csscd::OUTSIDE; break; - case XML_inEnd: nPlacement = csscd::INSIDE; break; - case XML_ctr: nPlacement = csscd::CENTER; break; - case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break; - case XML_t: nPlacement = csscd::TOP; break; - case XML_b: nPlacement = csscd::BOTTOM; break; - case XML_l: nPlacement = csscd::LEFT; break; - case XML_r: nPlacement = csscd::RIGHT; break; - case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break; - } + if( rDataLabel.mbDeleted ) + return; - if( !bDataSeriesLabel && nPlacement == -1 ) - return; - else if( nPlacement == -1 ) - nPlacement = rTypeInfo.mnDefLabelPos; + // data label number format (percentage format wins over value format) + rFormatter.convertNumberFormat( rPropSet, rDataLabel.maNumberFormat, false, bShowPercent ); - rPropSet.setProperty( PROP_LabelPlacement, nPlacement ); - } + // data label text formatting (frame formatting not supported by Chart2) + if( bDataSeriesLabel || (rDataLabel.mxTextProp.is() && !rDataLabel.mxTextProp->getParagraphs().empty()) ) + convertTextProperty(rPropSet, rFormatter, rDataLabel.mxTextProp); + + // data label separator (do not overwrite series separator, if no explicit point separator is present) + // Set the data label separator to "new line" if the value is shown as percentage with a category name, + // just like in MS-Office. In any other case the default separator will be a semicolon. + if( bShowPercent && !bShowValue && ( bDataSeriesLabel || rDataLabel.moaSeparator.has() ) ) + rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "\n" ) ); + else if( bDataSeriesLabel || rDataLabel.moaSeparator.has() ) + rPropSet.setProperty( PROP_LabelSeparator, rDataLabel.moaSeparator.get( "; " ) ); + + // data label placement (do not overwrite series placement, if no explicit point placement is present) + if( !(bDataSeriesLabel || rDataLabel.monLabelPos.has()) ) + return; + + namespace csscd = ::com::sun::star::chart::DataLabelPlacement; + sal_Int32 nPlacement = -1; + switch( rDataLabel.monLabelPos.get( XML_TOKEN_INVALID ) ) + { + case XML_outEnd: nPlacement = csscd::OUTSIDE; break; + case XML_inEnd: nPlacement = csscd::INSIDE; break; + case XML_ctr: nPlacement = csscd::CENTER; break; + case XML_inBase: nPlacement = csscd::NEAR_ORIGIN; break; + case XML_t: nPlacement = csscd::TOP; break; + case XML_b: nPlacement = csscd::BOTTOM; break; + case XML_l: nPlacement = csscd::LEFT; break; + case XML_r: nPlacement = csscd::RIGHT; break; + case XML_bestFit: nPlacement = csscd::AVOID_OVERLAP; break; } + + if( !bDataSeriesLabel && nPlacement == -1 ) + return; + + if( nPlacement == -1 ) + nPlacement = rTypeInfo.mnDefLabelPos; + + rPropSet.setProperty( PROP_LabelPlacement, nPlacement ); } void importBorderProperties( PropertySet& rPropSet, Shape& rShape, const GraphicHelper& rGraphicHelper ) @@ -356,7 +357,10 @@ void ErrorBarConverter::convertFromModel( const Reference< XDataSeries >& rxData { bool bShowPos = (mrModel.mnTypeId == XML_plus) || (mrModel.mnTypeId == XML_both); bool bShowNeg = (mrModel.mnTypeId == XML_minus) || (mrModel.mnTypeId == XML_both); - if( bShowPos || bShowNeg ) try + if( !(bShowPos || bShowNeg) ) + return; + + try { Reference< XPropertySet > xErrorBar( createInstance( "com.sun.star.chart2.ErrorBar" ), UNO_QUERY_THROW ); PropertySet aBarProp( xErrorBar ); diff --git a/oox/source/drawingml/chart/titleconverter.cxx b/oox/source/drawingml/chart/titleconverter.cxx index 10ebd308b4fa..a4a2d9c1ec89 100644 --- a/oox/source/drawingml/chart/titleconverter.cxx +++ b/oox/source/drawingml/chart/titleconverter.cxx @@ -144,34 +144,37 @@ TitleConverter::~TitleConverter() void TitleConverter::convertFromModel( const Reference< XTitled >& rxTitled, const OUString& rAutoTitle, ObjectType eObjType, sal_Int32 nMainIdx, sal_Int32 nSubIdx ) { - if( rxTitled.is() ) + if( !rxTitled.is() ) + return; + + // create the formatted strings + TextModel& rText = mrModel.mxText.getOrCreate(); + TextConverter aTextConv( *this, rText ); + Sequence< Reference< XFormattedString > > aStringSeq = aTextConv.createStringSequence( rAutoTitle, mrModel.mxTextProp, eObjType ); + if( !aStringSeq.hasElements() ) + return; + + try + { + // create the title object and set the string data + Reference< XTitle > xTitle( createInstance( "com.sun.star.chart2.Title" ), UNO_QUERY_THROW ); + xTitle->setText( aStringSeq ); + rxTitled->setTitleObject( xTitle ); + + // frame formatting (text formatting already done in TextConverter::createStringSequence()) + PropertySet aPropSet( xTitle ); + getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, eObjType ); + + // frame rotation + OSL_ENSURE( !mrModel.mxTextProp || !rText.mxTextBody, "TitleConverter::convertFromModel - multiple text properties" ); + ModelRef< TextBody > xTextProp = mrModel.mxTextProp.is() ? mrModel.mxTextProp : rText.mxTextBody; + ObjectFormatter::convertTextRotation( aPropSet, xTextProp, true, mrModel.mnDefaultRotation ); + + // register the title and layout data for conversion of position + registerTitleLayout( xTitle, mrModel.mxLayout, eObjType, nMainIdx, nSubIdx ); + } + catch( Exception& ) { - // create the formatted strings - TextModel& rText = mrModel.mxText.getOrCreate(); - TextConverter aTextConv( *this, rText ); - Sequence< Reference< XFormattedString > > aStringSeq = aTextConv.createStringSequence( rAutoTitle, mrModel.mxTextProp, eObjType ); - if( aStringSeq.hasElements() ) try - { - // create the title object and set the string data - Reference< XTitle > xTitle( createInstance( "com.sun.star.chart2.Title" ), UNO_QUERY_THROW ); - xTitle->setText( aStringSeq ); - rxTitled->setTitleObject( xTitle ); - - // frame formatting (text formatting already done in TextConverter::createStringSequence()) - PropertySet aPropSet( xTitle ); - getFormatter().convertFrameFormatting( aPropSet, mrModel.mxShapeProp, eObjType ); - - // frame rotation - OSL_ENSURE( !mrModel.mxTextProp || !rText.mxTextBody, "TitleConverter::convertFromModel - multiple text properties" ); - ModelRef< TextBody > xTextProp = mrModel.mxTextProp.is() ? mrModel.mxTextProp : rText.mxTextBody; - ObjectFormatter::convertTextRotation( aPropSet, xTextProp, true, mrModel.mnDefaultRotation ); - - // register the title and layout data for conversion of position - registerTitleLayout( xTitle, mrModel.mxLayout, eObjType, nMainIdx, nSubIdx ); - } - catch( Exception& ) - { - } } } @@ -186,7 +189,10 @@ LegendConverter::~LegendConverter() void LegendConverter::convertFromModel( const Reference< XDiagram >& rxDiagram ) { - if( rxDiagram.is() ) try + if( !rxDiagram.is() ) + return; + + try { namespace cssc = ::com::sun::star::chart; namespace cssc2 = ::com::sun::star::chart2; diff --git a/oox/source/drawingml/chart/typegroupconverter.cxx b/oox/source/drawingml/chart/typegroupconverter.cxx index 7ce8adc3ffdf..f55ac931fb98 100644 --- a/oox/source/drawingml/chart/typegroupconverter.cxx +++ b/oox/source/drawingml/chart/typegroupconverter.cxx @@ -468,50 +468,50 @@ void TypeGroupConverter::convertFromModel( const Reference< XDiagram >& rxDiagra void TypeGroupConverter::convertMarker( PropertySet& rPropSet, sal_Int32 nOoxSymbol, sal_Int32 nOoxSize, const ModelRef< Shape >& xShapeProps ) const { - if( !isSeriesFrameFormat() ) - { - namespace cssc = ::com::sun::star::chart2; + if( isSeriesFrameFormat() ) + return; - // symbol style - cssc::Symbol aSymbol; - aSymbol.Style = cssc::SymbolStyle_STANDARD; - switch( nOoxSymbol ) // compare with XclChPropSetHelper::WriteMarkerProperties in xlchart.cxx - { - case XML_auto: aSymbol.Style = cssc::SymbolStyle_AUTO; break; - case XML_none: aSymbol.Style = cssc::SymbolStyle_NONE; break; - case XML_square: aSymbol.StandardSymbol = 0; break; // square - case XML_diamond: aSymbol.StandardSymbol = 1; break; // diamond - case XML_triangle: aSymbol.StandardSymbol = 3; break; // arrow up - case XML_x: aSymbol.StandardSymbol = 10; break; // X, legacy bow tie - case XML_star: aSymbol.StandardSymbol = 12; break; // asterisk, legacy sand glass - case XML_dot: aSymbol.StandardSymbol = 4; break; // arrow right - case XML_dash: aSymbol.StandardSymbol = 13; break; // horizontal bar, legacy arrow down - case XML_circle: aSymbol.StandardSymbol = 8; break; // circle, legacy arrow right - case XML_plus: aSymbol.StandardSymbol = 11; break; // plus, legacy arrow left - } + namespace cssc = ::com::sun::star::chart2; - // symbol size (points in OOXML, 1/100 mm in Chart2) - sal_Int32 nSize = static_cast< sal_Int32 >( nOoxSize * (2540.0 / 72.0) + 0.5 ); - aSymbol.Size.Width = aSymbol.Size.Height = nSize; + // symbol style + cssc::Symbol aSymbol; + aSymbol.Style = cssc::SymbolStyle_STANDARD; + switch( nOoxSymbol ) // compare with XclChPropSetHelper::WriteMarkerProperties in xlchart.cxx + { + case XML_auto: aSymbol.Style = cssc::SymbolStyle_AUTO; break; + case XML_none: aSymbol.Style = cssc::SymbolStyle_NONE; break; + case XML_square: aSymbol.StandardSymbol = 0; break; // square + case XML_diamond: aSymbol.StandardSymbol = 1; break; // diamond + case XML_triangle: aSymbol.StandardSymbol = 3; break; // arrow up + case XML_x: aSymbol.StandardSymbol = 10; break; // X, legacy bow tie + case XML_star: aSymbol.StandardSymbol = 12; break; // asterisk, legacy sand glass + case XML_dot: aSymbol.StandardSymbol = 4; break; // arrow right + case XML_dash: aSymbol.StandardSymbol = 13; break; // horizontal bar, legacy arrow down + case XML_circle: aSymbol.StandardSymbol = 8; break; // circle, legacy arrow right + case XML_plus: aSymbol.StandardSymbol = 11; break; // plus, legacy arrow left + } + + // symbol size (points in OOXML, 1/100 mm in Chart2) + sal_Int32 nSize = static_cast< sal_Int32 >( nOoxSize * (2540.0 / 72.0) + 0.5 ); + aSymbol.Size.Width = aSymbol.Size.Height = nSize; - if(xShapeProps.is()) + if(xShapeProps.is()) + { + Color aFillColor = xShapeProps->getFillProperties().maFillColor; + aSymbol.FillColor = sal_Int32(aFillColor.getColor(getFilter().getGraphicHelper())); + // tdf#124817: if there is no fill color, use line color of the symbol + if( aSymbol.FillColor < 0 ) { - Color aFillColor = xShapeProps->getFillProperties().maFillColor; - aSymbol.FillColor = sal_Int32(aFillColor.getColor(getFilter().getGraphicHelper())); - // tdf#124817: if there is no fill color, use line color of the symbol - if( aSymbol.FillColor < 0 ) - { - Color aLineColor = xShapeProps->getLineProperties().maLineFill.maFillColor; - aSymbol.BorderColor = sal_Int32(aLineColor.getColor(getFilter().getGraphicHelper())); - rPropSet.setProperty(PROP_Color, aSymbol.BorderColor); - } - else - rPropSet.setProperty(PROP_Color, aSymbol.FillColor); + Color aLineColor = xShapeProps->getLineProperties().maLineFill.maFillColor; + aSymbol.BorderColor = sal_Int32(aLineColor.getColor(getFilter().getGraphicHelper())); + rPropSet.setProperty(PROP_Color, aSymbol.BorderColor); } - - // set the property - rPropSet.setProperty( PROP_Symbol, aSymbol ); + else + rPropSet.setProperty(PROP_Color, aSymbol.FillColor); } + + // set the property + rPropSet.setProperty( PROP_Symbol, aSymbol ); } void TypeGroupConverter::convertLineSmooth( PropertySet& rPropSet, bool bOoxSmooth ) const @@ -526,23 +526,23 @@ void TypeGroupConverter::convertLineSmooth( PropertySet& rPropSet, bool bOoxSmoo void TypeGroupConverter::convertBarGeometry( PropertySet& rPropSet, sal_Int32 nOoxShape ) const { - if( mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR) ) - { - namespace cssc = ::com::sun::star::chart2; + if( !(mb3dChart && (maTypeInfo.meTypeCategory == TYPECATEGORY_BAR)) ) + return; - sal_Int32 nGeom3d = cssc::DataPointGeometry3D::CUBOID; - switch( nOoxShape ) - { - case XML_box: nGeom3d = cssc::DataPointGeometry3D::CUBOID; break; - case XML_cone: nGeom3d = cssc::DataPointGeometry3D::CONE; break; - case XML_coneToMax: nGeom3d = cssc::DataPointGeometry3D::CONE; break; - case XML_cylinder: nGeom3d = cssc::DataPointGeometry3D::CYLINDER; break; - case XML_pyramid: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break; - case XML_pyramidToMax: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break; - default: OSL_FAIL( "TypeGroupConverter::convertBarGeometry - unknown 3D bar shape type" ); - } - rPropSet.setProperty( PROP_Geometry3D, nGeom3d ); + namespace cssc = ::com::sun::star::chart2; + + sal_Int32 nGeom3d = cssc::DataPointGeometry3D::CUBOID; + switch( nOoxShape ) + { + case XML_box: nGeom3d = cssc::DataPointGeometry3D::CUBOID; break; + case XML_cone: nGeom3d = cssc::DataPointGeometry3D::CONE; break; + case XML_coneToMax: nGeom3d = cssc::DataPointGeometry3D::CONE; break; + case XML_cylinder: nGeom3d = cssc::DataPointGeometry3D::CYLINDER; break; + case XML_pyramid: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break; + case XML_pyramidToMax: nGeom3d = cssc::DataPointGeometry3D::PYRAMID; break; + default: OSL_FAIL( "TypeGroupConverter::convertBarGeometry - unknown 3D bar shape type" ); } + rPropSet.setProperty( PROP_Geometry3D, nGeom3d ); } void TypeGroupConverter::convertPieRotation( PropertySet& rPropSet, sal_Int32 nOoxAngle ) const @@ -569,33 +569,33 @@ void TypeGroupConverter::convertPieExplosion( PropertySet& rPropSet, sal_Int32 n void TypeGroupConverter::insertDataSeries( const Reference< XChartType >& rxChartType, const Reference< XDataSeries >& rxSeries, sal_Int32 nAxesSetIdx ) { - if( rxSeries.is() ) - { - PropertySet aSeriesProp( rxSeries ); + if( !rxSeries.is() ) + return; - // series stacking mode - namespace cssc = ::com::sun::star::chart2; - cssc::StackingDirection eStacking = cssc::StackingDirection_NO_STACKING; - // stacked overrides deep-3d - if( isStacked() || isPercent() ) - eStacking = cssc::StackingDirection_Y_STACKING; - else if( isDeep3dChart() ) - eStacking = cssc::StackingDirection_Z_STACKING; - aSeriesProp.setProperty( PROP_StackingDirection, eStacking ); - - // additional series properties - aSeriesProp.setProperty( PROP_AttachedAxisIndex, nAxesSetIdx ); - - // insert series into container - try - { - Reference< XDataSeriesContainer > xSeriesCont( rxChartType, UNO_QUERY_THROW ); - xSeriesCont->addDataSeries( rxSeries ); - } - catch( Exception& ) - { - OSL_FAIL( "TypeGroupConverter::insertDataSeries - cannot add data series" ); - } + PropertySet aSeriesProp( rxSeries ); + + // series stacking mode + namespace cssc = ::com::sun::star::chart2; + cssc::StackingDirection eStacking = cssc::StackingDirection_NO_STACKING; + // stacked overrides deep-3d + if( isStacked() || isPercent() ) + eStacking = cssc::StackingDirection_Y_STACKING; + else if( isDeep3dChart() ) + eStacking = cssc::StackingDirection_Z_STACKING; + aSeriesProp.setProperty( PROP_StackingDirection, eStacking ); + + // additional series properties + aSeriesProp.setProperty( PROP_AttachedAxisIndex, nAxesSetIdx ); + + // insert series into container + try + { + Reference< XDataSeriesContainer > xSeriesCont( rxChartType, UNO_QUERY_THROW ); + xSeriesCont->addDataSeries( rxSeries ); + } + catch( Exception& ) + { + OSL_FAIL( "TypeGroupConverter::insertDataSeries - cannot add data series" ); } } diff --git a/oox/source/drawingml/fillproperties.cxx b/oox/source/drawingml/fillproperties.cxx index c8cc88f7b470..acc13271ebc1 100644 --- a/oox/source/drawingml/fillproperties.cxx +++ b/oox/source/drawingml/fillproperties.cxx @@ -325,157 +325,222 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper, sal_Int32 nShapeRotation, ::Color nPhClr, bool bFlipH, bool bFlipV ) const { - if( moFillType.has() ) + if( !moFillType.has() ) + return; + + FillStyle eFillStyle = FillStyle_NONE; + OSL_ASSERT((moFillType.get() & sal_Int32(0xFFFF0000))==0); + switch( moFillType.get() ) { - FillStyle eFillStyle = FillStyle_NONE; - OSL_ASSERT((moFillType.get() & sal_Int32(0xFFFF0000))==0); - switch( moFillType.get() ) - { - case XML_noFill: - eFillStyle = FillStyle_NONE; - break; + case XML_noFill: + eFillStyle = FillStyle_NONE; + break; - case XML_solidFill: - if( maFillColor.isUsed() ) + case XML_solidFill: + if( maFillColor.isUsed() ) + { + rPropMap.setProperty( ShapeProperty::FillColor, maFillColor.getColor( rGraphicHelper, nPhClr ) ); + if( maFillColor.hasTransparency() ) + rPropMap.setProperty( ShapeProperty::FillTransparency, maFillColor.getTransparency() ); + eFillStyle = FillStyle_SOLID; + } + break; + + case XML_gradFill: + // do not create gradient struct if property is not supported... + if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) ) + { + sal_Int32 nEndTrans = 0; + sal_Int32 nStartTrans = 0; + awt::Gradient aGradient; + aGradient.Angle = 900; + aGradient.StartIntensity = 100; + aGradient.EndIntensity = 100; + + // Old code, values in aGradient overwritten in many cases by newer code below + if( maGradientProps.maGradientStops.size() > 1 ) { - rPropMap.setProperty( ShapeProperty::FillColor, maFillColor.getColor( rGraphicHelper, nPhClr ) ); - if( maFillColor.hasTransparency() ) - rPropMap.setProperty( ShapeProperty::FillTransparency, maFillColor.getTransparency() ); - eFillStyle = FillStyle_SOLID; + aGradient.StartColor = sal_Int32(maGradientProps.maGradientStops.begin()->second.getColor( rGraphicHelper, nPhClr )); + aGradient.EndColor = sal_Int32(maGradientProps.maGradientStops.rbegin()->second.getColor( rGraphicHelper, nPhClr )); + if( maGradientProps.maGradientStops.rbegin()->second.hasTransparency() ) + nEndTrans = maGradientProps.maGradientStops.rbegin()->second.getTransparency()*255/100; + if( maGradientProps.maGradientStops.begin()->second.hasTransparency() ) + nStartTrans = maGradientProps.maGradientStops.begin()->second.getTransparency()*255/100; } - break; - case XML_gradFill: - // do not create gradient struct if property is not supported... - if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) ) + // "rotate with shape" set to false -> do not rotate + if ( !maGradientProps.moRotateWithShape.get( true ) ) + nShapeRotation = 0; + + if( maGradientProps.moGradientPath.has() ) + { + // position of gradient center (limited to [30%;100%], otherwise gradient is too hidden) + IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.get( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); + sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; + aGradient.XOffset = getLimitedValue<sal_Int16, sal_Int32>( + nCenterX / PER_PERCENT, 30, 100); + + // Style should be radial at least when the horizontal center is at 50%. + awt::GradientStyle eCircle = aGradient.XOffset == 50 + ? awt::GradientStyle_RADIAL + : awt::GradientStyle_ELLIPTICAL; + aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) + ? eCircle + : awt::GradientStyle_RECT; + + sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; + aGradient.YOffset = getLimitedValue<sal_Int16, sal_Int32>( + nCenterY / PER_PERCENT, 30, 100); + ::std::swap( aGradient.StartColor, aGradient.EndColor ); + ::std::swap( nStartTrans, nEndTrans ); + + extractGradientBorderFromStops(maGradientProps, rGraphicHelper, nPhClr, + aGradient); + } + else if (!maGradientProps.maGradientStops.empty()) { - sal_Int32 nEndTrans = 0; - sal_Int32 nStartTrans = 0; - awt::Gradient aGradient; - aGradient.Angle = 900; - aGradient.StartIntensity = 100; - aGradient.EndIntensity = 100; - - // Old code, values in aGradient overwritten in many cases by newer code below - if( maGradientProps.maGradientStops.size() > 1 ) + // A copy of the gradient stops for local modification + GradientFillProperties::GradientStopMap aGradientStops(maGradientProps.maGradientStops); + + // Add a fake gradient stop at 0% and 100% if necessary, so that the gradient always starts + // at 0% and ends at 100%, to make following logic clearer (?). + auto a0 = aGradientStops.find( 0.0 ); + if( a0 == aGradientStops.end() ) { - aGradient.StartColor = sal_Int32(maGradientProps.maGradientStops.begin()->second.getColor( rGraphicHelper, nPhClr )); - aGradient.EndColor = sal_Int32(maGradientProps.maGradientStops.rbegin()->second.getColor( rGraphicHelper, nPhClr )); - if( maGradientProps.maGradientStops.rbegin()->second.hasTransparency() ) - nEndTrans = maGradientProps.maGradientStops.rbegin()->second.getTransparency()*255/100; - if( maGradientProps.maGradientStops.begin()->second.hasTransparency() ) - nStartTrans = maGradientProps.maGradientStops.begin()->second.getTransparency()*255/100; + // temp variable required + Color aFirstColor(aGradientStops.begin()->second); + aGradientStops.emplace( 0.0, aFirstColor ); } - // "rotate with shape" set to false -> do not rotate - if ( !maGradientProps.moRotateWithShape.get( true ) ) - nShapeRotation = 0; - - if( maGradientProps.moGradientPath.has() ) + auto a1 = aGradientStops.find( 1.0 ); + if( a1 == aGradientStops.end() ) { - // position of gradient center (limited to [30%;100%], otherwise gradient is too hidden) - IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.get( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) ); - sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2; - aGradient.XOffset = getLimitedValue<sal_Int16, sal_Int32>( - nCenterX / PER_PERCENT, 30, 100); - - // Style should be radial at least when the horizontal center is at 50%. - awt::GradientStyle eCircle = aGradient.XOffset == 50 - ? awt::GradientStyle_RADIAL - : awt::GradientStyle_ELLIPTICAL; - aGradient.Style = (maGradientProps.moGradientPath.get() == XML_circle) - ? eCircle - : awt::GradientStyle_RECT; - - sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2; - aGradient.YOffset = getLimitedValue<sal_Int16, sal_Int32>( - nCenterY / PER_PERCENT, 30, 100); - ::std::swap( aGradient.StartColor, aGradient.EndColor ); - ::std::swap( nStartTrans, nEndTrans ); - - extractGradientBorderFromStops(maGradientProps, rGraphicHelper, nPhClr, - aGradient); + // ditto + Color aLastColor(aGradientStops.rbegin()->second); + aGradientStops.emplace( 1.0, aLastColor ); } - else if (!maGradientProps.maGradientStops.empty()) - { - // A copy of the gradient stops for local modification - GradientFillProperties::GradientStopMap aGradientStops(maGradientProps.maGradientStops); - // Add a fake gradient stop at 0% and 100% if necessary, so that the gradient always starts - // at 0% and ends at 100%, to make following logic clearer (?). - auto a0 = aGradientStops.find( 0.0 ); - if( a0 == aGradientStops.end() ) - { - // temp variable required - Color aFirstColor(aGradientStops.begin()->second); - aGradientStops.emplace( 0.0, aFirstColor ); - } - - auto a1 = aGradientStops.find( 1.0 ); - if( a1 == aGradientStops.end() ) + // Check if the gradient is symmetric, which we will emulate with an "axial" gradient. + bool bSymmetric(true); + { + GradientFillProperties::GradientStopMap::const_iterator aItA( aGradientStops.begin() ); + GradientFillProperties::GradientStopMap::const_iterator aItZ(std::prev(aGradientStops.end())); + while( bSymmetric && aItA->first < aItZ->first ) { - // ditto - Color aLastColor(aGradientStops.rbegin()->second); - aGradientStops.emplace( 1.0, aLastColor ); + if (!aItA->second.equals(aItZ->second, rGraphicHelper, nPhClr)) + bSymmetric = false; + else + { + ++aItA; + aItZ = std::prev(aItZ); + } } + // Don't be fooled if the middlemost stop isn't at 0.5. + if( bSymmetric && aItA == aItZ && aItA->first != 0.5 ) + bSymmetric = false; - // Check if the gradient is symmetric, which we will emulate with an "axial" gradient. - bool bSymmetric(true); + // If symmetric, do the rest of the logic for just a half. + if( bSymmetric ) { - GradientFillProperties::GradientStopMap::const_iterator aItA( aGradientStops.begin() ); - GradientFillProperties::GradientStopMap::const_iterator aItZ(std::prev(aGradientStops.end())); - while( bSymmetric && aItA->first < aItZ->first ) + // aItZ already points to the colour for the middle, but insert a fake stop at the + // exact middle if necessary. + if( aItA->first != aItZ->first ) { - if (!aItA->second.equals(aItZ->second, rGraphicHelper, nPhClr)) - bSymmetric = false; - else - { - ++aItA; - aItZ = std::prev(aItZ); - } - } - // Don't be fooled if the middlemost stop isn't at 0.5. - if( bSymmetric && aItA == aItZ && aItA->first != 0.5 ) - bSymmetric = false; + Color aMiddleColor = aItZ->second; + auto a05 = aGradientStops.find( 0.5 ); - // If symmetric, do the rest of the logic for just a half. - if( bSymmetric ) - { - // aItZ already points to the colour for the middle, but insert a fake stop at the - // exact middle if necessary. - if( aItA->first != aItZ->first ) - { - Color aMiddleColor = aItZ->second; - auto a05 = aGradientStops.find( 0.5 ); - - if( a05 != aGradientStops.end() ) - a05->second = aMiddleColor; - else - aGradientStops.emplace( 0.5, aMiddleColor ); - } - // Drop the rest of the stops - while( aGradientStops.rbegin()->first > 0.5 ) - aGradientStops.erase( aGradientStops.rbegin()->first ); + if( a05 != aGradientStops.end() ) + a05->second = aMiddleColor; + else + aGradientStops.emplace( 0.5, aMiddleColor ); } + // Drop the rest of the stops + while( aGradientStops.rbegin()->first > 0.5 ) + aGradientStops.erase( aGradientStops.rbegin()->first ); } + } - SAL_INFO("oox.drawingml.gradient", "symmetric: " << (bSymmetric ? "YES" : "NO") << - ", number of stops: " << aGradientStops.size()); - size_t nIndex = 0; - for (auto const& gradientStop : aGradientStops) - SAL_INFO("oox.drawingml.gradient", " " << nIndex++ << ": " << - gradientStop.first << ": " << - std::hex << sal_Int32(gradientStop.second.getColor( rGraphicHelper, nPhClr )) << std::dec << - "@" << (100 - gradientStop.second.getTransparency()) << "%"); - - // Now estimate the simple LO style gradient (only two stops, at n% and 100%, where n == - // the "border") that best emulates the gradient between begin() and prior(end()). - - // First look for the largest segment in the gradient. - GradientFillProperties::GradientStopMap::iterator aIt(aGradientStops.begin()); - double nWidestWidth = -1; - GradientFillProperties::GradientStopMap::iterator aWidestSegmentStart; + SAL_INFO("oox.drawingml.gradient", "symmetric: " << (bSymmetric ? "YES" : "NO") << + ", number of stops: " << aGradientStops.size()); + size_t nIndex = 0; + for (auto const& gradientStop : aGradientStops) + SAL_INFO("oox.drawingml.gradient", " " << nIndex++ << ": " << + gradientStop.first << ": " << + std::hex << sal_Int32(gradientStop.second.getColor( rGraphicHelper, nPhClr )) << std::dec << + "@" << (100 - gradientStop.second.getTransparency()) << "%"); + + // Now estimate the simple LO style gradient (only two stops, at n% and 100%, where n == + // the "border") that best emulates the gradient between begin() and prior(end()). + + // First look for the largest segment in the gradient. + GradientFillProperties::GradientStopMap::iterator aIt(aGradientStops.begin()); + double nWidestWidth = -1; + GradientFillProperties::GradientStopMap::iterator aWidestSegmentStart; + ++aIt; + while( aIt != aGradientStops.end() ) + { + if (aIt->first - std::prev(aIt)->first > nWidestWidth) + { + nWidestWidth = aIt->first - std::prev(aIt)->first; + aWidestSegmentStart = std::prev(aIt); + } ++aIt; + } + assert( nWidestWidth > 0 ); + + double nBorder = 0; + bool bSwap(false); + + // Do we have just two segments, and either one is of uniform colour, or three or more + // segments, and the widest one is the first or last one, and is it of uniform colour? If + // so, deduce the border from it, and drop that segment. + if( aGradientStops.size() == 3 && + aGradientStops.begin()->second.getColor(rGraphicHelper, nPhClr) == std::next(aGradientStops.begin())->second.getColor(rGraphicHelper, nPhClr) && + aGradientStops.begin()->second.getTransparency() == std::next(aGradientStops.begin())->second.getTransparency()) + { + // Two segments, first is uniformly coloured + SAL_INFO("oox.drawingml.gradient", "two segments, first is uniformly coloured"); + nBorder = std::next(aGradientStops.begin())->first - aGradientStops.begin()->first; + aGradientStops.erase(aGradientStops.begin()); + aWidestSegmentStart = aGradientStops.begin(); + } + else if( !bSymmetric && + aGradientStops.size() == 3 && + std::next(aGradientStops.begin())->second.getColor(rGraphicHelper, nPhClr) == std::prev(aGradientStops.end())->second.getColor(rGraphicHelper, nPhClr) && + std::next(aGradientStops.begin())->second.getTransparency() == std::prev(aGradientStops.end())->second.getTransparency()) + { + // Two segments, second is uniformly coloured + SAL_INFO("oox.drawingml.gradient", "two segments, second is uniformly coloured"); + nBorder = std::prev(aGradientStops.end())->first - std::next(aGradientStops.begin())->first; + aGradientStops.erase(std::next(aGradientStops.begin())); + aWidestSegmentStart = aGradientStops.begin(); + bSwap = true; + nShapeRotation = 180*60000 - nShapeRotation; + } + else if( !bSymmetric && + aGradientStops.size() >= 4 && + aWidestSegmentStart->second.getColor( rGraphicHelper, nPhClr ) == std::next(aWidestSegmentStart)->second.getColor(rGraphicHelper, nPhClr) && + aWidestSegmentStart->second.getTransparency() == std::next(aWidestSegmentStart)->second.getTransparency() && + ( aWidestSegmentStart == aGradientStops.begin() || + std::next(aWidestSegmentStart) == std::prev(aGradientStops.end()))) + { + // Not symmetric, three or more segments, the widest is first or last and is uniformly coloured + SAL_INFO("oox.drawingml.gradient", "first or last segment is widest and is uniformly coloured"); + nBorder = std::next(aWidestSegmentStart)->first - aWidestSegmentStart->first; + + // If it's the last segment that is uniformly coloured, rotate the gradient 180 + // degrees and swap start and end colours + if (std::next(aWidestSegmentStart) == std::prev(aGradientStops.end())) + { + bSwap = true; + nShapeRotation = 180*60000 - nShapeRotation; + } + + aGradientStops.erase( aWidestSegmentStart++ ); + + // Look for which is widest now + aIt = std::next(aGradientStops.begin()); + nWidestWidth = -1; while( aIt != aGradientStops.end() ) { if (aIt->first - std::prev(aIt)->first > nWidestWidth) @@ -485,253 +550,188 @@ void FillProperties::pushToPropMap( ShapePropertyMap& rPropMap, } ++aIt; } - assert( nWidestWidth > 0 ); + } + SAL_INFO("oox.drawingml.gradient", "widest segment start: " << aWidestSegmentStart->first << ", border: " << nBorder); + assert( (!bSymmetric && !bSwap) || !(bSymmetric && bSwap) ); + + // Now we have a potential border and a largest segment. Use those. + + aGradient.Style = bSymmetric ? awt::GradientStyle_AXIAL : awt::GradientStyle_LINEAR; + sal_Int32 nShadeAngle = maGradientProps.moShadeAngle.get( 0 ); + // Adjust for flips + if ( bFlipH ) + nShadeAngle = 180*60000 - nShadeAngle; + if ( bFlipV ) + nShadeAngle = -nShadeAngle; + sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation; + // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees) + aGradient.Angle = static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ); + Color aStartColor, aEndColor; + if( bSymmetric ) + { + aStartColor = std::next(aWidestSegmentStart)->second; + aEndColor = aWidestSegmentStart->second; + nBorder *= 2; + } + else if( bSwap ) + { + aStartColor = std::next(aWidestSegmentStart)->second; + aEndColor = aWidestSegmentStart->second; + } + else + { + aStartColor = aWidestSegmentStart->second; + aEndColor = std::next(aWidestSegmentStart)->second; + } - double nBorder = 0; - bool bSwap(false); + SAL_INFO("oox.drawingml.gradient", "start color: " << std::hex << sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr )) << std::dec << + "@" << (100-aStartColor.getTransparency()) << "%" + ", end color: " << std::hex << sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr )) << std::dec << + "@" << (100-aEndColor.getTransparency()) << "%"); - // Do we have just two segments, and either one is of uniform colour, or three or more - // segments, and the widest one is the first or last one, and is it of uniform colour? If - // so, deduce the border from it, and drop that segment. - if( aGradientStops.size() == 3 && - aGradientStops.begin()->second.getColor(rGraphicHelper, nPhClr) == std::next(aGradientStops.begin())->second.getColor(rGraphicHelper, nPhClr) && - aGradientStops.begin()->second.getTransparency() == std::next(aGradientStops.begin())->second.getTransparency()) - { - // Two segments, first is uniformly coloured - SAL_INFO("oox.drawingml.gradient", "two segments, first is uniformly coloured"); - nBorder = std::next(aGradientStops.begin())->first - aGradientStops.begin()->first; - aGradientStops.erase(aGradientStops.begin()); - aWidestSegmentStart = aGradientStops.begin(); - } - else if( !bSymmetric && - aGradientStops.size() == 3 && - std::next(aGradientStops.begin())->second.getColor(rGraphicHelper, nPhClr) == std::prev(aGradientStops.end())->second.getColor(rGraphicHelper, nPhClr) && - std::next(aGradientStops.begin())->second.getTransparency() == std::prev(aGradientStops.end())->second.getTransparency()) - { - // Two segments, second is uniformly coloured - SAL_INFO("oox.drawingml.gradient", "two segments, second is uniformly coloured"); - nBorder = std::prev(aGradientStops.end())->first - std::next(aGradientStops.begin())->first; - aGradientStops.erase(std::next(aGradientStops.begin())); - aWidestSegmentStart = aGradientStops.begin(); - bSwap = true; - nShapeRotation = 180*60000 - nShapeRotation; - } - else if( !bSymmetric && - aGradientStops.size() >= 4 && - aWidestSegmentStart->second.getColor( rGraphicHelper, nPhClr ) == std::next(aWidestSegmentStart)->second.getColor(rGraphicHelper, nPhClr) && - aWidestSegmentStart->second.getTransparency() == std::next(aWidestSegmentStart)->second.getTransparency() && - ( aWidestSegmentStart == aGradientStops.begin() || - std::next(aWidestSegmentStart) == std::prev(aGradientStops.end()))) - { - // Not symmetric, three or more segments, the widest is first or last and is uniformly coloured - SAL_INFO("oox.drawingml.gradient", "first or last segment is widest and is uniformly coloured"); - nBorder = std::next(aWidestSegmentStart)->first - aWidestSegmentStart->first; + aGradient.StartColor = sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr )); + aGradient.EndColor = sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr )); - // If it's the last segment that is uniformly coloured, rotate the gradient 180 - // degrees and swap start and end colours - if (std::next(aWidestSegmentStart) == std::prev(aGradientStops.end())) - { - bSwap = true; - nShapeRotation = 180*60000 - nShapeRotation; - } + if( aStartColor.hasTransparency() ) + nStartTrans = aStartColor.getTransparency()*255/100; + if( aEndColor.hasTransparency() ) + nEndTrans = aEndColor.getTransparency()*255/100; - aGradientStops.erase( aWidestSegmentStart++ ); + aGradient.Border = rtl::math::round(100*nBorder); + } - // Look for which is widest now - aIt = std::next(aGradientStops.begin()); - nWidestWidth = -1; - while( aIt != aGradientStops.end() ) - { - if (aIt->first - std::prev(aIt)->first > nWidestWidth) - { - nWidestWidth = aIt->first - std::prev(aIt)->first; - aWidestSegmentStart = std::prev(aIt); - } - ++aIt; - } - } - SAL_INFO("oox.drawingml.gradient", "widest segment start: " << aWidestSegmentStart->first << ", border: " << nBorder); - assert( (!bSymmetric && !bSwap) || !(bSymmetric && bSwap) ); - - // Now we have a potential border and a largest segment. Use those. - - aGradient.Style = bSymmetric ? awt::GradientStyle_AXIAL : awt::GradientStyle_LINEAR; - sal_Int32 nShadeAngle = maGradientProps.moShadeAngle.get( 0 ); - // Adjust for flips - if ( bFlipH ) - nShadeAngle = 180*60000 - nShadeAngle; - if ( bFlipV ) - nShadeAngle = -nShadeAngle; - sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation; - // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees) - aGradient.Angle = static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 ); - Color aStartColor, aEndColor; - if( bSymmetric ) - { - aStartColor = std::next(aWidestSegmentStart)->second; - aEndColor = aWidestSegmentStart->second; - nBorder *= 2; - } - else if( bSwap ) - { - aStartColor = std::next(aWidestSegmentStart)->second; - aEndColor = aWidestSegmentStart->second; - } - else - { - aStartColor = aWidestSegmentStart->second; - aEndColor = std::next(aWidestSegmentStart)->second; - } + // push gradient or named gradient to property map + if( rPropMap.setProperty( ShapeProperty::FillGradient, aGradient ) ) + eFillStyle = FillStyle_GRADIENT; - SAL_INFO("oox.drawingml.gradient", "start color: " << std::hex << sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr )) << std::dec << - "@" << (100-aStartColor.getTransparency()) << "%" - ", end color: " << std::hex << sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr )) << std::dec << - "@" << (100-aEndColor.getTransparency()) << "%"); + // push gradient transparency to property map + if( nStartTrans != 0 || nEndTrans != 0 ) + { + awt::Gradient aGrad(aGradient); + uno::Any aVal; + aGrad.EndColor = static_cast<sal_Int32>( nEndTrans | nEndTrans << 8 | nEndTrans << 16 ); + aGrad.StartColor = static_cast<sal_Int32>( nStartTrans | nStartTrans << 8 | nStartTrans << 16 ); + aVal <<= aGrad; + rPropMap.setProperty( ShapeProperty::GradientTransparency, aGrad ); + } - aGradient.StartColor = sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr )); - aGradient.EndColor = sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr )); + } + break; - if( aStartColor.hasTransparency() ) - nStartTrans = aStartColor.getTransparency()*255/100; - if( aEndColor.hasTransparency() ) - nEndTrans = aEndColor.getTransparency()*255/100; + case XML_blipFill: + // do not start complex graphic transformation if property is not supported... + if (maBlipProps.mxFillGraphic.is() && rPropMap.supportsProperty(ShapeProperty::FillBitmap)) + { + uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, nPhClr); + // TODO: "rotate with shape" is not possible with our current core - aGradient.Border = rtl::math::round(100*nBorder); + if (xGraphic.is()) + { + if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName) && + rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic)) + { + eFillStyle = FillStyle_BITMAP; } - - // push gradient or named gradient to property map - if( rPropMap.setProperty( ShapeProperty::FillGradient, aGradient ) ) - eFillStyle = FillStyle_GRADIENT; - - // push gradient transparency to property map - if( nStartTrans != 0 || nEndTrans != 0 ) + else if (rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic)) { - awt::Gradient aGrad(aGradient); - uno::Any aVal; - aGrad.EndColor = static_cast<sal_Int32>( nEndTrans | nEndTrans << 8 | nEndTrans << 16 ); - aGrad.StartColor = static_cast<sal_Int32>( nStartTrans | nStartTrans << 8 | nStartTrans << 16 ); - aVal <<= aGrad; - rPropMap.setProperty( ShapeProperty::GradientTransparency, aGrad ); + eFillStyle = FillStyle_BITMAP; } - } - break; - case XML_blipFill: - // do not start complex graphic transformation if property is not supported... - if (maBlipProps.mxFillGraphic.is() && rPropMap.supportsProperty(ShapeProperty::FillBitmap)) + // set other bitmap properties, if bitmap has been inserted into the map + if( eFillStyle == FillStyle_BITMAP ) { - uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, nPhClr); - // TODO: "rotate with shape" is not possible with our current core + // bitmap mode (single, repeat, stretch) + BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.get( XML_TOKEN_INVALID ) ); + rPropMap.setProperty( ShapeProperty::FillBitmapMode, eBitmapMode ); - if (xGraphic.is()) + // additional settings for repeated bitmap + if( eBitmapMode == BitmapMode_REPEAT ) { ... etc. - the rest is truncated _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits