LibreOffice Module sw (master)  1
objectformatter.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
22 #include <anchoreddrawobject.hxx>
23 #include <sortedobjs.hxx>
24 #include <rootfrm.hxx>
25 #include <pagefrm.hxx>
26 #include <flyfrms.hxx>
27 #include <txtfrm.hxx>
28 #include <layact.hxx>
30 
31 #include <vector>
32 
33 // --> #i26945# - Additionally the type of the anchor text frame
34 // is collected - by type is meant 'master' or 'follow'.
36 {
37  private:
38  struct tEntry
39  {
41  sal_uInt32 mnPageNumOfAnchor;
43  };
44 
45  std::vector< tEntry > maObjList;
46 
47  public:
49  {
50  }
51 
52  void Collect( SwAnchoredObject& _rAnchoredObj )
53  {
54  tEntry aNewEntry;
55  aNewEntry.mpAnchoredObj = &_rAnchoredObj;
56  // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
57  // is replaced by method <FindPageFrameOfAnchor()>. It's return value
58  // have to be checked.
59  SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
60  if ( pPageFrameOfAnchor )
61  {
62  aNewEntry.mnPageNumOfAnchor = pPageFrameOfAnchor->GetPhyPageNum();
63  }
64  else
65  {
66  aNewEntry.mnPageNumOfAnchor = 0;
67  }
68  // --> #i26945# - collect type of anchor
69  SwTextFrame* pAnchorCharFrame = _rAnchoredObj.FindAnchorCharFrame();
70  if ( pAnchorCharFrame )
71  {
72  aNewEntry.mbAnchoredAtMaster = !pAnchorCharFrame->IsFollow();
73  }
74  else
75  {
76  aNewEntry.mbAnchoredAtMaster = true;
77  }
78  maObjList.push_back( aNewEntry );
79  }
80 
81  SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
82  {
83  return maObjList[_nIndex].mpAnchoredObj;
84  }
85 
86  sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const
87  {
88  return maObjList[_nIndex].mnPageNumOfAnchor;
89  }
90 
91  // --> #i26945#
92  bool AnchoredAtMaster( sal_uInt32 _nIndex )
93  {
94  return maObjList[_nIndex].mbAnchoredAtMaster;
95  }
96 
97  sal_uInt32 Count() const
98  {
99  return maObjList.size();
100  }
101 };
102 
104  SwLayAction* _pLayAction,
105  const bool _bCollectPgNumOfAnchors )
106  : mrPageFrame( _rPageFrame ),
107  mbConsiderWrapOnObjPos( _rPageFrame.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ),
108  mpLayAction( _pLayAction ),
109  // --> #i26945#
110  mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : nullptr )
111 {
112 }
113 
115 {
116 }
117 
118 std::unique_ptr<SwObjectFormatter> SwObjectFormatter::CreateObjFormatter(
119  SwFrame& _rAnchorFrame,
120  const SwPageFrame& _rPageFrame,
121  SwLayAction* _pLayAction )
122 {
123  std::unique_ptr<SwObjectFormatter> pObjFormatter;
124  if ( _rAnchorFrame.IsTextFrame() )
125  {
127  static_cast<SwTextFrame&>(_rAnchorFrame),
128  _rPageFrame, _pLayAction );
129  }
130  else if ( _rAnchorFrame.IsLayoutFrame() )
131  {
133  static_cast<SwLayoutFrame&>(_rAnchorFrame),
134  _rPageFrame, _pLayAction );
135  }
136  else
137  {
138  OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
139  }
140 
141  return pObjFormatter;
142 }
143 
147  const SwPageFrame& _rPageFrame,
148  SwLayAction* _pLayAction )
149 {
150  bool bSuccess( true );
151 
152  // create corresponding object formatter
153  std::unique_ptr<SwObjectFormatter> pObjFormatter =
154  SwObjectFormatter::CreateObjFormatter( _rAnchorFrame, _rPageFrame, _pLayAction );
155 
156  if ( pObjFormatter )
157  {
158  // format anchored floating screen objects
159  bSuccess = pObjFormatter->DoFormatObjs();
160  }
161 
162  return bSuccess;
163 }
164 
168  SwFrame* _pAnchorFrame,
169  const SwPageFrame* _pPageFrame )
170 {
171  bool bSuccess( true );
172 
173  OSL_ENSURE( _pAnchorFrame || _rAnchoredObj.GetAnchorFrame(),
174  "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
175  SwFrame& rAnchorFrame = _pAnchorFrame ? *_pAnchorFrame : *(_rAnchoredObj.AnchorFrame());
176 
177  OSL_ENSURE( _pPageFrame || rAnchorFrame.FindPageFrame(),
178  "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
179  const SwPageFrame& rPageFrame = _pPageFrame ? *_pPageFrame : *(rAnchorFrame.FindPageFrame());
180 
181  // create corresponding object formatter
182  std::unique_ptr<SwObjectFormatter> pObjFormatter =
183  SwObjectFormatter::CreateObjFormatter( rAnchorFrame, rPageFrame, nullptr/*_pLayAction*/ );
184 
185  if ( pObjFormatter )
186  {
187  // format given floating screen object
188  // --> #i40147# - check for moved forward anchor frame
189  bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
190  }
191 
192  return bSuccess;
193 }
194 
205 {
206  _rLayoutFrame.Calc(_rLayoutFrame.getRootFrame()->GetCurrShell()->GetOut());
207 
208  SwFrame* pLowerFrame = _rLayoutFrame.Lower();
209  while ( pLowerFrame )
210  {
211  if ( pLowerFrame->IsLayoutFrame() )
212  {
213  FormatLayout_( *static_cast<SwLayoutFrame*>(pLowerFrame) );
214  }
215  pLowerFrame = pLowerFrame->GetNext();
216  }
217 }
218 
225 {
226  if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) == nullptr )
227  {
228  // only Writer fly frames have content
229  return;
230  }
231 
232  SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
233  SwContentFrame* pContent = rFlyFrame.ContainsContent();
234 
235  while ( pContent )
236  {
237  // format content
238  pContent->OptCalc();
239 
240  // format floating screen objects at content text frame
241  // #i23129#, #i36347# - pass correct page frame to
242  // the object formatter
243  if ( pContent->IsTextFrame() &&
245  *(pContent->FindPageFrame()),
246  GetLayAction() ) )
247  {
248  // restart format with first content
249  pContent = rFlyFrame.ContainsContent();
250  continue;
251  }
252 
253  // continue with next content
254  pContent = pContent->GetNextContentFrame();
255  }
256 }
257 
263 {
264  // collect anchor object and its 'anchor' page number, if requested
266  {
267  mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
268  }
269 
270  if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) != nullptr )
271  {
272  SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
273  // --> #i34753# - reset flag, which prevents a positioning
274  if ( rFlyFrame.IsFlyLayFrame() )
275  {
276  static_cast<SwFlyLayFrame&>(rFlyFrame).SetNoMakePos( false );
277  }
278 
279  // #i81146# new loop control
280  int nLoopControlRuns = 0;
281  const int nLoopControlMax = 15;
282 
283  do {
284  if ( mpLayAction )
285  {
286  mpLayAction->FormatLayoutFly( &rFlyFrame );
287  // --> consider, if the layout action
288  // has to be restarted due to a delete of a page frame.
289  if ( mpLayAction->IsAgain() )
290  {
291  break;
292  }
293  }
294  else
295  {
296  FormatLayout_( rFlyFrame );
297  }
298  // --> #i34753# - prevent further positioning, if
299  // to-page|to-fly anchored Writer fly frame is already clipped.
300  if ( rFlyFrame.IsFlyLayFrame() && rFlyFrame.IsClipped() )
301  {
302  static_cast<SwFlyLayFrame&>(rFlyFrame).SetNoMakePos( true );
303  }
304  // #i23129#, #i36347# - pass correct page frame
305  // to the object formatter
307  *(rFlyFrame.FindPageFrame()),
308  mpLayAction );
309  if ( mpLayAction )
310  {
311  mpLayAction->FormatFlyContent( &rFlyFrame );
312  // --> consider, if the layout action
313  // has to be restarted due to a delete of a page frame.
314  if ( mpLayAction->IsAgain() )
315  {
316  break;
317  }
318  }
319  else
320  {
321  FormatObjContent( rFlyFrame );
322  }
323 
324  if ( ++nLoopControlRuns >= nLoopControlMax )
325  {
326  OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
327  rFlyFrame.ValidateThisAndAllLowers( 2 );
328  nLoopControlRuns = 0;
329  }
330 
331  // --> #i57917#
332  // stop formatting of anchored object, if restart of layout process is requested.
333  } while ( !rFlyFrame.isFrameAreaDefinitionValid() &&
334  !_rAnchoredObj.RestartLayoutProcess() &&
335  rFlyFrame.GetAnchorFrame() == &GetAnchorFrame() );
336  }
337  else if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rAnchoredObj) != nullptr )
338  {
339  _rAnchoredObj.MakeObjPos();
340  }
341 }
342 
353 {
354  // --> #i26945#
355  SwFrame* pAnchorFrame( nullptr );
356  if ( GetAnchorFrame().IsTextFrame() &&
357  static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
358  _pMasterTextFrame )
359  {
360  pAnchorFrame = _pMasterTextFrame;
361  }
362  else
363  {
364  pAnchorFrame = &GetAnchorFrame();
365  }
366  if ( !pAnchorFrame->GetDrawObjs() )
367  {
368  // nothing to do, if no floating screen object is registered at the anchor frame.
369  return true;
370  }
371 
372  bool bSuccess( true );
373 
374  for ( size_t i = 0; i < pAnchorFrame->GetDrawObjs()->size(); ++i )
375  {
376  SwAnchoredObject* pAnchoredObj = (*pAnchorFrame->GetDrawObjs())[i];
377 
378  // check, if object's anchor is on the given page frame or
379  // object is registered at the given page frame.
380  // --> #i26945# - check, if the anchor character of the
381  // anchored object is located in a follow text frame. If this anchor
382  // follow text frame differs from the given anchor frame, the given
383  // anchor frame is a 'master' text frame of the anchor follow text frame.
384  // If the anchor follow text frame is in the same body as its 'master'
385  // text frame, do not format the anchored object.
386  // E.g., this situation can occur during the table row splitting algorithm.
387  SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame();
388  const bool bAnchoredAtFollowInSameBodyAsMaster =
389  pAnchorCharFrame && pAnchorCharFrame->IsFollow() &&
390  pAnchorCharFrame != pAnchoredObj->GetAnchorFrame() &&
391  pAnchorCharFrame->FindBodyFrame() ==
392  static_cast<SwTextFrame*>(pAnchoredObj->AnchorFrame())->FindBodyFrame();
393  if ( bAnchoredAtFollowInSameBodyAsMaster )
394  {
395  continue;
396  }
397  // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
398  // is replaced by method <FindPageFrameOfAnchor()>. It's return value
399  // have to be checked.
400  SwPageFrame* pPageFrameOfAnchor = pAnchoredObj->FindPageFrameOfAnchor();
401  OSL_ENSURE( pPageFrameOfAnchor,
402  "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
403  // --> #i26945#
404  if ( pPageFrameOfAnchor && pPageFrameOfAnchor == &mrPageFrame )
405  {
406  // if format of object fails, stop formatting and pass fail to
407  // calling method via the return value.
408  if ( !DoFormatObj( *pAnchoredObj ) )
409  {
410  bSuccess = false;
411  break;
412  }
413 
414  // considering changes at <pAnchorFrame->GetDrawObjs()> during
415  // format of the object.
416  if ( !pAnchorFrame->GetDrawObjs() ||
417  i > pAnchorFrame->GetDrawObjs()->size() )
418  {
419  break;
420  }
421  else
422  {
423  const size_t nActPosOfObj =
424  pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
425  if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
426  nActPosOfObj > i )
427  {
428  --i;
429  }
430  else if ( nActPosOfObj < i )
431  {
432  i = nActPosOfObj;
433  }
434  }
435  }
436  } // end of loop on <pAnchorFrame->.GetDrawObjs()>
437 
438  return bSuccess;
439 }
440 
446 {
447  return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
448 }
449 
454 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
455 {
456  return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0;
457 }
458 
463 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
464 {
465  return mpPgNumAndTypeOfAnchors == nullptr
466  || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
467 }
468 
474 {
475  return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
476 }
477 
478 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
vcl::RenderContext * GetOut() const
Definition: viewsh.hxx:341
virtual void MakeObjPos()=0
method to determine position for the object and set the position at the object
Base class of the Writer layout elements.
Definition: frame.hxx:297
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:151
SwAnchoredObject * operator[](sal_uInt32 _nIndex)
bool IsFlyLayFrame() const
Definition: flyfrm.hxx:195
bool IsFollow() const
Definition: flowfrm.hxx:166
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:545
SwContentFrame * GetNextContentFrame() const
Definition: cntfrm.hxx:98
sal_uInt32 GetPageNum(sal_uInt32 _nIndex) const
void FormatFlyContent(const SwFlyFrame *)
Definition: layact.cxx:1830
static std::unique_ptr< SwObjectFormatterTextFrame > CreateObjFormatter(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction)
method to create an instance of is necessary.
SwLayAction * GetLayAction()
const SwBodyFrame * FindBodyFrame() const
Definition: frame.hxx:1098
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1785
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:169
bool AnchoredAtMaster(sal_uInt32 _nIndex)
void FormatLayout_(SwLayoutFrame &_rLayoutFrame)
helper method for method - performs the intrinsic format of the layout of the given ...
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:190
SwLayAction * mpLayAction
SwTextFrame * FindAnchorCharFrame()
get frame, which contains the anchor character, if the object is anchored at-character or as-characte...
wrapper class for the positioning of Writer fly frames and drawing objects
static std::unique_ptr< SwObjectFormatter > CreateObjFormatter(SwFrame &_rAnchorFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction)
bool IsTextFrame() const
Definition: frame.hxx:1212
SwAnchoredObject * GetCollectedObj(const sal_uInt32 _nIndex)
accessor to collected anchored object
SwFrame * AnchorFrame()
void Collect(SwAnchoredObject &_rAnchoredObj)
SwObjectFormatter(const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction, const bool _bCollectPgNumOfAnchors=false)
int i
The usage of LayAction is always the same:
Definition: layact.hxx:56
bool FormatObjsAtFrame_(SwTextFrame *_pMasterTextFrame=nullptr)
invokes the intrinsic format method for all floating screen objects, anchored at anchor frame on the ...
sal_uInt32 GetPgNumOfCollected(const sal_uInt32 _nIndex)
accessor to 'anchor' page number of collected anchored object
size_t size() const
Definition: sortedobjs.cxx:42
SwPageFrame * FindPageFrame()
Definition: frame.hxx:660
const SwFrame * Lower() const
Definition: layfrm.hxx:101
const SwPageFrame & mrPageFrame
void FormatObj_(SwAnchoredObject &_rAnchoredObj)
performs the intrinsic format of a given floating screen object and its content.
sal_uInt32 Count() const
::rtl::Reference< Content > pContent
virtual SwFrame & GetAnchorFrame()=0
A page of the document layout.
Definition: pagefrm.hxx:40
std::vector< tEntry > maObjList
void OptCalc() const
Definition: frame.hxx:1058
bool RestartLayoutProcess() const
static bool FormatObjsAtFrame(SwFrame &_rAnchorFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction=nullptr)
method to format all floating screen objects at the given anchor frame
bool IsLayoutFrame() const
Definition: frame.hxx:1148
void FormatObjContent(SwAnchoredObject &_rAnchoredObj)
helper method for method - performs the intrinsic format of the content of the given...
general base class for all free-flowing frames
Definition: flyfrm.hxx:60
SwPageFrame * FindPageFrameOfAnchor()
method to determine the page frame, on which the 'anchor' of the given anchored object is...
std::unique_ptr< SwPageNumAndTypeOfAnchors > mpPgNumAndTypeOfAnchors
static bool FormatObj(SwAnchoredObject &_rAnchoredObj, SwFrame *_pAnchorFrame=nullptr, const SwPageFrame *_pPageFrame=nullptr)
method to format a given floating screen object
virtual ~SwObjectFormatter()
bool IsClipped() const
Definition: flyfrm.hxx:202
virtual bool DoFormatObj(SwAnchoredObject &_rAnchoredObj, const bool _bCheckForMovedFwd=false)=0
intrinsic method to format a certain floating screen object
bool IsAgain() const
Definition: layact.hxx:160
static std::unique_ptr< SwObjectFormatterLayFrame > CreateObjFormatter(SwLayoutFrame &_rAnchorLayFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction)
size_t ListPosOf(const SwAnchoredObject &_rAnchoredObj) const
Position of object <_rAnchoredObj> in sorted list.
Definition: sortedobjs.cxx:276
bool IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)
accessor to 'anchor' type of collected anchored object
void FormatLayoutFly(SwFlyFrame *)
Definition: layact.cxx:1419
void ValidateThisAndAllLowers(const sal_uInt16 nStage)
Definition: wsfrm.cxx:2016
A layout frame is a frame that contains other frames (m_pLower), e.g. SwPageFrame or SwTabFrame...
Definition: layfrm.hxx:35
const SwFrame * GetAnchorFrame() const
const SwContentFrame * ContainsContent() const
Checks if the frame contains one or more ContentFrame's anywhere in his subsidiary structure; if so t...
Definition: findfrm.cxx:66
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:204
SwRootFrame * getRootFrame()
Definition: frame.hxx:659
SwFrame * GetNext()
Definition: frame.hxx:656
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects