summaryrefslogtreecommitdiff
path: root/editeng/source/editeng/impedit3.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'editeng/source/editeng/impedit3.cxx')
-rw-r--r--editeng/source/editeng/impedit3.cxx1946
1 files changed, 1172 insertions, 774 deletions
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 9281f4d7dcf2..72bc2022b1ea 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -24,6 +24,7 @@
#include <vcl/settings.hxx>
#include <vcl/window.hxx>
+#include <editeng/outliner.hxx>
#include <editeng/tstpitem.hxx>
#include <editeng/lspcitem.hxx>
#include <editeng/flditem.hxx>
@@ -41,18 +42,24 @@
#include <editeng/wghtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/langitem.hxx>
+#include <editeng/frmdiritem.hxx>
#include <editeng/scriptspaceitem.hxx>
#include <editeng/charscaleitem.hxx>
#include <editeng/numitem.hxx>
+#include <outleeng.hxx>
+#include <TextPortion.hxx>
#include <svtools/colorcfg.hxx>
#include <svl/ctloptions.hxx>
#include <svl/asiancfg.hxx>
+#include <svx/compatflags.hxx>
+#include <sfx2/viewsh.hxx>
+
#include <editeng/hngpnctitem.hxx>
#include <editeng/forbiddencharacterstable.hxx>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <math.h>
#include <vcl/metric.hxx>
@@ -63,23 +70,27 @@
#include <i18nlangtag/mslangid.hxx>
#include <comphelper/processfactory.hxx>
+#include <comphelper/lok.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/sorted_vector.hxx>
#include <osl/diagnose.h>
#include <comphelper/string.hxx>
+#include <cstddef>
#include <memory>
#include <set>
#include <vcl/outdev/ScopedStates.hxx>
+#include <unicode/uchar.h>
+
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::linguistic2;
-constexpr OUStringLiteral CH_HYPH = u"-";
+constexpr OUString CH_HYPH = u"-"_ustr;
constexpr tools::Long WRONG_SHOW_MIN = 5;
@@ -105,42 +116,22 @@ struct TabInfo
}
-Point Rotate( const Point& rPoint, Degree10 nOrientation, const Point& rOrigin )
-{
- double nRealOrientation = nOrientation.get() * F_PI1800;
- double nCos = cos( nRealOrientation );
- double nSin = sin( nRealOrientation );
-
- Point aRotatedPos;
- Point aTranslatedPos( rPoint );
-
- // Translation
- aTranslatedPos -= rOrigin;
-
- // Rotation...
- aRotatedPos.setX( static_cast<tools::Long>( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() ) );
- aRotatedPos.setY( static_cast<tools::Long>(- ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() )) );
- aTranslatedPos = aRotatedPos;
-
- // Translation...
- aTranslatedPos += rOrigin;
- return aTranslatedPos;
-}
-
AsianCompressionFlags GetCharTypeForCompression( sal_Unicode cChar )
{
switch ( cChar )
{
case 0x3008: case 0x300A: case 0x300C: case 0x300E:
case 0x3010: case 0x3014: case 0x3016: case 0x3018:
- case 0x301A: case 0x301D:
+ case 0x301A: case 0x301D: case 0xFF09: case 0xFF3D:
+ case 0xFF5D:
{
return AsianCompressionFlags::PunctuationRight;
}
case 0x3001: case 0x3002: case 0x3009: case 0x300B:
case 0x300D: case 0x300F: case 0x3011: case 0x3015:
case 0x3017: case 0x3019: case 0x301B: case 0x301E:
- case 0x301F:
+ case 0x301F: case 0xFF08: case 0xFF0C: case 0xFF0E:
+ case 0xFF1A: case 0xFF1B: case 0xFF3B: case 0xFF5B:
{
return AsianCompressionFlags::PunctuationLeft;
}
@@ -156,7 +147,7 @@ static void lcl_DrawRedLines( OutputDevice& rOutDev,
const Point& rPoint,
size_t nIndex,
size_t nMaxEnd,
- const tools::Long* pDXArray,
+ std::span<const sal_Int32> pDXArray,
WrongList const * pWrongs,
Degree10 nOrientation,
const Point& rOrigin,
@@ -220,8 +211,8 @@ static void lcl_DrawRedLines( OutputDevice& rOutDev,
if (nOrientation)
{
- aPoint1 = Rotate(aPoint1, nOrientation, rOrigin);
- aPoint2 = Rotate(aPoint2, nOrientation, rOrigin);
+ rOrigin.RotateAround(aPoint1, nOrientation);
+ rOrigin.RotateAround(aPoint2, nOrientation);
}
{
@@ -237,35 +228,83 @@ static void lcl_DrawRedLines( OutputDevice& rOutDev,
}
}
-static Point lcl_ImplCalcRotatedPos( Point rPos, Point rOrigin, double nSin, double nCos )
+// For Kashidas from sw/source/core/text/porlay.cxx
+
+#define IS_JOINING_GROUP(c, g) ( u_getIntPropertyValue( (c), UCHAR_JOINING_GROUP ) == U_JG_##g )
+#define isAinChar(c) IS_JOINING_GROUP((c), AIN)
+#define isAlefChar(c) IS_JOINING_GROUP((c), ALEF)
+#define isDalChar(c) IS_JOINING_GROUP((c), DAL)
+#define isFehChar(c) (IS_JOINING_GROUP((c), FEH) || IS_JOINING_GROUP((c), AFRICAN_FEH))
+#define isGafChar(c) IS_JOINING_GROUP((c), GAF)
+#define isHehChar(c) IS_JOINING_GROUP((c), HEH)
+#define isKafChar(c) IS_JOINING_GROUP((c), KAF)
+#define isLamChar(c) IS_JOINING_GROUP((c), LAM)
+#define isQafChar(c) (IS_JOINING_GROUP((c), QAF) || IS_JOINING_GROUP((c), AFRICAN_QAF))
+#define isRehChar(c) IS_JOINING_GROUP((c), REH)
+#define isTahChar(c) IS_JOINING_GROUP((c), TAH)
+#define isTehMarbutaChar(c) IS_JOINING_GROUP((c), TEH_MARBUTA)
+#define isWawChar(c) IS_JOINING_GROUP((c), WAW)
+#define isSeenOrSadChar(c) (IS_JOINING_GROUP((c), SAD) || IS_JOINING_GROUP((c), SEEN))
+
+// Beh and characters that behave like Beh in medial form.
+static bool isBehChar(sal_Unicode cCh)
{
- Point aRotatedPos;
- // Translation...
- Point aTranslatedPos( rPos);
- aTranslatedPos -= rOrigin;
-
- aRotatedPos.setX( static_cast<tools::Long>( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() ) );
- aRotatedPos.setY( static_cast<tools::Long>(- ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() )) );
- aTranslatedPos = aRotatedPos;
- // Translation...
- aTranslatedPos += rOrigin;
-
- return aTranslatedPos;
+ bool bRet = false;
+ switch (u_getIntPropertyValue(cCh, UCHAR_JOINING_GROUP))
+ {
+ case U_JG_BEH:
+ case U_JG_NOON:
+ case U_JG_AFRICAN_NOON:
+ case U_JG_NYA:
+ case U_JG_YEH:
+ case U_JG_FARSI_YEH:
+ case U_JG_BURUSHASKI_YEH_BARREE:
+ bRet = true;
+ break;
+ default:
+ bRet = false;
+ break;
+ }
+
+ return bRet;
}
-static bool lcl_IsLigature( sal_Unicode cCh, sal_Unicode cNextCh ) // For Kashidas from sw/source/core/text/porlay.txt
+// Yeh and characters that behave like Yeh in final form.
+static bool isYehChar(sal_Unicode cCh)
+{
+ bool bRet = false;
+ switch (u_getIntPropertyValue(cCh, UCHAR_JOINING_GROUP))
+ {
+ case U_JG_YEH:
+ case U_JG_FARSI_YEH:
+ case U_JG_YEH_BARREE:
+ case U_JG_BURUSHASKI_YEH_BARREE:
+ case U_JG_YEH_WITH_TAIL:
+ bRet = true;
+ break;
+ default:
+ bRet = false;
+ break;
+ }
+
+ return bRet;
+}
+
+static bool isTransparentChar ( sal_Unicode cCh )
+{
+ return u_getIntPropertyValue( cCh, UCHAR_JOINING_TYPE ) == U_JT_TRANSPARENT;
+}
+
+static bool lcl_IsLigature( sal_Unicode cCh, sal_Unicode cNextCh )
{
// Lam + Alef
- return ( 0x644 == cCh && 0x627 == cNextCh ) ||
- // Beh + Reh
- ( 0x628 == cCh && 0x631 == cNextCh );
+ return ( isLamChar ( cCh ) && isAlefChar ( cNextCh ));
}
-static bool lcl_ConnectToPrev( sal_Unicode cCh, sal_Unicode cPrevCh ) // For Kashidas from sw/source/core/text/porlay.txt
+static bool lcl_ConnectToPrev( sal_Unicode cCh, sal_Unicode cPrevCh )
{
- // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left
- bool bRet = 0x627 != cPrevCh && 0x62F != cPrevCh && 0x630 != cPrevCh &&
- 0x631 != cPrevCh && 0x632 != cPrevCh && 0x648 != cPrevCh;
+ const int32_t nJoiningType = u_getIntPropertyValue( cPrevCh, UCHAR_JOINING_TYPE );
+ bool bRet = nJoiningType != U_JT_RIGHT_JOINING && nJoiningType != U_JT_NON_JOINING;
// check for ligatures cPrevChar + cChar
if ( bRet )
@@ -278,23 +317,23 @@ static bool lcl_ConnectToPrev( sal_Unicode cCh, sal_Unicode cPrevCh ) // For Ka
void ImpEditEngine::UpdateViews( EditView* pCurView )
{
- if ( !IsUpdateLayout() || IsFormatting() || aInvalidRect.IsEmpty() )
+ if ( !IsUpdateLayout() || IsFormatting() || maInvalidRect.IsEmpty() )
return;
DBG_ASSERT( IsFormatted(), "UpdateViews: Doc not formatted!" );
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
pView->HideCursor();
- tools::Rectangle aClipRect( aInvalidRect );
+ tools::Rectangle aClipRect(maInvalidRect);
tools::Rectangle aVisArea( pView->GetVisArea() );
aClipRect.Intersection( aVisArea );
if ( !aClipRect.IsEmpty() )
{
// convert to window coordinates...
- aClipRect = pView->pImpEditView->GetWindowPos( aClipRect );
+ aClipRect = pView->getImpl().GetWindowPos( aClipRect );
// moved to one executing method to allow finer control
pView->InvalidateWindow(aClipRect);
@@ -305,11 +344,11 @@ void ImpEditEngine::UpdateViews( EditView* pCurView )
if ( pCurView )
{
- bool bGotoCursor = pCurView->pImpEditView->DoAutoScroll();
+ bool bGotoCursor = pCurView->getImpl().DoAutoScroll();
pCurView->ShowCursor( bGotoCursor );
}
- aInvalidRect = tools::Rectangle();
+ maInvalidRect = tools::Rectangle();
CallStatusHdl();
}
@@ -318,18 +357,18 @@ IMPL_LINK_NOARG(ImpEditEngine, OnlineSpellHdl, Timer *, void)
if ( !Application::AnyInput( VclInputFlags::KEYBOARD ) && IsUpdateLayout() && IsFormatted() )
DoOnlineSpelling();
else
- aOnlineSpellTimer.Start();
+ maOnlineSpellTimer.Start();
}
IMPL_LINK_NOARG(ImpEditEngine, IdleFormatHdl, Timer *, void)
{
- aIdleFormatter.ResetRestarts();
+ maIdleFormatter.ResetRestarts();
// #i97146# check if that view is still available
// else probably the idle format timer fired while we're already
// downing
- EditView* pView = aIdleFormatter.GetView();
- for (EditView* aEditView : aEditViews)
+ EditView* pView = maIdleFormatter.GetView();
+ for (EditView* aEditView : maEditViews)
{
if( aEditView == pView )
{
@@ -341,7 +380,7 @@ IMPL_LINK_NOARG(ImpEditEngine, IdleFormatHdl, Timer *, void)
void ImpEditEngine::CheckIdleFormatter()
{
- aIdleFormatter.ForceTimeout();
+ maIdleFormatter.ForceTimeout();
// If not idle, but still not formatted:
if ( !IsFormatted() )
FormatDoc();
@@ -355,186 +394,218 @@ bool ImpEditEngine::IsPageOverflow( ) const
void ImpEditEngine::FormatFullDoc()
{
- for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
- GetParaPortions()[nPortion].MarkSelectionInvalid( 0 );
+ GetParaPortions().MarkAllSelectionsInvalid(0);
FormatDoc();
}
-void ImpEditEngine::FormatDoc()
+tools::Long ImpEditEngine::FormatParagraphs(o3tl::sorted_vector<sal_Int32>& aRepaintParagraphList)
{
- if (!IsUpdateLayout() || IsFormatting())
- return;
-
- bIsFormatting = true;
-
- // Then I can also start the spell-timer...
- if ( GetStatus().DoOnlineSpelling() )
- StartOnlineSpellTimer();
-
+ sal_Int32 nParaCount = GetParaPortions().Count();
tools::Long nY = 0;
bool bGrow = false;
- // Here already, so that not always in CreateLines...
- bool bMapChanged = ImpCheckRefMapMode();
- std::set<sal_Int32> aRepaintParas;
-
- for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
+ for (sal_Int32 nParagraph = 0; nParagraph < nParaCount; nParagraph++)
{
- ParaPortion& rParaPortion = GetParaPortions()[nPara];
- if ( rParaPortion.MustRepaint() || ( rParaPortion.IsInvalid() && rParaPortion.IsVisible() ) )
+ ParaPortion& rParaPortion = GetParaPortions().getRef(nParagraph);
+ if (rParaPortion.MustRepaint() || (rParaPortion.IsInvalid() && rParaPortion.IsVisible()))
{
// No formatting should be necessary for MustRepaint()!
- if ( !rParaPortion.IsInvalid() || CreateLines( nPara, nY ) )
+ if (CreateLines(nParagraph, nY))
{
- if ( !bGrow && GetTextRanger() )
+ if (!bGrow && GetTextRanger())
{
// For a change in height all below must be reformatted...
- for ( sal_Int32 n = nPara+1; n < GetParaPortions().Count(); n++ )
+ for (sal_Int32 n = nParagraph + 1; n < nParaCount; n++)
{
- ParaPortion& rPP = GetParaPortions()[n];
- rPP.MarkSelectionInvalid( 0 );
- rPP.GetLines().Reset();
+ ParaPortion& rParaPortionToInvalidate = GetParaPortions().getRef(n);
+ rParaPortionToInvalidate.MarkSelectionInvalid(0);
+ rParaPortionToInvalidate.GetLines().Reset();
}
}
bGrow = true;
- if ( IsCallParaInsertedOrDeleted() )
+ if (IsCallParaInsertedOrDeleted())
{
- GetEditEnginePtr()->ParagraphHeightChanged( nPara );
+ GetEditEnginePtr()->ParagraphHeightChanged(nParagraph);
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
- ImpEditView* pImpView = pView->pImpEditView.get();
- pImpView->ScrollStateChange();
+ pView->getImpl().ScrollStateChange();
}
}
- rParaPortion.SetMustRepaint( false );
+ rParaPortion.SetMustRepaint(false);
}
- aRepaintParas.insert(nPara);
+ aRepaintParagraphList.insert(nParagraph);
}
nY += rParaPortion.GetHeight();
}
+ return nY;
+}
+
+namespace
+{
+constexpr std::array<ScalingParameters, 13> constScaleLevels =
+{
+ ScalingParameters{ 1.000, 1.000, 1.0, 0.9 },
+ ScalingParameters{ 0.925, 0.925, 1.0, 0.9 },
+ ScalingParameters{ 0.925, 0.925, 1.0, 0.8 },
+ ScalingParameters{ 0.850, 0.850, 1.0, 0.9 },
+ ScalingParameters{ 0.850, 0.850, 1.0, 0.8 },
+ ScalingParameters{ 0.775, 0.775, 1.0, 0.8 },
+ ScalingParameters{ 0.700, 0.700, 1.0, 0.8 },
+ ScalingParameters{ 0.625, 0.625, 1.0, 0.8 },
+ ScalingParameters{ 0.550, 0.550, 1.0, 0.8 },
+ ScalingParameters{ 0.475, 0.475, 1.0, 0.8 },
+ ScalingParameters{ 0.400, 0.400, 1.0, 0.8 },
+ ScalingParameters{ 0.325, 0.325, 1.0, 0.8 },
+ ScalingParameters{ 0.250, 0.250, 1.0, 0.8 },
+};
+
+} // end anonymous ns
+
+void ImpEditEngine::ScaleContentToFitWindow(o3tl::sorted_vector<sal_Int32>& aRepaintParagraphList)
+{
+ if (!maCustomScalingParameters.areValuesDefault())
+ maScalingParameters = maCustomScalingParameters;
+
+ tools::Long nHeight = FormatParagraphs(aRepaintParagraphList);
+ bool bOverflow = nHeight > (maMaxAutoPaperSize.Height() * mnColumns);
+
+ size_t nCurrentScaleLevel = 0;
+ while (bOverflow && nCurrentScaleLevel < constScaleLevels.size())
+ {
+ // Clean-up and reset paragraphs
+ aRepaintParagraphList.clear();
+ for (auto& pParaPortionToInvalidate : GetParaPortions())
+ {
+ pParaPortionToInvalidate->GetLines().Reset();
+ pParaPortionToInvalidate->MarkSelectionInvalid(0);
+ pParaPortionToInvalidate->SetMustRepaint(true);
+ }
+
+ // Get new scaling parameters
+ maScalingParameters = constScaleLevels[nCurrentScaleLevel];
+
+ // Try again with different scaling factor
+ nHeight = FormatParagraphs(aRepaintParagraphList);
+ bOverflow = nHeight > (maMaxAutoPaperSize.Height() * mnColumns);
+
+ // Increase scale level
+ nCurrentScaleLevel++;
+ }
+}
- aInvalidRect = tools::Rectangle(); // make empty
+void ImpEditEngine::FormatDoc()
+{
+ if (!IsUpdateLayout() || IsFormatting())
+ return;
+
+ mbIsFormatting = true;
+
+ // Then I can also start the spell-timer...
+ if (GetStatus().DoOnlineSpelling())
+ StartOnlineSpellTimer();
+
+ // Reserve, as it should match the current number of paragraphs
+ o3tl::sorted_vector<sal_Int32> aRepaintParagraphList;
+ aRepaintParagraphList.reserve(GetParaPortions().Count());
+
+ if (maStatus.DoStretch())
+ ScaleContentToFitWindow(aRepaintParagraphList);
+ else
+ FormatParagraphs(aRepaintParagraphList);
+
+ maInvalidRect = tools::Rectangle(); // make empty
// One can also get into the formatting through UpdateMode ON=>OFF=>ON...
// enable optimization first after Vobis delivery...
{
tools::Long nNewHeightNTP;
tools::Long nNewHeight = CalcTextHeight(&nNewHeightNTP);
- tools::Long nDiff = nNewHeight - nCurTextHeight;
+ tools::Long nDiff = nNewHeight - mnCurTextHeight;
if ( nDiff )
- aStatus.GetStatusWord() |= !IsEffectivelyVertical() ? EditStatusFlags::TextHeightChanged : EditStatusFlags::TEXTWIDTHCHANGED;
+ {
+ maInvalidRect.Union(tools::Rectangle::Normalize(
+ { 0, nNewHeight }, { getWidthDirectionAware(maPaperSize), mnCurTextHeight }));
+ maStatus.GetStatusWord() |= !IsEffectivelyVertical() ? EditStatusFlags::TextHeightChanged : EditStatusFlags::TEXTWIDTHCHANGED;
+ }
- nCurTextHeight = nNewHeight;
- nCurTextHeightNTP = nNewHeightNTP;
+ mnCurTextHeight = nNewHeight;
+ mnCurTextHeightNTP = nNewHeightNTP;
- if ( aStatus.AutoPageSize() )
+ if ( maStatus.AutoPageSize() )
CheckAutoPageSize();
else if ( nDiff )
{
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
- ImpEditView* pImpView = pView->pImpEditView.get();
- if ( pImpView->DoAutoHeight() )
+ ImpEditView& rImpView = pView->getImpl();
+ if (rImpView.DoAutoHeight())
{
- Size aSz( pImpView->GetOutputArea().GetWidth(), nCurTextHeight );
- if ( aSz.Height() > aMaxAutoPaperSize.Height() )
- aSz.setHeight( aMaxAutoPaperSize.Height() );
- else if ( aSz.Height() < aMinAutoPaperSize.Height() )
- aSz.setHeight( aMinAutoPaperSize.Height() );
- pImpView->ResetOutputArea( tools::Rectangle(
- pImpView->GetOutputArea().TopLeft(), aSz ) );
+ Size aSz(rImpView.GetOutputArea().GetWidth(), mnCurTextHeight);
+ if ( aSz.Height() > maMaxAutoPaperSize.Height() )
+ aSz.setHeight( maMaxAutoPaperSize.Height() );
+ else if ( aSz.Height() < maMinAutoPaperSize.Height() )
+ aSz.setHeight( maMinAutoPaperSize.Height() );
+ rImpView.ResetOutputArea( tools::Rectangle(rImpView.GetOutputArea().TopLeft(), aSz));
}
}
}
- if (nDiff)
- aInvalidRect.Union(tools::Rectangle::Justify(
- { 0, nNewHeight }, { getWidthDirectionAware(aPaperSize), nCurTextHeight }));
-
- if (!aRepaintParas.empty())
+ if (!aRepaintParagraphList.empty())
{
auto CombineRepaintParasAreas = [&](const LineAreaInfo& rInfo) {
- if (aRepaintParas.count(rInfo.nPortion))
- aInvalidRect.Union(rInfo.aArea);
+ if (aRepaintParagraphList.count(rInfo.nPortion))
+ maInvalidRect.Union(rInfo.aArea);
return CallbackResult::Continue;
};
IterateLineAreas(CombineRepaintParasAreas, IterFlag::inclILS);
}
}
- bIsFormatting = false;
- bFormatted = true;
-
- if ( bMapChanged )
- GetRefDevice()->Pop();
+ mbIsFormatting = false;
+ mbFormatted = true;
CallStatusHdl(); // If Modified...
}
-bool ImpEditEngine::ImpCheckRefMapMode()
-{
- bool bChange = false;
-
- if ( aStatus.DoFormat100() )
- {
- MapMode aMapMode( GetRefDevice()->GetMapMode() );
- if ( aMapMode.GetScaleX().GetNumerator() != aMapMode.GetScaleX().GetDenominator() )
- bChange = true;
- else if ( aMapMode.GetScaleY().GetNumerator() != aMapMode.GetScaleY().GetDenominator() )
- bChange = true;
-
- if ( bChange )
- {
- Fraction Scale1( 1, 1 );
- aMapMode.SetScaleX( Scale1 );
- aMapMode.SetScaleY( Scale1 );
- GetRefDevice()->Push();
- GetRefDevice()->SetMapMode( aMapMode );
- }
- }
-
- return bChange;
-}
-
void ImpEditEngine::CheckAutoPageSize()
{
Size aPrevPaperSize( GetPaperSize() );
if ( GetStatus().AutoPageWidth() )
- aPaperSize.setWidth( !IsEffectivelyVertical() ? CalcTextWidth( true ) : GetTextHeight() );
+ maPaperSize.setWidth( !IsEffectivelyVertical() ? CalcTextWidth( true ) : GetTextHeight() );
if ( GetStatus().AutoPageHeight() )
- aPaperSize.setHeight( !IsEffectivelyVertical() ? GetTextHeight() : CalcTextWidth( true ) );
+ maPaperSize.setHeight( !IsEffectivelyVertical() ? GetTextHeight() : CalcTextWidth( true ) );
- SetValidPaperSize( aPaperSize ); // consider Min, Max
+ SetValidPaperSize( maPaperSize ); // consider Min, Max
- if ( aPaperSize == aPrevPaperSize )
+ if ( maPaperSize == aPrevPaperSize )
return;
- if ( ( !IsEffectivelyVertical() && ( aPaperSize.Width() != aPrevPaperSize.Width() ) )
- || ( IsEffectivelyVertical() && ( aPaperSize.Height() != aPrevPaperSize.Height() ) ) )
+ if ( ( !IsEffectivelyVertical() && ( maPaperSize.Width() != aPrevPaperSize.Width() ) )
+ || ( IsEffectivelyVertical() && ( maPaperSize.Height() != aPrevPaperSize.Height() ) ) )
{
// If ahead is centered / right or tabs...
- aStatus.GetStatusWord() |= !IsEffectivelyVertical() ? EditStatusFlags::TEXTWIDTHCHANGED : EditStatusFlags::TextHeightChanged;
+ maStatus.GetStatusWord() |= !IsEffectivelyVertical() ? EditStatusFlags::TEXTWIDTHCHANGED : EditStatusFlags::TextHeightChanged;
for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
{
// Only paragraphs which are not aligned to the left need to be
// reformatted, the height can not be changed here anymore.
- ParaPortion& rParaPortion = GetParaPortions()[nPara];
+ ParaPortion& rParaPortion = GetParaPortions().getRef(nPara);
SvxAdjust eJustification = GetJustification( nPara );
if ( eJustification != SvxAdjust::Left )
{
- rParaPortion.MarkSelectionInvalid( 0 );
+ rParaPortion.MarkSelectionInvalid(0);
CreateLines( nPara, 0 ); // 0: For AutoPageSize no TextRange!
}
}
}
- Size aInvSize = aPaperSize;
- if ( aPaperSize.Width() < aPrevPaperSize.Width() )
+ Size aInvSize = maPaperSize;
+ if ( maPaperSize.Width() < aPrevPaperSize.Width() )
aInvSize.setWidth( aPrevPaperSize.Width() );
- if ( aPaperSize.Height() < aPrevPaperSize.Height() )
+ if ( maPaperSize.Height() < aPrevPaperSize.Height() )
aInvSize.setHeight( aPrevPaperSize.Height() );
Size aSz( aInvSize );
@@ -543,18 +614,18 @@ void ImpEditEngine::CheckAutoPageSize()
aSz.setWidth( aInvSize.Height() );
aSz.setHeight( aInvSize.Width() );
}
- aInvalidRect = tools::Rectangle( Point(), aSz );
+ maInvalidRect = tools::Rectangle( Point(), aSz );
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
- pView->pImpEditView->RecalcOutputArea();
+ pView->getImpl().RecalcOutputArea();
}
}
void ImpEditEngine::CheckPageOverflow()
{
- SAL_INFO("editeng.chaining", "[CONTROL_STATUS] AutoPageSize is " << (( aStatus.GetControlWord() & EEControlBits::AUTOPAGESIZE ) ? "ON" : "OFF") );
+ SAL_INFO("editeng.chaining", "[CONTROL_STATUS] AutoPageSize is " << (( maStatus.GetControlWord() & EEControlBits::AUTOPAGESIZE ) ? "ON" : "OFF") );
tools::Long nBoxHeight = GetMaxAutoPaperSize().Height();
SAL_INFO("editeng.chaining", "[OVERFLOW-CHECK] Current MaxAutoPaperHeight is " << nBoxHeight);
@@ -572,12 +643,12 @@ void ImpEditEngine::CheckPageOverflow()
{
// which paragraph is the first to cause higher size of the box?
ImplUpdateOverflowingParaNum( nBoxHeight); // XXX: currently only for horizontal text
- //aStatus.SetPageOverflow(true);
+ //maStatus.SetPageOverflow(true);
mbNeedsChainingHandling = true;
} else
{
// No overflow if within box boundaries
- //aStatus.SetPageOverflow(false);
+ //maStatus.SetPageOverflow(false);
mbNeedsChainingHandling = false;
}
@@ -585,7 +656,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
@@ -595,46 +667,82 @@ tools::Long ImpEditEngine::GetColumnWidth(const Size& rPaperSize) const
return (nWidth - mnColumnSpacing * (mnColumns - 1)) / mnColumns;
}
+bool ImpEditEngine::createLinesForEmptyParagraph(ParaPortion& rParaPortion)
+{
+ // fast special treatment...
+ if (rParaPortion.GetTextPortions().Count())
+ rParaPortion.GetTextPortions().Reset();
+ if (rParaPortion.GetLines().Count())
+ rParaPortion.GetLines().Reset();
+
+ CreateAndInsertEmptyLine(rParaPortion);
+ return FinishCreateLines(rParaPortion);
+}
+
+tools::Long ImpEditEngine::calculateMaxLineWidth(tools::Long nStartX, SvxLRSpaceItem const& rLRItem)
+{
+ const bool bAutoSize = IsEffectivelyVertical() ? maStatus.AutoPageHeight() : maStatus.AutoPageWidth();
+ tools::Long nMaxLineWidth = GetColumnWidth(bAutoSize ? maMaxAutoPaperSize : maPaperSize);
+
+ 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(maPaperSize) - scaleXSpacingValue(rLRItem.GetRight());
+
+ // If still less than 0, it may be just the right edge.
+ if (nMaxLineWidth <= 0)
+ nMaxLineWidth = 1;
+
+ return nMaxLineWidth;
+}
+
bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
{
- ParaPortion& rParaPortion = GetParaPortions()[nPara];
+ assert(GetParaPortions().exists(nPara) && "Portion paragraph index is not valid");
+ ParaPortion& rParaPortion = GetParaPortions().getRef(nPara);
// sal_Bool: Changes in the height of paragraph Yes / No - sal_True/sal_False
- assert( rParaPortion.GetNode() && "Portion without Node in CreateLines" );
+ assert(rParaPortion.GetNode() && "Portion without Node in CreateLines" );
DBG_ASSERT( rParaPortion.IsVisible(), "Invisible paragraphs not formatted!" );
DBG_ASSERT( rParaPortion.IsInvalid(), "CreateLines: Portion not invalid!" );
- bool bProcessingEmptyLine = ( rParaPortion.GetNode()->Len() == 0 );
- bool bEmptyNodeWithPolygon = ( rParaPortion.GetNode()->Len() == 0 ) && GetTextRanger();
+ bool bProcessingEmptyLine = rParaPortion.GetNode()->Len() == 0 ;
+ bool bEmptyNodeWithPolygon = rParaPortion.GetNode()->Len() == 0 && GetTextRanger();
// Fast special treatment for empty paragraphs...
-
- if ( ( rParaPortion.GetNode()->Len() == 0 ) && !GetTextRanger() )
+ bool bEmptyParagraph = rParaPortion.GetNode()->Len() == 0 && !GetTextRanger();
+ if (bEmptyParagraph)
+ return createLinesForEmptyParagraph(rParaPortion);
+
+ sal_Int64 nCurrentPosY = nStartPosY;
+ // If we're allowed to skip parts outside and this cannot possibly fit in the given height,
+ // bail out to avoid possibly formatting a lot of text that will not be used. For the first
+ // paragraph still format at least a bit.
+ if( mbSkipOutsideFormat && nPara != 0
+ && !maStatus.AutoPageHeight() && maPaperSize.Height() < nCurrentPosY )
{
- // fast special treatment...
- if ( rParaPortion.GetTextPortions().Count() )
- rParaPortion.GetTextPortions().Reset();
- if ( rParaPortion.GetLines().Count() )
- rParaPortion.GetLines().Reset();
- CreateAndInsertEmptyLine( &rParaPortion );
- return FinishCreateLines( &rParaPortion );
+ return false;
}
+ //If the paragraph SvxFrameDirection is Stacked, use STACKED
+ const SvxFrameDirectionItem* pFrameDirItem = &GetParaAttrib(nPara, EE_PARA_WRITINGDIR);
+ bool bStacked = pFrameDirItem->GetValue() == SvxFrameDirection::Stacked;
+ if (bStacked)
+ maStatus.TurnOnFlags(EEControlBits::STACKED);
+ else
+ maStatus.TurnOffFlags(EEControlBits::STACKED);
// Initialization...
-
- // Always format for 100%:
- bool bMapChanged = ImpCheckRefMapMode();
-
- if ( rParaPortion.GetLines().Count() == 0 )
+ if (rParaPortion.GetLines().Count() == 0)
{
- EditLine* pL = new EditLine;
- rParaPortion.GetLines().Append(pL);
+ rParaPortion.GetLines().Append(std::make_unique<EditLine>());
}
-
// Get Paragraph attributes...
ContentNode* const pNode = rParaPortion.GetNode();
@@ -655,27 +763,28 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
const sal_Int32 nInvalidEnd = nInvalidStart + std::abs( nInvalidDiff );
bool bQuickFormat = false;
- if ( !bEmptyNodeWithPolygon && !HasScriptType( nPara, i18n::ScriptType::COMPLEX ) )
+
+ // Determine if quick format should be used
+ if (!bEmptyNodeWithPolygon && !HasScriptType(nPara, i18n::ScriptType::COMPLEX))
{
- if ( ( rParaPortion.IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) &&
- ( pNode->GetString().indexOf( CH_FEATURE, nInvalidStart ) > nInvalidEnd ) )
+ if (rParaPortion.IsSimpleInvalid() &&
+ rParaPortion.GetInvalidDiff() > 0 &&
+ pNode->GetString().indexOf(CH_FEATURE, nInvalidStart) > nInvalidEnd)
{
bQuickFormat = true;
}
- else if ( ( rParaPortion.IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
+ else if (rParaPortion.IsSimpleInvalid() && nInvalidDiff < 0)
{
// check if delete over the portion boundaries was done...
sal_Int32 nStart = nInvalidStart; // DOUBLE !!!!!!!!!!!!!!!
sal_Int32 nEnd = nStart - nInvalidDiff; // negative
bQuickFormat = true;
sal_Int32 nPos = 0;
- sal_Int32 nPortions = rParaPortion.GetTextPortions().Count();
- for ( sal_Int32 nTP = 0; nTP < nPortions; nTP++ )
+ for (auto const& pTextPortion : rParaPortion.GetTextPortions())
{
// There must be no start / end in the deleted area.
- const TextPortion& rTP = rParaPortion.GetTextPortions()[ nTP ];
- nPos = nPos + rTP.GetLen();
- if ( ( nPos > nStart ) && ( nPos < nEnd ) )
+ nPos = nPos + pTextPortion->GetLen();
+ if (nPos > nStart && nPos < nEnd)
{
bQuickFormat = false;
break;
@@ -691,7 +800,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
sal_Int32 nRealInvalidStart = nInvalidStart;
- if ( bEmptyNodeWithPolygon )
+ if (bEmptyNodeWithPolygon)
{
TextPortion* pDummyPortion = new TextPortion( 0 );
rParaPortion.GetTextPortions().Reset();
@@ -700,14 +809,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
else if ( bQuickFormat )
{
// faster Method:
- RecalcTextPortion( &rParaPortion, nInvalidStart, nInvalidDiff );
+ RecalcTextPortion(rParaPortion, nInvalidStart, nInvalidDiff);
}
else // nRealInvalidStart can be before InvalidStart, since Portions were deleted...
{
- CreateTextPortions( &rParaPortion, nRealInvalidStart );
+ CreateTextPortions(rParaPortion, nRealInvalidStart);
}
-
// Search for line with InvalidPos, start one line before
// Flag the line => do not remove it !
@@ -725,35 +833,38 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
}
// Begin one line before...
// If it is typed at the end, the line in front cannot change.
- if ( nLine && ( !rParaPortion.IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
+ if (nLine && (!rParaPortion.IsSimpleInvalid() ||
+ (nInvalidEnd < pNode->Len()) ||
+ (nInvalidDiff <= 0)))
+ {
nLine--;
+ }
- EditLine* pLine = &rParaPortion.GetLines()[nLine];
+ tools::Rectangle aBulletArea{Point(), Point()};
- static const tools::Rectangle aZeroArea { Point(), Point() };
- tools::Rectangle aBulletArea( aZeroArea );
- if ( !nLine )
+ if (!nLine)
{
- aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( &rParaPortion ) );
+ aBulletArea = GetEditEnginePtr()->GetBulletArea(GetParaPortions().GetPos(&rParaPortion));
if ( !aBulletArea.IsWidthEmpty() && aBulletArea.Right() > 0 )
- rParaPortion.SetBulletX( static_cast<sal_Int32>(GetXValue( aBulletArea.Right() )) );
+ rParaPortion.SetBulletX(sal_Int32(scaleXSpacingValue(aBulletArea.Right())));
else
rParaPortion.SetBulletX( 0 ); // if Bullet is set incorrectly
}
-
// Reformat all lines from here...
+ int nStartNextLineAfterMultiLineField = 0;
+
sal_Int32 nDelFromLine = -1;
bool bLineBreak = false;
+ EditLine* pLine = &rParaPortion.GetLines()[nLine];
sal_Int32 nIndex = pLine->GetStart();
EditLine aSaveLine( *pLine );
- SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() );
- ImplInitLayoutMode(*GetRefDevice(), nPara, nIndex);
+ SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() );
- std::vector<tools::Long> aBuf( pNode->Len() );
+ KernArray aCharPositionArray;
bool bSameLineAgain = false; // For TextRanger, if the height changes.
TabInfo aCurrentTab;
@@ -763,39 +874,33 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
while ( ( nIndex < pNode->Len() ) || bForceOneRun )
{
+ assert(pLine);
+
bForceOneRun = false;
+ bool bFieldStartNextLine = false;
bool bEOL = false;
bool bEOC = false;
sal_Int32 nPortionStart = 0;
sal_Int32 nPortionEnd = 0;
- tools::Long nStartX = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
+ tools::Long nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth);
+ // Multiline hyperlink may need to know if the next line is bigger.
+ tools::Long nStartXNextLine = nStartX;
if ( nIndex == 0 )
{
- tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
+ tools::Long nFI = scaleXSpacingValue(rLRItem.GetTextFirstLineOffset());
nStartX += nFI;
- if ( !nLine && ( rParaPortion.GetBulletX() > nStartX ) )
+ if (!nLine && rParaPortion.GetBulletX() > nStartX)
{
- nStartX = rParaPortion.GetBulletX();
+ nStartX = rParaPortion.GetBulletX();
}
}
- const bool bAutoSize = IsEffectivelyVertical() ? aStatus.AutoPageHeight() : aStatus.AutoPageWidth();
- tools::Long nMaxLineWidth = GetColumnWidth(bAutoSize ? aMaxAutoPaperSize : aPaperSize);
-
- nMaxLineWidth -= GetXValue( 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());
-
- // If still less than 0, it may be just the right edge.
- if ( nMaxLineWidth <= 0 )
- nMaxLineWidth = 1;
+ nStartX += nStartNextLineAfterMultiLineField;
+ nStartNextLineAfterMultiLineField = 0;
+ tools::Long nMaxLineWidth = calculateMaxLineWidth(nStartX, rLRItem);
// Problem:
// Since formatting starts a line _before_ the invalid position,
@@ -818,7 +923,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
{
GetTextRanger()->SetVertical( IsEffectivelyVertical() );
- tools::Long nTextY = nStartPosY + GetEditCursor( &rParaPortion, pLine, pLine->GetStart(), GetCursorFlags::NONE ).Top();
+ tools::Long nTextY = nStartPosY + GetEditCursor(rParaPortion, *pLine, pLine->GetStart(), CursorFlags()).Top();
if ( !bSameLineAgain )
{
SeekCursor( pNode, nTmpPos+1, aTmpFont );
@@ -871,7 +976,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.
@@ -929,10 +1034,10 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
nTmpWidth -= rPrev.GetSize().Width();
nTmpPos = nTmpPos - rPrev.GetLen();
rPrev.SetLen(rPrev.GetLen() + nTmpLen);
- rPrev.GetSize().setWidth( -1 );
+ rPrev.setWidth(-1);
}
- assert( nTmpPortion < rParaPortion.GetTextPortions().Count() && "No more Portions left!" );
+ assert(nTmpPortion < rParaPortion.GetTextPortions().Count() && "No more Portions left!");
pPortion = &rParaPortion.GetTextPortions()[nTmpPortion];
}
@@ -961,14 +1066,15 @@ 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() && ( nStretchX != 100 ) )
- nCurPos = nCurPos*100/std::max(static_cast<sal_Int32>(nStretchX), static_cast<sal_Int32>(1));
+ double fFontScalingX = maScalingParameters.fFontX;
+ if (maStatus.DoStretch() && (fFontScalingX != 1.0))
+ nCurPos = basegfx::fround<tools::Long>(double(nCurPos) / std::max(fFontScalingX, 0.01));
- 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()*/ ) );
+ short nAllSpaceBeforeText = short(rLRItem.GetTextLeft());
+ aCurrentTab.aTabStop = pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText , maEditDoc.GetDefTab() );
+ aCurrentTab.nTabPos = tools::Long(aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText);
aCurrentTab.bValid = false;
// Switch direction in R2L para...
@@ -992,23 +1098,23 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
pPortion->SetKind(PortionKind::TAB);
pPortion->SetExtraValue( aCurrentTab.aTabStop.GetFill() );
- pPortion->GetSize().setWidth( aCurrentTab.nTabPos - (nTmpWidth+nStartX) );
+ pPortion->setWidth( aCurrentTab.nTabPos - (nTmpWidth+nStartX) );
// Height needed...
SeekCursor( pNode, nTmpPos+1, aTmpFont );
- pPortion->GetSize().setHeight( aTmpFont.QuickGetTextSize( GetRefDevice(), OUString(), 0, 0 ).Height() );
+ pPortion->setHeight( GetRefDevice()->GetTextHeight() );
DBG_ASSERT( pPortion->GetSize().Width() >= 0, "Tab incorrectly calculated!" );
nTmpWidth = aCurrentTab.nTabPos-nStartX;
// If this is the first token on the line,
- // and nTmpWidth > aPaperSize.Width, => infinite loop!
+ // and nTmpWidth > maPaperSize.Width, => infinite loop!
if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
{
// What now?
// make the tab fitting
- pPortion->GetSize().setWidth( nXWidth-nOldTmpWidth );
+ pPortion->setWidth( nXWidth-nOldTmpWidth );
nTmpWidth = nXWidth-1;
bEOL = true;
bBrokenLine = true;
@@ -1022,7 +1128,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
case EE_FEATURE_LINEBR:
{
assert( pPortion );
- pPortion->GetSize().setWidth( 0 );
+ pPortion->setWidth(0);
bEOL = true;
bLineBreak = true;
pPortion->SetKind( PortionKind::LINEBREAK );
@@ -1040,11 +1146,12 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
OUString aFieldValue = static_cast<const EditCharAttribField*>(pNextFeature)->GetFieldValue();
// get size, but also DXArray to allow length information in line breaking below
- std::vector<tools::Long> aTmpDXArray;
- pPortion->GetSize() = aTmpFont.QuickGetTextSize(GetRefDevice(), aFieldValue, 0, aFieldValue.getLength(), &aTmpDXArray);
+ KernArray aTmpDXArray;
+ pPortion->SetSize(aTmpFont.QuickGetTextSize(GetRefDevice(),
+ aFieldValue, 0, aFieldValue.getLength(), &aTmpDXArray));
// So no scrolling for oversized fields
- if ( pPortion->GetSize().Width() > nXWidth )
+ if (pPortion->GetSize().Width() > nXWidth - nTmpWidth)
{
// create ExtraPortionInfo on-demand, flush lineBreaksList
ExtraPortionInfo *pExtraInfo = pPortion->GetExtraInfos();
@@ -1076,6 +1183,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
nDone));
sal_Int32 nLastCellBreak(0);
sal_Int32 nLineStartX(0);
+ nLineStartX = -nTmpWidth;
// always add 1st line break (safe, we already know we are larger than nXWidth)
pExtraInfo->lineBreaksList.push_back(0);
@@ -1093,6 +1201,22 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
if(0 != a)
{
pExtraInfo->lineBreaksList.push_back(a);
+ // the following lines may be different sized
+ if (nStartX > nStartXNextLine)
+ {
+ nXWidth += nStartX - nStartXNextLine;
+ pLine->SetNextLinePosXDiff(nStartX
+ - nStartXNextLine);
+ nStartXNextLine = nStartX;
+ }
+ }
+ else
+ {
+ //even the 1. char does not fit..
+ //this means the field should start on next line
+ //except if the actual line is a full line already
+ if (nLineStartX < 0 || nStartX > nStartXNextLine)
+ bFieldStartNextLine = true;
}
// moveLineStart forward in X
@@ -1110,6 +1234,17 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
nDone);
}
}
+ //next Line should start here... after this field end
+ if (!bFieldStartNextLine)
+ nStartNextLineAfterMultiLineField
+ = aTmpDXArray[nTextLength - 1] - nLineStartX;
+ else if (pExtraInfo)
+ {
+ // if the 1. character does not fit,
+ // but there is pExtraInfo, then delete it
+ pPortion->SetExtraInfos(nullptr);
+ pExtraInfo = nullptr;
+ }
}
nTmpWidth += pPortion->GetSize().Width();
EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
@@ -1117,7 +1252,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
rArray.insert(rArray.begin()+nPos, pPortion->GetSize().Width());
pPortion->SetKind(PortionKind::FIELD);
// If this is the first token on the line,
- // and nTmpWidth > aPaperSize.Width, => infinite loop!
+ // and nTmpWidth > maPaperSize.Width, => infinite loop!
if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) )
{
nTmpWidth = nXWidth-1;
@@ -1145,33 +1280,36 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
if (bContinueLastPortion)
{
- Size aSize( aTmpFont.QuickGetTextSize( GetRefDevice(),
- rParaPortion.GetNode()->GetString(), nTmpPos, nPortionLen, &aBuf ));
- pPortion->GetSize().AdjustWidth(aSize.Width() );
+ Size aSize = aTmpFont.QuickGetTextSize( GetRefDevice(), rParaPortion.GetNode()->GetString(), nTmpPos, nPortionLen, &aCharPositionArray, bStacked);
+ pPortion->adjustSize(aSize.Width(), 0);
if (pPortion->GetSize().Height() < aSize.Height())
- pPortion->GetSize().setHeight( aSize.Height() );
+ pPortion->setHeight(aSize.Height());
}
else
{
- pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(),
- rParaPortion.GetNode()->GetString(), nTmpPos, nPortionLen, &aBuf );
+ Size aSize = aTmpFont.QuickGetTextSize(GetRefDevice(), rParaPortion.GetNode()->GetString(), nTmpPos, nPortionLen, &aCharPositionArray, bStacked);
+ pPortion->SetSize(aSize);
}
// #i9050# Do Kerning also behind portions...
if ( ( aTmpFont.GetFixKerning() > 0 ) && ( ( nTmpPos + nPortionLen ) < pNode->Len() ) )
- pPortion->GetSize().AdjustWidth(aTmpFont.GetFixKerning() );
+ pPortion->adjustSize(aTmpFont.GetFixKerning(), 0);
if ( IsFixedCellHeight() )
- pPortion->GetSize().setHeight( ImplCalculateFontIndependentLineSpacing( aTmpFont.GetFontHeight() ) );
+ {
+ pPortion->setHeight( ImplCalculateFontIndependentLineSpacing( aTmpFont.GetFontHeight() ) );
+ }
// The array is generally flattened at the beginning
// => Always simply quick inserts.
size_t nPos = nTmpPos - pLine->GetStart();
EditLine::CharPosArrayType& rArray = pLine->GetCharPosArray();
- rArray.insert( rArray.begin() + nPos, aBuf.data(), aBuf.data() + nPortionLen);
+ assert(aCharPositionArray.get_factor() == 1);
+ std::vector<sal_Int32>& rKernArray = aCharPositionArray.get_subunit_array();
+ rArray.insert( rArray.begin() + nPos, rKernArray.data(), rKernArray.data() + nPortionLen);
// And now check for Compression:
if ( !bContinueLastPortion && nPortionLen && GetAsianCompressionMode() != CharCompressType::NONE )
{
- tools::Long* pDXArray = rArray.data() + nTmpPos - pLine->GetStart();
+ sal_Int32* pDXArray = rArray.data() + nTmpPos - pLine->GetStart();
bCompressedChars |= ImplCalcAsianCompression(
pNode, pPortion, nTmpPos, pDXArray, 10000, false);
}
@@ -1190,9 +1328,9 @@ 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 );
- pPortion->GetSize().AdjustWidth(nExtraSpace );
+ tools::Long nExtraSpace = pPortion->GetSize().Height() / 5;
+ nExtraSpace = scaleXSpacingValue(nExtraSpace);
+ pPortion->adjustSize(nExtraSpace, 0);
nTmpWidth += nExtraSpace;
}
}
@@ -1203,12 +1341,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
tools::Long nWidthAfterTab = 0;
for ( sal_Int32 n = aCurrentTab.nTabPortion+1; n <= nTmpPortion; n++ )
{
- const TextPortion& rTP = rParaPortion.GetTextPortions()[n];
- nWidthAfterTab += rTP.GetSize().Width();
+ const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[n];
+ nWidthAfterTab += rTextPortion.GetSize().Width();
}
tools::Long nW = nWidthAfterTab; // Length before tab position
if ( aCurrentTab.aTabStop.GetAdjustment() == SvxTabAdjust::Right )
{
+ // Do nothing
}
else if ( aCurrentTab.aTabStop.GetAdjustment() == SvxTabAdjust::Center )
{
@@ -1216,13 +1355,16 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
}
else if ( aCurrentTab.aTabStop.GetAdjustment() == SvxTabAdjust::Decimal )
{
- OUString aText = GetSelected( EditSelection( EditPaM( rParaPortion.GetNode(), nTmpPos ),
- EditPaM( rParaPortion.GetNode(), nTmpPos + nPortionLen ) ) );
+ EditPaM aSelectionStart(rParaPortion.GetNode(), nTmpPos);
+ EditPaM aSelectionEnd(rParaPortion.GetNode(), nTmpPos + nPortionLen);
+ EditSelection aSelection(aSelectionStart, aSelectionEnd);
+ OUString aText = GetSelected(aSelection);
+
sal_Int32 nDecPos = aText.indexOf( aCurrentTab.aTabStop.GetDecimal() );
if ( nDecPos != -1 )
{
nW -= rParaPortion.GetTextPortions()[nTmpPortion].GetSize().Width();
- nW += aTmpFont.QuickGetTextSize( GetRefDevice(), rParaPortion.GetNode()->GetString(), nTmpPos, nDecPos ).Width();
+ nW += aTmpFont.QuickGetTextSize(GetRefDevice(), rParaPortion.GetNode()->GetString(), nTmpPos, nDecPos, nullptr).Width();
aCurrentTab.bValid = false;
}
}
@@ -1237,14 +1379,14 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
aCurrentTab.bValid = false;
}
TextPortion& rTabPortion = rParaPortion.GetTextPortions()[aCurrentTab.nTabPortion];
- rTabPortion.GetSize().setWidth( aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX );
+ rTabPortion.setWidth( aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX );
nTmpWidth = aCurrentTab.nStartPosX + rTabPortion.GetSize().Width() + nWidthAfterTab;
}
nTmpPos = nTmpPos + nPortionLen;
nPortionEnd = nTmpPos;
nTmpPortion++;
- if ( aStatus.OneCharPerLine() )
+ if (maStatus.OneCharPerLine())
bEOL = true;
}
@@ -1256,7 +1398,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
// this was possibly a portion too far:
bool bFixedEnd = false;
- if ( aStatus.OneCharPerLine() )
+ if (maStatus.OneCharPerLine())
{
// State before Portion (apart from nTmpWidth):
nTmpPos -= pPortion ? nPortionLen : 0;
@@ -1275,7 +1417,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
{
DBG_ASSERT( pPortion->GetKind() == PortionKind::TEXT, "Len>1, but no TextPortion?" );
nTmpWidth -= pPortion->GetSize().Width();
- sal_Int32 nP = SplitTextPortion( &rParaPortion, nTmpPos, pLine );
+ sal_Int32 nP = SplitTextPortion(rParaPortion, nTmpPos, pLine);
nTmpWidth += rParaPortion.GetTextPortions()[nP].GetSize().Width();
}
}
@@ -1316,41 +1458,57 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
bEOL = true;
bEOC = true;
pLine->SetEnd( nPortionEnd );
- assert( rParaPortion.GetTextPortions().Count() && "No TextPortions?" );
- pLine->SetEndPortion( rParaPortion.GetTextPortions().Count() - 1 );
+ assert(rParaPortion.GetTextPortions().Count() && "No TextPortions?");
+ pLine->SetEndPortion(rParaPortion.GetTextPortions().Count() - 1);
}
- if ( aStatus.OneCharPerLine() )
+ if (maStatus.OneCharPerLine())
{
pLine->SetEnd( nPortionEnd );
pLine->SetEndPortion( nTmpPortion-1 );
}
else if ( bFixedEnd )
{
- pLine->SetEnd( nPortionStart );
- pLine->SetEndPortion( nTmpPortion-1 );
+ if (bFieldStartNextLine)
+ {
+ pLine->SetEnd(nPortionStart);
+ pLine->SetEndPortion(nTmpPortion - 1);
+ }
+ else
+ {
+ pLine->SetEnd(nPortionStart + 1);
+ pLine->SetEndPortion(nTmpPortion);
+ }
}
else if ( bLineBreak || bBrokenLine )
{
- pLine->SetEnd( nPortionStart+1 );
- pLine->SetEndPortion( nTmpPortion-1 );
+ if (bFieldStartNextLine)
+ {
+ pLine->SetEnd(nPortionStart);
+ pLine->SetEndPortion(nTmpPortion - 2);
+ }
+ else
+ {
+ pLine->SetEnd(nPortionStart + 1);
+ pLine->SetEndPortion(nTmpPortion - 1);
+ }
bEOC = false; // was set above, maybe change the sequence of the if's?
}
else if ( !bEOL && !bContinueLastPortion )
{
DBG_ASSERT( pPortion && ((nPortionEnd-nPortionStart) == pPortion->GetLen()), "However, another portion?!" );
- tools::Long nRemainingWidth = nMaxLineWidth - nTmpWidth;
+ tools::Long nRemainingWidth = !maStatus.IsSingleLine() ?
+ nMaxLineWidth - nTmpWidth : pLine->GetCharPosArray()[pLine->GetCharPosArray().size() - 1] + 1;
bool bCanHyphenate = ( aTmpFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL );
if ( bCompressedChars && pPortion && ( pPortion->GetLen() > 1 ) && pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed )
{
// I need the manipulated DXArray for determining the break position...
- tools::Long* pDXArray = pLine->GetCharPosArray().data() + (nPortionStart - pLine->GetStart());
+ sal_Int32* pDXArray = pLine->GetCharPosArray().data() + (nPortionStart - pLine->GetStart());
ImplCalcAsianCompression(
pNode, pPortion, nPortionStart, pDXArray, 10000, true);
}
if( pPortion )
- ImpBreakLine( &rParaPortion, pLine, pPortion, nPortionStart,
- nRemainingWidth, bCanHyphenate && bHyphenatePara );
+ ImpBreakLine(rParaPortion, *pLine, pPortion, nPortionStart, nRemainingWidth, bCanHyphenate && bHyphenatePara);
}
@@ -1358,18 +1516,18 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
// CalcTextSize should be replaced by a continuous registering!
- Size aTextSize = pLine->CalcTextSize( rParaPortion );
+ Size aTextSize = pLine->CalcTextSize(rParaPortion);
if ( aTextSize.Height() == 0 )
{
SeekCursor( pNode, pLine->GetStart()+1, aTmpFont );
- aTmpFont.SetPhysFont(*pRefDev);
- ImplInitDigitMode(*pRefDev, aTmpFont.GetLanguage());
+ aTmpFont.SetPhysFont(*mpRefDev);
+ ImplInitDigitMode(*mpRefDev, aTmpFont.GetLanguage());
if ( IsFixedCellHeight() )
aTextSize.setHeight( ImplCalculateFontIndependentLineSpacing( aTmpFont.GetFontHeight() ) );
else
- aTextSize.setHeight( aTmpFont.GetPhysTxtSize( pRefDev ).Height() );
+ aTextSize.setHeight( aTmpFont.GetPhysTxtSize(mpRefDev).Height() );
pLine->SetHeight( static_cast<sal_uInt16>(aTextSize.Height()) );
}
@@ -1403,12 +1561,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
bSameLineAgain = true;
}
-
- if ( !bSameLineAgain && !aStatus.IsOutliner() )
+ if (!bSameLineAgain && !maStatus.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 )
{
@@ -1420,7 +1579,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 );
@@ -1429,40 +1590,61 @@ 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 = maScalingParameters.fSpacingY;
+ 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 (maScalingParameters.fSpacingY < 1.0)
+ {
+ double fSpacingFactor = maScalingParameters.fSpacingY;
+ 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() ) ||
- ( IsEffectivelyVertical() && aStatus.AutoPageHeight() ) )
+ if ( ( !IsEffectivelyVertical() && maStatus.AutoPageWidth() ) ||
+ ( IsEffectivelyVertical() && maStatus.AutoPageHeight() ) )
{
// If the row fits within the current paper width, then this width
// 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(maPaperSize) - scaleXSpacingValue(rLRItem.GetRight()) - nStartX;
if ( aTextSize.Width() < nMaxLineWidthFix )
nMaxLineWidth = nMaxLineWidthFix;
}
@@ -1472,8 +1654,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
tools::Long nRemainingWidth = nMaxLineWidth - aTextSize.Width();
if ( nRemainingWidth > 0 )
{
- ImplExpandCompressedPortions( pLine, &rParaPortion, nRemainingWidth );
- aTextSize = pLine->CalcTextSize( rParaPortion );
+ ImplExpandCompressedPortions(*pLine, rParaPortion, nRemainingWidth);
+ aTextSize = pLine->CalcTextSize(rParaPortion);
}
}
@@ -1485,8 +1667,11 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
TextPortion& rTP = rParaPortion.GetTextPortions()[pLine->GetEndPortion()];
sal_Int32 nPosInArray = pLine->GetEnd()-1-pLine->GetStart();
tools::Long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n;
- pLine->GetCharPosArray()[ nPosInArray ] = nNewValue;
- rTP.GetSize().AdjustWidth(n );
+ if (o3tl::make_unsigned(nPosInArray) < pLine->GetCharPosArray().size())
+ {
+ pLine->GetCharPosArray()[ nPosInArray ] = nNewValue;
+ }
+ rTP.adjustSize(n, 0);
}
pLine->SetTextWidth( aTextSize.Width() );
@@ -1514,7 +1699,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
tools::Long nRemainingSpace = nMaxLineWidth - aTextSize.Width();
pLine->SetStartPosX( nStartX );
if ( nRemainingSpace > 0 && (!bEOC || bDistLastLine) )
- ImpAdjustBlocks( &rParaPortion, pLine, nRemainingSpace );
+ ImpAdjustBlocks(rParaPortion, *pLine, nRemainingSpace);
}
break;
default:
@@ -1548,7 +1733,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
}
// for <0 think over !
- if ( rParaPortion.IsSimpleInvalid() )
+ if (rParaPortion.IsSimpleInvalid())
{
// Change through simple Text changes...
// Do not cancel formatting since Portions possibly have to be split
@@ -1601,6 +1786,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
// as nEnd points to the last character!
sal_Int32 nEndPortion = pLine->GetEndPortion();
+ nCurrentPosY += pLine->GetHeight();
// Next line or maybe a new line...
pLine = nullptr;
@@ -1611,12 +1797,22 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
nDelFromLine = nLine;
break;
}
+ // Stop processing if allowed and this is outside of the paper size height.
+ // Format at least two lines though, in case something detects whether
+ // the text has been wrapped or something similar.
+ if( mbSkipOutsideFormat && nLine > 2
+ && !maStatus.AutoPageHeight() && maPaperSize.Height() < nCurrentPosY )
+ {
+ if ( pLine && ( nIndex >= pNode->Len()) )
+ nDelFromLine = nLine;
+ break;
+ }
if ( !pLine )
{
if ( nIndex < pNode->Len() )
{
pLine = new EditLine;
- rParaPortion.GetLines().Insert(++nLine, pLine);
+ rParaPortion.GetLines().Insert(++nLine, std::unique_ptr<EditLine>(pLine));
}
else if ( nIndex && bLineBreak && GetTextRanger() )
{
@@ -1625,7 +1821,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
TextPortion* pDummyPortion = new TextPortion( 0 );
rParaPortion.GetTextPortions().Append(pDummyPortion);
pLine = new EditLine;
- rParaPortion.GetLines().Insert(++nLine, pLine);
+ rParaPortion.GetLines().Insert(++nLine, std::unique_ptr<EditLine>(pLine));
bForceOneRun = true;
bProcessingEmptyLine = true;
}
@@ -1644,66 +1840,63 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
if ( nDelFromLine >= 0 )
rParaPortion.GetLines().DeleteFromLine( nDelFromLine );
- DBG_ASSERT( rParaPortion.GetLines().Count(), "No line after CreateLines!" );
+ DBG_ASSERT(rParaPortion.GetLines().Count(), "No line after CreateLines!");
if ( bLineBreak )
- CreateAndInsertEmptyLine( &rParaPortion );
-
- bool bHeightChanged = FinishCreateLines( &rParaPortion );
+ CreateAndInsertEmptyLine(rParaPortion);
- if ( bMapChanged )
- GetRefDevice()->Pop();
+ bool bHeightChanged = FinishCreateLines(rParaPortion);
GetRefDevice()->Pop();
return bHeightChanged;
}
-void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
+void ImpEditEngine::CreateAndInsertEmptyLine(ParaPortion& rParaPortion)
{
DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" );
EditLine* pTmpLine = new EditLine;
- pTmpLine->SetStart( pParaPortion->GetNode()->Len() );
- pTmpLine->SetEnd( pParaPortion->GetNode()->Len() );
- pParaPortion->GetLines().Append(pTmpLine);
+ pTmpLine->SetStart(rParaPortion.GetNode()->Len());
+ pTmpLine->SetEnd(rParaPortion.GetNode()->Len());
+ rParaPortion.GetLines().Append(std::unique_ptr<EditLine>(pTmpLine));
- bool bLineBreak = pParaPortion->GetNode()->Len() > 0;
+ bool bLineBreak = rParaPortion.GetNode()->Len() > 0;
sal_Int32 nSpaceBefore = 0;
- 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 );
+ sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth(rParaPortion.GetNode(), &nSpaceBefore);
+ const SvxLRSpaceItem& rLRItem = GetLRSpaceItem(rParaPortion.GetNode());
+ const SvxLineSpacingItem& rLSItem = rParaPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
+ 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 ) );
+ aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos(&rParaPortion));
if ( !aBulletArea.IsEmpty() && aBulletArea.Right() > 0 )
- pParaPortion->SetBulletX( static_cast<sal_Int32>(GetXValue( aBulletArea.Right() )) );
+ rParaPortion.SetBulletX(sal_Int32(scaleXSpacingValue(aBulletArea.Right())));
else
- pParaPortion->SetBulletX( 0 ); // If Bullet set incorrectly.
- if ( pParaPortion->GetBulletX() > nStartX )
+ rParaPortion.SetBulletX( 0 ); // If Bullet set incorrectly.
+ if (rParaPortion.GetBulletX() > nStartX)
{
- nStartX = GetXValue( rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBeforeAndMinLabelWidth );
- if ( pParaPortion->GetBulletX() > nStartX )
- nStartX = pParaPortion->GetBulletX();
+ nStartX = scaleXSpacingValue(rLRItem.GetTextLeft() + rLRItem.GetTextFirstLineOffset() + nSpaceBeforeAndMinLabelWidth);
+ if (rParaPortion.GetBulletX() > nStartX)
+ nStartX = rParaPortion.GetBulletX();
}
}
SvxFont aTmpFont;
- SeekCursor( pParaPortion->GetNode(), bLineBreak ? pParaPortion->GetNode()->Len() : 0, aTmpFont );
- aTmpFont.SetPhysFont(*pRefDev);
+ SeekCursor(rParaPortion.GetNode(), bLineBreak ? rParaPortion.GetNode()->Len() : 0, aTmpFont );
+ aTmpFont.SetPhysFont(*mpRefDev);
TextPortion* pDummyPortion = new TextPortion( 0 );
- pDummyPortion->GetSize() = aTmpFont.GetPhysTxtSize( pRefDev );
+ pDummyPortion->SetSize(aTmpFont.GetPhysTxtSize(mpRefDev));
if ( IsFixedCellHeight() )
- pDummyPortion->GetSize().setHeight( ImplCalculateFontIndependentLineSpacing( aTmpFont.GetFontHeight() ) );
- pParaPortion->GetTextPortions().Append(pDummyPortion);
+ pDummyPortion->setHeight( ImplCalculateFontIndependentLineSpacing( aTmpFont.GetFontHeight() ) );
+ rParaPortion.GetTextPortions().Append(pDummyPortion);
FormatterFontMetric aFormatterMetrics;
RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont );
pTmpLine->SetMaxAscent( aFormatterMetrics.nMaxAscent );
@@ -1712,12 +1905,12 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
if ( nLineHeight > pTmpLine->GetHeight() )
pTmpLine->SetHeight( nLineHeight );
- if ( !aStatus.IsOutliner() )
+ if (!maStatus.IsOutliner())
{
- sal_Int32 nPara = GetParaPortions().GetPos( pParaPortion );
+ sal_Int32 nPara = GetParaPortions().GetPos(&rParaPortion);
SvxAdjust eJustification = GetJustification( nPara );
- tools::Long nMaxLineWidth = GetColumnWidth(aPaperSize);
- nMaxLineWidth -= GetXValue( rLRItem.GetRight() );
+ tools::Long nMaxLineWidth = GetColumnWidth(maPaperSize);
+ nMaxLineWidth -= scaleXSpacingValue(rLRItem.GetRight());
if ( nMaxLineWidth < 0 )
nMaxLineWidth = 1;
if ( eJustification == SvxAdjust::Center )
@@ -1728,7 +1921,7 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
pTmpLine->SetStartPosX( nStartX );
- if ( !aStatus.IsOutliner() )
+ if (!maStatus.IsOutliner())
{
if ( rLSItem.GetLineSpaceRule() == SvxLineSpaceRule::Min )
{
@@ -1752,7 +1945,7 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
}
else if ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
{
- sal_Int32 nPara = GetParaPortions().GetPos( pParaPortion );
+ sal_Int32 nPara = GetParaPortions().GetPos(&rParaPortion);
if ( nPara || pTmpLine->GetStartPortion() ) // Not the very first line
{
// There are documents with PropLineSpace 0, why?
@@ -1789,37 +1982,37 @@ void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion )
{
// -2: The new one is already inserted.
#ifdef DBG_UTIL
- EditLine& rLastLine = pParaPortion->GetLines()[pParaPortion->GetLines().Count()-2];
- DBG_ASSERT( rLastLine.GetEnd() == pParaPortion->GetNode()->Len(), "different anyway?" );
+ EditLine& rLastLine = rParaPortion.GetLines()[rParaPortion.GetLines().Count()-2];
+ DBG_ASSERT( rLastLine.GetEnd() == rParaPortion.GetNode()->Len(), "different anyway?" );
#endif
- sal_Int32 nPos = pParaPortion->GetTextPortions().Count() - 1 ;
+ sal_Int32 nPos = rParaPortion.GetTextPortions().Count() - 1 ;
pTmpLine->SetStartPortion( nPos );
pTmpLine->SetEndPortion( nPos );
}
}
-bool ImpEditEngine::FinishCreateLines( ParaPortion* pParaPortion )
+bool ImpEditEngine::FinishCreateLines(ParaPortion& rParaPortion)
{
// CalcCharPositions( pParaPortion );
- pParaPortion->SetValid();
- tools::Long nOldHeight = pParaPortion->GetHeight();
- CalcHeight( pParaPortion );
+ rParaPortion.SetValid();
+ tools::Long nOldHeight = rParaPortion.GetHeight();
+ CalcHeight(rParaPortion);
- DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "FinishCreateLines: No Text-Portion?" );
- bool bRet = ( pParaPortion->GetHeight() != nOldHeight );
+ DBG_ASSERT(rParaPortion.GetTextPortions().Count(), "FinishCreateLines: No Text-Portion?");
+ bool bRet = rParaPortion.GetHeight() != nOldHeight;
return bRet;
}
-void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion const * pPortion, sal_Int32 nPortionStart, tools::Long nRemainingWidth, bool bCanHyphenate )
+void ImpEditEngine::ImpBreakLine(ParaPortion& rParaPortion, EditLine& rLine, TextPortion const * pPortion, sal_Int32 nPortionStart, tools::Long nRemainingWidth, bool bCanHyphenate)
{
- ContentNode* const pNode = pParaPortion->GetNode();
+ ContentNode* const pNode = rParaPortion.GetNode();
- sal_Int32 nBreakInLine = nPortionStart - pLine->GetStart();
+ sal_Int32 nBreakInLine = nPortionStart - rLine.GetStart();
sal_Int32 nMax = nBreakInLine + pPortion->GetLen();
- while ( ( nBreakInLine < nMax ) && ( pLine->GetCharPosArray()[nBreakInLine] < nRemainingWidth ) )
+ while ( ( nBreakInLine < nMax ) && ( rLine.GetCharPosArray()[nBreakInLine] < nRemainingWidth ) )
nBreakInLine++;
- sal_Int32 nMaxBreakPos = nBreakInLine + pLine->GetStart();
+ sal_Int32 nMaxBreakPos = nBreakInLine + rLine.GetStart();
sal_Int32 nBreakPos = SAL_MAX_INT32;
bool bCompressBlank = false;
@@ -1831,7 +2024,7 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
bool bAltFullRight = false;
sal_uInt32 nAltDelChar = 0;
- if ( ( nMaxBreakPos < ( nMax + pLine->GetStart() ) ) && ( pNode->GetChar( nMaxBreakPos ) == ' ' ) )
+ if ( ( nMaxBreakPos < ( nMax + rLine.GetStart() ) ) && ( pNode->GetChar( nMaxBreakPos ) == ' ' ) )
{
// Break behind the blank, blank will be compressed...
nBreakPos = nMaxBreakPos + 1;
@@ -1839,7 +2032,7 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
}
else
{
- sal_Int32 nMinBreakPos = pLine->GetStart();
+ sal_Int32 nMinBreakPos = rLine.GetStart();
const CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
for (size_t nAttr = rAttrs.size(); nAttr; )
{
@@ -1877,9 +2070,20 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
aUserOptions.allowPunctuationOutsideMargin = bAllowPunctuationOutsideMargin;
aUserOptions.allowHyphenateEnglish = false;
- i18n::LineBreakResults aLBR = _xBI->getLineBreak(
- pNode->GetString(), nMaxBreakPos, aLocale, nMinBreakPos, aHyphOptions, aUserOptions );
- nBreakPos = aLBR.breakIndex;
+ if (!maStatus.IsSingleLine())
+ {
+ i18n::LineBreakResults aLBR = _xBI->getLineBreak(
+ pNode->GetString(), nMaxBreakPos, aLocale, nMinBreakPos, aHyphOptions, aUserOptions );
+ nBreakPos = aLBR.breakIndex;
+
+ // show soft hyphen
+ if ( nBreakPos && CH_SOFTHYPHEN == pNode->GetString()[ sal_Int32(nBreakPos) - 1 ] )
+ bHyphenated = true;
+ }
+ else
+ {
+ nBreakPos = nMaxBreakPos;
+ }
// BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos
if ( nBreakPos < nMinBreakPos )
@@ -1906,7 +2110,7 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
}
bHangingPunctuation = nBreakPos > nMaxBreakPos;
- pLine->SetHangingPunctuation( bHangingPunctuation );
+ rLine.SetHangingPunctuation( bHangingPunctuation );
// Whether a separator or not, push the word after the separator through
// hyphenation... NMaxBreakPos is the last character that fits into
@@ -1928,14 +2132,14 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
const OUString aWord = pNode->GetString().copy(nWordStart, nWordLen);
sal_Int32 nMinTrail = nWordEnd-nMaxBreakPos+1; //+1: Before the dickey letter
Reference< XHyphenatedWord > xHyphWord;
- if (xHyphenator.is())
- xHyphWord = xHyphenator->hyphenate( aWord, aLocale, aWord.getLength() - nMinTrail, Sequence< PropertyValue >() );
+ if (mxHyphenator.is())
+ xHyphWord = mxHyphenator->hyphenate( aWord, aLocale, aWord.getLength() - nMinTrail, Sequence< PropertyValue >() );
if (xHyphWord.is())
{
bool bAlternate = xHyphWord->isAlternativeSpelling();
sal_Int32 _nWordLen = 1 + xHyphWord->getHyphenPos();
- if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= (pLine->GetStart() + 2 ) ) )
+ if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= (rLine.GetStart() + 2 ) ) )
{
if ( !bAlternate )
{
@@ -1946,8 +2150,8 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
{
// TODO: handle all alternative hyphenations (see hyphen-1.2.8/tests/unicode.*)
OUString aAlt( xHyphWord->getHyphenatedWord() );
- OUString aAltLeft(aAlt.copy(0, _nWordLen));
- OUString aAltRight(aAlt.copy(_nWordLen));
+ std::u16string_view aAltLeft(aAlt.subView(0, _nWordLen));
+ std::u16string_view aAltRight(aAlt.subView(_nWordLen));
bAltFullLeft = aWord.startsWith(aAltLeft);
bAltFullRight = aWord.endsWith(aAltRight);
nAltDelChar = aWord.getLength() - aAlt.getLength() + static_cast<int>(!bAltFullLeft) + static_cast<int>(!bAltFullRight);
@@ -2006,39 +2210,42 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
}
}
- if ( nBreakPos <= pLine->GetStart() )
+ if ( nBreakPos <= rLine.GetStart() )
{
// No separator in line => Chop!
nBreakPos = nMaxBreakPos;
// I18N nextCharacters !
- if ( nBreakPos <= pLine->GetStart() )
- nBreakPos = pLine->GetStart() + 1; // Otherwise infinite loop!
+ if ( nBreakPos <= rLine.GetStart() )
+ nBreakPos = rLine.GetStart() + 1; // Otherwise infinite loop!
}
}
// the dickey portion is the end portion
- pLine->SetEnd( nBreakPos );
+ rLine.SetEnd( nBreakPos );
- sal_Int32 nEndPortion = SplitTextPortion( pParaPortion, nBreakPos, pLine );
+ sal_Int32 nEndPortion = SplitTextPortion(rParaPortion, nBreakPos, &rLine);
if ( !bCompressBlank && !bHangingPunctuation )
{
// When justification is not SvxAdjust::Left, it's important to compress
// the trailing space even if there is enough room for the space...
// Don't check for SvxAdjust::Left, doesn't matter to compress in this case too...
- assert( nBreakPos > pLine->GetStart() && "ImpBreakLines - BreakPos not expected!" );
+ assert( nBreakPos > rLine.GetStart() && "ImpBreakLines - BreakPos not expected!" );
if ( pNode->GetChar( nBreakPos-1 ) == ' ' )
bCompressBlank = true;
}
if ( bCompressBlank || bHangingPunctuation )
{
- TextPortion& rTP = pParaPortion->GetTextPortions()[nEndPortion];
+ TextPortion& rTP = rParaPortion.GetTextPortions()[nEndPortion];
DBG_ASSERT( rTP.GetKind() == PortionKind::TEXT, "BlankRubber: No TextPortion!" );
- DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion at the beginning of the line?" );
- sal_Int32 nPosInArray = nBreakPos - 1 - pLine->GetStart();
- rTP.GetSize().setWidth( ( nPosInArray && ( rTP.GetLen() > 1 ) ) ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 );
- pLine->GetCharPosArray()[ nPosInArray ] = rTP.GetSize().Width();
+ DBG_ASSERT( nBreakPos > rLine.GetStart(), "SplitTextPortion at the beginning of the line?" );
+ sal_Int32 nPosInArray = nBreakPos - 1 - rLine.GetStart();
+ rTP.setWidth( ( nPosInArray && ( rTP.GetLen() > 1 ) ) ? rLine.GetCharPosArray()[ nPosInArray-1 ] : 0 );
+ if (o3tl::make_unsigned(nPosInArray) < rLine.GetCharPosArray().size())
+ {
+ rLine.GetCharPosArray()[ nPosInArray ] = rTP.GetSize().Width();
+ }
}
else if ( bHyphenated )
{
@@ -2047,51 +2254,55 @@ void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, Te
pHyphPortion->SetKind( PortionKind::HYPHENATOR );
if ( (cAlternateReplChar || cAlternateExtraChar) && bAltFullRight ) // alternation after the break doesn't supported
{
- TextPortion& rPrev = pParaPortion->GetTextPortions()[nEndPortion];
+ TextPortion& rPrev = rParaPortion.GetTextPortions()[nEndPortion];
DBG_ASSERT( rPrev.GetLen(), "Hyphenate: Prev portion?!" );
rPrev.SetLen( rPrev.GetLen() - nAltDelChar );
pHyphPortion->SetLen( nAltDelChar );
if (cAlternateReplChar && !bAltFullLeft) pHyphPortion->SetExtraValue( cAlternateReplChar );
// Correct width of the portion above:
- rPrev.GetSize().setWidth(
- pLine->GetCharPosArray()[ nBreakPos-1 - pLine->GetStart() - nAltDelChar ] );
+ rPrev.setWidth(
+ rLine.GetCharPosArray()[ nBreakPos-1 - rLine.GetStart() - nAltDelChar ] );
}
// Determine the width of the Hyph-Portion:
SvxFont aFont;
- SeekCursor( pParaPortion->GetNode(), nBreakPos, aFont );
+ SeekCursor(rParaPortion.GetNode(), nBreakPos, aFont);
aFont.SetPhysFont(*GetRefDevice());
- pHyphPortion->GetSize().setHeight( GetRefDevice()->GetTextHeight() );
- pHyphPortion->GetSize().setWidth( GetRefDevice()->GetTextWidth( CH_HYPH ) );
+ pHyphPortion->SetSize(Size(GetRefDevice()->GetTextWidth(CH_HYPH), GetRefDevice()->GetTextHeight()));
- pParaPortion->GetTextPortions().Insert(++nEndPortion, pHyphPortion);
+ rParaPortion.GetTextPortions().Insert(++nEndPortion, pHyphPortion);
}
- pLine->SetEndPortion( nEndPortion );
+ rLine.SetEndPortion( nEndPortion );
}
-void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, tools::Long nRemainingSpace )
+void ImpEditEngine::ImpAdjustBlocks(ParaPortion& rParaPortion, EditLine& rLine, tools::Long nRemainingSpace )
{
DBG_ASSERT( nRemainingSpace > 0, "AdjustBlocks: Somewhat too little..." );
- assert( pLine && "AdjustBlocks: Line ?!" );
- if ( ( nRemainingSpace < 0 ) || pLine->IsEmpty() )
+
+ if ( ( nRemainingSpace < 0 ) || rLine.IsEmpty() )
return ;
- const sal_Int32 nFirstChar = pLine->GetStart();
- const sal_Int32 nLastChar = pLine->GetEnd() -1; // Last points behind
- ContentNode* pNode = pParaPortion->GetNode();
+ const sal_Int32 nFirstChar = rLine.GetStart();
+ const sal_Int32 nLastChar = rLine.GetEnd() -1; // Last points behind
+ ContentNode* pNode = rParaPortion.GetNode();
DBG_ASSERT( nLastChar < pNode->Len(), "AdjustBlocks: Out of range!" );
// Search blanks or Kashidas...
std::vector<sal_Int32> aPositions;
+
+ // Kashidas ?
+ ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions );
+ auto nKashidas = aPositions.size();
+
sal_uInt16 nLastScript = i18n::ScriptType::LATIN;
for ( sal_Int32 nChar = nFirstChar; nChar <= nLastChar; nChar++ )
{
EditPaM aPaM( pNode, nChar+1 );
- LanguageType eLang = GetLanguage(aPaM);
+ LanguageType eLang = GetLanguage(aPaM).nLang;
sal_uInt16 nScript = GetI18NScriptType(aPaM);
- if ( MsLangId::getPrimaryLanguage( eLang) == LANGUAGE_ARABIC_PRIMARY_ONLY )
- // Arabic script is handled later.
+ // Arabic script is handled above, but if no Kashida positions are found, use blanks.
+ if (MsLangId::getPrimaryLanguage(eLang) == LANGUAGE_ARABIC_PRIMARY_ONLY && nKashidas)
continue;
if ( pNode->GetChar(nChar) == ' ' )
@@ -2117,9 +2328,6 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine,
nLastScript = nScript;
}
- // Kashidas ?
- ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions );
-
if ( aPositions.empty() )
return;
@@ -2127,26 +2335,26 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine,
// The width must be distributed to the blockers in front...
// But not if it is the only one.
if ( ( pNode->GetChar( nLastChar ) == ' ' ) && ( aPositions.size() > 1 ) &&
- ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) )
+ ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ).nLang ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) )
{
aPositions.pop_back();
sal_Int32 nPortionStart, nPortion;
- nPortion = pParaPortion->GetTextPortions().FindPortion( nLastChar+1, nPortionStart );
- TextPortion& rLastPortion = pParaPortion->GetTextPortions()[ nPortion ];
- tools::Long nRealWidth = pLine->GetCharPosArray()[nLastChar-nFirstChar];
+ nPortion = rParaPortion.GetTextPortions().FindPortion( nLastChar+1, nPortionStart );
+ TextPortion& rLastPortion = rParaPortion.GetTextPortions()[ nPortion ];
+ tools::Long nRealWidth = rLine.GetCharPosArray()[nLastChar-nFirstChar];
tools::Long nBlankWidth = nRealWidth;
if ( nLastChar > nPortionStart )
- nBlankWidth -= pLine->GetCharPosArray()[nLastChar-nFirstChar-1];
+ nBlankWidth -= rLine.GetCharPosArray()[nLastChar-nFirstChar-1];
// Possibly the blank has already been deducted in ImpBreakLine:
if ( nRealWidth == rLastPortion.GetSize().Width() )
{
// For the last character the portion must stop behind the blank
// => Simplify correction:
DBG_ASSERT( ( nPortionStart + rLastPortion.GetLen() ) == ( nLastChar+1 ), "Blank actually not at the end of the portion!?");
- rLastPortion.GetSize().AdjustWidth( -nBlankWidth );
+ rLastPortion.adjustSize(-nBlankWidth, 0);
nRemainingSpace += nBlankWidth;
}
- pLine->GetCharPosArray()[nLastChar-nFirstChar] -= nBlankWidth;
+ rLine.GetCharPosArray()[nLastChar-nFirstChar] -= nBlankWidth;
}
size_t nGaps = aPositions.size();
@@ -2156,6 +2364,19 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine,
DBG_ASSERT( nSomeExtraSpace < static_cast<tools::Long>(nGaps), "AdjustBlocks: ExtraSpace too large" );
DBG_ASSERT( nSomeExtraSpace >= 0, "AdjustBlocks: ExtraSpace < 0 " );
+ // Mark Kashida positions, so that VCL knows where to insert Kashida and
+ // where to only expand the width.
+ if (nKashidas)
+ {
+ rLine.GetKashidaArray().resize(rLine.GetCharPosArray().size(), false);
+ for (size_t i = 0; i < nKashidas; i++)
+ {
+ auto nChar = aPositions[i];
+ if ( nChar < nLastChar )
+ rLine.GetKashidaArray()[nChar-nFirstChar] = 1 /*sal_True*/;
+ }
+ }
+
// Correct the positions in the Array and the portion widths:
// Last character won't be considered...
for (auto const& nChar : aPositions)
@@ -2163,22 +2384,23 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine,
if ( nChar < nLastChar )
{
sal_Int32 nPortionStart, nPortion;
- nPortion = pParaPortion->GetTextPortions().FindPortion( nChar, nPortionStart, true );
- TextPortion& rLastPortion = pParaPortion->GetTextPortions()[ nPortion ];
+ nPortion = rParaPortion.GetTextPortions().FindPortion( nChar, nPortionStart, true );
+ TextPortion& rLastPortion = rParaPortion.GetTextPortions()[ nPortion ];
// The width of the portion:
- rLastPortion.GetSize().AdjustWidth(nMore4Everyone );
- if ( nSomeExtraSpace )
- rLastPortion.GetSize().AdjustWidth( 1 );
+ rLastPortion.adjustSize(nMore4Everyone, 0);
+ if (nSomeExtraSpace)
+ {
+ rLastPortion.adjustSize(1, 0);
+ }
// Correct positions in array
- // Even for kashidas just change positions, VCL will then draw the kashida automatically
sal_Int32 nPortionEnd = nPortionStart + rLastPortion.GetLen();
for ( sal_Int32 _n = nChar; _n < nPortionEnd; _n++ )
{
- pLine->GetCharPosArray()[_n-nFirstChar] += nMore4Everyone;
+ rLine.GetCharPosArray()[_n-nFirstChar] += nMore4Everyone;
if ( nSomeExtraSpace )
- pLine->GetCharPosArray()[_n-nFirstChar]++;
+ rLine.GetCharPosArray()[_n-nFirstChar]++;
}
if ( nSomeExtraSpace )
@@ -2187,11 +2409,18 @@ void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine,
}
// Now the text width contains the extra width...
- pLine->SetTextWidth( pLine->GetTextWidth() + nRemainingSpace );
+ rLine.SetTextWidth(rLine.GetTextWidth() + nRemainingSpace);
}
+// For Kashidas from sw/source/core/text/porlay.cxx
void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEnd, std::vector<sal_Int32>& rArray )
{
+ // Kashida glyph looks suspicious, skip Kashida justification
+ if (GetRefDevice()->GetMinKashida() <= 0)
+ return;
+
+ std::vector<sal_Int32> aKashidaArray;
+
// the search has to be performed on a per word base
EditSelection aWordSel( EditPaM( pNode, nStart ) );
@@ -2210,12 +2439,20 @@ void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_I
// restore selection for proper iteration at the end of the function
aWordSel.Max().SetIndex( nSavPos );
- sal_Int32 nIdx = 0;
+ sal_Int32 nIdx = 0, nPrevIdx = 0;
sal_Int32 nKashidaPos = -1;
- sal_Unicode cCh;
- sal_Unicode cPrevCh = 0;
+ sal_Unicode cCh, cPrevCh = 0;
+
+ int nPriorityLevel = 7; // 0..6 = level found
+ // 7 not found
- while ( nIdx < aWord.getLength() )
+ sal_Int32 nWordLen = aWord.getLength();
+
+ // ignore trailing vowel chars
+ while( nWordLen && isTransparentChar( aWord[ nWordLen - 1 ] ))
+ --nWordLen;
+
+ while ( nIdx < nWordLen )
{
cCh = aWord[ nIdx ];
@@ -2224,104 +2461,163 @@ void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, sal_Int32 nStart, sal_I
if ( 0x640 == cCh )
{
nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
- break;
+ nPriorityLevel = 0;
}
// 2. Priority:
// after a Seen or Sad
- if ( nIdx + 1 < aWord.getLength() &&
- ( 0x633 == cCh || 0x635 == cCh ) )
+ if (nPriorityLevel >= 1 && nIdx < nWordLen - 1)
{
- nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
- break;
+ if( isSeenOrSadChar( cCh )
+ && (aWord[ nIdx+1 ] != 0x200C) ) // #i98410#: prevent ZWNJ expansion
+ {
+ nKashidaPos = aWordSel.Min().GetIndex() + nIdx;
+ nPriorityLevel = 1;
+ }
}
// 3. Priority:
- // before final form of the Marbuta, Hah, Dal
- // 4. Priority:
- // before final form of Alef, Lam or Kaf
- if ( nIdx && nIdx + 1 == aWord.getLength() &&
- ( 0x629 == cCh || 0x62D == cCh || 0x62F == cCh ||
- 0x627 == cCh || 0x644 == cCh || 0x643 == cCh ) )
+ // before final form of Teh Marbuta, Heh, Dal
+ if ( nPriorityLevel >= 2 && nIdx > 0 )
{
- DBG_ASSERT( 0 != cPrevCh, "No previous character" );
+ if ( isTehMarbutaChar ( cCh ) || // Teh Marbuta (right joining)
+ isDalChar ( cCh ) || // Dal (right joining) final form may appear in the middle of word
+ ( isHehChar ( cCh ) && nIdx == nWordLen - 1)) // Heh (dual joining) only at end of word
+ {
- // check if character is connectable to previous character,
- if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ SAL_WARN_IF( 0 == cPrevCh, "editeng", "No previous character" );
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aWordSel.Min().GetIndex() + nPrevIdx;
+ nPriorityLevel = 2;
+ }
+ }
+ }
+
+ // 4. Priority:
+ // before final form of Alef, Tah, Lam, Kaf or Gaf
+ if ( nPriorityLevel >= 3 && nIdx > 0 )
+ {
+ if ( isAlefChar ( cCh ) || // Alef (right joining) final form may appear in the middle of word
+ (( isLamChar ( cCh ) || // Lam,
+ isTahChar ( cCh ) || // Tah,
+ isKafChar ( cCh ) || // Kaf (all dual joining)
+ isGafChar ( cCh ) )
+ && nIdx == nWordLen - 1)) // only at end of word
{
- nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
- break;
+ SAL_WARN_IF( 0 == cPrevCh, "editeng", "No previous character" );
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aWordSel.Min().GetIndex() + nPrevIdx;
+ nPriorityLevel = 3;
+ }
}
}
// 5. Priority:
- // before media Bah
- if ( nIdx && nIdx + 1 < aWord.getLength() && 0x628 == cCh )
+ // before medial Beh-like
+ if ( nPriorityLevel >= 4 && nIdx > 0 && nIdx < nWordLen - 1 )
{
- DBG_ASSERT( 0 != cPrevCh, "No previous character" );
-
- // check if next character is Reh, Yeh or Alef Maksura
- sal_Unicode cNextCh = aWord[ nIdx + 1 ];
+ if ( isBehChar ( cCh ) )
+ {
+ // check if next character is Reh or Yeh-like
+ sal_Unicode cNextCh = aWord[ nIdx + 1 ];
+ if ( isRehChar ( cNextCh ) || isYehChar ( cNextCh ))
+ {
+ SAL_WARN_IF( 0 == cPrevCh, "editeng", "No previous character" );
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aWordSel.Min().GetIndex() + nPrevIdx;
+ nPriorityLevel = 4;
+ }
+ }
+ }
+ }
- if ( 0x631 == cNextCh || 0x64A == cNextCh ||
- 0x649 == cNextCh )
+ // 6. Priority:
+ // before the final form of Waw, Ain, Qaf and Feh
+ if ( nPriorityLevel >= 5 && nIdx > 0 )
+ {
+ if ( isWawChar ( cCh ) || // Wav (right joining)
+ // final form may appear in the middle of word
+ (( isAinChar ( cCh ) || // Ain (dual joining)
+ isQafChar ( cCh ) || // Qaf (dual joining)
+ isFehChar ( cCh ) ) // Feh (dual joining)
+ && nIdx == nWordLen - 1)) // only at end of word
{
+ SAL_WARN_IF( 0 == cPrevCh, "editeng", "No previous character" );
// check if character is connectable to previous character,
if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
- nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
+ {
+ nKashidaPos = aWordSel.Min().GetIndex() + nPrevIdx;
+ nPriorityLevel = 5;
+ }
}
}
- // 6. Priority:
// other connecting possibilities
- if ( nIdx && nIdx + 1 == aWord.getLength() &&
- 0x60C <= cCh && 0x6FE >= cCh )
+ if ( nPriorityLevel >= 6 && nIdx > 0 )
{
- DBG_ASSERT( 0 != cPrevCh, "No previous character" );
-
- // check if character is connectable to previous character,
- if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ // Reh, Zain
+ if ( isRehChar ( cCh ) )
{
- // only choose this position if we did not find
- // a better one:
- if ( nKashidaPos<0 )
- nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1;
- break;
+ SAL_WARN_IF( 0 == cPrevCh, "editeng", "No previous character" );
+ // check if character is connectable to previous character,
+ if ( lcl_ConnectToPrev( cCh, cPrevCh ) )
+ {
+ nKashidaPos = aWordSel.Min().GetIndex() + nPrevIdx;
+ nPriorityLevel = 6;
+ }
}
}
- // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
- // Damma, Kasra, Shadda and Sukun when checking if
- // a character can be connected to previous character.
- if ( cCh < 0x64B || cCh > 0x652 )
+ // Do not consider vowel marks when checking if a character
+ // can be connected to previous character.
+ if ( !isTransparentChar ( cCh) )
+ {
cPrevCh = cCh;
+ nPrevIdx = nIdx;
+ }
++nIdx;
} // end of current word
if ( nKashidaPos>=0 )
- rArray.push_back( nKashidaPos );
+ aKashidaArray.push_back( nKashidaPos );
aWordSel = WordRight( aWordSel.Max(), css::i18n::WordType::DICTIONARY_WORD );
aWordSel = SelectWord( aWordSel, css::i18n::WordType::DICTIONARY_WORD );
}
+
+ // Validate
+ std::vector<sal_Int32> aDropped(aKashidaArray.size());
+ auto nOldLayout = GetRefDevice()->GetLayoutMode();
+ GetRefDevice()->SetLayoutMode(nOldLayout | vcl::text::ComplexTextLayoutFlags::BiDiRtl);
+ GetRefDevice()->ValidateKashidas(pNode->GetString(), nStart, nEnd - nStart,
+ aKashidaArray.size(), aKashidaArray.data(), aDropped.data());
+ GetRefDevice()->SetLayoutMode(nOldLayout);
+
+ for (auto const& pos : aKashidaArray)
+ if (std::find(aDropped.begin(), aDropped.end(), pos) == aDropped.end())
+ rArray.push_back(pos);
}
-sal_Int32 ImpEditEngine::SplitTextPortion( ParaPortion* pPortion, sal_Int32 nPos, EditLine* pCurLine )
+sal_Int32 ImpEditEngine::SplitTextPortion(ParaPortion& rParaPortion, sal_Int32 nPos, EditLine* pCurLine)
{
// The portion at nPos is split, if there is not a transition at nPos anyway
if ( nPos == 0 )
return 0;
- assert( pPortion && "SplitTextPortion: Which ?" );
-
sal_Int32 nSplitPortion;
sal_Int32 nTmpPos = 0;
TextPortion* pTextPortion = nullptr;
- sal_Int32 nPortions = pPortion->GetTextPortions().Count();
+ sal_Int32 nPortions = rParaPortion.GetTextPortions().Count();
for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ )
{
- TextPortion& rTP = pPortion->GetTextPortions()[nSplitPortion];
+ TextPortion& rTP = rParaPortion.GetTextPortions()[nSplitPortion];
nTmpPos = nTmpPos + rTP.GetLen();
if ( nTmpPos >= nPos )
{
@@ -2344,44 +2640,45 @@ sal_Int32 ImpEditEngine::SplitTextPortion( ParaPortion* pPortion, sal_Int32 nPos
sal_Int32 nOverlapp = nTmpPos - nPos;
pTextPortion->SetLen( pTextPortion->GetLen() - nOverlapp );
TextPortion* pNewPortion = new TextPortion( nOverlapp );
- pPortion->GetTextPortions().Insert(nSplitPortion+1, pNewPortion);
+ rParaPortion.GetTextPortions().Insert(nSplitPortion+1, pNewPortion);
// Set sizes
if ( pCurLine )
{
// No new GetTextSize, instead use values from the Array:
assert( nPos > pCurLine->GetStart() && "SplitTextPortion at the beginning of the line?" );
- pTextPortion->GetSize().setWidth( pCurLine->GetCharPosArray()[ nPos-pCurLine->GetStart()-1 ] );
+ pTextPortion->setWidth(pCurLine->GetCharPosArray()[nPos - pCurLine->GetStart() - 1]);
if ( pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed )
{
// We need the original size from the portion
- sal_Int32 nTxtPortionStart = pPortion->GetTextPortions().GetStartPos( nSplitPortion );
- SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() );
- SeekCursor( pPortion->GetNode(), nTxtPortionStart+1, aTmpFont );
+ sal_Int32 nTxtPortionStart = rParaPortion.GetTextPortions().GetStartPos( nSplitPortion );
+ SvxFont aTmpFont = rParaPortion.GetNode()->GetCharAttribs().GetDefFont();
+ SeekCursor(rParaPortion.GetNode(), nTxtPortionStart + 1, aTmpFont);
aTmpFont.SetPhysFont(*GetRefDevice());
GetRefDevice()->Push( vcl::PushFlags::TEXTLANGUAGE );
ImplInitDigitMode(*GetRefDevice(), aTmpFont.GetLanguage());
- Size aSz = aTmpFont.QuickGetTextSize( GetRefDevice(), pPortion->GetNode()->GetString(), nTxtPortionStart, pTextPortion->GetLen() );
+ Size aSz = aTmpFont.QuickGetTextSize( GetRefDevice(), rParaPortion.GetNode()->GetString(),
+ nTxtPortionStart, pTextPortion->GetLen(), nullptr );
GetRefDevice()->Pop();
pTextPortion->GetExtraInfos()->nOrgWidth = aSz.Width();
}
}
else
- pTextPortion->GetSize().setWidth( -1 );
+ pTextPortion->setWidth(-1);
return nSplitPortion;
}
-void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_Int32& rStart )
+void ImpEditEngine::CreateTextPortions(ParaPortion& rParaPortion, sal_Int32& rStart)
{
sal_Int32 nStartPos = rStart;
- ContentNode* pNode = pParaPortion->GetNode();
+ ContentNode* pNode = rParaPortion.GetNode();
DBG_ASSERT( pNode->Len(), "CreateTextPortions should not be used for empty paragraphs!" );
o3tl::sorted_vector< sal_Int32 > aPositions;
aPositions.insert( 0 );
- for (sal_uInt16 nAttr = 0;; ++nAttr)
+ for (std::size_t nAttr = 0;; ++nAttr)
{
// Insert Start and End into the Array...
// The Insert method does not allow for duplicate values...
@@ -2393,15 +2690,13 @@ void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_Int32& rS
}
aPositions.insert( pNode->Len() );
- if ( pParaPortion->aScriptInfos.empty() )
- InitScriptTypes( GetParaPortions().GetPos( pParaPortion ) );
+ if (rParaPortion.getScriptTypePosInfos().empty())
+ InitScriptTypes(GetParaPortions().GetPos(&rParaPortion));
- const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
- for (const ScriptTypePosInfo& rType : rTypes)
+ for (const ScriptTypePosInfo& rType : rParaPortion.getScriptTypePosInfos())
aPositions.insert( rType.nStartPos );
- const WritingDirectionInfos& rWritingDirections = pParaPortion->aWritingDirectionInfos;
- for (const WritingDirectionInfo & rWritingDirection : rWritingDirections)
+ for (const WritingDirectionInfo& rWritingDirection : rParaPortion.getWritingDirectionInfos())
aPositions.insert( rWritingDirection.nStartPos );
if ( mpIMEInfos && mpIMEInfos->nLen && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) )
@@ -2424,9 +2719,9 @@ void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_Int32& rS
sal_Int32 nPortionStart = 0;
sal_Int32 nInvPortion = 0;
sal_Int32 nP;
- for ( nP = 0; nP < pParaPortion->GetTextPortions().Count(); nP++ )
+ for ( nP = 0; nP < rParaPortion.GetTextPortions().Count(); nP++ )
{
- const TextPortion& rTmpPortion = pParaPortion->GetTextPortions()[nP];
+ const TextPortion& rTmpPortion = rParaPortion.GetTextPortions()[nP];
nPortionStart = nPortionStart + rTmpPortion.GetLen();
if ( nPortionStart >= nStartPos )
{
@@ -2436,16 +2731,16 @@ void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_Int32& rS
break;
}
}
- DBG_ASSERT( nP < pParaPortion->GetTextPortions().Count() || !pParaPortion->GetTextPortions().Count(), "Nothing to delete: CreateTextPortions" );
- if ( nInvPortion && ( nPortionStart+pParaPortion->GetTextPortions()[nInvPortion].GetLen() > nStartPos ) )
+ DBG_ASSERT( nP < rParaPortion.GetTextPortions().Count() || !rParaPortion.GetTextPortions().Count(), "Nothing to delete: CreateTextPortions" );
+ if ( nInvPortion && ( nPortionStart + rParaPortion.GetTextPortions()[nInvPortion].GetLen() > nStartPos ) )
{
// prefer one in front...
// But only if it was in the middle of the portion of, otherwise it
// might be the only one in the row in front!
nInvPortion--;
- nPortionStart = nPortionStart - pParaPortion->GetTextPortions()[nInvPortion].GetLen();
+ nPortionStart = nPortionStart - rParaPortion.GetTextPortions()[nInvPortion].GetLen();
}
- pParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion );
+ rParaPortion.GetTextPortions().DeleteFromPortion( nInvPortion );
// A portion may also have been formed by a line break:
aPositions.insert( nPortionStart );
@@ -2458,21 +2753,21 @@ void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_Int32& rS
while ( i != aPositions.end() )
{
TextPortion* pNew = new TextPortion( (*i++) - *nInvPos++ );
- pParaPortion->GetTextPortions().Append(pNew);
+ rParaPortion.GetTextPortions().Append(pNew);
}
- DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No Portions?!" );
+ DBG_ASSERT(rParaPortion.GetTextPortions().Count(), "No Portions?!");
#if OSL_DEBUG_LEVEL > 0
- OSL_ENSURE( ParaPortion::DbgCheckTextPortions(*pParaPortion), "Portion is broken?" );
+ OSL_ENSURE( ParaPortion::DbgCheckTextPortions(rParaPortion), "Portion is broken?" );
#endif
}
-void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_Int32 nStartPos, sal_Int32 nNewChars )
+void ImpEditEngine::RecalcTextPortion(ParaPortion& rParaPortion, sal_Int32 nStartPos, sal_Int32 nNewChars)
{
- DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "No Portions!" );
+ DBG_ASSERT(rParaPortion.GetTextPortions().Count(), "No Portions!");
DBG_ASSERT( nNewChars, "RecalcTextPortion with Diff == 0" );
- ContentNode* const pNode = pParaPortion->GetNode();
+ ContentNode* const pNode = rParaPortion.GetNode();
if ( nNewChars > 0 )
{
// If an Attribute begins/ends at nStartPos, then a new portion starts
@@ -2481,31 +2776,30 @@ void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_Int32 nSta
{
sal_Int32 nNewPortionPos = 0;
if ( nStartPos )
- nNewPortionPos = SplitTextPortion( pParaPortion, nStartPos ) + 1;
+ nNewPortionPos = SplitTextPortion(rParaPortion, nStartPos) + 1;
// A blank portion may be here, if the paragraph was empty,
// or if a line was created by a hard line break.
- if ( ( nNewPortionPos < pParaPortion->GetTextPortions().Count() ) &&
- !pParaPortion->GetTextPortions()[nNewPortionPos].GetLen() )
+ if ( ( nNewPortionPos < rParaPortion.GetTextPortions().Count() ) &&
+ !rParaPortion.GetTextPortions()[nNewPortionPos].GetLen() )
{
- TextPortion& rTP = pParaPortion->GetTextPortions()[nNewPortionPos];
+ TextPortion& rTP = rParaPortion.GetTextPortions()[nNewPortionPos];
DBG_ASSERT( rTP.GetKind() == PortionKind::TEXT, "the empty portion was no TextPortion!" );
rTP.SetLen( rTP.GetLen() + nNewChars );
}
else
{
TextPortion* pNewPortion = new TextPortion( nNewChars );
- pParaPortion->GetTextPortions().Insert(nNewPortionPos, pNewPortion);
+ rParaPortion.GetTextPortions().Insert(nNewPortionPos, pNewPortion);
}
}
else
{
sal_Int32 nPortionStart;
- const sal_Int32 nTP = pParaPortion->GetTextPortions().
- FindPortion( nStartPos, nPortionStart );
- TextPortion& rTP = pParaPortion->GetTextPortions()[ nTP ];
+ const sal_Int32 nTP = rParaPortion.GetTextPortions().FindPortion( nStartPos, nPortionStart );
+ TextPortion& rTP = rParaPortion.GetTextPortions()[ nTP ];
rTP.SetLen( rTP.GetLen() + nNewChars );
- rTP.GetSize().setWidth( -1 );
+ rTP.setWidth(-1);
}
}
else
@@ -2520,11 +2814,11 @@ void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_Int32 nSta
sal_Int32 nPortion = 0;
sal_Int32 nPos = 0;
sal_Int32 nEnd = nStartPos-nNewChars;
- sal_Int32 nPortions = pParaPortion->GetTextPortions().Count();
+ sal_Int32 nPortions = rParaPortion.GetTextPortions().Count();
TextPortion* pTP = nullptr;
for ( nPortion = 0; nPortion < nPortions; nPortion++ )
{
- pTP = &pParaPortion->GetTextPortions()[ nPortion ];
+ pTP = &rParaPortion.GetTextPortions()[ nPortion ];
if ( ( nPos+pTP->GetLen() ) > nStartPos )
{
DBG_ASSERT( nPos <= nStartPos, "Wrong Start!" );
@@ -2538,14 +2832,14 @@ void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_Int32 nSta
{
// Remove portion;
PortionKind nType = pTP->GetKind();
- pParaPortion->GetTextPortions().Remove( nPortion );
+ rParaPortion.GetTextPortions().Remove( nPortion );
if ( nType == PortionKind::LINEBREAK )
{
- TextPortion& rNext = pParaPortion->GetTextPortions()[ nPortion ];
+ TextPortion& rNext = rParaPortion.GetTextPortions()[ nPortion ];
if ( !rNext.GetLen() )
{
// Remove dummy portion
- pParaPortion->GetTextPortions().Remove( nPortion );
+ rParaPortion.GetTextPortions().Remove( nPortion );
}
}
}
@@ -2555,48 +2849,47 @@ void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_Int32 nSta
pTP->SetLen( pTP->GetLen() + nNewChars );
}
- sal_Int32 nPortionCount = pParaPortion->GetTextPortions().Count();
+ sal_Int32 nPortionCount = rParaPortion.GetTextPortions().Count();
assert( nPortionCount );
if (nPortionCount)
{
// No HYPHENATOR portion is allowed to get stuck right at the end...
sal_Int32 nLastPortion = nPortionCount - 1;
- pTP = &pParaPortion->GetTextPortions()[nLastPortion];
+ pTP = &rParaPortion.GetTextPortions()[nLastPortion];
if ( pTP->GetKind() == PortionKind::HYPHENATOR )
{
// Discard portion; if possible, correct the ones before,
// if the Hyphenator portion has swallowed one character...
if ( nLastPortion && pTP->GetLen() )
{
- TextPortion& rPrev = pParaPortion->GetTextPortions()[nLastPortion - 1];
+ TextPortion& rPrev = rParaPortion.GetTextPortions()[nLastPortion - 1];
DBG_ASSERT( rPrev.GetKind() == PortionKind::TEXT, "Portion?!" );
rPrev.SetLen( rPrev.GetLen() + pTP->GetLen() );
- rPrev.GetSize().setWidth( -1 );
+ rPrev.setWidth(-1);
}
- pParaPortion->GetTextPortions().Remove( nLastPortion );
+ rParaPortion.GetTextPortions().Remove( nLastPortion );
}
}
}
#if OSL_DEBUG_LEVEL > 0
- OSL_ENSURE( ParaPortion::DbgCheckTextPortions(*pParaPortion), "Portions are broken?" );
+ OSL_ENSURE( ParaPortion::DbgCheckTextPortions(rParaPortion), "Portions are broken?" );
#endif
}
void ImpEditEngine::SetTextRanger( std::unique_ptr<TextRanger> pRanger )
{
- pTextRanger = std::move(pRanger);
+ mpTextRanger = std::move(pRanger);
- for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
+ for (auto& pParaPortion : GetParaPortions())
{
- ParaPortion& rParaPortion = GetParaPortions()[nPara];
- rParaPortion.MarkSelectionInvalid( 0 );
- rParaPortion.GetLines().Reset();
+ pParaPortion->MarkSelectionInvalid( 0 );
+ pParaPortion->GetLines().Reset();
}
FormatFullDoc();
UpdateViews( GetActiveView() );
if ( IsUpdateLayout() && GetActiveView() )
- pActiveView->ShowCursor(false, false);
+ mpActiveView->ShowCursor(false, false);
}
void ImpEditEngine::SetVertical( bool bVertical)
@@ -2604,7 +2897,7 @@ void ImpEditEngine::SetVertical( bool bVertical)
if ( IsEffectivelyVertical() != bVertical)
{
GetEditDoc().SetVertical(bVertical);
- bool bUseCharAttribs = bool(aStatus.GetControlWord() & EEControlBits::USECHARATTRIBS);
+ bool bUseCharAttribs = bool(maStatus.GetControlWord() & EEControlBits::USECHARATTRIBS);
GetEditDoc().CreateDefFont( bUseCharAttribs );
if ( IsFormatted() )
{
@@ -2616,8 +2909,10 @@ void ImpEditEngine::SetVertical( bool bVertical)
void ImpEditEngine::SetRotation(TextRotation nRotation)
{
+ if (GetEditDoc().GetRotation() == nRotation)
+ return; // not modified
GetEditDoc().SetRotation(nRotation);
- bool bUseCharAttribs = bool(aStatus.GetControlWord() & EEControlBits::USECHARATTRIBS);
+ bool bUseCharAttribs = bool(maStatus.GetControlWord() & EEControlBits::USECHARATTRIBS);
GetEditDoc().CreateDefFont( bUseCharAttribs );
if ( IsFormatted() )
{
@@ -2628,8 +2923,14 @@ void ImpEditEngine::SetRotation(TextRotation nRotation)
void ImpEditEngine::SetTextColumns(sal_Int16 nColumns, sal_Int32 nSpacing)
{
+ assert(nColumns >= 1);
if (mnColumns != nColumns || mnColumnSpacing != nSpacing)
{
+ if (nColumns == 0)
+ {
+ SAL_WARN("editeng", "bad nColumns value, ignoring");
+ nColumns = 1;
+ }
mnColumns = nColumns;
mnColumnSpacing = nSpacing;
if (IsFormatted())
@@ -2710,7 +3011,7 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
/*
* Scan through char attributes of pNode
*/
- if ( aStatus.UseCharAttribs() )
+ if (maStatus.UseCharAttribs())
{
CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
size_t nAttr = 0;
@@ -2732,7 +3033,11 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
// #i1550# hard color attrib should win over text color from field
if ( pAttrib->Which() == EE_FEATURE_FIELD )
{
- EditCharAttrib* pColorAttr = pNode->GetCharAttribs().FindAttrib( EE_CHAR_COLOR, nPos );
+ // These Attribs positions come from PaMs, so their interval is right-open and left-closed
+ // when SeekCursor is called, nPos is incremented by 1. I do not know why...
+ // probably designed to be a nEndPos, and like in a PaM, it is the position after the actual character.
+ sal_Int32 nPosActual = nPos > 0 ? nPos - 1 : 0;
+ EditCharAttrib* pColorAttr = pNode->GetCharAttribs().FindAttribRightOpen( EE_CHAR_COLOR, nPosActual );
if ( pColorAttr )
pColorAttr->SetFont( rFont, pOut );
}
@@ -2754,12 +3059,12 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
if ( (rFont.GetKerning() != FontKerning::NONE) && IsKernAsianPunctuation() && ( nScriptTypeI18N == i18n::ScriptType::ASIAN ) )
rFont.SetKerning( rFont.GetKerning() | FontKerning::Asian );
- if ( aStatus.DoNotUseColors() )
+ if (maStatus.DoNotUseColors())
{
rFont.SetColor( /* rColorItem.GetValue() */ COL_BLACK );
}
- if ( aStatus.DoStretch() || ( nRelWidth != 100 ) )
+ if (maStatus.DoStretch() || ( nRelWidth != 100 ))
{
// For the current Output device, because otherwise if RefDev=Printer its looks
// ugly on the screen!
@@ -2778,24 +3083,29 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
Size aRealSz( aMetric.GetFontSize() );
rFont.SetPropr( 100 );
- if ( aStatus.DoStretch() )
+ if (maStatus.DoStretch())
{
- if ( nStretchY != 100 )
+ if (maScalingParameters.fFontY != 1.0)
{
- aRealSz.setHeight( aRealSz.Height() * nStretchY );
- aRealSz.setHeight( aRealSz.Height() / 100 );
+ double fHeightRounded = roundToNearestPt(aRealSz.Height());
+ double fNewHeight = fHeightRounded * maScalingParameters.fFontY;
+ fNewHeight = roundToNearestPt(fNewHeight);
+ aRealSz.setHeight(basegfx::fround<tools::Long>(fNewHeight));
}
- if ( nStretchX != 100 )
+ if (maScalingParameters.fFontX != 1.0)
{
- if ( nStretchX == nStretchY &&
- nRelWidth == 100 )
+ auto fFontX = maScalingParameters.fFontX;
+ auto fFontY = maScalingParameters.fFontY;
+ if (fFontX == fFontY && nRelWidth == 100 )
{
aRealSz.setWidth( 0 );
}
else
{
- aRealSz.setWidth( aRealSz.Width() * nStretchX );
- aRealSz.setWidth( aRealSz.Width() / 100 );
+ double fWidthRounded = roundToNearestPt(aRealSz.Width());
+ double fNewWidth = fWidthRounded * fFontX;
+ fNewWidth = roundToNearestPt(fNewWidth);
+ aRealSz.setWidth(basegfx::fround<tools::Long>(fNewWidth));
// Also the Kerning: (long due to handle Interim results)
tools::Long nKerning = rFont.GetFixKerning();
@@ -2810,17 +3120,15 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
>0 >100 > (Proportional)
<0 >100 < (The amount, thus disproportional)
*/
- if ( ( nKerning < 0 ) && ( nStretchX > 100 ) )
+ if (nKerning < 0 && fFontX > 1.0)
{
// disproportional
- nKerning *= 100;
- nKerning /= nStretchX;
+ nKerning = basegfx::fround(nKerning / fFontX);
}
else if ( nKerning )
{
// Proportional
- nKerning *= nStretchX;
- nKerning /= 100;
+ nKerning = basegfx::fround(nKerning * fFontX);
}
rFont.SetFixKerning( static_cast<short>(nKerning) );
}
@@ -2862,6 +3170,8 @@ void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_Int32 nPos, SvxFont& rFo
ExtTextInputAttr nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ];
if ( nAttr & ExtTextInputAttr::Underline )
rFont.SetUnderline( LINESTYLE_SINGLE );
+ else if ( nAttr & ExtTextInputAttr::DoubleUnderline )
+ rFont.SetUnderline( LINESTYLE_DOUBLE );
else if ( nAttr & ExtTextInputAttr::BoldUnderline )
rFont.SetUnderline( LINESTYLE_BOLD );
else if ( nAttr & ExtTextInputAttr::DottedUnderline )
@@ -2895,11 +3205,11 @@ void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics
if ( nPropr != 100 )
{
rFont.SetPropr( 100 );
- rFont.SetPhysFont(*pRefDev);
+ rFont.SetPhysFont(*mpRefDev);
}
sal_uInt16 nAscent, nDescent;
- FontMetric aMetric( pRefDev->GetFontMetric() );
+ FontMetric aMetric(mpRefDev->GetFontMetric());
nAscent = static_cast<sal_uInt16>(aMetric.GetAscent());
if ( IsAddExtLeading() )
nAscent = sal::static_int_cast< sal_uInt16 >(
@@ -2915,10 +3225,10 @@ void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics
{
sal_uInt16 nIntLeading = ( aMetric.GetInternalLeading() > 0 ) ? static_cast<sal_uInt16>(aMetric.GetInternalLeading()) : 0;
// Fonts without leading cause problems
- if ( ( nIntLeading == 0 ) && ( pRefDev->GetOutDevType() == OUTDEV_PRINTER ) )
+ if ( ( nIntLeading == 0 ) && (mpRefDev->GetOutDevType() == OUTDEV_PRINTER))
{
// Lets see what Leading one gets on the screen
- VclPtr<VirtualDevice> pVDev = GetVirtualDevice( pRefDev->GetMapMode(), pRefDev->GetDrawMode() );
+ VclPtr<VirtualDevice> pVDev = GetVirtualDevice(mpRefDev->GetMapMode(), mpRefDev->GetDrawMode());
rFont.SetPhysFont(*pVDev);
aMetric = pVDev->GetFontMetric();
@@ -3055,13 +3365,13 @@ Point ImpEditEngine::MoveToNextLine(
// Move the point by the requested distance in Y direction
adjustYDirectionAware(rMovePos, nLineHeight);
// Check if the resulting position has moved beyond the limits, and more columns left.
- // The limits are defined by a rectangle starting from aOrigin with width of aPaperSize
- // and height of nCurTextHeight
+ // The limits are defined by a rectangle starting from aOrigin with width of maPaperSize
+ // and height of mnCurTextHeight
Point aOtherCorner = aOrigin;
- adjustXDirectionAware(aOtherCorner, getWidthDirectionAware(aPaperSize));
- adjustYDirectionAware(aOtherCorner, nCurTextHeight);
+ adjustXDirectionAware(aOtherCorner, getWidthDirectionAware(maPaperSize));
+ adjustYDirectionAware(aOtherCorner, mnCurTextHeight);
tools::Long nNeeded
- = getYOverflowDirectionAware(rMovePos, tools::Rectangle::Justify(aOrigin, aOtherCorner));
+ = getYOverflowDirectionAware(rMovePos, tools::Rectangle::Normalize(aOrigin, aOtherCorner));
if (pnHeightNeededToNotWrap)
*pnHeightNeededToNotWrap = nNeeded;
if (nNeeded && rColumn < mnColumns)
@@ -3076,7 +3386,7 @@ Point ImpEditEngine::MoveToNextLine(
// Move the point by the requested distance in Y direction
adjustYDirectionAware(rMovePos, nLineHeight);
// Move the point by the column+spacing distance in X direction
- adjustXDirectionAware(rMovePos, GetColumnWidth(aPaperSize) + mnColumnSpacing);
+ adjustXDirectionAware(rMovePos, GetColumnWidth(maPaperSize) + mnColumnSpacing);
}
}
@@ -3084,7 +3394,6 @@ Point ImpEditEngine::MoveToNextLine(
}
// TODO: use IterateLineAreas in ImpEditEngine::Paint, to avoid algorithm duplication
-
void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Point aStartPos, bool bStripOnly, Degree10 nOrientation )
{
if ( !IsUpdateLayout() && !bStripOnly )
@@ -3097,7 +3406,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
tools::Long nFirstVisYPos = - rOutDev.GetMapMode().GetOrigin().Y();
DBG_ASSERT( GetParaPortions().Count(), "No ParaPortion?!" );
- SvxFont aTmpFont( GetParaPortions()[0].GetNode()->GetCharAttribs().GetDefFont() );
+ SvxFont aTmpFont = GetParaPortions().getRef(0).GetNode()->GetCharAttribs().GetDefFont();
vcl::PDFExtOutDevData* const pPDFExtOutDevData = dynamic_cast< vcl::PDFExtOutDevData* >( rOutDev.GetExtOutDevData() );
// In the case of rotated text is aStartPos considered TopLeft because
@@ -3105,13 +3414,6 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// un-scrolled.
// The rectangle is infinite.
const Point aOrigin( aStartPos );
- double nCos = 0.0, nSin = 0.0;
- if ( nOrientation )
- {
- double nRealOrientation = nOrientation.get()*F_PI1800;
- nCos = cos( nRealOrientation );
- nSin = sin( nRealOrientation );
- }
// #110496# Added some more optional metafile comments. This
// change: factored out some duplicated code.
@@ -3124,19 +3426,19 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// Over all the paragraphs...
- for ( sal_Int32 n = 0; n < GetParaPortions().Count(); n++ )
+ for (sal_Int32 nParaPortion = 0; nParaPortion < GetParaPortions().Count(); nParaPortion++)
{
- const ParaPortion& rPortion = GetParaPortions()[n];
+ ParaPortion const& rParaPortion = GetParaPortions().getRef(nParaPortion);
// if when typing idle formatting, asynchronous Paint.
// Invisible Portions may be invalid.
- if ( rPortion.IsVisible() && rPortion.IsInvalid() )
+ if (rParaPortion.IsVisible() && rParaPortion.IsInvalid())
return;
if ( pPDFExtOutDevData )
- pPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
+ pPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::Paragraph);
- const tools::Long nParaHeight = rPortion.GetHeight();
- if ( rPortion.IsVisible() && (
+ const tools::Long nParaHeight = rParaPortion.GetHeight();
+ if (rParaPortion.IsVisible() && (
( !IsEffectivelyVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRect.Top() ) ) ||
( IsEffectivelyVertical() && IsTopToBottom() && ( ( aStartPos.X() - nParaHeight ) < aClipRect.Right() ) ) ||
( IsEffectivelyVertical() && !IsTopToBottom() && ( ( aStartPos.X() + nParaHeight ) > aClipRect.Left() ) ) ) )
@@ -3146,22 +3448,21 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// Over the lines of the paragraph...
- const sal_Int32 nLines = rPortion.GetLines().Count();
+ const sal_Int32 nLines = rParaPortion.GetLines().Count();
const sal_Int32 nLastLine = nLines-1;
bool bEndOfParagraphWritten(false);
- adjustYDirectionAware(aStartPos, rPortion.GetFirstLineOffset());
+ adjustYDirectionAware(aStartPos, rParaPortion.GetFirstLineOffset());
- const SvxLineSpacingItem& rLSItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
+ const SvxLineSpacingItem& rLSItem = rParaPortion.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++ )
{
- const EditLine* const pLine = &rPortion.GetLines()[nLine];
- assert( pLine && "NULL-Pointer in the line iterator in UpdateViews" );
+ EditLine* pLine = &GetParaPortions().getRef(nParaPortion).GetLines()[nLine];
sal_Int32 nIndex = pLine->GetStart();
tools::Long nLineHeight = pLine->GetHeight();
if (nLine != nLastLine)
@@ -3185,10 +3486,10 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
{
Point aLineStart(aStartPos);
adjustYDirectionAware(aLineStart, -nLineHeight);
- GetEditEnginePtr()->PaintingFirstLine(n, aLineStart, aOrigin, nOrientation, rOutDev);
+ GetEditEnginePtr()->PaintingFirstLine(nParaPortion, aLineStart, aOrigin, nOrientation, rOutDev);
// Remember whether a bullet was painted.
- const SfxBoolItem& rBulletState = pEditEngine->GetParaAttrib(n, EE_PARA_BULLETSTATE);
+ const SfxBoolItem& rBulletState = mpEditEngine->GetParaAttrib(nParaPortion, EE_PARA_BULLETSTATE);
bPaintBullet = rBulletState.GetValue();
}
@@ -3197,15 +3498,24 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
bool bParsingFields = false;
std::vector< sal_Int32 >::iterator itSubLines;
+ tools::Long nFirstPortionXOffset = 0;
for ( sal_Int32 nPortion = pLine->GetStartPortion(); nPortion <= pLine->GetEndPortion(); nPortion++ )
{
- DBG_ASSERT( rPortion.GetTextPortions().Count(), "Line without Textportion in Paint!" );
- const TextPortion& rTextPortion = rPortion.GetTextPortions()[nPortion];
+ DBG_ASSERT(rParaPortion.GetTextPortions().Count(), "Line without Textportion in Paint!");
+ const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[nPortion];
- const tools::Long nPortionXOffset = GetPortionXOffset( &rPortion, pLine, nPortion );
+ const tools::Long nPortionXOffset = GetPortionXOffset(rParaPortion, *pLine, nPortion);
setXDirectionAwareFrom(aTmpPos, aStartPos);
- adjustXDirectionAware(aTmpPos, nPortionXOffset);
+
+ if (nPortion == pLine->GetStartPortion())
+ nFirstPortionXOffset = nPortionXOffset;
+
+ if (!bParsingFields)
+ adjustXDirectionAware(aTmpPos, nPortionXOffset);
+ else
+ adjustXDirectionAware(aTmpPos, nFirstPortionXOffset);
+
if (isXOverflowDirectionAware(aTmpPos, aClipRect))
break; // No further output in line necessary
@@ -3215,7 +3525,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
case PortionKind::FIELD:
case PortionKind::HYPHENATOR:
{
- SeekCursor( rPortion.GetNode(), nIndex+1, aTmpFont, &rOutDev );
+ SeekCursor(rParaPortion.GetNode(), nIndex + 1, aTmpFont, &rOutDev);
bool bDrawFrame = false;
@@ -3241,7 +3551,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
aTmpFont.SetFillColor( COL_LIGHTGRAY );
aTmpFont.SetTransparent( sal_False );
}
- else if ( GetI18NScriptType( EditPaM( rPortion.GetNode(), nIndex+1 ) ) == i18n::ScriptType::COMPLEX )
+ else if (GetI18NScriptType(EditPaM(rParaPortion.GetNode(), nIndex + 1)) == i18n::ScriptType::COMPLEX)
{
aTmpFont.SetFillColor( COL_LIGHTCYAN );
aTmpFont.SetTransparent( sal_False );
@@ -3252,21 +3562,29 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// #114278# Saving both layout mode and language (since I'm
// potentially changing both)
rOutDev.Push( vcl::PushFlags::TEXTLAYOUTMODE|vcl::PushFlags::TEXTLANGUAGE );
- ImplInitLayoutMode(rOutDev, n, nIndex);
+ ImplInitLayoutMode(rOutDev, nParaPortion, nIndex);
ImplInitDigitMode(rOutDev, aTmpFont.GetLanguage());
OUString aText;
sal_Int32 nTextStart = 0;
sal_Int32 nTextLen = 0;
- const tools::Long* pDXArray = nullptr;
- std::vector<tools::Long> aTmpDXArray;
+ std::span<const sal_Int32> pDXArray;
+ std::span<const sal_Bool> pKashidaArray;
+ KernArray aTmpDXArray;
if ( rTextPortion.GetKind() == PortionKind::TEXT )
{
- aText = rPortion.GetNode()->GetString();
+ aText = rParaPortion.GetNode()->GetString();
nTextStart = nIndex;
nTextLen = rTextPortion.GetLen();
- pDXArray = pLine->GetCharPosArray().data() + (nIndex - pLine->GetStart());
+ pDXArray = std::span(pLine->GetCharPosArray().data() + (nIndex - pLine->GetStart()),
+ pLine->GetCharPosArray().size() - (nIndex - pLine->GetStart()));
+
+ if (!pLine->GetKashidaArray().empty())
+ {
+ pKashidaArray = std::span(pLine->GetKashidaArray().data() + (nIndex - pLine->GetStart()),
+ pLine->GetKashidaArray().size() - (nIndex - pLine->GetStart()));
+ }
// Paint control characters (#i55716#)
/* XXX: Given that there's special handling
@@ -3274,7 +3592,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
* (U+200B ZERO WIDTH SPACE and U+2060 WORD
* JOINER) it is assumed to be not relevant
* for MarkUrlFields(). */
- if ( aStatus.MarkNonUrlFields() )
+ if (maStatus.MarkNonUrlFields())
{
sal_Int32 nTmpIdx;
const sal_Int32 nTmpEnd = nTextStart + rTextPortion.GetLen();
@@ -3287,7 +3605,8 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
if ( 0x200B == cChar || 0x2060 == cChar )
{
- tools::Long nHalfBlankWidth = aTmpFont.QuickGetTextSize( &rOutDev, " ", 0, 1 ).Width() / 2;
+ tools::Long nHalfBlankWidth = aTmpFont.QuickGetTextSize( &rOutDev,
+ " ", 0, 1, nullptr ).Width() / 2;
const tools::Long nAdvanceX = ( nTmpIdx == nTmpEnd ?
rTextPortion.GetSize().Width() :
@@ -3323,13 +3642,14 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
aTmpFont.SetPropr( 25 );
aTmpFont.SetPhysFont(rOutDev);
- const Size aSlashSize = aTmpFont.QuickGetTextSize( &rOutDev, aSlash, 0, 1 );
+ const Size aSlashSize = aTmpFont.QuickGetTextSize( &rOutDev,
+ aSlash, 0, 1, nullptr );
Point aSlashPos( aTmpPos );
const tools::Long nAddX = nHalfBlankWidth - aSlashSize.Width() / 2;
setXDirectionAwareFrom(aSlashPos, aTopLeftRectPos);
adjustXDirectionAware(aSlashPos, nAddX);
- aTmpFont.QuickDrawText( &rOutDev, aSlashPos, aSlash, 0, 1 );
+ aTmpFont.QuickDrawText( &rOutDev, aSlashPos, aSlash, 0, 1, {} );
aTmpFont.SetEscapement( nOldEscapement );
aTmpFont.SetPropr( nOldPropr );
@@ -3341,22 +3661,19 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
}
else if ( rTextPortion.GetKind() == PortionKind::FIELD )
{
- const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
+ const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
assert( pAttr && "Field not found");
DBG_ASSERT( dynamic_cast< const SvxFieldItem* >( pAttr->GetItem() ) != nullptr, "Field of the wrong type! ");
aText = static_cast<const EditCharAttribField*>(pAttr)->GetFieldValue();
nTextStart = 0;
nTextLen = aText.getLength();
ExtraPortionInfo *pExtraInfo = rTextPortion.GetExtraInfos();
- // Do not split the Fields into different lines while editing
- // With EditView on Overlay bStripOnly is now set for stripping to
- // primitives. To stay compatible in EditMode use pActiveView to detect
- // when we are in EditMode. For whatever reason URLs are drawn as single
- // line in edit mode, originally clipped against edit area (which is no
- // longer done in Overlay mode and allows to *read* the URL).
- // It would be difficult to change this due to needed adaptations in
- // EditEngine (look for lineBreaksList creation)
- if( nullptr == pActiveView && bStripOnly && !bParsingFields && pExtraInfo && !pExtraInfo->lineBreaksList.empty() )
+ //For historical reasons URLs was drawn as single line in edit mode
+ //but now we changed it, so it wraps similar as simple text.
+ //It is not perfect, it still use lineBreaksList, so it won’t seek
+ //word ends to wrap text there, but it would be difficult to change
+ //this due to needed adaptations in EditEngine
+ if (bStripOnly && !bParsingFields && pExtraInfo && !pExtraInfo->lineBreaksList.empty())
{
bParsingFields = true;
itSubLines = pExtraInfo->lineBreaksList.begin();
@@ -3373,6 +3690,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
aTmpPos += MoveToNextLine(aStartPos, nMaxAscent,
nColumn, aOrigin);
+ adjustXDirectionAware(aTmpPos, -pLine->GetNextLinePosXDiff());
}
std::vector< sal_Int32 >::iterator curIt = itSubLines;
++itSubLines;
@@ -3386,12 +3704,43 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
nTextStart = *curIt;
nTextLen = nTextLen - nTextStart;
bParsingFields = false;
+
+ if (nLine + 1 < nLines)
+ {
+ // tdf#148966 don't paint the line break following a
+ // multiline field based on a compat flag
+ OutlinerEditEng* pOutlEditEng{ dynamic_cast<OutlinerEditEng*>(mpEditEngine)};
+ int nStartNextLine = rParaPortion.GetLines()[nLine + 1].GetStartPortion();
+ const TextPortion& rNextTextPortion = rParaPortion.GetTextPortions()[nStartNextLine];
+ if (pOutlEditEng
+ && pOutlEditEng->GetCompatFlag(SdrCompatibilityFlag::IgnoreBreakAfterMultilineField)
+ .value_or(false))
+ {
+ if (rNextTextPortion.GetKind() == PortionKind::LINEBREAK)
+ ++nLine; //ignore the following linebreak
+ }
+ else if (mpActiveView && rNextTextPortion.GetKind() == PortionKind::LINEBREAK)
+ {
+ // if we are at edit mode, the compat flag does not work
+ // here we choose to work if compat flag is true,
+ // this is better for newer documents
+ nLine++;
+ }
+ if (rNextTextPortion.GetKind() != PortionKind::LINEBREAK)
+ {
+ nLine++;
+ pLine = &GetParaPortions().getRef(nParaPortion).GetLines()[nLine];
+ }
+ }
}
}
aTmpFont.SetPhysFont(*GetRefDevice());
- aTmpFont.QuickGetTextSize( GetRefDevice(), aText, nTextStart, nTextLen, &aTmpDXArray );
- pDXArray = aTmpDXArray.data();
+ aTmpFont.QuickGetTextSize( GetRefDevice(), aText, nTextStart, nTextLen,
+ &aTmpDXArray );
+ assert(aTmpDXArray.get_factor() == 1);
+ std::vector<sal_Int32>& rKernArray = aTmpDXArray.get_subunit_array();
+ pDXArray = rKernArray;
// add a meta file comment if we record to a metafile
if( bMetafileValid )
@@ -3416,8 +3765,11 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// crash when accessing 0 pointer in pDXArray
aTmpFont.SetPhysFont(*GetRefDevice());
- aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.getLength(), &aTmpDXArray );
- pDXArray = aTmpDXArray.data();
+ aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.getLength(),
+ &aTmpDXArray );
+ assert(aTmpDXArray.get_factor() == 1);
+ std::vector<sal_Int32>& rKernArray = aTmpDXArray.get_subunit_array();
+ pDXArray = rKernArray;
}
tools::Long nTxtWidth = rTextPortion.GetSize().Width();
@@ -3435,7 +3787,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
if(GetStatus().DoOnlineSpelling() && rTextPortion.GetLen())
{
- WrongList* pWrongs = rPortion.GetNode()->GetWrongList();
+ WrongList* pWrongs = rParaPortion.GetNode()->GetWrongList();
if(pWrongs && !pWrongs->empty())
{
@@ -3482,7 +3834,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
if(PortionKind::FIELD == rTextPortion.GetKind())
{
- const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
+ const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
if(pFieldItem)
@@ -3494,7 +3846,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// support for EOC, EOW, EOS TEXT comments. To support that,
// the locale is needed. With the locale and a XBreakIterator it is
// possible to re-create the text marking info on primitive level
- const lang::Locale aLocale(GetLocale(EditPaM(rPortion.GetNode(), nIndex + 1)));
+ const lang::Locale aLocale(GetLocale(EditPaM(rParaPortion.GetNode(), nIndex + 1)));
// create EOL and EOP bools
const bool bEndOfLine(nPortion == pLine->GetEndPortion());
@@ -3513,8 +3865,8 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
ImplCalcDigitLang(aTmpFont.GetLanguage()));
// StripPortions() data callback
- GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray,
- aTmpFont, n, rTextPortion.GetRightToLeftLevel(),
+ GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray,
+ aTmpFont, nParaPortion, rTextPortion.GetRightToLeftLevel(),
!aWrongSpellVector.empty() ? &aWrongSpellVector : nullptr,
pFieldData,
bEndOfLine, bEndOfParagraph, // support for EOL/EOP TEXT comments
@@ -3542,7 +3894,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
aTmpFont.SetEscapement( 0 );
}
- aOutPos = lcl_ImplCalcRotatedPos( aOutPos, aOrigin, nSin, nCos );
+ aOrigin.RotateAround(aOutPos, nOrientation);
aTmpFont.SetOrientation( aTmpFont.GetOrientation()+nOrientation );
aTmpFont.SetPhysFont(rOutDev);
@@ -3561,20 +3913,20 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// base line of the original font height...
// But only if there was something underlined before!
bool bSpecialUnderline = false;
- EditCharAttrib* pPrev = rPortion.GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex );
+ EditCharAttrib* pPrev = rParaPortion.GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex );
if ( pPrev )
{
SvxFont aDummy;
// Underscore in front?
if ( pPrev->GetStart() )
{
- SeekCursor( rPortion.GetNode(), pPrev->GetStart(), aDummy );
+ SeekCursor( rParaPortion.GetNode(), pPrev->GetStart(), aDummy );
if ( aDummy.GetUnderline() != LINESTYLE_NONE )
bSpecialUnderline = true;
}
- if ( !bSpecialUnderline && ( pPrev->GetEnd() < rPortion.GetNode()->Len() ) )
+ if ( !bSpecialUnderline && ( pPrev->GetEnd() < rParaPortion.GetNode()->Len() ) )
{
- SeekCursor( rPortion.GetNode(), pPrev->GetEnd()+1, aDummy );
+ SeekCursor( rParaPortion.GetNode(), pPrev->GetEnd()+1, aDummy );
if ( aDummy.GetUnderline() != LINESTYLE_NONE )
bSpecialUnderline = true;
}
@@ -3586,11 +3938,14 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
aTmpFont.SetEscapement( 0 );
aTmpFont.SetPropr( 100 );
aTmpFont.SetPhysFont(rOutDev);
- OUStringBuffer aBlanks;
+ OUStringBuffer aBlanks(nTextLen);
comphelper::string::padToLength( aBlanks, nTextLen, ' ' );
Point aUnderlinePos( aOutPos );
if ( nOrientation )
- aUnderlinePos = lcl_ImplCalcRotatedPos( aTmpPos, aOrigin, nSin, nCos );
+ {
+ aUnderlinePos = aTmpPos;
+ aOrigin.RotateAround(aUnderlinePos, nOrientation);
+ }
rOutDev.DrawStretchText( aUnderlinePos, aSz.Width(), aBlanks.makeStringAndClear(), 0, nTextLen );
aTmpFont.SetUnderline( LINESTYLE_NONE );
@@ -3616,47 +3971,63 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
' ' == aText[nTextStart + nTextLen - 1] )
--nTextLen;
+ // PDF export:
+ const SvxFieldData* pFieldData = nullptr;
+ if (pPDFExtOutDevData)
+ {
+ if (rTextPortion.GetKind() == PortionKind::FIELD)
+ {
+ const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
+ const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
+ if (pFieldItem)
+ {
+ pFieldData = pFieldItem->GetField();
+ auto pUrlField = dynamic_cast<const SvxURLField*>(pFieldData);
+ if (pUrlField)
+ if (pPDFExtOutDevData->GetIsExportTaggedPDF())
+ pPDFExtOutDevData->WrapBeginStructureElement(vcl::PDFWriter::Link, "Link");
+ }
+ }
+ }
+
// output directly
- aTmpFont.QuickDrawText( &rOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray );
+ aTmpFont.QuickDrawText( &rOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray, pKashidaArray );
if ( bDrawFrame )
{
Point aTopLeft( aTmpPos );
aTopLeft.AdjustY( -(pLine->GetMaxAscent()) );
if ( nOrientation )
- aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos );
+ aOrigin.RotateAround(aTopLeft, nOrientation);
tools::Rectangle aRect( aTopLeft, rTextPortion.GetSize() );
rOutDev.DrawRect( aRect );
}
// PDF export:
- if ( pPDFExtOutDevData )
+ if (pPDFExtOutDevData)
{
- if ( rTextPortion.GetKind() == PortionKind::FIELD )
+ if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFieldData))
{
- const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
- const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
- if( pFieldItem )
+ Point aTopLeft(aTmpPos);
+ aTopLeft.AdjustY(-(pLine->GetMaxAscent()));
+
+ tools::Rectangle aRect(aTopLeft, rTextPortion.GetSize());
+ vcl::PDFExtOutDevBookmarkEntry aBookmark;
+ aBookmark.nLinkId = pPDFExtOutDevData->CreateLink(aRect, pUrlField->GetRepresentation());
+ aBookmark.aBookmark = pUrlField->GetURL();
+ std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
+ rBookmarks.push_back(aBookmark);
+
+ if (pPDFExtOutDevData->GetIsExportTaggedPDF())
{
- const SvxFieldData* pFieldData = pFieldItem->GetField();
- if ( auto pUrlField = dynamic_cast< const SvxURLField* >( pFieldData ) )
- {
- Point aTopLeft( aTmpPos );
- aTopLeft.AdjustY( -(pLine->GetMaxAscent()) );
-
- tools::Rectangle aRect( aTopLeft, rTextPortion.GetSize() );
- vcl::PDFExtOutDevBookmarkEntry aBookmark;
- aBookmark.nLinkId = pPDFExtOutDevData->CreateLink( aRect );
- aBookmark.aBookmark = pUrlField->GetURL();
- std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks();
- rBookmarks.push_back( aBookmark );
- }
+ pPDFExtOutDevData->SetStructureAttributeNumerical(vcl::PDFWriter::LinkAnnotation, aBookmark.nLinkId);
+ pPDFExtOutDevData->EndStructureElement();
}
}
}
}
- const WrongList* const pWrongList = rPortion.GetNode()->GetWrongList();
+ const WrongList* const pWrongList = rParaPortion.GetNode()->GetWrongList();
if ( GetStatus().DoOnlineSpelling() && pWrongList && !pWrongList->empty() && rTextPortion.GetLen() )
{
{//#105750# adjust LinePos for superscript or subscript text
@@ -3669,7 +4040,10 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
}
Color aOldColor( rOutDev.GetLineColor() );
rOutDev.SetLineColor( GetColorConfig().GetColorValue( svtools::SPELL ).nColor );
- lcl_DrawRedLines( rOutDev, aTmpFont.GetFontSize().Height(), aRedLineTmpPos, static_cast<size_t>(nIndex), static_cast<size_t>(nIndex) + rTextPortion.GetLen(), pDXArray, rPortion.GetNode()->GetWrongList(), nOrientation, aOrigin, IsEffectivelyVertical(), rTextPortion.IsRightToLeft() );
+ lcl_DrawRedLines(rOutDev, aTmpFont.GetFontSize().Height(), aRedLineTmpPos,
+ static_cast<size_t>(nIndex), static_cast<size_t>(nIndex) + rTextPortion.GetLen(),
+ pDXArray, rParaPortion.GetNode()->GetWrongList(), nOrientation,
+ aOrigin, IsEffectivelyVertical(), rTextPortion.IsRightToLeft());
rOutDev.SetLineColor( aOldColor );
}
}
@@ -3681,7 +4055,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
// add a meta file comment if we record to a metafile
if( bMetafileValid )
{
- const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
+ const EditCharAttrib* pAttr = rParaPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
assert( pAttr && "Field not found" );
const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
@@ -3703,12 +4077,12 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
{
if ( rTextPortion.GetExtraValue() && ( rTextPortion.GetExtraValue() != ' ' ) )
{
- SeekCursor( rPortion.GetNode(), nIndex+1, aTmpFont, &rOutDev );
+ SeekCursor(rParaPortion.GetNode(), nIndex+1, aTmpFont, &rOutDev);
aTmpFont.SetTransparent( false );
aTmpFont.SetEscapement( 0 );
aTmpFont.SetPhysFont(rOutDev);
tools::Long nCharWidth = aTmpFont.QuickGetTextSize( &rOutDev,
- OUString(rTextPortion.GetExtraValue()), 0, 1 ).Width();
+ OUString(rTextPortion.GetExtraValue()), 0, 1, {} ).Width();
sal_Int32 nChars = 2;
if( nCharWidth )
nChars = rTextPortion.GetSize().Width() / nCharWidth;
@@ -3717,10 +4091,10 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
else if ( nChars == 2 )
nChars = 3; // looks better
- OUStringBuffer aBuf;
+ OUStringBuffer aBuf(nChars);
comphelper::string::padToLength(aBuf, nChars, rTextPortion.GetExtraValue());
OUString aText(aBuf.makeStringAndClear());
- aTmpFont.QuickDrawText( &rOutDev, aTmpPos, aText, 0, aText.getLength() );
+ aTmpFont.QuickDrawText( &rOutDev, aTmpPos, aText, 0, aText.getLength(), {} );
rOutDev.DrawStretchText( aTmpPos, rTextPortion.GetSize().Width(), aText );
if ( bStripOnly )
@@ -3736,7 +4110,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
GetEditEnginePtr()->DrawingTab( aTmpPos,
rTextPortion.GetSize().Width(),
OUString(rTextPortion.GetExtraValue()),
- aTmpFont, n, rTextPortion.GetRightToLeftLevel(),
+ aTmpFont, nParaPortion, rTextPortion.GetRightToLeftLevel(),
bEndOfLine, bEndOfParagraph,
aOverlineColor, aTextLineColor);
}
@@ -3753,8 +4127,8 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
const Color aTextLineColor(rOutDev.GetTextLineColor());
GetEditEnginePtr()->DrawingText(
- aTmpPos, OUString(), 0, 0, nullptr,
- aTmpFont, n, 0,
+ aTmpPos, OUString(), 0, 0, {}, {},
+ aTmpFont, nParaPortion, 0,
nullptr,
nullptr,
bEndOfLine, bEndOfParagraph,
@@ -3774,7 +4148,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
}
}
- if ( ( nLine != nLastLine ) && !aStatus.IsOutliner() )
+ if ((nLine != nLastLine ) && !maStatus.IsOutliner())
{
adjustYDirectionAware(aStartPos, nSBL);
}
@@ -3784,10 +4158,10 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
break;
}
- if ( !aStatus.IsOutliner() )
+ if (!maStatus.IsOutliner())
{
- const SvxULSpaceItem& rULItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
- tools::Long nUL = GetYValue( rULItem.GetLower() );
+ const SvxULSpaceItem& rULItem = rParaPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
+ tools::Long nUL = scaleYSpacingValue(rULItem.GetLower());
adjustYDirectionAware(aStartPos, nUL);
}
@@ -3802,8 +4176,8 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
const Color aTextLineColor(rOutDev.GetTextLineColor());
GetEditEnginePtr()->DrawingText(
- aTmpPos, OUString(), 0, 0, nullptr,
- aTmpFont, n, 0,
+ aTmpPos, OUString(), 0, 0, {}, {},
+ aTmpFont, nParaPortion, 0,
nullptr,
nullptr,
false, true, // support for EOL/EOP TEXT comments
@@ -3879,19 +4253,21 @@ void ImpEditEngine::Paint( ImpEditView* pView, const tools::Rectangle& rRect, Ou
pView->DrawSelectionXOR(pView->GetEditSelection(), nullptr, &rTarget);
}
-void ImpEditEngine::InsertContent( ContentNode* pNode, sal_Int32 nPos )
+void ImpEditEngine::InsertContent(std::unique_ptr<ContentNode> pNode, sal_Int32 nPos )
{
DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " );
DBG_ASSERT( IsInUndo(), "InsertContent only for Undo()!" );
- GetParaPortions().Insert(nPos, ParaPortion( pNode ));
- aEditDoc.Insert(nPos, pNode);
+
+ GetParaPortions().Insert(nPos, std::make_unique<ParaPortion>(pNode.get()));
+ maEditDoc.Insert(nPos, std::move(pNode));
+
if ( IsCallParaInsertedOrDeleted() )
GetEditEnginePtr()->ParagraphInserted( nPos );
}
EditPaM ImpEditEngine::SplitContent( sal_Int32 nNode, sal_Int32 nSepPos )
{
- ContentNode* pNode = aEditDoc.GetObject( nNode );
+ ContentNode* pNode = maEditDoc.GetObject( nNode );
DBG_ASSERT( pNode, "Invalid Node in SplitContent" );
DBG_ASSERT( IsInUndo(), "SplitContent only for Undo()!" );
DBG_ASSERT( nSepPos <= pNode->Len(), "Index out of range: SplitContent" );
@@ -3901,8 +4277,8 @@ EditPaM ImpEditEngine::SplitContent( sal_Int32 nNode, sal_Int32 nSepPos )
EditPaM ImpEditEngine::ConnectContents( sal_Int32 nLeftNode, bool bBackward )
{
- ContentNode* pLeftNode = aEditDoc.GetObject( nLeftNode );
- ContentNode* pRightNode = aEditDoc.GetObject( nLeftNode+1 );
+ ContentNode* pLeftNode = maEditDoc.GetObject( nLeftNode );
+ ContentNode* pRightNode = maEditDoc.GetObject( nLeftNode+1 );
DBG_ASSERT( pLeftNode, "Invalid left node in ConnectContents ");
DBG_ASSERT( pRightNode, "Invalid right node in ConnectContents ");
return ImpConnectParagraphs( pLeftNode, pRightNode, bBackward );
@@ -3910,8 +4286,8 @@ EditPaM ImpEditEngine::ConnectContents( sal_Int32 nLeftNode, bool bBackward )
bool ImpEditEngine::SetUpdateLayout( bool bUp, EditView* pCurView, bool bForceUpdate )
{
- const bool bPrevUpdateLayout = bUpdateLayout;
- const bool bChanged = (bUpdateLayout != bUp);
+ const bool bPrevUpdateLayout = mbUpdateLayout;
+ const bool mbChanged = (mbUpdateLayout != bUp);
// When switching from true to false, all selections were visible,
// => paint over
@@ -3919,8 +4295,8 @@ bool ImpEditEngine::SetUpdateLayout( bool bUp, EditView* pCurView, bool bForceUp
// If !bFormatted, e.g. after SetText, then if UpdateMode=true
// formatting is not needed immediately, probably because more text is coming.
// At latest it is formatted at a Paint/CalcTextWidth.
- bUpdateLayout = bUp;
- if ( bUpdateLayout && ( bChanged || bForceUpdate ) )
+ mbUpdateLayout = bUp;
+ if ( mbUpdateLayout && ( mbChanged || bForceUpdate ) )
FormatAndLayout( pCurView );
return bPrevUpdateLayout;
}
@@ -3938,13 +4314,13 @@ void ImpEditEngine::ShowParagraph( sal_Int32 nParagraph, bool bShow )
{
// Mark as deleted, so that no selection will end or begin at
// this paragraph...
- aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pPPortion->GetNode(), nParagraph ));
+ maDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pPPortion->GetNode(), nParagraph ));
UpdateSelections();
// The region below will not be invalidated if UpdateMode = sal_False!
// If anyway, then save as sal_False before SetVisible !
}
- if ( bShow && ( pPPortion->IsInvalid() || !pPPortion->nHeight ) )
+ if (bShow && (pPPortion->IsInvalid() || !pPPortion->GetHeight()))
{
if ( !GetTextRanger() )
{
@@ -3954,21 +4330,21 @@ void ImpEditEngine::ShowParagraph( sal_Int32 nParagraph, bool bShow )
}
else
{
- CalcHeight( pPPortion );
+ CalcHeight(*pPPortion);
}
- nCurTextHeight += pPPortion->GetHeight();
+ mnCurTextHeight += pPPortion->GetHeight();
}
else
{
- nCurTextHeight = 0x7fffffff;
+ mnCurTextHeight = 0x7fffffff;
}
}
pPPortion->SetMustRepaint( true );
if ( IsUpdateLayout() && !IsInUndo() && !GetTextRanger() )
{
- aInvalidRect = tools::Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion ) ),
- Point( GetPaperSize().Width(), nCurTextHeight ) );
+ maInvalidRect = tools::Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion ) ),
+ Point( GetPaperSize().Width(), mnCurTextHeight ) );
UpdateViews( GetActiveView() );
}
}
@@ -3978,12 +4354,12 @@ EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_Int32 nNew
DBG_ASSERT( GetParaPortions().Count() != 0, "No paragraphs found: MoveParagraphs" );
if ( GetParaPortions().Count() == 0 )
return EditSelection();
- aOldPositions.Justify();
+ aOldPositions.Normalize();
EditSelection aSel( ImpMoveParagraphs( aOldPositions, nNewPos ) );
- if ( nNewPos >= GetParaPortions().Count() )
- nNewPos = GetParaPortions().Count() - 1;
+ if (nNewPos >= GetParaPortions().Count())
+ nNewPos = GetParaPortions().lastIndex();
// Where the paragraph was inserted it has to be properly redrawn:
// Where the paragraph was removed it has to be properly redrawn:
@@ -3999,11 +4375,11 @@ EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_Int32 nNew
ParaPortion* pLowerPortion = GetParaPortions().SafeGetObject( nLastPortion );
if (pUpperPortion && pLowerPortion)
{
- aInvalidRect = tools::Rectangle(); // make empty
- aInvalidRect.SetLeft( 0 );
- aInvalidRect.SetRight(GetColumnWidth(aPaperSize));
- aInvalidRect.SetTop( GetParaPortions().GetYOffset( pUpperPortion ) );
- aInvalidRect.SetBottom( GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight() );
+ maInvalidRect = tools::Rectangle(); // make empty
+ maInvalidRect.SetLeft( 0 );
+ maInvalidRect.SetRight(GetColumnWidth(maPaperSize));
+ maInvalidRect.SetTop( GetParaPortions().GetYOffset( pUpperPortion ) );
+ maInvalidRect.SetBottom( GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight() );
UpdateViews( pCurView );
}
@@ -4021,17 +4397,18 @@ void ImpEditEngine::InvalidateFromParagraph( sal_Int32 nFirstInvPara )
{
// The following paragraphs are not invalidated, since ResetHeight()
// => size change => all the following are re-issued anyway.
- if ( nFirstInvPara != 0 )
+
+ if (nFirstInvPara != 0)
{
- ParaPortion& rTmpPortion = GetParaPortions()[nFirstInvPara-1];
- rTmpPortion.MarkInvalid( rTmpPortion.GetNode()->Len(), 0 );
- rTmpPortion.ResetHeight();
+ ParaPortion& rPortion = GetParaPortions().getRef(nFirstInvPara - 1);
+ rPortion.MarkInvalid(rPortion.GetNode()->Len(), 0);
+ rPortion.ResetHeight();
}
else
{
- ParaPortion& rTmpPortion = GetParaPortions()[0];
- rTmpPortion.MarkSelectionInvalid( 0 );
- rTmpPortion.ResetHeight();
+ ParaPortion& rPortion = GetParaPortions().getRef(0);
+ rPortion.MarkSelectionInvalid(0);
+ rPortion.ResetHeight();
}
}
@@ -4042,41 +4419,45 @@ IMPL_LINK_NOARG(ImpEditEngine, StatusTimerHdl, Timer *, void)
void ImpEditEngine::CallStatusHdl()
{
- if ( aStatusHdlLink.IsSet() && bool(aStatus.GetStatusWord()) )
+ if (maStatusHdlLink.IsSet() && bool(maStatus.GetStatusWord()))
{
// The Status has to be reset before the Call,
// since other Flags might be set in the handler...
- EditStatus aTmpStatus( aStatus );
- aStatus.Clear();
- aStatusHdlLink.Call( aTmpStatus );
- aStatusTimer.Stop(); // If called by hand...
+ EditStatus aTmpStatus( maStatus );
+ maStatus.Clear();
+ maStatusHdlLink.Call( aTmpStatus );
+ maStatusTimer.Stop(); // If called by hand...
}
}
ContentNode* ImpEditEngine::GetPrevVisNode( ContentNode const * pCurNode )
{
- const ParaPortion& rPortion1 = FindParaPortion( pCurNode );
- const ParaPortion* pPortion2 = GetPrevVisPortion( &rPortion1 );
- if ( pPortion2 )
- return pPortion2->GetNode();
+ const ParaPortion* pPortion = FindParaPortion( pCurNode );
+ DBG_ASSERT( pPortion, "GetPrevVisibleNode: No matching portion!" );
+ pPortion = GetPrevVisPortion( pPortion );
+ if ( pPortion )
+ return pPortion->GetNode();
return nullptr;
}
ContentNode* ImpEditEngine::GetNextVisNode( ContentNode const * pCurNode )
{
- const ParaPortion& rPortion = FindParaPortion( pCurNode );
- const ParaPortion* pPortion = GetNextVisPortion( &rPortion );
+ const ParaPortion* pPortion = FindParaPortion( pCurNode );
+ DBG_ASSERT( pPortion, "GetNextVisibleNode: No matching portion!" );
+ pPortion = GetNextVisPortion( pPortion );
if ( pPortion )
return pPortion->GetNode();
return nullptr;
}
-const ParaPortion* ImpEditEngine::GetPrevVisPortion( const ParaPortion* pCurPortion ) const
+const ParaPortion* ImpEditEngine::GetPrevVisPortion( const ParaPortion* pCurPortion) const
{
- sal_Int32 nPara = GetParaPortions().GetPos( pCurPortion );
- const ParaPortion* pPortion = nPara ? &GetParaPortions()[--nPara] : nullptr;
- while ( pPortion && !pPortion->IsVisible() )
- pPortion = nPara ? &GetParaPortions()[--nPara] : nullptr;
+ sal_Int32 nPara = GetParaPortions().GetPos(pCurPortion);
+ DBG_ASSERT(GetParaPortions().exists(nPara) , "Portion not found: GetPrevVisPortion");
+
+ const ParaPortion* pPortion = nPara ? GetParaPortions().SafeGetObject(--nPara) : nullptr;
+ while (pPortion && !pPortion->IsVisible())
+ pPortion = nPara ? GetParaPortions().SafeGetObject(--nPara) : nullptr;
return pPortion;
}
@@ -4105,17 +4486,17 @@ tools::Long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
// All paragraphs must have the block justification set.
return 0;
- const ParaPortion* pPortion = &rParaPortions[i];
- nTotalOccupiedHeight += pPortion->GetFirstLineOffset();
+ ParaPortion const& rPortion = rParaPortions.getRef(i);
+ nTotalOccupiedHeight += rPortion.GetFirstLineOffset();
- const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
+ const SvxLineSpacingItem& rLSItem = rPortion.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() );
+ const SvxULSpaceItem& rULItem = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
+ tools::Long nUL = scaleYSpacingValue(rULItem.GetLower());
- const EditLineList& rLines = pPortion->GetLines();
+ const EditLineList& rLines = rPortion.GetLines();
sal_Int32 nLineCount = rLines.Count();
nTotalLineCount += nLineCount;
for (sal_Int32 j = 0; j < nLineCount; ++j)
@@ -4128,7 +4509,7 @@ tools::Long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
}
}
- tools::Long nTotalSpace = getHeightDirectionAware(aPaperSize);
+ tools::Long nTotalSpace = getHeightDirectionAware(maPaperSize);
nTotalSpace -= nTotalOccupiedHeight;
if (nTotalSpace <= 0 || nTotalLineCount <= 1)
return 0;
@@ -4173,17 +4554,19 @@ std::optional<EditSelection> ImpEditEngine::SelectParagraph( sal_Int32 nPara )
void ImpEditEngine::FormatAndLayout( EditView* pCurView, bool bCalledFromUndo )
{
- if ( bDowning )
- return ;
+ if (mbDowning)
+ return;
if ( IsInUndo() )
IdleFormatAndLayout( pCurView );
else
{
if (bCalledFromUndo)
+ {
// in order to make bullet points that have had their styles changed, redraw themselves
- for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
- GetParaPortions()[nPortion].MarkInvalid( 0, 0 );
+ for (auto& pParaPortion : GetParaPortions())
+ pParaPortion->MarkInvalid(0, 0);
+ }
FormatDoc();
UpdateViews( pCurView );
}
@@ -4194,44 +4577,41 @@ void ImpEditEngine::FormatAndLayout( EditView* pCurView, bool bCalledFromUndo )
void ImpEditEngine::SetFlatMode( bool bFlat )
{
- if ( bFlat != aStatus.UseCharAttribs() )
+ if ( bFlat != maStatus.UseCharAttribs() )
return;
if ( !bFlat )
- aStatus.TurnOnFlags( EEControlBits::USECHARATTRIBS );
+ maStatus.TurnOnFlags( EEControlBits::USECHARATTRIBS );
else
- aStatus.TurnOffFlags( EEControlBits::USECHARATTRIBS );
+ maStatus.TurnOffFlags( EEControlBits::USECHARATTRIBS );
- aEditDoc.CreateDefFont( !bFlat );
+ maEditDoc.CreateDefFont( !bFlat );
FormatFullDoc();
UpdateViews();
- if ( pActiveView )
- pActiveView->ShowCursor();
+ if (mpActiveView)
+ mpActiveView->ShowCursor();
}
-void ImpEditEngine::SetCharStretching( sal_uInt16 nX, sal_uInt16 nY )
+void ImpEditEngine::setScalingParameters(ScalingParameters const& rScalingParameters)
{
- bool bChanged;
- if ( !IsEffectivelyVertical() )
- {
- bChanged = nStretchX!=nX || nStretchY!=nY;
- nStretchX = nX;
- nStretchY = nY;
- }
- else
+ ScalingParameters aNewScalingParameters(rScalingParameters);
+
+ if (IsEffectivelyVertical())
{
- bChanged = nStretchX!=nY || nStretchY!=nX;
- nStretchX = nY;
- nStretchY = nX;
+ std::swap(aNewScalingParameters.fFontX, aNewScalingParameters.fFontY);
+ std::swap(aNewScalingParameters.fSpacingX, aNewScalingParameters.fSpacingY);
}
- if (bChanged && aStatus.DoStretch())
+ bool bScalingChanged = maScalingParameters != aNewScalingParameters;
+ maCustomScalingParameters = maScalingParameters = aNewScalingParameters;
+
+ if (bScalingChanged && maStatus.DoStretch())
{
FormatFullDoc();
// (potentially) need everything redrawn
- aInvalidRect=tools::Rectangle(0,0,1000000,1000000);
- UpdateViews( GetActiveView() );
+ maInvalidRect = tools::Rectangle(0, 0, 1000000, 1000000);
+ UpdateViews(GetActiveView());
}
}
@@ -4250,7 +4630,7 @@ const SvxNumberFormat* ImpEditEngine::GetNumberFormat( const ContentNode *pNode
// object to provide
// access to the SvxNumberFormat of the Outliner.
// The EditEngine implementation will just return 0.
- pRes = pEditEngine->GetNumberFormat( nPara );
+ pRes = mpEditEngine->GetNumberFormat( nPara );
}
}
@@ -4288,23 +4668,21 @@ sal_Int32 ImpEditEngine::GetSpaceBeforeAndMinLabelWidth(
const SvxLRSpaceItem& ImpEditEngine::GetLRSpaceItem( ContentNode* pNode )
{
- return pNode->GetContentAttribs().GetItem( aStatus.IsOutliner() ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE );
+ return pNode->GetContentAttribs().GetItem( maStatus.IsOutliner() ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE );
}
// select a representative text language for the digit type according to the
// text numeral setting:
-LanguageType ImpEditEngine::ImplCalcDigitLang(LanguageType eCurLang) const
+LanguageType ImpEditEngine::ImplCalcDigitLang(LanguageType eCurLang)
{
- if (utl::ConfigManager::IsFuzzing())
+ if (comphelper::IsFuzzing())
return LANGUAGE_ENGLISH_US;
// #114278# Also setting up digit language from Svt options
// (cannot reliably inherit the outdev's setting)
- if( !pCTLOptions )
- pCTLOptions.reset( new SvtCTLOptions );
LanguageType eLang = eCurLang;
- const SvtCTLOptions::TextNumerals nCTLTextNumerals = pCTLOptions->GetCTLTextNumerals();
+ const SvtCTLOptions::TextNumerals nCTLTextNumerals = SvtCTLOptions::GetCTLTextNumerals();
if ( SvtCTLOptions::NUMERALS_HINDI == nCTLTextNumerals )
eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
@@ -4383,42 +4761,56 @@ void ImpEditEngine::ImplInitLayoutMode(OutputDevice& rOutDev, sal_Int32 nPara, s
Reference < i18n::XBreakIterator > const & ImpEditEngine::ImplGetBreakIterator() const
{
- if ( !xBI.is() )
+ if (!mxBI.is())
{
- Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
- xBI = i18n::BreakIterator::create( xContext );
+ uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ mxBI = i18n::BreakIterator::create(xContext);
}
- return xBI;
+ return mxBI;
}
Reference < i18n::XExtendedInputSequenceChecker > const & ImpEditEngine::ImplGetInputSequenceChecker() const
{
- if ( !xISC.is() )
+ if (!mxISC.is())
{
- Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
- xISC = i18n::InputSequenceChecker::create( xContext );
+ uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());
+ mxISC = i18n::InputSequenceChecker::create(xContext);
}
- return xISC;
+ return mxISC;
}
Color ImpEditEngine::GetAutoColor() const
{
- Color aColor = GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+ Color aColor;
- if ( GetBackgroundColor() != COL_AUTO )
+ if (comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current())
{
- if ( GetBackgroundColor().IsDark() && aColor.IsDark() )
+ // Get document background color from current view instead
+ aColor = SfxViewShell::Current()->GetColorConfigColor(svtools::DOCCOLOR);
+ if (aColor.IsDark())
aColor = COL_WHITE;
- else if ( GetBackgroundColor().IsBright() && aColor.IsBright() )
+ else
aColor = COL_BLACK;
}
+ else
+ {
+ aColor = GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+
+ if ( GetBackgroundColor() != COL_AUTO )
+ {
+ if ( GetBackgroundColor().IsDark() && aColor.IsDark() )
+ aColor = COL_WHITE;
+ else if ( GetBackgroundColor().IsBright() && aColor.IsBright() )
+ aColor = COL_BLACK;
+ }
+ }
return aColor;
}
bool ImpEditEngine::ImplCalcAsianCompression(ContentNode* pNode,
TextPortion* pTextPortion, sal_Int32 nStartPos,
- tools::Long* pDXArray, sal_uInt16 n100thPercentFromMax,
+ sal_Int32* pDXArray, sal_uInt16 n100thPercentFromMax,
bool bManipulateDXArray)
{
DBG_ASSERT( GetAsianCompressionMode() != CharCompressType::NONE, "ImplCalcAsianCompression - Why?" );
@@ -4528,7 +4920,7 @@ bool ImpEditEngine::ImplCalcAsianCompression(ContentNode* pNode,
if ( bCompressed && ( n100thPercentFromMax == 10000 ) )
pTextPortion->GetExtraInfos()->nWidthFullCompression = nNewPortionWidth;
- pTextPortion->GetSize().setWidth( nNewPortionWidth );
+ pTextPortion->setWidth(nNewPortionWidth);
if ( pTextPortion->GetExtraInfos() && ( n100thPercentFromMax != 10000 ) )
{
@@ -4538,21 +4930,21 @@ bool ImpEditEngine::ImplCalcAsianCompression(ContentNode* pNode,
nShrink /= 10000;
tools::Long nNewWidth = pTextPortion->GetExtraInfos()->nOrgWidth - nShrink;
if ( nNewWidth < pTextPortion->GetSize().Width() )
- pTextPortion->GetSize().setWidth( nNewWidth );
+ pTextPortion->setWidth(nNewWidth);
}
}
return bCompressed;
}
-void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, tools::Long nRemainingWidth )
+void ImpEditEngine::ImplExpandCompressedPortions(EditLine& rLine, ParaPortion& rParaPortion, tools::Long nRemainingWidth)
{
bool bFoundCompressedPortion = false;
tools::Long nCompressed = 0;
std::vector<TextPortion*> aCompressedPortions;
- sal_Int32 nPortion = pLine->GetEndPortion();
- TextPortion* pTP = &pParaPortion->GetTextPortions()[ nPortion ];
+ sal_Int32 nPortion = rLine.GetEndPortion();
+ TextPortion* pTP = &rParaPortion.GetTextPortions()[ nPortion ];
while ( pTP && ( pTP->GetKind() == PortionKind::TEXT ) )
{
if ( pTP->GetExtraInfos() && pTP->GetExtraInfos()->bCompressed )
@@ -4561,7 +4953,7 @@ void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion*
nCompressed += pTP->GetExtraInfos()->nOrgWidth - pTP->GetSize().Width();
aCompressedPortions.push_back(pTP);
}
- pTP = ( nPortion > pLine->GetStartPortion() ) ? &pParaPortion->GetTextPortions()[ --nPortion ] : nullptr;
+ pTP = ( nPortion > rLine.GetStartPortion() ) ? &rParaPortion.GetTextPortions()[ --nPortion ] : nullptr;
}
if ( !bFoundCompressedPortion )
@@ -4580,16 +4972,16 @@ void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion*
{
pTP = pTP2;
pTP->GetExtraInfos()->bCompressed = false;
- pTP->GetSize().setWidth( pTP->GetExtraInfos()->nOrgWidth );
+ pTP->setWidth(pTP->GetExtraInfos()->nOrgWidth);
if ( nCompressPercent )
{
- sal_Int32 nTxtPortion = pParaPortion->GetTextPortions().GetPos( pTP );
- sal_Int32 nTxtPortionStart = pParaPortion->GetTextPortions().GetStartPos( nTxtPortion );
- DBG_ASSERT( nTxtPortionStart >= pLine->GetStart(), "Portion doesn't belong to the line!!!" );
- tools::Long* pDXArray = pLine->GetCharPosArray().data() + (nTxtPortionStart - pLine->GetStart());
+ sal_Int32 nTxtPortion = rParaPortion.GetTextPortions().GetPos( pTP );
+ sal_Int32 nTxtPortionStart = rParaPortion.GetTextPortions().GetStartPos( nTxtPortion );
+ DBG_ASSERT( nTxtPortionStart >= rLine.GetStart(), "Portion doesn't belong to the line!!!" );
+ sal_Int32* pDXArray = rLine.GetCharPosArray().data() + (nTxtPortionStart - rLine.GetStart());
if ( pTP->GetExtraInfos()->pOrgDXArray )
memcpy( pDXArray, pTP->GetExtraInfos()->pOrgDXArray.get(), (pTP->GetLen()-1)*sizeof(sal_Int32) );
- ImplCalcAsianCompression( pParaPortion->GetNode(), pTP, nTxtPortionStart, pDXArray, static_cast<sal_uInt16>(nCompressPercent), true );
+ ImplCalcAsianCompression( rParaPortion.GetNode(), pTP, nTxtPortionStart, pDXArray, static_cast<sal_uInt16>(nCompressPercent), true );
}
}
}
@@ -4599,15 +4991,16 @@ void ImpEditEngine::ImplUpdateOverflowingParaNum(tools::Long nPaperHeight)
tools::Long nY = 0;
tools::Long nPH;
- for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) {
- ParaPortion& rPara = GetParaPortions()[nPara];
- nPH = rPara.GetHeight();
+ for (sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++)
+ {
+ ParaPortion& rParaPortion = GetParaPortions().getRef(nPara);
+ nPH = rParaPortion.GetHeight();
nY += nPH;
- if ( nY > nPaperHeight /*nCurTextHeight*/ ) // found first paragraph overflowing
+ if ( nY > nPaperHeight /*mnCurTextHeight*/ ) // found first paragraph overflowing
{
mnOverflowingPara = nPara;
SAL_INFO("editeng.chaining", "[CHAINING] Setting first overflowing #Para#: " << nPara);
- ImplUpdateOverflowingLineNum( nPaperHeight, nPara, nY-nPH);
+ ImplUpdateOverflowingLineNum( nPaperHeight, nPara, nY - nPH);
return;
}
}
@@ -4617,21 +5010,26 @@ void ImpEditEngine::ImplUpdateOverflowingLineNum(tools::Long nPaperHeight,
sal_uInt32 nOverflowingPara,
tools::Long nHeightBeforeOverflowingPara)
{
+ if (GetParaPortions().exists(nOverflowingPara))
+ return;
+
tools::Long nY = nHeightBeforeOverflowingPara;
tools::Long nLH;
- ParaPortion& rPara = GetParaPortions()[nOverflowingPara];
+ ParaPortion& rParaPortion = GetParaPortions().getRef(nOverflowingPara);
// Like UpdateOverflowingParaNum but for each line in the first
// overflowing paragraph.
- for ( sal_Int32 nLine = 0; nLine < rPara.GetLines().Count(); nLine++ ) {
+ for (sal_Int32 nLine = 0; nLine < rParaPortion.GetLines().Count(); nLine++)
+ {
// XXX: We must use a reference here because the copy constructor resets the height
- EditLine &aLine = rPara.GetLines()[nLine];
+ EditLine &aLine = rParaPortion.GetLines()[nLine];
nLH = aLine.GetHeight();
nY += nLH;
// Debugging output
- if (nLine == 0) {
+ if (nLine == 0)
+ {
SAL_INFO("editeng.chaining", "[CHAINING] First line has height " << nLH);
}