diff options
Diffstat (limited to 'sw/source/core/text/inftxt.cxx')
-rw-r--r-- | sw/source/core/text/inftxt.cxx | 614 |
1 files changed, 397 insertions, 217 deletions
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx index bb63a36ae157..b293f18f824a 100644 --- a/sw/source/core/text/inftxt.cxx +++ b/sw/source/core/text/inftxt.cxx @@ -29,7 +29,6 @@ #include <editeng/hyphenzoneitem.hxx> #include <editeng/hngpnctitem.hxx> #include <editeng/scriptspaceitem.hxx> -#include <editeng/brushitem.hxx> #include <editeng/splwrap.hxx> #include <editeng/pgrditem.hxx> #include <editeng/tstpitem.hxx> @@ -38,7 +37,6 @@ #include <SwSmartTagMgr.hxx> #include <breakit.hxx> #include <editeng/forbiddenruleitem.hxx> -#include <paintfrm.hxx> #include <swmodule.hxx> #include <vcl/svapp.hxx> #include <viewsh.hxx> @@ -66,6 +64,18 @@ #include <vcl/gdimtf.hxx> #include <vcl/virdev.hxx> #include <vcl/gradient.hxx> +#include <i18nlangtag/mslangid.hxx> +#include <formatlinebreak.hxx> + +#include <view.hxx> +#include <wrtsh.hxx> +#include <com/sun/star/text/XTextRange.hpp> +#include <unotextrange.hxx> +#include <SwStyleNameMapper.hxx> +#include <unoprnms.hxx> +#include <editeng/unoprnms.hxx> +#include <unomap.hxx> +#include <com/sun/star/awt/FontSlant.hpp> using namespace ::com::sun::star; using namespace ::com::sun::star::linguistic2; @@ -99,7 +109,7 @@ SwLineInfo::~SwLineInfo() void SwLineInfo::CtorInitLineInfo( const SwAttrSet& rAttrSet, const SwTextNode& rTextNode ) { - m_pRuler.reset( new SvxTabStopItem( rAttrSet.GetTabStops() ) ); + m_oRuler.emplace( rAttrSet.GetTabStops() ); if ( rTextNode.GetListTabStopPosition( m_nListTabStopPosition ) ) { m_bListTabStopIncluded = true; @@ -107,15 +117,15 @@ void SwLineInfo::CtorInitLineInfo( const SwAttrSet& rAttrSet, // insert the list tab stop into SvxTabItem instance <pRuler> const SvxTabStop aListTabStop( m_nListTabStopPosition, SvxTabAdjust::Left ); - m_pRuler->Insert( aListTabStop ); + m_oRuler->Insert( aListTabStop ); // remove default tab stops, which are before the inserted list tab stop - for ( sal_uInt16 i = 0; i < m_pRuler->Count(); i++ ) + for ( sal_uInt16 i = 0; i < m_oRuler->Count(); i++ ) { - if ( (*m_pRuler)[i].GetTabPos() < m_nListTabStopPosition && - (*m_pRuler)[i].GetAdjustment() == SvxTabAdjust::Default ) + if ( (*m_oRuler)[i].GetTabPos() < m_nListTabStopPosition && + (*m_oRuler)[i].GetAdjustment() == SvxTabAdjust::Default ) { - m_pRuler->Remove(i); + m_oRuler->Remove(i); continue; } } @@ -124,12 +134,12 @@ void SwLineInfo::CtorInitLineInfo( const SwAttrSet& rAttrSet, if ( !rTextNode.getIDocumentSettingAccess()->get(DocumentSettingId::TABS_RELATIVE_TO_INDENT) ) { // remove default tab stop at position 0 - for ( sal_uInt16 i = 0; i < m_pRuler->Count(); i++ ) + for ( sal_uInt16 i = 0; i < m_oRuler->Count(); i++ ) { - if ( (*m_pRuler)[i].GetTabPos() == 0 && - (*m_pRuler)[i].GetAdjustment() == SvxTabAdjust::Default ) + if ( (*m_oRuler)[i].GetTabPos() == 0 && + (*m_oRuler)[i].GetAdjustment() == SvxTabAdjust::Default ) { - m_pRuler->Remove(i); + m_oRuler->Remove(i); break; } } @@ -191,6 +201,7 @@ SwTextSizeInfo::SwTextSizeInfo() , m_pText(nullptr) , m_nIdx(0) , m_nLen(0) +, m_nMeasureLen(COMPLETE_STRING) , m_nKanaIdx(0) , m_bOnWin (false) , m_bNotEOL (false) @@ -221,6 +232,7 @@ SwTextSizeInfo::SwTextSizeInfo( const SwTextSizeInfo &rNew ) m_pText(&rNew.GetText()), m_nIdx(rNew.GetIdx()), m_nLen(rNew.GetLen()), + m_nMeasureLen(rNew.GetMeasureLen()), m_nKanaIdx( rNew.GetKanaIdx() ), m_bOnWin( rNew.OnWin() ), m_bNotEOL( rNew.NotEOL() ), @@ -280,14 +292,14 @@ void SwTextSizeInfo::CtorInitTextSizeInfo( OutputDevice* pRenderContext, SwTextF // Set default layout mode ( LTR or RTL ). if ( m_pFrame->IsRightToLeft() ) { - m_pOut->SetLayoutMode( ComplexTextLayoutFlags::BiDiStrong | ComplexTextLayoutFlags::BiDiRtl ); - m_pRef->SetLayoutMode( ComplexTextLayoutFlags::BiDiStrong | ComplexTextLayoutFlags::BiDiRtl ); + m_pOut->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong | vcl::text::ComplexTextLayoutFlags::BiDiRtl ); + m_pRef->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong | vcl::text::ComplexTextLayoutFlags::BiDiRtl ); m_nDirection = DIR_RIGHT2LEFT; } else { - m_pOut->SetLayoutMode( ComplexTextLayoutFlags::BiDiStrong ); - m_pRef->SetLayoutMode( ComplexTextLayoutFlags::BiDiStrong ); + m_pOut->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong ); + m_pRef->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong ); m_nDirection = DIR_LEFT2RIGHT; } @@ -309,7 +321,7 @@ void SwTextSizeInfo::CtorInitTextSizeInfo( OutputDevice* pRenderContext, SwTextF m_pText = &m_pFrame->GetText(); m_nIdx = nNewIdx; - m_nLen = TextFrameIndex(COMPLETE_STRING); + m_nLen = m_nMeasureLen = TextFrameIndex(COMPLETE_STRING); m_bNotEOL = false; m_bStopUnderflow = m_bFootnoteInside = m_bOtherThanFootnoteInside = false; m_bMulti = m_bFirstMulti = m_bRuby = m_bHanging = m_bScriptSpace = @@ -332,6 +344,7 @@ SwTextSizeInfo::SwTextSizeInfo( const SwTextSizeInfo &rNew, const OUString* pTex m_pText(pText), m_nIdx(nIndex), m_nLen(COMPLETE_STRING), + m_nMeasureLen(COMPLETE_STRING), m_nKanaIdx( rNew.GetKanaIdx() ), m_bOnWin( rNew.OnWin() ), m_bNotEOL( rNew.NotEOL() ), @@ -407,6 +420,7 @@ SwPosSize SwTextSizeInfo::GetTextSize() const 0 ; SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, &rSI, *m_pText, m_nIdx, m_nLen ); + aDrawInf.SetMeasureLen( m_nMeasureLen ); aDrawInf.SetFrame( m_pFrame ); aDrawInf.SetFont( m_pFnt ); aDrawInf.SetSnapToGrid( SnapToGrid() ); @@ -417,7 +431,7 @@ SwPosSize SwTextSizeInfo::GetTextSize() const void SwTextSizeInfo::GetTextSize( const SwScriptInfo* pSI, const TextFrameIndex nIndex, const TextFrameIndex nLength, const sal_uInt16 nComp, sal_uInt16& nMinSize, sal_uInt16& nMaxSizeDiff, - vcl::TextLayoutCache const*const pCache) const + vcl::text::TextLayoutCache const*const pCache) const { SwDrawTextInfo aDrawInf( m_pVsh, *m_pOut, pSI, *m_pText, nIndex, nLength, 0, false, pCache); @@ -426,14 +440,14 @@ void SwTextSizeInfo::GetTextSize( const SwScriptInfo* pSI, const TextFrameIndex aDrawInf.SetSnapToGrid( SnapToGrid() ); aDrawInf.SetKanaComp( nComp ); SwPosSize aSize( m_pFnt->GetTextSize_( aDrawInf ) ); - nMaxSizeDiff = static_cast<sal_uInt16>(aDrawInf.GetKanaDiff()); + nMaxSizeDiff = o3tl::narrowing<sal_uInt16>(aDrawInf.GetKanaDiff()); nMinSize = aSize.Width(); } TextFrameIndex SwTextSizeInfo::GetTextBreak( const tools::Long nLineWidth, const TextFrameIndex nMaxLen, const sal_uInt16 nComp, - vcl::TextLayoutCache const*const pCache) const + vcl::text::TextLayoutCache const*const pCache) const { const SwScriptInfo& rScriptInfo = const_cast<SwParaPortion*>(GetParaPortion())->GetScriptInfo(); @@ -454,7 +468,7 @@ TextFrameIndex SwTextSizeInfo::GetTextBreak( const tools::Long nLineWidth, const TextFrameIndex nMaxLen, const sal_uInt16 nComp, TextFrameIndex& rExtraCharPos, - vcl::TextLayoutCache const*const pCache) const + vcl::text::TextLayoutCache const*const pCache) const { const SwScriptInfo& rScriptInfo = const_cast<SwParaPortion*>(GetParaPortion())->GetScriptInfo(); @@ -521,39 +535,6 @@ SwTextPaintInfo::SwTextPaintInfo( SwTextFrame *pFrame, const SwRect &rPaint ) CtorInitTextPaintInfo( pFrame->getRootFrame()->GetCurrShell()->GetOut(), pFrame, rPaint ); } -/// Returns if the current background color is dark. -static bool lcl_IsDarkBackground( const SwTextPaintInfo& rInf ) -{ - std::optional<Color> pCol = rInf.GetFont()->GetBackColor(); - if( ! pCol || COL_TRANSPARENT == *pCol ) - { - const SvxBrushItem* pItem; - SwRect aOrigBackRect; - drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes; - - // Consider, that [GetBackgroundBrush(...)] can set <pCol> - // See implementation in /core/layout/paintfrm.cxx - // There is a background color, if there is a background brush and - // its color is *not* "no fill"/"auto fill". - if( rInf.GetTextFrame()->GetBackgroundBrush( aFillAttributes, pItem, pCol, aOrigBackRect, false, /*bConsiderTextBox=*/false ) ) - { - if ( !pCol ) - pCol = pItem->GetColor(); - - // Determined color <pCol> can be <COL_TRANSPARENT>. Thus, check it. - if ( *pCol == COL_TRANSPARENT) - pCol.reset(); - } - else - pCol.reset(); - } - - if( !pCol ) - pCol = aGlobalRetoucheColor; - - return pCol->IsDark(); -} - namespace { /** @@ -604,7 +585,7 @@ SwTransparentTextGuard::~SwTransparentTextGuard() Gradient aVCLGradient; sal_uInt8 nTransPercentVcl = 255 - m_rPaintInf.GetFont()->GetColor().GetAlpha(); const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl); - aVCLGradient.SetStyle(GradientStyle::Linear); + aVCLGradient.SetStyle(css::awt::GradientStyle_LINEAR); aVCLGradient.SetStartColor(aTransColor); aVCLGradient.SetEndColor(aTransColor); aVCLGradient.SetAngle(0_deg10); @@ -653,7 +634,7 @@ void SwTextPaintInfo::DrawText_( const OUString &rText, const SwLinePortion &rPo aDrawInf.SetUnderFnt( m_pUnderFnt ); const tools::Long nSpaceAdd = ( rPor.IsBlankPortion() || rPor.IsDropPortion() || - rPor.InNumberGrp() ) ? 0 : GetSpaceAdd(); + rPor.InNumberGrp() ) ? 0 : GetSpaceAdd(/*bShrink=*/true); if ( nSpaceAdd ) { TextFrameIndex nCharCnt(0); @@ -681,7 +662,7 @@ void SwTextPaintInfo::DrawText_( const OUString &rText, const SwLinePortion &rPo // Draw text next to the left border Point aFontPos(m_aPos); - if( m_pFnt->GetLeftBorder() && !static_cast<const SwTextPortion&>(rPor).GetJoinBorderWithPrev() ) + if( m_pFnt->GetLeftBorder() && rPor.InTextGrp() && !static_cast<const SwTextPortion&>(rPor).GetJoinBorderWithPrev() ) { const sal_uInt16 nLeftBorderSpace = m_pFnt->GetLeftBorderSpace(); if ( GetTextFrame()->IsRightToLeft() ) @@ -716,7 +697,9 @@ void SwTextPaintInfo::DrawText_( const OUString &rText, const SwLinePortion &rPo std::unique_ptr<SwTransparentTextGuard, o3tl::default_delete<SwTransparentTextGuard>> pTransparentText; if (m_pFnt->GetColor() != COL_AUTO && m_pFnt->GetColor().IsTransparent()) { - pTransparentText.reset(new SwTransparentTextGuard(rPor, *this, aDrawInf)); + // if drawing to a backend that supports transparency for text color, then we don't need to use this + if (!m_bOnWin || !m_pOut->SupportsOperation(OutDevSupportType::TransparentText) || m_pOut->GetConnectMetaFile()) + pTransparentText.reset(new SwTransparentTextGuard(rPor, *this, aDrawInf)); } if( GetTextFly().IsOn() ) @@ -955,7 +938,7 @@ static void lcl_DrawSpecial( const SwTextPaintInfo& rTextPaintInfo, const SwLine Point aTmpPos( nX, nY ); rNonConstTextPaintInfo.SetPos( aTmpPos ); sal_uInt16 nOldWidth = rPor.Width(); - const_cast<SwLinePortion&>(rPor).Width( static_cast<sal_uInt16>(aFontSize.Width()) ); + const_cast<SwLinePortion&>(rPor).Width( o3tl::narrowing<sal_uInt16>(aFontSize.Width()) ); rTextPaintInfo.DrawText( aTmp, rPor ); const_cast<SwLinePortion&>(rPor).Width( nOldWidth ); rNonConstTextPaintInfo.SetFont( const_cast<SwFont*>(pOldFnt) ); @@ -996,6 +979,13 @@ void SwTextPaintInfo::DrawLineBreak( const SwLinePortion &rPor ) const if( !OnWin() ) return; + SwLineBreakClear eClear = SwLineBreakClear::NONE; + if (rPor.IsBreakPortion()) + { + const auto& rBreakPortion = static_cast<const SwBreakPortion&>(rPor); + eClear = rBreakPortion.GetClear(); + } + sal_uInt16 nOldWidth = rPor.Width(); const_cast<SwLinePortion&>(rPor).Width( LINE_BREAK_WIDTH ); @@ -1008,7 +998,24 @@ void SwTextPaintInfo::DrawLineBreak( const SwLinePortion &rPor ) const CHAR_LINEBREAK_RTL : CHAR_LINEBREAK; const sal_uInt8 nOptions = 0; - lcl_DrawSpecial( *this, rPor, aRect, NON_PRINTING_CHARACTER_COLOR, cChar, nOptions ); + SwRect aTextRect(aRect); + if (eClear == SwLineBreakClear::LEFT || eClear == SwLineBreakClear::ALL) + aTextRect.AddLeft(30); + if (eClear == SwLineBreakClear::RIGHT || eClear == SwLineBreakClear::ALL) + aTextRect.AddRight(-30); + lcl_DrawSpecial( *this, rPor, aTextRect, NON_PRINTING_CHARACTER_COLOR, cChar, nOptions ); + + if (eClear != SwLineBreakClear::NONE) + { + // Paint indicator if this clear is left/right/all. + m_pOut->Push(vcl::PushFlags::LINECOLOR); + m_pOut->SetLineColor(NON_PRINTING_CHARACTER_COLOR); + if (eClear != SwLineBreakClear::RIGHT) + m_pOut->DrawLine(aRect.BottomLeft(), aRect.TopLeft()); + if (eClear != SwLineBreakClear::LEFT) + m_pOut->DrawLine(aRect.BottomRight(), aRect.TopRight()); + m_pOut->Pop(); + } } const_cast<SwLinePortion&>(rPor).Width( nOldWidth ); @@ -1089,8 +1096,7 @@ void SwTextPaintInfo::DrawPostIts( bool bScript ) const if ( GetTextFrame()->IsVertical() ) GetTextFrame()->SwitchHorizontalToVertical( aTmpRect ); - const tools::Rectangle aRect( aTmpRect.SVRect() ); - SwViewOption::PaintPostIts( const_cast<OutputDevice*>(GetOut()), aRect, bScript ); + GetOpt().PaintPostIts( const_cast<OutputDevice*>(GetOut()), aTmpRect, bScript ); } @@ -1101,19 +1107,22 @@ void SwTextPaintInfo::DrawCheckBox(const SwFieldFormCheckboxPortion &rPor, bool if ( !aIntersect.HasArea() ) return; - if (OnWin() && SwViewOption::IsFieldShadings() && + if (OnWin() && GetOpt().IsFieldShadings() && !GetOpt().IsPagePreview()) { OutputDevice* pOut = const_cast<OutputDevice*>(GetOut()); - pOut->Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR ); - pOut->SetFillColor( SwViewOption::GetFieldShadingsColor() ); + pOut->Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR ); + if( m_pFnt->GetHighlightColor() != COL_TRANSPARENT ) + pOut->SetFillColor(m_pFnt->GetHighlightColor()); + else + pOut->SetFillColor(GetOpt().GetFieldShadingsColor()); pOut->SetLineColor(); pOut->DrawRect( aIntersect.SVRect() ); pOut->Pop(); } - const int delta=10; + const int delta = 25; tools::Rectangle r(aIntersect.Left()+delta, aIntersect.Top()+delta, aIntersect.Right()-delta, aIntersect.Bottom()-delta); - m_pOut->Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR ); + m_pOut->Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR ); m_pOut->SetLineColor( Color(0, 0, 0)); m_pOut->SetFillColor(); m_pOut->DrawRect( r ); @@ -1125,7 +1134,7 @@ void SwTextPaintInfo::DrawCheckBox(const SwFieldFormCheckboxPortion &rPor, bool m_pOut->Pop(); } -void SwTextPaintInfo::DrawBackground( const SwLinePortion &rPor ) const +void SwTextPaintInfo::DrawBackground( const SwLinePortion &rPor, const Color *pColor ) const { OSL_ENSURE( OnWin(), "SwTextPaintInfo::DrawBackground: printer pollution ?" ); @@ -1136,18 +1145,14 @@ void SwTextPaintInfo::DrawBackground( const SwLinePortion &rPor ) const return; OutputDevice* pOut = const_cast<OutputDevice*>(GetOut()); - pOut->Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR ); + pOut->Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR ); - // For dark background we do not want to have a filled rectangle - if ( GetVsh() && GetVsh()->GetWin() && lcl_IsDarkBackground( *this ) ) - { - pOut->SetLineColor( SwViewOption::GetFontColor() ); - } + if ( pColor ) + pOut->SetFillColor( *pColor ); else - { - pOut->SetFillColor( SwViewOption::GetFieldShadingsColor() ); - pOut->SetLineColor(); - } + pOut->SetFillColor( GetOpt().GetFieldShadingsColor() ); + + pOut->SetLineColor(); DrawRect( aIntersect, true ); pOut->Pop(); @@ -1162,7 +1167,7 @@ void SwTextPaintInfo::DrawBackBrush( const SwLinePortion &rPor ) const { SwPosition const aPosition(m_pFrame->MapViewToModelPos(GetIdx())); const ::sw::mark::IMark* pFieldmark = - m_pFrame->GetDoc().getIDocumentMarkAccess()->getFieldmarkFor(aPosition); + m_pFrame->GetDoc().getIDocumentMarkAccess()->getInnerFieldmarkFor(aPosition); bool bIsStartMark = (TextFrameIndex(1) == GetLen() && CH_TXT_ATR_FIELDSTART == GetText()[sal_Int32(GetIdx())]); if(pFieldmark) { @@ -1171,12 +1176,12 @@ void SwTextPaintInfo::DrawBackBrush( const SwLinePortion &rPor ) const if(bIsStartMark) SAL_INFO("sw.core", "Found StartMark"); if (OnWin() && (pFieldmark!=nullptr || bIsStartMark) && - SwViewOption::IsFieldShadings() && + GetOpt().IsFieldShadings() && !GetOpt().IsPagePreview()) { OutputDevice* pOutDev = const_cast<OutputDevice*>(GetOut()); - pOutDev->Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR ); - pOutDev->SetFillColor( SwViewOption::GetFieldShadingsColor() ); + pOutDev->Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR ); + pOutDev->SetFillColor( GetOpt().GetFieldShadingsColor() ); pOutDev->SetLineColor( ); pOutDev->DrawRect( aIntersect.SVRect() ); pOutDev->Pop(); @@ -1208,89 +1213,7 @@ void SwTextPaintInfo::DrawBackBrush( const SwLinePortion &rPor ) const aFillColor = *m_pFnt->GetBackColor(); } - // tdf#104349 do not highlight portions of space chars before end of line if the compatibility option is enabled - // for LTR mode only - if ( !GetTextFrame()->IsRightToLeft() ) - { - if (GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS)) - { - bool draw = false; - bool full = false; - SwLinePortion *pPos = const_cast<SwLinePortion *>(&rPor); - TextFrameIndex nIdx = GetIdx(); - TextFrameIndex nLen; - - do - { - nLen = pPos->GetLen(); - for (TextFrameIndex i = nIdx; i < (nIdx + nLen); ++i) - { - if (i < TextFrameIndex(GetText().getLength()) - && GetText()[sal_Int32(i)] == CH_TXTATR_NEWLINE) - { - if ( i >= (GetIdx() + rPor.GetLen()) ) - { - goto drawcontinue; - } - } - if (i >= TextFrameIndex(GetText().getLength()) - || GetText()[sal_Int32(i)] != CH_BLANK) - { - draw = true; - if ( i >= (GetIdx() + rPor.GetLen()) ) - { - full = true; - goto drawcontinue; - } - } - } - nIdx += nLen; - pPos = pPos->GetNextPortion(); - } while ( pPos ); - - drawcontinue: - - if ( !draw ) - return; - - if ( !full ) - { - pPos = const_cast<SwLinePortion *>(&rPor); - nIdx = GetIdx(); - - nLen = pPos->GetLen(); - for (TextFrameIndex i = nIdx + nLen - TextFrameIndex(1); - i >= nIdx; --i) - { - if (i < TextFrameIndex(GetText().getLength()) - && GetText()[sal_Int32(i)] == CH_TXTATR_NEWLINE) - { - continue; - } - if (i >= TextFrameIndex(GetText().getLength()) - || GetText()[sal_Int32(i)] != CH_BLANK) - { - sal_uInt16 nOldWidth = rPor.Width(); - sal_uInt16 nNewWidth = GetTextSize(m_pOut, nullptr, - GetText(), nIdx, (i + TextFrameIndex(1) - nIdx)).Width(); - - const_cast<SwLinePortion&>(rPor).Width( nNewWidth ); - CalcRect( rPor, nullptr, &aIntersect, true ); - const_cast<SwLinePortion&>(rPor).Width( nOldWidth ); - - if ( !aIntersect.HasArea() ) - { - return; - } - - break; - } - } - } - } - } - - pTmpOut->Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR ); + pTmpOut->Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR ); pTmpOut->SetFillColor(aFillColor); pTmpOut->SetLineColor(); @@ -1312,71 +1235,243 @@ void SwTextPaintInfo::DrawBorder( const SwLinePortion &rPor ) const } } -void SwTextPaintInfo::DrawViewOpt( const SwLinePortion &rPor, - PortionType nWhich ) const +namespace { + +bool HasValidPropertyValue(const uno::Any& rAny) { - if( !OnWin() || IsMulti() ) + if (bool bValue; rAny >>= bValue) + { + return true; + } + else if (OUString aValue; (rAny >>= aValue) && !(aValue.isEmpty())) + { + return true; + } + else if (awt::FontSlant eValue; rAny >>= eValue) + { + return true; + } + else if (tools::Long nValueLong; rAny >>= nValueLong) + { + return true; + } + else if (double fValue; rAny >>= fValue) + { + return true; + } + else if (short nValueShort; rAny >>= nValueShort) + { + return true; + } + else + return false; +} +} + +void SwTextPaintInfo::DrawCSDFHighlighting(const SwLinePortion &rPor) const +{ + // Don't use GetActiveView() as it does not work as expected when there are multiple open + // documents. + SwView* pView = SwTextFrame::GetView(); + if (!pView) return; - bool bDraw = false; - switch( nWhich ) - { - case PortionType::Footnote: - case PortionType::QuoVadis: - case PortionType::Number: - case PortionType::Field: - case PortionType::Hidden: - case PortionType::Tox: - case PortionType::Ref: - case PortionType::Meta: - case PortionType::ControlChar: - if ( !GetOpt().IsPagePreview() - && !GetOpt().IsReadonly() - && SwViewOption::IsFieldShadings() - && ( PortionType::Number != nWhich - || m_pFrame->GetTextNodeForParaProps()->HasMarkedLabel())) // #i27615# + StylesHighlighterColorMap& rCharStylesColorMap = pView->GetStylesHighlighterCharColorMap(); + + if (rCharStylesColorMap.empty() && !pView->IsHighlightCharDF()) + return; + + SwRect aRect; + CalcRect(rPor, &aRect, nullptr, true); + if(!aRect.HasArea()) + return; + + SwTextFrame* pFrame = const_cast<SwTextFrame*>(GetTextFrame()); + if (!pFrame) + return; + + SwPosition aPosition(pFrame->MapViewToModelPos(GetIdx())); + SwPosition aMarkPosition(pFrame->MapViewToModelPos(GetIdx() + GetLen())); + + rtl::Reference<SwXTextRange> xRange( + SwXTextRange::CreateXTextRange(pFrame->GetDoc(), aPosition, &aMarkPosition)); + + OUString sCurrentCharStyle; + xRange->getPropertyValue("CharStyleName") >>= sCurrentCharStyle; + + std::optional<OUString> sCSNumberOrDF; // CS number or "df" or not used + std::optional<Color> aFillColor; + + // check for CS formatting, if not CS formatted check for direct character formatting + if (!sCurrentCharStyle.isEmpty()) + { + if (!rCharStylesColorMap.empty()) { - bDraw = PortionType::Footnote != nWhich || m_pFrame->IsFootnoteAllowed(); + OUString sCharStyleDisplayName; + sCharStyleDisplayName = SwStyleNameMapper::GetUIName(sCurrentCharStyle, + SwGetPoolIdFromName::ChrFmt); + if (!sCharStyleDisplayName.isEmpty() + && rCharStylesColorMap.find(sCharStyleDisplayName) + != rCharStylesColorMap.end()) + { + aFillColor = rCharStylesColorMap[sCharStyleDisplayName].first; + sCSNumberOrDF = OUString::number(rCharStylesColorMap[sCharStyleDisplayName].second); + } } - break; - case PortionType::Bookmark: - // no shading - break; - case PortionType::InputField: - // input field shading also in read-only mode - if ( !GetOpt().IsPagePreview() - && SwViewOption::IsFieldShadings() ) + } + // not character style formatted + else if (pView->IsHighlightCharDF()) + { + const std::vector<OUString> aHiddenProperties{ UNO_NAME_RSID, + UNO_NAME_PARA_IS_NUMBERING_RESTART, + UNO_NAME_PARA_STYLE_NAME, + UNO_NAME_PARA_CONDITIONAL_STYLE_NAME, + UNO_NAME_PAGE_STYLE_NAME, + UNO_NAME_NUMBERING_START_VALUE, + UNO_NAME_NUMBERING_IS_NUMBER, + UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE, + UNO_NAME_CHAR_STYLE_NAME, + UNO_NAME_NUMBERING_LEVEL, + UNO_NAME_SORTED_TEXT_ID, + UNO_NAME_PARRSID, + UNO_NAME_CHAR_COLOR_THEME, + UNO_NAME_CHAR_COLOR_TINT_OR_SHADE }; + + SfxItemPropertySet const& rPropSet( + *aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)); + SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap()); + + + const uno::Sequence<beans::Property> aProperties + = xRange->getPropertySetInfo()->getProperties(); + + for (const beans::Property& rProperty : aProperties) { - bDraw = true; + const OUString& rPropName = rProperty.Name; + + if (!rMap.hasPropertyByName(rPropName)) + continue; + + if (std::find(aHiddenProperties.begin(), aHiddenProperties.end(), rPropName) + != aHiddenProperties.end()) + continue; + + if (xRange->getPropertyState(rPropName) == beans::PropertyState_DIRECT_VALUE) + { + const uno::Any aAny = xRange->getPropertyValue(rPropName); + if (HasValidPropertyValue(aAny)) + { + sCSNumberOrDF = SwResId(STR_CHARACTER_DIRECT_FORMATTING_TAG); + aFillColor = COL_LIGHTGRAY; + break; + } + } } - break; - case PortionType::Table: - if ( GetOpt().IsTab() ) bDraw = true; - break; - case PortionType::SoftHyphen: - if ( GetOpt().IsSoftHyph() )bDraw = true; - break; - case PortionType::Blank: - if ( GetOpt().IsHardBlank())bDraw = true; - break; - default: + } + if (sCSNumberOrDF) + { + OutputDevice* pTmpOut = const_cast<OutputDevice*>(GetOut()); + pTmpOut->Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR + | vcl::PushFlags::TEXTLAYOUTMODE | vcl::PushFlags::FONT); + + // draw a filled rectangle at the formatted CS or DF text + pTmpOut->SetFillColor(aFillColor.value()); + pTmpOut->SetLineColor(aFillColor.value()); + tools::Rectangle aSVRect(aRect.SVRect()); + pTmpOut->DrawRect(aSVRect); + + // calculate size and position for the CS number or "df" text and rectangle + tools::Long nWidth = pTmpOut->GetTextWidth(sCSNumberOrDF.value()); + tools::Long nHeight = pTmpOut->GetTextHeight(); + aSVRect.SetSize(Size(nWidth, nHeight)); + aSVRect.Move(-(nWidth / 1.5), -(nHeight / 1.5)); + + vcl::Font aFont(pTmpOut->GetFont()); + aFont.SetOrientation(Degree10(0)); + pTmpOut->SetFont(aFont); + + pTmpOut->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::TextOriginLeft); + //pTmpOut->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::BiDiStrong); + + pTmpOut->SetTextFillColor(aFillColor.value()); + pTmpOut->DrawText(aSVRect, sCSNumberOrDF.value(), DrawTextFlags::NONE); + + pTmpOut->Pop(); + } +} + +void SwTextPaintInfo::DrawViewOpt( const SwLinePortion &rPor, + PortionType nWhich, const Color *pColor ) const +{ + if( !OnWin() || IsMulti() ) + return; + + bool bDraw = false; + if ( !GetOpt().IsPagePreview() + && !GetOpt().IsReadonly() ) + { + switch( nWhich ) { - OSL_ENSURE( false, "SwTextPaintInfo::DrawViewOpt: don't know how to draw this" ); + case PortionType::Tab: + if ( GetOpt().IsViewMetaChars() ) + bDraw = GetOpt().IsTab(); + break; + case PortionType::SoftHyphen: + if ( GetOpt().IsViewMetaChars() ) + bDraw = GetOpt().IsSoftHyph(); + break; + case PortionType::Blank: + if ( GetOpt().IsViewMetaChars() ) + bDraw = GetOpt().IsHardBlank(); + break; + case PortionType::ControlChar: + if ( GetOpt().IsViewMetaChars() ) + bDraw = true; + break; + case PortionType::Bookmark: + // no shading break; + case PortionType::Footnote: + case PortionType::QuoVadis: + case PortionType::Number: + case PortionType::Hidden: + case PortionType::Tox: + case PortionType::Ref: + case PortionType::Meta: + case PortionType::ContentControl: + case PortionType::Field: + case PortionType::InputField: + // input field shading also in read-only mode + if (GetOpt().IsFieldShadings() + && ( PortionType::Number != nWhich + || m_pFrame->GetTextNodeForParaProps()->HasMarkedLabel())) // #i27615# + { + bDraw = PortionType::Footnote != nWhich || m_pFrame->IsFootnoteAllowed(); + } + break; + default: + { + OSL_ENSURE( false, "SwTextPaintInfo::DrawViewOpt: don't know how to draw this" ); + break; + } } } + if ( bDraw ) - DrawBackground( rPor ); + DrawBackground( rPor, pColor ); } static void lcl_InitHyphValues( PropertyValues &rVals, - sal_Int16 nMinLeading, sal_Int16 nMinTrailing, bool bNoCapsHyphenation ) + sal_Int16 nMinLeading, sal_Int16 nMinTrailing, + bool bNoCapsHyphenation, bool bNoLastWordHyphenation, + sal_Int16 nMinWordLength, sal_Int16 nTextHyphZone, bool bKeep, sal_Int16 nKeepType, + sal_Int16 nCompoundMinLeading ) { sal_Int32 nLen = rVals.getLength(); if (0 == nLen) // yet to be initialized? { - rVals.realloc( 3 ); + rVals.realloc( 9 ); PropertyValue *pVal = rVals.getArray(); pVal[0].Name = UPN_HYPH_MIN_LEADING; @@ -1390,13 +1485,43 @@ static void lcl_InitHyphValues( PropertyValues &rVals, pVal[2].Name = UPN_HYPH_NO_CAPS; pVal[2].Handle = UPH_HYPH_NO_CAPS; pVal[2].Value <<= bNoCapsHyphenation; + + pVal[3].Name = UPN_HYPH_NO_LAST_WORD; + pVal[3].Handle = UPH_HYPH_NO_LAST_WORD; + pVal[3].Value <<= bNoLastWordHyphenation; + + pVal[4].Name = UPN_HYPH_MIN_WORD_LENGTH; + pVal[4].Handle = UPH_HYPH_MIN_WORD_LENGTH; + pVal[4].Value <<= nMinWordLength; + + pVal[5].Name = UPN_HYPH_ZONE; + pVal[5].Handle = UPH_HYPH_ZONE; + pVal[5].Value <<= nTextHyphZone; + + pVal[6].Name = UPN_HYPH_KEEP_TYPE; + pVal[6].Handle = UPH_HYPH_KEEP_TYPE; + pVal[6].Value <<= nKeepType; + + pVal[7].Name = UPN_HYPH_COMPOUND_MIN_LEADING; + pVal[7].Handle = UPH_HYPH_COMPOUND_MIN_LEADING; + pVal[7].Value <<= nCompoundMinLeading; + + pVal[8].Name = UPN_HYPH_KEEP; + pVal[8].Handle = UPH_HYPH_KEEP; + pVal[8].Value <<= bKeep; } - else if (3 == nLen) // already initialized once? + else if (9 == nLen) // already initialized once? { PropertyValue *pVal = rVals.getArray(); pVal[0].Value <<= nMinLeading; pVal[1].Value <<= nMinTrailing; pVal[2].Value <<= bNoCapsHyphenation; + pVal[3].Value <<= bNoLastWordHyphenation; + pVal[4].Value <<= nMinWordLength; + pVal[5].Value <<= nTextHyphZone; + pVal[6].Value <<= nKeepType; + pVal[7].Value <<= nCompoundMinLeading; + pVal[8].Value <<= bKeep; } else { OSL_FAIL( "unexpected size of sequence" ); @@ -1405,7 +1530,7 @@ static void lcl_InitHyphValues( PropertyValues &rVals, const PropertyValues & SwTextFormatInfo::GetHyphValues() const { - OSL_ENSURE( 3 == m_aHyphVals.getLength(), + OSL_ENSURE( 9 == m_aHyphVals.getLength(), "hyphenation values not yet initialized" ); return m_aHyphVals; } @@ -1423,8 +1548,16 @@ bool SwTextFormatInfo::InitHyph( const bool bAutoHyphen ) { const sal_Int16 nMinimalLeading = std::max(rAttr.GetMinLead(), sal_uInt8(2)); const sal_Int16 nMinimalTrailing = rAttr.GetMinTrail(); + const sal_Int16 nMinimalWordLength = rAttr.GetMinWordLength(); const bool bNoCapsHyphenation = rAttr.IsNoCapsHyphenation(); - lcl_InitHyphValues( m_aHyphVals, nMinimalLeading, nMinimalTrailing, bNoCapsHyphenation); + const bool bNoLastWordHyphenation = rAttr.IsNoLastWordHyphenation(); + const sal_Int16 nTextHyphZone = rAttr.GetTextHyphenZone(); + const bool bKeep = rAttr.IsKeep(); + const sal_Int16 nKeepType = rAttr.GetKeepType(); + const sal_Int16 nCompoundMinimalLeading = std::max(rAttr.GetCompoundMinLead(), sal_uInt8(2)); + lcl_InitHyphValues( m_aHyphVals, nMinimalLeading, nMinimalTrailing, + bNoCapsHyphenation, bNoLastWordHyphenation, + nMinimalWordLength, nTextHyphZone, bKeep, nKeepType, nCompoundMinimalLeading ); } return bAuto; } @@ -1456,7 +1589,7 @@ void SwTextFormatInfo::CtorInitTextFormatInfo( OutputDevice* pRenderContext, SwT SetLineStart(TextFrameIndex(0)); SvtCTLOptions::TextNumerals const nTextNumerals( - SW_MOD()->GetCTLOptions().GetCTLTextNumerals()); + SvtCTLOptions::GetCTLTextNumerals()); // cannot cache for NUMERALS_CONTEXT because we need to know the string // for the whole paragraph now if (nTextNumerals != SvtCTLOptions::NUMERALS_CONTEXT) @@ -1483,7 +1616,9 @@ bool SwTextFormatInfo::IsHyphenate() const return false; LanguageType eTmp = GetFont()->GetLanguage(); - if( LANGUAGE_DONTKNOW == eTmp || LANGUAGE_NONE == eTmp ) + // TODO: check for more ideographic langs w/o hyphenation as a concept + if ( LANGUAGE_DONTKNOW == eTmp || LANGUAGE_NONE == eTmp + || !MsLangId::usesHyphenation(eTmp) ) return false; uno::Reference< XHyphenator > xHyph = ::GetHyphenator(); @@ -1501,7 +1636,7 @@ bool SwTextFormatInfo::IsHyphenate() const pShell->AppendInfoBarWhenReady( "hyphenationmissing", SwResId(STR_HYPH_MISSING), SwResId(STR_HYPH_MISSING_DETAIL) - .replaceFirst("%1", g_pBreakIt->GetLocale(eTmp).Language), + .replaceFirst("%1", LanguageTag::convertToBcp47( g_pBreakIt->GetLocale(eTmp))), InfobarType::WARNING); } } @@ -1616,6 +1751,37 @@ SwTextFormatInfo::SwTextFormatInfo( const SwTextFormatInfo& rInf, SetFirstMulti( rInf.IsFirstMulti() ); } +void SwTextFormatInfo::UpdateTabSeen(PortionType type) +{ + switch (type) + { + case PortionType::TabLeft: + m_eLastTabsSeen = TabSeen::Left; + break; + case PortionType::TabRight: + m_eLastTabsSeen = TabSeen::Right; + break; + case PortionType::TabCenter: + m_eLastTabsSeen = TabSeen::Center; + break; + case PortionType::TabDecimal: + m_eLastTabsSeen = TabSeen::Decimal; + break; + case PortionType::Break: + m_eLastTabsSeen = TabSeen::None; + break; + default: + break; + } +} + +void SwTextFormatInfo::SetLast(SwLinePortion* pNewLast) +{ + m_pLast = pNewLast; + assert(pNewLast); // We never pass nullptr here. If we start, then a check is needed below. + UpdateTabSeen(pNewLast->GetWhichPor()); +} + bool SwTextFormatInfo::CheckFootnotePortion_( SwLineLayout const * pCurr ) { const sal_uInt16 nHeight = pCurr->GetRealHeight(); @@ -1758,7 +1924,9 @@ SwTwips SwTextFormatInfo::GetLineWidth() const bool bTabOverMargin = GetTextFrame()->GetDoc().getIDocumentSettingAccess().get( DocumentSettingId::TAB_OVER_MARGIN); - if (!bTabOverMargin) + const bool bTabOverSpacing = GetTextFrame()->GetDoc().getIDocumentSettingAccess().get( + DocumentSettingId::TAB_OVER_SPACING); + if (!bTabOverMargin && !bTabOverSpacing) return nLineWidth; SwTabPortion* pLastTab = GetLastTab(); @@ -1789,6 +1957,12 @@ SwTwips SwTextFormatInfo::GetLineWidth() // text frame area to the right (RR above, but not LL). nLineWidth = nTextFrameWidth - X(); + if (!bTabOverMargin) // thus bTabOverSpacing only + { + // right, center, decimal can back-fill all the available space - same as TabOverMargin + if (pLastTab->GetWhichPor() == PortionType::TabLeft) + nLineWidth = nTextFrameWidth - pLastTab->GetTabPos(); + } return nLineWidth; } @@ -1803,6 +1977,7 @@ SwTextSlot::SwTextSlot( , m_pOldGrammarCheckList(nullptr) , nIdx(0) , nLen(0) + , nMeasureLen(0) , pInf(nullptr) { if( rCh.isEmpty() ) @@ -1822,11 +1997,15 @@ SwTextSlot::SwTextSlot( pInf = const_cast<SwTextSizeInfo*>(pNew); nIdx = pInf->GetIdx(); nLen = pInf->GetLen(); + nMeasureLen = pInf->GetMeasureLen(); pOldText = &(pInf->GetText()); m_pOldCachedVclData = pInf->GetCachedVclData(); pInf->SetText( aText ); pInf->SetIdx(TextFrameIndex(0)); pInf->SetLen(bTextLen ? TextFrameIndex(pInf->GetText().getLength()) : pPor->GetLen()); + if (nMeasureLen != TextFrameIndex(COMPLETE_STRING)) + pInf->SetMeasureLen(TextFrameIndex(COMPLETE_STRING)); + pInf->SetCachedVclData(nullptr); // ST2 @@ -1900,6 +2079,7 @@ SwTextSlot::~SwTextSlot() pInf->SetText( *pOldText ); pInf->SetIdx( nIdx ); pInf->SetLen( nLen ); + pInf->SetMeasureLen( nMeasureLen ); // ST2 // Restore old smart tag list |