From 604f6fc8fe7438f7cfbcfc8a3107ace59e950627 Mon Sep 17 00:00:00 2001 From: "Armin Le Grand (allotropia)" Date: Fri, 28 Oct 2022 17:54:32 +0200 Subject: [PATCH] tdf#143377 Correct maximum Skew for TextOrientation in Calc For zero or 180 degree text orinentation errors can happen in the Border visualization, theoretically also in the Text rendering. Ths has to do with sin(0) and sin(180) being zero and lead internal to numerical problems, e.g. a very huge Skew that when applied show the reported 'errors'. I limit this mechanism now to +/- 1/2 degree from the critical mentioned places, for Border and Text - to not risk to have different points of corrections. The UI only allows angles of 1 degree steps, but UNO API and pdf import may allow more. Change-Id: Idbc68f6a7beab84df0672165c2a813d96eeff84e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/141999 Tested-by: Jenkins Reviewed-by: Armin Le Grand --- include/basegfx/numeric/ftools.hxx | 2 +- sc/source/ui/view/output2.cxx | 14 ++++++- svx/source/dialog/framelinkarray.cxx | 59 +++++++++++++++++++--------- 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/include/basegfx/numeric/ftools.hxx b/include/basegfx/numeric/ftools.hxx index 4f1bc1680000..1e7f0a34e71c 100644 --- a/include/basegfx/numeric/ftools.hxx +++ b/include/basegfx/numeric/ftools.hxx @@ -109,7 +109,7 @@ namespace basegfx /** Snap v to the range [0.0 .. fWidth] using modulo */ - double snapToZeroRange(double v, double fWidth); + BASEGFX_DLLPUBLIC double snapToZeroRange(double v, double fWidth); /** Snap v to the range [fLow .. fHigh] using modulo */ diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx index a7efd3dbb088..abee5a2e8756 100644 --- a/sc/source/ui/view/output2.cxx +++ b/sc/source/ui/view/output2.cxx @@ -4689,15 +4689,25 @@ void ScOutputData::DrawRotated(bool bPixelToLogic) { eRotMode = pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue(); - if ( nAttrRotate == 18000_deg100 ) + // tdf#143377 To use the same limits to avoid too big Skew + // with TextOrientation in Calc, use 1/2 degree here, too. + // This equals '50' in the notation here + const bool bForbidSkew( + nAttrRotate < Degree100(50) || // range [0..50] + nAttrRotate > Degree100(36000 - 50) || // range [35950..36000[ + (nAttrRotate > Degree100(18000 - 50) && (nAttrRotate < Degree100(18000 + 50)))); // range 50 around 18000 + + if ( bForbidSkew ) + { eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow + } if ( bLayoutRTL ) nAttrRotate = -nAttrRotate; double nRealOrient = toRadians(nAttrRotate); // 1/100 degree nCos = cos( nRealOrient ); - nSin = sin( nRealOrient ); + nSin = bForbidSkew ? 0 : sin( nRealOrient ); } } diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx index aabce64ba78e..755b86e59f28 100644 --- a/svx/source/dialog/framelinkarray.cxx +++ b/svx/source/dialog/framelinkarray.cxx @@ -29,6 +29,7 @@ #include #include #include +// #include //#define OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL #ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL @@ -110,27 +111,47 @@ basegfx::B2DHomMatrix Cell::HelperCreateB2DHomMatrixFromB2DRange( if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode ) { - // when rotated, adapt values. Get Skew (cos/sin == 1/tan) - const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation))); + // tdf#143377 We need to limit applying Skew to geometry since the closer + // we get to 0.0 or PI the more sin(mfOrientation) will get to zero and the + // huger the Skew effect will be. For that, use an epsilon-radius of 1/2 + // degree around the dangerous points 0.0 and PI. - switch (meRotMode) + // Snap to modulo to [0.0 .. 2PI[ to make compare easier + const double fSnapped(::basegfx::snapToZeroRange(mfOrientation, M_PI * 2.0)); + + // As a compromize, allow up to 1/2 degree + static const double fMinAng(M_PI/360.0); + + // Check if Skew makes sense or would be too huge + const bool bForbidSkew( + fSnapped < fMinAng || // range [0.0 .. fMinAng] + fSnapped > (M_PI * 2.0) - fMinAng || // range [PI-fMinAng .. 2PI[ + fabs(fSnapped - M_PI) < fMinAng); // range [PI-fMinAng .. PI+fMinAng] + + if(!bForbidSkew) { - case SvxRotateMode::SVX_ROTATE_MODE_TOP: - // shear Y-Axis - aY.setX(-fSkew); - break; - case SvxRotateMode::SVX_ROTATE_MODE_CENTER: - // shear origin half, Y full - aOrigin.setX(aOrigin.getX() + (fSkew * 0.5)); - aY.setX(-fSkew); - break; - case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM: - // shear origin full, Y full - aOrigin.setX(aOrigin.getX() + fSkew); - aY.setX(-fSkew); - break; - default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above - break; + // when rotated, adapt values. Get Skew (cos/sin == 1/tan) + const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation))); + + switch (meRotMode) + { + case SvxRotateMode::SVX_ROTATE_MODE_TOP: + // shear Y-Axis + aY.setX(-fSkew); + break; + case SvxRotateMode::SVX_ROTATE_MODE_CENTER: + // shear origin half, Y full + aOrigin.setX(aOrigin.getX() + (fSkew * 0.5)); + aY.setX(-fSkew); + break; + case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM: + // shear origin full, Y full + aOrigin.setX(aOrigin.getX() + fSkew); + aY.setX(-fSkew); + break; + default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above + break; + } } }