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 <Armin.Le.Grand@me.com>
This commit is contained in:
Armin Le Grand (allotropia)
2022-10-31 10:01:46 +01:00
committed by Armin Le Grand
parent d3caee0a7a
commit 604f6fc8fe
3 changed files with 53 additions and 22 deletions
+1 -1
View File
@@ -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
*/
+12 -2
View File
@@ -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 );
}
}
+40 -19
View File
@@ -29,6 +29,7 @@
#include <svx/sdr/primitive2d/sdrframeborderprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <basegfx/polygon/b2dpolygonclipper.hxx>
// #include <basegfx/numeric/ftools.hxx>
//#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;
}
}
}