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  OUString aName("dbg_lay.go");
246  SvFileStream aStream( aName, StreamMode::READ );
247  if( aStream.IsOpen() )
248  {
249  pImpl = new SwImplProtocol();
250  pImpl->FileInit();
251  }
252  aStream.Close();
253 }
254 
255 // End of logging
256 
258 {
259  if( pImpl )
260  {
261  delete pImpl;
262  pImpl = nullptr;
263  if( pFntCache )
264  pFntCache->Flush();
265  }
267 }
268 
270  : nTypes( FRM_ALL ),
271  nLineCount( 0 ), nMaxLines( USHRT_MAX ), nTestMode( 0 )
272 {
273  NewStream();
274 }
275 
277 {
278  OUString aName("dbg_lay.out");
279  nLineCount = 0;
280  pStream.reset( new SvFileStream( aName, StreamMode::WRITE | StreamMode::TRUNC ) );
281  if( pStream->GetError() )
282  {
283  pStream.reset();
284  }
285  return nullptr != pStream;
286 }
287 
289 {
290  if( pStream )
291  {
292  pStream->Close();
293  pStream.reset();
294  }
295  pFrameIds.reset();
296  aVars.clear();
297 }
298 
300 void SwImplProtocol::CheckLine( OString& rLine )
301 {
302  rLine = rLine.toAsciiLowerCase(); // upper/lower case is the same
303  rLine = rLine.replace( '\t', ' ' );
304  if( '#' == rLine[0] ) // comments start with '#'
305  return;
306  if( '[' == rLine[0] ) // section: FrameIds, type or function
307  {
308  OString aTmp = rLine.getToken(0, ']');
309  if (aTmp == "[frmid") // section FrameIds
310  {
311  nInitFile = 1;
312  pFrameIds.reset(); // default: log all frames
313  }
314  else if (aTmp == "[frmtype")// section types
315  {
316  nInitFile = 2;
317  nTypes = FRM_ALL; // default: log all frame types
318  }
319  else if (aTmp == "[record")// section functions
320  {
321  nInitFile = 3;
322  SwProtocol::SetRecord( PROT::FileInit );// default: don't log any function
323  }
324  else if (aTmp == "[test")// section functions
325  {
326  nInitFile = 4; // default:
327  nTestMode = 0; // log outside of test formatting
328  }
329  else if (aTmp == "[max")// Max number of lines
330  {
331  nInitFile = 5; // default:
333  }
334  else if (aTmp == "[var")// variables
335  {
336  nInitFile = 6;
337  }
338  else
339  nInitFile = 0; // oops: unknown section?
340  rLine = rLine.copy(aTmp.getLength() + 1);
341  }
342 
343  // spaces (or tabs) are the delimiter
344  sal_Int32 nIndex = 0;
345  do
346  {
347  OString aTok = rLine.getToken( 0, ' ', nIndex );
348  bool bNo = false;
349  if( !aTok.isEmpty() && '!' == aTok[0] )
350  {
351  bNo = true; // remove this function/type
352  aTok = aTok.copy(1);
353  }
354  if( !aTok.isEmpty() )
355  {
356  sal_Int64 nVal = aTok.toInt64();
357  switch ( nInitFile )
358  {
359  case 1: InsertFrame( sal_uInt16( nVal ) ); // add FrameId
360  break;
361  case 2: {
362  SwFrameType nNew = static_cast<SwFrameType>(nVal);
363  if( bNo )
364  nTypes &= ~nNew; // remove type
365  else
366  nTypes |= nNew; // add type
367  }
368  break;
369  case 3: {
370  PROT nOld = SwProtocol::Record();
371  if( bNo )
372  nOld &= ~PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
373  else
374  nOld |= PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
375  SwProtocol::SetRecord( nOld );
376  }
377  break;
378  case 4: {
379  sal_uInt8 nNew = static_cast<sal_uInt8>(nVal);
380  if( bNo )
381  nTestMode &= ~nNew; // reset test mode
382  else
383  nTestMode |= nNew; // set test mode
384  }
385  break;
386  case 5: nMaxLines = static_cast<sal_uInt16>(nVal);
387  break;
388  case 6: aVars.push_back( nVal );
389  break;
390  }
391  }
392  }
393  while ( nIndex >= 0 );
394 }
395 
398 {
399  OUString aName("dbg_lay.ini");
400  SvFileStream aStream( aName, StreamMode::READ );
401  if( aStream.IsOpen() )
402  {
403  OString aLine;
404  nInitFile = 0;
405  while( aStream.good() )
406  {
407  char c;
408  aStream.ReadChar( c );
409  if( '\n' == c || '\r' == c ) // line ending
410  {
411  aLine = aLine.trim();
412  if( !aLine.isEmpty() )
413  CheckLine( aLine ); // evaluate line
414  aLine.clear();
415  }
416  else
417  aLine += OString(c);
418  }
419  if( !aLine.isEmpty() )
420  CheckLine( aLine ); // evaluate last line
421  }
422  aStream.Close();
423 }
424 
426 static void lcl_Start(OStringBuffer& rOut, OStringBuffer& rLay, DbgAction nAction)
427 {
428  if( nAction == DbgAction::Start )
429  {
430  rLay.append(" ");
431  rOut.append(" On");
432  }
433  else if( nAction == DbgAction::End )
434  {
435  if( rLay.getLength() > 1 )
436  {
437  rLay.remove(rLay.getLength() - 2, rLay.getLength());
438  rOut.remove(0, 2);
439  }
440  rOut.append(" Off");
441  }
442 }
443 
446 static void lcl_Flags(OStringBuffer& rOut, const SwFrame* pFrame)
447 {
448  rOut.append(" ValidSize");
449  rOut.append(pFrame->isFrameAreaSizeValid() ? '+' : '-');
450  rOut.append(" ValidPos");
451  rOut.append(pFrame->isFrameAreaPositionValid() ? '+' : '-');
452  rOut.append(" ValidPrtArea");
453  rOut.append(pFrame->isFramePrintAreaValid() ? '+' : '-');
454 }
455 
456 static void lcl_Padded(OStringBuffer& rOut, const OString& s, size_t length)
457 {
458  if (sal_Int32(length) < s.getLength())
459  length = s.getLength();
460  rOut.append(s);
461  for (size_t i = 0; i < length - s.getLength(); i++)
462  {
463  rOut.append(" ");
464  }
465 }
466 
467 static void lcl_Padded(OStringBuffer& rOut, const long n, size_t length = 5)
468 {
469  char sz[RTL_STR_MAX_VALUEOFINT64];
470  rtl_str_valueOfInt64(sz, n, 10);
471  OString s(sz);
472  lcl_Padded(rOut, s, length);
473 }
474 
476 static void lcl_FrameRect(OStringBuffer& rOut, const char* hint, const SwRect& rect)
477 {
478  rOut.append("[");
479  rOut.append(hint);
480  rOut.append(":X:");
481  lcl_Padded(rOut, rect.Pos().X());
482  rOut.append(", Y:");
483  lcl_Padded(rOut, rect.Pos().Y());
484  rOut.append(", Width:");
485  lcl_Padded(rOut, rect.SSize().Width());
486  rOut.append(", Height:");
487  lcl_Padded(rOut, rect.SSize().Height());
488  rOut.append("] ");
489 }
490 
491 static OString lcl_TableInfo(const SwTabFrame* pTabFrame)
492 {
493  const SwTable* pTable = pTabFrame->GetTable();
494  const SwModify* pModify = pTable->GetRegisteredIn();
495  const SwFormat* pFormat = static_cast<const SwFormat*>(pModify);
496  const OUString& text = pFormat->GetName();
497  return OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
498 }
499 
500 static OString lcl_RowInfo(const SwRowFrame* pFrame)
501 {
502  // dummy, needs actual functionality...
503  if (pFrame == nullptr)
504  return "";
505  const SwTableLine* pTabLine = pFrame->GetTabLine();
506  if (pTabLine == nullptr)
507  return "";
508 
509  return "RowInfo";
510 }
511 
512 static OUString lcl_CellText(const SwCellFrame* pFrame)
513 {
514  OUString result;
515  int n = 0;
516 
517  const SwStartNode* pStartNode = pFrame->GetTabBox()->GetSttNd();
518  const SwEndNode* pEndNode = pStartNode->EndOfSectionNode();
519  const SwNodes& nodes = pStartNode->GetNodes();
520 
521  for (sal_uLong i = pStartNode->GetIndex(); i < nodes.Count(); i++)
522  {
523  SwNode* pNode = nodes[i];
524 
525  if (pNode->IsEndNode())
526  {
527  if (pNode->EndOfSectionNode() == pEndNode)
528  break;
529  }
530  else if (pNode->IsTextNode())
531  {
532  n++;
533  result += "Para:" + OUString::number(10) + " " +
534  pNode->GetTextNode()->GetText();
535  }
536  }
537 
538  return OUString::number(n) + " para(s):" + result;
539 }
540 
541 static OString lcl_CellInfo(const SwCellFrame* pFrame)
542 {
543  const OUString text = "CellInfo: " + pFrame->GetTabBox()->GetName() + " Text: " + lcl_CellText(pFrame);
544  return OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
545 }
546 
548 static void lcl_FrameType( OStringBuffer& rOut, const SwFrame* pFrame )
549 {
550  if( pFrame->IsTextFrame() )
551  rOut.append("SwTextFrame ");
552  else if( pFrame->IsLayoutFrame() )
553  {
554  if( pFrame->IsPageFrame() )
555  rOut.append("SwPageFrame ");
556  else if( pFrame->IsColumnFrame() )
557  rOut.append("SwColumnFrame ");
558  else if( pFrame->IsBodyFrame() )
559  {
560  if( pFrame->GetUpper() && pFrame->IsColBodyFrame() )
561  rOut.append("(Col)");
562  rOut.append("SwBodyFrame ");
563  }
564  else if( pFrame->IsRootFrame() )
565  rOut.append("SwRootFrame ");
566  else if( pFrame->IsCellFrame() )
567  rOut.append("SwCellFrame ");
568  else if( pFrame->IsTabFrame() )
569  rOut.append("SwTabFrame ");
570  else if( pFrame->IsRowFrame() )
571  rOut.append("SwRowFrame ");
572  else if( pFrame->IsSctFrame() )
573  rOut.append("SwSectionFrame ");
574  else if( pFrame->IsHeaderFrame() )
575  rOut.append("SwHeaderFrame ");
576  else if( pFrame->IsFooterFrame() )
577  rOut.append("SwFooterFrame ");
578  else if( pFrame->IsFootnoteFrame() )
579  rOut.append("SwFootnoteFrame ");
580  else if( pFrame->IsFootnoteContFrame() )
581  rOut.append("SwFootnoteContFrame ");
582  else if( pFrame->IsFlyFrame() )
583  rOut.append("SwFlyFrame ");
584  else
585  rOut.append("SwLayoutFrame ");
586  }
587  else if( pFrame->IsNoTextFrame() )
588  rOut.append("SwNoTextFrame");
589  else
590  rOut.append("Not impl. ");
591 }
592 
599 void SwImplProtocol::Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
600 {
601  sal_uInt16 nSpecial = 0;
602  if( nSpecial ) // the possible debugger manipulations
603  {
604  sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrame ));
605  switch ( nSpecial )
606  {
607  case 1: InsertFrame( nId ); break;
608  case 2: DeleteFrame( nId ); break;
609  case 3: pFrameIds.reset(); break;
610  case 4: pStream.reset(); break;
611  }
612  return;
613  }
614  if( !pStream && !NewStream() )
615  return; // still no stream
616 
617  if( pFrameIds && !pFrameIds->count( sal_uInt16(lcl_GetFrameId( pFrame )) ) )
618  return; // doesn't belong to the wished FrameIds
619 
620  if( !(pFrame->GetType() & nTypes) )
621  return; // the type is unwanted
622 
623  if( 1 == nTestMode && nFunction != PROT::TestFormat )
624  return; // we may only log inside a test formatting
625  bool bTmp = false;
626  OStringBuffer aOut(aLayer);
627  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(pFrame)));
628  aOut.append(' ');
629  lcl_FrameType( aOut, pFrame ); // then the frame type
630  switch ( nFunction ) // and the function
631  {
632  case PROT::MakeAll: aOut.append("SwFrame::MakeAll");
633  lcl_Start( aOut, aLayer, nAct );
634  if( nAct == DbgAction::Start )
635  lcl_Flags( aOut, pFrame );
636  break;
637  case PROT::MoveFwd: bTmp = true;
638  [[fallthrough]];
639  case PROT::MoveBack:
640  if (nFunction == (bTmp ? PROT::Init : PROT::FileInit))
641  aOut.append("SwFlowFrame::MoveFwd");
642  else
643  aOut.append("SwFlowFrame::MoveBwd");
644  lcl_Start( aOut, aLayer, nAct );
645  if( pParam )
646  {
647  aOut.append(' ');
648  aOut.append(static_cast<sal_Int32>(*static_cast<sal_uInt16*>(pParam)));
649  }
650  break;
651  case PROT::GrowTest:
652  aOut.append("SwFrame::Grow (test)");
653  lcl_Start( aOut, aLayer, nAct );
654  break;
655  case PROT::ShrinkTest:
656  aOut.append("SwFrame::Shrink (test)");
657  lcl_Start( aOut, aLayer, nAct );
658  break;
659  case PROT::AdjustN :
660  case PROT::Shrink: bTmp = true;
661  [[fallthrough]];
662  case PROT::Grow:
663  if (!bTmp)
664  aOut.append("SwFrame::Grow");
665  else
666  {
667  if (nFunction == PROT::Shrink)
668  aOut.append("SwFrame::Shrink");
669  else
670  aOut.append("SwFrame::AdjustNeighbourhood");
671  }
672  lcl_Start( aOut, aLayer, nAct );
673  if( pParam )
674  {
675  aOut.append(' ');
676  aOut.append(static_cast<sal_Int64>(*static_cast<long*>(pParam)));
677  }
678  break;
679  case PROT::PrintArea: aOut.append("PROT::PrintArea");
680  lcl_Start( aOut, aLayer, nAct );
681  break;
682  case PROT::Size: aOut.append("PROT::Size");
683  lcl_Start( aOut, aLayer, nAct );
684  aOut.append(' ');
685  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Height()));
686  break;
687  case PROT::Leaf: aOut.append("SwFrame::GetPrev/NextSctLeaf");
688  lcl_Start( aOut, aLayer, nAct );
689  aOut.append(' ');
690  if( pParam )
691  {
692  aOut.append(' ');
693  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame*>(pParam))));
694  }
695  break;
696  case PROT::FileInit: FileInit();
697  aOut.append("Initialize");
698  break;
699  case PROT::Section: SectFunc(aOut, nAct, pParam);
700  break;
701  case PROT::Cut: bTmp = true;
702  [[fallthrough]];
703  case PROT::Paste:
704  if (bTmp)
705  aOut.append("PROT::Cut from ");
706  else
707  aOut.append("PROT::Paste to ");
708  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame*>(pParam))));
709  break;
710  case PROT::TestFormat:
711  aOut.append("SwTextFrame::TestFormat");
712  lcl_Start( aOut, aLayer, nAct );
713  if( DbgAction::Start == nAct )
714  nTestMode |= 2;
715  else
716  nTestMode &= ~2;
717  break;
718  case PROT::FrmChanges:
719  {
720  SwRect& rFrame = *static_cast<SwRect*>(pParam);
721  if( pFrame->getFrameArea().Pos() != rFrame.Pos() )
722  {
723  aOut.append("PosChg: (");
724  aOut.append(static_cast<sal_Int64>(rFrame.Left()));
725  aOut.append(", ");
726  aOut.append(static_cast<sal_Int64>(rFrame.Top()));
727  aOut.append(") -> (");
728  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Left()));
729  aOut.append(", ");
730  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Top()));
731  aOut.append(") ");
732  }
733  if( pFrame->getFrameArea().Height() != rFrame.Height() )
734  {
735  aOut.append("Height: ");
736  aOut.append(static_cast<sal_Int64>(rFrame.Height()));
737  aOut.append(" -> ");
738  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Height()));
739  aOut.append(" ");
740  }
741  if( pFrame->getFrameArea().Width() != rFrame.Width() )
742  {
743  aOut.append("Width: ");
744  aOut.append(static_cast<sal_Int64>(rFrame.Width()));
745  aOut.append(" -> ");
746  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Width()));
747  aOut.append(' ');
748  }
749  break;
750  }
751  default: break;
752  }
753 
754  aOut.append(" ");
755  while (aOut.getLength() < 40) aOut.append(" ");
756  lcl_FrameRect(aOut, "SwFrame", pFrame->getFrameArea());
757 
758  aOut.append(" ");
759  while (aOut.getLength() < 90) aOut.append(" ");
760  lcl_FrameRect(aOut, "SwPrint", pFrame->getFramePrintArea());
761 
762  if (pFrame->IsTextFrame())
763  {
764  aOut.append(" ");
765  while (aOut.getLength() < 140) aOut.append(" ");
766  const OUString& text = static_cast<const SwTextFrame*>(pFrame)->GetText();
767  OString o = OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
768  aOut.append(o);
769  }
770  else if (pFrame->IsTabFrame())
771  {
772  const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pFrame);
773  aOut.append(lcl_TableInfo(pTabFrame));
774  }
775  else if (pFrame->IsRowFrame())
776  {
777  const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pFrame);
778  aOut.append(lcl_RowInfo(pRowFrame));
779 
780  }
781  else if (pFrame->IsCellFrame())
782  {
783  const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(pFrame);
784  aOut.append(lcl_CellInfo(pCellFrame));
785  }
786 
787  SAL_INFO("sw.layout.debug", aOut.getStr());
788  pStream->WriteOString( aOut.makeStringAndClear() );
789  (*pStream) << endl; // output
790  pStream->Flush(); // to the disk, so we can read it immediately
791  if( ++nLineCount >= nMaxLines ) // max number of lines reached?
792  {
793  SAL_WARN("sw.layout.debug", "max number of lines reached");
794  SwProtocol::SetRecord( PROT::FileInit ); // => end f logging
795  }
796 }
797 
799 void SwImplProtocol::SectFunc(OStringBuffer &rOut, DbgAction nAct, void const * pParam)
800 {
801  bool bTmp = false;
802  switch( nAct )
803  {
804  case DbgAction::Merge: rOut.append("Merge Section ");
805  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
806  break;
807  case DbgAction::CreateMaster: bTmp = true;
808  [[fallthrough]];
809  case DbgAction::CreateFollow: rOut.append("Create Section ");
810  if (bTmp)
811  rOut.append("Master to ");
812  else
813  rOut.append("Follow from ");
814  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
815  break;
816  case DbgAction::DelMaster: bTmp = true;
817  [[fallthrough]];
818  case DbgAction::DelFollow: rOut.append("Delete Section ");
819  if (bTmp)
820  rOut.append("Master to ");
821  else
822  rOut.append("Follow from ");
823  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
824  break;
825  default: break;
826  }
827 }
828 
836 void SwImplProtocol::InsertFrame( sal_uInt16 nId )
837 {
838  if( !pFrameIds )
839  pFrameIds.reset( new std::set<sal_uInt16> );
840  if( pFrameIds->count( nId ) )
841  return;
842  pFrameIds->insert( nId );
843 }
844 
846 void SwImplProtocol::DeleteFrame( sal_uInt16 nId )
847 {
848  if( !pFrameIds )
849  return;
850  pFrameIds->erase(nId);
851 }
852 
853 /*
854  * The task here is to find the right SwImplEnterLeave object based on the
855  * function; everything else is then done in his Ctor/Dtor.
856  */
857 SwEnterLeave::SwEnterLeave( const SwFrame* pFrame, PROT nFunc, DbgAction nAct, void* pPar )
858 {
859  if( !SwProtocol::Record( nFunc ) )
860  return;
861  switch( nFunc )
862  {
863  case PROT::AdjustN :
864  case PROT::Grow:
865  case PROT::Shrink : pImpl.reset( new SwSizeEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
866  case PROT::MoveFwd:
867  case PROT::MoveBack : pImpl.reset( new SwUpperEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
868  case PROT::FrmChanges : pImpl.reset( new SwFrameChangesLeave( pFrame, nFunc, nAct, pPar ) ); break;
869  default: pImpl.reset( new SwImplEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
870  }
871  pImpl->Enter();
872 }
873 
874 /* This is not inline because we don't want the SwImplEnterLeave definition inside
875  * dbg_lay.hxx.
876  */
878 {
879  if (pImpl)
880  pImpl->Leave();
881 }
882 
884 {
886 }
887 
889 {
891 }
892 
893 void SwSizeEnterLeave::Leave()
894 {
895  nFrameHeight = pFrame->getFrameArea().Height() - nFrameHeight;
896  SwProtocol::Record( pFrame, nFunction, DbgAction::End, &nFrameHeight );
897 }
898 
899 void SwUpperEnterLeave::Enter()
900 {
901  nFrameId = pFrame->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrame->GetUpper() )) : 0;
902  SwProtocol::Record( pFrame, nFunction, DbgAction::Start, &nFrameId );
903 }
904 
905 void SwUpperEnterLeave::Leave()
906 {
907  nFrameId = pFrame->GetUpper() ? sal_uInt16(lcl_GetFrameId( pFrame->GetUpper() )) : 0;
908  SwProtocol::Record( pFrame, nFunction, DbgAction::End, &nFrameId );
909 }
910 
911 void SwFrameChangesLeave::Enter()
912 {
913 }
914 
915 void SwFrameChangesLeave::Leave()
916 {
917  if( pFrame->getFrameArea() != aFrame )
919 }
920 
921 #endif // DBG_UTIL
922 
923 /* 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:300
static bool Start()
Definition: dbg_lay.hxx:69
static OString lcl_TableInfo(const SwTabFrame *pTabFrame)
Definition: dbg_lay.cxx:491
bool IsFootnoteFrame() const
Definition: frame.hxx:1180
SwEnterLeave(const SwFrame *pFrame, PROT nFunc, DbgAction nAct, void *pPar)
Definition: dbg_lay.cxx:857
void InsertFrame(sal_uInt16 nFrameId)
if pFrameIds==NULL all Frames will be logged.
Definition: dbg_lay.cxx:836
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:446
#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:799
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:846
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
bool IsColumnFrame() const
Definition: frame.hxx:1160
OUString GetName() const
Definition: swtable.cxx:1827
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:476
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:883
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:456
static OUString lcl_CellText(const SwCellFrame *pFrame)
Definition: dbg_lay.cxx:512
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:426
static OString lcl_CellInfo(const SwCellFrame *pFrame)
Definition: dbg_lay.cxx:541
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:548
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:888
SvStream & ReadChar(char &rChar)
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:439
static void Stop()
Definition: dbg_lay.cxx:257
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:253
SvStream & endl(SvStream &rStr)
#define SAL_INFO(area, stream)
OUString aName
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:599
bool NewStream()
Definition: dbg_lay.cxx:276
bool IsPageFrame() const
Definition: frame.hxx:1156
static OString lcl_RowInfo(const SwRowFrame *pFrame)
Definition: dbg_lay.cxx:500
bool good() const
def text(shape, st)
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:397
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:836
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