include/svx/compatflags.hxx                             |    2 
 include/tools/poly.hxx                                  |    1 
 oox/qa/unit/shape.cxx                                   |    4 
 sc/source/ui/docshell/docsh.cxx                         |    2 
 sd/qa/unit/export-tests-ooxml3.cxx                      |    2 
 sd/source/ui/docshell/docshel4.cxx                      |    2 
 svx/qa/unit/data/tdf148000_CurvedTextWidth.pptx         |binary
 svx/qa/unit/data/tdf148000_CurvedTextWidth_Legacy.odp   |binary
 svx/qa/unit/data/tdf148000_CurvedTextWidth_New.odp      |binary
 svx/qa/unit/svdraw.cxx                                  |   39 ++
 svx/source/customshapes/EnhancedCustomShapeFontWork.cxx |  275 +++++++++++++---
 svx/source/svdraw/svdmodel.cxx                          |   18 -
 sw/source/uibase/app/docshini.cxx                       |    2 
 13 files changed, 296 insertions(+), 51 deletions(-)

New commits:
commit 3a5cc107efb843b01193230c56dc8d9c0072348a
Author:     Attila Szűcs <attila.sz...@collabora.com>
AuthorDate: Wed Nov 15 07:04:32 2023 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Wed Nov 22 11:10:08 2023 +0100

    tdf#148000 impress: improve fontwork text placement.
    
    Improved the calculation of positions of text characters for multi-line 
texts.
    
    The previous version only fitted the text to the basic outline (curve), and 
then scale them to the appropriate text line.
    This means that the text will be wider or shorter, depending on the shape 
of the curve, and which line it is on
    
    Now it calculates a curve for each paragraph and fits text on it.
    Text will be approximately the same width on each line.
    Except if the text is wider as the curve. Because then it shrinks the text 
to fit on the curve. (this can only happens on inner curves)
    
    Reused the same compat flag that was used in bug148000, now it serves
    as a Powerpoint compatible mode for FontWork, so no need to create new
    compat flag every time FontWork has improve.
    
    That means that the Fontwork in old documents has remains the same
    
    Refactored horizontal/vertical alignment, but had to keep the old hacks
    as well.
    
    Note: if there are too many lines of text, and the vertical alignment 
causes internal curves, then curves can shrink to 0 length (center point of a 
circle) or even to negative length,
    These cases are impossible to display normally, so it will be glitchy
    similar to how it was before this patch.
    MS PowerPoint avoid these cases by not allowing vertical alignments that
    would result internal (smaller) curves.
    
    Added unittest to check legacy-odb / new-odp / pptx file.
    
    It change the display of fontwork, so in some cases it may feel like
    a regression.
    
    Change-Id: Iac2d9bc751bbc2b6f747c33958f969cb3543fae5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159776
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/include/svx/compatflags.hxx b/include/svx/compatflags.hxx
index f7d021f17bf7..9a64bd2bab80 100644
--- a/include/svx/compatflags.hxx
+++ b/include/svx/compatflags.hxx
@@ -11,7 +11,7 @@
 enum class SdrCompatibilityFlag
 {
     AnchoredTextOverflowLegacy, ///< for tdf#99729
-    LegacySingleLineFontwork, ///< for tdf#148000
+    LegacyFontwork, ///< for tdf#148000 false == Fontwork works in PowerPoint 
compat mode
     ConnectorUseSnapRect, ///< for tdf#149756
     IgnoreBreakAfterMultilineField, ///< for tdf#148966
 };
diff --git a/include/tools/poly.hxx b/include/tools/poly.hxx
index 77653d23bda7..24705f6c9e3c 100644
--- a/include/tools/poly.hxx
+++ b/include/tools/poly.hxx
@@ -114,6 +114,7 @@ public:
 
     void                SetSize( sal_uInt16 nNewSize );
     sal_uInt16          GetSize() const;
+    sal_uInt16          size() const { return GetSize(); } //for vector 
compability
 
     void                Clear();
 
