File bsc1175552.diff of Package libreoffice

From d9a4d60c360d9dcba316eeb915adc0095f284544 Mon Sep 17 00:00:00 2001
From: Miklos Vajna <vmiklos@collabora.com>
Date: Fri, 25 Sep 2020 17:27:03 +0200
Subject: [PATCH] bsc1175552.diff

This is a combination of 4 commits.

This is the 1st commit message:

oox smartart: snake algo: consider child's aspect ratio request for cols/rows

If the child's aspect ratio request will shrink the width, then take
that into account when calculating how many rows / cols we need.

This reduces the number of columns for the bugdoc from 4 to 3, which is
needed, but not enough to render it correctly.

(cherry picked from commit acc9aead3cc5162379d34a455aa15f7b13907cf1)

Conflicts:
	sd/qa/unit/import-tests-smartart.cxx

This is the commit message #2:

oox smartart: snake algo: start parsing relative width constraints

This is needed, but not enough to have the correct width for each shape
and spacing item on the path of the snake. Currently we give the same
width for all children, while the shapes typically have a larger width
than the spacings.

(cherry picked from commit ab291c94fb5338a1cf0ab8fe7cbf57dd5c5f81cb)

This is the commit message #3:

oox smartart: snake algo: apply constraints on child shape widths

This requires tracking what is the total of the width request of child
shapes, then scaling them according to what is the total available
width.

Additionally, the height of child shapes should be adjusted based on
their aspect ratio requests. A related trap is when an (invisible)
spacing shape is at the end of the row, that would result in smaller
spacing between the rows, so track the max height of shapes inside a
single row.

With this, finally the 6 child shapes are arranged on 2 rows, not 3
ones.

(cherry picked from commit 5d899bf3ee59a226f855c8c56389344862efaa95)

Conflicts:
	sd/qa/unit/import-tests-smartart.cxx

This is the commit message #4:

oox smartart: snake algo: make sure child shape height stays within parent

1) When applying double outside spacing, introduced with commit
0a29c928afa74123bca05dc089c751603d368467 (oox smartart, picture strip:
fix lack of spacing around the picture list, 2019-02-26), make sure that
is only applied in the direction of a signle row: i.e. the bugdoc case
is left/right outer spacing, but no top/bottom spacing.

2) If a child shape has an aspect ratio request, make sure that it only
decreases what would be allocated by default, so the children never
leave the parent's rectangle.

3) Fix a mis-match between the first and second row, the unexpected
small left padding in the second row was because code assumed that all
child shapes have the same width; which is not true, when widths come
from constraints.

With this in place, we finally do a good rendering of the bugdoc, and
child shapes are always within the bounds of the background.

(cherry picked from commit 71303c5c23bdb385e9f12c0dbe5d2a0818b836ec)

Conflicts:
	sd/qa/unit/import-tests-smartart.cxx

Change-Id: Ia2606dcd945402f7dfe17c6e2f261bfd98667022
---
 .../drawingml/diagram/diagramlayoutatoms.cxx  | 181 ++++++++++++++++--
 1 file changed, 162 insertions(+), 19 deletions(-)

diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 6175832a426d..d3c2033f74f1 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -361,6 +361,12 @@ void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints,
                 bRequireForName = false;
                 break;
         }
+        switch (maConstraint.mnPointType)
+        {
+            case XML_sibTrans:
+                bRequireForName = false;
+                break;
+        }
     }
 
     if (bRequireForName && maConstraint.msForName.isEmpty())
@@ -456,6 +462,12 @@ namespace
  */
 void ApplyConstraintToLayout(const Constraint& rConstraint, LayoutPropertyMap& rProperties)
 {
+    // TODO handle the case when we have ptType="...", not forName="...".
+    if (rConstraint.msForName.isEmpty())
+    {
+        return;
+    }
+
     const LayoutPropertyMap::const_iterator aRef = rProperties.find(rConstraint.msRefForName);
     if (aRef != rProperties.end())
     {
@@ -1285,27 +1297,101 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
             if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0)
                 break;
 
-            // Parse constraints, only self spacing from height as a start.
-            double fSpaceFromConstraint = 0;
+            // Parse constraints.
+            double fChildAspectRatio = rShape->getChildren()[0]->getAspectRatio();
+            double fShapeHeight = rShape->getSize().Height;
+            double fShapeWidth = rShape->getSize().Width;
+            // Check if we have a child aspect ratio. If so, need to shrink one dimension to
+            // achieve that ratio.
+            if (fChildAspectRatio && fShapeHeight
+                && fChildAspectRatio < (fShapeWidth / fShapeHeight))
+            {
+                fShapeWidth = fShapeHeight * fChildAspectRatio;
+            }
+
+            double fSpaceFromConstraint = 1.0;
+            LayoutPropertyMap aPropertiesByName;
+            std::map<sal_Int32, LayoutProperty> aPropertiesByType;
+            LayoutProperty& rParent = aPropertiesByName[""];
+            rParent[XML_w] = fShapeWidth;
+            rParent[XML_h] = fShapeHeight;
             for (const auto& rConstr : rConstraints)
             {
-                if (rConstr.mnRefType == XML_h)
+                if (rConstr.mnRefType == XML_w || rConstr.mnRefType == XML_h)
                 {
                     if (rConstr.mnType == XML_sp && rConstr.msForName.isEmpty())
                         fSpaceFromConstraint = rConstr.mfFactor;
                 }
+
+                auto itRefForName = aPropertiesByName.find(rConstr.msRefForName);
+                if (itRefForName == aPropertiesByName.end())
+                {
+                    continue;
+                }
+
+                auto it = itRefForName->second.find(rConstr.mnRefType);
+                if (it == itRefForName->second.end())
+                {
+                    continue;
+                }
+
+                if (rConstr.mfValue != 0.0)
+                {
+                    continue;
+                }
+
+                sal_Int32 nValue = it->second * rConstr.mfFactor;
+
+                if (rConstr.mnPointType == XML_none)
+                {
+                    aPropertiesByName[rConstr.msForName][rConstr.mnType] = nValue;
+                }
+                else
+                {
+                    aPropertiesByType[rConstr.mnPointType][rConstr.mnType] = nValue;
+                }
+            }
+
+            std::vector<sal_Int32> aShapeWidths(rShape->getChildren().size());
+            for (size_t i = 0; i < rShape->getChildren().size(); ++i)
+            {
+                ShapePtr pChild = rShape->getChildren()[i];
+                if (!pChild->getDataNodeType())
+                {
+                    // TODO handle the case when the requirement applies by name, not by point type.
+                    aShapeWidths[i] = fShapeWidth;
+                    continue;
+                }
+
+                auto itNodeType = aPropertiesByType.find(pChild->getDataNodeType());
+                if (itNodeType == aPropertiesByType.end())
+                {
+                    aShapeWidths[i] = fShapeWidth;
+                    continue;
+                }
+
+                auto it = itNodeType->second.find(XML_w);
+                if (it == itNodeType->second.end())
+                {
+                    aShapeWidths[i] = fShapeWidth;
+                    continue;
+                }
+
+                aShapeWidths[i] = it->second;
             }
-            bool bSpaceFromConstraints = fSpaceFromConstraint != 0;
+
+            bool bSpaceFromConstraints = fSpaceFromConstraint != 1.0;
 
             const sal_Int32 nDir = maMap.count(XML_grDir) ? maMap.find(XML_grDir)->second : XML_tL;
             sal_Int32 nIncX = 1;
             sal_Int32 nIncY = 1;
+            bool bHorizontal = true;
             switch (nDir)
             {
                 case XML_tL: nIncX =  1; nIncY =  1; break;
                 case XML_tR: nIncX = -1; nIncY =  1; break;
-                case XML_bL: nIncX =  1; nIncY = -1; break;
-                case XML_bR: nIncX = -1; nIncY = -1; break;
+                case XML_bL: nIncX =  1; nIncY = -1; bHorizontal = false; break;
+                case XML_bR: nIncX = -1; nIncY = -1; bHorizontal = false; break;
             }
 
             sal_Int32 nCount = rShape->getChildren().size();
@@ -1315,7 +1401,7 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
 
             sal_Int32 nCol = 1;
             sal_Int32 nRow = 1;
-            double fChildAspectRatio = rShape->getChildren()[0]->getAspectRatio();
+            sal_Int32 nMaxRowWidth = 0;
             if (nCount <= fChildAspectRatio)
                 // Child aspect ratio request (width/height) is N, and we have at most N shapes.
                 // This means we don't need multiple columns.
@@ -1324,11 +1410,25 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
             {
                 for ( ; nRow<nCount; nRow++)
                 {
-                    nCol = (nCount+nRow-1) / nRow;
-                    const double fShapeHeight = rShape->getSize().Height;
-                    const double fShapeWidth = rShape->getSize().Width;
-                    if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio)
+                    nCol = std::ceil(static_cast<double>(nCount) / nRow);
+                    sal_Int32 nRowWidth = 0;
+                    for (sal_Int32 i = 0; i < nCol; ++i)
+                    {
+                        if (i >= nCount)
+                        {
+                            break;
+                        }
+
+                        nRowWidth += aShapeWidths[i];
+                    }
+                    if ((fShapeHeight * nRow) / nRowWidth >= fAspectRatio)
+                    {
+                        if (nRowWidth > nMaxRowWidth)
+                        {
+                            nMaxRowWidth = nRowWidth;
+                        }
                         break;
+                    }
                 }
             }
 
@@ -1355,6 +1455,8 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
                                       static_cast<sal_Int32>(nHeight * fChildAspectRatio));
                     aChildSize = awt::Size(nWidth, nHeight);
                 }
+
+                bHorizontal = false;
             }
 
             awt::Point aCurrPos(0, 0);
@@ -1363,8 +1465,13 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
             if (nIncY == -1)
                 aCurrPos.Y = rShape->getSize().Height - aChildSize.Height;
             else if (bSpaceFromConstraints)
-                // Initial vertical offset to have upper spacing (outside, so double amount).
-                aCurrPos.Y = aChildSize.Height * fSpace * 2;
+            {
+                if (!bHorizontal)
+                {
+                    // Initial vertical offset to have upper spacing (outside, so double amount).
+                    aCurrPos.Y = aChildSize.Height * fSpace * 2;
+                }
+            }
 
             sal_Int32 nStartX = aCurrPos.X;
             sal_Int32 nColIdx = 0,index = 0;
@@ -1374,35 +1481,71 @@ void AlgAtom::layoutShape(const ShapePtr& rShape, const std::vector<Constraint>&
             switch(aContDir)
             {
                 case XML_sameDir:
+                {
+                sal_Int32 nRowHeight = 0;
                 for (auto & aCurrShape : rShape->getChildren())
                 {
                     aCurrShape->setPosition(aCurrPos);
-                    aCurrShape->setSize(aChildSize);
-                    aCurrShape->setChildSize(aChildSize);
+                    awt::Size aCurrSize(aChildSize);
+                    // aShapeWidths items are a portion of nMaxRowWidth. We want the same ratio,
+                    // based on the original parent width, ignoring the aspect ratio request.
+                    double fWidthFactor = static_cast<double>(aShapeWidths[index]) / nMaxRowWidth;
+                    bool bWidthsFromConstraints = nCount >= 2 && rShape->getChildren()[1]->getDataNodeType() == XML_sibTrans;
+                    if (bWidthsFromConstraints)
+                    {
+                        // We can only work from constraints if spacing is represented by a real
+                        // child shape.
+                        aCurrSize.Width = rShape->getSize().Width * fWidthFactor;
+                    }
+                    if (fChildAspectRatio)
+                    {
+                        aCurrSize.Height = aCurrSize.Width / fChildAspectRatio;
+
+                        // Child shapes are not allowed to leave their parent.
+                        aCurrSize.Height = std::min<sal_Int32>(aCurrSize.Height, rShape->getSize().Height / (nRow + (nRow-1)*fSpace));
+                    }
+                    if (aCurrSize.Height > nRowHeight)
+                    {
+                        nRowHeight = aCurrSize.Height;
+                    }
+                    aCurrShape->setSize(aCurrSize);
+                    aCurrShape->setChildSize(aCurrSize);
 
                     index++; // counts index of child, helpful for positioning.
 
                     if(index%nCol==0 || ((index/nCol)+1)!=nRow)
-                        aCurrPos.X += nIncX * (aChildSize.Width + fSpace*aChildSize.Width);
+                        aCurrPos.X += nIncX * (aCurrSize.Width + fSpace*aCurrSize.Width);
 
                     if(++nColIdx == nCol) // condition for next row
                     {
                         // if last row, then position children according to number of shapes.
                         if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol)
+                        {
                             // position first child of last row
-                            aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2;
+                            if (bWidthsFromConstraints)
+                            {
+                                aCurrPos.X = nStartX;
+                            }
+                            else
+                            {
+                                // Can assume that all child shape has the same width.
+                                aCurrPos.X = nStartX + (nIncX * (aCurrSize.Width + fSpace*aCurrSize.Width))/2;
+                            }
+                        }
                         else
                             // if not last row, positions first child of that row
                             aCurrPos.X = nStartX;
-                        aCurrPos.Y += nIncY * (aChildSize.Height + fSpace*aChildSize.Height);
+                        aCurrPos.Y += nIncY * (nRowHeight + fSpace*nRowHeight);
                         nColIdx = 0;
+                        nRowHeight = 0;
                     }
 
                     // positions children in the last row.
                     if(index%nCol!=0 && index>=3 && ((index/nCol)+1)==nRow)
-                        aCurrPos.X += (nIncX * (aChildSize.Width + fSpace*aChildSize.Width));
+                        aCurrPos.X += (nIncX * (aCurrSize.Width + fSpace*aCurrSize.Width));
                 }
                 break;
+                }
                 case XML_revDir:
                 for (auto & aCurrShape : rShape->getChildren())
                 {
-- 
2.26.2

openSUSE Build Service is sponsored by