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 3d7dad88c409fecd3ba4a3f27f8e2e6e2e5f14d7 Author: Attila Szűcs <attila.sz...@collabora.com> AuthorDate: Wed Nov 15 07:04:32 2023 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Sun Nov 26 15:07:35 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. Squashed a lot of typo fix commits by Andrea Gelmini. 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> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159975 Tested-by: Jenkins Reviewed-by: Andras Timar <andras.ti...@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 d9f2a4544901..fd653ec724b7 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 compatibility void Clear(); diff --git a/oox/qa/unit/shape.cxx b/oox/qa/unit/shape.cxx index 4db45f7451be..d2475095e716 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 16cb0655c94f..7c9d67636c67 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -619,7 +619,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 3d630db22aa3..6a66e59af884 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -573,7 +573,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 aeee4709208a..74c70579bde7 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 d61dde7734cd..15d526fdeb37 100644 --- a/svx/qa/unit/svdraw.cxx +++ b/svx/qa/unit/svdraw.cxx @@ -426,6 +426,45 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testTdf148000_EOLinCurvedText) } } +CPPUNIT_TEST_FIXTURE(SvdrawTest, testTdf148000_CurvedTextWidth) +{ + std::vector<OUString> aFilenames + = { u"tdf148000_CurvedTextWidth.pptx", u"tdf148000_CurvedTextWidth_New.odp", + u"tdf148000_CurvedTextWidth_Legacy.odp" }; + + 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/"; + + // 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").toInt32(); + sal_Int32 nX2 = getXPath(pXmlDoc, aBasePath + "polygon[13]/point[1]", "x").toInt32(); + sal_Int32 nX3 = getXPath(pXmlDoc, aBasePath + "polygon[85]/point[1]", "x").toInt32(); + sal_Int32 nX4 = getXPath(pXmlDoc, aBasePath + "polygon[97]/point[1]", "x").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..2e19aa344ec4 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 alignment: 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 don't 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 data + sal_uInt16 i; + for (i = 0; i < nPointCount; i++) + { + //Normal vector for a point will be calculated from its neighbour points + //except if it 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 and the current curve + double fCurvesDist = rTextArea.aBoundRect.GetHeight() / 2.0 + + rTextArea.aBoundRect.Top() + - rParagraph.aBoundRect.Center().Y(); + // vertical 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 between 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 need to 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 adjustment + // so the text will be rendered just as long as the curve 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 because 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 4e1ea3c78ac5..d25d9b47d7f4 100644 --- a/svx/source/svdraw/svdmodel.cxx +++ b/svx/source/svdraw/svdmodel.cxx @@ -85,7 +85,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; @@ -94,7 +94,7 @@ struct SdrModelImpl : mpUndoManager(nullptr) , mpUndoFactory(nullptr) , mbAnchoredTextOverflowLegacy(false) - , mbLegacySingleLineFontwork(false) + , mbLegacyFontwork(false) , mbConnectorUseSnapRect(false) , mbIgnoreBreakAfterMultilineField(false) , mpTheme(new model::Theme("Office")) @@ -1718,8 +1718,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; @@ -1736,8 +1736,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: @@ -1801,9 +1801,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. @@ -1839,7 +1839,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 7407de9ef6f5..9643c5a3c878 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 } }