Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:frispete:LibreOffice
libreoffice
bsc1162022.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File bsc1162022.diff of Package libreoffice
From 8e797ffdedcfe63a6aaf28557931461b1d3cf87f Mon Sep 17 00:00:00 2001 From: Miklos Vajna <vmiklos@collabora.com> Date: Fri, 24 Jul 2020 15:52:10 +0200 Subject: [PATCH] bsc1162022.diff This is a combination of 7 commits. This is the 1st commit message: oox smartart: start parsing rule lists I have a linear algorithm where some elements should be scaled down, but not all of them. These requirements are described using rules. This commit just adds the parsing for them, so that later AlgAtom::layoutShape() can create an improved layout, taking rules into account. (cherry picked from commit 6ca5412bac9e3da5cd20f315fc853c7733f10858) This is the commit message #2: oox smartart: consider rules when scaling in linear layout The bugdoc has an arrow shape which is 100% wide, and there are multiple shapes before it, which also have a 100% wide constraint. The reason PowerPoint scales down the shapes (but not the arrow) is because rules declare it should happen this way. So start taking rules into account in linear layouts. (cherry picked from commit 0024c48b4822062995effed7db4f1281196384bb) Conflicts: sd/qa/unit/import-tests-smartart.cxx This is the commit message #3: oox smartart, linear layout: correctly scale spacings wrt constraints and rules When constraints request a width which is larger than 100%, we scale down. Then rules decide which children should be scaled down and which ones stay as-is. This commit adjusts the size of children which have no rule, but their size has a constraint that they're a fraction of a scaled down child. (cherry picked from commit 91f0f7e5e0a55cb1dbd729a1d7de52388b1cfb15) This is the commit message #4: Avoid UBSan signed-integer-overflow ...during CppunitTest_sd_import_tests_smartart: > oox/source/drawingml/diagram/diagramlayoutatoms.cxx:656:50: runtime error: signed integer overflow: 1924451 - -2147483647 cannot be represented in type 'int' > #0 in oox::drawingml::AlgAtom::layoutShape(std::shared_ptr<oox::drawingml::Shape> const&, std::__debug::vector<oox::drawingml::Constraint, std::allocator<oox::drawingml::Constraint> > const&, std::__debug::vector<oox::drawingml::Rule, std::allocator<oox::drawingml::Rule> > const&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:656:50 > #1 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::AlgAtom&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:202:19 > #2 in oox::drawingml::AlgAtom::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:386:14 > #3 in oox::drawingml::LayoutAtomVisitorBase::defaultVisit(oox::drawingml::LayoutAtom const&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:32:16 > #4 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::LayoutNode&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:243:5 > #5 in oox::drawingml::LayoutNode::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:1452:14 > #6 in oox::drawingml::LayoutAtomVisitorBase::defaultVisit(oox::drawingml::LayoutAtom const&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:32:16 > #7 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::LayoutNode&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:245:5 > #8 in oox::drawingml::LayoutNode::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:1452:14 > #9 in oox::drawingml::LayoutAtomVisitorBase::visit(oox::drawingml::ForEachAtom&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:98:20 > #10 in oox::drawingml::ForEachAtom::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:167:14 > #11 in oox::drawingml::LayoutAtomVisitorBase::defaultVisit(oox::drawingml::LayoutAtom const&) at oox/source/drawingml/diagram/layoutatomvisitorbase.cxx:32:16 > #12 in oox::drawingml::ShapeLayoutingVisitor::visit(oox::drawingml::LayoutNode&) at oox/source/drawingml/diagram/layoutatomvisitors.cxx:245:5 > #13 in oox::drawingml::LayoutNode::accept(oox::drawingml::LayoutAtomVisitor&) at oox/source/drawingml/diagram/diagramlayoutatoms.cxx:1452:14 > #14 in oox::drawingml::Diagram::addTo(std::shared_ptr<oox::drawingml::Shape> const&) at oox/source/drawingml/diagram/diagram.cxx:122:30 > #15 in oox::drawingml::loadDiagram(std::shared_ptr<oox::drawingml::Shape> const&, oox::core::XmlFilterBase&, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, oox::core::Relations const&) at oox/source/drawingml/diagram/diagram.cxx:356:15 > #16 in oox::drawingml::DiagramGraphicDataContext::onCreateContext(int, oox::AttributeList const&) at oox/source/drawingml/graphicshapecontext.cxx:252:9 > #17 in non-virtual thunk to oox::drawingml::DiagramGraphicDataContext::onCreateContext(int, oox::AttributeList const&) at oox/source/drawingml/graphicshapecontext.cxx > #18 in oox::core::ContextHandler2Helper::implCreateChildContext(int, com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> const&) at oox/source/core/contexthandler2.cxx:94:34 > #19 in oox::core::ContextHandler2::createFastChildContext(int, com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> const&) at oox/source/core/contexthandler2.cxx:191:12 > #20 in non-virtual thunk to oox::core::ContextHandler2::createFastChildContext(int, com::sun::star::uno::Reference<com::sun::star::xml::sax::XFastAttributeList> const&) at oox/source/core/contexthandler2.cxx > #21 in (anonymous namespace)::Entity::startElement((anonymous namespace)::Event const*) at sax/source/fastparser/fastparser.cxx:432:44 > #22 in sax_fastparser::FastSaxParserImpl::callbackStartElement(unsigned char const*, unsigned char const*, unsigned char const*, int, unsigned char const**, int, unsigned char const**) at sax/source/fastparser/fastparser.cxx:1246:21 > #23 in (anonymous namespace)::call_callbackStartElement(void*, unsigned char const*, unsigned char const*, unsigned char const*, int, unsigned char const**, int, int, unsigned char const**) at sax/source/fastparser/fastparser.cxx:305:18 > #24 in xmlParseStartTag2 at workdir/UnpackedTarball/libxml2/parser.c:9588:6 > #25 in xmlParseTryOrFinish at workdir/UnpackedTarball/libxml2/parser.c:11378:14 > #26 in xmlParseChunk__internal_alias at workdir/UnpackedTarball/libxml2/parser.c:12280:13 > #27 in sax_fastparser::FastSaxParserImpl::parse() at sax/source/fastparser/fastparser.cxx:1046:21 > #28 in sax_fastparser::FastSaxParserImpl::parseStream(com::sun::star::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:866:9 > #29 in sax_fastparser::FastSaxParser::parseStream(com::sun::star::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:1369:13 > #30 in oox::core::FastParser::parseStream(com::sun::star::xml::sax::InputSource const&, bool) at oox/source/core/fastparser.cxx:121:15 > #31 in oox::core::FastParser::parseStream(com::sun::star::uno::Reference<com::sun::star::io::XInputStream> const&, rtl::OUString const&) at oox/source/core/fastparser.cxx:129:5 > #32 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&, oox::core::FastParser&) at oox/source/core/xmlfilterbase.cxx:402:21 > #33 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&) at oox/source/core/xmlfilterbase.cxx:331:12 > #34 in oox::ppt::PresentationFragmentHandler::importSlide(rtl::Reference<oox::core::FragmentHandler> const&, std::shared_ptr<oox::ppt::SlidePersist> const&) at oox/source/ppt/presentationfragmenthandler.cxx:610:17 > #35 in oox::ppt::PresentationFragmentHandler::importSlide(unsigned int, bool, bool) at oox/source/ppt/presentationfragmenthandler.cxx:348:13 > #36 in oox::ppt::PresentationFragmentHandler::finalizeImport() at oox/source/ppt/presentationfragmenthandler.cxx:499:17 > #37 in oox::core::FragmentHandler2::endDocument() at oox/source/core/fragmenthandler2.cxx:54:5 > #38 in sax_fastparser::FastSaxParserImpl::parseStream(com::sun::star::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:872:36 > #39 in sax_fastparser::FastSaxParser::parseStream(com::sun::star::xml::sax::InputSource const&) at sax/source/fastparser/fastparser.cxx:1369:13 > #40 in oox::core::FastParser::parseStream(com::sun::star::xml::sax::InputSource const&, bool) at oox/source/core/fastparser.cxx:121:15 > #41 in oox::core::FastParser::parseStream(com::sun::star::uno::Reference<com::sun::star::io::XInputStream> const&, rtl::OUString const&) at oox/source/core/fastparser.cxx:129:5 > #42 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&, oox::core::FastParser&) at oox/source/core/xmlfilterbase.cxx:402:21 > #43 in oox::core::XmlFilterBase::importFragment(rtl::Reference<oox::core::FragmentHandler> const&) at oox/source/core/xmlfilterbase.cxx:331:12 > #44 in oox::ppt::PowerPointImport::importDocument() at oox/source/ppt/pptimport.cxx:145:17 > #45 in oox::core::FilterBase::filter(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at oox/source/core/filterbase.cxx:485:49 > #46 in oox::ppt::PowerPointImport::filter(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at oox/source/ppt/pptimport.cxx:223:24 > #47 in SfxObjectShell::ImportFrom(SfxMedium&, com::sun::star::uno::Reference<com::sun::star::text::XTextRange> const&) at sfx2/source/doc/objstor.cxx:2251:34 > #48 in sd::DrawDocShell::ImportFrom(SfxMedium&, com::sun::star::uno::Reference<com::sun::star::text::XTextRange> const&) at sd/source/ui/docshell/docshel4.cxx:399:39 > #49 in SfxObjectShell::DoLoad(SfxMedium*) at sfx2/source/doc/objstor.cxx:738:23 > #50 in SdModelTestBase::loadURL(rtl::OUString const&, int, std::shared_ptr<SfxAllItemSet>) at sd/qa/unit/sdmodeltestbase.hxx:181:30 > #51 in SdImportTestSmartArt::testText() at sd/qa/unit/import-tests-smartart.cxx:250:37 As discussed on IRC: > Jul 31 18:52:58 <vmiklos> sberg: yes, that looks reasonable, clearly the > expectation is that there is at least one element, in which case that > nVertMin grows from 0 and nVertMax shrinks from > std::numeric_limits<sal_Int32>::max() > Jul 31 18:54:43 <vmiklos> sberg: sounds like i made that mistake in > acdde3c643fde015214c546b1567727272ea799e, but recently i added a test that > now uncovered the problem :) (cherry picked from commit ae4a69d7559a537e86630b2890d28b0d8f6f47d0) This is the commit message #5: oox smartart, linear layout: fix scaling of spacing without rules With this, finally the arrow shape has the correct horizontal position and width, even if the markup is as complex as the PowerPoint UI generates it (the previous version was a more minimal version). (cherry picked from commit 880673412143a7db7ea1bf4766040662dfc085dc) This is the commit message #6: oox smartart, linear layout: limit height of children to parent size Constraints are OK to request more, but it seems PowerPoint doesn't allow leaving the parent, which simplifies the layout as well. (cherry picked from commit b7481a026348c3417fa13a440312521dccee9ec8) This is the commit message #7: oox smartart: add support for <dgm:layoutNode ... chOrder="t"> This changes the order of children, which matters when they have no explicit ZOrder. With this, the text shapes on the arrow shape are on top of the arrow, not behind it. The trick is that nominally chOrder can be "t"(op) or "b"(ottom), defaulting to bottom, but there is a difference between an explicit "b" and not setting it. When not setting it, the layout node is expected to inherit it from its parent layout node, recursively. This would probably make sense for other algorithms as well, but set it only for the linear algorithm for now, as that's where we have a bug document showing the PowerPoint behavior. (cherry picked from commit 3c185bf386b4c9609ab32d19bf95b83fe0eeeea3) Change-Id: I433f92c620149ef5590aebc8cbf43110e1d2fb85 --- .../diagram/constraintlistcontext.cxx | 30 +++ .../diagram/constraintlistcontext.hxx | 14 ++ oox/source/drawingml/diagram/diagram.cxx | 20 ++ .../drawingml/diagram/diagramlayoutatoms.cxx | 202 +++++++++++++++++- .../drawingml/diagram/diagramlayoutatoms.hxx | 25 ++- .../diagram/layoutatomvisitorbase.cxx | 5 + .../diagram/layoutatomvisitorbase.hxx | 4 +- .../drawingml/diagram/layoutatomvisitors.cxx | 26 ++- .../drawingml/diagram/layoutatomvisitors.hxx | 4 + .../drawingml/diagram/layoutnodecontext.cxx | 22 +- 10 files changed, 330 insertions(+), 22 deletions(-) diff --git a/oox/source/drawingml/diagram/constraintlistcontext.cxx b/oox/source/drawingml/diagram/constraintlistcontext.cxx index cc71c89b226a..1dfbdc23b18b 100644 --- a/oox/source/drawingml/diagram/constraintlistcontext.cxx +++ b/oox/source/drawingml/diagram/constraintlistcontext.cxx @@ -73,6 +73,36 @@ ConstraintListContext::onCreateContext( ::sal_Int32 aElement, return this; } +RuleListContext::RuleListContext(ContextHandler2Helper const& rParent, const LayoutAtomPtr& pNode) + : ContextHandler2(rParent) + , mpNode(pNode) +{ + assert(pNode); +} + +RuleListContext::~RuleListContext() {} + +core::ContextHandlerRef RuleListContext::onCreateContext(sal_Int32 nElement, + const AttributeList& rAttribs) +{ + switch (nElement) + { + case DGM_TOKEN(rule): + { + auto pNode = std::make_shared<RuleAtom>(mpNode->getLayoutNode()); + LayoutAtom::connect(mpNode, pNode); + + Rule& rRule = pNode->getRule(); + rRule.msForName = rAttribs.getString(XML_forName, ""); + break; + } + default: + break; + } + + return this; +} + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/diagram/constraintlistcontext.hxx b/oox/source/drawingml/diagram/constraintlistcontext.hxx index 619235ac2550..a1d21d37c182 100644 --- a/oox/source/drawingml/diagram/constraintlistcontext.hxx +++ b/oox/source/drawingml/diagram/constraintlistcontext.hxx @@ -37,6 +37,20 @@ private: LayoutAtomPtr mpNode; }; +/// Handles one <dgm:ruleLst> element. +class RuleListContext : public oox::core::ContextHandler2 +{ +public: + RuleListContext(ContextHandler2Helper const& rParent, const LayoutAtomPtr& pNode); + virtual ~RuleListContext() override; + + virtual oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElement, + const AttributeList& rAttribs) override; + +private: + LayoutAtomPtr mpNode; +}; + } } #endif diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index a03a06c39125..509a1f845e25 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -82,6 +82,25 @@ static void sortChildrenByZOrder(const ShapePtr& pShape) sortChildrenByZOrder(rChild); } +/// Removes empty group shapes, now that their spacing influenced the layout. +static void removeUnneededGroupShapes(const ShapePtr& pShape) +{ + std::vector<ShapePtr>& rChildren = pShape->getChildren(); + + rChildren.erase(std::remove_if(rChildren.begin(), rChildren.end(), + [](const ShapePtr& aChild) { + return aChild->getServiceName() + == "com.sun.star.drawing.GroupShape" + && aChild->getChildren().empty(); + }), + rChildren.end()); + + for (const auto& pChild : rChildren) + { + removeUnneededGroupShapes(pChild); + } +} + void Diagram::addTo( const ShapePtr & pParentShape ) { if (pParentShape->getSize().Width == 0 || pParentShape->getSize().Height == 0) @@ -103,6 +122,7 @@ void Diagram::addTo( const ShapePtr & pParentShape ) mpLayout->getNode()->accept(aLayoutingVisitor); sortChildrenByZOrder(pParentShape); + removeUnneededGroupShapes(pParentShape); } ShapePtr pBackground(new Shape("com.sun.star.drawing.CustomShape")); diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index 19b1d10679f4..44a66f819e98 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -19,6 +19,8 @@ #include "diagramlayoutatoms.hxx" +#include <set> + #include "layoutatomvisitorbase.hxx" #include <basegfx/numeric/ftools.hxx> @@ -338,6 +340,11 @@ void ConstraintAtom::accept( LayoutAtomVisitor& rVisitor ) rVisitor.visit(*this); } +void RuleAtom::accept( LayoutAtomVisitor& rVisitor ) +{ + rVisitor.visit(*this); +} + void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints, bool bRequireForName) const { @@ -367,6 +374,14 @@ void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints, } } +void RuleAtom::parseRule(std::vector<Rule>& rRules) const +{ + if (!maRule.msForName.isEmpty()) + { + rRules.push_back(maRule); + } +} + void AlgAtom::accept( LayoutAtomVisitor& rVisitor ) { rVisitor.visit(*this); @@ -466,9 +481,21 @@ void ApplyConstraintToLayout(const Constraint& rConstraint, LayoutPropertyMap& r } } -void AlgAtom::layoutShape( const ShapePtr& rShape, - const std::vector<Constraint>& rConstraints ) +void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>& rConstraints, + const std::vector<Rule>& rRules) { + if (mnType != XML_lin) + { + // TODO Handle spacing from constraints for non-lin algorithms as well. + rShape->getChildren().erase( + std::remove_if(rShape->getChildren().begin(), rShape->getChildren().end(), + [](const ShapePtr& aChild) { + return aChild->getServiceName() == "com.sun.star.drawing.GroupShape" + && aChild->getChildren().empty(); + }), + rShape->getChildren().end()); + } + switch(mnType) { case XML_composite: @@ -625,7 +652,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, } // See if all vertical space is used or we have to center the content. - if (nVertMin >= 0 && nVertMax <= rParent[XML_h]) + if (nVertMin >= 0 && nVertMin <= nVertMax && nVertMax <= rParent[XML_h]) { sal_Int32 nDiff = rParent[XML_h] - (nVertMax - nVertMin); if (nDiff > 0) @@ -879,7 +906,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, const sal_Int32 nIncX = nDir==XML_fromL ? 1 : (nDir==XML_fromR ? -1 : 0); const sal_Int32 nIncY = nDir==XML_fromT ? 1 : (nDir==XML_fromB ? -1 : 0); - sal_Int32 nCount = rShape->getChildren().size(); + double fCount = rShape->getChildren().size(); sal_Int32 nConnectorAngle = 0; switch (nDir) { @@ -900,9 +927,21 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, LayoutProperty& rProperty = aProperties[rConstraint.msForName]; if (rConstraint.mnType == XML_w) + { rProperty[XML_w] = rShape->getSize().Width * rConstraint.mfFactor; + if (rProperty[XML_w] > rShape->getSize().Width) + { + rProperty[XML_w] = rShape->getSize().Width; + } + } if (rConstraint.mnType == XML_h) + { rProperty[XML_h] = rShape->getSize().Height * rConstraint.mfFactor; + if (rProperty[XML_h] > rShape->getSize().Height) + { + rProperty[XML_h] = rShape->getSize().Height; + } + } // TODO: get values from differently named constraints as well if (rConstraint.msForName == "sp" || rConstraint.msForName == "space" || rConstraint.msForName == "sibTrans") @@ -915,11 +954,114 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, } // first approximation of children size + std::set<OUString> aChildrenToShrink; + for (const auto& rRule : rRules) + { + // Consider rules: when scaling down, only change children where the rule allows + // doing so. + aChildrenToShrink.insert(rRule.msForName); + } + + if (!aChildrenToShrink.empty()) + { + // Have scaling info from rules: then only count scaled children. + // Also count children which are a fraction of a scaled child. + std::set<OUString> aChildrenToShrinkDeps; + for (auto& aCurrShape : rShape->getChildren()) + { + if (aChildrenToShrink.find(aCurrShape->getInternalName()) + == aChildrenToShrink.end()) + { + if (fCount > 1.0) + { + fCount -= 1.0; + + bool bIsDependency = false; + double fFactor = 0; + for (const auto& rConstraint : rConstraints) + { + if (rConstraint.msForName != aCurrShape->getInternalName()) + { + continue; + } + + if ((nDir == XML_fromL || nDir == XML_fromR) && rConstraint.mnType != XML_w) + { + continue; + } + if ((nDir == XML_fromL || nDir == XML_fromR) && rConstraint.mnType == XML_w) + { + fFactor = rConstraint.mfFactor; + } + + if ((nDir == XML_fromT || nDir == XML_fromB) && rConstraint.mnType != XML_h) + { + continue; + } + if ((nDir == XML_fromT || nDir == XML_fromB) && rConstraint.mnType == XML_h) + { + fFactor = rConstraint.mfFactor; + } + + if (aChildrenToShrink.find(rConstraint.msRefForName) == aChildrenToShrink.end()) + { + continue; + } + + // At this point we have a child with a size which is a factor of an + // other child which will be scaled. + fCount += rConstraint.mfFactor; + aChildrenToShrinkDeps.insert(aCurrShape->getInternalName()); + bIsDependency = true; + break; + } + + if (!bIsDependency && aCurrShape->getServiceName() == "com.sun.star.drawing.GroupShape") + { + bool bScaleDownEmptySpacing = false; + if (nDir == XML_fromL || nDir == XML_fromR) + { + oox::OptValue<sal_Int32> oWidth = findProperty(aProperties, aCurrShape->getInternalName(), XML_w); + bScaleDownEmptySpacing = oWidth.has() && oWidth.get() > 0; + } + if (!bScaleDownEmptySpacing && (nDir == XML_fromT || nDir == XML_fromB)) + { + oox::OptValue<sal_Int32> oHeight = findProperty(aProperties, aCurrShape->getInternalName(), XML_h); + bScaleDownEmptySpacing = oHeight.has() && oHeight.get() > 0; + } + if (bScaleDownEmptySpacing && aCurrShape->getChildren().empty()) + { + fCount += fFactor; + aChildrenToShrinkDeps.insert(aCurrShape->getInternalName()); + } + } + } + } + } + + aChildrenToShrink.insert(aChildrenToShrinkDeps.begin(), aChildrenToShrinkDeps.end()); + + // No manual spacing: spacings are children as well. + aSpaceSize = awt::Size(); + } + else + { + // TODO Handle spacing from constraints without rules as well. + rShape->getChildren().erase( + std::remove_if(rShape->getChildren().begin(), rShape->getChildren().end(), + [](const ShapePtr& aChild) { + return aChild->getServiceName() + == "com.sun.star.drawing.GroupShape" + && aChild->getChildren().empty(); + }), + rShape->getChildren().end()); + fCount = rShape->getChildren().size(); + } awt::Size aChildSize = rShape->getSize(); if (nDir == XML_fromL || nDir == XML_fromR) - aChildSize.Width /= nCount; + aChildSize.Width /= fCount; else if (nDir == XML_fromT || nDir == XML_fromB) - aChildSize.Height /= nCount; + aChildSize.Height /= fCount; awt::Point aCurrPos(0, 0); if (nIncX == -1) @@ -943,8 +1085,8 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, aTotalSize.Height += aSize.Height; } - aTotalSize.Width += (nCount-1) * aSpaceSize.Width; - aTotalSize.Height += (nCount-1) * aSpaceSize.Height; + aTotalSize.Width += (fCount-1) * aSpaceSize.Width; + aTotalSize.Height += (fCount-1) * aSpaceSize.Height; double fWidthScale = 1.0; double fHeightScale = 1.0; @@ -966,8 +1108,18 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, aSize.Width = oWidth.get(); if (oHeight.has()) aSize.Height = oHeight.get(); - aSize.Width *= fWidthScale; - aSize.Height *= fHeightScale; + if (aChildrenToShrink.empty() + || aChildrenToShrink.find(aCurrShape->getInternalName()) + != aChildrenToShrink.end()) + { + aSize.Width *= fWidthScale; + } + if (aChildrenToShrink.empty() + || aChildrenToShrink.find(aCurrShape->getInternalName()) + != aChildrenToShrink.end()) + { + aSize.Height *= fHeightScale; + } aCurrShape->setSize(aSize); aCurrShape->setChildSize(aSize); @@ -976,6 +1128,14 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, aCurrPos.Y = (rShape->getSize().Height - aSize.Height) / 2; if (nIncY) aCurrPos.X = (rShape->getSize().Width - aSize.Width) / 2; + if (aCurrPos.X < 0) + { + aCurrPos.X = 0; + } + if (aCurrPos.Y < 0) + { + aCurrPos.Y = 0; + } aCurrShape->setPosition(aCurrPos); @@ -987,6 +1147,28 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, if (aCurrShape->getSubType() == XML_conn) aCurrShape->setRotation(nConnectorAngle * PER_DEGREE); } + + // Newer shapes are behind older ones by default. Reverse this if requested. + sal_Int32 nChildOrder = XML_b; + const LayoutNode* pParentLayoutNode = nullptr; + for (LayoutAtomPtr pAtom = getParent(); pAtom; pAtom = pAtom->getParent()) + { + auto pLayoutNode = dynamic_cast<LayoutNode*>(pAtom.get()); + if (pLayoutNode) + { + pParentLayoutNode = pLayoutNode; + break; + } + } + if (pParentLayoutNode) + { + nChildOrder = pParentLayoutNode->getChildOrder(); + } + if (nChildOrder == XML_t) + { + std::reverse(rShape->getChildren().begin(), rShape->getChildren().end()); + } + break; } diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index 2e4551642389..ab152bed0b70 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -63,6 +63,7 @@ struct ConditionAttr sal_Int32 mnVal; }; +/// Constraints allow you to specify an ideal (or starting point) size for each shape. struct Constraint { sal_Int32 mnFor; @@ -78,6 +79,12 @@ struct Constraint sal_Int32 mnOperator; }; +/// Rules allow you to specify what to do when constraints can't be fully satisfied. +struct Rule +{ + OUString msForName; +}; + typedef std::map<sal_Int32, sal_Int32> LayoutProperty; typedef std::map<OUString, LayoutProperty> LayoutPropertyMap; @@ -146,6 +153,20 @@ private: Constraint maConstraint; }; +/// Represents one <dgm:rule> element. +class RuleAtom + : public LayoutAtom +{ +public: + RuleAtom(LayoutNode& rLayoutNode) : LayoutAtom(rLayoutNode) {} + virtual void accept( LayoutAtomVisitor& ) override; + Rule& getRule() + { return maRule; } + void parseRule(std::vector<Rule>& rRules) const; +private: + Rule maRule; +}; + class AlgAtom : public LayoutAtom { @@ -162,7 +183,8 @@ public: { maMap[nType]=nVal; } sal_Int32 getVerticalShapesCount(const ShapePtr& rShape); void layoutShape( const ShapePtr& rShape, - const std::vector<Constraint>& rConstraints ); + const std::vector<Constraint>& rConstraints, + const std::vector<Rule>& rRules ); void setAspectRatio(double fAspectRatio) { mfAspectRatio = fAspectRatio; } @@ -250,6 +272,7 @@ public: { msStyleLabel = sLabel; } void setChildOrder( sal_Int32 nOrder ) { mnChildOrder = nOrder; } + sal_Int32 getChildOrder() const { return mnChildOrder; } void setExistingShape( const ShapePtr& pShape ) { mpExistingShape = pShape; } const ShapePtr& getExistingShape() const diff --git a/oox/source/drawingml/diagram/layoutatomvisitorbase.cxx b/oox/source/drawingml/diagram/layoutatomvisitorbase.cxx index 98206433653a..d9df0403a6e7 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitorbase.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitorbase.cxx @@ -142,6 +142,11 @@ void ShallowPresNameVisitor::visit(ConstraintAtom& /*rAtom*/) // stop processing } +void ShallowPresNameVisitor::visit(RuleAtom& /*rAtom*/) +{ + // stop processing +} + void ShallowPresNameVisitor::visit(AlgAtom& /*rAtom*/) { // stop processing diff --git a/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx b/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx index ff12f82e2f96..4069a732ebef 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx +++ b/oox/source/drawingml/diagram/layoutatomvisitorbase.hxx @@ -32,6 +32,7 @@ struct LayoutAtomVisitor { virtual ~LayoutAtomVisitor() {} virtual void visit(ConstraintAtom& rAtom) = 0; + virtual void visit(RuleAtom& rAtom) = 0; virtual void visit(AlgAtom& rAtom) = 0; virtual void visit(ForEachAtom& rAtom) = 0; virtual void visit(ConditionAtom& rAtom) = 0; @@ -68,7 +69,7 @@ protected: sal_Int32 mnCurrIdx; sal_Int32 mnCurrStep; sal_Int32 mnCurrCnt; - enum {LAYOUT_NODE, CONSTRAINT, ALGORITHM} meLookFor; + enum {LAYOUT_NODE, CONSTRAINT, ALGORITHM, RULE} meLookFor; }; class ShallowPresNameVisitor : public LayoutAtomVisitorBase @@ -81,6 +82,7 @@ public: using LayoutAtomVisitorBase::visit; virtual void visit(ConstraintAtom& rAtom) override; + virtual void visit(RuleAtom& rAtom) override; virtual void visit(AlgAtom& rAtom) override; virtual void visit(ForEachAtom& rAtom) override; virtual void visit(LayoutNode& rAtom) override; diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx index c616ca3a9010..ccea74c2efde 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -35,6 +35,11 @@ void ShapeCreationVisitor::visit(ConstraintAtom& /*rAtom*/) // stop processing } +void ShapeCreationVisitor::visit(RuleAtom& /*rAtom*/) +{ + // stop processing +} + void ShapeCreationVisitor::visit(AlgAtom& rAtom) { if (meLookFor == ALGORITHM) @@ -118,12 +123,6 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) meLookFor = LAYOUT_NODE; defaultVisit(rAtom); - // remove unneeded empty group shapes - pCurrParent->getChildren().erase( - std::remove_if(pCurrParent->getChildren().begin(), pCurrParent->getChildren().end(), - [] (const ShapePtr & aChild) { return aChild->getServiceName() == "com.sun.star.drawing.GroupShape" && aChild->getChildren().empty(); }), - pCurrParent->getChildren().end()); - meLookFor = ALGORITHM; defaultVisit(rAtom); meLookFor = LAYOUT_NODE; @@ -143,6 +142,11 @@ void ShapeTemplateVisitor::visit(ConstraintAtom& /*rAtom*/) // stop processing } +void ShapeTemplateVisitor::visit(RuleAtom& /*rAtom*/) +{ + // stop processing +} + void ShapeTemplateVisitor::visit(AlgAtom& /*rAtom*/) { // stop processing @@ -182,6 +186,12 @@ void ShapeLayoutingVisitor::visit(ConstraintAtom& rAtom) rAtom.parseConstraint(maConstraints, /*bRequireForName=*/true); } +void ShapeLayoutingVisitor::visit(RuleAtom& rAtom) +{ + if (meLookFor == RULE) + rAtom.parseRule(maRules); +} + void ShapeLayoutingVisitor::visit(AlgAtom& rAtom) { if (meLookFor == ALGORITHM) @@ -189,7 +199,7 @@ void ShapeLayoutingVisitor::visit(AlgAtom& rAtom) const PresPointShapeMap aMap = rAtom.getLayoutNode().getDiagram().getLayout()->getPresPointShapeMap(); auto pShape = aMap.find(mpCurrentNode); if (pShape != aMap.end()) - rAtom.layoutShape(pShape->second, maConstraints); + rAtom.layoutShape(pShape->second, maConstraints, maRules); } } @@ -227,6 +237,8 @@ void ShapeLayoutingVisitor::visit(LayoutNode& rAtom) // process alg atoms first, nested layout nodes afterwards meLookFor = CONSTRAINT; defaultVisit(rAtom); + meLookFor = RULE; + defaultVisit(rAtom); meLookFor = ALGORITHM; defaultVisit(rAtom); meLookFor = LAYOUT_NODE; diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx index 656f61d79e6a..3ac2fa7e4fb8 100644 --- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx @@ -41,6 +41,7 @@ public: using LayoutAtomVisitorBase::visit; virtual void visit(ConstraintAtom& rAtom) override; + virtual void visit(RuleAtom& rAtom) override; virtual void visit(AlgAtom& rAtom) override; virtual void visit(LayoutNode& rAtom) override; virtual void visit(ShapeAtom& rAtom) override; @@ -58,6 +59,7 @@ public: using LayoutAtomVisitorBase::visit; virtual void visit(ConstraintAtom& rAtom) override; + virtual void visit(RuleAtom& rAtom) override; virtual void visit(AlgAtom& rAtom) override; virtual void visit(ForEachAtom& rAtom) override; virtual void visit(LayoutNode& rAtom) override; @@ -79,12 +81,14 @@ public: using LayoutAtomVisitorBase::visit; virtual void visit(ConstraintAtom& rAtom) override; + virtual void visit(RuleAtom& rAtom) override; virtual void visit(AlgAtom& rAtom) override; virtual void visit(LayoutNode& rAtom) override; virtual void visit(ShapeAtom& rAtom) override; private: std::vector<Constraint> maConstraints; + std::vector<Rule> maRules; }; } } diff --git a/oox/source/drawingml/diagram/layoutnodecontext.cxx b/oox/source/drawingml/diagram/layoutnodecontext.cxx index 3547aad28a7a..bfd00367a76c 100644 --- a/oox/source/drawingml/diagram/layoutnodecontext.cxx +++ b/oox/source/drawingml/diagram/layoutnodecontext.cxx @@ -194,7 +194,24 @@ LayoutNodeContext::onCreateContext( ::sal_Int32 aElement, { LayoutNodePtr pNode( new LayoutNode(mpNode->getLayoutNode().getDiagram()) ); LayoutAtom::connect(mpNode, pNode); - pNode->setChildOrder( rAttribs.getToken( XML_chOrder, XML_b ) ); + + if (rAttribs.hasAttribute(XML_chOrder)) + { + pNode->setChildOrder(rAttribs.getToken(XML_chOrder, XML_b)); + } + else + { + for (LayoutAtomPtr pAtom = mpNode; pAtom; pAtom = pAtom->getParent()) + { + auto pLayoutNode = dynamic_cast<LayoutNode*>(pAtom.get()); + if (pLayoutNode) + { + pNode->setChildOrder(pLayoutNode->getChildOrder()); + break; + } + } + } + pNode->setMoveWith( rAttribs.getString( XML_moveWith ).get() ); pNode->setStyleLabel( rAttribs.getString( XML_styleLbl ).get() ); return new LayoutNodeContext( *this, rAttribs, pNode ); @@ -262,8 +279,7 @@ LayoutNodeContext::onCreateContext( ::sal_Int32 aElement, } case DGM_TOKEN( ruleLst ): // CT_Rules - // TODO - break; + return new RuleListContext( *this, mpNode ); case DGM_TOKEN( varLst ): { LayoutNodePtr pNode(std::dynamic_pointer_cast<LayoutNode>(mpNode)); -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor