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>
29 #include <fmtanchr.hxx>
30 #include <doc.hxx>
32 
33 #include <vector>
34 
35 // --> #i26945# - Additionally the type of the anchor text frame
36 // is collected - by type is meant 'master' or 'follow'.
38 {
39  private:
40  struct tEntry
41  {
43  sal_uInt32 mnPageNumOfAnchor;
45  };
46 
47  std::vector< tEntry > maObjList;
48 
49  public:
51  {
52  }
53 
54  void Collect( SwAnchoredObject& _rAnchoredObj )
55  {
56  tEntry aNewEntry;
57  aNewEntry.mpAnchoredObj = &_rAnchoredObj;
58  // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
59  // is replaced by method <FindPageFrameOfAnchor()>. It's return value
60  // have to be checked.
61  SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
62  if ( pPageFrameOfAnchor )
63  {
64  aNewEntry.mnPageNumOfAnchor = pPageFrameOfAnchor->GetPhyPageNum();
65  }
66  else
67  {
68  aNewEntry.mnPageNumOfAnchor = 0;
69  }
70  // --> #i26945# - collect type of anchor
71  SwTextFrame* pAnchorCharFrame = _rAnchoredObj.FindAnchorCharFrame();
72  if ( pAnchorCharFrame )
73  {
74  aNewEntry.mbAnchoredAtMaster = !pAnchorCharFrame->IsFollow();
75  }
76  else
77  {
78  aNewEntry.mbAnchoredAtMaster = true;
79  }
80  maObjList.push_back( aNewEntry );
81  }
82 
83  SwAnchoredObject* operator[]( sal_uInt32 _nIndex )
84  {
85  return maObjList[_nIndex].mpAnchoredObj;
86  }
87 
88  sal_uInt32 GetPageNum( sal_uInt32 _nIndex ) const
89  {
90  return maObjList[_nIndex].mnPageNumOfAnchor;
91  }
92 
93  // --> #i26945#
94  bool AnchoredAtMaster( sal_uInt32 _nIndex )
95  {
96  return maObjList[_nIndex].mbAnchoredAtMaster;
97  }
98 
99  sal_uInt32 Count() const
100  {
101  return maObjList.size();
102  }
103 };
104 
106  SwLayAction* _pLayAction,
107  const bool _bCollectPgNumOfAnchors )
108  : mrPageFrame( _rPageFrame ),
109  mbConsiderWrapOnObjPos( _rPageFrame.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ),
110  mpLayAction( _pLayAction ),
111  // --> #i26945#
112  mpPgNumAndTypeOfAnchors( _bCollectPgNumOfAnchors ? new SwPageNumAndTypeOfAnchors() : nullptr )
113 {
114 }
115 
117 {
118 }
119 
120 std::unique_ptr<SwObjectFormatter> SwObjectFormatter::CreateObjFormatter(
121  SwFrame& _rAnchorFrame,
122  const SwPageFrame& _rPageFrame,
123  SwLayAction* _pLayAction )
124 {
125  std::unique_ptr<SwObjectFormatter> pObjFormatter;
126  if ( _rAnchorFrame.IsTextFrame() )
127  {
129  static_cast<SwTextFrame&>(_rAnchorFrame),
130  _rPageFrame, _pLayAction );
131  }
132  else if ( _rAnchorFrame.IsLayoutFrame() )
133  {
135  static_cast<SwLayoutFrame&>(_rAnchorFrame),
136  _rPageFrame, _pLayAction );
137  }
138  else
139  {
140  OSL_FAIL( "<SwObjectFormatter::CreateObjFormatter(..)> - unexpected type of anchor frame" );
141  }
142 
143  return pObjFormatter;
144 }
145 
149  const SwPageFrame& _rPageFrame,
150  SwLayAction* _pLayAction )
151 {
152  bool bSuccess( true );
153 
154  // create corresponding object formatter
155  std::unique_ptr<SwObjectFormatter> pObjFormatter =
156  SwObjectFormatter::CreateObjFormatter( _rAnchorFrame, _rPageFrame, _pLayAction );
157 
158  if ( pObjFormatter )
159  {
160  // format anchored floating screen objects
161  bSuccess = pObjFormatter->DoFormatObjs();
162  }
163 
164  return bSuccess;
165 }
166 
170  SwFrame* _pAnchorFrame,
171  const SwPageFrame* _pPageFrame )
172 {
173  bool bSuccess( true );
174 
175  OSL_ENSURE( _pAnchorFrame || _rAnchoredObj.GetAnchorFrame(),
176  "<SwObjectFormatter::FormatObj(..)> - missing anchor frame" );
177  SwFrame& rAnchorFrame = _pAnchorFrame ? *_pAnchorFrame : *(_rAnchoredObj.AnchorFrame());
178 
179  OSL_ENSURE( _pPageFrame || rAnchorFrame.FindPageFrame(),
180  "<SwObjectFormatter::FormatObj(..)> - missing page frame" );
181  const SwPageFrame& rPageFrame = _pPageFrame ? *_pPageFrame : *(rAnchorFrame.FindPageFrame());
182 
183  // create corresponding object formatter
184  std::unique_ptr<SwObjectFormatter> pObjFormatter =
185  SwObjectFormatter::CreateObjFormatter( rAnchorFrame, rPageFrame, nullptr/*_pLayAction*/ );
186 
187  if ( pObjFormatter )
188  {
189  // format given floating screen object
190  // --> #i40147# - check for moved forward anchor frame
191  bSuccess = pObjFormatter->DoFormatObj( _rAnchoredObj, true );
192  }
193 
194  return bSuccess;
195 }
196 
207 {
208  _rLayoutFrame.Calc(_rLayoutFrame.getRootFrame()->GetCurrShell()->GetOut());
209 
210  SwFrame* pLowerFrame = _rLayoutFrame.Lower();
211  while ( pLowerFrame )
212  {
213  if ( pLowerFrame->IsLayoutFrame() )
214  {
215  FormatLayout_( *static_cast<SwLayoutFrame*>(pLowerFrame) );
216  }
217  pLowerFrame = pLowerFrame->GetNext();
218  }
219 }
220 
227 {
228  if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) == nullptr )
229  {
230  // only Writer fly frames have content
231  return;
232  }
233 
234  SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
235  SwContentFrame* pContent = rFlyFrame.ContainsContent();
236 
237  while ( pContent )
238  {
239  // format content
240  pContent->OptCalc();
241 
242  // format floating screen objects at content text frame
243  // #i23129#, #i36347# - pass correct page frame to
244  // the object formatter
245  if ( pContent->IsTextFrame() &&
247  *(pContent->FindPageFrame()),
248  GetLayAction() ) )
249  {
250  // restart format with first content
251  pContent = rFlyFrame.ContainsContent();
252  continue;
253  }
254 
255  // continue with next content
256  pContent = pContent->GetNextContentFrame();
257  }
258 }
259 
265 {
266  // collect anchor object and its 'anchor' page number, if requested
268  {
269  mpPgNumAndTypeOfAnchors->Collect( _rAnchoredObj );
270  }
271 
272  if ( dynamic_cast<const SwFlyFrame*>( &_rAnchoredObj) != nullptr )
273  {
274  SwFlyFrame& rFlyFrame = static_cast<SwFlyFrame&>(_rAnchoredObj);
275  // --> #i34753# - reset flag, which prevents a positioning
276  if ( rFlyFrame.IsFlyLayFrame() )
277  {
278  static_cast<SwFlyLayFrame&>(rFlyFrame).SetNoMakePos( false );
279  }
280 
281  // #i81146# new loop control
282  int nLoopControlRuns = 0;
283  const int nLoopControlMax = 15;
284 
285  do {
286  if ( mpLayAction )
287  {
288  mpLayAction->FormatLayoutFly( &rFlyFrame );
289  // --> consider, if the layout action
290  // has to be restarted due to a delete of a page frame.
291  if ( mpLayAction->IsAgain() )
292  {
293  break;
294  }
295  }
296  else
297  {
298  FormatLayout_( rFlyFrame );
299  }
300  // --> #i34753# - prevent further positioning, if
301  // to-page|to-fly anchored Writer fly frame is already clipped.
302  if ( rFlyFrame.IsFlyLayFrame() && rFlyFrame.IsClipped() )
303  {
304  static_cast<SwFlyLayFrame&>(rFlyFrame).SetNoMakePos( true );
305  }
306  // #i23129#, #i36347# - pass correct page frame
307  // to the object formatter
309  *(rFlyFrame.FindPageFrame()),
310  mpLayAction );
311  if ( mpLayAction )
312  {
313  mpLayAction->FormatFlyContent( &rFlyFrame );
314  // --> consider, if the layout action
315  // has to be restarted due to a delete of a page frame.
316  if ( mpLayAction->IsAgain() )
317  {
318  break;
319  }
320  }
321  else
322  {
323  FormatObjContent( rFlyFrame );
324  }
325 
326  if ( ++nLoopControlRuns >= nLoopControlMax )
327  {
328  OSL_FAIL( "LoopControl in SwObjectFormatter::FormatObj_: Stage 3!!!" );
329  rFlyFrame.ValidateThisAndAllLowers( 2 );
330  nLoopControlRuns = 0;
331  }
332 
333  // --> #i57917#
334  // stop formatting of anchored object, if restart of layout process is requested.
335  } while ( !rFlyFrame.isFrameAreaDefinitionValid() &&
336  !_rAnchoredObj.RestartLayoutProcess() &&
337  rFlyFrame.GetAnchorFrame() == &GetAnchorFrame() );
338  }
339  else if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rAnchoredObj) != nullptr )
340  {
341  _rAnchoredObj.MakeObjPos();
342  }
343 }
344 
355 {
356  // --> #i26945#
357  SwFrame* pAnchorFrame( nullptr );
358  if ( GetAnchorFrame().IsTextFrame() &&
359  static_cast<SwTextFrame&>(GetAnchorFrame()).IsFollow() &&
360  _pMasterTextFrame )
361  {
362  pAnchorFrame = _pMasterTextFrame;
363  }
364  else
365  {
366  pAnchorFrame = &GetAnchorFrame();
367  }
368  if ( !pAnchorFrame->GetDrawObjs() )
369  {
370  // nothing to do, if no floating screen object is registered at the anchor frame.
371  return true;
372  }
373 
374  bool bSuccess( true );
375 
376  for ( size_t i = 0; i < pAnchorFrame->GetDrawObjs()->size(); ++i )
377  {
378  SwAnchoredObject* pAnchoredObj = (*pAnchorFrame->GetDrawObjs())[i];
379 
380  // check, if object's anchor is on the given page frame or
381  // object is registered at the given page frame.
382  // --> #i26945# - check, if the anchor character of the
383  // anchored object is located in a follow text frame. If this anchor
384  // follow text frame differs from the given anchor frame, the given
385  // anchor frame is a 'master' text frame of the anchor follow text frame.
386  // If the anchor follow text frame is in the same body as its 'master'
387  // text frame, do not format the anchored object.
388  // E.g., this situation can occur during the table row splitting algorithm.
389  SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame();
390  const bool bAnchoredAtFollowInSameBodyAsMaster =
391  pAnchorCharFrame && pAnchorCharFrame->IsFollow() &&
392  pAnchorCharFrame != pAnchoredObj->GetAnchorFrame() &&
393  pAnchorCharFrame->FindBodyFrame() ==
394  static_cast<SwTextFrame*>(pAnchoredObj->AnchorFrame())->FindBodyFrame();
395  if ( bAnchoredAtFollowInSameBodyAsMaster )
396  {
397  continue;
398  }
399  // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
400  // is replaced by method <FindPageFrameOfAnchor()>. It's return value
401  // have to be checked.
402  SwPageFrame* pPageFrameOfAnchor = pAnchoredObj->FindPageFrameOfAnchor();
403  OSL_ENSURE( pPageFrameOfAnchor,
404  "<SwObjectFormatter::FormatObjsAtFrame_()> - missing page frame." );
405  // --> #i26945#
406  if ( pPageFrameOfAnchor && pPageFrameOfAnchor == &mrPageFrame )
407  {
408  // if format of object fails, stop formatting and pass fail to
409  // calling method via the return value.
410  if ( !DoFormatObj( *pAnchoredObj ) )
411  {
412  bSuccess = false;
413  break;
414  }
415 
416  // considering changes at <pAnchorFrame->GetDrawObjs()> during
417  // format of the object.
418  if ( !pAnchorFrame->GetDrawObjs() ||
419  i > pAnchorFrame->GetDrawObjs()->size() )
420  {
421  break;
422  }
423  else
424  {
425  const size_t nActPosOfObj =
426  pAnchorFrame->GetDrawObjs()->ListPosOf( *pAnchoredObj );
427  if ( nActPosOfObj == pAnchorFrame->GetDrawObjs()->size() ||
428  nActPosOfObj > i )
429  {
430  --i;
431  }
432  else if ( nActPosOfObj < i )
433  {
434  i = nActPosOfObj;
435  }
436  }
437  }
438  } // end of loop on <pAnchorFrame->.GetDrawObjs()>
439 
440  return bSuccess;
441 }
442 
448 {
449  return mpPgNumAndTypeOfAnchors ? (*mpPgNumAndTypeOfAnchors)[_nIndex] : nullptr;
450 }
451 
456 sal_uInt32 SwObjectFormatter::GetPgNumOfCollected( const sal_uInt32 _nIndex )
457 {
458  return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->GetPageNum(_nIndex) : 0;
459 }
460 
465 bool SwObjectFormatter::IsCollectedAnchoredAtMaster( const sal_uInt32 _nIndex )
466 {
467  return mpPgNumAndTypeOfAnchors == nullptr
468  || mpPgNumAndTypeOfAnchors->AnchoredAtMaster(_nIndex);
469 }
470 
476 {
477  return mpPgNumAndTypeOfAnchors ? mpPgNumAndTypeOfAnchors->Count() : 0;
478 }
479 
480 /* 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:295
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
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:543
SwContentFrame * GetNextContentFrame() const
Definition: cntfrm.hxx:98
sal_uInt32 GetPageNum(sal_uInt32 _nIndex) const
void FormatFlyContent(const SwFlyFrame *)
Definition: layact.cxx:1810
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:1096
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1788
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:167
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:1210
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)
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:658
const SwFrame * Lower() const
Definition: layfrm.hxx:100
int i
const SwPageFrame & mrPageFrame
void FormatObj_(SwAnchoredObject &_rAnchoredObj)
performs the intrinsic format of a given floating screen object and its content.
sal_uInt32 Count() const
virtual SwFrame & GetAnchorFrame()=0
A page of the document layout.
Definition: pagefrm.hxx:40
std::vector< tEntry > maObjList
void OptCalc() const
Definition: frame.hxx:1056
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:1146
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:275
bool IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)
accessor to 'anchor' type of collected anchored object
void FormatLayoutFly(SwFlyFrame *)
Definition: layact.cxx:1399
void ValidateThisAndAllLowers(const sal_uInt16 nStage)
Definition: wsfrm.cxx:2017
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:657
SwFrame * GetNext()
Definition: frame.hxx:654
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects