1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/linguistic2/XHyphenator.hpp>
22 #include <unotools/linguprops.hxx>
23 #include <unotools/lingucfg.hxx>
24 #include <hintids.hxx>
25 #include <svl/ctloptions.hxx>
26 #include <sfx2/infobar.hxx>
27 #include <sfx2/printer.hxx>
28 #include <sal/log.hxx>
29 #include <editeng/hyphenzoneitem.hxx>
30 #include <editeng/hngpnctitem.hxx>
31 #include <editeng/scriptspaceitem.hxx>
32 #include <editeng/splwrap.hxx>
33 #include <editeng/pgrditem.hxx>
34 #include <editeng/tstpitem.hxx>
35 #include <editeng/shaditem.hxx>
37 #include <SwSmartTagMgr.hxx>
38 #include <breakit.hxx>
39 #include <editeng/forbiddenruleitem.hxx>
40 #include <swmodule.hxx>
41 #include <vcl/svapp.hxx>
43 #include <viewopt.hxx>
44 #include <frmtool.hxx>
45 #include <IDocumentSettingAccess.hxx>
46 #include <IDocumentDeviceAccess.hxx>
47 #include <IDocumentMarkAccess.hxx>
49 #include <rootfrm.hxx>
51 #include <noteurl.hxx>
59 #include <numrule.hxx>
60 #include <EnhancedPDFExportHelper.hxx>
62 #include <strings.hrc>
63 #include <o3tl/deleter.hxx>
64 #include <vcl/gdimtf.hxx>
65 #include <vcl/virdev.hxx>
66 #include <vcl/gradient.hxx>
67 #include <i18nlangtag/mslangid.hxx>
68 #include <formatlinebreak.hxx>
72 #include <com/sun/star/text/XTextRange.hpp>
73 #include <unotextrange.hxx>
74 #include <SwStyleNameMapper.hxx>
75 #include <unoprnms.hxx>
76 #include <editeng/unoprnms.hxx>
78 #include <com/sun/star/awt/FontSlant.hpp>
80 using namespace ::com::sun::star
;
81 using namespace ::com::sun::star::linguistic2
;
82 using namespace ::com::sun::star::uno
;
83 using namespace ::com::sun::star::beans
;
85 #define CHAR_UNDERSCORE u'_'
86 #define CHAR_LEFT_ARROW u'\x25C0'
87 #define CHAR_RIGHT_ARROW u'\x25B6'
88 #define CHAR_TAB u'\x2192'
89 #define CHAR_TAB_RTL u'\x2190'
90 #define CHAR_LINEBREAK u'\x21B5'
91 #define CHAR_LINEBREAK_RTL u'\x21B3'
93 #define DRAW_SPECIAL_OPTIONS_CENTER 1
94 #define DRAW_SPECIAL_OPTIONS_ROTATE 2
96 SwLineInfo::SwLineInfo()
97 : m_pSpace( nullptr ),
98 m_nVertAlign( SvxParaVertAlignItem::Align::Automatic
),
100 m_bListTabStopIncluded( false ),
101 m_nListTabStopPosition( 0 )
105 SwLineInfo::~SwLineInfo()
109 void SwLineInfo::CtorInitLineInfo( const SwAttrSet
& rAttrSet
,
110 const SwTextNode
& rTextNode
)
112 m_oRuler
.emplace( rAttrSet
.GetTabStops() );
113 if ( rTextNode
.GetListTabStopPosition( m_nListTabStopPosition
) )
115 m_bListTabStopIncluded
= true;
117 // insert the list tab stop into SvxTabItem instance <pRuler>
118 const SvxTabStop
aListTabStop( m_nListTabStopPosition
,
119 SvxTabAdjust::Left
);
120 m_oRuler
->Insert( aListTabStop
);
122 // remove default tab stops, which are before the inserted list tab stop
123 for ( sal_uInt16 i
= 0; i
< m_oRuler
->Count(); i
++ )
125 if ( (*m_oRuler
)[i
].GetTabPos() < m_nListTabStopPosition
&&
126 (*m_oRuler
)[i
].GetAdjustment() == SvxTabAdjust::Default
)
134 if ( !rTextNode
.getIDocumentSettingAccess()->get(DocumentSettingId::TABS_RELATIVE_TO_INDENT
) )
136 // remove default tab stop at position 0
137 for ( sal_uInt16 i
= 0; i
< m_oRuler
->Count(); i
++ )
139 if ( (*m_oRuler
)[i
].GetTabPos() == 0 &&
140 (*m_oRuler
)[i
].GetAdjustment() == SvxTabAdjust::Default
)
148 m_pSpace
= &rAttrSet
.GetLineSpacing();
149 m_nVertAlign
= rAttrSet
.GetParaVertAlign().GetValue();
150 m_nDefTabStop
= USHRT_MAX
;
153 void SwTextInfo::CtorInitTextInfo( SwTextFrame
*pFrame
)
155 m_pPara
= pFrame
->GetPara();
156 m_nTextStart
= pFrame
->GetOffset();
159 SAL_WARN("sw.core", "+SwTextInfo::CTOR: missing paragraph information");
160 pFrame
->Format(pFrame
->getRootFrame()->GetCurrShell()->GetOut());
161 m_pPara
= pFrame
->GetPara();
165 SwTextInfo::SwTextInfo( const SwTextInfo
&rInf
)
166 : m_pPara( const_cast<SwTextInfo
&>(rInf
).GetParaPortion() )
167 , m_nTextStart( rInf
.GetTextStart() )
170 #if OSL_DEBUG_LEVEL > 0
172 static void ChkOutDev( const SwTextSizeInfo
&rInf
)
174 if ( !rInf
.GetVsh() )
177 const OutputDevice
* pOut
= rInf
.GetOut();
178 const OutputDevice
* pRef
= rInf
.GetRefDev();
179 OSL_ENSURE( pOut
&& pRef
, "ChkOutDev: invalid output devices" );
183 static TextFrameIndex
GetMinLen( const SwTextSizeInfo
&rInf
)
185 const TextFrameIndex
nTextLen(rInf
.GetText().getLength());
186 if (rInf
.GetLen() == TextFrameIndex(COMPLETE_STRING
))
188 const TextFrameIndex nInfLen
= rInf
.GetIdx() + rInf
.GetLen();
189 return std::min(nTextLen
, nInfLen
);
192 SwTextSizeInfo::SwTextSizeInfo()
193 : m_pKanaComp(nullptr)
198 , m_pUnderFnt(nullptr)
204 , m_nMeasureLen(COMPLETE_STRING
)
208 , m_bURLNotify(false)
209 , m_bStopUnderflow(false)
210 , m_bFootnoteInside(false)
211 , m_bOtherThanFootnoteInside(false)
213 , m_bFirstMulti(false)
216 , m_bScriptSpace(false)
217 , m_bForbiddenChars(false)
218 , m_bSnapToGrid(false)
222 SwTextSizeInfo::SwTextSizeInfo( const SwTextSizeInfo
&rNew
)
223 : SwTextInfo( rNew
),
224 m_pKanaComp(rNew
.GetpKanaComp()),
225 m_pVsh(const_cast<SwTextSizeInfo
&>(rNew
).GetVsh()),
226 m_pOut(const_cast<SwTextSizeInfo
&>(rNew
).GetOut()),
227 m_pRef(const_cast<SwTextSizeInfo
&>(rNew
).GetRefDev()),
228 m_pFnt(const_cast<SwTextSizeInfo
&>(rNew
).GetFont()),
229 m_pUnderFnt(rNew
.GetUnderFnt()),
230 m_pFrame(rNew
.m_pFrame
),
231 m_pOpt(&rNew
.GetOpt()),
232 m_pText(&rNew
.GetText()),
233 m_nIdx(rNew
.GetIdx()),
234 m_nLen(rNew
.GetLen()),
235 m_nMeasureLen(rNew
.GetMeasureLen()),
236 m_nKanaIdx( rNew
.GetKanaIdx() ),
237 m_bOnWin( rNew
.OnWin() ),
238 m_bNotEOL( rNew
.NotEOL() ),
239 m_bURLNotify( rNew
.URLNotify() ),
240 m_bStopUnderflow( rNew
.StopUnderflow() ),
241 m_bFootnoteInside( rNew
.IsFootnoteInside() ),
242 m_bOtherThanFootnoteInside( rNew
.IsOtherThanFootnoteInside() ),
243 m_bMulti( rNew
.IsMulti() ),
244 m_bFirstMulti( rNew
.IsFirstMulti() ),
245 m_bRuby( rNew
.IsRuby() ),
246 m_bHanging( rNew
.IsHanging() ),
247 m_bScriptSpace( rNew
.HasScriptSpace() ),
248 m_bForbiddenChars( rNew
.HasForbiddenChars() ),
249 m_bSnapToGrid( rNew
.SnapToGrid() ),
250 m_nDirection( rNew
.GetDirection() )
252 #if OSL_DEBUG_LEVEL > 0
257 void SwTextSizeInfo::CtorInitTextSizeInfo( OutputDevice
* pRenderContext
, SwTextFrame
*pFrame
,
258 TextFrameIndex
const nNewIdx
)
260 m_pKanaComp
= nullptr;
263 CtorInitTextInfo( m_pFrame
);
264 SwDoc
const& rDoc(m_pFrame
->GetDoc());
265 m_pVsh
= m_pFrame
->getRootFrame()->GetCurrShell();
267 // Get the output and reference device
270 m_pOut
= pRenderContext
;
271 m_pRef
= &m_pVsh
->GetRefDev();
272 m_bOnWin
= m_pVsh
->GetWin() || OUTDEV_WINDOW
== m_pOut
->GetOutDevType() || m_pVsh
->isOutputToWindow();
276 // Access via StarONE. We do not need a Shell or an active one.
277 if (rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE
))
279 // We can only pick the AppWin here? (there's nothing better to pick?)
280 m_pOut
= Application::GetDefaultDevice();
283 m_pOut
= rDoc
.getIDocumentDeviceAccess().getPrinter(false);
288 #if OSL_DEBUG_LEVEL > 0
292 // Set default layout mode ( LTR or RTL ).
293 if ( m_pFrame
->IsRightToLeft() )
295 m_pOut
->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong
| vcl::text::ComplexTextLayoutFlags::BiDiRtl
);
296 m_pRef
->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong
| vcl::text::ComplexTextLayoutFlags::BiDiRtl
);
297 m_nDirection
= DIR_RIGHT2LEFT
;
301 m_pOut
->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong
);
302 m_pRef
->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::BiDiStrong
);
303 m_nDirection
= DIR_LEFT2RIGHT
;
309 m_pVsh
->GetViewOptions() :
310 SW_MOD()->GetViewOption(rDoc
.getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE
)); // Options from Module, due to StarONE
312 // bURLNotify is set if MakeGraphic prepares it
314 m_bURLNotify
= pNoteURL
&& !m_bOnWin
;
316 SetSnapToGrid( m_pFrame
->GetTextNodeForParaProps()->GetSwAttrSet().GetParaGrid().GetValue() &&
317 m_pFrame
->IsInDocBody() );
320 m_pUnderFnt
= nullptr;
321 m_pText
= &m_pFrame
->GetText();
324 m_nLen
= m_nMeasureLen
= TextFrameIndex(COMPLETE_STRING
);
326 m_bStopUnderflow
= m_bFootnoteInside
= m_bOtherThanFootnoteInside
= false;
327 m_bMulti
= m_bFirstMulti
= m_bRuby
= m_bHanging
= m_bScriptSpace
=
328 m_bForbiddenChars
= false;
330 SetLen( GetMinLen( *this ) );
333 SwTextSizeInfo::SwTextSizeInfo( const SwTextSizeInfo
&rNew
, const OUString
* pText
,
334 TextFrameIndex
const nIndex
)
335 : SwTextInfo( rNew
),
336 m_pKanaComp(rNew
.GetpKanaComp()),
337 m_pVsh(const_cast<SwTextSizeInfo
&>(rNew
).GetVsh()),
338 m_pOut(const_cast<SwTextSizeInfo
&>(rNew
).GetOut()),
339 m_pRef(const_cast<SwTextSizeInfo
&>(rNew
).GetRefDev()),
340 m_pFnt(const_cast<SwTextSizeInfo
&>(rNew
).GetFont()),
341 m_pUnderFnt(rNew
.GetUnderFnt()),
342 m_pFrame( rNew
.m_pFrame
),
343 m_pOpt(&rNew
.GetOpt()),
346 m_nLen(COMPLETE_STRING
),
347 m_nMeasureLen(COMPLETE_STRING
),
348 m_nKanaIdx( rNew
.GetKanaIdx() ),
349 m_bOnWin( rNew
.OnWin() ),
350 m_bNotEOL( rNew
.NotEOL() ),
351 m_bURLNotify( rNew
.URLNotify() ),
352 m_bStopUnderflow( rNew
.StopUnderflow() ),
353 m_bFootnoteInside( rNew
.IsFootnoteInside() ),
354 m_bOtherThanFootnoteInside( rNew
.IsOtherThanFootnoteInside() ),
355 m_bMulti( rNew
.IsMulti() ),
356 m_bFirstMulti( rNew
.IsFirstMulti() ),
357 m_bRuby( rNew
.IsRuby() ),
358 m_bHanging( rNew
.IsHanging() ),
359 m_bScriptSpace( rNew
.HasScriptSpace() ),
360 m_bForbiddenChars( rNew
.HasForbiddenChars() ),
361 m_bSnapToGrid( rNew
.SnapToGrid() ),
362 m_nDirection( rNew
.GetDirection() )
364 #if OSL_DEBUG_LEVEL > 0
367 SetLen( GetMinLen( *this ) );
370 SwTextSizeInfo::SwTextSizeInfo(SwTextFrame
*const pTextFrame
,
371 TextFrameIndex
const nIndex
)
374 CtorInitTextSizeInfo( pTextFrame
->getRootFrame()->GetCurrShell()->GetOut(), pTextFrame
, nIndex
);
377 void SwTextSizeInfo::SelectFont()
379 // The path needs to go via ChgPhysFnt or the FontMetricCache gets confused.
380 // In this case pLastMet has it's old value.
381 // Wrong: GetOut()->SetFont( GetFont()->GetFnt() );
382 GetFont()->Invalidate();
383 GetFont()->ChgPhysFnt( m_pVsh
, *GetOut() );
386 void SwTextSizeInfo::NoteAnimation() const
389 SwRootFrame::FlushVout();
391 OSL_ENSURE( m_pOut
== m_pVsh
->GetOut(),
392 "SwTextSizeInfo::NoteAnimation() changed m_pOut" );
395 SwPosSize
SwTextSizeInfo::GetTextSize( OutputDevice
* pOutDev
,
396 const SwScriptInfo
* pSI
,
397 const OUString
& rText
,
398 const TextFrameIndex nIndex
,
399 const TextFrameIndex nLength
) const
401 SwDrawTextInfo
aDrawInf( m_pVsh
, *pOutDev
, pSI
, rText
, nIndex
, nLength
);
402 aDrawInf
.SetFrame( m_pFrame
);
403 aDrawInf
.SetFont( m_pFnt
);
404 aDrawInf
.SetSnapToGrid( SnapToGrid() );
405 aDrawInf
.SetKanaComp( 0 );
406 return SwPosSize(m_pFnt
->GetTextSize_( aDrawInf
));
409 SwPosSize
SwTextSizeInfo::GetTextSize() const
411 const SwScriptInfo
& rSI
=
412 const_cast<SwParaPortion
*>(GetParaPortion())->GetScriptInfo();
414 // in some cases, compression is not allowed or suppressed for
415 // performance reasons
416 sal_uInt16 nComp
=( SwFontScript::CJK
== GetFont()->GetActual() &&
417 rSI
.CountCompChg() &&
422 SwDrawTextInfo
aDrawInf( m_pVsh
, *m_pOut
, &rSI
, *m_pText
, m_nIdx
, m_nLen
);
423 aDrawInf
.SetMeasureLen( m_nMeasureLen
);
424 aDrawInf
.SetFrame( m_pFrame
);
425 aDrawInf
.SetFont( m_pFnt
);
426 aDrawInf
.SetSnapToGrid( SnapToGrid() );
427 aDrawInf
.SetKanaComp( nComp
);
428 return SwPosSize(m_pFnt
->GetTextSize_( aDrawInf
));
431 void SwTextSizeInfo::GetTextSize( const SwScriptInfo
* pSI
, const TextFrameIndex nIndex
,
432 const TextFrameIndex nLength
, const sal_uInt16 nComp
,
433 sal_uInt16
& nMinSize
, sal_uInt16
& nMaxSizeDiff
,
434 vcl::text::TextLayoutCache
const*const pCache
) const
436 SwDrawTextInfo
aDrawInf( m_pVsh
, *m_pOut
, pSI
, *m_pText
, nIndex
, nLength
,
438 aDrawInf
.SetFrame( m_pFrame
);
439 aDrawInf
.SetFont( m_pFnt
);
440 aDrawInf
.SetSnapToGrid( SnapToGrid() );
441 aDrawInf
.SetKanaComp( nComp
);
442 SwPosSize
aSize( m_pFnt
->GetTextSize_( aDrawInf
) );
443 nMaxSizeDiff
= o3tl::narrowing
<sal_uInt16
>(aDrawInf
.GetKanaDiff());
444 nMinSize
= aSize
.Width();
447 TextFrameIndex
SwTextSizeInfo::GetTextBreak( const tools::Long nLineWidth
,
448 const TextFrameIndex nMaxLen
,
449 const sal_uInt16 nComp
,
450 vcl::text::TextLayoutCache
const*const pCache
) const
452 const SwScriptInfo
& rScriptInfo
=
453 const_cast<SwParaPortion
*>(GetParaPortion())->GetScriptInfo();
455 OSL_ENSURE( m_pRef
== m_pOut
, "GetTextBreak is supposed to use the RefDev" );
456 SwDrawTextInfo
aDrawInf( m_pVsh
, *m_pOut
, &rScriptInfo
,
457 *m_pText
, GetIdx(), nMaxLen
, 0, false, pCache
);
458 aDrawInf
.SetFrame( m_pFrame
);
459 aDrawInf
.SetFont( m_pFnt
);
460 aDrawInf
.SetSnapToGrid( SnapToGrid() );
461 aDrawInf
.SetKanaComp( nComp
);
462 aDrawInf
.SetHyphPos( nullptr );
464 return m_pFnt
->GetTextBreak( aDrawInf
, nLineWidth
);
467 TextFrameIndex
SwTextSizeInfo::GetTextBreak( const tools::Long nLineWidth
,
468 const TextFrameIndex nMaxLen
,
469 const sal_uInt16 nComp
,
470 TextFrameIndex
& rExtraCharPos
,
471 vcl::text::TextLayoutCache
const*const pCache
) const
473 const SwScriptInfo
& rScriptInfo
=
474 const_cast<SwParaPortion
*>(GetParaPortion())->GetScriptInfo();
476 OSL_ENSURE( m_pRef
== m_pOut
, "GetTextBreak is supposed to use the RefDev" );
477 SwDrawTextInfo
aDrawInf( m_pVsh
, *m_pOut
, &rScriptInfo
,
478 *m_pText
, GetIdx(), nMaxLen
, 0, false, pCache
);
479 aDrawInf
.SetFrame( m_pFrame
);
480 aDrawInf
.SetFont( m_pFnt
);
481 aDrawInf
.SetSnapToGrid( SnapToGrid() );
482 aDrawInf
.SetKanaComp( nComp
);
483 aDrawInf
.SetHyphPos( &rExtraCharPos
);
485 return m_pFnt
->GetTextBreak( aDrawInf
, nLineWidth
);
488 bool SwTextSizeInfo::HasHint(TextFrameIndex
const nPos
) const
490 std::pair
<SwTextNode
const*, sal_Int32
> const pos(m_pFrame
->MapViewToModel(nPos
));
491 return pos
.first
->GetTextAttrForCharAt(pos
.second
);
494 void SwTextPaintInfo::CtorInitTextPaintInfo( OutputDevice
* pRenderContext
, SwTextFrame
*pFrame
, const SwRect
&rPaint
)
496 CtorInitTextSizeInfo( pRenderContext
, pFrame
, TextFrameIndex(0) );
497 m_aTextFly
.CtorInitTextFly( pFrame
);
498 m_aPaintRect
= rPaint
;
500 m_pSpaceAdd
= nullptr;
501 m_pWrongList
= nullptr;
502 m_pGrammarCheckList
= nullptr;
503 m_pSmartTags
= nullptr;
504 m_pBrushItem
= nullptr;
507 SwTextPaintInfo::SwTextPaintInfo( const SwTextPaintInfo
&rInf
, const OUString
* pText
)
508 : SwTextSizeInfo( rInf
, pText
)
509 , m_pWrongList( rInf
.GetpWrongList() )
510 , m_pGrammarCheckList( rInf
.GetGrammarCheckList() )
511 , m_pSmartTags( rInf
.GetSmartTags() )
512 , m_pSpaceAdd( rInf
.GetpSpaceAdd() ),
513 m_pBrushItem( rInf
.GetBrushItem() ),
514 m_aTextFly( rInf
.GetTextFly() ),
515 m_aPos( rInf
.GetPos() ),
516 m_aPaintRect( rInf
.GetPaintRect() ),
517 m_nSpaceIdx( rInf
.GetSpaceIdx() )
520 SwTextPaintInfo::SwTextPaintInfo( const SwTextPaintInfo
&rInf
)
521 : SwTextSizeInfo( rInf
)
522 , m_pWrongList( rInf
.GetpWrongList() )
523 , m_pGrammarCheckList( rInf
.GetGrammarCheckList() )
524 , m_pSmartTags( rInf
.GetSmartTags() )
525 , m_pSpaceAdd( rInf
.GetpSpaceAdd() ),
526 m_pBrushItem( rInf
.GetBrushItem() ),
527 m_aTextFly( rInf
.GetTextFly() ),
528 m_aPos( rInf
.GetPos() ),
529 m_aPaintRect( rInf
.GetPaintRect() ),
530 m_nSpaceIdx( rInf
.GetSpaceIdx() )
533 SwTextPaintInfo::SwTextPaintInfo( SwTextFrame
*pFrame
, const SwRect
&rPaint
)
535 CtorInitTextPaintInfo( pFrame
->getRootFrame()->GetCurrShell()->GetOut(), pFrame
, rPaint
);
541 * Context class that captures the draw operations on rDrawInf's output device for transparency
544 class SwTransparentTextGuard
546 ScopedVclPtrInstance
<VirtualDevice
> m_aContentVDev
;
547 GDIMetaFile m_aContentMetafile
;
548 MapMode m_aNewMapMode
;
550 SwTextPaintInfo
& m_rPaintInf
;
551 SwDrawTextInfo
& m_rDrawInf
;
554 SwTransparentTextGuard(const SwLinePortion
& rPor
, SwTextPaintInfo
& rPaintInf
,
555 SwDrawTextInfo
& rDrawInf
);
556 ~SwTransparentTextGuard();
559 SwTransparentTextGuard::SwTransparentTextGuard(const SwLinePortion
& rPor
,
560 SwTextPaintInfo
& rPaintInf
, SwDrawTextInfo
& rDrawInf
)
561 : m_aNewMapMode(rPaintInf
.GetOut()->GetMapMode())
562 , m_rPaintInf(rPaintInf
)
563 , m_rDrawInf(rDrawInf
)
565 rPaintInf
.CalcRect(rPor
, &m_aPorRect
);
566 rDrawInf
.SetOut(*m_aContentVDev
);
567 m_aContentVDev
->SetMapMode(rPaintInf
.GetOut()->GetMapMode());
568 m_aContentMetafile
.Record(m_aContentVDev
.get());
569 m_aContentVDev
->SetLineColor(rPaintInf
.GetOut()->GetLineColor());
570 m_aContentVDev
->SetFillColor(rPaintInf
.GetOut()->GetFillColor());
571 m_aContentVDev
->SetFont(rPaintInf
.GetOut()->GetFont());
572 m_aContentVDev
->SetDrawMode(rPaintInf
.GetOut()->GetDrawMode());
573 m_aContentVDev
->SetSettings(rPaintInf
.GetOut()->GetSettings());
574 m_aContentVDev
->SetRefPoint(rPaintInf
.GetOut()->GetRefPoint());
577 SwTransparentTextGuard::~SwTransparentTextGuard()
579 m_aContentMetafile
.Stop();
580 m_aContentMetafile
.WindStart();
581 m_aNewMapMode
.SetOrigin(m_aPorRect
.TopLeft());
582 m_aContentMetafile
.SetPrefMapMode(m_aNewMapMode
);
583 m_aContentMetafile
.SetPrefSize(m_aPorRect
.SSize());
584 m_rDrawInf
.SetOut(*m_rPaintInf
.GetOut());
585 Gradient aVCLGradient
;
586 sal_uInt8 nTransPercentVcl
= 255 - m_rPaintInf
.GetFont()->GetColor().GetAlpha();
587 const Color
aTransColor(nTransPercentVcl
, nTransPercentVcl
, nTransPercentVcl
);
588 aVCLGradient
.SetStyle(css::awt::GradientStyle_LINEAR
);
589 aVCLGradient
.SetStartColor(aTransColor
);
590 aVCLGradient
.SetEndColor(aTransColor
);
591 aVCLGradient
.SetAngle(0_deg10
);
592 aVCLGradient
.SetBorder(0);
593 aVCLGradient
.SetOfsX(0);
594 aVCLGradient
.SetOfsY(0);
595 aVCLGradient
.SetStartIntensity(100);
596 aVCLGradient
.SetEndIntensity(100);
597 aVCLGradient
.SetSteps(2);
598 m_rPaintInf
.GetOut()->DrawTransparent(m_aContentMetafile
, m_aPorRect
.TopLeft(),
599 m_aPorRect
.SSize(), aVCLGradient
);
603 void SwTextPaintInfo::DrawText_( const OUString
&rText
, const SwLinePortion
&rPor
,
604 TextFrameIndex
const nStart
, TextFrameIndex
const nLength
,
605 const bool bKern
, const bool bWrong
,
606 const bool bSmartTag
,
607 const bool bGrammarCheck
)
612 // The SwScriptInfo is useless if we are inside a field portion
613 SwScriptInfo
* pSI
= nullptr;
614 if ( ! rPor
.InFieldGrp() )
615 pSI
= &GetParaPortion()->GetScriptInfo();
617 // in some cases, kana compression is not allowed or suppressed for
618 // performance reasons
619 sal_uInt16 nComp
= 0;
621 nComp
= GetKanaComp();
623 bool bCfgIsAutoGrammar
= false;
624 SvtLinguConfig().GetProperty( UPN_IS_GRAMMAR_AUTO
) >>= bCfgIsAutoGrammar
;
625 const bool bBullet
= OnWin() && GetOpt().IsBlank() && IsNoSymbol();
626 const bool bTmpWrong
= bWrong
&& OnWin() && GetOpt().IsOnlineSpell();
627 const bool bTmpGrammarCheck
= bGrammarCheck
&& OnWin() && bCfgIsAutoGrammar
&& GetOpt().IsOnlineSpell();
628 const bool bTmpSmart
= bSmartTag
&& OnWin() && !GetOpt().IsPagePreview() && SwSmartTagMgr::Get().IsSmartTagsEnabled();
630 OSL_ENSURE( GetParaPortion(), "No paragraph!");
631 SwDrawTextInfo
aDrawInf( m_pFrame
->getRootFrame()->GetCurrShell(), *m_pOut
, pSI
, rText
, nStart
, nLength
,
632 rPor
.Width(), bBullet
);
634 aDrawInf
.SetUnderFnt( m_pUnderFnt
);
636 const tools::Long nSpaceAdd
= ( rPor
.IsBlankPortion() || rPor
.IsDropPortion() ||
637 rPor
.InNumberGrp() ) ? 0 : GetSpaceAdd();
640 TextFrameIndex
nCharCnt(0);
641 // #i41860# Thai justified alignment needs some
642 // additional information:
643 aDrawInf
.SetNumberOfBlanks( rPor
.InTextGrp() ?
644 static_cast<const SwTextPortion
&>(rPor
).GetSpaceCnt( *this, nCharCnt
) :
648 aDrawInf
.SetSpace( nSpaceAdd
);
649 aDrawInf
.SetKanaComp( nComp
);
651 // the font is used to identify the current script via nActual
652 aDrawInf
.SetFont( m_pFnt
);
653 // the frame is used to identify the orientation
654 aDrawInf
.SetFrame( GetTextFrame() );
655 // we have to know if the paragraph should snap to grid
656 aDrawInf
.SetSnapToGrid( SnapToGrid() );
657 // for underlining we must know when not to add extra space behind
658 // a character in justified mode
659 aDrawInf
.SetSpaceStop( ! rPor
.GetNextPortion() ||
660 rPor
.GetNextPortion()->InFixMargGrp() ||
661 rPor
.GetNextPortion()->IsHolePortion() );
663 // Draw text next to the left border
664 Point
aFontPos(m_aPos
);
665 if( m_pFnt
->GetLeftBorder() && rPor
.InTextGrp() && !static_cast<const SwTextPortion
&>(rPor
).GetJoinBorderWithPrev() )
667 const sal_uInt16 nLeftBorderSpace
= m_pFnt
->GetLeftBorderSpace();
668 if ( GetTextFrame()->IsRightToLeft() )
670 aFontPos
.AdjustX( -nLeftBorderSpace
);
674 switch( m_pFnt
->GetOrientation(GetTextFrame()->IsVertical()).get() )
677 aFontPos
.AdjustX(nLeftBorderSpace
);
680 aFontPos
.AdjustY( -nLeftBorderSpace
);
683 aFontPos
.AdjustX( -nLeftBorderSpace
);
686 aFontPos
.AdjustY(nLeftBorderSpace
);
690 if( aFontPos
.X() < 0 )
692 if( aFontPos
.Y() < 0 )
696 // Handle semi-transparent text if necessary.
697 std::unique_ptr
<SwTransparentTextGuard
, o3tl::default_delete
<SwTransparentTextGuard
>> pTransparentText
;
698 if (m_pFnt
->GetColor() != COL_AUTO
&& m_pFnt
->GetColor().IsTransparent())
700 pTransparentText
.reset(new SwTransparentTextGuard(rPor
, *this, aDrawInf
));
703 if( GetTextFly().IsOn() )
705 // aPos needs to be the TopLeft, because we cannot calculate the
706 // ClipRects otherwise
707 const Point
aPoint( aFontPos
.X(), aFontPos
.Y() - rPor
.GetAscent() );
708 const Size
aSize( rPor
.Width(), rPor
.Height() );
709 aDrawInf
.SetPos( aPoint
);
710 aDrawInf
.SetSize( aSize
);
711 aDrawInf
.SetAscent( rPor
.GetAscent() );
712 aDrawInf
.SetKern( bKern
? rPor
.Width() : 0 );
713 aDrawInf
.SetWrong( bTmpWrong
? m_pWrongList
: nullptr );
714 aDrawInf
.SetGrammarCheck( bTmpGrammarCheck
? m_pGrammarCheckList
: nullptr );
715 aDrawInf
.SetSmartTags( bTmpSmart
? m_pSmartTags
: nullptr );
716 GetTextFly().DrawTextOpaque( aDrawInf
);
720 aDrawInf
.SetPos( aFontPos
);
722 m_pFnt
->DrawStretchText_( aDrawInf
);
725 aDrawInf
.SetWrong( bTmpWrong
? m_pWrongList
: nullptr );
726 aDrawInf
.SetGrammarCheck( bTmpGrammarCheck
? m_pGrammarCheckList
: nullptr );
727 aDrawInf
.SetSmartTags( bTmpSmart
? m_pSmartTags
: nullptr );
728 m_pFnt
->DrawText_( aDrawInf
);
733 void SwTextPaintInfo::CalcRect( const SwLinePortion
& rPor
,
734 SwRect
* pRect
, SwRect
* pIntersect
,
735 const bool bInsideBox
) const
737 Size
aSize( rPor
.Width(), rPor
.Height() );
738 if( rPor
.IsHangingPortion() )
739 aSize
.setWidth( static_cast<const SwHangingPortion
&>(rPor
).GetInnerWidth() );
740 if( rPor
.InSpaceGrp() && GetSpaceAdd() )
742 SwTwips nAdd
= rPor
.CalcSpacing( GetSpaceAdd(), *this );
743 if( rPor
.InFieldGrp() && GetSpaceAdd() < 0 && nAdd
)
744 nAdd
+= GetSpaceAdd() / SPACING_PRECISION_FACTOR
;
745 aSize
.AdjustWidth(nAdd
);
752 tools::Long nTmp
= aSize
.Width();
753 aSize
.setWidth( aSize
.Height() );
754 aSize
.setHeight( nTmp
);
755 if ( 1 == GetDirection() )
757 aPoint
.setX( X() - rPor
.GetAscent() );
758 aPoint
.setY( Y() - aSize
.Height() );
762 aPoint
.setX( X() - rPor
.Height() + rPor
.GetAscent() );
769 if (GetTextFrame()->IsVertLR() && !GetTextFrame()->IsVertLRBT())
770 aPoint
.setY( Y() - rPor
.Height() + rPor
.GetAscent() );
772 aPoint
.setY( Y() - rPor
.GetAscent() );
775 // Adjust x coordinate if we are inside a bidi portion
776 const bool bFrameDir
= GetTextFrame()->IsRightToLeft();
777 const bool bCounterDir
= ( !bFrameDir
&& DIR_RIGHT2LEFT
== GetDirection() ) ||
778 ( bFrameDir
&& DIR_LEFT2RIGHT
== GetDirection() );
781 aPoint
.AdjustX( -(aSize
.Width()) );
783 SwRect
aRect( aPoint
, aSize
);
785 if ( GetTextFrame()->IsRightToLeft() )
786 GetTextFrame()->SwitchLTRtoRTL( aRect
);
788 if ( GetTextFrame()->IsVertical() )
789 GetTextFrame()->SwitchHorizontalToVertical( aRect
);
791 if( bInsideBox
&& rPor
.InTextGrp() )
793 const bool bJoinWithPrev
=
794 static_cast<const SwTextPortion
&>(rPor
).GetJoinBorderWithPrev();
795 const bool bJoinWithNext
=
796 static_cast<const SwTextPortion
&>(rPor
).GetJoinBorderWithNext();
797 const bool bIsVert
= GetTextFrame()->IsVertical();
798 const bool bIsVertLRBT
= GetTextFrame()->IsVertLRBT();
799 aRect
.AddTop( GetFont()->CalcShadowSpace(SvxShadowItemSide::TOP
, bIsVert
, bIsVertLRBT
,
800 bJoinWithPrev
, bJoinWithNext
));
801 aRect
.AddBottom( - GetFont()->CalcShadowSpace(SvxShadowItemSide::BOTTOM
, bIsVert
, bIsVertLRBT
,
802 bJoinWithPrev
, bJoinWithNext
));
803 aRect
.AddLeft( GetFont()->CalcShadowSpace(SvxShadowItemSide::LEFT
, bIsVert
, bIsVertLRBT
,
804 bJoinWithPrev
, bJoinWithNext
));
805 aRect
.AddRight( - GetFont()->CalcShadowSpace(SvxShadowItemSide::RIGHT
, bIsVert
, bIsVertLRBT
,
806 bJoinWithPrev
, bJoinWithNext
));
812 if( aRect
.HasArea() && pIntersect
)
814 ::SwAlignRect( aRect
, GetVsh(), GetOut() );
816 if ( GetOut()->IsClipRegion() )
818 SwRect
aClip( GetOut()->GetClipRegion().GetBoundRect() );
819 aRect
.Intersection( aClip
);
827 * Draws a special portion
828 * E.g.: line break portion, tab portion
830 * @param rPor The portion
831 * @param rRect The rectangle surrounding the character
832 * @param rCol Specify a color for the character
833 * @param bCenter Draw the character centered, otherwise left aligned
834 * @param bRotate Rotate the character if character rotation is set
836 static void lcl_DrawSpecial( const SwTextPaintInfo
& rTextPaintInfo
, const SwLinePortion
& rPor
,
837 SwRect
& rRect
, const Color
& rCol
, sal_Unicode cChar
,
840 bool bCenter
= 0 != ( nOptions
& DRAW_SPECIAL_OPTIONS_CENTER
);
841 bool bRotate
= 0 != ( nOptions
& DRAW_SPECIAL_OPTIONS_ROTATE
);
843 // rRect is given in absolute coordinates
844 if ( rTextPaintInfo
.GetTextFrame()->IsRightToLeft() )
845 rTextPaintInfo
.GetTextFrame()->SwitchRTLtoLTR( rRect
);
846 if ( rTextPaintInfo
.GetTextFrame()->IsVertical() )
847 rTextPaintInfo
.GetTextFrame()->SwitchVerticalToHorizontal( rRect
);
849 const SwFont
* pOldFnt
= rTextPaintInfo
.GetFont();
851 // Font is generated only once:
852 static SwFont s_aFnt
= [&]()
854 SwFont
tmp( *pOldFnt
);
855 tmp
.SetFamily( FAMILY_DONTKNOW
, tmp
.GetActual() );
856 tmp
.SetName( numfunc::GetDefBulletFontname(), tmp
.GetActual() );
857 tmp
.SetStyleName(OUString(), tmp
.GetActual());
858 tmp
.SetCharSet( RTL_TEXTENCODING_SYMBOL
, tmp
.GetActual() );
862 // Some of the current values are set at the font:
864 s_aFnt
.SetVertical( 0_deg10
, rTextPaintInfo
.GetTextFrame()->IsVertical() );
866 s_aFnt
.SetVertical( pOldFnt
->GetOrientation() );
868 s_aFnt
.SetColor(rCol
);
870 Size
aFontSize( 0, SPECIAL_FONT_HEIGHT
);
871 s_aFnt
.SetSize( aFontSize
, s_aFnt
.GetActual() );
873 SwTextPaintInfo
& rNonConstTextPaintInfo
= const_cast<SwTextPaintInfo
&>(rTextPaintInfo
);
875 rNonConstTextPaintInfo
.SetFont( &s_aFnt
);
877 // The maximum width depends on the current orientation
878 const Degree10 nDir
= s_aFnt
.GetOrientation( rTextPaintInfo
.GetTextFrame()->IsVertical() );
880 if (nDir
== 900_deg10
|| nDir
== 2700_deg10
)
881 nMaxWidth
= rRect
.Height();
884 assert(nDir
== 0_deg10
); //Unknown direction set at font
885 nMaxWidth
= rRect
.Width();
888 // check if char fits into rectangle
889 const OUString
aTmp( cChar
);
890 aFontSize
= rTextPaintInfo
.GetTextSize( aTmp
).SvLSize();
891 while ( aFontSize
.Width() > nMaxWidth
)
893 SwTwips nFactor
= ( 100 * aFontSize
.Width() ) / nMaxWidth
;
894 const SwTwips nOldWidth
= aFontSize
.Width();
896 // new height for font
897 const SwFontScript nAct
= s_aFnt
.GetActual();
898 aFontSize
.setHeight( ( 100 * s_aFnt
.GetSize( nAct
).Height() ) / nFactor
);
899 aFontSize
.setWidth( ( 100 * s_aFnt
.GetSize( nAct
).Width() ) / nFactor
);
901 if ( !aFontSize
.Width() && !aFontSize
.Height() )
904 s_aFnt
.SetSize( aFontSize
, nAct
);
906 aFontSize
= rTextPaintInfo
.GetTextSize( aTmp
).SvLSize();
908 if ( aFontSize
.Width() >= nOldWidth
)
912 const Point
aOldPos( rTextPaintInfo
.GetPos() );
914 // adjust values so that tab is vertically and horizontally centered
915 SwTwips nX
= rRect
.Left();
916 SwTwips nY
= rRect
.Top();
917 switch ( nDir
.get() )
921 nX
+= ( rRect
.Width() - aFontSize
.Width() ) / 2;
922 nY
+= ( rRect
.Height() - aFontSize
.Height() ) / 2 + rTextPaintInfo
.GetAscent();
926 nX
+= ( rRect
.Width() - aFontSize
.Height() ) / 2 + rTextPaintInfo
.GetAscent();
927 nY
+= ( rRect
.Height() + aFontSize
.Width() ) / 2;
931 nX
+= ( rRect
.Width() + aFontSize
.Height() ) / 2 - rTextPaintInfo
.GetAscent();
932 nY
+= ( rRect
.Height() - aFontSize
.Width() ) / 2;
936 Point
aTmpPos( nX
, nY
);
937 rNonConstTextPaintInfo
.SetPos( aTmpPos
);
938 sal_uInt16 nOldWidth
= rPor
.Width();
939 const_cast<SwLinePortion
&>(rPor
).Width( o3tl::narrowing
<sal_uInt16
>(aFontSize
.Width()) );
940 rTextPaintInfo
.DrawText( aTmp
, rPor
);
941 const_cast<SwLinePortion
&>(rPor
).Width( nOldWidth
);
942 rNonConstTextPaintInfo
.SetFont( const_cast<SwFont
*>(pOldFnt
) );
943 rNonConstTextPaintInfo
.SetPos( aOldPos
);
946 void SwTextPaintInfo::DrawRect( const SwRect
&rRect
, bool bRetouche
) const
948 if ( OnWin() || !bRetouche
)
950 if( m_aTextFly
.IsOn() )
951 const_cast<SwTextPaintInfo
*>(this)->GetTextFly().
952 DrawFlyRect( m_pOut
, rRect
);
954 m_pOut
->DrawRect( rRect
.SVRect() );
958 void SwTextPaintInfo::DrawTab( const SwLinePortion
&rPor
) const
964 CalcRect( rPor
, &aRect
);
966 if ( ! aRect
.HasArea() )
969 const sal_Unicode cChar
= GetTextFrame()->IsRightToLeft() ? CHAR_TAB_RTL
: CHAR_TAB
;
970 const sal_uInt8 nOptions
= DRAW_SPECIAL_OPTIONS_CENTER
| DRAW_SPECIAL_OPTIONS_ROTATE
;
972 lcl_DrawSpecial( *this, rPor
, aRect
, NON_PRINTING_CHARACTER_COLOR
, cChar
, nOptions
);
975 void SwTextPaintInfo::DrawLineBreak( const SwLinePortion
&rPor
) const
980 SwLineBreakClear eClear
= SwLineBreakClear::NONE
;
981 if (rPor
.IsBreakPortion())
983 const auto& rBreakPortion
= static_cast<const SwBreakPortion
&>(rPor
);
984 eClear
= rBreakPortion
.GetClear();
987 sal_uInt16 nOldWidth
= rPor
.Width();
988 const_cast<SwLinePortion
&>(rPor
).Width( LINE_BREAK_WIDTH
);
991 CalcRect( rPor
, &aRect
);
993 if( aRect
.HasArea() )
995 const sal_Unicode cChar
= GetTextFrame()->IsRightToLeft() ?
996 CHAR_LINEBREAK_RTL
: CHAR_LINEBREAK
;
997 const sal_uInt8 nOptions
= 0;
999 SwRect
aTextRect(aRect
);
1000 if (eClear
== SwLineBreakClear::LEFT
|| eClear
== SwLineBreakClear::ALL
)
1001 aTextRect
.AddLeft(30);
1002 if (eClear
== SwLineBreakClear::RIGHT
|| eClear
== SwLineBreakClear::ALL
)
1003 aTextRect
.AddRight(-30);
1004 lcl_DrawSpecial( *this, rPor
, aTextRect
, NON_PRINTING_CHARACTER_COLOR
, cChar
, nOptions
);
1006 if (eClear
!= SwLineBreakClear::NONE
)
1008 // Paint indicator if this clear is left/right/all.
1009 m_pOut
->Push(vcl::PushFlags::LINECOLOR
);
1010 m_pOut
->SetLineColor(NON_PRINTING_CHARACTER_COLOR
);
1011 if (eClear
!= SwLineBreakClear::RIGHT
)
1012 m_pOut
->DrawLine(aRect
.BottomLeft(), aRect
.TopLeft());
1013 if (eClear
!= SwLineBreakClear::LEFT
)
1014 m_pOut
->DrawLine(aRect
.BottomRight(), aRect
.TopRight());
1019 const_cast<SwLinePortion
&>(rPor
).Width( nOldWidth
);
1022 void SwTextPaintInfo::DrawRedArrow( const SwLinePortion
&rPor
) const
1024 Size
aSize( SPECIAL_FONT_HEIGHT
, SPECIAL_FONT_HEIGHT
);
1025 SwRect
aRect( static_cast<const SwArrowPortion
&>(rPor
).GetPos(), aSize
);
1027 if( static_cast<const SwArrowPortion
&>(rPor
).IsLeft() )
1029 aRect
.Pos().AdjustY(20 - GetAscent() );
1030 aRect
.Pos().AdjustX(20 );
1031 if( aSize
.Height() > rPor
.Height() )
1032 aRect
.Height( rPor
.Height() );
1033 cChar
= CHAR_LEFT_ARROW
;
1037 if( aSize
.Height() > rPor
.Height() )
1038 aRect
.Height( rPor
.Height() );
1039 aRect
.Pos().AdjustY( -(aRect
.Height() + 20) );
1040 aRect
.Pos().AdjustX( -(aRect
.Width() + 20) );
1041 cChar
= CHAR_RIGHT_ARROW
;
1044 if ( GetTextFrame()->IsVertical() )
1045 GetTextFrame()->SwitchHorizontalToVertical( aRect
);
1047 if( aRect
.HasArea() )
1049 const sal_uInt8 nOptions
= 0;
1050 lcl_DrawSpecial( *this, rPor
, aRect
, COL_LIGHTRED
, cChar
, nOptions
);
1054 void SwTextPaintInfo::DrawPostIts( bool bScript
) const
1056 if( !OnWin() || !m_pOpt
->IsPostIts() )
1062 const sal_uInt16 nPostItsWidth
= SwViewOption::GetPostItsWidth( GetOut() );
1063 const sal_uInt16 nFontHeight
= m_pFnt
->GetHeight( m_pVsh
, *GetOut() );
1064 const sal_uInt16 nFontAscent
= m_pFnt
->GetAscent( m_pVsh
, *GetOut() );
1066 switch ( m_pFnt
->GetOrientation( GetTextFrame()->IsVertical() ).get() )
1069 aSize
.setWidth( nPostItsWidth
);
1070 aSize
.setHeight( nFontHeight
);
1071 aTmp
.setX( m_aPos
.X() );
1072 aTmp
.setY( m_aPos
.Y() - nFontAscent
);
1075 aSize
.setHeight( nPostItsWidth
);
1076 aSize
.setWidth( nFontHeight
);
1077 aTmp
.setX( m_aPos
.X() - nFontAscent
);
1078 aTmp
.setY( m_aPos
.Y() );
1081 aSize
.setHeight( nPostItsWidth
);
1082 aSize
.setWidth( nFontHeight
);
1083 aTmp
.setX( m_aPos
.X() - nFontHeight
+
1085 aTmp
.setY( m_aPos
.Y() );
1089 SwRect
aTmpRect( aTmp
, aSize
);
1091 if ( GetTextFrame()->IsRightToLeft() )
1092 GetTextFrame()->SwitchLTRtoRTL( aTmpRect
);
1094 if ( GetTextFrame()->IsVertical() )
1095 GetTextFrame()->SwitchHorizontalToVertical( aTmpRect
);
1097 GetOpt().PaintPostIts( const_cast<OutputDevice
*>(GetOut()), aTmpRect
, bScript
);
1101 void SwTextPaintInfo::DrawCheckBox(const SwFieldFormCheckboxPortion
&rPor
, bool bChecked
) const
1104 CalcRect( rPor
, &aIntersect
);
1105 if ( !aIntersect
.HasArea() )
1108 if (OnWin() && GetOpt().IsFieldShadings() &&
1109 !GetOpt().IsPagePreview())
1111 OutputDevice
* pOut
= const_cast<OutputDevice
*>(GetOut());
1112 pOut
->Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
1113 pOut
->SetFillColor( GetOpt().GetFieldShadingsColor() );
1114 pOut
->SetLineColor();
1115 pOut
->DrawRect( aIntersect
.SVRect() );
1119 tools::Rectangle
r(aIntersect
.Left()+delta
, aIntersect
.Top()+delta
, aIntersect
.Right()-delta
, aIntersect
.Bottom()-delta
);
1120 m_pOut
->Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
1121 m_pOut
->SetLineColor( Color(0, 0, 0));
1122 m_pOut
->SetFillColor();
1123 m_pOut
->DrawRect( r
);
1126 m_pOut
->DrawLine(r
.TopLeft(), r
.BottomRight());
1127 m_pOut
->DrawLine(r
.TopRight(), r
.BottomLeft());
1132 void SwTextPaintInfo::DrawBackground( const SwLinePortion
&rPor
, const Color
*pColor
) const
1134 OSL_ENSURE( OnWin(), "SwTextPaintInfo::DrawBackground: printer pollution ?" );
1137 CalcRect( rPor
, nullptr, &aIntersect
, true );
1139 if ( !aIntersect
.HasArea() )
1142 OutputDevice
* pOut
= const_cast<OutputDevice
*>(GetOut());
1143 pOut
->Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
1146 pOut
->SetFillColor( *pColor
);
1148 pOut
->SetFillColor( GetOpt().GetFieldShadingsColor() );
1150 pOut
->SetLineColor();
1152 DrawRect( aIntersect
, true );
1156 void SwTextPaintInfo::DrawBackBrush( const SwLinePortion
&rPor
) const
1160 CalcRect( rPor
, &aIntersect
, nullptr, true );
1161 if(aIntersect
.HasArea())
1163 SwPosition
const aPosition(m_pFrame
->MapViewToModelPos(GetIdx()));
1164 const ::sw::mark::IMark
* pFieldmark
=
1165 m_pFrame
->GetDoc().getIDocumentMarkAccess()->getInnerFieldmarkFor(aPosition
);
1166 bool bIsStartMark
= (TextFrameIndex(1) == GetLen()
1167 && CH_TXT_ATR_FIELDSTART
== GetText()[sal_Int32(GetIdx())]);
1169 SAL_INFO("sw.core", "Found Fieldmark " << pFieldmark
->ToString());
1172 SAL_INFO("sw.core", "Found StartMark");
1173 if (OnWin() && (pFieldmark
!=nullptr || bIsStartMark
) &&
1174 GetOpt().IsFieldShadings() &&
1175 !GetOpt().IsPagePreview())
1177 OutputDevice
* pOutDev
= const_cast<OutputDevice
*>(GetOut());
1178 pOutDev
->Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
1179 pOutDev
->SetFillColor( GetOpt().GetFieldShadingsColor() );
1180 pOutDev
->SetLineColor( );
1181 pOutDev
->DrawRect( aIntersect
.SVRect() );
1188 CalcRect( rPor
, nullptr, &aIntersect
, true );
1190 if ( !aIntersect
.HasArea() )
1193 OutputDevice
* pTmpOut
= const_cast<OutputDevice
*>(GetOut());
1195 // #i16816# tagged pdf support
1196 SwTaggedPDFHelper
aTaggedPDFHelper( nullptr, nullptr, nullptr, *pTmpOut
);
1200 if( m_pFnt
->GetHighlightColor() != COL_TRANSPARENT
)
1202 aFillColor
= m_pFnt
->GetHighlightColor();
1206 if( !m_pFnt
->GetBackColor() )
1208 aFillColor
= *m_pFnt
->GetBackColor();
1211 // tdf#104349 do not highlight portions of space chars before end of line if the compatibility option is enabled
1212 // for LTR mode only
1213 if ( !GetTextFrame()->IsRightToLeft() )
1215 if (GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS
))
1219 const sal_Int32 nMaxLen
= GetText().getLength();
1220 const sal_Int32
nCurrPorEnd(GetIdx() + rPor
.GetLen());
1221 const SwLinePortion
* pPos
= &rPor
;
1222 TextFrameIndex nIdx
= GetIdx();
1226 const sal_Int32 nEndPos
= std::min(sal_Int32(nIdx
+ pPos
->GetLen()), nMaxLen
);
1227 for (sal_Int32 i
= sal_Int32(nIdx
); i
< nEndPos
; ++i
)
1229 if (i
< nMaxLen
&& i
>= nCurrPorEnd
&& GetText()[i
] == CH_TXTATR_NEWLINE
)
1232 if (i
== nMaxLen
|| GetText()[i
] != CH_BLANK
)
1235 if (i
>= nCurrPorEnd
)
1242 nIdx
+= pPos
->GetLen();
1243 pPos
= pPos
->GetNextPortion();
1253 const sal_Int32 nLastPos
= std::min(nCurrPorEnd
, nMaxLen
) - 1;
1254 for (sal_Int32 i
= nLastPos
; TextFrameIndex(i
) >= GetIdx(); --i
)
1256 if (GetText()[i
] == CH_TXTATR_NEWLINE
)
1259 if (GetText()[i
] != CH_BLANK
)
1261 const sal_uInt16 nOldWidth
= rPor
.Width();
1262 const sal_uInt16 nExcessWidth
1263 = GetTextSize(m_pOut
, nullptr, GetText(), TextFrameIndex(i
+ 1),
1264 TextFrameIndex(nLastPos
- i
)).Width();
1265 const_cast<SwLinePortion
&>(rPor
).Width(nOldWidth
- nExcessWidth
);
1266 CalcRect( rPor
, nullptr, &aIntersect
, true );
1267 const_cast<SwLinePortion
&>(rPor
).Width( nOldWidth
);
1269 if ( !aIntersect
.HasArea() )
1279 pTmpOut
->Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
1281 pTmpOut
->SetFillColor(aFillColor
);
1282 pTmpOut
->SetLineColor();
1284 DrawRect( aIntersect
, false );
1289 void SwTextPaintInfo::DrawBorder( const SwLinePortion
&rPor
) const
1292 CalcRect( rPor
, &aDrawArea
);
1293 if ( aDrawArea
.HasArea() )
1295 PaintCharacterBorder(*m_pFnt
, aDrawArea
, GetTextFrame()->IsVertical(),
1296 GetTextFrame()->IsVertLRBT(), rPor
.GetJoinBorderWithPrev(),
1297 rPor
.GetJoinBorderWithNext());
1303 bool HasValidPropertyValue(const uno::Any
& rAny
)
1305 if (bool bValue
; rAny
>>= bValue
)
1309 else if (OUString aValue
; (rAny
>>= aValue
) && !(aValue
.isEmpty()))
1313 else if (awt::FontSlant eValue
; rAny
>>= eValue
)
1317 else if (tools::Long nValueLong
; rAny
>>= nValueLong
)
1321 else if (double fValue
; rAny
>>= fValue
)
1325 else if (short nValueShort
; rAny
>>= nValueShort
)
1334 void SwTextPaintInfo::DrawCSDFHighlighting(const SwLinePortion
&rPor
) const
1336 // Don't use GetActiveView() as it does not work as expected when there are multiple open
1338 SwView
* pView
= SwTextFrame::GetView();
1342 StylesHighlighterColorMap
& rCharStylesColorMap
= pView
->GetStylesHighlighterCharColorMap();
1344 if (rCharStylesColorMap
.empty() && !pView
->IsHighlightCharDF())
1348 CalcRect(rPor
, &aRect
, nullptr, true);
1349 if(!aRect
.HasArea())
1352 SwTextFrame
* pFrame
= const_cast<SwTextFrame
*>(GetTextFrame());
1356 SwPosition
aPosition(pFrame
->MapViewToModelPos(GetIdx()));
1357 SwPosition
aMarkPosition(pFrame
->MapViewToModelPos(GetIdx() + GetLen()));
1359 uno::Reference
<text::XTextRange
> xRange(
1360 SwXTextRange::CreateXTextRange(pFrame
->GetDoc(), aPosition
, &aMarkPosition
));
1361 uno::Reference
<beans::XPropertySet
> xPropertiesSet(xRange
, uno::UNO_QUERY_THROW
);
1363 OUString sCurrentCharStyle
;
1364 xPropertiesSet
->getPropertyValue("CharStyleName") >>= sCurrentCharStyle
;
1366 std::optional
<OUString
> sCSNumberOrDF
; // CS number or "df" or not used
1367 std::optional
<Color
> aFillColor
;
1369 // check for CS formatting, if not CS formatted check for direct character formatting
1370 if (!sCurrentCharStyle
.isEmpty())
1372 if (!rCharStylesColorMap
.empty())
1374 OUString sCharStyleDisplayName
;
1375 sCharStyleDisplayName
= SwStyleNameMapper::GetUIName(sCurrentCharStyle
,
1376 SwGetPoolIdFromName::ChrFmt
);
1377 if (!sCharStyleDisplayName
.isEmpty()
1378 && rCharStylesColorMap
.find(sCharStyleDisplayName
)
1379 != rCharStylesColorMap
.end())
1381 aFillColor
= rCharStylesColorMap
[sCharStyleDisplayName
].first
;
1382 sCSNumberOrDF
= OUString::number(rCharStylesColorMap
[sCharStyleDisplayName
].second
);
1386 // not character style formatted
1387 else if (pView
->IsHighlightCharDF())
1389 const std::vector
<OUString
> aHiddenProperties
{ UNO_NAME_RSID
,
1390 UNO_NAME_PARA_IS_NUMBERING_RESTART
,
1391 UNO_NAME_PARA_STYLE_NAME
,
1392 UNO_NAME_PARA_CONDITIONAL_STYLE_NAME
,
1393 UNO_NAME_PAGE_STYLE_NAME
,
1394 UNO_NAME_NUMBERING_START_VALUE
,
1395 UNO_NAME_NUMBERING_IS_NUMBER
,
1396 UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE
,
1397 UNO_NAME_CHAR_STYLE_NAME
,
1398 UNO_NAME_NUMBERING_LEVEL
,
1399 UNO_NAME_SORTED_TEXT_ID
,
1401 UNO_NAME_CHAR_COLOR_THEME
,
1402 UNO_NAME_CHAR_COLOR_TINT_OR_SHADE
};
1404 SfxItemPropertySet
const& rPropSet(
1405 *aSwMapProvider
.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE
));
1406 SfxItemPropertyMap
const& rMap(rPropSet
.getPropertyMap());
1409 uno::Reference
<beans::XPropertyState
> xPropertiesState(xRange
, uno::UNO_QUERY_THROW
);
1410 const uno::Sequence
<beans::Property
> aProperties
1411 = xPropertiesSet
->getPropertySetInfo()->getProperties();
1413 for (const beans::Property
& rProperty
: aProperties
)
1415 const OUString
& rPropName
= rProperty
.Name
;
1417 if (!rMap
.hasPropertyByName(rPropName
))
1420 if (std::find(aHiddenProperties
.begin(), aHiddenProperties
.end(), rPropName
)
1421 != aHiddenProperties
.end())
1424 if (xPropertiesState
->getPropertyState(rPropName
) == beans::PropertyState_DIRECT_VALUE
)
1426 const uno::Any aAny
= xPropertiesSet
->getPropertyValue(rPropName
);
1427 if (HasValidPropertyValue(aAny
))
1429 sCSNumberOrDF
= SwResId(STR_CHARACTER_DIRECT_FORMATTING_TAG
);
1430 aFillColor
= COL_LIGHTGRAY
;
1438 OutputDevice
* pTmpOut
= const_cast<OutputDevice
*>(GetOut());
1439 pTmpOut
->Push(vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
1440 | vcl::PushFlags::TEXTLAYOUTMODE
| vcl::PushFlags::FONT
);
1442 // draw a filled rectangle at the formatted CS or DF text
1443 pTmpOut
->SetFillColor(aFillColor
.value());
1444 pTmpOut
->SetLineColor(aFillColor
.value());
1445 tools::Rectangle
aSVRect(aRect
.SVRect());
1446 pTmpOut
->DrawRect(aSVRect
);
1448 // calculate size and position for the CS number or "df" text and rectangle
1449 tools::Long nWidth
= pTmpOut
->GetTextWidth(sCSNumberOrDF
.value());
1450 tools::Long nHeight
= pTmpOut
->GetTextHeight();
1451 aSVRect
.SetSize(Size(nWidth
, nHeight
));
1452 aSVRect
.Move(-(nWidth
/ 1.5), -(nHeight
/ 1.5));
1454 vcl::Font
aFont(pTmpOut
->GetFont());
1455 aFont
.SetOrientation(Degree10(0));
1456 pTmpOut
->SetFont(aFont
);
1458 pTmpOut
->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::TextOriginLeft
);
1459 //pTmpOut->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::BiDiStrong);
1461 pTmpOut
->SetTextFillColor(aFillColor
.value());
1462 pTmpOut
->DrawText(aSVRect
, sCSNumberOrDF
.value(), DrawTextFlags::NONE
);
1468 void SwTextPaintInfo::DrawViewOpt( const SwLinePortion
&rPor
,
1469 PortionType nWhich
, const Color
*pColor
) const
1471 if( !OnWin() || IsMulti() )
1477 case PortionType::Footnote
:
1478 case PortionType::QuoVadis
:
1479 case PortionType::Number
:
1480 case PortionType::Field
:
1481 case PortionType::Hidden
:
1482 case PortionType::Tox
:
1483 case PortionType::Ref
:
1484 case PortionType::Meta
:
1485 case PortionType::ContentControl
:
1486 case PortionType::ControlChar
:
1487 if ( !GetOpt().IsPagePreview()
1488 && !GetOpt().IsReadonly()
1489 && GetOpt().IsFieldShadings()
1490 && ( PortionType::Number
!= nWhich
1491 || m_pFrame
->GetTextNodeForParaProps()->HasMarkedLabel())) // #i27615#
1493 bDraw
= PortionType::Footnote
!= nWhich
|| m_pFrame
->IsFootnoteAllowed();
1496 case PortionType::Bookmark
:
1499 case PortionType::InputField
:
1500 // input field shading also in read-only mode
1501 if ( !GetOpt().IsPagePreview()
1502 && GetOpt().IsFieldShadings() )
1507 case PortionType::Tab
:
1508 if ( GetOpt().IsTab() ) bDraw
= true;
1510 case PortionType::SoftHyphen
:
1511 if ( GetOpt().IsSoftHyph() )bDraw
= true;
1513 case PortionType::Blank
:
1514 if ( GetOpt().IsHardBlank())bDraw
= true;
1518 OSL_ENSURE( false, "SwTextPaintInfo::DrawViewOpt: don't know how to draw this" );
1523 DrawBackground( rPor
, pColor
);
1526 static void lcl_InitHyphValues( PropertyValues
&rVals
,
1527 sal_Int16 nMinLeading
, sal_Int16 nMinTrailing
,
1528 bool bNoCapsHyphenation
, bool bNoLastWordHyphenation
,
1529 sal_Int16 nMinWordLength
, sal_Int16 nTextHyphZone
)
1531 sal_Int32 nLen
= rVals
.getLength();
1533 if (0 == nLen
) // yet to be initialized?
1536 PropertyValue
*pVal
= rVals
.getArray();
1538 pVal
[0].Name
= UPN_HYPH_MIN_LEADING
;
1539 pVal
[0].Handle
= UPH_HYPH_MIN_LEADING
;
1540 pVal
[0].Value
<<= nMinLeading
;
1542 pVal
[1].Name
= UPN_HYPH_MIN_TRAILING
;
1543 pVal
[1].Handle
= UPH_HYPH_MIN_TRAILING
;
1544 pVal
[1].Value
<<= nMinTrailing
;
1546 pVal
[2].Name
= UPN_HYPH_NO_CAPS
;
1547 pVal
[2].Handle
= UPH_HYPH_NO_CAPS
;
1548 pVal
[2].Value
<<= bNoCapsHyphenation
;
1550 pVal
[3].Name
= UPN_HYPH_NO_LAST_WORD
;
1551 pVal
[3].Handle
= UPH_HYPH_NO_LAST_WORD
;
1552 pVal
[3].Value
<<= bNoLastWordHyphenation
;
1554 pVal
[4].Name
= UPN_HYPH_MIN_WORD_LENGTH
;
1555 pVal
[4].Handle
= UPH_HYPH_MIN_WORD_LENGTH
;
1556 pVal
[4].Value
<<= nMinWordLength
;
1558 pVal
[5].Name
= UPN_HYPH_ZONE
;
1559 pVal
[5].Handle
= UPH_HYPH_ZONE
;
1560 pVal
[5].Value
<<= nTextHyphZone
;
1562 else if (6 == nLen
) // already initialized once?
1564 PropertyValue
*pVal
= rVals
.getArray();
1565 pVal
[0].Value
<<= nMinLeading
;
1566 pVal
[1].Value
<<= nMinTrailing
;
1567 pVal
[2].Value
<<= bNoCapsHyphenation
;
1568 pVal
[3].Value
<<= bNoLastWordHyphenation
;
1569 pVal
[4].Value
<<= nMinWordLength
;
1570 pVal
[5].Value
<<= nTextHyphZone
;
1573 OSL_FAIL( "unexpected size of sequence" );
1577 const PropertyValues
& SwTextFormatInfo::GetHyphValues() const
1579 OSL_ENSURE( 6 == m_aHyphVals
.getLength(),
1580 "hyphenation values not yet initialized" );
1584 bool SwTextFormatInfo::InitHyph( const bool bAutoHyphen
)
1586 const SwAttrSet
& rAttrSet
= GetTextFrame()->GetTextNodeForParaProps()->GetSwAttrSet();
1587 SetHanging( rAttrSet
.GetHangingPunctuation().GetValue() );
1588 SetScriptSpace( rAttrSet
.GetScriptSpace().GetValue() );
1589 SetForbiddenChars( rAttrSet
.GetForbiddenRule().GetValue() );
1590 const SvxHyphenZoneItem
&rAttr
= rAttrSet
.GetHyphenZone();
1591 MaxHyph() = rAttr
.GetMaxHyphens();
1592 const bool bAuto
= bAutoHyphen
|| rAttr
.IsHyphen();
1593 if( bAuto
|| m_bInterHyph
)
1595 const sal_Int16 nMinimalLeading
= std::max(rAttr
.GetMinLead(), sal_uInt8(2));
1596 const sal_Int16 nMinimalTrailing
= rAttr
.GetMinTrail();
1597 const sal_Int16 nMinimalWordLength
= rAttr
.GetMinWordLength();
1598 const bool bNoCapsHyphenation
= rAttr
.IsNoCapsHyphenation();
1599 const bool bNoLastWordHyphenation
= rAttr
.IsNoLastWordHyphenation();
1600 const sal_Int16 nTextHyphZone
= rAttr
.GetTextHyphenZone();
1601 lcl_InitHyphValues( m_aHyphVals
, nMinimalLeading
, nMinimalTrailing
,
1602 bNoCapsHyphenation
, bNoLastWordHyphenation
,
1603 nMinimalWordLength
, nTextHyphZone
);
1608 void SwTextFormatInfo::CtorInitTextFormatInfo( OutputDevice
* pRenderContext
, SwTextFrame
*pNewFrame
, const bool bNewInterHyph
,
1609 const bool bNewQuick
, const bool bTst
)
1611 CtorInitTextPaintInfo( pRenderContext
, pNewFrame
, SwRect() );
1613 m_bQuick
= bNewQuick
;
1614 m_bInterHyph
= bNewInterHyph
;
1616 //! needs to be done in this order
1617 m_bAutoHyph
= InitHyph();
1619 m_bIgnoreFly
= false;
1620 m_bFakeLineStart
= false;
1622 m_bDropInit
= false;
1623 m_bTestFormat
= bTst
;
1628 m_nForcedLeftMargin
= 0;
1631 m_nLineNetHeight
= 0;
1632 SetLineStart(TextFrameIndex(0));
1634 SvtCTLOptions::TextNumerals
const nTextNumerals(
1635 SvtCTLOptions::GetCTLTextNumerals());
1636 // cannot cache for NUMERALS_CONTEXT because we need to know the string
1637 // for the whole paragraph now
1638 if (nTextNumerals
!= SvtCTLOptions::NUMERALS_CONTEXT
)
1640 // set digit mode to what will be used later to get same results
1641 SwDigitModeModifier
const m(*m_pRef
, LANGUAGE_NONE
/*dummy*/);
1642 assert(m_pRef
->GetDigitLanguage() != LANGUAGE_NONE
);
1643 SetCachedVclData(OutputDevice::CreateTextLayoutCache(*m_pText
));
1650 * If the Hyphenator returns ERROR or the language is set to NOLANGUAGE
1651 * we do not hyphenate.
1652 * Else, we always hyphenate if we do interactive hyphenation.
1653 * If we do not do interactive hyphenation, we only hyphenate if ParaFormat is
1654 * set to automatic hyphenation.
1656 bool SwTextFormatInfo::IsHyphenate() const
1658 if( !m_bInterHyph
&& !m_bAutoHyph
)
1661 LanguageType eTmp
= GetFont()->GetLanguage();
1662 // TODO: check for more ideographic langs w/o hyphenation as a concept
1663 if ( LANGUAGE_DONTKNOW
== eTmp
|| LANGUAGE_NONE
== eTmp
1664 || !MsLangId::usesHyphenation(eTmp
) )
1667 uno::Reference
< XHyphenator
> xHyph
= ::GetHyphenator();
1672 SvxSpellWrapper::CheckHyphLang( xHyph
, eTmp
);
1674 if (!xHyph
->hasLocale(g_pBreakIt
->GetLocale(eTmp
)))
1676 SfxObjectShell
* pShell
= m_pFrame
->GetDoc().GetDocShell();
1679 pShell
->AppendInfoBarWhenReady(
1680 "hyphenationmissing", SwResId(STR_HYPH_MISSING
),
1681 SwResId(STR_HYPH_MISSING_DETAIL
)
1682 .replaceFirst("%1", LanguageTag::convertToBcp47( g_pBreakIt
->GetLocale(eTmp
))),
1683 InfobarType::WARNING
);
1687 return xHyph
->hasLocale( g_pBreakIt
->GetLocale(eTmp
) );
1690 const SwFormatDrop
*SwTextFormatInfo::GetDropFormat() const
1692 const SwFormatDrop
*pDrop
= &GetTextFrame()->GetTextNodeForParaProps()->GetSwAttrSet().GetDrop();
1693 if( 1 >= pDrop
->GetLines() ||
1694 ( !pDrop
->GetChars() && !pDrop
->GetWholeWord() ) )
1699 void SwTextFormatInfo::Init()
1701 // Not initialized: pRest, nLeft, nRight, nFirst, nRealWidth
1703 m_bArrowDone
= m_bFull
= m_bFootnoteDone
= m_bErgoDone
= m_bNumDone
= m_bNoEndHyph
=
1704 m_bNoMidHyph
= m_bStop
= m_bNewLine
= m_bUnderflow
= m_bTabOverflow
= false;
1706 // generally we do not allow number portions in follows, except...
1707 if ( GetTextFrame()->IsFollow() )
1709 const SwTextFrame
* pMaster
= GetTextFrame()->FindMaster();
1710 OSL_ENSURE(pMaster
, "pTextFrame without Master");
1711 const SwLinePortion
* pTmpPara
= pMaster
? pMaster
->GetPara() : nullptr;
1713 // there is a master for this follow and the master does not have
1714 // any contents (especially it does not have a number portion)
1715 m_bNumDone
= ! pTmpPara
||
1716 ! static_cast<const SwParaPortion
*>(pTmpPara
)->GetFirstPortion()->IsFlyPortion();
1722 m_pLastTab
= nullptr;
1723 m_pUnderflow
= nullptr;
1725 m_nWidth
= m_nRealWidth
;
1726 m_nForcedLeftMargin
= 0;
1727 m_nSoftHyphPos
= TextFrameIndex(0);
1728 m_nUnderScorePos
= TextFrameIndex(COMPLETE_STRING
);
1729 m_nLastBookmarkPos
= TextFrameIndex(-1);
1731 SetIdx(TextFrameIndex(0));
1732 SetLen(TextFrameIndex(GetText().getLength()));
1736 SwTextFormatInfo::SwTextFormatInfo(OutputDevice
* pRenderContext
, SwTextFrame
*pFrame
, const bool bInterHyphL
,
1737 const bool bQuickL
, const bool bTst
)
1739 CtorInitTextFormatInfo(pRenderContext
, pFrame
, bInterHyphL
, bQuickL
, bTst
);
1743 * There are a few differences between a copy constructor
1744 * and the following constructor for multi-line formatting.
1745 * The root is the first line inside the multi-portion,
1746 * the line start is the actual position in the text,
1747 * the line width is the rest width from the surrounding line
1748 * and the bMulti and bFirstMulti-flag has to be set correctly.
1750 SwTextFormatInfo::SwTextFormatInfo( const SwTextFormatInfo
& rInf
,
1751 SwLineLayout
& rLay
, SwTwips nActWidth
) :
1752 SwTextPaintInfo( rInf
),
1756 m_pUnderflow(nullptr),
1758 m_pLastTab(nullptr),
1759 m_nSoftHyphPos(TextFrameIndex(0)),
1760 m_nLineStart(rInf
.GetIdx()),
1761 m_nUnderScorePos(TextFrameIndex(COMPLETE_STRING
)),
1762 m_nLeft(rInf
.m_nLeft
),
1763 m_nRight(rInf
.m_nRight
),
1764 m_nFirst(rInf
.m_nLeft
),
1765 m_nRealWidth(sal_uInt16(nActWidth
)),
1766 m_nWidth(m_nRealWidth
),
1768 m_nLineNetHeight(0),
1769 m_nForcedLeftMargin(0),
1771 m_bFootnoteDone(true),
1778 m_bUnderflow(false),
1779 m_bInterHyph(false),
1782 m_bQuick(rInf
.m_bQuick
),
1783 m_bNoEndHyph(false),
1784 m_bNoMidHyph(false),
1785 m_bIgnoreFly(false),
1786 m_bFakeLineStart(false),
1787 m_bTabOverflow( false ),
1788 m_bTestFormat(rInf
.m_bTestFormat
),
1794 SetFirstMulti( rInf
.IsFirstMulti() );
1797 bool SwTextFormatInfo::CheckFootnotePortion_( SwLineLayout
const * pCurr
)
1799 const sal_uInt16 nHeight
= pCurr
->GetRealHeight();
1800 for( SwLinePortion
*pPor
= pCurr
->GetNextPortion(); pPor
; pPor
= pPor
->GetNextPortion() )
1802 if( pPor
->IsFootnotePortion() && nHeight
> static_cast<SwFootnotePortion
*>(pPor
)->Orig() )
1804 SetLineHeight( nHeight
);
1805 SetLineNetHeight( pCurr
->Height() );
1812 TextFrameIndex
SwTextFormatInfo::ScanPortionEnd(TextFrameIndex
const nStart
,
1813 TextFrameIndex
const nEnd
)
1816 TextFrameIndex i
= nStart
;
1818 // Used for decimal tab handling:
1819 const sal_Unicode cTabDec
= GetLastTab() ? GetTabDecimal() : 0;
1820 const sal_Unicode cThousandSep
= ',' == cTabDec
? '.' : ',';
1822 // #i45951# German (Switzerland) uses ' as thousand separator
1823 const sal_Unicode cThousandSep2
= ',' == cTabDec
? '.' : '\'';
1825 bool bNumFound
= false;
1826 const bool bTabCompat
= GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT
);
1828 for( ; i
< nEnd
; ++i
)
1830 const sal_Unicode cPos
= GetChar( i
);
1833 case CH_TXTATR_BREAKWORD
:
1834 case CH_TXTATR_INWORD
:
1839 case CHAR_SOFTHYPHEN
:
1840 case CHAR_HARDHYPHEN
:
1841 case CHAR_HARDBLANK
:
1849 case CHAR_UNDERSCORE
:
1850 if (TextFrameIndex(COMPLETE_STRING
) == m_nUnderScorePos
)
1851 m_nUnderScorePos
= i
;
1857 if( cTabDec
== cPos
)
1859 OSL_ENSURE( cPos
, "Unexpected end of string" );
1860 if( cPos
) // robust
1867 // Compatibility: First non-digit character behind a
1868 // a digit character becomes the hook character
1871 if ( ( 0x2F < cPos
&& cPos
< 0x3A ) ||
1872 ( bNumFound
&& ( cPos
== cThousandSep
|| cPos
== cThousandSep2
) ) )
1881 SetTabDecimal( cPos
);
1890 // Check if character *behind* the portion has
1891 // to become the hook:
1892 if (i
== nEnd
&& i
< TextFrameIndex(GetText().getLength()) && bNumFound
)
1894 const sal_Unicode cPos
= GetChar( i
);
1895 if ( cPos
!= cTabDec
&& cPos
!= cThousandSep
&& cPos
!=cThousandSep2
&& ( 0x2F >= cPos
|| cPos
>= 0x3A ) )
1897 m_cHookChar
= GetChar( i
);
1898 SetTabDecimal( m_cHookChar
);
1905 bool SwTextFormatInfo::LastKernPortion()
1909 if( GetLast()->IsKernPortion() )
1911 if( GetLast()->Width() || ( GetLast()->GetLen() &&
1912 !GetLast()->IsHolePortion() ) )
1915 SwLinePortion
* pPor
= GetRoot();
1916 SwLinePortion
*pKern
= nullptr;
1919 if( pPor
->IsKernPortion() )
1921 else if( pPor
->Width() || ( pPor
->GetLen() && !pPor
->IsHolePortion() ) )
1923 pPor
= pPor
->GetNextPortion();
1933 SwTwips
SwTextFormatInfo::GetLineWidth()
1935 SwTwips nLineWidth
= Width() - X();
1937 const bool bTabOverMargin
= GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
1938 DocumentSettingId::TAB_OVER_MARGIN
);
1939 const bool bTabOverSpacing
= GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
1940 DocumentSettingId::TAB_OVER_SPACING
);
1941 if (!bTabOverMargin
&& !bTabOverSpacing
)
1944 SwTabPortion
* pLastTab
= GetLastTab();
1948 // Consider tab portions over the printing bounds of the text frame.
1949 if (pLastTab
->GetTabPos() <= Width())
1952 // Calculate the width that starts at the left (or in case of first line:
1953 // first) margin, but ends after the right paragraph margin:
1955 // +--------------------+
1957 // +--------------------+
1958 // ^ m_nLeftMargin (absolute)
1959 // ^ nLeftMarginWidth (relative to m_nLeftMargin), X() is relative to this
1961 // ^ paragraph right
1962 // <--------------------> is GetTextFrame()->getFrameArea().Width()
1963 // <--------------> is Width()
1964 // <-----------------> is what we need to be able to compare to X() (nTextFrameWidth)
1965 SwTwips nLeftMarginWidth
= m_nLeftMargin
- GetTextFrame()->getFrameArea().Left();
1966 SwTwips nTextFrameWidth
= GetTextFrame()->getFrameArea().Width() - nLeftMarginWidth
;
1968 // If there is one such tab portion, then text is allowed to use the full
1969 // text frame area to the right (RR above, but not LL).
1970 nLineWidth
= nTextFrameWidth
- X();
1972 if (!bTabOverMargin
) // thus bTabOverSpacing only
1974 // right, center, decimal can back-fill all the available space - same as TabOverMargin
1975 if (pLastTab
->GetWhichPor() == PortionType::TabLeft
)
1976 nLineWidth
= nTextFrameWidth
- pLastTab
->GetTabPos();
1981 SwTextSlot::SwTextSlot(
1982 const SwTextSizeInfo
*pNew
,
1983 const SwLinePortion
*pPor
,
1986 OUString
const & rCh
)
1988 , m_pOldSmartTagList(nullptr)
1989 , m_pOldGrammarCheckList(nullptr)
1997 bOn
= pPor
->GetExpText( *pNew
, aText
);
2005 // The text is replaced ...
2009 pInf
= const_cast<SwTextSizeInfo
*>(pNew
);
2010 nIdx
= pInf
->GetIdx();
2011 nLen
= pInf
->GetLen();
2012 nMeasureLen
= pInf
->GetMeasureLen();
2013 pOldText
= &(pInf
->GetText());
2014 m_pOldCachedVclData
= pInf
->GetCachedVclData();
2015 pInf
->SetText( aText
);
2016 pInf
->SetIdx(TextFrameIndex(0));
2017 pInf
->SetLen(bTextLen
? TextFrameIndex(pInf
->GetText().getLength()) : pPor
->GetLen());
2018 if (nMeasureLen
!= TextFrameIndex(COMPLETE_STRING
))
2019 pInf
->SetMeasureLen(TextFrameIndex(COMPLETE_STRING
));
2021 pInf
->SetCachedVclData(nullptr);
2027 m_pOldSmartTagList
= static_cast<SwTextPaintInfo
*>(pInf
)->GetSmartTags();
2028 if (m_pOldSmartTagList
)
2030 std::pair
<SwTextNode
const*, sal_Int32
> pos(pNew
->GetTextFrame()->MapViewToModel(nIdx
));
2031 SwWrongList
const*const pSmartTags(pos
.first
->GetSmartTags());
2034 const sal_uInt16 nPos
= pSmartTags
->GetWrongPos(pos
.second
);
2035 const sal_Int32 nListPos
= pSmartTags
->Pos(nPos
);
2036 if (nListPos
== pos
.second
&& pSmartTags
->SubList(nPos
) != nullptr)
2038 m_pTempIter
.reset(new sw::WrongListIterator(*pSmartTags
->SubList(nPos
)));
2039 static_cast<SwTextPaintInfo
*>(pInf
)->SetSmartTags(m_pTempIter
.get());
2041 else if (!m_pTempList
&& nPos
< pSmartTags
->Count()
2042 && nListPos
< pos
.second
&& !aText
.isEmpty())
2044 m_pTempList
.reset(new SwWrongList( WRONGLIST_SMARTTAG
));
2045 m_pTempList
->Insert( OUString(), nullptr, 0, aText
.getLength(), 0 );
2046 m_pTempIter
.reset(new sw::WrongListIterator(*m_pTempList
));
2047 static_cast<SwTextPaintInfo
*>(pInf
)->SetSmartTags(m_pTempIter
.get());
2050 static_cast<SwTextPaintInfo
*>(pInf
)->SetSmartTags(nullptr);
2053 static_cast<SwTextPaintInfo
*>(pInf
)->SetSmartTags(nullptr);
2055 m_pOldGrammarCheckList
= static_cast<SwTextPaintInfo
*>(pInf
)->GetGrammarCheckList();
2056 if (!m_pOldGrammarCheckList
)
2059 std::pair
<SwTextNode
const*, sal_Int32
> pos(pNew
->GetTextFrame()->MapViewToModel(nIdx
));
2060 SwWrongList
const*const pGrammar(pos
.first
->GetGrammarCheck());
2063 const sal_uInt16 nPos
= pGrammar
->GetWrongPos(pos
.second
);
2064 const sal_Int32 nListPos
= pGrammar
->Pos(nPos
);
2065 if (nListPos
== pos
.second
&& pGrammar
->SubList(nPos
) != nullptr)
2067 m_pTempIter
.reset(new sw::WrongListIterator(*pGrammar
->SubList(nPos
)));
2068 static_cast<SwTextPaintInfo
*>(pInf
)->SetGrammarCheckList(m_pTempIter
.get());
2070 else if (!m_pTempList
&& nPos
< pGrammar
->Count()
2071 && nListPos
< pos
.second
&& !aText
.isEmpty())
2073 m_pTempList
.reset(new SwWrongList( WRONGLIST_GRAMMAR
));
2074 m_pTempList
->Insert( OUString(), nullptr, 0, aText
.getLength(), 0 );
2075 m_pTempIter
.reset(new sw::WrongListIterator(*m_pTempList
));
2076 static_cast<SwTextPaintInfo
*>(pInf
)->SetGrammarCheckList(m_pTempIter
.get());
2079 static_cast<SwTextPaintInfo
*>(pInf
)->SetGrammarCheckList(nullptr);
2082 static_cast<SwTextPaintInfo
*>(pInf
)->SetGrammarCheckList(nullptr);
2085 SwTextSlot::~SwTextSlot()
2090 pInf
->SetCachedVclData(m_pOldCachedVclData
);
2091 pInf
->SetText( *pOldText
);
2092 pInf
->SetIdx( nIdx
);
2093 pInf
->SetLen( nLen
);
2094 pInf
->SetMeasureLen( nMeasureLen
);
2097 // Restore old smart tag list
2098 if (m_pOldSmartTagList
)
2099 static_cast<SwTextPaintInfo
*>(pInf
)->SetSmartTags(m_pOldSmartTagList
);
2100 if (m_pOldGrammarCheckList
)
2101 static_cast<SwTextPaintInfo
*>(pInf
)->SetGrammarCheckList(m_pOldGrammarCheckList
);
2104 SwFontSave::SwFontSave(const SwTextSizeInfo
&rInf
, SwFont
*pNew
,
2107 , pFnt(pNew
? const_cast<SwTextSizeInfo
&>(rInf
).GetFont() : nullptr)
2113 pInf
= &const_cast<SwTextSizeInfo
&>(rInf
);
2114 // In these cases we temporarily switch to the new font:
2115 // 1. the fonts have a different magic number
2116 // 2. they have different script types
2117 // 3. their background colors differ (this is not covered by 1.)
2118 if( pFnt
->DifferentFontCacheId( pNew
, pFnt
->GetActual() ) ||
2119 pNew
->GetActual() != pFnt
->GetActual() ||
2120 ( ! pNew
->GetBackColor() && pFnt
->GetBackColor() ) ||
2121 ( pNew
->GetBackColor() && ! pFnt
->GetBackColor() ) ||
2122 ( pNew
->GetBackColor() && pFnt
->GetBackColor() &&
2123 ( *pNew
->GetBackColor() != *pFnt
->GetBackColor() ) ) )
2125 pNew
->SetTransparent( true );
2126 pNew
->SetAlign( ALIGN_BASELINE
);
2127 pInf
->SetFont( pNew
);
2132 pNew
->ChgPhysFnt( pInf
->GetVsh(), *pInf
->GetOut() );
2133 if( pItr
&& pItr
->GetFnt() == pFnt
)
2136 pIter
->SetFnt( pNew
);
2140 SwFontSave::~SwFontSave()
2146 pInf
->SetFont( pFnt
);
2149 pIter
->SetFnt( pFnt
);
2150 pIter
->m_nPosition
= COMPLETE_STRING
;
2155 bool SwTextFormatInfo::ChgHyph( const bool bNew
)
2157 const bool bOld
= m_bAutoHyph
;
2158 if( m_bAutoHyph
!= bNew
)
2162 // Set language in the Hyphenator
2164 m_pFnt
->ChgPhysFnt( m_pVsh
, *m_pOut
);
2170 bool SwTextFormatInfo::CheckCurrentPosBookmark()
2172 if (m_nLastBookmarkPos
!= GetIdx())
2174 m_nLastBookmarkPos
= GetIdx();
2183 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */