diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2023-03-23 11:24:30 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2023-03-26 15:07:39 +0000 |
commit | 628275acb1b9652e65b8c5c013549dce5ad6f5bf (patch) | |
tree | 1678c423d242e0899cf73a2ab23f37faafd35232 /editeng/source | |
parent | a5fde5d749d27b0da216da4412f8b750178b1b08 (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>
Diffstat (limited to 'editeng/source')
-rw-r--r-- | editeng/source/editeng/editeng.cxx | 23 | ||||
-rw-r--r-- | editeng/source/editeng/editobj.cxx | 11 | ||||
-rw-r--r-- | editeng/source/editeng/editobj2.hxx | 14 | ||||
-rw-r--r-- | editeng/source/editeng/impedit.hxx | 98 | ||||
-rw-r--r-- | editeng/source/editeng/impedit2.cxx | 29 | ||||
-rw-r--r-- | editeng/source/editeng/impedit3.cxx | 148 | ||||
-rw-r--r-- | editeng/source/editeng/impedit4.cxx | 24 | ||||
-rw-r--r-- | editeng/source/outliner/outlin2.cxx | 14 | ||||
-rw-r--r-- | editeng/source/outliner/outliner.cxx | 23 |
9 files changed, 234 insertions, 150 deletions
diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx index 32fad4d8fc35..69fef679c7f3 100644 --- a/editeng/source/editeng/editeng.cxx +++ b/editeng/source/editeng/editeng.cxx @@ -2006,14 +2006,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 ) ); } @@ -2266,14 +2265,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 437754d70def..d0ec8632f134 100644 --- a/editeng/source/editeng/editobj.cxx +++ b/editeng/source/editeng/editobj.cxx @@ -70,11 +70,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 fd8ff61f66ca..7bbd0fd9e765 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; @@ -733,11 +736,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 ); @@ -1080,8 +1112,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; } @@ -1282,45 +1325,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 4e87e36af5d3..e6cbdcfbdeb9 100644 --- a/editeng/source/editeng/impedit2.cxx +++ b/editeng/source/editeng/impedit2.cxx @@ -98,8 +98,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), @@ -3222,7 +3225,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; } @@ -3266,7 +3269,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); } } @@ -3402,10 +3405,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 ) { @@ -3414,7 +3417,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 ) { @@ -4337,7 +4340,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 ) { @@ -4350,14 +4353,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 } @@ -4377,7 +4380,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': @@ -4386,7 +4389,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 ) @@ -4408,7 +4411,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 376d1df7ad13..6cb45a385748 100644 --- a/editeng/source/editeng/impedit3.cxx +++ b/editeng/source/editeng/impedit3.cxx @@ -668,7 +668,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 @@ -827,7 +828,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 } @@ -861,10 +862,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 ) ) @@ -876,13 +877,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 ) @@ -962,7 +963,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. @@ -1052,14 +1053,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... @@ -1286,8 +1287,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->adjustSize(nExtraSpace, 0); nTmpWidth += nExtraSpace; } @@ -1500,12 +1501,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 ) { @@ -1517,7 +1519,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 ); @@ -1526,29 +1530,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() ) || @@ -1558,8 +1584,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; } @@ -1784,23 +1809,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(); } @@ -1828,7 +1853,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 ) @@ -2994,20 +3019,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) @@ -3023,15 +3052,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) ); } @@ -3369,7 +3398,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++ ) @@ -4033,7 +4062,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); } @@ -4359,10 +4388,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(); @@ -4459,28 +4488,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 5affeff55455..424b43aadaeb 100644 --- a/editeng/source/editeng/impedit4.cxx +++ b/editeng/source/editeng/impedit4.cxx @@ -1093,7 +1093,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++ ) { @@ -1178,9 +1178,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()) ) @@ -3103,4 +3105,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 013c680df152..c3a672499ef5 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 72340587ba05..6cd7ab274b0a 100644 --- a/editeng/source/outliner/outliner.cxx +++ b/editeng/source/outliner/outliner.cxx @@ -48,6 +48,7 @@ #include <sal/log.hxx> #include <o3tl/safeint.hxx> #include <o3tl/string_view.hxx> +#include <o3tl/temporary.hxx> #include <osl/diagnose.h> #include <memory> @@ -801,7 +802,6 @@ bool Outliner::Collapse( Paragraph const * pPara ) return true; } - vcl::Font Outliner::ImpCalcBulletFont( sal_Int32 nPara ) const { const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); @@ -840,16 +840,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; - tools::Long nScaledLineHeight = aStdFont.GetFontSize().Height(); - nScaledLineHeight *= nScale*10; - nScaledLineHeight /= 1000; + double fScale = pFmt->GetBulletRelSize() * nStretchY / 100.0; + double fScaledLineHeight = aStdFont.GetFontSize().Height(); + fScaledLineHeight *= fScale * 10; + 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) ); @@ -887,8 +887,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()), |