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 ( auto pFlyFrame = dynamic_cast<SwFlyFrame*>( &_rAnchoredObj) )
271  {
272  // --> #i34753# - reset flag, which prevents a positioning
273  if ( pFlyFrame->IsFlyLayFrame() )
274  {
275  static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( false );
276  }
277 
278  // #i81146# new loop control
279  int nLoopControlRuns = 0;
280  const int nLoopControlMax = 15;
281 
282  do {
283  if ( mpLayAction )
284  {
285  mpLayAction->FormatLayoutFly( pFlyFrame );
286  // --> consider, if the layout action
287  // has to be restarted due to a delete of a page frame.
288  if ( mpLayAction->IsAgain() )
289  {
290  break;
291  }
292  }
293  else
294  {
295  FormatLayout_( *pFlyFrame );
296  }
297  // --> #i34753# - prevent further positioning, if
298  // to-page|to-fly anchored Writer fly frame is already clipped.
299  if ( pFlyFrame->IsFlyLayFrame() && pFlyFrame->IsClipped() )
300  {
301  static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( true );
302  }
303  // #i23129#, #i36347# - pass correct page frame
304  // to the object formatter
306  *(pFlyFrame->FindPageFrame()),
307  mpLayAction );
308  if ( mpLayAction )
309  {
310  mpLayAction->FormatFlyContent( pFlyFrame );
311  // --> consider, if the layout action
312  // has to be restarted due to a delete of a page frame.
313  if ( mpLayAction->IsAgain() )
314  {
315  break;
316  }
317  }
318  else
319  {
320  FormatObjContent( *pFlyFrame );
321  }
322 
323  if ( ++nLoopControlRuns >= nLoopControlMax )
324  {
325  OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
326  pFlyFrame->ValidateThisAndAllLowers( 2 );
327  nLoopControlRuns = 0;
328  }
329 
330  // --> #i57917#
331  // stop formatting of anchored object, if restart of layout process is requested.
332  } while ( !pFlyFrame->isFrameAreaDefinitionValid() &&
333  !_rAnchoredObj.RestartLayoutProcess() &&
334  pFlyFrame->GetAnchorFrame() == &GetAnchorFrame() );
335  }
336  else if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rAnchoredObj) != nullptr )
337  {
338  _rAnchoredObj.MakeObjPos();
339  }
340 }
341 
352 {
353  // --> #i26945#
354  SwFrame* pAnchorFrame( nullptr );
355  if ( GetAnchorFrame().IsTextFrame() &&
356  static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
357  _pMasterTextFrame )
358  {
359  pAnchorFrame = _pMasterTextFrame;
360  }
361  else
362  {
363  pAnchorFrame = &GetAnchorFrame();
364  }
365  if ( !pAnchorFrame->GetDrawObjs() )
366  {
367  // nothing to do, if no floating screen object is registered at the anchor frame.
368  return true;
369  }
370 
371  bool bSuccess( true );
372 
373  for ( size_t i = 0; i < pAnchorFrame->GetDrawObjs()->size(); ++i )
374  {
375  SwAnchoredObject* pAnchoredObj = (*pAnchorFrame->GetDrawObjs())[i];
376 
377  // check, if object's anchor is on the given page frame or
378  // object is registered at the given page frame.
379  // --> #i26945# - check, if the anchor character of the
380  // anchored object is located in a follow text frame. If this anchor
381  // follow text frame differs from the given anchor frame, the given
382  // anchor frame is a 'master' text frame of the anchor follow text frame.
383  // If the anchor follow text frame is in the same body as its 'master'
384  // text frame, do not format the anchored object.
385  // E.g., this situation can occur during the table row splitting algorithm.
386  SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame();
387  const bool bAnchoredAtFollowInSameBodyAsMaster =
388  pAnchorCharFrame && pAnchorCharFrame->IsFollow() &&
389  pAnchorCharFrame != pAnchoredObj->GetAnchorFrame() &&
390  pAnchorCharFrame->FindBodyFrame() ==
391  static_cast<SwTextFrame*>(pAnchoredObj->AnchorFrame())->FindBodyFrame();
392  if ( bAnchoredAtFollowInSameBodyAsMaster )
393  {
394  continue;
395  }
396  // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
397  // is replaced by method <FindPageFrameOfAnchor()>. It's return value
398  // have to be checked.
399  SwPageFrame* pPageFrameOfAnchor = pAnchoredObj->FindPageFrameOfAnchor();
400  OSL_ENSURE( pPageFrameOfAnchor,
401  "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
402  // --> #i26945#
403  if ( pPageFrameOfAnchor && pPageFrameOfAnchor == &mrPageFrame )
404  {
405  // if format of object fails, stop formatting and pass fail to
406  // calling method via the return value.
407  if ( !DoFormatObj( *pAnchoredObj ) )
408  {
409  bSuccess = false;
410  break;
411  }
412 
413  // considering changes at <pAnchorFrame->GetDrawObjs()> during
414  // format of the object.
415  if ( !pAnchorFrame->GetDrawObjs() ||
416  i > pAnchorFrame->GetDrawObjs()->size() )
417  {
418  break;
419  }
420  else
421  {
422  const size_t nActPosOfObj =
423  pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
424  if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
425  nActPosOfObj > i )
426  {
427  --i;
428  }
429  else if ( nActPosOfObj < i )
430  {
431  i = nActPosOfObj;
432  }
433  }
434  }
435  } // end of loop on <pAnchorFrame->.GetDrawObjs()>
436 
437  return bSuccess;
438 }
439 
445 {
446  return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
447 }
448 
453 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
454 {
455  return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0;
456 }
457 
462 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
463 {
464  return mpPgNumAndTypeOfAnchors == nullptr
465  || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
466 }
467 
473 {
474  return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
475 }
476 
477 /* 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:338
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:298
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:151
SwAnchoredObject * operator[](sal_uInt32 _nIndex)
bool IsFollow() const
Definition: flowfrm.hxx:166
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:548
SwContentFrame * GetNextContentFrame() const
Definition: cntfrm.hxx:98
sal_uInt32 GetPageNum(sal_uInt32 _nIndex) const
void FormatFlyContent(const SwFlyFrame *)
Definition: layact.cxx:1834
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:1101
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1787
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:191
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:1215
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:663
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:41
std::vector< tEntry > maObjList
void OptCalc() const
Definition: frame.hxx:1061
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:1151
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()
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:1423
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:208
SwRootFrame * getRootFrame()
Definition: frame.hxx:662
SwFrame * GetNext()
Definition: frame.hxx:659
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects