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 <sal/log.hxx>
110 #include <tools/stream.hxx>
111 
114 
115 static sal_uLong lcl_GetFrameId( const SwFrame* pFrame )
116 {
117 #if OSL_DEBUG_LEVEL > 1
118  static bool bFrameId = false;
119  if( bFrameId )
120  return pFrame->GetFrameId();
121 #endif
122  if( pFrame )
123  return pFrame->GetFrameId();
124  return 0;
125 }
126 
128 {
129  std::unique_ptr<SvFileStream> pStream; // output stream
130  std::unique_ptr<std::set<sal_uInt16>> pFrameIds; // which FrameIds shall be logged ( NULL == all)
131  std::vector<long> aVars; // variables
132  OStringBuffer aLayer; // indentation of output (" " per start/end)
133  SwFrameType nTypes; // which types shall be logged
134  sal_uInt16 nLineCount; // printed lines
135  sal_uInt16 nMaxLines; // max lines to be printed
136  sal_uInt8 nInitFile; // range (FrameId,FrameType,Record) during reading of the INI file
137  sal_uInt8 nTestMode; // special for test formatting, logging may only be done in test formatting.
138  void Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam );
139  bool NewStream();
140  void CheckLine( OString& rLine );
141  static void SectFunc( OStringBuffer& rOut, DbgAction nAct, void const * pParam );
142 public:
143  SwImplProtocol();
144  ~SwImplProtocol();
145  // logging
146  void Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
147  { if( pStream ) Record_( pFrame, nFunction, nAct, pParam ); }
148  void InsertFrame( sal_uInt16 nFrameId ); // take FrameId for logging
149  void DeleteFrame( sal_uInt16 nFrameId ); // remove FrameId; don't log him anymore
150  void FileInit(); // read the INI file
151  void ChkStream() { if( !pStream ) NewStream(); }
152 };
153 
154 /* Through the PROTOCOL_ENTER macro a SwEnterLeave object gets created. If the
155  * current function should be logged a SwImplEnterLeace object gets created.
156  * The funny thing here is, that the Ctor of the Impl object is automatically
157  * called at the beginning of the function and the Dtor is automatically called
158  * when leaving the function. In the base implementation the Ctor calls only
159  * PROTOCOL(..) with DbgAction::Start and in the Dtor a PROTOCOL(..) with DbgAction::End.
160  * It's possible to derive from this class, for example to be able to document
161  * frame resize while leaving a function. To do this, one only needs to add the
162  * desired SwImplEnterLeave class in SwEnterLeave::Ctor().
163  */
164 
166 {
167 protected:
168  const SwFrame* pFrame; // the frame
169  PROT const nFunction; // the function
170  DbgAction const nAction; // the action if needed
171  void* const pParam; // further parameter
172 public:
173  SwImplEnterLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
174  : pFrame( pF ), nFunction( nFunct ), nAction( nAct ), pParam( pPar ) {}
175  virtual ~SwImplEnterLeave() {}
176  virtual void Enter(); // message when entering
177  virtual void Leave(); // message when leaving
178 };
179 
180 namespace {
181 
182 class SwSizeEnterLeave : public SwImplEnterLeave
183 {
184  long nFrameHeight;
185 public:
186  SwSizeEnterLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
187  : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrameHeight( pF->getFrameArea().Height() ) {}
188 
189  virtual void Leave() override; // resize message
190 };
191 
192 class SwUpperEnterLeave : public SwImplEnterLeave
193 {
194  sal_uInt16 nFrameId;
195 public:
196  SwUpperEnterLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
197  : SwImplEnterLeave( pF, nFunct, nAct, pPar ), nFrameId( 0 ) {}
198 
199  virtual void Enter() override; // message
200  virtual void Leave() override; // message of FrameId from upper
201 };
202 
203 class SwFrameChangesLeave : public SwImplEnterLeave
204 {
205  SwRect aFrame;
206 public:
207  SwFrameChangesLeave( const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar )
208  : SwImplEnterLeave( pF, nFunct, nAct, pPar ), aFrame( pF->getFrameArea() ) {}
209 
210  virtual void Enter() override; // no message
211  virtual void Leave() override; // message when resizing the Frame area
212 };
213 
214 }
215 
216 void SwProtocol::Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
217 {
218  if( Start() )
219  { // We reach this point if SwProtocol::nRecord is binary OR'd with PROT::Init(0x1) using the debugger
220  bool bFinit = false; // This gives the possibility to stop logging of this action in the debugger
221  if( bFinit )
222  {
223  nRecord &= ~nFunction; // Don't log this function any longer
224  nRecord &= ~PROT::Init; // Always reset PROT::Init
225  return;
226  }
227  nRecord |= nFunction; // Activate logging of this function
228  nRecord &= ~PROT::Init; // Always reset PROT::Init
229  if( pImpl )
230  pImpl->ChkStream();
231  }
232  if( !pImpl ) // Create Impl object if needed
233  pImpl = new SwImplProtocol();
234  pImpl->Record( pFrame, nFunction, nAct, pParam ); // ...and start logging
235 }
236 
237 // The following function gets called when pulling in the writer DLL through
238 // TextInit(..) and gives the possibility to release functions
239 // and/or FrameIds to the debugger
240 
242 {
244  OUString aName("dbg_lay.go");
245  SvFileStream aStream( aName, 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  OUString aName("dbg_lay.out");
278  nLineCount = 0;
279  pStream.reset( new SvFileStream( aName, StreamMode::WRITE | StreamMode::TRUNC ) );
280  if( pStream->GetError() )
281  {
282  pStream.reset();
283  }
284  return nullptr != pStream;
285 }
286 
288 {
289  if( pStream )
290  {
291  pStream->Close();
292  pStream.reset();
293  }
294  pFrameIds.reset();
295  aVars.clear();
296 }
297 
299 void SwImplProtocol::CheckLine( OString& rLine )
300 {
301  rLine = rLine.toAsciiLowerCase(); // upper/lower case is the same
302  rLine = rLine.replace( '\t', ' ' );
303  if( '#' == rLine[0] ) // comments start with '#'
304  return;
305  if( '[' == rLine[0] ) // section: FrameIds, type or function
306  {
307  OString aTmp = rLine.getToken(0, ']');
308  if (aTmp == "[frmid") // section FrameIds
309  {
310  nInitFile = 1;
311  pFrameIds.reset(); // default: log all frames
312  }
313  else if (aTmp == "[frmtype")// section types
314  {
315  nInitFile = 2;
316  nTypes = FRM_ALL; // default: log all frame types
317  }
318  else if (aTmp == "[record")// section functions
319  {
320  nInitFile = 3;
321  SwProtocol::SetRecord( PROT::FileInit );// default: don't log any function
322  }
323  else if (aTmp == "[test")// section functions
324  {
325  nInitFile = 4; // default:
326  nTestMode = 0; // log outside of test formatting
327  }
328  else if (aTmp == "[max")// Max number of lines
329  {
330  nInitFile = 5; // default:
332  }
333  else if (aTmp == "[var")// variables
334  {
335  nInitFile = 6;
336  }
337  else
338  nInitFile = 0; // oops: unknown section?
339  rLine = rLine.copy(aTmp.getLength() + 1);
340  }
341 
342  // spaces (or tabs) are the delimiter
343  sal_Int32 nIndex = 0;
344  do
345  {
346  OString aTok = rLine.getToken( 0, ' ', nIndex );
347  bool bNo = false;
348  if( !aTok.isEmpty() && '!' == aTok[0] )
349  {
350  bNo = true; // remove this function/type
351  aTok = aTok.copy(1);
352  }
353  if( !aTok.isEmpty() )
354  {
355  sal_Int64 nVal = aTok.toInt64();
356  switch ( nInitFile )
357  {
358  case 1: InsertFrame( sal_uInt16( nVal ) ); // add FrameId
359  break;
360  case 2: {
361  SwFrameType nNew = static_cast<SwFrameType>(nVal);
362  if( bNo )
363  nTypes &= ~nNew; // remove type
364  else
365  nTypes |= nNew; // add type
366  }
367  break;
368  case 3: {
369  PROT nOld = SwProtocol::Record();
370  if( bNo )
371  nOld &= ~PROT(nVal); // remove function
372  else
373  nOld |= PROT(nVal); // remove function
374  SwProtocol::SetRecord( nOld );
375  }
376  break;
377  case 4: {
378  sal_uInt8 nNew = static_cast<sal_uInt8>(nVal);
379  if( bNo )
380  nTestMode &= ~nNew; // reset test mode
381  else
382  nTestMode |= nNew; // set test mode
383  }
384  break;
385  case 5: nMaxLines = static_cast<sal_uInt16>(nVal);
386  break;
387  case 6: aVars.push_back( nVal );
388  break;
389  }
390  }
391  }
392  while ( nIndex >= 0 );
393 }
394 
397 {
398  OUString aName("dbg_lay.ini");
399  SvFileStream aStream( aName, StreamMode::READ );
400  if( aStream.IsOpen() )
401  {
402  OString aLine;
403  nInitFile = 0;
404  while( aStream.good() )
405  {
406  char c;
407  aStream.ReadChar( c );
408  if( '\n' == c || '\r' == c ) // line ending
409  {
410  aLine = aLine.trim();
411  if( !aLine.isEmpty() )
412  CheckLine( aLine ); // evaluate line
413  aLine.clear();
414  }
415  else
416  aLine += OString(c);
417  }
418  if( !aLine.isEmpty() )
419  CheckLine( aLine ); // evaluate last line
420  }
421  aStream.Close();
422 }
423 
425 static void lcl_Start(OStringBuffer& rOut, OStringBuffer& rLay, DbgAction nAction)
426 {
427  if( nAction == DbgAction::Start )
428  {
429  rLay.append(" ");
430  rOut.append(" On");
431  }
432  else if( nAction == DbgAction::End )
433  {
434  if( rLay.getLength() > 1 )
435  {
436  rLay.remove(rLay.getLength() - 2, rLay.getLength());
437  rOut.remove(0, 2);
438  }
439  rOut.append(" Off");
440  }
441 }
442 
445 static void lcl_Flags(OStringBuffer& rOut, const SwFrame* pFrame)
446 {
447  rOut.append(" ValidSize");
448  rOut.append(pFrame->isFrameAreaSizeValid() ? '+' : '-');
449  rOut.append(" ValidPos");
450  rOut.append(pFrame->isFrameAreaPositionValid() ? '+' : '-');
451  rOut.append(" ValidPrtArea");
452  rOut.append(pFrame->isFramePrintAreaValid() ? '+' : '-');
453 }
454 
455 static void lcl_Padded(OStringBuffer& rOut, const OString& s, size_t length)
456 {
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:146
Base class of the Writer layout elements.
Definition: frame.hxx:295
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
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:132
std::unique_ptr< std::set< sal_uInt16 > > pFrameIds
Definition: dbg_lay.cxx:130
bool IsRootFrame() const
Definition: frame.hxx:1150
virtual ~SwImplEnterLeave()
Definition: dbg_lay.cxx:175
std::unique_ptr< SvFileStream > pStream
Definition: dbg_lay.cxx:129
std::vector< long > aVars
Definition: dbg_lay.cxx:131
const OUString & GetText() const
Definition: ndtxt.hxx:210
void *const pParam
Definition: dbg_lay.cxx:171
const SwTable * GetTable() const
Definition: tabfrm.hxx:144
SwFrameType GetType() const
Definition: frame.hxx:498
sal_uIntPtr sal_uLong
const SwRect & getFramePrintArea() const
Definition: frame.hxx:176
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:189
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:137
void Pos(const Point &rNew)
Definition: swrect.hxx:167
static PROT Record()
Definition: dbg_lay.hxx:72
bool IsCellFrame() const
Definition: frame.hxx:1202
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
void CheckLine(OString &rLine)
analyze a line in the INI file
Definition: dbg_lay.cxx:299
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:1178
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:1186
void Top(const long nTop)
Definition: swrect.hxx:202
const SwTableBox * GetTabBox() const
Definition: cellfrm.hxx:52
const SwRect & getFrameArea() const
Definition: frame.hxx:175
SwImplEnterLeave(const SwFrame *pF, PROT nFunct, DbgAction nAct, void *pPar)
Definition: dbg_lay.cxx:173
length
const OUString & GetName() const
Definition: format.hxx:111
bool IsTextFrame() const
Definition: frame.hxx:1210
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:445
#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:1190
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:133
DbgAction
Definition: dbg_lay.hxx:50
sal_uInt8 nInitFile
Definition: dbg_lay.cxx:136
Base class for various Writer styles.
Definition: format.hxx:43
bool IsColumnFrame() const
Definition: frame.hxx:1158
OUString GetName() const
Definition: swtable.cxx:1827
static sal_uLong lcl_GetFrameId(const SwFrame *pFrame)
Definition: dbg_lay.cxx:115
static SwImplProtocol * pImpl
Definition: dbg_lay.hxx:68
static void Init()
Definition: dbg_lay.cxx:241
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
PROT const nFunction
Definition: dbg_lay.cxx:169
int i
SwLayoutFrame * GetUpper()
Definition: frame.hxx:656
bool isFramePrintAreaValid() const
Definition: frame.hxx:164
bool IsRowFrame() const
Definition: frame.hxx:1198
static PROT nRecord
Definition: dbg_lay.hxx:67
sal_uInt16 nLineCount
Definition: dbg_lay.cxx:134
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:162
void SSize(const Size &rNew)
Definition: swrect.hxx:176
bool isFrameAreaSizeValid() const
Definition: frame.hxx:163
SwFntCache * pFntCache
Definition: fntcache.cxx:64
static void lcl_Padded(OStringBuffer &rOut, const OString &s, size_t length)
Definition: dbg_lay.cxx:455
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:425
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
DbgAction const nAction
Definition: dbg_lay.cxx:170
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
bool IsLayoutFrame() const
Definition: frame.hxx:1146
void Left(const long nLeft)
Definition: swrect.hxx:193
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:1194
void ChkStream()
Definition: dbg_lay.cxx:151
unsigned char sal_uInt8
void Width(long nNew)
Definition: swrect.hxx:185
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:1214
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:1154
static OString lcl_RowInfo(const SwRowFrame *pFrame)
Definition: dbg_lay.cxx:497
bool good() const
def text(shape, st)
sal_uInt16 nMaxLines
Definition: dbg_lay.cxx:135
void FileInit()
read the file "dbg_lay.ini" in the current directory and evaluate it.
Definition: dbg_lay.cxx:396
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:68
bool IsFootnoteContFrame() const
Definition: frame.hxx:1174
bool IsBodyFrame() const
Definition: frame.hxx:1182
const int nLineCount
bool IsTextNode() const
Definition: node.hxx:636
bool IsFooterFrame() const
Definition: frame.hxx:1170
const SwFrame * pFrame
Definition: dbg_lay.cxx:168
std::unique_ptr< SwImplEnterLeave > pImpl
Definition: dbg_lay.hxx:82
sal_uInt32 GetFrameId() const
Definition: frame.hxx:170
SwCellFrame is one table cell in the document layout.
Definition: cellfrm.hxx:30
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:842
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
bool IsOpen() const
bool IsHeaderFrame() const
Definition: frame.hxx:1166
Base class of the Writer document model elements.
Definition: node.hxx:79