diff --git a/oox/qa/unit/shape.cxx b/oox/qa/unit/shape.cxx
index 54ea52cce19c..d3a971cd58db 100644
--- a/oox/qa/unit/shape.cxx
+++ b/oox/qa/unit/shape.cxx
@@ -178,9 +178,9 @@ CPPUNIT_TEST_FIXTURE(OoxShapeTest, 
testTdf125582_TextOnCircle)
     {
         SdrObjCustomShape& rSdrCustomShape(
             
static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape)));
-        // Without the fix in place width was 3639, but should be 4824 for 
96dpi.
+        // Without the fix in place width was 3639, but should be 4784 for 
96dpi.
         tools::Rectangle aBoundRect(rSdrCustomShape.GetCurrentBoundRect());
-        CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(4824), aBoundRect.GetWidth(), 
5);
+        CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(4784), aBoundRect.GetWidth(), 
5);
     }
 
     drawing::TextVerticalAdjust eAdjust;
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
index c951814ce77f..77cf975166de 100644
--- a/sc/source/ui/docshell/docsh.cxx
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -612,7 +612,7 @@ bool ScDocShell::Load( SfxMedium& rMedium )
         {
             
pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy,
                                              true); // for tdf#99729
-            
pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacySingleLineFontwork,
+            
pDrawLayer->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork,
                                              true); // for tdf#148000
         }
     }
diff --git a/sd/qa/unit/export-tests-ooxml3.cxx 
b/sd/qa/unit/export-tests-ooxml3.cxx
index dbe68d2fcd7e..106073c47816 100644
--- a/sd/qa/unit/export-tests-ooxml3.cxx
+++ b/sd/qa/unit/export-tests-ooxml3.cxx
@@ -582,7 +582,7 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, 
testTdf125573_FontWorkScaleX)
     // BoundRect is DPI dependent, thus allow some range.
     // Expected width is 13139 in 96dpi and is 13106 in 120 dpi, for example
     // (Without fix Expected less than: 85 Actual  : 10432)
-    CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectArch.Width - 13139));
+    CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectArch.Width - 13145));
 
     // Error was, that text in shapes of category "Warp" was not scaled to the 
path.
     uno::Reference<beans::XPropertySet> xShapeWaveProps(getShapeFromPage(0, 
1));
diff --git a/sd/source/ui/docshell/docshel4.cxx 
b/sd/source/ui/docshell/docshel4.cxx
index 6b9d8993ada9..742614d101c1 100644
--- a/sd/source/ui/docshell/docshel4.cxx
+++ b/sd/source/ui/docshell/docshel4.cxx
@@ -270,7 +270,7 @@ bool DrawDocShell::Load( SfxMedium& rMedium )
     if (IsOwnStorageFormat(rMedium))
     {
         
mpDoc->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy, 
true); // for tdf#99729
-        
mpDoc->SetCompatibilityFlag(SdrCompatibilityFlag::LegacySingleLineFontwork, 
true); // for tdf#148000
+        mpDoc->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork, 
true); // for tdf#148000
     }
 
     bool       bRet = false;
