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 .
19 #ifndef INCLUDED_SW_SOURCE_CORE_INC_TXTFRM_HXX
20 #define INCLUDED_SW_SOURCE_CORE_INC_TXTFRM_HXX
22 #include <com/sun/star/uno/Sequence.hxx>
24 #include "TextFrameIndex.hxx"
25 #include <nodeoffset.hxx>
32 namespace com::sun::star::linguistic2
{ class XHyphenatedWord
; }
34 namespace sw::mark
{ class IMark
; }
38 class SwTextFormatter
;
39 class SwTextFormatInfo
;
41 class WidowsAndOrphans
;
43 class SwInterHyphInfo
; // Hyphenate()
47 struct SwCursorMoveState
;
49 class SwPortionHandler
;
51 enum class ExpandMode
;
55 class SwFlyAtContentFrame
;
57 #define NON_PRINTING_CHARACTER_COLOR Color(0x26, 0x8b, 0xd2)
59 /// a clone of SwInterHyphInfo, but with TextFrameIndex instead of node index
60 class SwInterHyphInfoTextFrame
63 /// output: hyphenated word
64 css::uno::Reference
<css::linguistic2::XHyphenatedWord
> m_xHyphWord
;
66 /// input: requested range to hyphenate
67 TextFrameIndex m_nStart
;
68 TextFrameIndex m_nEnd
;
69 /// output: found word
70 TextFrameIndex m_nWordStart
;
71 TextFrameIndex m_nWordLen
;
73 SwInterHyphInfoTextFrame(SwTextFrame
const& rFrame
,
74 SwTextNode
const& rNode
, SwInterHyphInfo
const& rHyphInfo
);
75 void UpdateTextNodeHyphInfo(SwTextFrame
const& rFrame
,
76 SwTextNode
const& rNode
, SwInterHyphInfo
& o_rHyphInfo
);
78 void SetHyphWord(const css::uno::Reference
<css::linguistic2::XHyphenatedWord
> &xHW
)
87 * Describes a part of a single text node, which will be part of a text frame,
88 * even when redlines are hidden at a layout level.
92 SwTextNode
* /*const logically, but need assignment for std::vector*/ pNode
;
95 Extent(SwTextNode
*const p
, sal_Int32
const s
, sal_Int32
const e
)
96 : pNode(p
), nStart(s
), nEnd(e
)
99 assert(nStart
!= nEnd
);
106 std::pair
<SwTextNode
*, sal_Int32
> MapViewToModel(MergedPara
const&, TextFrameIndex nIndex
);
107 TextFrameIndex
MapModelToView(MergedPara
const&, SwTextNode
const* pNode
, sal_Int32 nIndex
);
109 // warning: Existing must be used only once; a second use would delete the frame created by the first one...
110 enum class FrameMode
{ New
, Existing
};
111 std::unique_ptr
<sw::MergedPara
> CheckParaRedlineMerge(SwTextFrame
& rFrame
, SwTextNode
& rTextNode
, FrameMode eMode
);
112 SwTextFrame
* MakeTextFrame(SwTextNode
& rNode
, SwFrame
*, sw::FrameMode eMode
);
114 bool FrameContainsNode(SwContentFrame
const& rFrame
, SwNodeOffset nNodeIndex
);
115 bool IsParaPropsNode(SwRootFrame
const& rLayout
, SwTextNode
const& rNode
);
116 SwTextNode
* GetParaPropsNode(SwRootFrame
const& rLayout
, SwNode
const& rNode
);
117 SwPosition
GetParaPropsPos(SwRootFrame
const& rLayout
, SwPosition
const& rPos
);
118 std::pair
<SwTextNode
*, SwTextNode
*>
119 GetFirstAndLastNode(SwRootFrame
const& rLayout
, SwNode
const& rPos
);
121 SwTextNode
const& GetAttrMerged(SfxItemSet
& rFormatSet
,
122 SwTextNode
const& rNode
, SwRootFrame
const* pLayout
);
124 void GotoPrevLayoutTextFrame(SwNodeIndex
& rIndex
, SwRootFrame
const* pLayout
);
125 void GotoNextLayoutTextFrame(SwNodeIndex
& rIndex
, SwRootFrame
const* pLayout
);
127 TextFrameIndex
UpdateMergedParaForDelete(MergedPara
& rMerged
,
129 SwTextNode
const& rNode
, sal_Int32 nIndex
, sal_Int32 nLen
);
131 void MoveMergedFlysAndFootnotes(std::vector
<SwTextFrame
*> const& rFrames
,
132 SwTextNode
const& rFirstNode
, SwTextNode
& rSecondNode
, bool);
134 void MoveDeletedPrevFrames(const SwTextNode
& rDeletedPrev
, SwTextNode
& rNode
);
135 enum class Recreate
{ No
, ThisNode
, Predecessor
};
136 void CheckResetRedlineMergeFlag(SwTextNode
& rNode
, Recreate eRecreateMerged
);
138 void UpdateFramesForAddDeleteRedline(SwDoc
& rDoc
, SwPaM
const& rPam
);
139 void UpdateFramesForRemoveDeleteRedline(SwDoc
& rDoc
, SwPaM
const& rPam
);
141 void AddRemoveFlysAnchoredToFrameStartingAtNode(
142 SwTextFrame
& rFrame
, SwTextNode
& rTextNode
,
143 std::set
<SwNodeOffset
> *pSkipped
);
145 OUString
GetExpandTextMerged(SwRootFrame
const* pLayout
,
146 SwTextNode
const& rNode
, bool bWithNumber
,
147 bool bWithSpacesForLevel
, ExpandMode i_mode
);
149 bool IsMarkHidden(SwRootFrame
const& rLayout
, ::sw::mark::IMark
const& rMark
);
150 bool IsMarkHintHidden(SwRootFrame
const& rLayout
,
151 SwTextNode
const& rNode
, SwTextAttrEnd
const& rHint
);
153 void RecreateStartTextFrames(SwTextNode
& rNode
);
155 sw::InsertText
MakeInsertText(SwTextNode
& rNode
, const sal_Int32 nPos
, const sal_Int32 nLen
);
158 * Decides if rTextNode has a numbering which has layout-level values (e.g. Arabic, but not
161 bool HasNumberingWhichNeedsLayoutUpdate(const SwTextNode
& rTextNode
);
165 /// Represents the visualization of a paragraph. Typical upper is an
166 /// SwBodyFrame. The first text portion of the first line is az SwParaPortion.
167 class SW_DLLPUBLIC SwTextFrame final
: public SwContentFrame
169 friend class SwTextIter
;
170 friend class SwTestFormat
;
171 friend class WidowsAndOrphans
;
172 friend class TextFrameLockGuard
; // May Lock()/Unlock()
173 friend bool sw_ChangeOffset(SwTextFrame
* pFrame
, TextFrameIndex nNew
);
175 /// SwLineLayout cache: the lines are not actually owned by the SwTextFrame
176 /// but by this SwCache, so they will be deleted in large documents
177 /// if there are too many of them, but the "valid" flags of the frame
178 /// will still be set; GetFormatted() is the function that forces
179 /// recreation of the SwLineLayout by Format() if necessary.
180 static SwCache
*s_pTextCache
;
181 static constexpr tools::Long nMinPrtLine
= 0; // This Line must not be underrun when printing
182 // Hack for table cells stretching multiple pages
184 sal_Int32 mnAllLines
:24; // Line count for the Paint (including nThisLines)
185 sal_Int32 mnThisLines
:8; // Count of Lines of the Frame
187 // The x position for flys anchored at this paragraph.
188 // These values are calculated in SwTextFrame::CalcBaseOfstForFly()
189 SwTwips mnFlyAnchorOfst
;
190 // The x position for wrap-through flys anchored at this paragraph.
191 SwTwips mnFlyAnchorOfstNoWrap
;
192 /// The y position for wrap-through flys anchored at this paragraph.
193 SwTwips mnFlyAnchorVertOfstNoWrap
;
194 SwTwips mnFootnoteLine
;
195 // OD 2004-03-17 #i11860# - re-factoring of #i11859#
196 // member for height of last line (value needed for proportional line spacing)
197 SwTwips mnHeightOfLastLine
;
198 // member for the additional first line offset, which is caused by the list
199 // label alignment for list level position and space mode LABEL_ALIGNMENT.
200 // This additional first line offset is used for the text formatting.
201 // It is NOT used for the determination of printing area.
202 SwTwips mnAdditionalFirstLineOffset
;
204 /// redline merge data
205 std::unique_ptr
<sw::MergedPara
> m_pMergedPara
;
207 TextFrameIndex mnOffset
; // Is the offset in the Content (character count)
209 sal_uInt16 mnCacheIndex
; // Index into the cache, USHRT_MAX if there's definitely no fitting object in the cache
211 // Separates the Master and creates a Follow or adjusts the data in the Follow
212 void AdjustFollow_( SwTextFormatter
&rLine
, TextFrameIndex nOffset
,
213 TextFrameIndex nStrEnd
, const sal_uInt8 nMode
);
215 // Iterates all Lines and sets the line spacing using the attribute
216 void CalcLineSpace();
218 // Only called in Format
219 void AdjustFrame( const SwTwips nChgHeight
, bool bHasToFit
= false );
221 // Evaluates the Preps in Format()
223 void PrepWidows( const sal_uInt16 nNeed
, bool bNotify
);
224 void InvalidateRange_( const SwCharRange
&, const tools::Long
= 0);
225 inline void InvalidateRange( const SwCharRange
&, const tools::Long
= 0);
227 // WidowsAndOrphans, AdjustFrame, AdjustFollow
228 void FormatAdjust( SwTextFormatter
&rLine
, WidowsAndOrphans
&rFrameBreak
,
229 TextFrameIndex nStrLen
, const bool bDummy
);
230 void ChangeOffset( SwTextFrame
* pFrame
, TextFrameIndex nNew
);
232 bool mbLocked
: 1; // In the Format?
233 bool mbWidow
: 1; // Is our follow a Widow?
234 bool mbJustWidow
: 1; // Did we just request Widow flag on master?
235 bool mbEmpty
: 1; // Are we an empty paragraph?
236 bool mbInFootnoteConnect
: 1; // Is in Connect at the moment
237 bool mbFootnote
: 1; // Has at least one footnote
238 bool mbRepaint
: 1; // TextFrame: Repaint is ready to be fetched
239 /// Contains rotated portions.
240 bool mbHasRotatedPortions
: 1;
241 bool mbFieldFollow
: 1; // Start with Field rest of the Master
242 bool mbHasAnimation
: 1; // Contains animated SwGrfNumPortion
243 bool mbIsSwapped
: 1; // during text formatting we swap the
244 // width and height for vertical formatting
245 // OD 14.03.2003 #i11760# - flag to control, if follow is formatted in
246 // method <CalcFollow(..)>.
247 // E.g., avoid formatting of follow, if method <SwLayoutFrame::FormatWidthCols(..)>
249 bool mbFollowFormatAllowed
: 1;
252 void Lock() { mbLocked
= true; }
253 void Unlock() { mbLocked
= false; }
254 void SetWidow( const bool bNew
) { mbWidow
= bNew
; }
255 void SetJustWidow( const bool bNew
) { mbJustWidow
= bNew
; }
256 void SetEmpty( const bool bNew
) { mbEmpty
= bNew
; }
257 void SetFieldFollow( const bool bNew
) { mbFieldFollow
= bNew
; }
259 bool IsIdxInside(TextFrameIndex nPos
, TextFrameIndex nLen
) const;
261 // Changes the Frame or not (cf. FlyCnt)
262 bool GetModelPositionForViewPoint_(SwPosition
*pPos
, const Point
&rPoint
,
263 const bool bChgFrame
, SwCursorMoveState
* = nullptr ) const;
264 void FillCursorPos( SwFillData
&rFill
) const;
266 // Format exactly one Line
267 bool FormatLine( SwTextFormatter
&rLine
, const bool bPrev
);
269 // In order to safe stack space, we split this method:
270 // Format_ calls Format_ with parameters
271 void FormatImpl( vcl::RenderContext
* pRenderContext
, SwParaPortion
*pPara
,
272 ::std::vector
<SwAnchoredObject
*> & rIntersectingObjs
);
273 void Format_( SwTextFormatter
&rLine
, SwTextFormatInfo
&rInf
,
274 const bool bAdjust
= false );
275 void FormatOnceMore( SwTextFormatter
&rLine
, SwTextFormatInfo
&rInf
);
277 // Formats the Follow and ensures disposing on orphans
278 bool CalcFollow(TextFrameIndex nTextOfst
);
280 virtual void MakePos() override
;
282 // Corrects the position from which we need to format
283 static TextFrameIndex
FindBrk(std::u16string_view aText
, TextFrameIndex nStart
,
284 TextFrameIndex nEnd
);
287 SwTwips
GetFootnoteFrameHeight_() const;
289 // Outsourced to CalcPreps
290 bool CalcPrepFootnoteAdjust();
292 // For Footnote and WidOrp: Forced validation
293 void ValidateFrame();
294 void ValidateBodyFrame();
296 bool GetDropRect_( SwRect
&rRect
) const;
298 void SetPara( SwParaPortion
*pNew
, bool bDelete
= true );
300 bool IsFootnoteNumFrame_() const;
302 // Refresh formatting information
303 bool FormatQuick( bool bForceQuickFormat
);
305 // Opt: Format empty paragraphs
307 SwTwips
EmptyHeight() const;
309 // Opt: Paint empty paragraphs
310 bool PaintEmpty( const SwRect
&, bool bCheck
) const;
312 void ChgThisLines(); // Must always be called if the Line count could have changed
314 // required for 'new' relative anchor position
315 void CalcBaseOfstForFly();
317 /** method to determine height of last line, needed for proportional line spacing
319 OD 2004-03-17 #i11860#
320 OD 2005-05-20 #i47162# - introduce new optional parameter <_bUseFont>
321 in order to force the usage of the former algorithm to determine the
322 height of the last line, which uses the font.
325 optional input parameter - boolean indicating, if the font has to be
326 used to determine the height of the last line. default value: false
328 void CalcHeightOfLastLine( const bool _bUseFont
= false );
330 virtual void DestroyImpl() override
;
331 virtual ~SwTextFrame() override
;
333 void UpdateOutlineContentVisibilityButton(SwWrtShell
* pWrtSh
) const;
334 void PaintOutlineContentVisibilityButton() const;
336 void PaintParagraphStylesHighlighting() const;
338 virtual void SwClientNotify(SwModify
const& rModify
, SfxHint
const& rHint
) override
;
340 /// Like GetDrawObjs(), but limit to fly frames which are allowed to split.
341 std::vector
<SwFlyAtContentFrame
*> GetSplitFlyDrawObjs() const;
345 virtual const SvxFormatBreakItem
& GetBreakItem() const override
;
346 virtual const SwFormatPageDesc
& GetPageDescItem() const override
;
348 css::uno::Sequence
< css::style::TabStop
> GetTabStopInfo( SwTwips CurrentPos
) override
;
351 * This is public, as it needs to be called by some methods in order to save the Prepare
356 /// Is called by DoIdleJob_(), ExecSpellPopup() and UpDown()
357 SwRect
AutoSpell_(SwTextNode
&, sal_Int32
);
359 /// Is called by DoIdleJob_()
360 SwRect
SmartTagScan(SwTextNode
&);
362 /// Is called by DoIdleJob_()
363 void CollectAutoCmplWrds(SwTextNode
&, sal_Int32
);
366 * Returns the view rectangle for the rPos model position. The values are relative to the upper
367 * left position of the page frame.
368 * Additional information can be obtained by passing an SwCursorMoveState object.
369 * Returns false if rPos > number of character is string
371 virtual bool GetCharRect( SwRect
& rRect
, const SwPosition
& rPos
,
372 SwCursorMoveState
* pCMS
= nullptr, bool bAllowFarAway
= true ) const override
;
374 /// A slimmer version of GetCharRect for autopositioning Frames
375 bool GetAutoPos( SwRect
&, const SwPosition
& ) const;
378 * Determine top of line for given position in the text frame
380 * OD 11.11.2003 #i22341#
381 * Assumption: given position exists in the text frame or in a follow of it
382 * OD 2004-02-02 - adjustment
383 * Top of first paragraph line is the top of the paragraph.
384 * OD 2004-03-18 #i11860# - Consider upper space amount considered for
385 * previous frame and the page grid.
387 * @param _onTopOfLine
388 * output parameter - top of line, if the given position is found in the
392 * input parameter - reference to the position in the text frame
394 * @return boolean indicating, if the top of line for the given position
395 * has been determined or not.
397 bool GetTopOfLine( SwTwips
& _onTopOfLine
,
398 const SwPosition
& _rPos
) const;
400 virtual bool FillSelection( SwSelectionList
& rList
, const SwRect
& rRect
) const override
;
403 * In nOffset returns the offset of the char within the set
404 * text buffer, which is closest to the position provided by
405 * aPoint within the layout's SSize.
407 * @returns false if the SPoint is outside of the SSize else
410 virtual bool GetModelPositionForViewPoint( SwPosition
*, Point
&,
411 SwCursorMoveState
* = nullptr, bool bTestBackground
= false ) const override
;
414 * Makes sure that the Frame is not switched (e.g. switched for a
415 * character-bound Frame)
417 bool GetKeyCursorOfst(SwPosition
*pPos
, const Point
&rPoint
) const
418 { return GetModelPositionForViewPoint_( pPos
, rPoint
, false ); }
420 void PaintExtraData( const SwRect
& rRect
) const; /// Page number etc.
421 SwRect
GetPaintSwRect();
422 virtual void PaintSwFrame( vcl::RenderContext
& rRenderContext
, SwRect
const&,
423 SwPrintData
const*const pPrintData
= nullptr ) const override
;
424 virtual bool GetInfo( SfxPoolItem
& ) const override
;
427 * Layout oriented cursor travelling:
428 * Left border, right border, previous Line, following Line,
429 * same horizontal position
431 virtual bool LeftMargin(SwPaM
*) const override
;
432 virtual bool RightMargin(SwPaM
*, bool bAPI
= false) const override
;
434 virtual bool UnitUp(SwPaM
*, const SwTwips nOffset
,
435 bool bSetInReadOnly
) const override
;
436 virtual bool UnitDown(SwPaM
*, const SwTwips nOffset
,
437 bool bSetInReadOnly
) const override
;
438 bool UnitUp_(SwPaM
*, const SwTwips nOffset
,
439 bool bSetInReadOnly
) const;
440 bool UnitDown_(SwPaM
*, const SwTwips nOffset
,
441 bool bSetInReadOnly
) const;
444 * Prepares the cursor position for a visual cursor move (BiDi).
445 * The behaviour is different for insert and overwrite cursors
447 void PrepareVisualMove( TextFrameIndex
& nPos
, sal_uInt8
& nCursorLevel
,
448 bool& bRight
, bool bInsertCursor
);
450 /// Methods to manage the FollowFrame
451 void SplitFrame(TextFrameIndex nTextPos
);
452 SwContentFrame
*JoinFrame();
453 TextFrameIndex
GetOffset() const { return mnOffset
; }
454 void SetOffset_(TextFrameIndex nNewOfst
);
455 inline void SetOffset (TextFrameIndex nNewOfst
);
456 void ManipOfst(TextFrameIndex
const nNewOfst
) { mnOffset
= nNewOfst
; }
457 SwTextFrame
*GetFrameAtPos ( const SwPosition
&rPos
);
458 inline const SwTextFrame
*GetFrameAtPos ( const SwPosition
&rPos
) const;
459 SwTextFrame
& GetFrameAtOfst(TextFrameIndex nOfst
);
460 /// If there's a Follow and we don't contain text ourselves
461 bool IsEmptyMaster() const
462 { return GetFollow() && !GetFollow()->GetOffset(); }
464 void SetMergedPara(std::unique_ptr
<sw::MergedPara
> p
);
465 sw::MergedPara
* GetMergedPara() { return m_pMergedPara
.get(); }
466 sw::MergedPara
const* GetMergedPara() const { return m_pMergedPara
.get(); }
468 /// Returns the text portion we want to edit (for inline see underneath)
469 const OUString
& GetText() const;
470 SwTextNode
const* GetTextNodeForParaProps() const;
471 SwTextNode
const* GetTextNodeForFirstText() const;
472 SwTextNode
* GetTextNodeFirst()
473 { return const_cast<SwTextNode
*>(const_cast<SwTextFrame
const*>(this)->GetTextNodeFirst()); };
474 SwTextNode
const* GetTextNodeFirst() const;
476 { return const_cast<SwDoc
&>(const_cast<SwTextFrame
const*>(this)->GetDoc()); }
477 SwDoc
const& GetDoc() const;
479 SwTextFrame(SwTextNode
* const, SwFrame
*, sw::FrameMode eMode
);
482 * SwContentFrame: the shortcut for the Frames
483 * If the void* casts wrongly, it's its own fault!
484 * The void* must be checked for 0 in any case!
486 * return true if the Portion associated with this SwTextFrame was
487 * potentially destroyed and replaced by Prepare
489 virtual bool Prepare( const PrepareHint ePrep
= PrepareHint::Clear
,
490 const void *pVoid
= nullptr, bool bNotify
= true ) override
;
493 * nMaxHeight is the required height
494 * bSplit indicates, that the paragraph has to be split
495 * bTst indicates, that we are currently doing a test formatting
497 virtual bool WouldFit(SwTwips
&nMaxHeight
, bool &bSplit
, bool bTst
, bool bMoveBwd
) override
;
500 * The WouldFit equivalent for temporarily rewired TextFrames
501 * nMaxHeight returns the required size here too and bSplit
502 * determines whether the paragraph needs to be split.
503 * We pass the potential predecessor for the distance calculation
505 bool TestFormat( const SwFrame
* pPrv
, SwTwips
&nMaxHeight
, bool &bSplit
);
508 * We format a Line for interactive hyphenation
511 bool Hyphenate(SwInterHyphInfoTextFrame
& rInf
);
514 inline SwTwips
GrowTst( const SwTwips nGrow
);
516 SwParaPortion
*GetPara();
517 inline const SwParaPortion
*GetPara() const;
518 inline bool HasPara() const;
519 bool HasPara_() const;
521 /// map position in potentially merged text frame to SwPosition
522 std::pair
<SwTextNode
*, sal_Int32
> MapViewToModel(TextFrameIndex nIndex
) const;
523 SwPosition
MapViewToModelPos(TextFrameIndex nIndex
) const;
524 TextFrameIndex
MapModelToView(SwTextNode
const* pNode
, sal_Int32 nIndex
) const;
525 TextFrameIndex
MapModelToViewPos(SwPosition
const& rPos
) const;
527 // If there are any hanging punctuation portions in the margin
528 // the offset will be returned.
529 SwTwips
HangingMargin() const;
531 /// Get the amount of lower margin of this frame we need to consider for fly portion purposes.
532 SwTwips
GetLowerMarginForFlyIntersect() const;
535 bool IsLocked() const { return mbLocked
; }
537 bool IsWidow() const { return mbWidow
; }
538 bool IsJustWidow() const { return mbJustWidow
; }
539 bool IsEmpty() const { return mbEmpty
; }
540 bool HasFootnote() const { return mbFootnote
; }
541 bool IsInFootnoteConnect()const { return mbInFootnoteConnect
;}
542 bool IsFieldFollow() const { return mbFieldFollow
;}
544 inline void SetRepaint() const;
545 inline void ResetRepaint() const;
546 bool HasRepaint() const { return mbRepaint
; }
547 void SetHasRotatedPortions(bool bHasRotatedPortions
);
548 bool GetHasRotatedPortions() const { return mbHasRotatedPortions
; }
549 void SetAnimation() const
550 { const_cast<SwTextFrame
*>(this)->mbHasAnimation
= true; }
551 bool HasAnimation() const { return mbHasAnimation
; }
553 bool IsSwapped() const { return mbIsSwapped
; }
555 /// Does the Frame have a local footnote (in this Frame or Follow)?
557 void CalcFootnoteFlag(TextFrameIndex nStop
= TextFrameIndex(COMPLETE_STRING
)); //For testing SplitFrame
559 void CalcFootnoteFlag();
563 bool IsHiddenNow() const; // bHidden && pOut == pPrt
564 void HideHidden(); // Remove appendage if Hidden
565 void HideFootnotes(TextFrameIndex nStart
, TextFrameIndex nEnd
);
568 * Hides respectively shows objects, which are anchored at paragraph,
569 * at/as a character of the paragraph, corresponding to the paragraph and
570 * paragraph portion visibility.
572 void HideAndShowObjects();
575 void RemoveFootnote(TextFrameIndex nStart
,
576 TextFrameIndex nLen
= TextFrameIndex(COMPLETE_STRING
));
577 inline SwTwips
GetFootnoteFrameHeight() const;
578 SwTextFrame
*FindFootnoteRef( const SwTextFootnote
*pFootnote
);
579 const SwTextFrame
*FindFootnoteRef( const SwTextFootnote
*pFootnote
) const
580 { return const_cast<SwTextFrame
*>(this)->FindFootnoteRef( pFootnote
); }
581 void ConnectFootnote( SwTextFootnote
*pFootnote
, const SwTwips nDeadLine
);
584 * If we're a Footnote that grows towards its reference ...
585 * public, because it's needed by SwContentFrame::MakeAll
587 SwTwips
GetFootnoteLine( const SwTextFootnote
*pFootnote
) const;
589 TextFrameIndex
GetDropLen(TextFrameIndex nWishLen
) const;
591 LanguageType
GetLangOfChar(TextFrameIndex nIndex
, sal_uInt16 nScript
,
592 bool bNoChar
= false) const;
594 virtual void Format( vcl::RenderContext
* pRenderContext
, const SwBorderAttrs
*pAttrs
= nullptr ) override
;
595 virtual void CheckDirection( bool bVert
) override
;
597 /// Returns the sum of line height in pLine
598 SwTwips
GetParHeight() const;
600 inline SwTextFrame
*GetFollow();
601 inline const SwTextFrame
*GetFollow() const;
603 /// Find the page number of ErgoSum and QuoVadis
604 SwTextFrame
*FindQuoVadisFrame();
607 * In case the SwLineLayout was cleared out of the s_pTextCache, recreate it
609 * #i29062# GetFormatted() can trigger a full formatting
610 * of the paragraph, causing other layout frames to become invalid. This
611 * has to be avoided during painting. Therefore we need to pass the
612 * information that we are currently in the paint process.
614 SwTextFrame
* GetFormatted( bool bForceQuickFormat
= false );
616 /// Will be moved soon
617 void SetFootnote( const bool bNew
) { mbFootnote
= bNew
; }
619 /// Respect the Follows
620 inline bool IsInside(TextFrameIndex nPos
) const;
622 /// DropCaps and selections
623 bool GetDropRect( SwRect
&rRect
) const
624 { return HasPara() && GetDropRect_( rRect
); }
626 static SwCache
*GetTextCache() { return s_pTextCache
; }
627 static void SetTextCache( SwCache
*pNew
) { s_pTextCache
= pNew
; }
629 static tools::Long
GetMinPrtLine() { return nMinPrtLine
; }
631 sal_uInt16
GetCacheIdx() const { return mnCacheIndex
; }
632 void SetCacheIdx( const sal_uInt16 nNew
) { mnCacheIndex
= nNew
; }
634 /// Removes the Line information from the Cache but retains the entry itself
636 /// Removes this frame completely from the Cache
637 void RemoveFromCache();
639 /// Am I a FootnoteFrame, with a number at the start of the paragraph?
640 bool IsFootnoteNumFrame() const
641 { return IsInFootnote() && !GetIndPrev() && IsFootnoteNumFrame_(); }
644 * Simulates a formatting as if there were not right margin or Flys or other
645 * obstacles and returns the width
647 SwTwips
CalcFitToContent();
650 * Simulate format for a list item paragraph, whose list level attributes
651 * are in LABEL_ALIGNMENT mode, in order to determine additional first
652 * line offset for the real text formatting due to the value of label
653 * adjustment attribute of the list level.
655 void CalcAdditionalFirstLineOffset();
657 SwTwips
GetAdditionalFirstLineOffset() const
659 return mnAdditionalFirstLineOffset
;
663 * Returns the additional line spacing for the next paragraph
664 * @param _bNoPropLineSpacing: control, whether the value of a
665 * proportional line spacing is returned or not
667 tools::Long
GetLineSpace( const bool _bNoPropLineSpacing
= false ) const;
669 /// Returns the first line height
670 sal_uInt16
FirstLineHeight() const;
672 /// Rewires FlyInContentFrame, if nEnd > Index >= nStart
673 void MoveFlyInCnt(SwTextFrame
*pNew
, TextFrameIndex nStart
, TextFrameIndex nEnd
);
675 /// Calculates the position of FlyInContentFrames
676 TextFrameIndex
CalcFlyPos( SwFrameFormat
const * pSearch
);
678 /// Determines the start position and step size of the register
679 bool FillRegister( SwTwips
& rRegStart
, sal_uInt16
& rRegDiff
);
681 /// Determines the line count
682 sal_Int32
GetLineCount(TextFrameIndex nPos
);
684 /// For displaying the line numbers
685 sal_Int32
GetAllLines() const { return mnAllLines
; }
686 sal_Int32
GetThisLines() const { return mnThisLines
;}
687 void RecalcAllLines();
689 /// Stops the animations within numberings
690 void StopAnimation( const OutputDevice
*pOut
);
692 /// Visit all portions for Accessibility
693 void VisitPortions( SwPortionHandler
& rPH
) const;
695 /// Returns the script info stored at the paraportion
696 const SwScriptInfo
* GetScriptInfo() const;
698 /// Swaps width and height of the text frame
699 void SwapWidthAndHeight();
702 * Calculates the coordinates of a rectangle when switching from
703 * horizontal to vertical layout
705 void SwitchHorizontalToVertical( SwRect
& rRect
) const;
708 * Calculates the coordinates of a point when switching from
709 * horizontal to vertical layout
711 void SwitchHorizontalToVertical( Point
& rPoint
) const;
714 * Calculates the limit value when switching from
715 * horizontal to vertical layout
717 tools::Long
SwitchHorizontalToVertical( tools::Long nLimit
) const;
720 * Calculates the coordinates of a rectangle when switching from
721 * vertical to horizontal layout
723 void SwitchVerticalToHorizontal( SwRect
& rRect
) const;
726 * Calculates the coordinates of a point when switching from
727 * vertical to horizontal layout
729 void SwitchVerticalToHorizontal( Point
& rPoint
) const;
732 * Calculates the a limit value when switching from
733 * vertical to horizontal layout
735 tools::Long
SwitchVerticalToHorizontal( tools::Long nLimit
) const;
738 * Calculates the coordinates of a rectangle when switching from
741 void SwitchLTRtoRTL( SwRect
& rRect
) const;
744 * Calculates the coordinates of a point when switching from
747 void SwitchLTRtoRTL( Point
& rPoint
) const;
750 * Calculates the coordinates of a rectangle when switching from
753 void SwitchRTLtoLTR( SwRect
& rRect
) const { SwitchLTRtoRTL( rRect
); }
756 * Calculates the coordinates of a point when switching from
759 void SwitchRTLtoLTR( Point
& rPoint
) const { SwitchLTRtoRTL( rPoint
); };
761 bool FollowFormatAllowed() const
763 return mbFollowFormatAllowed
;
766 void AllowFollowFormat()
768 mbFollowFormatAllowed
= true;
771 void ForbidFollowFormat()
773 mbFollowFormatAllowed
= false;
776 SwTwips
GetBaseOffsetForFly( bool bIgnoreFlysAnchoredAtThisFrame
) const
778 return ( bIgnoreFlysAnchoredAtThisFrame
?
780 mnFlyAnchorOfstNoWrap
);
783 SwTwips
GetBaseVertOffsetForFly(bool bIgnoreFlysAnchoredAtThisFrame
) const;
785 SwTwips
GetHeightOfLastLine() const
787 return mnHeightOfLastLine
;
790 static void repaintTextFrames( const SwTextNode
& rNode
);
792 void RegisterToNode(SwTextNode
&, bool isForceNodeAsFirst
= false);
794 bool IsSymbolAt(TextFrameIndex
) const;
795 OUString
GetCurWord(SwPosition
const&) const;
796 sal_uInt16
GetScalingOfSelectedText(TextFrameIndex nStt
, TextFrameIndex nEnd
);
798 /// This text frame may have a split fly frames anchored to it. Is any of them a frame that has
799 /// a follow, i.e. not the last in a master -> follow 1 -> ... -> last follow chain?
800 SwFlyAtContentFrame
* HasNonLastSplitFlyDrawObj() const;
802 /// This text frame has a follow and the text frame don't contain text. Additionally one split
803 /// fly is anchored to the text frame.
804 bool IsEmptyMasterWithSplitFly() const;
806 /// This text frame is not split, doesn't fit the upper, has a single split fly anchored to it
807 /// with a negative vertical offset. Such frames may need explicit splitting.
808 bool IsEmptyWithSplitFly() const;
810 static SwView
* GetView();
812 virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer
) const override
;
815 //use this to protect a SwTextFrame for a given scope from getting merged with
816 //its neighbour and thus deleted
817 class TextFrameLockGuard
820 SwTextFrame
*m_pTextFrame
;
823 //Lock pFrame for the lifetime of the Cut/Paste call, etc. to avoid
824 //SwTextFrame::AdjustFollow_ removing the pFrame we're trying to Make
825 TextFrameLockGuard(SwFrame
* pFrame
)
827 m_pTextFrame
= pFrame
->IsTextFrame() ? static_cast<SwTextFrame
*>(pFrame
) : nullptr;
830 m_bOldLocked
= m_pTextFrame
->IsLocked();
831 m_pTextFrame
->Lock();
835 m_bOldLocked
= false;
839 ~TextFrameLockGuard()
841 if (m_pTextFrame
&& !m_bOldLocked
)
842 m_pTextFrame
->Unlock();
846 inline const SwParaPortion
*SwTextFrame::GetPara() const
848 return const_cast<SwTextFrame
*>(this)->GetPara();
851 inline bool SwTextFrame::HasPara() const
853 return mnCacheIndex
!=USHRT_MAX
&& HasPara_();
856 inline SwTwips
SwTextFrame::GrowTst( const SwTwips nGrow
)
858 return Grow( nGrow
, true );
861 inline bool SwTextFrame::IsInside(TextFrameIndex
const nPos
) const
864 if( nPos
< GetOffset() )
868 const SwTextFrame
*pFoll
= GetFollow();
869 if( pFoll
&& nPos
>= pFoll
->GetOffset() )
875 inline SwTwips
SwTextFrame::GetFootnoteFrameHeight() const
877 if( !IsFollow() && IsInFootnote() && HasPara() )
878 return GetFootnoteFrameHeight_();
883 inline const SwTextFrame
*SwTextFrame::GetFollow() const
885 return static_cast<const SwTextFrame
*>(SwContentFrame::GetFollow());
887 inline SwTextFrame
*SwTextFrame::GetFollow()
889 return static_cast<SwTextFrame
*>(SwContentFrame::GetFollow());
892 inline const SwTextFrame
*SwTextFrame::GetFrameAtPos( const SwPosition
&rPos
) const
894 return const_cast<SwTextFrame
*>(this)->GetFrameAtPos( rPos
);
897 inline void SwTextFrame::SetOffset(TextFrameIndex
const nNewOfst
)
899 if ( mnOffset
!= nNewOfst
)
900 SetOffset_( nNewOfst
);
903 inline void SwTextFrame::SetRepaint() const
905 const_cast<SwTextFrame
*>(this)->mbRepaint
= true;
907 inline void SwTextFrame::ResetRepaint() const
909 const_cast<SwTextFrame
*>(this)->mbRepaint
= false;
912 class TemporarySwap
{
914 explicit TemporarySwap(SwTextFrame
* frame
, bool swap
):
915 m_frame(frame
), m_undo(false)
917 if (m_frame
->IsVertical() && swap
) {
919 m_frame
->SwapWidthAndHeight();
925 m_frame
->SwapWidthAndHeight();
930 TemporarySwap(TemporarySwap
const &) = delete;
931 void operator =(TemporarySwap
const &) = delete;
933 SwTextFrame
* m_frame
;
937 class SwSwapIfSwapped
: private TemporarySwap
{
939 explicit SwSwapIfSwapped(SwTextFrame
* frame
):
940 TemporarySwap(frame
, frame
->IsSwapped()) {}
943 class SwSwapIfNotSwapped
: private TemporarySwap
{
945 explicit SwSwapIfNotSwapped(SwTextFrame
* frame
):
946 TemporarySwap(frame
, !frame
->IsSwapped()) {}
950 * Helper class which can be used instead of the macros if a function
951 * has too many returns
955 const SwTextFrame
* pFrame
;
958 SwFrameSwapper( const SwTextFrame
* pFrame
, bool bSwapIfNotSwapped
);
962 class SwLayoutModeModifier
964 const OutputDevice
& m_rOut
;
965 vcl::text::ComplexTextLayoutFlags m_nOldLayoutMode
;
967 SwLayoutModeModifier( const OutputDevice
& rOutp
);
968 ~SwLayoutModeModifier();
969 void Modify( bool bChgToRTL
);
973 class SwDigitModeModifier
975 const OutputDevice
& rOut
;
976 LanguageType nOldLanguageType
;
978 SwDigitModeModifier( const OutputDevice
& rOutp
, LanguageType eCurLang
);
979 ~SwDigitModeModifier();
985 * Describes parts of multiple text nodes, which will form a text frame, even
986 * when redlines are hidden at a layout level.
990 sw::WriterMultiListener listener
;
991 std::vector
<Extent
> extents
;
992 /// note: cannot be const currently to avoid UB because SwTextGuess::Guess
993 /// const_casts it and modifies it (also, Update will modify it)
995 /// most paragraph properties are taken from the first non-empty node
996 SwTextNode
* pParaPropsNode
;
997 /// except break attributes, those are taken from the first node
998 SwTextNode
*const pFirstNode
;
999 /// mainly for sanity checks
1000 SwTextNode
const* pLastNode
;
1001 MergedPara(SwTextFrame
& rFrame
, std::vector
<Extent
>&& rExtents
,
1003 SwTextNode
*const pProps
, SwTextNode
*const pFirst
,
1004 SwTextNode
const*const pLast
)
1005 : listener(rFrame
), extents(std::move(rExtents
)), mergedText(std::move(aText
))
1006 , pParaPropsNode(pProps
), pFirstNode(pFirst
), pLastNode(pLast
)
1008 assert(pParaPropsNode
);
1014 /// iterate SwTextAttr in potentially merged text frame
1015 class MergedAttrIterBase
1018 sw::MergedPara
const*const m_pMerged
;
1019 SwTextNode
const*const m_pNode
;
1020 size_t m_CurrentExtent
;
1021 size_t m_CurrentHint
;
1022 MergedAttrIterBase(SwTextFrame
const& rFrame
);
1025 class MergedAttrIter
1026 : public MergedAttrIterBase
1029 MergedAttrIter(SwTextFrame
const& rFrame
) : MergedAttrIterBase(rFrame
) {}
1030 SwTextAttr
const* NextAttr(SwTextNode
const** ppNode
= nullptr);
1033 class MergedAttrIterByEnd
1036 std::vector
<std::pair
<SwTextNode
const*, SwTextAttr
const*>> m_Hints
;
1037 SwTextNode
const*const m_pNode
;
1038 size_t m_CurrentHint
;
1040 MergedAttrIterByEnd(SwTextFrame
const& rFrame
);
1041 SwTextAttr
const* NextAttr(SwTextNode
const*& rpNode
);
1045 class MergedAttrIterReverse
1046 : public MergedAttrIterBase
1049 MergedAttrIterReverse(SwTextFrame
const& rFrame
);
1050 SwTextAttr
const* PrevAttr(SwTextNode
const** ppNode
= nullptr);
1054 const SwTwips WIDOW_MAGIC
= (SAL_MAX_INT32
- 1)/2;
1060 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */