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 #include <osl/diagnose.h>
31 
32 #include <vector>
33 
34 // --> #i26945# - Additionally the type of the anchor text frame
35 // is collected - by type is meant 'master' or 'follow'.
37 {
38  private:
39  struct tEntry
40  {
42  sal_uInt32 mnPageNumOfAnchor;
44  };
45 
46  std::vector< tEntry > maObjList;
47 
48  public:
50  {
51  }
52 
53  void Collect( SwAnchoredObject& _rAnchoredObj )
54  {
55  tEntry aNewEntry;
56  aNewEntry.mpAnchoredObj = &_rAnchoredObj;
57  // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
58  // is replaced by method <FindPageFrameOfAnchor()>. It's return value
59  // have to be checked.
60  SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
61  if ( pPageFrameOfAnchor )
62  {
63  aNewEntry.mnPageNumOfAnchor = pPageFrameOfAnchor->GetPhyPageNum();
64  }
65  else
66  {
67  aNewEntry.mnPageNumOfAnchor = 0;
68  }
69  // --> #i26945# - collect type of anchor
70  SwTextFrame* pAnchorCharFrame = _rAnchoredObj.FindAnchorCharFrame();
71  if ( pAnchorCharFrame )
72  {
73  aNewEntry.mbAnchoredAtMaster = !pAnchorCharFrame->IsFollow();
74  }
75  else
76  {
77  aNewEntry.mbAnchoredAtMaster = true;
78  }
79  maObjList.push_back( aNewEntry );
80  }
81 
82  SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
83  {
84  return maObjList[_nIndex].mpAnchoredObj;
85  }
86 
87  sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const
88  {
89  return maObjList[_nIndex].mnPageNumOfAnchor;
90  }
91 
92  // --> #i26945#
93  bool AnchoredAtMaster( sal_uInt32 _nIndex )
94  {
95  return maObjList[_nIndex].mbAnchoredAtMaster;
96  }
97 
98  sal_uInt32 Count() const
99  {
100  return maObjList.size();
101  }
102 };
103 
105  SwLayAction* _pLayAction,
106  const bool _bCollectPgNumOfAnchors )
107  : mrPageFrame( _rPageFrame ),
108  mbConsiderWrapOnObjPos( _rPageFrame.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ),
109  mpLayAction( _pLayAction ),
110  // --> #i26945#
111  mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : nullptr )
112 {
113 }
114 
116 {
117 }
118 
119 std::unique_ptr<SwObjectFormatter> SwObjectFormatter::CreateObjFormatter(
120  SwFrame& _rAnchorFrame,
121  const SwPageFrame& _rPageFrame,
122  SwLayAction* _pLayAction )
123 {
124  std::unique_ptr<SwObjectFormatter> pObjFormatter;
125  if ( _rAnchorFrame.IsTextFrame() )
126  {
128  static_cast<SwTextFrame&>(_rAnchorFrame),
129  _rPageFrame, _pLayAction );
130  }
131  else if ( _rAnchorFrame.IsLayoutFrame() )
132  {
134  static_cast<SwLayoutFrame&>(_rAnchorFrame),
135  _rPageFrame, _pLayAction );
136  }
137  else
138  {
139  OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
140  }
141 
142  return pObjFormatter;
143 }
144 
148  const SwPageFrame& _rPageFrame,
149  SwLayAction* _pLayAction )
150 {
151  bool bSuccess( true );
152 
153  // create corresponding object formatter
154  std::unique_ptr<SwObjectFormatter> pObjFormatter =
155  SwObjectFormatter::CreateObjFormatter( _rAnchorFrame, _rPageFrame, _pLayAction );
156 
157  if ( pObjFormatter )
158  {
159  // format anchored floating screen objects
160  bSuccess = pObjFormatter->DoFormatObjs();
161  }
162 
163  return bSuccess;
164 }
165 
169  SwFrame* _pAnchorFrame,
170  const SwPageFrame* _pPageFrame )
171 {
172  bool bSuccess( true );
173 
174  OSL_ENSURE( _pAnchorFrame || _rAnchoredObj.GetAnchorFrame(),
175  "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
176  SwFrame& rAnchorFrame = _pAnchorFrame ? *_pAnchorFrame : *(_rAnchoredObj.AnchorFrame());
177 
178  OSL_ENSURE( _pPageFrame || rAnchorFrame.FindPageFrame(),
179  "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
180  const SwPageFrame& rPageFrame = _pPageFrame ? *_pPageFrame : *(rAnchorFrame.FindPageFrame());
181 
182  // create corresponding object formatter
183  std::unique_ptr<SwObjectFormatter> pObjFormatter =
184  SwObjectFormatter::CreateObjFormatter( rAnchorFrame, rPageFrame, nullptr/*_pLayAction*/ );
185 
186  if ( pObjFormatter )
187  {
188  // format given floating screen object
189  // --> #i40147# - check for moved forward anchor frame
190  bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
191  }
192 
193  return bSuccess;
194 }
195 
206 {
207  _rLayoutFrame.Calc(_rLayoutFrame.getRootFrame()->GetCurrShell()->GetOut());
208 
209  SwFrame* pLowerFrame = _rLayoutFrame.Lower();
210  while ( pLowerFrame )
211  {
212  if ( pLowerFrame->IsLayoutFrame() )
213  {
214  FormatLayout_( *static_cast<SwLayoutFrame*>(pLowerFrame) );
215  }
216  pLowerFrame = pLowerFrame->GetNext();
217  }
218 }
219 
226 {
227  if ( !_rAnchoredObj.DynCastFlyFrame() )
228  {
229  // only Writer fly frames have content
230  return;
231  }
232 
233  SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
234  SwContentFrame* pContent = rFlyFrame.ContainsContent();
235 
236  while ( pContent )
237  {
238  // format content
239  pContent->OptCalc();
240 
241  // format floating screen objects at content text frame
242  // #i23129#, #i36347# - pass correct page frame to
243  // the object formatter
244  if ( pContent->IsTextFrame() &&
246  *(pContent->FindPageFrame()),
247  GetLayAction() ) )
248  {
249  // restart format with first content
250  pContent = rFlyFrame.ContainsContent();
251  continue;
252  }
253 
254  // continue with next content
255  pContent = pContent->GetNextContentFrame();
256  }
257 }
258 
264 {
265  // collect anchor object and its 'anchor' page number, if requested
267  {
268  mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
269  }
270 
271  if ( auto pFlyFrame = _rAnchoredObj.DynCastFlyFrame() )
272  {
273  // --> #i34753# - reset flag, which prevents a positioning
274  if ( pFlyFrame->IsFlyLayFrame() )
275  {
276  static_cast<SwFlyLayFrame*>(pFlyFrame)->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( pFlyFrame );
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_( *pFlyFrame );
297  }
298  // --> #i34753# - prevent further positioning, if
299  // to-page|to-fly anchored Writer fly frame is already clipped.
300  if ( pFlyFrame->IsFlyLayFrame() && pFlyFrame->IsClipped() )
301  {
302  static_cast<SwFlyLayFrame*>(pFlyFrame)->SetNoMakePos( true );
303  }
304  // #i23129#, #i36347# - pass correct page frame
305  // to the object formatter
307  *(pFlyFrame->FindPageFrame()),
308  mpLayAction );
309  if ( mpLayAction )
310  {
311  mpLayAction->FormatFlyContent( pFlyFrame );
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( *pFlyFrame );
322  }
323 
324  if ( ++nLoopControlRuns >= nLoopControlMax )
325  {
326  OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
327  pFlyFrame->ValidateThisAndAllLowers( 2 );
328  nLoopControlRuns = 0;
329  }
330 
331  // --> #i57917#
332  // stop formatting of anchored object, if restart of layout process is requested.
333  } while ( !pFlyFrame->isFrameAreaDefinitionValid() &&
334  !_rAnchoredObj.RestartLayoutProcess() &&
335  pFlyFrame->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: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:315
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:158
SwAnchoredObject * operator[](sal_uInt32 _nIndex)
bool IsFollow() const
Definition: flowfrm.hxx:166
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:565
SwContentFrame * GetNextContentFrame() const
Definition: cntfrm.hxx:115
sal_uInt32 GetPageNum(sal_uInt32 _nIndex) const
void FormatFlyContent(const SwFlyFrame *)
Definition: layact.cxx:1891
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:1121
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1788
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:204
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:1235
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:55
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:43
SwPageFrame * FindPageFrame()
Definition: frame.hxx:681
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.
virtual const SwFlyFrame * DynCastFlyFrame() const
sal_uInt32 Count() const
virtual SwFrame & GetAnchorFrame()=0
A page of the document layout.
Definition: pagefrm.hxx:57
std::vector< tEntry > maObjList
void OptCalc() const
Definition: frame.hxx:1081
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:1171
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:78
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:167
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:277
bool IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)
accessor to 'anchor' type of collected anchored object
void FormatLayoutFly(SwFlyFrame *)
Definition: layact.cxx:1439
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:67
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:207
SwRootFrame * getRootFrame()
Definition: frame.hxx:680
SwFrame * GetNext()
Definition: frame.hxx:677
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects