summaryrefslogtreecommitdiff
path: root/editeng
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 /editeng
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 'editeng')
-rw-r--r--editeng/source/editeng/editeng.cxx23
-rw-r--r--editeng/source/editeng/editobj.cxx11
-rw-r--r--editeng/source/editeng/editobj2.hxx14
-rw-r--r--editeng/source/editeng/impedit.hxx98
-rw-r--r--editeng/source/editeng/impedit2.cxx29
-rw-r--r--editeng/source/editeng/impedit3.cxx148
-rw-r--r--editeng/source/editeng/impedit4.cxx24
-rw-r--r--editeng/source/outliner/outlin2.cxx14
-rw-r--r--editeng/source/outliner/outliner.cxx24
9 files changed, 235 insertions, 150 deletions
diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index 993b6e1b15f1..e63de2032da1 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -2005,14 +2005,13 @@ Point EditEngine::GetDocPosTopLeft( sal_Int32 nParagraph )
else
{
const SvxLRSpaceItem& rLRItem = pImpEditEngine->GetLRSpaceItem( pPPortion->GetNode() );
-// TL_NF_LR aPoint.X() = pImpEditEngine->GetXValue( (short)(rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset()) );
sal_Int32 nSpaceBefore = 0;
pImpEditEngine->GetSpaceBeforeAndMinLabelWidth( pPPortion->GetNode(), &nSpaceBefore );
short nX = static_cast<short>(rLRItem.GetTextLeft()
+ rLRItem.GetTextFirstLineOffset()
+ nSpaceBefore);
- aPoint.setX( pImpEditEngine->GetXValue( nX
- ) );
+
+ aPoint.setX(pImpEditEngine->scaleXSpacingValue(nX));
}
aPoint.setY( pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ) );
}
@@ -2265,14 +2264,24 @@ bool EditEngine::HasText( const SvxSearchItem& rSearchItem )
return pImpEditEngine->HasText( rSearchItem );
}
-void EditEngine::SetGlobalCharStretching(double nX, double nY)
+void EditEngine::setGlobalScale(double fFontScaleX, double fFontScaleY, double fSpacingScaleX, double fSpacingScaleY)
+{
+ pImpEditEngine->setScale(fFontScaleX, fFontScaleY, fSpacingScaleX, fSpacingScaleY);
+}
+
+void EditEngine::getGlobalSpacingScale(double& rX, double& rY) const
+{
+ pImpEditEngine->getSpacingScale(rX, rY);
+}
+
+void EditEngine::getGlobalFontScale(double& rX, double& rY) const
{
- pImpEditEngine->SetCharStretching( nX, nY );
+ pImpEditEngine->getFontScale(rX, rY);
}
-void EditEngine::GetGlobalCharStretching(double& rX, double& rY) const
+void EditEngine::setRoundFontSizeToPt(bool bRound) const
{
- pImpEditEngine->GetCharStretching( rX, rY );
+ pImpEditEngine->setRoundToNearestPt(bRound);
}
bool EditEngine::ShouldCreateBigTextObject() const
diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index 292d32e3bb3d..b1e10dd11938 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -72,11 +72,14 @@ void XEditAttribute::SetItem(const SfxPoolItem& rNew)
pItem = &rNew;
}
-XParaPortionList::XParaPortionList(
- OutputDevice* pRefDev, sal_uInt32 nPW, double nStretchX, double nStretchY)
+XParaPortionList::XParaPortionList(OutputDevice* pRefDev, sal_uInt32 nPW,
+ double fFontScaleX, double fFontScaleY,
+ double fSpacingScaleX, double fSpacingScaleY)
: pRefDevPtr(pRefDev)
- , mnStretchX(nStretchX)
- , mnStretchY(nStretchY)
+ , mfFontScaleX(fFontScaleX)
+ , mfFontScaleY(fFontScaleY)
+ , mfSpacingScaleX(fSpacingScaleX)
+ , mfSpacingScaleY(fSpacingScaleY)
, nPaperWidth(nPW)
{
}
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index 86a2e379be20..86c81e23f94e 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -94,12 +94,14 @@ class XParaPortionList
ListType maList;
VclPtr<OutputDevice> pRefDevPtr;
- double mnStretchX;
- double mnStretchY;
+ double mfFontScaleX;
+ double mfFontScaleY;
+ double mfSpacingScaleX;
+ double mfSpacingScaleY;
sal_uInt32 nPaperWidth;
public:
- XParaPortionList(OutputDevice* pRefDev, sal_uInt32 nPW, double nStretchX, double nStretchY);
+ XParaPortionList(OutputDevice* pRefDev, sal_uInt32 nPW, double fFontScaleX, double fFontScaleY, double fSpacingScaleX, double fSpacingScaleY);
void push_back(XParaPortion* p);
const XParaPortion& operator[](size_t i) const;
@@ -108,8 +110,10 @@ public:
sal_uInt32 GetPaperWidth() const { return nPaperWidth; }
bool RefDevIsVirtual() const {return pRefDevPtr->IsVirtual();}
const MapMode& GetRefMapMode() const { return pRefDevPtr->GetMapMode(); }
- double GetStretchX() const { return mnStretchX; }
- double GetStretchY() const { return mnStretchY; }
+ double getFontScaleX() const { return mfFontScaleX; }
+ double getFontScaleY() const { return mfFontScaleY; }
+ double getSpacingScaleX() const { return mfSpacingScaleX; }
+ double getSpacingScaleY() const { return mfSpacingScaleY; }
};
class ContentInfo
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index 6d2303ee113c..67f98cf2cef3 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -528,8 +528,11 @@ private:
Color maBackgroundColor;
- double mnStretchX;
- double mnStretchY;
+ double mfFontScaleX;
+ double mfFontScaleY;
+ double mfSpacingScaleX;
+ double mfSpacingScaleY;
+ bool mbRoundToNearestPt;
CharCompressType nAsianCompressionMode;
@@ -732,11 +735,40 @@ private:
std::vector<std::unique_ptr<SvxFontItem>>& rFontTable, SvxColorList& rColorList );
sal_Int32 LogicToTwips( sal_Int32 n );
- inline short GetXValue( short nXValue ) const;
- inline tools::Long GetXValue( tools::Long nXValue ) const;
+ double scaleXSpacingValue(tools::Long nXValue) const
+ {
+ if (!aStatus.DoStretch() || mfSpacingScaleX == 100.0)
+ return nXValue;
+
+ return double(nXValue) * mfSpacingScaleX / 100.0;
+ }
- inline short GetYValue( short nYValue ) const;
- inline sal_uInt16 GetYValue( sal_uInt16 nYValue ) const;
+ double scaleYSpacingValue(sal_uInt16 nYValue) const
+ {
+ if (!aStatus.DoStretch() || mfSpacingScaleY == 100.0)
+ return nYValue;
+
+ return double(nYValue) * mfSpacingScaleY / 100.0;
+ }
+
+ double scaleYFontValue(sal_uInt16 nYValue) const
+ {
+ if (!aStatus.DoStretch() || (mfFontScaleY == 100.0))
+ return nYValue;
+
+ return double(nYValue) * mfFontScaleY / 100.0;
+ }
+
+ double scaleXFontValue(tools::Long nXValue) const
+ {
+ if (!aStatus.DoStretch() || (mfFontScaleX == 100.0))
+ return nXValue;
+
+ return double(nXValue) * mfFontScaleY / 100.0;
+ }
+
+ void setRoundToNearestPt(bool bRound) { mbRoundToNearestPt = bRound; }
+ double roundToNearestPt(double fInput) const;
ContentNode* GetPrevVisNode( ContentNode const * pCurNode );
ContentNode* GetNextVisNode( ContentNode const * pCurNode );
@@ -1079,8 +1111,19 @@ public:
SvxCellJustifyMethod GetJustifyMethod( sal_Int32 nPara ) const;
SvxCellVerJustify GetVerJustification( sal_Int32 nPara ) const;
- void SetCharStretching(double nX, double nY);
- inline void GetCharStretching(double& rX, double& rY) const;
+ void setScale(double fFontScaleX, double fFontScaleY, double fSpacingScaleX, double fSpacingScaleY);
+
+ void getFontScale(double& rX, double& rY) const
+ {
+ rX = mfFontScaleX;
+ rY = mfFontScaleY;
+ }
+
+ void getSpacingScale(double& rX, double& rY) const
+ {
+ rX = mfSpacingScaleX;
+ rY = mfSpacingScaleY;
+ }
sal_Int32 GetBigTextObjectStart() const { return nBigTextObjectStart; }
@@ -1279,45 +1322,6 @@ inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode const * pNode )
return GetParaPortions()[ nPos ];
}
-inline void ImpEditEngine::GetCharStretching(double& rX, double& rY) const
-{
- rX = mnStretchX;
- rY = mnStretchY;
-}
-
-inline short ImpEditEngine::GetXValue( short nXValue ) const
-{
- if ( !aStatus.DoStretch() || ( mnStretchX == 100.0 ) )
- return nXValue;
-
- return basegfx::fround(double(nXValue) * mnStretchX / 100.0);
-}
-
-
-inline tools::Long ImpEditEngine::GetXValue( tools::Long nXValue ) const
-{
- if ( !aStatus.DoStretch() || ( mnStretchX == 100.0 ) )
- return nXValue;
-
- return basegfx::fround(nXValue * mnStretchX / 100.0);
-}
-
-inline short ImpEditEngine::GetYValue( short nYValue ) const
-{
- if ( !aStatus.DoStretch() || ( mnStretchY == 100.0 ) )
- return nYValue;
-
- return basegfx::fround(double(nYValue) * mnStretchY / 100.0);
-}
-
-inline sal_uInt16 ImpEditEngine::GetYValue( sal_uInt16 nYValue ) const
-{
- if ( !aStatus.DoStretch() || ( mnStretchY == 100.0 ) )
- return nYValue;
-
- return basegfx::fround(double(nYValue) * mnStretchY / 100.0);
-}
-
inline PointerStyle ImpEditView::GetPointer()
{
if ( !mxPointer )
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx
index d37334f3c2e1..9f2296ed957b 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -97,8 +97,11 @@ ImpEditEngine::ImpEditEngine( EditEngine* pEE, SfxItemPool* pItemPool ) :
pUndoManager(nullptr),
aWordDelimiters(" .,;:-`'?!_=\"{}()[]"),
maBackgroundColor(COL_AUTO),
- mnStretchX(100.0),
- mnStretchY(100.0),
+ mfFontScaleX(100.0),
+ mfFontScaleY(100.0),
+ mfSpacingScaleX(100.0),
+ mfSpacingScaleY(100.0),
+ mbRoundToNearestPt(false),
nAsianCompressionMode(CharCompressType::NONE),
eDefaultHorizontalTextDirection(EEHorizontalTextDirection::Default),
nBigTextObjectStart(20),
@@ -3162,7 +3165,7 @@ void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eO
const SvxLineSpacingItem& rLSItem
= pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
nSBL = (rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix)
- ? GetYValue(rLSItem.GetInterLineSpace())
+ ? scaleYSpacingValue(rLSItem.GetInterLineSpace())
: 0;
}
@@ -3206,7 +3209,7 @@ void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eO
{
const SvxULSpaceItem& rULItem
= pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
- tools::Long nUL = GetYValue(rULItem.GetLower());
+ tools::Long nUL = scaleYSpacingValue(rULItem.GetLower());
adjustYDirectionAware(aLineStart, nUL);
}
}
@@ -3342,10 +3345,10 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
// width, here not preferred. I general, it is best not leave it
// to StartPosX, also the right indents have to be taken into
// account!
- tools::Long nCurWidth = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
+ tools::Long nCurWidth = scaleXSpacingValue(rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth);
if ( nLine == 0 )
{
- tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
+ tools::Long nFI = scaleXSpacingValue(rLRItem.GetTextFirstLineOffset());
nCurWidth -= nFI;
if ( pPortion->GetBulletX() > nCurWidth )
{
@@ -3354,7 +3357,7 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
nCurWidth = pPortion->GetBulletX();
}
}
- nCurWidth += GetXValue( rLRItem.GetRight() );
+ nCurWidth += scaleXSpacingValue(rLRItem.GetRight());
nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
if ( nCurWidth > nMaxWidth )
{
@@ -4275,7 +4278,7 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
- sal_Int32 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
+ sal_Int32 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) ? scaleYSpacingValue(rLSItem.GetInterLineSpace()) : 0;
if ( nSBL )
{
@@ -4288,14 +4291,14 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
sal_Int32 nPortion = GetParaPortions().GetPos( pPortion );
if ( nPortion )
{
- sal_uInt16 nUpper = GetYValue( rULItem.GetUpper() );
+ sal_uInt16 nUpper = scaleYSpacingValue(rULItem.GetUpper());
pPortion->nHeight += nUpper;
pPortion->nFirstLineOffset = nUpper;
}
if ( nPortion != (GetParaPortions().Count()-1) )
{
- pPortion->nHeight += GetYValue( rULItem.GetLower() ); // not in the last
+ pPortion->nHeight += scaleYSpacingValue(rULItem.GetLower()); // not in the last
}
@@ -4315,7 +4318,7 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
// Only Writer3: Do not add up, but minimum distance.
// check if distance by LineSpacing > Upper:
- sal_uInt16 nExtraSpace = GetYValue( lcl_CalcExtraSpace( rLSItem ) );
+ sal_uInt16 nExtraSpace = scaleYSpacingValue(lcl_CalcExtraSpace(rLSItem));
if ( nExtraSpace > pPortion->nFirstLineOffset )
{
// Paragraph becomes 'bigger':
@@ -4324,7 +4327,7 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
}
// Determine nFirstLineOffset now f(pNode) => now f(pNode, pPrev):
- sal_uInt16 nPrevLower = GetYValue( rPrevULItem.GetLower() );
+ sal_uInt16 nPrevLower = scaleYSpacingValue(rPrevULItem.GetLower());
// This PrevLower is still in the height of PrevPortion ...
if ( nPrevLower > pPortion->nFirstLineOffset )
@@ -4346,7 +4349,7 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
if ( pPrev->IsInvalid() )
return;
- nExtraSpace = GetYValue( lcl_CalcExtraSpace( rPrevLSItem ) );
+ nExtraSpace = scaleYSpacingValue(lcl_CalcExtraSpace(rPrevLSItem));
if ( nExtraSpace > nPrevLower )
{
sal_uInt16 nMoreLower = nExtraSpace - nPrevLower;
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index f1cec3a1db18..4ab658dfabc6 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -585,7 +585,8 @@ void ImpEditEngine::CheckPageOverflow()
static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight )
{
- return ( nFontHeight * 12 ) / 10; // + 20%
+ constexpr const double f120Percent = 12.0 / 10.0;
+ return basegfx::fround(nFontHeight * f120Percent); // + 20%
}
tools::Long ImpEditEngine::GetColumnWidth(const Size& rPaperSize) const
@@ -736,7 +737,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
{
aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
if ( !aBulletArea.IsWidthEmpty() && aBulletArea.Right() > 0 )
- pParaPortion->SetBulletX( static_cast<sal_Int32>(GetXValue( aBulletArea.Right() )) );
+ pParaPortion->SetBulletX(sal_Int32(scaleXSpacingValue(aBulletArea.Right())));
else
pParaPortion->SetBulletX( 0 ); // if Bullet is set incorrectly
}
@@ -770,10 +771,10 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
sal_Int32 nPortionStart = 0;
sal_Int32 nPortionEnd = 0;
- tools::Long nStartX = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
+ tools::Long nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth);
if ( nIndex == 0 )
{
- tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
+ tools::Long nFI = scaleXSpacingValue(rLRItem.GetTextFirstLineOffset());
nStartX += nFI;
if ( !nLine && ( pParaPortion->GetBulletX() > nStartX ) )
@@ -785,13 +786,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
const bool bAutoSize = IsEffectivelyVertical() ? aStatus.AutoPageHeight() : aStatus.AutoPageWidth();
tools::Long nMaxLineWidth = GetColumnWidth(bAutoSize ? aMaxAutoPaperSize : aPaperSize);
- nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
+ nMaxLineWidth -= scaleXSpacingValue(rLRItem.GetRight());
nMaxLineWidth -= nStartX;
// If PaperSize == long_max, one cannot take away any negative
// first line indent. (Overflow)
if ( ( nMaxLineWidth < 0 ) && ( nStartX < 0 ) )
- nMaxLineWidth = GetColumnWidth(aPaperSize) - GetXValue(rLRItem.GetRight());
+ nMaxLineWidth = GetColumnWidth(aPaperSize) - scaleXSpacingValue(rLRItem.GetRight());
// If still less than 0, it may be just the right edge.
if ( nMaxLineWidth <= 0 )
@@ -871,7 +872,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
}
nXWidth = nMaxRangeWidth;
if ( nXWidth )
- nMaxLineWidth = nXWidth - nStartX - GetXValue( rLRItem.GetRight() );
+ nMaxLineWidth = nXWidth - nStartX - scaleXSpacingValue(rLRItem.GetRight());
else
{
// Try further down in the polygon.
@@ -961,14 +962,14 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
tools::Long nOldTmpWidth = nTmpWidth;
// Search for Tab-Pos...
- tools::Long nCurPos = nTmpWidth+nStartX;
+ tools::Long nCurPos = nTmpWidth + nStartX;
// consider scaling
- if ( aStatus.DoStretch() && ( mnStretchX != 100.0 ) )
- nCurPos = basegfx::fround(double(nCurPos) * 100.0 / std::max(mnStretchX, 1.0));
+ if (aStatus.DoStretch() && (mfFontScaleX != 100.0))
+ nCurPos = basegfx::fround(double(nCurPos) * 100.0 / std::max(mfFontScaleX, 1.0));
short nAllSpaceBeforeText = static_cast< short >(rLRItem.GetTextLeft()/* + rLRItem.GetTextLeft()*/ + nSpaceBeforeAndMinLabelWidth);
aCurrentTab.aTabStop = pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText /*rLRItem.GetTextLeft()*/, aEditDoc.GetDefTab() );
- aCurrentTab.nTabPos = GetXValue( static_cast<tools::Long>( aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText /*rLRItem.GetTextLeft()*/ ) );
+ aCurrentTab.nTabPos = scaleXFontValue(tools::Long(aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText/*rLRItem.GetTextLeft()*/));
aCurrentTab.bValid = false;
// Switch direction in R2L para...
@@ -1190,8 +1191,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
// No spacing within L2R/R2L nesting
if ( bAllow )
{
- tools::Long nExtraSpace = pPortion->GetSize().Height()/5;
- nExtraSpace = GetXValue( nExtraSpace );
+ tools::Long nExtraSpace = pPortion->GetSize().Height() / 5;
+ nExtraSpace = scaleXSpacingValue(nExtraSpace);
pPortion->GetSize().AdjustWidth(nExtraSpace );
nTmpWidth += nExtraSpace;
}
@@ -1405,12 +1406,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
bSameLineAgain = true;
}
-
if ( !bSameLineAgain && !aStatus.IsOutliner() )
{
if ( rLSItem.GetLineSpaceRule() == SvxLineSpaceRule::Min )
{
- sal_uInt16 nMinHeight = GetYValue( rLSItem.GetLineHeight() );
+ double fMinHeight = scaleYSpacingValue(rLSItem.GetLineHeight());
+ sal_uInt16 nMinHeight = basegfx::fround(fMinHeight);
+
sal_uInt16 nTxtHeight = pLine->GetHeight();
if ( nTxtHeight < nMinHeight )
{
@@ -1422,7 +1424,9 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
}
else if ( rLSItem.GetLineSpaceRule() == SvxLineSpaceRule::Fix )
{
- sal_uInt16 nFixHeight = GetYValue( rLSItem.GetLineHeight() );
+ double fFixHeight = scaleYSpacingValue(rLSItem.GetLineHeight());
+ sal_uInt16 nFixHeight = basegfx::fround(fFixHeight);
+
sal_uInt16 nTxtHeight = pLine->GetHeight();
pLine->SetMaxAscent( static_cast<sal_uInt16>(pLine->GetMaxAscent() + ( nFixHeight - nTxtHeight ) ) );
pLine->SetHeight( nFixHeight, nTxtHeight );
@@ -1431,29 +1435,51 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
{
// There are documents with PropLineSpace 0, why?
// (cmc: re above question :-) such documents can be seen by importing a .ppt
- if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() < 100 ) )
+ sal_uInt16 nPropLineSpace = rLSItem.GetPropLineSpace();
+ double fProportionalScale = double(nPropLineSpace) / 100.0;
+ constexpr const double f80Percent = 8.0 / 10.0;
+ double fSpacingFactor = mfSpacingScaleY / 100.0;
+ if (nPropLineSpace && nPropLineSpace < 100)
{
// Adapted code from sw/source/core/text/itrform2.cxx
- sal_uInt16 nPropLineSpace = rLSItem.GetPropLineSpace();
sal_uInt16 nAscent = pLine->GetMaxAscent();
- sal_uInt16 nNewAscent = pLine->GetTxtHeight() * nPropLineSpace / 100 * 4 / 5; // 80%
- if ( !nAscent || nAscent > nNewAscent )
- {
- pLine->SetMaxAscent( nNewAscent );
- }
- sal_uInt16 nHeight = pLine->GetHeight() * nPropLineSpace / 100;
- pLine->SetHeight( nHeight, pLine->GetTxtHeight() );
+ sal_uInt16 nNewAscent = basegfx::fround(pLine->GetTxtHeight() * fSpacingFactor * fProportionalScale * f80Percent);
+ if (!nAscent || nAscent > nNewAscent)
+ pLine->SetMaxAscent(nNewAscent);
+ sal_uInt16 nHeight = basegfx::fround(pLine->GetHeight() * fProportionalScale * fSpacingFactor);
+
+ pLine->SetHeight(nHeight, pLine->GetTxtHeight());
}
- else if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) )
+ else if (nPropLineSpace && nPropLineSpace != 100)
{
sal_uInt16 nTxtHeight = pLine->GetHeight();
- sal_Int32 nPropTextHeight = nTxtHeight * rLSItem.GetPropLineSpace() / 100;
+ sal_Int32 nPropTextHeight = nTxtHeight * fProportionalScale * fSpacingFactor;
// The Ascent has to be adjusted for the difference:
tools::Long nDiff = pLine->GetHeight() - nPropTextHeight;
pLine->SetMaxAscent( static_cast<sal_uInt16>( pLine->GetMaxAscent() - nDiff ) );
pLine->SetHeight( static_cast<sal_uInt16>( nPropTextHeight ), nTxtHeight );
}
}
+ else if (rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Off)
+ {
+ if (mfSpacingScaleY < 100.0)
+ {
+ double fSpacingFactor = mfSpacingScaleY / 100.0;
+ sal_uInt16 nPropLineSpace = basegfx::fround(100.0 * fSpacingFactor);
+ if (nPropLineSpace && nPropLineSpace < 100)
+ {
+ // Adapted code from sw/source/core/text/itrform2.cxx
+ sal_uInt16 nAscent = pLine->GetMaxAscent();
+ sal_uInt16 nNewAscent = basegfx::fround(pLine->GetTxtHeight() * fSpacingFactor);
+ if (!nAscent || nAscent > nNewAscent)
+ pLine->SetMaxAscent(nNewAscent);
+ sal_uInt16 nHeight = basegfx::fround(pLine->GetHeight() * fSpacingFactor);
+
+ pLine->SetHeight(nHeight, pLine->GetTxtHeight());
+ }
+
+ }
+ }
}
if ( ( !IsEffectivelyVertical() && aStatus.AutoPageWidth() ) ||
@@ -1463,8 +1489,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
// has to be used for the Alignment. If it does not fit or if it
// will change the paper width, it will be formatted again for
// Justification! = LEFT anyway.
- tools::Long nMaxLineWidthFix = GetColumnWidth(aPaperSize)
- - GetXValue( rLRItem.GetRight() ) - nStartX;
+ tools::Long nMaxLineWidthFix = GetColumnWidth(aPaperSize) - scaleXSpacingValue(rLRItem.GetRight()) - nStartX;
if ( aTextSize.Width() < nMaxLineWidthFix )
nMaxLineWidth = nMaxLineWidthFix;
}
@@ -1678,23 +1703,23 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pParaPortion->GetNode(), &nSpaceBefore );
const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pParaPortion->GetNode() );
const SvxLineSpacingItem& rLSItem = pParaPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
- tools::Long nStartX = GetXValue( rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBefore );
+ tools::Long nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBefore);
tools::Rectangle aBulletArea { Point(), Point() };
if ( bLineBreak )
{
- nStartX = GetXValue( rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBeforeAndMinLabelWidth );
+ nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBeforeAndMinLabelWidth);
}
else
{
aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
if ( !aBulletArea.IsEmpty() && aBulletArea.Right() > 0 )
- pParaPortion->SetBulletX( static_cast<sal_Int32>(GetXValue( aBulletArea.Right() )) );
+ pParaPortion->SetBulletX(sal_Int32(scaleXSpacingValue(aBulletArea.Right())));
else
pParaPortion->SetBulletX( 0 ); // If Bullet set incorrectly.
if ( pParaPortion->GetBulletX() > nStartX )
{
- nStartX = GetXValue( rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBeforeAndMinLabelWidth );
+ nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBeforeAndMinLabelWidth);
if ( pParaPortion->GetBulletX() > nStartX )
nStartX = pParaPortion->GetBulletX();
}
@@ -1722,7 +1747,7 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
sal_Int32 nPara = GetParaPortions().GetPos( pParaPortion );
SvxAdjust eJustification = GetJustification( nPara );
tools::Long nMaxLineWidth = GetColumnWidth(aPaperSize);
- nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
+ nMaxLineWidth -= scaleXSpacingValue(rLRItem.GetRight());
if ( nMaxLineWidth < 0 )
nMaxLineWidth = 1;
if ( eJustification == SvxAdjust::Center )
@@ -2797,20 +2822,24 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
if ( aStatus.DoStretch() )
{
- if (mnStretchY != 100.0)
+ if (mfFontScaleY != 100.0)
{
- double fNewHeight = (double(aRealSz.Height()) * mnStretchY) / 100.0;
+ double fHeightRounded = roundToNearestPt(aRealSz.Height());
+ double fNewHeight = fHeightRounded * (mfFontScaleY / 100.0);
+ fNewHeight = roundToNearestPt(fNewHeight);
aRealSz.setHeight(basegfx::fround(fNewHeight));
}
- if (mnStretchX != 100.0)
+ if (mfFontScaleX != 100.0)
{
- if (mnStretchX == mnStretchY && nRelWidth == 100 )
+ if (mfFontScaleX == mfFontScaleY && nRelWidth == 100 )
{
aRealSz.setWidth( 0 );
}
else
{
- double fNewWidth = (double(aRealSz.Width()) * mnStretchX) / 100.0;
+ double fWidthRounded = roundToNearestPt(aRealSz.Width());
+ double fNewWidth = fWidthRounded * (mfFontScaleX / 100.0);
+ fNewWidth = roundToNearestPt(fNewWidth);
aRealSz.setWidth(basegfx::fround(fNewWidth));
// Also the Kerning: (long due to handle Interim results)
@@ -2826,15 +2855,15 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
>0 >100 > (Proportional)
<0 >100 < (The amount, thus disproportional)
*/
- if (nKerning < 0 && mnStretchX > 100.0)
+ if (nKerning < 0 && mfFontScaleX > 100.0)
{
// disproportional
- nKerning = basegfx::fround((double(nKerning) * 100.0) / mnStretchX);
+ nKerning = basegfx::fround((double(nKerning) * 100.0) / mfFontScaleX);
}
else if ( nKerning )
{
// Proportional
- nKerning = basegfx::fround((double(nKerning) * mnStretchX) / 100.0);
+ nKerning = basegfx::fround((double(nKerning) * mfFontScaleX) / 100.0);
}
rFont.SetFixKerning( static_cast<short>(nKerning) );
}
@@ -3170,7 +3199,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
- ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
+ ? scaleYSpacingValue(rLSItem.GetInterLineSpace()) : 0;
bool bPaintBullet (false);
for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
@@ -3803,7 +3832,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
if ( !aStatus.IsOutliner() )
{
const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
- tools::Long nUL = GetYValue( rULItem.GetLower() );
+ tools::Long nUL = scaleYSpacingValue(rULItem.GetLower());
adjustYDirectionAware(aStartPos, nUL);
}
@@ -4129,10 +4158,10 @@ tools::Long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
- ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
+ ? scaleYSpacingValue(rLSItem.GetInterLineSpace()) : 0;
const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
- tools::Long nUL = GetYValue( rULItem.GetLower() );
+ tools::Long nUL = scaleYSpacingValue(rULItem.GetLower());
const EditLineList& rLines = pPortion->GetLines();
sal_Int32 nLineCount = rLines.Count();
@@ -4229,28 +4258,35 @@ void ImpEditEngine::SetFlatMode( bool bFlat )
pActiveView->ShowCursor();
}
-void ImpEditEngine::SetCharStretching(double nX, double nY)
+void ImpEditEngine::setScale(double fFontScaleX, double fFontScaleY, double fSpacingScaleX, double fSpacingScaleY)
{
bool bChanged;
- if ( !IsEffectivelyVertical() )
+
+ if (!IsEffectivelyVertical())
{
- bChanged = mnStretchX != nX || mnStretchY != nY;
- mnStretchX = nX;
- mnStretchY = nY;
+ bChanged = mfFontScaleX != fFontScaleX || mfFontScaleY != fFontScaleY ||
+ mfSpacingScaleX != fSpacingScaleX || mfSpacingScaleY != fSpacingScaleY;
+ mfFontScaleX = fFontScaleX;
+ mfFontScaleY = fFontScaleY;
+ mfSpacingScaleX = fSpacingScaleX;
+ mfSpacingScaleY = fSpacingScaleY;
}
else
{
- bChanged = mnStretchX != nY || mnStretchY != nX;
- mnStretchX = nY;
- mnStretchY = nX;
+ bChanged = mfFontScaleX != fFontScaleY || mfFontScaleY != fFontScaleX ||
+ mfSpacingScaleX != fSpacingScaleY || mfSpacingScaleY != fSpacingScaleX;
+ mfFontScaleX = fFontScaleY;
+ mfFontScaleY = fFontScaleX;
+ mfSpacingScaleX = fSpacingScaleY;
+ mfSpacingScaleY = fSpacingScaleX;
}
if (bChanged && aStatus.DoStretch())
{
FormatFullDoc();
// (potentially) need everything redrawn
- aInvalidRect=tools::Rectangle(0,0,1000000,1000000);
- UpdateViews( GetActiveView() );
+ aInvalidRect = tools::Rectangle(0, 0, 1000000, 1000000);
+ UpdateViews(GetActiveView());
}
}
diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx
index 0c5992e7ad2d..40a203a729e8 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -1087,7 +1087,7 @@ std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject( EditSelection a
// sleeper set up when Olli paragraphs not hacked!
if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && IsUpdateLayout() && ( nTextPortions >= nBigObjectStart ) )
{
- XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), GetColumnWidth(aPaperSize), mnStretchX, mnStretchY );
+ XParaPortionList* pXList = new XParaPortionList(GetRefDevice(), GetColumnWidth(aPaperSize), mfFontScaleX, mfFontScaleY, mfSpacingScaleX, mfSpacingScaleY);
pTxtObj->SetPortionInfo(std::unique_ptr<XParaPortionList>(pXList));
for ( nNode = nStartNode; nNode <= nEndNode; nNode++ )
{
@@ -1172,9 +1172,11 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject
XParaPortionList* pPortionInfo = rTextObjectImpl.GetPortionInfo();
if ( pPortionInfo && ( static_cast<tools::Long>(pPortionInfo->GetPaperWidth()) == GetColumnWidth(aPaperSize) )
- && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() )
- && ( pPortionInfo->GetStretchX() == mnStretchX)
- && ( pPortionInfo->GetStretchY() == mnStretchY))
+ && pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode()
+ && pPortionInfo->getFontScaleX() == mfFontScaleX
+ && pPortionInfo->getFontScaleY() == mfFontScaleY
+ && pPortionInfo->getSpacingScaleX() == mfSpacingScaleX
+ && pPortionInfo->getSpacingScaleY() == mfSpacingScaleY)
{
if ( (pPortionInfo->GetRefDevPtr() == GetRefDevice()) ||
(pPortionInfo->RefDevIsVirtual() && GetRefDevice()->IsVirtual()) )
@@ -3061,4 +3063,18 @@ sal_Int32 ImpEditEngine::LogicToTwips(sal_Int32 n)
return aSz.Width();
}
+double ImpEditEngine::roundToNearestPt(double fInput) const
+{
+ if (mbRoundToNearestPt)
+ {
+ double fInputPt = o3tl::convert(fInput, o3tl::Length::mm100, o3tl::Length::pt);
+ auto nInputRounded = basegfx::fround(fInputPt);
+ return o3tl::convert(double(nInputRounded), o3tl::Length::pt, o3tl::Length::mm100);
+ }
+ else
+ {
+ return fInput;
+ }
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/editeng/source/outliner/outlin2.cxx b/editeng/source/outliner/outlin2.cxx
index 19230afeeab3..7229d7063a3b 100644
--- a/editeng/source/outliner/outlin2.cxx
+++ b/editeng/source/outliner/outlin2.cxx
@@ -482,7 +482,7 @@ void Outliner::QuickFormatDoc()
pEditEngine->QuickFormatDoc();
}
-void Outliner::SetGlobalCharStretching(double nX, double nY)
+void Outliner::setGlobalScale(double rFontX, double rFontY, double rSpacingX, double rSpacingY)
{
// reset bullet size
sal_Int32 nParagraphs = pParaList->GetParagraphCount();
@@ -493,12 +493,18 @@ void Outliner::SetGlobalCharStretching(double nX, double nY)
pPara->aBulSize.setWidth( -1 );
}
- pEditEngine->SetGlobalCharStretching( nX, nY );
+ pEditEngine->setGlobalScale(rFontX, rFontY, rSpacingX, rSpacingY);
}
-void Outliner::GetGlobalCharStretching(double& rX, double& rY) const
+void Outliner::getGlobalScale(double& rFontX, double& rFontY, double& rSpacingX, double& rSpacingY) const
{
- pEditEngine->GetGlobalCharStretching(rX, rY);
+ pEditEngine->getGlobalFontScale(rFontX, rFontY);
+ pEditEngine->getGlobalSpacingScale(rSpacingX, rSpacingY);
+}
+
+void Outliner::setRoundFontSizeToPt(bool bRound) const
+{
+ pEditEngine->setRoundFontSizeToPt(bRound);
}
void Outliner::EraseVirtualDevice()
diff --git a/editeng/source/outliner/outliner.cxx b/editeng/source/outliner/outliner.cxx
index 0acbc3dbbb4a..75db039f5dc9 100644
--- a/editeng/source/outliner/outliner.cxx
+++ b/editeng/source/outliner/outliner.cxx
@@ -47,6 +47,8 @@
#include <libxml/xmlwriter.h>
#include <sal/log.hxx>
#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <o3tl/temporary.hxx>
#include <osl/diagnose.h>
#include <memory>
@@ -805,7 +807,6 @@ bool Outliner::Collapse( Paragraph const * pPara )
return false;
}
-
vcl::Font Outliner::ImpCalcBulletFont( sal_Int32 nPara ) const
{
const SvxNumberFormat* pFmt = GetNumberFormat( nPara );
@@ -844,16 +845,16 @@ vcl::Font Outliner::ImpCalcBulletFont( sal_Int32 nPara ) const
}
// Use original scale...
- double nStretchX, nStretchY;
- GetGlobalCharStretching(nStretchX, nStretchY);
+ double nStretchY = 100.0;
+ getGlobalScale(o3tl::temporary(double()), nStretchY, o3tl::temporary(double()), o3tl::temporary(double()));
- sal_uInt16 nScale = pFmt->GetBulletRelSize() * nStretchY / 100;
- sal_uLong nScaledLineHeight = aStdFont.GetFontSize().Height();
- nScaledLineHeight *= nScale*10;
- nScaledLineHeight /= 1000;
+ double fScale = pFmt->GetBulletRelSize() * nStretchY / 100;
+ double fScaledLineHeight = aStdFont.GetFontSize().Height();
+ fScaledLineHeight *= fScale * 10.0;
+ fScaledLineHeight /= 1000.0;
aBulletFont.SetAlignment( ALIGN_BOTTOM );
- aBulletFont.SetFontSize( Size( 0, nScaledLineHeight ) );
+ aBulletFont.SetFontSize(Size(0, basegfx::fround(fScaledLineHeight)));
bool bVertical = IsVertical();
aBulletFont.SetVertical( bVertical );
aBulletFont.SetOrientation( Degree10(bVertical ? (IsTopToBottom() ? 2700 : 900) : 0) );
@@ -891,8 +892,11 @@ void Outliner::PaintBullet(sal_Int32 nPara, const Point& rStartPos, const Point&
bool bRightToLeftPara = pEditEngine->IsRightToLeft( nPara );
tools::Rectangle aBulletArea( ImpCalcBulletArea( nPara, true, false ) );
- double nStretchX, nStretchY;
- GetGlobalCharStretching(nStretchX, nStretchY);
+
+ double nStretchX = 100.0;
+ getGlobalScale(o3tl::temporary(double()), o3tl::temporary(double()),
+ nStretchX, o3tl::temporary(double()));
+
tools::Long nStretchBulletX = basegfx::fround(double(aBulletArea.Left()) * nStretchX / 100.0);
tools::Long nStretchBulletWidth = basegfx::fround(double(aBulletArea.GetWidth()) * nStretchX / 100.0);
aBulletArea = tools::Rectangle(Point(nStretchBulletX, aBulletArea.Top()),