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 | |
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>
31 files changed, 452 insertions, 258 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()), diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx index f5487e779a4b..0693d06821f9 100644 --- a/include/editeng/editeng.hxx +++ b/include/editeng/editeng.hxx @@ -414,8 +414,12 @@ public: void QuickDelete( const ESelection& rSel ); void QuickMarkToBeRepainted( sal_Int32 nPara ); - void SetGlobalCharStretching(double nX, double nY); - void GetGlobalCharStretching(double& rX, double& rY) const; + void setGlobalScale(double fFontScaleX, double fFontScaleY, double fSpacingScaleX, double fSpacingScaleY); + + void getGlobalSpacingScale(double& rX, double& rY) const; + void getGlobalFontScale(double& rX, double& rY) const; + + void setRoundFontSizeToPt(bool bRound) const; void SetEditTextObjectPool( SfxItemPool* pPool ); SfxItemPool* GetEditTextObjectPool() const; diff --git a/include/editeng/outliner.hxx b/include/editeng/outliner.hxx index a4f02568a64f..192b30d01634 100644 --- a/include/editeng/outliner.hxx +++ b/include/editeng/outliner.hxx @@ -931,8 +931,10 @@ public: bool IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder ); bool IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder, bool* pbBulletPos ); - void SetGlobalCharStretching(double nX = 100.0, double nY = 100.0); - void GetGlobalCharStretching(double& rX, double& rY) const; + void setGlobalScale(double rFontX = 100.0, double rFontY = 100.0, double rSpacingX = 100.0, double rSpacingY = 100.0); + void getGlobalScale(double& rFontX, double& rFontY, double& rSpacingX, double& rSpacingY) const; + void setRoundFontSizeToPt(bool bRound) const; + void EraseVirtualDevice(); bool ShouldCreateBigTextObject() const; diff --git a/include/oox/export/drawingml.hxx b/include/oox/export/drawingml.hxx index 59c9ace37113..2a72225680fb 100644 --- a/include/oox/export/drawingml.hxx +++ b/include/oox/export/drawingml.hxx @@ -315,7 +315,7 @@ public: @returns true if any paragraph properties were written */ - bool WriteParagraphProperties(const css::uno::Reference< css::text::XTextContent >& rParagraph, const css::uno::Reference<css::beans::XPropertySet>& rXShapePropSet, float fFirstCharHeight, sal_Int32 nElement); + bool WriteParagraphProperties(const css::uno::Reference< css::text::XTextContent >& rParagraph, float fFirstCharHeight, sal_Int32 nElement); void WriteParagraphNumbering(const css::uno::Reference< css::beans::XPropertySet >& rXPropSet, float fFirstCharHeight, sal_Int16 nLevel ); void WriteParagraphTabStops(const css::uno::Reference<css::beans::XPropertySet>& rXPropSet); diff --git a/include/svx/sdtfsitm.hxx b/include/svx/sdtfsitm.hxx index d98e431dab68..ccdcb7c4dbe9 100644 --- a/include/svx/sdtfsitm.hxx +++ b/include/svx/sdtfsitm.hxx @@ -35,14 +35,17 @@ class SVXCORE_DLLPUBLIC SdrTextFitToSizeTypeItem final { public: static SfxPoolItem* CreateDefault(); - SdrTextFitToSizeTypeItem( - css::drawing::TextFitToSizeType const eFit = css::drawing::TextFitToSizeType_NONE) - : SfxEnumItem(SDRATTR_TEXT_FITTOSIZE, eFit) {} + SdrTextFitToSizeTypeItem(css::drawing::TextFitToSizeType const eFit = css::drawing::TextFitToSizeType_NONE) + : SfxEnumItem(SDRATTR_TEXT_FITTOSIZE, eFit) + { + } + SdrTextFitToSizeTypeItem(const SdrTextFitToSizeTypeItem& rItem) - : SfxEnumItem(rItem), - m_nMaxScale(rItem.GetMaxScale()) + : SfxEnumItem(rItem) + , m_nMaxScale(rItem.GetMaxScale()) { } + virtual SdrTextFitToSizeTypeItem* Clone(SfxItemPool* pPool=nullptr) const override; bool operator==(const SfxPoolItem& rItem) const override; virtual sal_uInt16 GetValueCount() const override; @@ -55,10 +58,11 @@ public: virtual bool HasBoolValue() const override; virtual bool GetBoolValue() const override; virtual void SetBoolValue(bool bVal) override; - void SetMaxScale(sal_Int16 nMaxScale) { m_nMaxScale = nMaxScale; } - sal_Int16 GetMaxScale() const { return m_nMaxScale; } + + void SetMaxScale(double nMaxScale) { m_nMaxScale = nMaxScale; } + double GetMaxScale() const { return m_nMaxScale; } private: - sal_Int16 m_nMaxScale = 0; + double m_nMaxScale = 0.0; }; #endif diff --git a/include/svx/svdotext.hxx b/include/svx/svdotext.hxx index a1cccb0804a4..ccecae20e2f8 100644 --- a/include/svx/svdotext.hxx +++ b/include/svx/svdotext.hxx @@ -275,6 +275,8 @@ private: Fraction& aFitXCorrection ) const; void ImpAutoFitText( SdrOutliner& rOutliner ) const; void ImpAutoFitText( SdrOutliner& rOutliner, const Size& rShapeSize, bool bIsVerticalWriting ) const; + void autoFitTextForCompatibility(SdrOutliner& rOutliner, const Size& rShapeSize) const; + SVX_DLLPRIVATE rtl::Reference<SdrObject> ImpConvertContainedTextToSdrPathObjs(bool bToPoly) const; SVX_DLLPRIVATE void ImpRegisterLink(); SVX_DLLPRIVATE void ImpDeregisterLink(); @@ -403,7 +405,9 @@ public: // FitToSize and Fontwork are not taken into account in GetTextSize()! virtual const Size& GetTextSize() const; void FitFrameToTextSize(); - sal_uInt16 GetFontScaleY() const; + + double GetFontScale() const; + double GetSpacingScale() const; // Simultaneously sets the text into the Outliner (possibly // the one of the EditOutliner) and sets the PaperSize. diff --git a/include/svx/unoshprp.hxx b/include/svx/unoshprp.hxx index 70be33007013..8a6302659702 100644 --- a/include/svx/unoshprp.hxx +++ b/include/svx/unoshprp.hxx @@ -363,7 +363,7 @@ { UNO_NAME_MISC_OBJ_SIZEPROTECT, SDRATTR_OBJSIZEPROTECT , cppu::UnoType<bool>::get(), 0, 0},\ { u"UINameSingular", OWN_ATTR_UINAME_SINGULAR , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0}, \ { u"UINamePlural", OWN_ATTR_UINAME_PLURAL , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0}, \ - { u"TextFitToSizeScale", OWN_ATTR_TEXTFITTOSIZESCALE, ::cppu::UnoType<sal_Int16>::get(), 0, 0}, \ + { u"TextFitToSizeScale", OWN_ATTR_TEXTFITTOSIZESCALE, ::cppu::UnoType<double>::get(), 0, 0}, \ /* #i68101# */ \ { UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , ::cppu::UnoType<OUString>::get(), 0, 0}, \ { UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , ::cppu::UnoType<OUString>::get(), 0, 0}, \ diff --git a/oox/inc/drawingml/textparagraph.hxx b/oox/inc/drawingml/textparagraph.hxx index 4920c99da7c5..1f43249372a5 100644 --- a/oox/inc/drawingml/textparagraph.hxx +++ b/oox/inc/drawingml/textparagraph.hxx @@ -77,8 +77,7 @@ public: const TextListStyle& rMasterTextListStyle, const TextListStyle& rTextListStyle, bool bFirst, - float nDefaultCharHeight, - sal_Int32 nAutofitFontScale) const; + float nDefaultCharHeight) const; bool HasMathXml() const { diff --git a/oox/inc/drawingml/textparagraphproperties.hxx b/oox/inc/drawingml/textparagraphproperties.hxx index d3742e7377e0..e362119ed6f9 100644 --- a/oox/inc/drawingml/textparagraphproperties.hxx +++ b/oox/inc/drawingml/textparagraphproperties.hxx @@ -104,7 +104,6 @@ public: const BulletList* pMasterBuList, bool bApplyBulletList, float fFontSize, - sal_Int32 nAutofitFontScale = 100000, bool bPushDefaultValues = false ) const; /** Returns the largest character size of this paragraph. If possible the diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index efba958fa0e4..7927b7aa6945 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -186,13 +186,13 @@ void Diagram::syncDiagramFontHeights() { // Find out the minimum scale within this group. const ShapePairs& rShapePairs = rNameAndPairs.second; - sal_Int16 nMinScale = 100; + double nMinScale = 100.0; for (const auto& rShapePair : rShapePairs) { uno::Reference<beans::XPropertySet> xPropertySet(rShapePair.second, uno::UNO_QUERY); if (xPropertySet.is()) { - sal_Int16 nTextFitToSizeScale = 0; + double nTextFitToSizeScale = 0.0; xPropertySet->getPropertyValue("TextFitToSizeScale") >>= nTextFitToSizeScale; if (nTextFitToSizeScale > 0 && nTextFitToSizeScale < nMinScale) { @@ -202,7 +202,7 @@ void Diagram::syncDiagramFontHeights() } // Set that minimum scale for all members of the group. - if (nMinScale < 100) + if (nMinScale < 100.0) { for (const auto& rShapePair : rShapePairs) { diff --git a/oox/source/drawingml/textbody.cxx b/oox/source/drawingml/textbody.cxx index 1be15c4f885d..266ff44b22f9 100644 --- a/oox/source/drawingml/textbody.cxx +++ b/oox/source/drawingml/textbody.cxx @@ -65,7 +65,7 @@ void TextBody::insertAt( for (auto const& paragraph : maParagraphs) { paragraph->insertAt(rFilterBase, xText, xAt, rTextStyleProperties, aMasterTextStyle, - maTextListStyle, (nIndex == 0), nCharHeight, getTextProperties().mnFontScale); + maTextListStyle, (nIndex == 0), nCharHeight); ++nIndex; } } @@ -149,7 +149,7 @@ void TextBody::ApplyStyleEmpty( TextParagraphProperties aParaProp; aParaProp.apply(*pTextParagraphStyle); aParaProp.pushToPropSet(&rFilterBase, xProps, aioBulletList, &pTextParagraphStyle->getBulletList(), - true, nCharHeight, getTextProperties().mnFontScale, true); + true, nCharHeight, true); } } diff --git a/oox/source/drawingml/textparagraph.cxx b/oox/source/drawingml/textparagraph.cxx index f08efdbff3c3..e33cbb690ee9 100644 --- a/oox/source/drawingml/textparagraph.cxx +++ b/oox/source/drawingml/textparagraph.cxx @@ -88,7 +88,7 @@ void TextParagraph::insertAt( const TextCharacterProperties& rTextStyleProperties, const TextListStyle& rMasterTextListStyle, const TextListStyle& rTextListStyle, bool bFirst, - float nDefaultCharHeight, sal_Int32 nAutofitFontScale) const + float nDefaultCharHeight) const { try { sal_Int32 nParagraphSize = 0; @@ -176,7 +176,7 @@ void TextParagraph::insertAt( } float fCharacterSize = nCharHeight > 0 ? GetFontHeight ( nCharHeight ) : pTextParagraphStyle->getCharHeightPoints( 12 ); - aParaProp.pushToPropSet( &rFilterBase, xProps, aioBulletList, &pTextParagraphStyle->getBulletList(), true, fCharacterSize, nAutofitFontScale, true ); + aParaProp.pushToPropSet( &rFilterBase, xProps, aioBulletList, &pTextParagraphStyle->getBulletList(), true, fCharacterSize, true ); } // empty paragraphs do not have bullets in ppt diff --git a/oox/source/drawingml/textparagraphproperties.cxx b/oox/source/drawingml/textparagraphproperties.cxx index af65e0037d16..8122c4e53324 100644 --- a/oox/source/drawingml/textparagraphproperties.cxx +++ b/oox/source/drawingml/textparagraphproperties.cxx @@ -407,7 +407,7 @@ void TextParagraphProperties::apply( const TextParagraphProperties& rSourceProps void TextParagraphProperties::pushToPropSet( const ::oox::core::XmlFilterBase* pFilterBase, const Reference < XPropertySet >& xPropSet, PropertyMap& rioBulletMap, const BulletList* pMasterBuList, bool bApplyBulletMap, float fCharacterSize, - sal_Int32 nAutofitFontScale, bool bPushDefaultValues ) const + bool bPushDefaultValues ) const { PropertySet aPropSet( xPropSet ); aPropSet.setProperties( maTextParagraphPropertyMap ); @@ -433,14 +433,6 @@ void TextParagraphProperties::pushToPropSet( const ::oox::core::XmlFilterBase* p std::optional< sal_Int32 > noParaLeftMargin( moParaLeftMargin ); std::optional< sal_Int32 > noFirstLineIndentation( moFirstLineIndentation ); - // tdf#149961 Impress scales the indents when text is autofitted while Powerpoint doesn't - // Try to counteract this by multiplying indents by the inverse of the autofit font scale. - if ( nAutofitFontScale ) - { - if ( noParaLeftMargin ) noParaLeftMargin = *noParaLeftMargin * MAX_PERCENT / nAutofitFontScale; - if ( noFirstLineIndentation ) noFirstLineIndentation = *noFirstLineIndentation * MAX_PERCENT / nAutofitFontScale; - } - if ( nNumberingType != NumberingType::NUMBER_NONE ) { if ( noParaLeftMargin ) diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 5335dca58486..d610435d0eb2 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -3200,7 +3200,7 @@ void DrawingML::WriteLinespacing(const LineSpacing& rSpacing, float fFirstCharHe } } -bool DrawingML::WriteParagraphProperties(const Reference<XTextContent>& rParagraph, const Reference<XPropertySet>& rXShapePropSet, float fFirstCharHeight, sal_Int32 nElement) +bool DrawingML::WriteParagraphProperties(const Reference<XTextContent>& rParagraph, float fFirstCharHeight, sal_Int32 nElement) { Reference< XPropertySet > rXPropSet( rParagraph, UNO_QUERY ); Reference< XPropertyState > rXPropState( rParagraph, UNO_QUERY ); @@ -3294,24 +3294,6 @@ bool DrawingML::WriteParagraphProperties(const Reference<XTextContent>& rParagra if (GetProperty(rXPropSet, "ParaTabStopDefaultDistance")) mAny >>= nParaDefaultTabSize; - // for autofitted textboxes, scale the indents - if (GetProperty(rXShapePropSet, "TextFitToSize") && mAny.get<TextFitToSizeType>() == TextFitToSizeType_AUTOFIT) - { - SvxShapeText* pTextShape = dynamic_cast<SvxShapeText*>(rXShapePropSet.get()); - if (pTextShape) - { - SdrTextObj* pTextObject = DynCastSdrTextObj(pTextShape->GetSdrObject()); - if (pTextObject) - { - const auto nFontScaleY = pTextObject->GetFontScaleY(); - nLeftMargin = nLeftMargin * nFontScaleY / 100; - nLineIndentation = nLineIndentation * nFontScaleY / 100; - nParaLeftMargin = nParaLeftMargin * nFontScaleY / 100; - nParaFirstLineIndent = nParaFirstLineIndent * nFontScaleY / 100; - } - } - } - if (nParaLeftMargin) // For Paragraph mpFS->startElementNS( XML_a, nElement, XML_lvl, sax_fastparser::UseIf(OString::number(nLevel), nLevel > 0), @@ -3401,7 +3383,7 @@ void DrawingML::WriteLstStyles(const css::uno::Reference<css::text::XTextContent fFirstCharHeight = xFirstRunPropSet->getPropertyValue("CharHeight").get<float>(); mpFS->startElementNS(XML_a, XML_lstStyle); - if( !WriteParagraphProperties(rParagraph, rXShapePropSet, fFirstCharHeight, XML_lvl1pPr) ) + if( !WriteParagraphProperties(rParagraph, fFirstCharHeight, XML_lvl1pPr) ) mpFS->startElementNS(XML_a, XML_lvl1pPr); WriteRunProperties(xFirstRunPropSet, false, XML_defRPr, true, rbOverridingCharHeight, rnCharHeight, GetScriptType(rRun->getString()), rXShapePropSet); @@ -3443,7 +3425,7 @@ void DrawingML::WriteParagraph( const Reference< XTextContent >& rParagraph, rnCharHeight = 100 * fFirstCharHeight; rbOverridingCharHeight = true; } - WriteParagraphProperties(rParagraph, rXShapePropSet, fFirstCharHeight, XML_pPr); + WriteParagraphProperties(rParagraph, fFirstCharHeight, XML_pPr); bPropertiesWritten = true; } WriteRun( run, rbOverridingCharHeight, rnCharHeight, rXShapePropSet); @@ -3994,16 +3976,29 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo { const sal_Int32 MAX_SCALE_VAL = 100000; sal_Int32 nFontScale = MAX_SCALE_VAL; + sal_Int32 nSpacingReduction = 0; SvxShapeText* pTextShape = dynamic_cast<SvxShapeText*>(rXIface.get()); if (pTextShape) { SdrTextObj* pTextObject = DynCastSdrTextObj(pTextShape->GetSdrObject()); if (pTextObject) - nFontScale = pTextObject->GetFontScaleY() * 1000; + { + nFontScale = sal_Int32(pTextObject->GetFontScale() * 1000.0); + nSpacingReduction = sal_Int32((100.0 - pTextObject->GetSpacingScale()) * 1000.0); + } } - mpFS->singleElementNS(XML_a, XML_normAutofit, XML_fontScale, - sax_fastparser::UseIf(OString::number(nFontScale), nFontScale < MAX_SCALE_VAL && nFontScale > 0)); + bool bExportFontScale = false; + if (nFontScale < MAX_SCALE_VAL && nFontScale > 0) + bExportFontScale = true; + + bool bExportSpaceReduction = false; + if (nSpacingReduction < MAX_SCALE_VAL && nSpacingReduction > 0) + bExportSpaceReduction = true; + + mpFS->singleElementNS(XML_a, XML_normAutofit, + XML_fontScale, sax_fastparser::UseIf(OString::number(nFontScale), bExportFontScale), + XML_lnSpcReduction, sax_fastparser::UseIf(OString::number(nSpacingReduction), bExportSpaceReduction)); } else { @@ -4091,7 +4086,7 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo if( aAny >>= xParagraph ) { mpFS->startElementNS(XML_a, XML_p); - WriteParagraphProperties(xParagraph, rXPropSet, nCharHeight, XML_pPr); + WriteParagraphProperties(xParagraph, nCharHeight, XML_pPr); sal_Int16 nDummy = -1; WriteRunProperties(rXPropSet, false, XML_endParaRPr, false, bOverridingCharHeight, nCharHeight, nDummy, rXPropSet); diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx index b4d993a3c0c9..7d04d29886ec 100644 --- a/sd/qa/unit/export-tests-ooxml2.cxx +++ b/sd/qa/unit/export-tests-ooxml2.cxx @@ -1823,10 +1823,10 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testTextColumns_3columns) CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int32(300)), xColProps->getPropertyValue("AutomaticDistance")); // Scale value may be unstable; just test that the text is actually scaled - sal_Int16 nScale; - CPPUNIT_ASSERT(xProps->getPropertyValue("TextFitToSizeScale") >>= nScale); - CPPUNIT_ASSERT_GREATER(sal_Int16(0), nScale); - CPPUNIT_ASSERT_LESS(sal_Int16(100), nScale); + double fScale; + CPPUNIT_ASSERT(xProps->getPropertyValue("TextFitToSizeScale") >>= fScale); + CPPUNIT_ASSERT_GREATER(0.0, fScale); + CPPUNIT_ASSERT_LESS(100.0, fScale); } save("Impress Office Open XML"); @@ -1843,10 +1843,10 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testTextColumns_3columns) CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int32(300)), xColProps->getPropertyValue("AutomaticDistance")); // Scale value may be unstable; just test that the text is actually scaled - sal_Int16 nScale; - CPPUNIT_ASSERT(xProps->getPropertyValue("TextFitToSizeScale") >>= nScale); - CPPUNIT_ASSERT_GREATER(sal_Int16(0), nScale); - CPPUNIT_ASSERT_LESS(sal_Int16(100), nScale); + double fScale; + CPPUNIT_ASSERT(xProps->getPropertyValue("TextFitToSizeScale") >>= fScale); + CPPUNIT_ASSERT_GREATER(0.0, fScale); + CPPUNIT_ASSERT_LESS(100.0, fScale); } xmlDocUniquePtr pXmlDocRels = parseExport("ppt/slides/slide1.xml"); diff --git a/sd/qa/unit/export-tests-ooxml3.cxx b/sd/qa/unit/export-tests-ooxml3.cxx index ccbfc6e35335..3931c53b912b 100644 --- a/sd/qa/unit/export-tests-ooxml3.cxx +++ b/sd/qa/unit/export-tests-ooxml3.cxx @@ -233,7 +233,7 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testFontScale) // Rounding errors possible, approximate value (+/- 1%) OUString sScale = getXPath( pXmlDocContent, "/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:bodyPr/a:normAutofit", "fontScale"); - CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(76000), sScale.toInt32(), 1000); + CPPUNIT_ASSERT_DOUBLES_EQUAL(sal_Int32(81111), sScale.toInt32(), 1000); } CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testShapeAutofitPPTX) @@ -1914,15 +1914,12 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testAutofittedTextboxIndent) save("Impress Office Open XML"); - // Without the accompanying fix in place, these tests would have failed with: - // - Expected: 691200 - // - Actual : 1080000 - // i.e. paragraph indent wasn't scaled proportionally to autofitted textbox - // font scale on export + // Check that the indent hasn't changed and wasn't scaled when exporting + // (the behaviour changed). xmlDocUniquePtr pXmlDocContent1 = parseExport("ppt/slides/slide1.xml"); assertXPath(pXmlDocContent1, "/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p[1]/a:pPr", "marL", - "712800"); + "1080000"); } CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest3, testTdf151622_oleIcon) diff --git a/sd/qa/unit/import-tests-smartart.cxx b/sd/qa/unit/import-tests-smartart.cxx index 895ca7f03211..049a64eb0193 100644 --- a/sd/qa/unit/import-tests-smartart.cxx +++ b/sd/qa/unit/import-tests-smartart.cxx @@ -1528,13 +1528,13 @@ CPPUNIT_TEST_FIXTURE(SdImportTestSmartArt, testAutofitSync) uno::Reference<drawing::XShape> xMiddle = getChildShape(xDiagram, 2); uno::Reference<beans::XPropertySet> xFirstInner(getChildShape(getChildShape(xMiddle, 0), 0), uno::UNO_QUERY); - sal_Int16 nFirstScale = 0; + double nFirstScale = 0; CPPUNIT_ASSERT(xFirstInner->getPropertyValue("TextFitToSizeScale") >>= nFirstScale); - CPPUNIT_ASSERT_GREATER(static_cast<sal_Int16>(0), nFirstScale); - CPPUNIT_ASSERT_LESS(static_cast<sal_Int16>(100), nFirstScale); + CPPUNIT_ASSERT_GREATER(0.0, nFirstScale); + CPPUNIT_ASSERT_LESS(100.0, nFirstScale); uno::Reference<beans::XPropertySet> xSecondInner(getChildShape(getChildShape(xMiddle, 2), 0), uno::UNO_QUERY); - sal_Int16 nSecondScale = 0; + double nSecondScale = 0; CPPUNIT_ASSERT(xSecondInner->getPropertyValue("TextFitToSizeScale") >>= nSecondScale); // Without the accompanying fix in place, this test would have failed with: diff --git a/sd/qa/unit/import-tests2.cxx b/sd/qa/unit/import-tests2.cxx index 9d44f11552d8..e585673e3ad8 100644 --- a/sd/qa/unit/import-tests2.cxx +++ b/sd/qa/unit/import-tests2.cxx @@ -1343,8 +1343,10 @@ CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf120028) double fCharHeight = 0; xPropSet->getPropertyValue("CharHeight") >>= fCharHeight; CPPUNIT_ASSERT_DOUBLES_EQUAL(13.5, fCharHeight, 1E-12); - // 13.5 * 90% is approx. 12.1 (the correct scaled font size) - CPPUNIT_ASSERT_EQUAL(uno::Any(sal_Int16(90)), xShape->getPropertyValue("TextFitToSizeScale")); + + double fTextSclale = 0.0; + xShape->getPropertyValue("TextFitToSizeScale") >>= fTextSclale; + CPPUNIT_ASSERT_DOUBLES_EQUAL(92.0, fTextSclale, 1E1); } CPPUNIT_TEST_FIXTURE(SdImportTest2, testDescriptionImport) @@ -1845,11 +1847,9 @@ CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf149961AutofitIndentation) const SvxNumBulletItem* pNumFmt = aEdit.GetParaAttribs(0).GetItem(EE_PARA_NUMBULLET); CPPUNIT_ASSERT(pNumFmt); - // Without the accompanying fix in place, this test would have failed with: - // - Expected: 12700 - // - Actual : 3175 - CPPUNIT_ASSERT_EQUAL(sal_Int32(12700), pNumFmt->GetNumRule().GetLevel(0).GetAbsLSpace()); - CPPUNIT_ASSERT_EQUAL(sal_Int32(-12700), + // Spacing doesn't change when it is scaled + CPPUNIT_ASSERT_EQUAL(sal_Int32(3175), pNumFmt->GetNumRule().GetLevel(0).GetAbsLSpace()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-3175), pNumFmt->GetNumRule().GetLevel(0).GetFirstLineOffset()); } } diff --git a/sd/source/ui/view/drtxtob.cxx b/sd/source/ui/view/drtxtob.cxx index d8503d0412f7..a7204b992ed8 100644 --- a/sd/source/ui/view/drtxtob.cxx +++ b/sd/source/ui/view/drtxtob.cxx @@ -46,6 +46,7 @@ #include <editeng/writingmodeitem.hxx> #include <editeng/frmdiritem.hxx> #include <editeng/fhgtitem.hxx> +#include <o3tl/temporary.hxx> #include <sfx2/objface.hxx> @@ -165,7 +166,7 @@ void TextObjectBar::GetAttrState( SfxItemSet& rSet ) case SID_ATTR_CHAR_STRIKEOUT: case SID_ATTR_CHAR_CASEMAP: { - double stretchX = 100.0; + double stretchY = 100.0; SvxScriptSetItem aSetItem( nSlotId, GetPool() ); aSetItem.GetItemSet().Put( aAttrSet, false ); @@ -183,9 +184,8 @@ void TextObjectBar::GetAttrState( SfxItemSet& rSet ) if (OutlineView* pOView = dynamic_cast<OutlineView*>(mpView)) pOLV = pOView->GetViewByWindow(mpViewShell->GetActiveWindow()); - double stretchY = 100.0; - if( pOutliner ) - pOutliner->GetGlobalCharStretching(stretchX, stretchY); + if (pOutliner) + pOutliner->getGlobalScale(o3tl::temporary(double()), stretchY, o3tl::temporary(double()), o3tl::temporary(double())); if(pOLV && !pOLV->GetSelection().HasRange()) { @@ -204,7 +204,7 @@ void TextObjectBar::GetAttrState( SfxItemSet& rSet ) if( nSlotId == SID_ATTR_CHAR_FONTHEIGHT ) { SvxFontHeightItem aFontItem = dynamic_cast<const SvxFontHeightItem&>(*pI); - aFontItem.SetHeight(aFontItem.GetHeight(), stretchX, aFontItem.GetPropUnit()); + aFontItem.SetHeight(aFontItem.GetHeight() * (stretchY / 100.0), 100, aFontItem.GetPropUnit()); aFontItem.SetWhich(nWhich); aAttrSet.Put( aFontItem ); } diff --git a/svx/source/svdraw/svdotext.cxx b/svx/source/svdraw/svdotext.cxx index 20e54ca976ac..65f1dab7db65 100644 --- a/svx/source/svdraw/svdotext.cxx +++ b/svx/source/svdraw/svdotext.cxx @@ -43,6 +43,7 @@ #include <svx/sdtfsitm.hxx> #include <svx/sdtmfitm.hxx> #include <svx/xtextit0.hxx> +#include <svx/compatflags.hxx> #include <sdr/properties/textproperties.hxx> #include <sdr/contact/viewcontactoftextobj.hxx> #include <basegfx/tuple/b2dtuple.hxx> @@ -51,8 +52,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; @@ -908,6 +912,9 @@ void SdrTextObj::ImpSetCharStretching(SdrOutliner& rOutliner, const Size& rTextS } #endif } + + rOutliner.setRoundFontSizeToPt(false); + unsigned nLoopCount=0; bool bNoMoreLoop = false; tools::Long nXDiff0=0x7FFFFFFF; @@ -982,7 +989,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; @@ -1172,7 +1179,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); @@ -1230,15 +1238,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 @@ -1253,6 +1272,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 @@ -1260,6 +1285,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(); @@ -1283,7 +1309,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) { @@ -1302,20 +1328,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 ad6edb104e01..ddbc6bfe540a 100644 --- a/svx/source/svdraw/svdotextdecomposition.cxx +++ b/svx/source/svdraw/svdotextdecomposition.cxx @@ -1226,7 +1226,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 5e89f5d42874..94f73bfbf206 100644 --- a/svx/source/svdraw/svdoutl.cxx +++ b/svx/source/svdraw/svdoutl.cxx @@ -50,7 +50,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 4ee178c5e58a..85cd6045a234 100644 --- a/svx/source/unodraw/unoshape.cxx +++ b/svx/source/unodraw/unoshape.cxx @@ -173,7 +173,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 = DynCastSdrTextObj(pObject); if (!pTextObj) @@ -188,7 +188,7 @@ sal_Int16 GetTextFitToSizeScale(SdrObject* pObject) return 0; } - return pTextObj->GetFontScaleY(); + return pTextObj->GetFontScale(); } } @@ -2361,7 +2361,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(pSdrObject->GetMergedItem(SDRATTR_TEXT_FITTOSIZE)); @@ -2871,7 +2871,8 @@ bool SvxShape::getPropertyValueImpl( const OUString&, const SfxItemPropertyMapEn case OWN_ATTR_TEXTFITTOSIZESCALE: { - rValue <<= GetTextFitToSizeScale(GetSdrObject()); + double nScale = GetTextFitToSizeScale(GetSdrObject()); + rValue <<= nScale; break; } |