LibreOffice Module sw (master)  1
dbg_lay.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 
20 #ifdef DBG_UTIL
21 
22 /*
23  * And here's the description:
24  *
25  * The PROTOCOL macros allow you to log events in frame methods. In places where
26  * logging is useful either one of the PROTOCOL(...) or PROTOCOL_ENTER(...) can
27  * be used. PROTOCOL_ENTER(...) additionally logs the leaving of a method.
28  *
29  * The PROTOCOL macros accept the following parameters:
30  * 1. A pointer to an SwFrame (usually "this" or "rThis")
31  * 2. The function group i.e. PROT::MakeAll. This is used to decide (inline)
32  * whether this event shall be logged at the current time.
33  * 3. The action, usually 0. For example DbgAction::Start indents output in the log
34  * file and DbgAction::End stops the indentation. This allows for example
35  * PROTOCOL_ENTER to indent at the beginning of a method and stop indenting
36  * when leaving the method.
37  * 4. The fourth parameter is a void pointer which allows to pass anything
38  * which can be used in the log. A good example is PROT::Grow: this requires
39  * a pointer to the value which defines how much to grow.
40  *
41  * The log file is called "dbg_lay.out", which is saved in the current (BIN-)
42  * directory. The file contains lines with FrameId, function group and additional
43  * information.
44  *
45  * What exactly is going to be logged, can be defined as follows:
46  * 1. The static variable SwProtocol::nRecord contains the function groups
47  * which shall be logged.
48  * A value of i.e. PROT::Grow causes calls to SwFrame::Grow to be
49  * logged; PROT::MakeAll logs the calls to xxx::MakeAll.
50  * The PROT_XY values can be combined using binary OR, the default value
51  * is null - no method calls are logged.
52  * 2. The SwImplProtocol class contains a filter for frame types, only method
53  * call of frame types which are defined there are logged.
54  * The member nTypes can be set to values like SwFrameType::Page or SwFrameType::Section and
55  * may be combined using binary OR. The default values is 0xFFFF - meaning
56  * all frame types.
57  * 3. The SwImplProtocol class contains an ArrayPointer to FrameIds which need to be
58  * tracked. If the pointer is null, all frames will be logged; otherwise
59  * only frames of linked from the array will be logged.
60  *
61  * Code changes are needed to start logging; either change the default of nRecord
62  * in SwProtocol::Init() or change the debugger. There are several possible
63  * places in the debugger:
64  * 1. Set a breakpoint in SwProtocol::Init() and manipulate nRecord there, set
65  * FrameIds accordingly then start logging during program start.
66  * 2. Set a breakpoint before any PROTOCOL or PROTOCOL_ENTER macro during
67  * program execution, then set the lowest bit (PROT::Init) of
68  * SwProtocol::nRecord. This activates the function group of the following
69  * macro and causes it to be logged in the future.
70  * 3. There's a special case for 2: If one uses 2. in SwRootFrame::PaintSwFrame(..),
71  * the log settings are taken from the file "dbg_lay.ini"!
72  * In this INI-file you can have comment lines starting with a '#'.
73  * The sections "[frmid]", "[frmtype]" and "[record]" are relevant.
74  * In the [frmid] section, you can put FrameIds of the Frames to be logged.
75  * If there are no entries in this section, all Frames will be logged.
76  * In the [frmtype] section, the frame types which should be logged are
77  * listed; default is USHRT_MAX which means that all types are logged.
78  * It's possible to remove types from the list using '!' in front of a
79  * value. The value !0xC000 would for example exclude SwContentFrames from
80  * logging.
81  * In the [record] section the functions group which should be logged are
82  * listed; default is 0 which means that none are logged. It's also
83  * possible to remove functions using '!'.
84  * An example INI file:
85  * #Functions: all(0x0007ffff), except PrintArea (0x200)
86  * [record] 524287 !512
87  * [frmid]
88  * #the following FrameIds:
89  * 1 2 12 13 14 15
90  * #no layout frames, except ColumnFrames
91  * [frmtype] !0x3FFF 0x4
92  *
93  * As soon as the logging is in process, one can manipulate many things in
94  * SwImplProtocol::Record_(...) using a debugger, especially concerning
95  * frame types and FrameIds.
96  */
97 
98 #include <dbg_lay.hxx>
99 
100 #include <txtfrm.hxx>
101 #include <fntcache.hxx>
102 #include <tabfrm.hxx>
103 #include <rowfrm.hxx>
104 #include <cellfrm.hxx>
105 #include <layfrm.hxx>
106 #include <frame.hxx>
107 #include <swtable.hxx>
108 #include <ndtxt.hxx>
109 #include <rtl/strbuf.hxx>
110 #include <sal/log.hxx>
111 #include <tools/stream.hxx>
112 
115 
116 static sal_uLong lcl_GetFrameId( const SwFrame* pFrame )
117 {
118 #if OSL_DEBUG_LEVEL > 1
119  static bool bFrameId = false;
120  if( bFrameId )
121  return pFrame->GetFrameId();
122 #endif
123  if( pFrame )
124  return pFrame->GetFrameId();
125  return 0;
126 }
127 
129 {
130  std::unique_ptr<SvFileStream> pStream; // output stream
131  std::unique_ptr<std::set<sal_uInt16>> pFrameIds; // which FrameIds shall be logged ( NULL == all)
132  std::vector<long> aVars; // variables
133  OStringBuffer aLayer; // indentation of output (" " per start/end)
134  SwFrameType nTypes; // which types shall be logged
135  sal_uInt16 nLineCount; // printed lines
136  sal_uInt16 nMaxLines; // max lines to be printed
137  sal_uInt8 nInitFile; // range (FrameId,FrameType,Record) during reading of the INI file
138  sal_uInt8 nTestMode; // special for test formatting, logging may only be done in test formatting.
139  void Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam );
140  bool NewStream();
141  void CheckLine( OString& rLine );
142  static void SectFunc( OStringBuffer& rOut, DbgAction nAct, void const * pParam );
143 public:
144  SwImplProtocol();
145  ~SwImplProtocol();
146  // logging
147  void Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
148  { if( pStream ) Record_( pFrame, nFunction, nAct, pParam ); }
149  void InsertFrame( sal_uInt16 nFrameId ); // take FrameId for logging
150  void DeleteFrame( sal_uInt16 nFrameId ); // remove FrameId; don't log him anymore
151  void FileInit(); // read the INI file
152  void ChkStream() { if( !pStream ) NewStream(); }
153 };
154 
155 /* Through the PROTOCOL_ENTER macro a SwEnterLeave object gets created. If the
156  * current function should be logged a SwImplEnterLeace object gets created.
157  * The funny thing here is, that the Ctor of the Impl object is automatically
158  * called at the beginning of the function and the Dtor is automatically called
159  * when leaving the function. In the base implementation the Ctor calls only
160  * PROTOCOL(..) with DbgAction::Start and in the Dtor a PROTOCOL(..) with DbgAction::End.
161  * It's possible to derive from this class, for example to be able to document
162  * frame resize while leaving a function. To do this, one only needs to add the
163  * desired SwImplEnterLeave class in SwEnterLeave::Ctor().
164  */
165 
167 {
168 protected:
169  const SwFrame* pFrame; // the frame
170  PROT nFunction; // the function
171  DbgAction nAction; // the action if needed
172  void* pParam; // further parameter
173 public:
174  SwImplEnterLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
175  : pFrame( pF ), nFunction( nFunct ), nAction( nAct ), pParam( pPar ) {}
176  virtual ~SwImplEnterLeave() {}
177  virtual void Enter(); // message when entering
178  virtual void Leave(); // message when leaving
179 };
180 
181 namespace {
182 
183 class SwSizeEnterLeave : public SwImplEnterLeave
184 {
185  long nFrameHeight;
186 public:
187  SwSizeEnterLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
188  : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrameHeight( pF->getFrameArea().Height() ) {}
189 
190  virtual void Leave() override; // resize message
191 };
192 
193 class SwUpperEnterLeave : public SwImplEnterLeave
194 {
195  sal_uInt16 nFrameId;
196 public:
197  SwUpperEnterLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
198  : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrameId( 0 ) {}
199 
200  virtual void Enter() override; // message
201  virtual void Leave() override; // message of FrameId from upper
202 };
203 
204 class SwFrameChangesLeave : public SwImplEnterLeave
205 {
206  SwRect aFrame;
207 public:
208  SwFrameChangesLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
209  : SwImplEnterLeave( pF, nFunct, nAct, pPar ), aFrame( pF->getFrameArea() ) {}
210 
211  virtual void Enter() override; // no message
212  virtual void Leave() override; // message when resizing the Frame area
213 };
214 
215 }
216 
217 void SwProtocol::Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
218 {
219  if( Start() )
220  { // We reach this point if SwProtocol::nRecord is binary OR'd with PROT::Init(0x1) using the debugger
221  bool bFinit = false; // This gives the possibility to stop logging of this action in the debugger
222  if( bFinit )
223  {
224  nRecord &= ~nFunction; // Don't log this function any longer
225  nRecord &= ~PROT::Init; // Always reset PROT::Init
226  return;
227  }
228  nRecord |= nFunction; // Activate logging of this function
229  nRecord &= ~PROT::Init; // Always reset PROT::Init
230  if( pImpl )
231  pImpl->ChkStream();
232  }
233  if( !pImpl ) // Create Impl object if needed
234  pImpl = new SwImplProtocol();
235  pImpl->Record( pFrame, nFunction, nAct, pParam ); // ...and start logging
236 }
237 
238 // The following function gets called when pulling in the writer DLL through
239 // TextInit(..) and gives the possibility to release functions
240 // and/or FrameIds to the debugger
241 
243 {
245  SvFileStream aStream( "dbg_lay.go", StreamMode::READ );
246  if( aStream.IsOpen() )
247  {
248  pImpl = new SwImplProtocol();
249  pImpl->FileInit();
250  }
251  aStream.Close();
252 }
253 
254 // End of logging
255 
257 {
258  if( pImpl )
259  {
260  delete pImpl;
261  pImpl = nullptr;
262  if( pFntCache )
263  pFntCache->Flush();
264  }
266 }
267 
269  : nTypes( FRM_ALL ),
270  nLineCount( 0 ), nMaxLines( USHRT_MAX ), nTestMode( 0 )
271 {
272  NewStream();
273 }
274 
276 {
277  nLineCount = 0;
278  pStream.reset( new SvFileStream( "dbg_lay.out", StreamMode::WRITE | StreamMode::TRUNC ) );
279  if( pStream->GetError() )
280  {
281  pStream.reset();
282  }
283  return nullptr != pStream;
284 }
285 
287 {
288  if( pStream )
289  {
290  pStream->Close();
291  pStream.reset();
292  }
293  pFrameIds.reset();
294  aVars.clear();
295 }
296 
298 void SwImplProtocol::CheckLine( OString& rLine )
299 {
300  rLine = rLine.toAsciiLowerCase(); // upper/lower case is the same
301  rLine = rLine.replace( '\t', ' ' );
302  if( '#' == rLine[0] ) // comments start with '#'
303  return;
304  if( '[' == rLine[0] ) // section: FrameIds, type or function
305  {
306  OString aTmp = rLine.getToken(0, ']');
307  if (aTmp == "[frmid") // section FrameIds
308  {
309  nInitFile = 1;
310  pFrameIds.reset(); // default: log all frames
311  }
312  else if (aTmp == "[frmtype")// section types
313  {
314  nInitFile = 2;
315  nTypes = FRM_ALL; // default: log all frame types
316  }
317  else if (aTmp == "[record")// section functions
318  {
319  nInitFile = 3;
320  SwProtocol::SetRecord( PROT::FileInit );// default: don't log any function
321  }
322  else if (aTmp == "[test")// section functions
323  {
324  nInitFile = 4; // default:
325  nTestMode = 0; // log outside of test formatting
326  }
327  else if (aTmp == "[max")// Max number of lines
328  {
329  nInitFile = 5; // default:
331  }
332  else if (aTmp == "[var")// variables
333  {
334  nInitFile = 6;
335  }
336  else
337  nInitFile = 0; // oops: unknown section?
338  rLine = rLine.copy(aTmp.getLength() + 1);
339  }
340 
341  // spaces (or tabs) are the delimiter
342  sal_Int32 nIndex = 0;
343  do
344  {
345  OString aTok = rLine.getToken( 0, ' ', nIndex );
346  bool bNo = false;
347  if( !aTok.isEmpty() && '!' == aTok[0] )
348  {
349  bNo = true; // remove this function/type
350  aTok = aTok.copy(1);
351  }
352  if( !aTok.isEmpty() )
353  {
354  sal_Int64 nVal = aTok.toInt64();
355  switch ( nInitFile )
356  {
357  case 1: InsertFrame( sal_uInt16( nVal ) ); // add FrameId
358  break;
359  case 2: {
360  SwFrameType nNew = static_cast<SwFrameType>(nVal);
361  if( bNo )
362  nTypes &= ~nNew; // remove type
363  else
364  nTypes |= nNew; // add type
365  }
366  break;
367  case 3: {
368  PROT nOld = SwProtocol::Record();
369  if( bNo )
370  nOld &= ~PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
371  else
372  nOld |= PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
373  SwProtocol::SetRecord( nOld );
374  }
375  break;
376  case 4: {
377  sal_uInt8 nNew = static_cast<sal_uInt8>(nVal);
378  if( bNo )
379  nTestMode &= ~nNew; // reset test mode
380  else
381  nTestMode |= nNew; // set test mode
382  }
383  break;
384  case 5: nMaxLines = static_cast<sal_uInt16>(nVal);
385  break;
386  case 6: aVars.push_back( nVal );
387  break;
388  }
389  }
390  }
391  while ( nIndex >= 0 );
392 }
393 
396 {
397  SvFileStream aStream( "dbg_lay.ini", StreamMode::READ );
398  if( aStream.IsOpen() )
399  {
400  OString aLine;
401  nInitFile = 0;
402  while( aStream.good() )
403  {
404  char c;
405  aStream.ReadChar( c );
406  if( '\n' == c || '\r' == c ) // line ending
407  {
408  aLine = aLine.trim();
409  if( !aLine.isEmpty() )
410  CheckLine( aLine ); // evaluate line
411  aLine.clear();
412  }
413  else
414  aLine += OString(c);
415  }
416  if( !aLine.isEmpty() )
417  CheckLine( aLine ); // evaluate last line
418  }
419  aStream.Close();
420 }
421 
423 static void lcl_Start(OStringBuffer& rOut, OStringBuffer& rLay, DbgAction nAction)
424 {
425  if( nAction == DbgAction::Start )
426  {
427  rLay.append(" ");
428  rOut.append(" On");
429  }
430  else if( nAction == DbgAction::End )
431  {
432  if( rLay.getLength() > 1 )
433  {
434  rLay.remove(rLay.getLength() - 2, rLay.getLength());
435  rOut.remove(0, 2);
436  }
437  rOut.append(" Off");
438  }
439 }
440 
443 static void lcl_Flags(OStringBuffer& rOut, const SwFrame* pFrame)
444 {
445  rOut.append(" ValidSize");
446  rOut.append(pFrame->isFrameAreaSizeValid() ? '+' : '-');
447  rOut.append(" ValidPos");
448  rOut.append(pFrame->isFrameAreaPositionValid() ? '+' : '-');
449  rOut.append(" ValidPrtArea");
450  rOut.append(pFrame->isFramePrintAreaValid() ? '+' : '-');
451 }
452 
453 static void lcl_Padded(OStringBuffer& rOut, const OString& s, size_t length)
454 {
455  if (sal_Int32(length) < s.getLength())
456  length = s.getLength();
457  rOut.append(s);
458  for (size_t i = 0; i < length - s.getLength(); i++)
459  {
460  rOut.append(" ");
461  }
462 }
463 
464 static void lcl_Padded(OStringBuffer& rOut, const long n, size_t length = 5)
465 {
466  char sz[RTL_STR_MAX_VALUEOFINT64];
467  rtl_str_valueOfInt64(sz, n, 10);
468  OString s(sz);
469  lcl_Padded(rOut, s, length);
470 }
471 
473 static void lcl_FrameRect(OStringBuffer& rOut, const char* hint, const SwRect& rect)
474 {
475  rOut.append("[");
476  rOut.append(hint);
477  rOut.append(":X:");
478  lcl_Padded(rOut, rect.Pos().X());
479  rOut.append(", Y:");
480  lcl_Padded(rOut, rect.Pos().Y());
481  rOut.append(", Width:");
482  lcl_Padded(rOut, rect.SSize().Width());
483  rOut.append(", Height:");
484  lcl_Padded(rOut, rect.SSize().Height());
485  rOut.append("] ");
486 }
487 
488 static OString lcl_TableInfo(const SwTabFrame* pTabFrame)
489 {
490  const SwTable* pTable = pTabFrame->GetTable();
491  const SwModify* pModify = pTable->GetRegisteredIn();
492  const SwFormat* pFormat = static_cast<const SwFormat*>(pModify);
493  const OUString& text = pFormat->GetName();
494  return OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
495 }
496 
497 static OString lcl_RowInfo(const SwRowFrame* pFrame)
498 {
499  // dummy, needs actual functionality...
500  if (pFrame == nullptr)
501  return "";
502  const SwTableLine* pTabLine = pFrame->GetTabLine();
503  if (pTabLine == nullptr)
504  return "";
505 
506  return "RowInfo";
507 }
508 
509 static OUString lcl_CellText(const SwCellFrame* pFrame)
510 {
511  OUString result;
512  int n = 0;
513 
514  const SwStartNode* pStartNode = pFrame->GetTabBox()->GetSttNd();
515  const SwEndNode* pEndNode = pStartNode->EndOfSectionNode();
516  const SwNodes& nodes = pStartNode->GetNodes();
517 
518  for (sal_uLong i = pStartNode->GetIndex(); i < nodes.Count(); i++)
519  {
520  SwNode* pNode = nodes[i];
521 
522  if (pNode->IsEndNode())
523  {
524  if (pNode->EndOfSectionNode() == pEndNode)
525  break;
526  }
527  else if (pNode->IsTextNode())
528  {
529  n++;
530  result += "Para:" + OUString::number(10) + " " +
531  pNode->GetTextNode()->GetText();
532  }
533  }
534 
535  return OUString::number(n) + " para(s):" + result;
536 }
537 
538 static OString lcl_CellInfo(const SwCellFrame* pFrame)
539 {
540  const OUString text = "CellInfo: " + pFrame->GetTabBox()->GetName() + " Text: " + lcl_CellText(pFrame);
541  return OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
542 }
543 
545 static void lcl_FrameType( OStringBuffer& rOut, const SwFrame* pFrame )
546 {
547  if( pFrame->IsTextFrame() )
548  rOut.append("SwTextFrame ");
549  else if( pFrame->IsLayoutFrame() )
550  {
551  if( pFrame->IsPageFrame() )
552  rOut.append("SwPageFrame ");
553  else if( pFrame->IsColumnFrame() )
554  rOut.append("SwColumnFrame ");
555  else if( pFrame->IsBodyFrame() )
556  {
557  if( pFrame->GetUpper() && pFrame->IsColBodyFrame() )
558  rOut.append("(Col)");
559  rOut.append("SwBodyFrame ");
560  }
561  else if( pFrame->IsRootFrame() )
562  rOut.append("SwRootFrame ");
563  else if( pFrame->IsCellFrame() )
564  rOut.append("SwCellFrame ");
565  else if( pFrame->IsTabFrame() )
566  rOut.append("SwTabFrame ");
567  else if( pFrame->IsRowFrame() )
568  rOut.append("SwRowFrame ");
569  else if( pFrame->IsSctFrame() )
570  rOut.append("SwSectionFrame ");
571  else if( pFrame->IsHeaderFrame() )
572  rOut.append("SwHeaderFrame ");
573  else if( pFrame->IsFooterFrame() )
574  rOut.append("SwFooterFrame ");
575  else if( pFrame->IsFootnoteFrame() )
576  rOut.append("SwFootnoteFrame ");
577  else if( pFrame->IsFootnoteContFrame() )
578  rOut.append("SwFootnoteContFrame ");
579  else if( pFrame->IsFlyFrame() )
580  rOut.append("SwFlyFrame ");
581  else
582  rOut.append("SwLayoutFrame ");
583  }
584  else if( pFrame->IsNoTextFrame() )
585  rOut.append("SwNoTextFrame");
586  else
587  rOut.append("Not impl. ");
588 }
589 
596 void SwImplProtocol::Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
597 {
598  sal_uInt16 nSpecial = 0;
599  if( nSpecial ) // the possible debugger manipulations
600  {
601  sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrame ));
602  switch ( nSpecial )
603  {
604  case 1: InsertFrame( nId ); break;
605  case 2: DeleteFrame( nId ); break;
606  case 3: pFrameIds.reset(); break;
607  case 4: pStream.reset(); break;
608  }
609  return;
610  }
611  if( !pStream && !NewStream() )
612  return; // still no stream
613 
614  if( pFrameIds && !pFrameIds->count( sal_uInt16(lcl_GetFrameId( pFrame )) ) )
615  return; // doesn't belong to the wished FrameIds
616 
617  if( !(pFrame->GetType() & nTypes) )
618  return; // the type is unwanted
619 
620  if( 1 == nTestMode && nFunction != PROT::TestFormat )
621  return; // we may only log inside a test formatting
622  bool bTmp = false;
623  OStringBuffer aOut(aLayer);
624  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(pFrame)));
625  aOut.append(' ');
626  lcl_FrameType( aOut, pFrame ); // then the frame type
627  switch ( nFunction ) // and the function
628  {
629  case PROT::MakeAll: aOut.append("SwFrame::MakeAll");
630  lcl_Start( aOut, aLayer, nAct );
631  if( nAct == DbgAction::Start )
632  lcl_Flags( aOut, pFrame );
633  break;
634  case PROT::MoveFwd: bTmp = true;
635  [[fallthrough]];
636  case PROT::MoveBack:
637  if (nFunction == (bTmp ? PROT::Init : PROT::FileInit))
638  aOut.append("SwFlowFrame::MoveFwd");
639  else
640  aOut.append("SwFlowFrame::MoveBwd");
641  lcl_Start( aOut, aLayer, nAct );
642  if( pParam )
643  {
644  aOut.append(' ');
645  aOut.append(static_cast<sal_Int32>(*static_cast<sal_uInt16*>(pParam)));
646  }
647  break;
648  case PROT::GrowTest:
649  aOut.append("SwFrame::Grow (test)");
650  lcl_Start( aOut, aLayer, nAct );
651  break;
652  case PROT::ShrinkTest:
653  aOut.append("SwFrame::Shrink (test)");
654  lcl_Start( aOut, aLayer, nAct );
655  break;
656  case PROT::AdjustN :
657  case PROT::Shrink: bTmp = true;
658  [[fallthrough]];
659  case PROT::Grow:
660  if (!bTmp)
661  aOut.append("SwFrame::Grow");
662  else
663  {
664  if (nFunction == PROT::Shrink)
665  aOut.append("SwFrame::Shrink");
666  else
667  aOut.append("SwFrame::AdjustNeighbourhood");
668  }
669  lcl_Start( aOut, aLayer, nAct );
670  if( pParam )
671  {
672  aOut.append(' ');
673  aOut.append(static_cast<sal_Int64>(*static_cast<long*>(pParam)));
674  }
675  break;
676  case PROT::PrintArea: aOut.append("PROT::PrintArea");
677  lcl_Start( aOut, aLayer, nAct );
678  break;
679  case PROT::Size: aOut.append("PROT::Size");
680  lcl_Start( aOut, aLayer, nAct );
681  aOut.append(' ');
682  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Height()));
683  break;
684  case PROT::Leaf: aOut.append("SwFrame::GetPrev/NextSctLeaf");
685  lcl_Start( aOut, aLayer, nAct );
686  aOut.append(' ');
687  if( pParam )
688  {
689  aOut.append(' ');
690  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame*>(pParam))));
691  }
692  break;
693  case PROT::FileInit: FileInit();
694  aOut.append("Initialize");
695  break;
696  case PROT::Section: SectFunc(aOut, nAct, pParam);
697  break;
698  case PROT::Cut: bTmp = true;
699  [[fallthrough]];
700  case PROT::Paste:
701  if (bTmp)
702  aOut.append("PROT::Cut from ");
703  else
704  aOut.append("PROT::Paste to ");
705  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame*>(pParam))));
706  break;
707  case PROT::TestFormat:
708  aOut.append("SwTextFrame::TestFormat");
709  lcl_Start( aOut, aLayer, nAct );
710  if( DbgAction::Start == nAct )
711  nTestMode |= 2;
712  else
713  nTestMode &= ~2;
714  break;
715  case PROT::FrmChanges:
716  {
717  SwRect& rFrame = *static_cast<SwRect*>(pParam);
718  if( pFrame->getFrameArea().Pos() != rFrame.Pos() )
719  {
720  aOut.append("PosChg: (");
721  aOut.append(static_cast<sal_Int64>(rFrame.Left()));
722  aOut.append(", ");
723  aOut.append(static_cast<sal_Int64>(rFrame.Top()));
724  aOut.append(") -> (");
725  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Left()));
726  aOut.append(", ");
727  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Top()));
728  aOut.append(") ");
729  }
730  if( pFrame->getFrameArea().Height() != rFrame.Height() )
731  {
732  aOut.append("Height: ");
733  aOut.append(static_cast<sal_Int64>(rFrame.Height()));
734  aOut.append(" -> ");
735  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Height()));
736  aOut.append(" ");
737  }
738  if( pFrame->getFrameArea().Width() != rFrame.Width() )
739  {
740  aOut.append("Width: ");
741  aOut.append(static_cast<sal_Int64>(rFrame.Width()));
742  aOut.append(" -> ");
743  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Width()));
744  aOut.append(' ');
745  }
746  break;
747  }
748  default: break;
749  }
750 
751  aOut.append(" ");
752  while (aOut.getLength() < 40) aOut.append(" ");
753  lcl_FrameRect(aOut, "SwFrame", pFrame->getFrameArea());
754 
755  aOut.append(" ");
756  while (aOut.getLength() < 90) aOut.append(" ");
757  lcl_FrameRect(aOut, "SwPrint", pFrame->getFramePrintArea());
758 
759  if (pFrame->IsTextFrame())
760  {
761  aOut.append(" ");
762  while (aOut.getLength() < 140) aOut.append(" ");
763  const OUString& text = static_cast<const SwTextFrame*>(pFrame)->GetText();
764  OString o = OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
765  aOut.append(o);
766  }
767  else if (pFrame->IsTabFrame())
768  {
769  const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pFrame);
770  aOut.append(lcl_TableInfo(pTabFrame));
771  }
772  else if (pFrame->IsRowFrame())
773  {
774  const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pFrame);
775  aOut.append(lcl_RowInfo(pRowFrame));
776 
777  }
778  else if (pFrame->IsCellFrame())
779  {
780  const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(pFrame);
781  aOut.append(lcl_CellInfo(pCellFrame));
782  }
783 
784  SAL_INFO("sw.layout.debug", aOut.getStr());
785  pStream->WriteOString( aOut.makeStringAndClear() );
786  (*pStream) << endl; // output
787  pStream->Flush(); // to the disk, so we can read it immediately
788  if( ++nLineCount >= nMaxLines ) // max number of lines reached?
789  {
790  SAL_WARN("sw.layout.debug", "max number of lines reached");
791  SwProtocol::SetRecord( PROT::FileInit ); // => end f logging
792  }
793 }
794 
796 void SwImplProtocol::SectFunc(OStringBuffer &rOut, DbgAction nAct, void const * pParam)
797 {
798  bool bTmp = false;
799  switch( nAct )
800  {
801  case DbgAction::Merge: rOut.append("Merge Section ");
802  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
803  break;
804  case DbgAction::CreateMaster: bTmp = true;
805  [[fallthrough]];
806  case DbgAction::CreateFollow: rOut.append("Create Section ");
807  if (bTmp)
808  rOut.append("Master to ");
809  else
810  rOut.append("Follow from ");
811  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
812  break;
813  case DbgAction::DelMaster: bTmp = true;
814  [[fallthrough]];
815  case DbgAction::DelFollow: rOut.append("Delete Section ");
816  if (bTmp)
817  rOut.append("Master to ");
818  else
819  rOut.append("Follow from ");
820  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
821  break;
822  default: break;
823  }
824 }
825 
833 void SwImplProtocol::InsertFrame( sal_uInt16 nId )
834 {
835  if( !pFrameIds )
836  pFrameIds.reset( new std::set<sal_uInt16> );
837  if( pFrameIds->count( nId ) )
838  return;
839  pFrameIds->insert( nId );
840 }
841 
843 void SwImplProtocol::DeleteFrame( sal_uInt16 nId )
844 {
845  if( !pFrameIds )
846  return;
847  pFrameIds->erase(nId);
848 }
849 
850 /*
851  * The task here is to find the right SwImplEnterLeave object based on the
852  * function; everything else is then done in his Ctor/Dtor.
853  */
854 SwEnterLeave::SwEnterLeave( const SwFrame* pFrame, PROT nFunc, DbgAction nAct, void* pPar )
855 {
856  if( !SwProtocol::Record( nFunc ) )
857  return;
858  switch( nFunc )
859  {
860  case PROT::AdjustN :
861  case PROT::Grow:
862  case PROT::Shrink : pImpl.reset( new SwSizeEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
863  case PROT::MoveFwd:
864  case PROT::MoveBack : pImpl.reset( new SwUpperEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
865  case PROT::FrmChanges : pImpl.reset( new SwFrameChangesLeave( pFrame, nFunc, nAct, pPar ) ); break;
866  default: pImpl.reset( new SwImplEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
867  }
868  pImpl->Enter();
869 }
870 
871 /* This is not inline because we don't want the SwImplEnterLeave definition inside
872  * dbg_lay.hxx.
873  */
875 {
876  if (pImpl)
877  pImpl->Leave();
878 }
879 
881 {
883 }
884 
886 {
888 }
889 
890 void SwSizeEnterLeave::Leave()
891 {
892  nFrameHeight = pFrame->getFrameArea().Height() - nFrameHeight;
893  SwProtocol::Record( pFrame, nFunction, DbgAction::End, &nFrameHeight );
894 }
895 
896 void SwUpperEnterLeave::Enter()
897 {
898  nFrameId = pFrame->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrame->GetUpper() )) : 0;
899  SwProtocol::Record( pFrame, nFunction, DbgAction::Start, &nFrameId );
900 }
901 
902 void SwUpperEnterLeave::Leave()
903 {
904  nFrameId = pFrame->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrame->GetUpper() )) : 0;
905  SwProtocol::Record( pFrame, nFunction, DbgAction::End, &nFrameId );
906 }
907 
908 void SwFrameChangesLeave::Enter()
909 {
910 }
911 
912 void SwFrameChangesLeave::Leave()
913 {
914  if( pFrame->getFrameArea() != aFrame )
916 }
917 
918 #endif // DBG_UTIL
919 
920 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:682
Starts a section of nodes in the document model.
Definition: node.hxx:303
void Record(const SwFrame *pFrame, PROT nFunction, DbgAction nAct, void *pParam)
Definition: dbg_lay.cxx:147
Base class of the Writer layout elements.
Definition: frame.hxx:297
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:151
sal_uLong GetIndex() const
Definition: node.hxx:282
sal_Int32 nIndex
sal_uLong Count() const
Definition: ndarr.hxx:142
OStringBuffer aLayer
Definition: dbg_lay.cxx:133
std::unique_ptr< std::set< sal_uInt16 > > pFrameIds
Definition: dbg_lay.cxx:131
bool IsRootFrame() const
Definition: frame.hxx:1152
virtual ~SwImplEnterLeave()
Definition: dbg_lay.cxx:176
std::unique_ptr< SvFileStream > pStream
Definition: dbg_lay.cxx:130
std::vector< long > aVars
Definition: dbg_lay.cxx:132
const OUString & GetText() const
Definition: ndtxt.hxx:211
const SwTable * GetTable() const
Definition: tabfrm.hxx:144
SwFrameType GetType() const
Definition: frame.hxx:500
sal_uIntPtr sal_uLong
const SwRect & getFramePrintArea() const
Definition: frame.hxx:178
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:30
sal_Int64 n
void Height(long nNew)
Definition: swrect.hxx:191
sal_Int16 nId
PROT
Definition: dbg_lay.hxx:26
SwTableLine is one table row in the document model.
Definition: swtable.hxx:344
sal_uInt8 nTestMode
Definition: dbg_lay.cxx:138
void Pos(const Point &rNew)
Definition: swrect.hxx:169
static PROT Record()
Definition: dbg_lay.hxx:72
bool IsCellFrame() const
Definition: frame.hxx:1204
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
void CheckLine(OString &rLine)
analyze a line in the INI file
Definition: dbg_lay.cxx:298
static bool Start()
Definition: dbg_lay.hxx:69
static OString lcl_TableInfo(const SwTabFrame *pTabFrame)
Definition: dbg_lay.cxx:488
bool IsFootnoteFrame() const
Definition: frame.hxx:1180
SwEnterLeave(const SwFrame *pFrame, PROT nFunc, DbgAction nAct, void *pPar)
Definition: dbg_lay.cxx:854
void InsertFrame(sal_uInt16 nFrameId)
if pFrameIds==NULL all Frames will be logged.
Definition: dbg_lay.cxx:833
bool IsFlyFrame() const
Definition: frame.hxx:1188
void Top(const long nTop)
Definition: swrect.hxx:204
const SwTableBox * GetTabBox() const
Definition: cellfrm.hxx:52
const SwRect & getFrameArea() const
Definition: frame.hxx:177
SwImplEnterLeave(const SwFrame *pF, PROT nFunct, DbgAction nAct, void *pPar)
Definition: dbg_lay.cxx:174
length
const OUString & GetName() const
Definition: format.hxx:111
bool IsTextFrame() const
Definition: frame.hxx:1212
void Flush()
Definition: fntcache.cxx:161
static void lcl_Flags(OStringBuffer &rOut, const SwFrame *pFrame)
output the ValidSize-, ValidPos- and ValidPrtArea-Flag ("Sz","Ps","PA") of the frame; "+" stands for ...
Definition: dbg_lay.cxx:443
#define FRM_ALL
Definition: frame.hxx:100
static void SectFunc(OStringBuffer &rOut, DbgAction nAct, void const *pParam)
Handle the output of the SectionFrames.
Definition: dbg_lay.cxx:796
bool IsSctFrame() const
Definition: frame.hxx:1192
void DeleteFrame(sal_uInt16 nFrameId)
Removes a FrameId from the pFrameIds array, so that it won't be logged anymore.
Definition: dbg_lay.cxx:843
static void SetRecord(PROT nNew)
Definition: dbg_lay.hxx:73
SwFrameType nTypes
Definition: dbg_lay.cxx:134
DbgAction
Definition: dbg_lay.hxx:50
sal_uInt8 nInitFile
Definition: dbg_lay.cxx:137
Base class for various Writer styles.
Definition: format.hxx:43
exports com.sun.star. text
bool IsColumnFrame() const
Definition: frame.hxx:1160
OUString GetName() const
Definition: swtable.cxx:1830
static sal_uLong lcl_GetFrameId(const SwFrame *pFrame)
Definition: dbg_lay.cxx:116
static SwImplProtocol * pImpl
Definition: dbg_lay.hxx:68
int i
static void Init()
Definition: dbg_lay.cxx:242
SwFrameType
Definition: frame.hxx:72
static void lcl_FrameRect(OStringBuffer &rOut, const char *hint, const SwRect &rect)
output the frame as plain text.
Definition: dbg_lay.cxx:473
SwLayoutFrame * GetUpper()
Definition: frame.hxx:658
bool isFramePrintAreaValid() const
Definition: frame.hxx:166
bool IsRowFrame() const
Definition: frame.hxx:1200
static PROT nRecord
Definition: dbg_lay.hxx:67
sal_uInt16 nLineCount
Definition: dbg_lay.cxx:135
virtual void Enter()
Definition: dbg_lay.cxx:880
bool IsEndNode() const
Definition: node.hxx:632
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:693
bool isFrameAreaPositionValid() const
Definition: frame.hxx:164
void SSize(const Size &rNew)
Definition: swrect.hxx:178
bool isFrameAreaSizeValid() const
Definition: frame.hxx:165
SwFntCache * pFntCache
Definition: fntcache.cxx:64
static void lcl_Padded(OStringBuffer &rOut, const OString &s, size_t length)
Definition: dbg_lay.cxx:453
static OUString lcl_CellText(const SwCellFrame *pFrame)
Definition: dbg_lay.cxx:509
static void lcl_Start(OStringBuffer &rOut, OStringBuffer &rLay, DbgAction nAction)
enable indentation by two spaces during DbgAction::Start and disable it again at DbgAction::End.
Definition: dbg_lay.cxx:423
static OString lcl_CellInfo(const SwCellFrame *pFrame)
Definition: dbg_lay.cxx:538
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:110
static void lcl_FrameType(OStringBuffer &rOut, const SwFrame *pFrame)
output the type of the frame as plain text.
Definition: dbg_lay.cxx:545
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
bool IsLayoutFrame() const
Definition: frame.hxx:1148
void Left(const long nLeft)
Definition: swrect.hxx:195
virtual void Leave()
Definition: dbg_lay.cxx:885
SvStream & ReadChar(char &rChar)
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:439
static void Stop()
Definition: dbg_lay.cxx:256
bool IsTabFrame() const
Definition: frame.hxx:1196
void ChkStream()
Definition: dbg_lay.cxx:152
unsigned char sal_uInt8
void Width(long nNew)
Definition: swrect.hxx:187
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:254
SvStream & endl(SvStream &rStr)
#define SAL_INFO(area, stream)
bool IsNoTextFrame() const
Definition: frame.hxx:1216
const SwModify * GetRegisteredIn() const
Definition: calbck.hxx:157
bool IsColBodyFrame() const
These SwFrame inlines are here, so that frame.hxx does not need to include layfrm.hxx.
Definition: layfrm.hxx:209
void Record_(const SwFrame *pFrame, PROT nFunction, DbgAction nAct, void *pParam)
Is only called if the PROTOCOL macro finds out, that this function should be recorded (...
Definition: dbg_lay.cxx:596
bool NewStream()
Definition: dbg_lay.cxx:275
bool IsPageFrame() const
Definition: frame.hxx:1156
static OString lcl_RowInfo(const SwRowFrame *pFrame)
Definition: dbg_lay.cxx:497
bool good() const
sal_uInt16 nMaxLines
Definition: dbg_lay.cxx:136
void FileInit()
read the file "dbg_lay.ini" in the current directory and evaluate it.
Definition: dbg_lay.cxx:395
Any result
#define SAL_WARN(area, stream)
Ends a section of nodes in the document model.
Definition: node.hxx:333
const SwTableLine * GetTabLine() const
Definition: rowfrm.hxx:69
bool IsFootnoteContFrame() const
Definition: frame.hxx:1176
bool IsBodyFrame() const
Definition: frame.hxx:1184
const int nLineCount
bool IsTextNode() const
Definition: node.hxx:636
bool IsFooterFrame() const
Definition: frame.hxx:1172
const SwFrame * pFrame
Definition: dbg_lay.cxx:169
std::unique_ptr< SwImplEnterLeave > pImpl
Definition: dbg_lay.hxx:82
sal_uInt32 GetFrameId() const
Definition: frame.hxx:172
SwCellFrame is one table cell in the document layout.
Definition: cellfrm.hxx:30
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:844
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
bool IsOpen() const
bool IsHeaderFrame() const
Definition: frame.hxx:1168
DbgAction nAction
Definition: dbg_lay.cxx:171
Base class of the Writer document model elements.
Definition: node.hxx:79