summaryrefslogtreecommitdiff
path: root/svx
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2023-03-23 11:24:30 +0900
committerTomaž Vajngerl <quikee@gmail.com>2023-04-07 12:35:28 +0200
commit81ff712657dba53376c94c9bb266e7c838ef40e2 (patch)
tree4398a1cbb46fd321353c4d520a14cf7d4c1cc94d /svx
parentbaf9a9b40d6fbe62fbe1c024c5d808631432da84 (diff)
tdf#90407 Change the auto-fit alg. to match better with OOXML
The auto-fit algorithm has been tweaked to be more in-line with the expectations of OOXML. This means a couple of changes to what properties are scaled by the algorithm have been made: - most properties that influence the X axis position or size (for example indent) are not scaled down or changed by scaling. - properties that influence y axis position and size are scaled by a separate parameter (like in the OOXML). This is used in the auto-fit algorithm in a different way. - if line spacing is proportional, it is now scaled with the spacing parameter. Fixed line spacing doesn't get scaled. - the main scaling X,Y parameter only scales the fonts. - trying hard to scale the fonts to the nearest pt (point) value With this change the scaling is much more stable than it was before - for example it doesn't matter what the unscaled font size is, when it is scaled down to the text box size, it (should) always look the same (for example scaling from 32pt -> 10pt or 64pt -> 10pt or even 999pt -> 10pt). The algorithm is also rewritten to be better at finding a fit and is also better at find a good fit, but it can take more iterations by doing so (there are ways to improve it however). Previous algorithm used a linear search to converge to the best fit in less iterations, but the issue with that was that it could in some cases miss a solution (especially since change to floating point scaling parameter). The new algorithm now uses a binary search - always trying the middle of the search space. OOXML export and import was also changed to take advantage of the font scaling and spacing scaling parameters. The additional scaling at export that was needed to have consistent OOXML support was removed. Change-Id: I8f3bb8d43a01931f18bd7ffdf8e0ba40caa73d8b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149207 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149934 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Diffstat (limited to 'svx')
-rw-r--r--svx/source/svdraw/svdotext.cxx137
-rw-r--r--svx/source/svdraw/svdotextdecomposition.cxx2
-rw-r--r--svx/source/svdraw/svdoutl.cxx2
-rw-r--r--svx/source/unodraw/unoshape.cxx9
4 files changed, 132 insertions, 18 deletions
diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx
index 99249b788c75..d9a80a9cfb0b 100644
--- a/svx/source/svdraw/svdotext.cxx
+++ b/svx/source/svdraw/svdotext.cxx
@@ -51,7 +51,11 @@
#include <vcl/virdev.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <sal/log.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <o3tl/temporary.hxx>
+#include <unotools/configmgr.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/fhgtitem.hxx>
using namespace com::sun::star;
@@ -922,6 +926,9 @@ void SdrTextObj::ImpSetCharStretching(SdrOutliner& rOutliner, const Size& rTextS
}
#endif
}
+
+ rOutliner.setRoundFontSizeToPt(false);
+
unsigned nLoopCount=0;
bool bNoMoreLoop = false;
tools::Long nXDiff0=0x7FFFFFFF;
@@ -996,7 +1003,7 @@ void SdrTextObj::ImpSetCharStretching(SdrOutliner& rOutliner, const Size& rTextS
nY = nX;
bNoMoreLoop = true;
}
- rOutliner.SetGlobalCharStretching(nX, nY);
+ rOutliner.setGlobalScale(nX, nY);
nLoopCount++;
Size aSiz(rOutliner.CalcTextSize());
tools::Long nXDiff = aSiz.Width() - nWantWdt;
@@ -1181,7 +1188,8 @@ void SdrTextObj::ImpInitDrawOutliner( SdrOutliner& rOutl ) const
nOutlinerMode = OutlinerMode::TextObject;
rOutl.Init( nOutlinerMode );
- rOutl.SetGlobalCharStretching(100.0, 100.0);
+ rOutl.setGlobalScale(100.0, 100.0, 100.0, 100.0);
+
EEControlBits nStat=rOutl.GetControlWord();
nStat &= ~EEControlBits(EEControlBits::STRETCHING|EEControlBits::AUTOPAGESIZE);
rOutl.SetControlWord(nStat);
@@ -1239,15 +1247,26 @@ void SdrTextObj::ImpSetupDrawOutlinerForPaint( bool bContourFrame,
}
}
-sal_uInt16 SdrTextObj::GetFontScaleY() const
+double SdrTextObj::GetFontScale() const
{
SdrOutliner& rOutliner = ImpGetDrawOutliner();
// This eventually calls ImpAutoFitText
UpdateOutlinerFormatting(rOutliner, o3tl::temporary(tools::Rectangle()));
- double nStretchY;
- rOutliner.GetGlobalCharStretching(o3tl::temporary(double()), nStretchY);
- return nStretchY;
+ double fScaleY;
+ rOutliner.getGlobalScale(o3tl::temporary(double()), fScaleY, o3tl::temporary(double()), o3tl::temporary(double()));
+ return fScaleY;
+}
+
+double SdrTextObj::GetSpacingScale() const
+{
+ SdrOutliner& rOutliner = ImpGetDrawOutliner();
+ // This eventually calls ImpAutoFitText
+ UpdateOutlinerFormatting(rOutliner, o3tl::temporary(tools::Rectangle()));
+
+ double fSpacingScaleY;
+ rOutliner.getGlobalScale(o3tl::temporary(double()), o3tl::temporary(double()), o3tl::temporary(double()), fSpacingScaleY);
+ return fSpacingScaleY;
}
void SdrTextObj::ImpAutoFitText( SdrOutliner& rOutliner ) const
@@ -1262,6 +1281,12 @@ void SdrTextObj::ImpAutoFitText( SdrOutliner& rOutliner ) const
void SdrTextObj::ImpAutoFitText(SdrOutliner& rOutliner, const Size& rTextSize,
bool bIsVerticalWriting) const
{
+ if (!bIsVerticalWriting)
+ {
+ autoFitTextForCompatibility(rOutliner, rTextSize);
+ return;
+ }
+
// EditEngine formatting is unstable enough for
// line-breaking text that we need some more samples
@@ -1269,6 +1294,7 @@ void SdrTextObj::ImpAutoFitText(SdrOutliner& rOutliner, const Size& rTextSize,
double nMinStretchX = 0.0;
double nMinStretchY = 0.0;
std::array<sal_Int32, 10> aOldStretchXVals = {0,0,0,0,0,0,0,0,0,0};
+ rOutliner.setRoundFontSizeToPt(false);
for (size_t i = 0; i < aOldStretchXVals.size(); ++i)
{
const Size aCurrTextSize = rOutliner.CalcTextSizeNTP();
@@ -1292,7 +1318,7 @@ void SdrTextObj::ImpAutoFitText(SdrOutliner& rOutliner, const Size& rTextSize,
fFactor = std::sqrt(fFactor);
double nCurrStretchX, nCurrStretchY;
- rOutliner.GetGlobalCharStretching(nCurrStretchX, nCurrStretchY);
+ rOutliner.getGlobalScale(nCurrStretchX, nCurrStretchY, o3tl::temporary(double()), o3tl::temporary(double()));
if (fFactor >= 0.98)
{
@@ -1311,20 +1337,107 @@ void SdrTextObj::ImpAutoFitText(SdrOutliner& rOutliner, const Size& rTextSize,
nCurrStretchX = double(basegfx::fround(nCurrStretchX * fFactor * 100.0)) / 100.00;
nCurrStretchY = double(basegfx::fround(nCurrStretchY * fFactor * 100.0)) / 100.00;
- rOutliner.SetGlobalCharStretching(std::min(100.0, nCurrStretchX), std::min(100.0, nCurrStretchY));
+ double nStretchX = std::min(100.0, nCurrStretchX);
+ double nStretchY = std::min(100.0, nCurrStretchY);
+
+ rOutliner.setGlobalScale(nStretchX, nStretchY, nStretchX, nStretchY);
SAL_INFO("svx", "zoom is " << nCurrStretchX);
}
}
const SdrTextFitToSizeTypeItem& rItem = GetObjectItem(SDRATTR_TEXT_FITTOSIZE);
- if (rItem.GetMaxScale() > 0)
+ if (rItem.GetMaxScale() > 0.0)
{
- nMinStretchX = std::min<sal_uInt16>(rItem.GetMaxScale(), nMinStretchX);
- nMinStretchY = std::min<sal_uInt16>(rItem.GetMaxScale(), nMinStretchY);
+ nMinStretchX = std::min(rItem.GetMaxScale(), nMinStretchX);
+ nMinStretchY = std::min(rItem.GetMaxScale(), nMinStretchY);
}
SAL_INFO("svx", "final zoom is " << nMinStretchX);
- rOutliner.SetGlobalCharStretching(std::min(100.0, nMinStretchX), std::min(100.0, nMinStretchY));
+
+ nMinStretchX = std::min(100.0, nMinStretchX);
+ nMinStretchY = std::min(100.0, nMinStretchY);
+
+ rOutliner.setGlobalScale(nMinStretchX, nMinStretchY, nMinStretchX, nMinStretchY);
+}
+
+void SdrTextObj::autoFitTextForCompatibility(SdrOutliner& rOutliner, const Size& rTextBoxSize) const
+{
+ rOutliner.setRoundFontSizeToPt(true);
+
+ const SdrTextFitToSizeTypeItem& rItem = GetObjectItem(SDRATTR_TEXT_FITTOSIZE);
+ double fMaxScale = rItem.GetMaxScale();
+ if (fMaxScale > 0.0)
+ {
+ rOutliner.setGlobalScale(fMaxScale, fMaxScale, 100.0, 100.0);
+ }
+ else
+ {
+ fMaxScale = 100.0;
+ }
+
+ Size aCurrentTextBoxSize = rOutliner.CalcTextSizeNTP();
+ tools::Long nExtendTextBoxBy = -50;
+ aCurrentTextBoxSize.extendBy(0, nExtendTextBoxBy);
+ double fCurrentFitFactor = double(rTextBoxSize.Height()) / aCurrentTextBoxSize.Height();
+
+ if (fCurrentFitFactor >= 1.0)
+ return;
+
+ sal_Int32 nFontHeight = GetObjectItemSet().Get(EE_CHAR_FONTHEIGHT).GetHeight();
+
+ double fFontHeightPt = o3tl::convert(double(nFontHeight), o3tl::Length::mm100, o3tl::Length::pt);
+ double fMinY = 0.0;
+ double fMaxY = fMaxScale;
+
+ double fBestFontScale = 0.0;
+ double fBestSpacing = fMaxScale;
+ double fBestFitFactor = fCurrentFitFactor;
+
+ double fInTheMidle = 0.5;
+
+ int iteration = 0;
+ double fFitFactorTarget = 1.00;
+
+ while (iteration < 10)
+ {
+ iteration++;
+ double fScaleY = fMinY + (fMaxY - fMinY) * fInTheMidle;
+
+ double fScaledFontHeight = fFontHeightPt * (fScaleY / 100.0);
+ double fRoundedScaledFontHeight = std::floor(fScaledFontHeight * 10.0) / 10.0;
+ double fCurrentFontScale = (fRoundedScaledFontHeight / fFontHeightPt) * 100.0;
+
+ fCurrentFitFactor = 0.0; // reset fit factor;
+
+ for (double fCurrentSpacing : {100.0, 90.0, 80.0})
+ {
+ if (fCurrentFitFactor >= fFitFactorTarget)
+ continue;
+
+ rOutliner.setGlobalScale(fCurrentFontScale, fCurrentFontScale, 100.0, fCurrentSpacing);
+
+ aCurrentTextBoxSize = rOutliner.CalcTextSizeNTP();
+ aCurrentTextBoxSize.extendBy(0, nExtendTextBoxBy);
+ fCurrentFitFactor = double(rTextBoxSize.Height()) / aCurrentTextBoxSize.Height();
+
+ if (fCurrentSpacing == 100.0)
+ {
+ if (fCurrentFitFactor > fFitFactorTarget)
+ fMinY = fCurrentFontScale;
+ else
+ fMaxY = fCurrentFontScale;
+ }
+
+ if ((fBestFitFactor < fFitFactorTarget && fCurrentFitFactor > fBestFitFactor)
+ || (fCurrentFitFactor >= fFitFactorTarget && fCurrentFitFactor < fBestFitFactor))
+ {
+ fBestFontScale = fCurrentFontScale;
+ fBestSpacing = fCurrentSpacing;
+ fBestFitFactor = fCurrentFitFactor;
+ }
+ }
+ }
+ rOutliner.setGlobalScale(fBestFontScale, fBestFontScale, 100.0, fBestSpacing);
}
void SdrTextObj::SetupOutlinerFormatting( SdrOutliner& rOutl, tools::Rectangle& rPaintRect ) const
diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx
index 1fc6b8f08cff..dfc4acbb9aa9 100644
--- a/svx/source/svdraw/svdotextdecomposition.cxx
+++ b/svx/source/svdraw/svdotextdecomposition.cxx
@@ -1203,7 +1203,7 @@ void SdrTextObj::impDecomposeStretchTextPrimitive(
// to layout without mirroring
const double fScaleX(fabs(aScale.getX()) / aOutlinerScale.getX());
const double fScaleY(fabs(aScale.getY()) / aOutlinerScale.getY());
- rOutliner.SetGlobalCharStretching(fScaleX * 100.0, fScaleY * 100.0);
+ rOutliner.setGlobalScale(fScaleX * 100.0, fScaleY * 100.0, 100.0, 100.0);
// When mirroring in X and Y,
// move the null point which was top left to bottom right.
diff --git a/svx/source/svdraw/svdoutl.cxx b/svx/source/svdraw/svdoutl.cxx
index 3737b1fdf268..8cd9089e065c 100644
--- a/svx/source/svdraw/svdoutl.cxx
+++ b/svx/source/svdraw/svdoutl.cxx
@@ -47,7 +47,7 @@ void SdrOutliner::SetTextObj( const SdrTextObj* pObj )
nOutlinerMode2 = OutlinerMode::TextObject;
Init( nOutlinerMode2 );
- SetGlobalCharStretching();
+ setGlobalScale(100.0, 100.0, 100.0, 100.0);
EEControlBits nStat = GetControlWord();
nStat &= ~EEControlBits( EEControlBits::STRETCHING | EEControlBits::AUTOPAGESIZE );
diff --git a/svx/source/unodraw/unoshape.cxx b/svx/source/unodraw/unoshape.cxx
index 5cc292621bfa..0f9d5ece94da 100644
--- a/svx/source/unodraw/unoshape.cxx
+++ b/svx/source/unodraw/unoshape.cxx
@@ -174,7 +174,7 @@ protected:
};
/// Calculates what scaling factor will be used for autofit text scaling of this shape.
-sal_Int16 GetTextFitToSizeScale(SdrObject* pObject)
+double GetTextFitToSizeScale(SdrObject* pObject)
{
SdrTextObj* pTextObj = dynamic_cast<SdrTextObj*>(pObject);
if (!pTextObj)
@@ -189,7 +189,7 @@ sal_Int16 GetTextFitToSizeScale(SdrObject* pObject)
return 0;
}
- return pTextObj->GetFontScaleY();
+ return pTextObj->GetFontScale();
}
}
@@ -2441,7 +2441,7 @@ bool SvxShape::setPropertyValueImpl( const OUString&, const SfxItemPropertyMapEn
case OWN_ATTR_TEXTFITTOSIZESCALE:
{
- sal_Int16 nMaxScale = 0;
+ double nMaxScale = 0.0;
if (rValue >>= nMaxScale)
{
SdrTextFitToSizeTypeItem aItem(GetSdrObject()->GetMergedItem(SDRATTR_TEXT_FITTOSIZE));
@@ -2939,7 +2939,8 @@ bool SvxShape::getPropertyValueImpl( const OUString&, const SfxItemPropertyMapEn
case OWN_ATTR_TEXTFITTOSIZESCALE:
{
- rValue <<= GetTextFitToSizeScale(GetSdrObject());
+ double nScale = GetTextFitToSizeScale(GetSdrObject());
+ rValue <<= nScale;
break;
}