include/svx/compatflags.hxx | 2 include/tools/poly.hxx | 1 oox/qa/unit/shape.cxx | 2 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, 295 insertions(+), 50 deletions(-)
New commits: commit 202f2d6f6529a8fe5a12dded879bafb546d9add3 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: Thu Nov 23 10:02:19 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/+/159428 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> 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 d9f2a4544901..dff37a51b436 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 c0bae9cbb536..64730eedd4ca 100644 --- a/oox/qa/unit/shape.cxx +++ b/oox/qa/unit/shape.cxx @@ -166,7 +166,7 @@ CPPUNIT_TEST_FIXTURE(OoxShapeTest, testTdf125582_TextOnCircle) static_cast<SdrObjCustomShape&>(*SdrObject::getSdrObjectFromXShape(xShape))); // Without the fix in place width was 3639, but should be 4824 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 41035532cb27..a0d45efd23a6 100644 --- a/sc/source/ui/docshell/docsh.cxx +++ b/sc/source/ui/docshell/docsh.cxx @@ -613,7 +613,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 e827e4d96805..0c9ab10203e0 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -769,7 +769,7 @@ void SdOOXMLExportTest3::testTdf125573_FontWorkScaleX() xShapeArchProps->getPropertyValue(UNO_NAME_MISC_OBJ_BOUNDRECT) >>= aBoundRectArch; // BoundRect is DPI dependent, thus allow some range. // (Without fix Expected less than: 85 Actual : 10432) - CPPUNIT_ASSERT_LESS(sal_Int32(85), std::abs(aBoundRectArch.Width - 13038)); + 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 dea4c4595681..ff099387cb00 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 7dbd96b04f67..bc73141d8107 100644 --- a/svx/qa/unit/svdraw.cxx +++ b/svx/qa/unit/svdraw.cxx @@ -424,6 +424,45 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testTdf148000_EOLinCurvedText) } } +CPPUNIT_TEST_FIXTURE(SvdrawTest, testTdf148000_CurvedTextEidth) +{ + 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]/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[6*14+1]/point[1]", "x").toInt32(); + sal_Int32 nX4 = getXPath(pXmlDoc, aBasePath + "polygon[6*14+13]/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 648e5cfa56f3..4ca1bf17bd1e 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 @@ -567,6 +568,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; @@ -718,10 +720,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 ); @@ -746,7 +750,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 ) @@ -773,46 +778,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() ) ); } } } + } } } @@ -970,7 +1171,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 5c5d73d79a74..476594401021 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")) @@ -1747,8 +1747,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; @@ -1765,8 +1765,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: @@ -1830,9 +1830,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. @@ -1875,7 +1875,7 @@ void SdrModel::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rValu addPair(aUserData, "AnchoredTextOverflowLegacy", GetCompatibilityFlag(SdrCompatibilityFlag::AnchoredTextOverflowLegacy)); addPair(aUserData, "LegacySingleLineFontwork", - GetCompatibilityFlag(SdrCompatibilityFlag::LegacySingleLineFontwork)); + GetCompatibilityFlag(SdrCompatibilityFlag::LegacyFontwork)); addPair(aUserData, "ConnectorUseSnapRect", GetCompatibilityFlag(SdrCompatibilityFlag::ConnectorUseSnapRect)); addPair(aUserData, "IgnoreBreakAfterMultilineField", diff --git a/sw/source/uibase/app/docshini.cxx b/sw/source/uibase/app/docshini.cxx index 5c629ebd3d54..7ae315d92a62 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 } }