diff --git a/svx/qa/unit/data/tdf148000_CurvedTextWidth.pptx 
b/svx/qa/unit/data/tdf148000_CurvedTextWidth.pptx
new file mode 100644
index 000000000000..be286cb1cea6
Binary files /dev/null and b/svx/qa/unit/data/tdf148000_CurvedTextWidth.pptx 
differ
diff --git a/svx/qa/unit/data/tdf148000_CurvedTextWidth_Legacy.odp 
b/svx/qa/unit/data/tdf148000_CurvedTextWidth_Legacy.odp
new file mode 100644
index 000000000000..24cf1593f133
Binary files /dev/null and 
b/svx/qa/unit/data/tdf148000_CurvedTextWidth_Legacy.odp differ
diff --git a/svx/qa/unit/data/tdf148000_CurvedTextWidth_New.odp 
b/svx/qa/unit/data/tdf148000_CurvedTextWidth_New.odp
new file mode 100644
index 000000000000..45b6ed0e1f16
Binary files /dev/null and b/svx/qa/unit/data/tdf148000_CurvedTextWidth_New.odp 
differ
diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx
index 8a6a39892b9d..2a7b7950c998 100644
--- a/svx/qa/unit/svdraw.cxx
+++ b/svx/qa/unit/svdraw.cxx
@@ -427,6 +427,45 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, 
testTdf148000_EOLinCurvedText)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(SvdrawTest, testTdf148000_CurvedTextEidth)
+{
+    std::vector<OUString> aFilenames
+        = { u"tdf148000_CurvedTextWidth.pptx"_ustr, 
u"tdf148000_CurvedTextWidth_New.odp"_ustr,
+            u"tdf148000_CurvedTextWidth_Legacy.odp"_ustr };
+
+    for (int i = 0; i < 3; i++)
+    {
+        loadFromURL(aFilenames[i]);
+
+        SdrPage* pSdrPage = getFirstDrawPageWithAssert();
+
+        xmlDocUniquePtr pXmlDoc = 
lcl_dumpAndParseFirstObjectWithAssert(pSdrPage);
+
+        OString aBasePath = 
"/primitive2D/objectinfo[4]/objectinfo/unhandled/unhandled/"
+                            "polypolygoncolor/polypolygon/"_ostr;
+
+        // The text is: 7 line od "OOOOOOO"
+        // Take the x coord of the 4 "O" on the corners
+        sal_Int32 nX1 = getXPath(pXmlDoc, aBasePath + "polygon[1]/point[1]", 
"x"_ostr).toInt32();
+        sal_Int32 nX2 = getXPath(pXmlDoc, aBasePath + "polygon[13]/point[1]", 
"x"_ostr).toInt32();
+        sal_Int32 nX3 = getXPath(pXmlDoc, aBasePath + "polygon[85]/point[1]", 
"x"_ostr).toInt32();
+        sal_Int32 nX4 = getXPath(pXmlDoc, aBasePath + "polygon[97]/point[1]", 
"x"_ostr).toInt32();
+
+        if (i < 2)
+        {
+            // All the lines should be positioned similar (start/end is 
similar)
+            CPPUNIT_ASSERT_LESS(sal_Int32(150), abs(nX3 - nX1));
+            CPPUNIT_ASSERT_LESS(sal_Int32(150), abs(nX4 - nX2));
+        }
+        else
+        {
+            // In legacy mode, the outer lines become much wider
+            CPPUNIT_ASSERT_GREATER(sal_Int32(1500), nX3 - nX1);
+            CPPUNIT_ASSERT_GREATER(sal_Int32(1500), nX2 - nX4);
+        }
+    }
+}
+
 CPPUNIT_TEST_FIXTURE(SvdrawTest, testSurfaceMetal)
 {
     loadFromURL(u"tdf140321_metal.odp");
diff --git a/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx 
b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
index 7d7ee4fdbc81..8f2896109e9e 100644
--- a/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
+++ b/svx/source/customshapes/EnhancedCustomShapeFontWork.cxx
@@ -75,6 +75,7 @@ struct FWTextArea                       // representing 
multiple concluding para
 {
     std::vector< FWParagraphData >      vParagraphs;
     tools::Rectangle                           aBoundRect;
+    sal_Int32                           nHAlignMove = 0;
 };
 struct FWData                           // representing the whole text
 {
@@ -135,7 +136,7 @@ static bool InitializeFontWorkData(
                 {
                     // search line break.
                     if 
(!rSdrObjCustomShape.getSdrModelFromSdrObject().GetCompatibilityFlag(
-                            SdrCompatibilityFlag::LegacySingleLineFontwork))
+                            SdrCompatibilityFlag::LegacyFontwork))
                         nPos = aParaText[nPara].indexOf(sal_Unicode(u'\1'), 
nPrevPos);
                     else
                         nPos = -1; // tdf#148000: ignore line breaks in legacy 
fontworks
@@ -570,6 +571,7 @@ static bool GetFontWorkOutline(
             {
                 sal_Int32 nHorzDiff = 0;
                 sal_Int32 nVertDiff = static_cast<double>( 
rFWData.nSingleLineHeight ) * fFactor * ( rTextArea.vParagraphs.size() - 1 );
+                rTextArea.nHAlignMove = nVertDiff;
 
                 if ( eHorzAdjust == SDRTEXTHORZADJUST_CENTER )
                     nHorzDiff = ( rFWData.fHorizontalTextScaling * 
rTextArea.aBoundRect.GetWidth() - rParagraph.aBoundRect.GetWidth() ) / 2;
@@ -721,10 +723,12 @@ static void InsertMissingOutlinePoints( const 
std::vector< double >& rDistances,
     }
 }
 
-static void GetPoint( const tools::Polygon& rPoly, const std::vector< double 
>& rDistances, const double& fX, double& fx1, double& fy1 )
+//only 2 types used: 'const tools::Polygon&' and 'const std::vector<Point>&'
+template <class T>
+static void GetPoint( T rPoly, const std::vector< double >& rDistances, const 
double& fX, double& fx1, double& fy1 )
 {
     fy1 = fx1 = 0.0;
-    if ( rPoly.GetSize() <= 1 )
+    if (rPoly.size() <= 1)
         return;
 
     std::vector< double >::const_iterator aIter = std::lower_bound( 
rDistances.begin(), rDistances.end(), fX );
@@ -749,7 +753,8 @@ static void GetPoint( const tools::Polygon& rPoly, const 
std::vector< double >&
     fy1 = rPt2.Y() + fHeight;
 }
 
-static void FitTextOutlinesToShapeOutlines( const tools::PolyPolygon& 
aOutlines2d, FWData& rFWData )
+static void FitTextOutlinesToShapeOutlines(const tools::PolyPolygon& 
aOutlines2d, FWData& rFWData,
+                                           SdrTextHorzAdjust eHorzAdjust, bool 
bPPFontwork)
 {
     sal_uInt16 nOutline2dIdx = 0;
     for( auto& rTextArea : rFWData.vTextAreas )
@@ -776,46 +781,242 @@ static void FitTextOutlinesToShapeOutlines( const 
tools::PolyPolygon& aOutlines2
                 std::vector< double > vDistances;
                 vDistances.reserve( nPointCount );
                 CalcDistances( rOutlinePoly, vDistances );
+
                 if ( !vDistances.empty() )
                 {
-                    for( auto& rParagraph : rTextArea.vParagraphs )
+                    // horizontal aligment: how much we have to move text to 
the right.
+                    int nAdjust = -1;
+                    switch (eHorzAdjust)
+                    {
+                        case SDRTEXTHORZADJUST_RIGHT:
+                            nAdjust = 2; // 2 half of the possible
+                            break;
+                        case SDRTEXTHORZADJUST_CENTER:
+                            nAdjust = 1; // 1 half of the possible
+                            break;
+                        case SDRTEXTHORZADJUST_BLOCK:
+                            nAdjust = -1; // don't know what it is, so dont 
even align
+                            break;
+                        case SDRTEXTHORZADJUST_LEFT:
+                            nAdjust = 0; // no need to move
+                            break;
+                    }
+
+                    if (bPPFontwork && rTextArea.vParagraphs.size() > 1 && 
nAdjust >= 0)
+                    {
+                        // If we have multiple lines of text to fit to the 
outline (curve)
+                        // then we have to be able to calculate outer versions 
of the outline
+                        // where we can fit the next lines of texts
+                        // those outer lines will be wider (or shorter) as the 
original outline
+                        // and probably will looks different as the original 
outline.
+                        //
+                        // for example if we have an outline like this:
+                        // <____>
+                        // then the middle part will have the same normals, so 
distances there,
+                        //  will not change for an outer outline
+                        // while the points near the edge will have different 
normals,
+                        //  distances around there will increase for an outer 
(wider) outline
+
+                        //Normal vectors for every rOutlinePoly point. 1024 
long
+                        std::vector<Point> vNorm;
+                        //wider curve path points, for current paragraph 
(rOutlinePoly + vNorm*line)
+                        std::vector<Point> vCurOutline;
+                        //distances between points of this wider curve
+                        std::vector<double> vCurDistances;
+
+                        vCurDistances.reserve(nPointCount);
+                        vCurOutline.reserve(nPointCount);
+                        vNorm.reserve(nPointCount);
+
+                        // Calculate Normal vectors, and allocate curve datas
+                        sal_uInt16 i;
+                        for (i = 0; i < nPointCount; i++)
+                        {
+                            //Normal vector for a point will be calculated 
from its neightbour points
+                            //except if is in the start/end of the vector
+                            sal_uInt16 nPointIdx1 = i == 0 ? i : i - 1;
+                            sal_uInt16 nPointIdx2 = i == nPointCount - 1 ? i : 
i + 1;
+
+                            Point aPoint = rOutlinePoly.GetPoint(nPointIdx2)
+                                           - rOutlinePoly.GetPoint(nPointIdx1);
+
+                            double fLen = sqrt(aPoint.X() * aPoint.X() + 
aPoint.Y() * aPoint.Y());
+
+                            if (fLen > 0)
+                            {
+                                //Rotate by 90 degree, and divide by length, 
to get normal vector
+                                vNorm.emplace_back(aPoint.getY() * 1024 / fLen,
+                                                   -aPoint.getX() * 1024 / 
fLen);
+                            }
+                            else
+                            {
+                                vNorm.emplace_back(0, 0);
+                            }
+                            vCurOutline.emplace_back(Point());
+                            vCurDistances.push_back(0);
+
+                        }
+
+                        for( auto& rParagraph : rTextArea.vParagraphs )
+                        {
+                            //calculate the actual outline length, and its 
align adjustments
+                            double fAdjust;
+                            double fCurWidth;
+
+                            // distance between the original an the current 
curve
+                            double fCurvesDist = 
rTextArea.aBoundRect.GetHeight() / 2.0
+                                                 + rTextArea.aBoundRect.Top()
+                                                 - 
rParagraph.aBoundRect.Center().Y();
+                            // verical alignment adjust
+                            fCurvesDist -= rTextArea.nHAlignMove;
+
+                            for (i = 0; i < nPointCount; i++)
+                            {
+                                vCurOutline[i]
+                                    = rOutlinePoly.GetPoint(i) + vNorm[i] * 
fCurvesDist / 1024.0;
+                                if (i > 0)
+                                {
+                                    //calculate distances between points on 
the outer outline
+                                    const double fDx = vCurOutline[i].X() - 
vCurOutline[i - 1].X();
+                                    const double fDy = vCurOutline[i].Y() - 
vCurOutline[i - 1].Y();
+                                    vCurDistances[i] = sqrt(fDx * fDx + fDy * 
fDy);
+                                }
+                                else
+                                    vCurDistances[i] = 0;
+                            }
+                            std::partial_sum(vCurDistances.begin(), 
vCurDistances.end(),
+                                             vCurDistances.begin());
+                            fCurWidth = vCurDistances[vCurDistances.size() - 
1];
+                            if (fCurWidth > 0.0)
+                            {
+                                for (auto& rDistance : vCurDistances)
+                                    rDistance /= fCurWidth;
+                            }
+
+                            // if the current outline is longer then the text 
to fit in,
+                            // then we have to divide the bonus space betweeen 
the
+                            // before-/after- text area.
+                            // fAdjust means how much space we put before the 
text.
+                            if (fCurWidth > rParagraph.aBoundRect.GetWidth())
+                            {
+                                fAdjust
+                                    = nAdjust * (fCurWidth - 
rParagraph.aBoundRect.GetWidth()) / 2;
+                            }
+                            else
+                                fAdjust = -1;   // we neet tho shrink the text 
to fit the curve
+
+                            for ( auto& rCharacter : rParagraph.vCharacters )
+                            {
+                                for (tools::PolyPolygon& rPolyPoly : 
rCharacter.vOutlines)
+                                {
+                                    tools::Rectangle 
aBoundRect(rPolyPoly.GetBoundRect());
+                                    double fx1 = aBoundRect.Left() - nLeft;
+                                    double fx2 = aBoundRect.Right() - nLeft;
+
+                                    double fParaRectWidth = 
rParagraph.aBoundRect.GetWidth();
+                                    // Undo Horizontal alignment, hacked into 
poly coords,
+                                    // so we can calculate it the right way
+                                    double fHA = 
(rFWData.fHorizontalTextScaling
+                                                      * 
rTextArea.aBoundRect.GetWidth()
+                                                  - 
rParagraph.aBoundRect.GetWidth())
+                                                 * nAdjust / 2;
+
+                                    fx1 -= fHA;
+                                    fx2 -= fHA;
+
+                                    double fy1, fy2;
+                                    double fM1 = fx1 / fParaRectWidth;
+                                    double fM2 = fx2 / fParaRectWidth;
+
+                                    // if fAdjust<0, then it means, the text 
was longer, as
+                                    // the current outline, so we will skip 
the text scaling, and
+                                    // the text horizontal alignment ajustment
+                                    // so the text will be rendered just as 
long as the cureve is.
+                                    if (fAdjust >= 0)
+                                    {
+                                        fM1 = (fM1 * fParaRectWidth + fAdjust) 
/ fCurWidth;
+                                        fM2 = (fM2 * fParaRectWidth + fAdjust) 
/ fCurWidth;
+                                    }
+                                    // 0 <= fM1,fM2 <= 1 should be true, but 
rounding errors can
+                                    // make a small mistake.
+                                    // make sure they are >0 becuase 
GetPoint() need that
+                                    if (fM1 < 0) fM1 = 0;
+                                    if (fM2 < 0) fM2 = 0;
+
+                                    GetPoint(vCurOutline, vCurDistances, fM1, 
fx1, fy1);
+                                    GetPoint(vCurOutline, vCurDistances, fM2, 
fx2, fy2);
+
+                                    double fvx = fy2 - fy1;
+                                    double fvy = - ( fx2 - fx1 );
+                                    fx1 = fx1 + ( ( fx2 - fx1 ) * 0.5 );
+                                    fy1 = fy1 + ( ( fy2 - fy1 ) * 0.5 );
+
+                                    double fAngle = atan2( -fvx, -fvy );
+                                    double fL = hypot( fvx, fvy );
+                                    if (fL == 0.0)
+                                    {
+                                        SAL_WARN("svx", 
"FitTextOutlinesToShapeOutlines div-by-zero, abandon fit");
+                                        break;
+                                    }
+                                    fvx = fvx / fL;
+                                    fvy = fvy / fL;
+                                    // Undo Vertical alignment hacked into 
poly coords
+                                    // We already calculated the right 
alignment into the curve
+                                    fL = rTextArea.nHAlignMove;
+                                    fvx *= fL;
+                                    fvy *= fL;
+                                    rPolyPoly.Rotate( Point( 
aBoundRect.Center().X(), rParagraph.aBoundRect.Center().Y() ), sin( fAngle ), 
cos( fAngle ) );
+                                    rPolyPoly.Move( static_cast<sal_Int32>( ( 
fx1 + fvx )- aBoundRect.Center().X() ), static_cast<sal_Int32>( ( fy1 + fvy ) - 
rParagraph.aBoundRect.Center().Y() ) );
+                                }
+                            }
+                        }
+                    }
+                    else
                     {
-                        for ( auto& rCharacter : rParagraph.vCharacters )
+                        // Fallback / old way to handle multiple lines:
+                        // Every text lines use the same original outline 
(curve),
+                        // it just scale character coordinates to fit to the 
right text line
+                        // (curve), resulting wider/thinner space between 
characters
+                        for (auto& rParagraph : rTextArea.vParagraphs)
                         {
-                            for( tools::PolyPolygon& rPolyPoly : 
rCharacter.vOutlines )
+                            for (auto& rCharacter : rParagraph.vCharacters)
                             {
-                                tools::Rectangle aBoundRect( 
rPolyPoly.GetBoundRect() );
-                                double fx1 = aBoundRect.Left() - nLeft;
-                                double fx2 = aBoundRect.Right() - nLeft;
-                                double fy1, fy2;
-                                double fM1 = fx1 / static_cast<double>(nWidth);
-                                double fM2 = fx2 / static_cast<double>(nWidth);
-
-                                GetPoint( rOutlinePoly, vDistances, fM1, fx1, 
fy1 );
-                                GetPoint( rOutlinePoly, vDistances, fM2, fx2, 
fy2 );
-
-                                double fvx = fy2 - fy1;
-                                double fvy = - ( fx2 - fx1 );
-                                fx1 = fx1 + ( ( fx2 - fx1 ) * 0.5 );
-                                fy1 = fy1 + ( ( fy2 - fy1 ) * 0.5 );
-
-                                double fAngle = atan2( -fvx, -fvy );
-                                double fL = hypot( fvx, fvy );
-                                if (fL == 0.0)
+                                for (tools::PolyPolygon& rPolyPoly : 
rCharacter.vOutlines)
                                 {
-                                    SAL_WARN("svx", 
"FitTextOutlinesToShapeOutlines div-by-zero, abandon fit");
-                                    break;
+                                    tools::Rectangle 
aBoundRect(rPolyPoly.GetBoundRect());
+                                    double fx1 = aBoundRect.Left() - nLeft;
+                                    double fx2 = aBoundRect.Right() - nLeft;
+                                    double fy1, fy2;
+                                    double fM1 = fx1 / 
static_cast<double>(nWidth);
+                                    double fM2 = fx2 / 
static_cast<double>(nWidth);
+
+                                    GetPoint(rOutlinePoly, vDistances, fM1, 
fx1, fy1);
+                                    GetPoint(rOutlinePoly, vDistances, fM2, 
fx2, fy2);
+
+                                    double fvx = fy2 - fy1;
+                                    double fvy = -(fx2 - fx1);
+                                    fx1 = fx1 + ((fx2 - fx1) * 0.5);
+                                    fy1 = fy1 + ((fy2 - fy1) * 0.5);
+
+                                    double fAngle = atan2(-fvx, -fvy);
+                                    double fL = hypot(fvx, fvy);
+                                    if (fL == 0.0)
+                                    {
+                                        SAL_WARN("svx", 
"FitTextOutlinesToShapeOutlines div-by-zero, abandon fit");
+                                        break;
+                                    }
+                                    fvx = fvx / fL;
+                                    fvy = fvy / fL;
+                                    fL = rTextArea.aBoundRect.GetHeight() / 
2.0 + rTextArea.aBoundRect.Top() - rParagraph.aBoundRect.Center().Y();
+                                    fvx *= fL;
+                                    fvy *= fL;
+                                    rPolyPoly.Rotate( Point( 
aBoundRect.Center().X(), rParagraph.aBoundRect.Center().Y() ), sin( fAngle ), 
cos( fAngle ) );
+                                    rPolyPoly.Move( static_cast<sal_Int32>( ( 
fx1 + fvx )- aBoundRect.Center().X() ), static_cast<sal_Int32>( ( fy1 + fvy ) - 
rParagraph.aBoundRect.Center().Y() ) );
                                 }
-                                fvx = fvx / fL;
-                                fvy = fvy / fL;
-                                fL = rTextArea.aBoundRect.GetHeight() / 2.0 + 
rTextArea.aBoundRect.Top() - rParagraph.aBoundRect.Center().Y();
-                                fvx *= fL;
-                                fvy *= fL;
-                                rPolyPoly.Rotate( Point( 
aBoundRect.Center().X(), rParagraph.aBoundRect.Center().Y() ), sin( fAngle ), 
cos( fAngle ) );
-                                rPolyPoly.Move( static_cast<sal_Int32>( ( fx1 
+ fvx )- aBoundRect.Center().X() ), static_cast<sal_Int32>( ( fy1 + fvy ) - 
rParagraph.aBoundRect.Center().Y() ) );
                             }
                         }
                     }
+
                 }
             }
         }
@@ -973,7 +1174,11 @@ rtl::Reference<SdrObject> 
EnhancedCustomShapeFontWork::CreateFontWork(
                 return nullptr;
             }
 
-            FitTextOutlinesToShapeOutlines( aOutlines2d, aFWData );
+            SdrTextHorzAdjust eHorzAdjust(
+                
rSdrObjCustomShape.GetMergedItem(SDRATTR_TEXT_HORZADJUST).GetValue());
+            bool bPPFontwork = 
!rSdrObjCustomShape.getSdrModelFromSdrObject().GetCompatibilityFlag(
+                              SdrCompatibilityFlag::LegacyFontwork);
+            FitTextOutlinesToShapeOutlines( aOutlines2d, aFWData, eHorzAdjust, 
bPPFontwork );
 
             pRet = CreateSdrObjectFromParagraphOutlines(
                 aFWData,
diff --git a/svx/source/svdraw/svdmodel.cxx b/svx/source/svdraw/svdmodel.cxx
index ba57b71c685b..90fc769e20b7 100644
--- a/svx/source/svdraw/svdmodel.cxx
+++ b/svx/source/svdraw/svdmodel.cxx
@@ -86,7 +86,7 @@ struct SdrModelImpl
     SfxUndoManager* mpUndoManager;
     SdrUndoFactory* mpUndoFactory;
     bool mbAnchoredTextOverflowLegacy; // tdf#99729 compatibility flag
-    bool mbLegacySingleLineFontwork;   // tdf#148000 compatibility flag
+    bool mbLegacyFontwork;             // tdf#148000 compatibility flag
     bool mbConnectorUseSnapRect;       // tdf#149756 compatibility flag
     bool mbIgnoreBreakAfterMultilineField; ///< tdf#148966 compatibility flag
     std::shared_ptr<model::Theme> mpTheme;
@@ -96,7 +96,7 @@ struct SdrModelImpl
         : mpUndoManager(nullptr)
         , mpUndoFactory(nullptr)
         , mbAnchoredTextOverflowLegacy(false)
-        , mbLegacySingleLineFontwork(false)
+        , mbLegacyFontwork(false)
         , mbConnectorUseSnapRect(false)
         , mbIgnoreBreakAfterMultilineField(false)
         , mpTheme(new model::Theme("Office"))
@@ -1724,8 +1724,8 @@ void SdrModel::SetCompatibilityFlag(SdrCompatibilityFlag 
eFlag, bool bEnabled)
         case SdrCompatibilityFlag::AnchoredTextOverflowLegacy:
             mpImpl->mbAnchoredTextOverflowLegacy = bEnabled;
             break;
-        case SdrCompatibilityFlag::LegacySingleLineFontwork:
-            mpImpl->mbLegacySingleLineFontwork = bEnabled;
+        case SdrCompatibilityFlag::LegacyFontwork:
+            mpImpl->mbLegacyFontwork = bEnabled;
             break;
         case SdrCompatibilityFlag::ConnectorUseSnapRect:
             mpImpl->mbConnectorUseSnapRect = bEnabled;
@@ -1742,8 +1742,8 @@ bool SdrModel::GetCompatibilityFlag(SdrCompatibilityFlag 
eFlag) const
     {
         case SdrCompatibilityFlag::AnchoredTextOverflowLegacy:
             return mpImpl->mbAnchoredTextOverflowLegacy;
-        case SdrCompatibilityFlag::LegacySingleLineFontwork:
-            return mpImpl->mbLegacySingleLineFontwork;
+        case SdrCompatibilityFlag::LegacyFontwork:
+            return mpImpl->mbLegacyFontwork;
         case SdrCompatibilityFlag::ConnectorUseSnapRect:
             return mpImpl->mbConnectorUseSnapRect;
         case SdrCompatibilityFlag::IgnoreBreakAfterMultilineField:
@@ -1807,9 +1807,9 @@ void SdrModel::ReadUserDataSequenceValue(const 
beans::PropertyValue* pValue)
     else if (pValue->Name == "LegacySingleLineFontwork")
     {
         bool bBool = false;
-        if (pValue->Value >>= bBool)
+        if ((pValue->Value >>= bBool) && mpImpl->mbLegacyFontwork != bBool)
         {
-            mpImpl->mbLegacySingleLineFontwork = bBool;
+            mpImpl->mbLegacyFontwork = bBool;
             // tdf#148000 hack: reset all CustomShape geometry as they may 
depend on this property
             // Ideally this ReadUserDataSequenceValue should be called before 
geometry creation
             // Once the calling order will be fixed, this hack will not be 
needed.
@@ -1845,7 +1845,7 @@ void SdrModel::WriteUserDataSequence(uno::Sequence 
<beans::PropertyValue>& rValu
     std::vector< std::pair< OUString, uno::Any > > aUserData
     {
         { "AnchoredTextOverflowLegacy", 
uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy))
 },
-        { "LegacySingleLineFontwork", 
uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::LegacySingleLineFontwork)) 
},
+        { "LegacySingleLineFontwork", 
uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork)) },
         { "ConnectorUseSnapRect", 
uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::ConnectorUseSnapRect)) },
         { "IgnoreBreakAfterMultilineField", 
uno::Any(GetCompatibilityFlag(SdrCompatibilityFlag::IgnoreBreakAfterMultilineField))
 }
     };
diff --git a/sw/source/uibase/app/docshini.cxx 
b/sw/source/uibase/app/docshini.cxx
index 6d3cf42a7858..5acee759dba2 100644
--- a/sw/source/uibase/app/docshini.cxx
+++ b/sw/source/uibase/app/docshini.cxx
@@ -482,7 +482,7 @@ bool  SwDocShell::Load( SfxMedium& rMedium )
             {
                 
pDrawModel->SetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy,
                                                  true); // legacy processing 
for tdf#99729
-                
pDrawModel->SetCompatibilityFlag(SdrCompatibilityFlag::LegacySingleLineFontwork,
+                
pDrawModel->SetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork,
                                                  true); // legacy processing 
for tdf#148000
             }
         }

Reply via email to