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> m_pStream; // output stream
131  std::unique_ptr<std::set<sal_uInt16>>
132  m_pFrameIds; // which FrameIds shall be logged ( NULL == all)
133  std::vector<long> m_aVars; // variables
134  OStringBuffer m_aLayer; // indentation of output (" " per start/end)
135  SwFrameType m_nTypes; // which types shall be logged
136  sal_uInt16 m_nLineCount; // printed lines
137  sal_uInt16 m_nMaxLines; // max lines to be printed
138  sal_uInt8 m_nInitFile; // range (FrameId,FrameType,Record) during reading of the INI file
139  sal_uInt8
140  m_nTestMode; // special for test formatting, logging may only be done in test formatting.
141  void Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam );
142  bool NewStream();
143  void CheckLine( OString& rLine );
144  static void SectFunc( OStringBuffer& rOut, DbgAction nAct, void const * pParam );
145 public:
146  SwImplProtocol();
147  ~SwImplProtocol();
148  // logging
149  void Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
150  {
151  if (m_pStream)
152  Record_(pFrame, nFunction, nAct, pParam);
153  }
154  void InsertFrame( sal_uInt16 nFrameId ); // take FrameId for logging
155  void DeleteFrame( sal_uInt16 nFrameId ); // remove FrameId; don't log him anymore
156  void FileInit(); // read the INI file
157  void ChkStream() {
158  if (!m_pStream)
159  NewStream();
160  }
161 };
162 
163 /* Through the PROTOCOL_ENTER macro a SwEnterLeave object gets created. If the
164  * current function should be logged as SwImplEnterLeace object gets created.
165  * The funny thing here is, that the Ctor of the Impl object is automatically
166  * called at the beginning of the function and the Dtor is automatically called
167  * when leaving the function. In the base implementation the Ctor calls only
168  * PROTOCOL(..) with DbgAction::Start and in the Dtor a PROTOCOL(..) with DbgAction::End.
169  * It's possible to derive from this class, for example to be able to document
170  * frame resize while leaving a function. To do this, one only needs to add the
171  * desired SwImplEnterLeave class in SwEnterLeave::Ctor().
172  */
173 
175 {
176 protected:
177  const SwFrame* m_pFrame; // the frame
178  PROT m_nFunction; // the function
179  DbgAction m_nAction; // the action if needed
180  void* m_pParam; // further parameter
181 public:
182  SwImplEnterLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
183  : m_pFrame(pF)
184  , m_nFunction(nFunct)
185  , m_nAction(nAct)
186  , m_pParam(pPar)
187  {
188  }
189  virtual ~SwImplEnterLeave() {}
190  virtual void Enter(); // message when entering
191  virtual void Leave(); // message when leaving
192 };
193 
194 namespace {
195 
196 class SwSizeEnterLeave : public SwImplEnterLeave
197 {
198  tools::Long m_nFrameHeight;
199 
200 public:
201  SwSizeEnterLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
202  : SwImplEnterLeave(pF, nFunct, nAct, pPar)
203  , m_nFrameHeight(pF->getFrameArea().Height())
204  {
205  }
206 
207  virtual void Leave() override; // resize message
208 };
209 
210 class SwUpperEnterLeave : public SwImplEnterLeave
211 {
212  sal_uInt16 m_nFrameId;
213 
214 public:
215  SwUpperEnterLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
216  : SwImplEnterLeave(pF, nFunct, nAct, pPar)
217  , m_nFrameId(0)
218  {
219  }
220 
221  virtual void Enter() override; // message
222  virtual void Leave() override; // message of FrameId from upper
223 };
224 
225 class SwFrameChangesLeave : public SwImplEnterLeave
226 {
227  SwRect m_aFrame;
228 
229 public:
230  SwFrameChangesLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
231  : SwImplEnterLeave(pF, nFunct, nAct, pPar)
232  , m_aFrame(pF->getFrameArea())
233  {
234  }
235 
236  virtual void Enter() override; // no message
237  virtual void Leave() override; // message when resizing the Frame area
238 };
239 
240 }
241 
242 void SwProtocol::Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
243 {
244  if( Start() )
245  { // We reach this point if SwProtocol::nRecord is binary OR'd with PROT::Init(0x1) using the debugger
246  bool bFinit = false; // This gives the possibility to stop logging of this action in the debugger
247  if( bFinit )
248  {
249  s_nRecord &= ~nFunction; // Don't log this function any longer
250  s_nRecord &= ~PROT::Init; // Always reset PROT::Init
251  return;
252  }
253  s_nRecord |= nFunction; // Activate logging of this function
254  s_nRecord &= ~PROT::Init; // Always reset PROT::Init
255  if( s_pImpl )
256  s_pImpl->ChkStream();
257  }
258  if( !s_pImpl ) // Create Impl object if needed
259  s_pImpl = new SwImplProtocol();
260  s_pImpl->Record( pFrame, nFunction, nAct, pParam ); // ...and start logging
261 }
262 
263 // The following function gets called when pulling in the writer DLL through
264 // TextInit(..) and gives the possibility to release functions
265 // and/or FrameIds to the debugger
266 
268 {
270  SvFileStream aStream( "dbg_lay.go", StreamMode::READ );
271  if( aStream.IsOpen() )
272  {
273  s_pImpl = new SwImplProtocol();
274  s_pImpl->FileInit();
275  }
276  aStream.Close();
277 }
278 
279 // End of logging
280 
282 {
283  if( s_pImpl )
284  {
285  delete s_pImpl;
286  s_pImpl = nullptr;
287  if( pFntCache )
288  pFntCache->Flush();
289  }
291 }
292 
294  : m_nTypes(FRM_ALL)
295  , m_nLineCount(0)
296  , m_nMaxLines(USHRT_MAX)
297  , m_nTestMode(0)
298 {
299  NewStream();
300 }
301 
303 {
304  m_nLineCount = 0;
305  m_pStream.reset(new SvFileStream("dbg_lay.out", StreamMode::WRITE | StreamMode::TRUNC));
306  if (m_pStream->GetError())
307  {
308  m_pStream.reset();
309  }
310  return nullptr != m_pStream;
311 }
312 
314 {
315  if (m_pStream)
316  {
317  m_pStream->Close();
318  m_pStream.reset();
319  }
320  m_pFrameIds.reset();
321  m_aVars.clear();
322 }
323 
325 void SwImplProtocol::CheckLine( OString& rLine )
326 {
327  rLine = rLine.toAsciiLowerCase(); // upper/lower case is the same
328  rLine = rLine.replace( '\t', ' ' );
329  if( '#' == rLine[0] ) // comments start with '#'
330  return;
331  if( '[' == rLine[0] ) // section: FrameIds, type or function
332  {
333  OString aTmp = rLine.getToken(0, ']');
334  if (aTmp == "[frmid") // section FrameIds
335  {
336  m_nInitFile = 1;
337  m_pFrameIds.reset(); // default: log all frames
338  }
339  else if (aTmp == "[frmtype")// section types
340  {
341  m_nInitFile = 2;
342  m_nTypes = FRM_ALL; // default: log all frame types
343  }
344  else if (aTmp == "[record")// section functions
345  {
346  m_nInitFile = 3;
347  SwProtocol::SetRecord( PROT::FileInit );// default: don't log any function
348  }
349  else if (aTmp == "[test")// section functions
350  {
351  m_nInitFile = 4; // default:
352  m_nTestMode = 0; // log outside of test formatting
353  }
354  else if (aTmp == "[max")// Max number of lines
355  {
356  m_nInitFile = 5; // default:
358  }
359  else if (aTmp == "[var")// variables
360  {
361  m_nInitFile = 6;
362  }
363  else
364  m_nInitFile = 0; // oops: unknown section?
365  rLine = rLine.copy(aTmp.getLength() + 1);
366  }
367 
368  // spaces (or tabs) are the delimiter
369  sal_Int32 nIndex = 0;
370  do
371  {
372  OString aTok = rLine.getToken( 0, ' ', nIndex );
373  bool bNo = false;
374  if( !aTok.isEmpty() && '!' == aTok[0] )
375  {
376  bNo = true; // remove this function/type
377  aTok = aTok.copy(1);
378  }
379  if( !aTok.isEmpty() )
380  {
381  sal_Int64 nVal = aTok.toInt64();
382  switch (m_nInitFile)
383  {
384  case 1: InsertFrame( sal_uInt16( nVal ) ); // add FrameId
385  break;
386  case 2: {
387  SwFrameType nNew = static_cast<SwFrameType>(nVal);
388  if( bNo )
389  m_nTypes &= ~nNew; // remove type
390  else
391  m_nTypes |= nNew; // add type
392  }
393  break;
394  case 3: {
395  PROT nOld = SwProtocol::Record();
396  if( bNo )
397  nOld &= ~PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
398  else
399  nOld |= PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
400  SwProtocol::SetRecord( nOld );
401  }
402  break;
403  case 4: {
404  sal_uInt8 nNew = static_cast<sal_uInt8>(nVal);
405  if( bNo )
406  m_nTestMode &= ~nNew; // reset test mode
407  else
408  m_nTestMode |= nNew; // set test mode
409  }
410  break;
411  case 5:
412  m_nMaxLines = static_cast<sal_uInt16>(nVal);
413  break;
414  case 6:
415  m_aVars.push_back(nVal);
416  break;
417  }
418  }
419  }
420  while ( nIndex >= 0 );
421 }
422 
425 {
426  SvFileStream aStream( "dbg_lay.ini", StreamMode::READ );
427  if( aStream.IsOpen() )
428  {
429  OString aLine;
430  m_nInitFile = 0;
431  while( aStream.good() )
432  {
433  char c;
434  aStream.ReadChar( c );
435  if( '\n' == c || '\r' == c ) // line ending
436  {
437  aLine = aLine.trim();
438  if( !aLine.isEmpty() )
439  CheckLine( aLine ); // evaluate line
440  aLine.clear();
441  }
442  else
443  aLine += OString(c);
444  }
445  if( !aLine.isEmpty() )
446  CheckLine( aLine ); // evaluate last line
447  }
448  aStream.Close();
449 }
450 
452 static void lcl_Start(OStringBuffer& rOut, OStringBuffer& rLay, DbgAction nAction)
453 {
454  if( nAction == DbgAction::Start )
455  {
456  rLay.append(" ");
457  rOut.append(" On");
458  }
459  else if( nAction == DbgAction::End )
460  {
461  if( rLay.getLength() > 1 )
462  {
463  rLay.remove(rLay.getLength() - 2, rLay.getLength());
464  rOut.remove(0, 2);
465  }
466  rOut.append(" Off");
467  }
468 }
469 
472 static void lcl_Flags(OStringBuffer& rOut, const SwFrame* pFrame)
473 {
474  rOut.append(" ValidSize");
475  rOut.append(pFrame->isFrameAreaSizeValid() ? '+' : '-');
476  rOut.append(" ValidPos");
477  rOut.append(pFrame->isFrameAreaPositionValid() ? '+' : '-');
478  rOut.append(" ValidPrtArea");
479  rOut.append(pFrame->isFramePrintAreaValid() ? '+' : '-');
480 }
481 
482 static void lcl_Padded(OStringBuffer& rOut, const OString& s, size_t length)
483 {
484  if (sal_Int32(length) < s.getLength())
485  length = s.getLength();
486  rOut.append(s);
487  for (size_t i = 0; i < length - s.getLength(); i++)
488  {
489  rOut.append(" ");
490  }
491 }
492 
493 static void lcl_Padded(OStringBuffer& rOut, const tools::Long n, size_t length = 5)
494 {
495  char sz[RTL_STR_MAX_VALUEOFINT64];
496  rtl_str_valueOfInt64(sz, n, 10);
497  OString s(sz);
498  lcl_Padded(rOut, s, length);
499 }
500 
502 static void lcl_FrameRect(OStringBuffer& rOut, const char* hint, const SwRect& rect)
503 {
504  rOut.append("[");
505  rOut.append(hint);
506  rOut.append(":X:");
507  lcl_Padded(rOut, rect.Pos().X());
508  rOut.append(", Y:");
509  lcl_Padded(rOut, rect.Pos().Y());
510  rOut.append(", Width:");
511  lcl_Padded(rOut, rect.SSize().Width());
512  rOut.append(", Height:");
513  lcl_Padded(rOut, rect.SSize().Height());
514  rOut.append("] ");
515 }
516 
517 static OString lcl_TableInfo(const SwTabFrame* pTabFrame)
518 {
519  const SwTable* pTable = pTabFrame->GetTable();
520  const SwModify* pModify = pTable->GetRegisteredIn();
521  const SwFormat* pFormat = static_cast<const SwFormat*>(pModify);
522  const OUString& text = pFormat->GetName();
523  return OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
524 }
525 
526 static OString lcl_RowInfo(const SwRowFrame* pFrame)
527 {
528  // dummy, needs actual functionality...
529  if (pFrame == nullptr)
530  return "";
531  const SwTableLine* pTabLine = pFrame->GetTabLine();
532  if (pTabLine == nullptr)
533  return "";
534 
535  return "RowInfo";
536 }
537 
538 static OUString lcl_CellText(const SwCellFrame* pFrame)
539 {
540  OUString result;
541  int n = 0;
542 
543  const SwStartNode* pStartNode = pFrame->GetTabBox()->GetSttNd();
544  const SwEndNode* pEndNode = pStartNode->EndOfSectionNode();
545  const SwNodes& nodes = pStartNode->GetNodes();
546 
547  for (sal_uLong i = pStartNode->GetIndex(); i < nodes.Count(); i++)
548  {
549  SwNode* pNode = nodes[i];
550 
551  if (pNode->IsEndNode())
552  {
553  if (pNode->EndOfSectionNode() == pEndNode)
554  break;
555  }
556  else if (pNode->IsTextNode())
557  {
558  n++;
559  result += "Para:" + OUString::number(10) + " " +
560  pNode->GetTextNode()->GetText();
561  }
562  }
563 
564  return OUString::number(n) + " para(s):" + result;
565 }
566 
567 static OString lcl_CellInfo(const SwCellFrame* pFrame)
568 {
569  const OUString text = "CellInfo: " + pFrame->GetTabBox()->GetName() + " Text: " + lcl_CellText(pFrame);
570  return OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
571 }
572 
574 static void lcl_FrameType( OStringBuffer& rOut, const SwFrame* pFrame )
575 {
576  if( pFrame->IsTextFrame() )
577  rOut.append("SwTextFrame ");
578  else if( pFrame->IsLayoutFrame() )
579  {
580  if( pFrame->IsPageFrame() )
581  rOut.append("SwPageFrame ");
582  else if( pFrame->IsColumnFrame() )
583  rOut.append("SwColumnFrame ");
584  else if( pFrame->IsBodyFrame() )
585  {
586  if( pFrame->GetUpper() && pFrame->IsColBodyFrame() )
587  rOut.append("(Col)");
588  rOut.append("SwBodyFrame ");
589  }
590  else if( pFrame->IsRootFrame() )
591  rOut.append("SwRootFrame ");
592  else if( pFrame->IsCellFrame() )
593  rOut.append("SwCellFrame ");
594  else if( pFrame->IsTabFrame() )
595  rOut.append("SwTabFrame ");
596  else if( pFrame->IsRowFrame() )
597  rOut.append("SwRowFrame ");
598  else if( pFrame->IsSctFrame() )
599  rOut.append("SwSectionFrame ");
600  else if( pFrame->IsHeaderFrame() )
601  rOut.append("SwHeaderFrame ");
602  else if( pFrame->IsFooterFrame() )
603  rOut.append("SwFooterFrame ");
604  else if( pFrame->IsFootnoteFrame() )
605  rOut.append("SwFootnoteFrame ");
606  else if( pFrame->IsFootnoteContFrame() )
607  rOut.append("SwFootnoteContFrame ");
608  else if( pFrame->IsFlyFrame() )
609  rOut.append("SwFlyFrame ");
610  else
611  rOut.append("SwLayoutFrame ");
612  }
613  else if( pFrame->IsNoTextFrame() )
614  rOut.append("SwNoTextFrame");
615  else
616  rOut.append("Not impl. ");
617 }
618 
625 void SwImplProtocol::Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
626 {
627  sal_uInt16 nSpecial = 0;
628  if( nSpecial ) // the possible debugger manipulations
629  {
630  sal_uInt16 nId = sal_uInt16(lcl_GetFrameId( pFrame ));
631  switch ( nSpecial )
632  {
633  case 1: InsertFrame( nId ); break;
634  case 2: DeleteFrame( nId ); break;
635  case 3:
636  m_pFrameIds.reset();
637  break;
638  case 4:
639  m_pStream.reset();
640  break;
641  }
642  return;
643  }
644  if (!m_pStream && !NewStream())
645  return; // still no stream
646 
647  if (m_pFrameIds && !m_pFrameIds->count(sal_uInt16(lcl_GetFrameId(pFrame))))
648  return; // doesn't belong to the wished FrameIds
649 
650  if (!(pFrame->GetType() & m_nTypes))
651  return; // the type is unwanted
652 
653  if (1 == m_nTestMode && nFunction != PROT::TestFormat)
654  return; // we may only log inside a test formatting
655  bool bTmp = false;
656  OStringBuffer aOut(m_aLayer);
657  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(pFrame)));
658  aOut.append(' ');
659  lcl_FrameType( aOut, pFrame ); // then the frame type
660  switch ( nFunction ) // and the function
661  {
662  case PROT::MakeAll: aOut.append("SwFrame::MakeAll");
663  lcl_Start(aOut, m_aLayer, nAct);
664  if (nAct == DbgAction::Start)
665  lcl_Flags(aOut, pFrame);
666  break;
667  case PROT::MoveFwd: bTmp = true;
668  [[fallthrough]];
669  case PROT::MoveBack:
670  if (nFunction == (bTmp ? PROT::Init : PROT::FileInit))
671  aOut.append("SwFlowFrame::MoveFwd");
672  else
673  aOut.append("SwFlowFrame::MoveBwd");
674  lcl_Start(aOut, m_aLayer, nAct);
675  if( pParam )
676  {
677  aOut.append(' ');
678  aOut.append(static_cast<sal_Int32>(*static_cast<sal_uInt16*>(pParam)));
679  }
680  break;
681  case PROT::GrowTest:
682  aOut.append("SwFrame::Grow (test)");
683  lcl_Start(aOut, m_aLayer, nAct);
684  break;
685  case PROT::ShrinkTest:
686  aOut.append("SwFrame::Shrink (test)");
687  lcl_Start(aOut, m_aLayer, nAct);
688  break;
689  case PROT::AdjustN :
690  case PROT::Shrink: bTmp = true;
691  [[fallthrough]];
692  case PROT::Grow:
693  if (!bTmp)
694  aOut.append("SwFrame::Grow");
695  else
696  {
697  if (nFunction == PROT::Shrink)
698  aOut.append("SwFrame::Shrink");
699  else
700  aOut.append("SwFrame::AdjustNeighbourhood");
701  }
702  lcl_Start(aOut, m_aLayer, nAct);
703  if( pParam )
704  {
705  aOut.append(' ');
706  aOut.append(static_cast<sal_Int64>(*static_cast<tools::Long*>(pParam)));
707  }
708  break;
709  case PROT::PrintArea: aOut.append("PROT::PrintArea");
710  lcl_Start(aOut, m_aLayer, nAct);
711  break;
712  case PROT::Size: aOut.append("PROT::Size");
713  lcl_Start(aOut, m_aLayer, nAct);
714  aOut.append(' ');
715  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Height()));
716  break;
717  case PROT::Leaf: aOut.append("SwFrame::GetPrev/NextSctLeaf");
718  lcl_Start(aOut, m_aLayer, nAct);
719  aOut.append(' ');
720  if (pParam)
721  {
722  aOut.append(' ');
723  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame*>(pParam))));
724  }
725  break;
726  case PROT::FileInit: FileInit();
727  aOut.append("Initialize");
728  break;
729  case PROT::Section: SectFunc(aOut, nAct, pParam);
730  break;
731  case PROT::Cut: bTmp = true;
732  [[fallthrough]];
733  case PROT::Paste:
734  if (bTmp)
735  aOut.append("PROT::Cut from ");
736  else
737  aOut.append("PROT::Paste to ");
738  aOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame*>(pParam))));
739  break;
740  case PROT::TestFormat:
741  aOut.append("SwTextFrame::TestFormat");
742  lcl_Start(aOut, m_aLayer, nAct);
743  if( DbgAction::Start == nAct )
744  m_nTestMode |= 2;
745  else
746  m_nTestMode &= ~2;
747  break;
748  case PROT::FrmChanges:
749  {
750  SwRect& rFrame = *static_cast<SwRect*>(pParam);
751  if( pFrame->getFrameArea().Pos() != rFrame.Pos() )
752  {
753  aOut.append("PosChg: (");
754  aOut.append(static_cast<sal_Int64>(rFrame.Left()));
755  aOut.append(", ");
756  aOut.append(static_cast<sal_Int64>(rFrame.Top()));
757  aOut.append(") -> (");
758  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Left()));
759  aOut.append(", ");
760  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Top()));
761  aOut.append(") ");
762  }
763  if( pFrame->getFrameArea().Height() != rFrame.Height() )
764  {
765  aOut.append("Height: ");
766  aOut.append(static_cast<sal_Int64>(rFrame.Height()));
767  aOut.append(" -> ");
768  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Height()));
769  aOut.append(" ");
770  }
771  if( pFrame->getFrameArea().Width() != rFrame.Width() )
772  {
773  aOut.append("Width: ");
774  aOut.append(static_cast<sal_Int64>(rFrame.Width()));
775  aOut.append(" -> ");
776  aOut.append(static_cast<sal_Int64>(pFrame->getFrameArea().Width()));
777  aOut.append(' ');
778  }
779  break;
780  }
781  default: break;
782  }
783 
784  aOut.append(" ");
785  while (aOut.getLength() < 40) aOut.append(" ");
786  lcl_FrameRect(aOut, "SwFrame", pFrame->getFrameArea());
787 
788  aOut.append(" ");
789  while (aOut.getLength() < 90) aOut.append(" ");
790  lcl_FrameRect(aOut, "SwPrint", pFrame->getFramePrintArea());
791 
792  if (pFrame->IsTextFrame())
793  {
794  aOut.append(" ");
795  while (aOut.getLength() < 140) aOut.append(" ");
796  const OUString& text = static_cast<const SwTextFrame*>(pFrame)->GetText();
797  OString o = OUStringToOString(text, RTL_TEXTENCODING_ASCII_US);
798  aOut.append(o);
799  }
800  else if (pFrame->IsTabFrame())
801  {
802  const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pFrame);
803  aOut.append(lcl_TableInfo(pTabFrame));
804  }
805  else if (pFrame->IsRowFrame())
806  {
807  const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pFrame);
808  aOut.append(lcl_RowInfo(pRowFrame));
809 
810  }
811  else if (pFrame->IsCellFrame())
812  {
813  const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(pFrame);
814  aOut.append(lcl_CellInfo(pCellFrame));
815  }
816 
817  SAL_INFO("sw.layout.debug", aOut.getStr());
818  m_pStream->WriteOString(aOut.makeStringAndClear());
819  (*m_pStream) << endl; // output
820  m_pStream->Flush(); // to the disk, so we can read it immediately
821  if (++m_nLineCount >= m_nMaxLines) // max number of lines reached?
822  {
823  SAL_WARN("sw.layout.debug", "max number of lines reached");
824  SwProtocol::SetRecord( PROT::FileInit ); // => end f logging
825  }
826 }
827 
829 void SwImplProtocol::SectFunc(OStringBuffer &rOut, DbgAction nAct, void const * pParam)
830 {
831  bool bTmp = false;
832  switch( nAct )
833  {
834  case DbgAction::Merge: rOut.append("Merge Section ");
835  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
836  break;
837  case DbgAction::CreateMaster: bTmp = true;
838  [[fallthrough]];
839  case DbgAction::CreateFollow: rOut.append("Create Section ");
840  if (bTmp)
841  rOut.append("Master to ");
842  else
843  rOut.append("Follow from ");
844  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
845  break;
846  case DbgAction::DelMaster: bTmp = true;
847  [[fallthrough]];
848  case DbgAction::DelFollow: rOut.append("Delete Section ");
849  if (bTmp)
850  rOut.append("Master to ");
851  else
852  rOut.append("Follow from ");
853  rOut.append(static_cast<sal_Int64>(lcl_GetFrameId(static_cast<SwFrame const *>(pParam))));
854  break;
855  default: break;
856  }
857 }
858 
866 void SwImplProtocol::InsertFrame( sal_uInt16 nId )
867 {
868  if (!m_pFrameIds)
869  m_pFrameIds.reset(new std::set<sal_uInt16>);
870  if (m_pFrameIds->count(nId))
871  return;
872  m_pFrameIds->insert(nId);
873 }
874 
876 void SwImplProtocol::DeleteFrame( sal_uInt16 nId )
877 {
878  if (!m_pFrameIds)
879  return;
880  m_pFrameIds->erase(nId);
881 }
882 
883 /*
884  * The task here is to find the right SwImplEnterLeave object based on the
885  * function; everything else is then done in his Ctor/Dtor.
886  */
887 SwEnterLeave::SwEnterLeave( const SwFrame* pFrame, PROT nFunc, DbgAction nAct, void* pPar )
888 {
889  if( !SwProtocol::Record( nFunc ) )
890  return;
891  switch( nFunc )
892  {
893  case PROT::AdjustN :
894  case PROT::Grow:
895  case PROT::Shrink : pImpl.reset( new SwSizeEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
896  case PROT::MoveFwd:
897  case PROT::MoveBack : pImpl.reset( new SwUpperEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
898  case PROT::FrmChanges : pImpl.reset( new SwFrameChangesLeave( pFrame, nFunc, nAct, pPar ) ); break;
899  default: pImpl.reset( new SwImplEnterLeave( pFrame, nFunc, nAct, pPar ) ); break;
900  }
901  pImpl->Enter();
902 }
903 
904 /* This is not inline because we don't want the SwImplEnterLeave definition inside
905  * dbg_lay.hxx.
906  */
908 {
909  if (pImpl)
910  pImpl->Leave();
911 }
912 
914 {
916 }
917 
920 }
921 
922 void SwSizeEnterLeave::Leave()
923 {
924  m_nFrameHeight = m_pFrame->getFrameArea().Height() - m_nFrameHeight;
925  SwProtocol::Record(m_pFrame, m_nFunction, DbgAction::End, &m_nFrameHeight);
926 }
927 
928 void SwUpperEnterLeave::Enter()
929 {
930  m_nFrameId = m_pFrame->GetUpper() ? sal_uInt16(lcl_GetFrameId(m_pFrame->GetUpper())) : 0;
931  SwProtocol::Record(m_pFrame, m_nFunction, DbgAction::Start, &m_nFrameId);
932 }
933 
934 void SwUpperEnterLeave::Leave()
935 {
936  m_nFrameId = m_pFrame->GetUpper() ? sal_uInt16(lcl_GetFrameId(m_pFrame->GetUpper())) : 0;
937  SwProtocol::Record(m_pFrame, m_nFunction, DbgAction::End, &m_nFrameId);
938 }
939 
940 void SwFrameChangesLeave::Enter()
941 {
942 }
943 
944 void SwFrameChangesLeave::Leave()
945 {
946  if (m_pFrame->getFrameArea() != m_aFrame)
947  SwProtocol::Record(m_pFrame, PROT::FrmChanges, DbgAction::NONE, &m_aFrame);
948 }
949 
950 #endif // DBG_UTIL
951 
952 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwFrameType m_nTypes
Definition: dbg_lay.cxx:135
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:690
Starts a section of nodes in the document model.
Definition: node.hxx:311
void Record(const SwFrame *pFrame, PROT nFunction, DbgAction nAct, void *pParam)
Definition: dbg_lay.cxx:149
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:290
sal_Int32 nIndex
sal_uLong Count() const
Definition: ndarr.hxx:142
sal_uInt8 m_nTestMode
Definition: dbg_lay.cxx:140
bool IsRootFrame() const
Definition: frame.hxx:1152
virtual ~SwImplEnterLeave()
Definition: dbg_lay.cxx:189
const OUString & GetText() const
Definition: ndtxt.hxx:211
const SwTable * GetTable() const
Definition: tabfrm.hxx:144
void Left(const tools::Long nLeft)
Definition: swrect.hxx:195
SwFrameType GetType() const
Definition: frame.hxx:500
sal_uIntPtr sal_uLong
long Long
const SwRect & getFramePrintArea() const
Definition: frame.hxx:178
std::unique_ptr< std::set< sal_uInt16 > > m_pFrameIds
Definition: dbg_lay.cxx:132
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:30
sal_Int64 n
sal_uInt8 m_nInitFile
Definition: dbg_lay.cxx:138
sal_Int16 nId
OStringBuffer m_aLayer
Definition: dbg_lay.cxx:134
PROT
Definition: dbg_lay.hxx:26
SwTableLine is one table row in the document model.
Definition: swtable.hxx:350
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
DbgAction m_nAction
Definition: dbg_lay.cxx:179
void CheckLine(OString &rLine)
analyze a line in the INI file
Definition: dbg_lay.cxx:325
static bool Start()
Definition: dbg_lay.hxx:69
static OString lcl_TableInfo(const SwTabFrame *pTabFrame)
Definition: dbg_lay.cxx:517
bool IsFootnoteFrame() const
Definition: frame.hxx:1180
SwEnterLeave(const SwFrame *pFrame, PROT nFunc, DbgAction nAct, void *pPar)
Definition: dbg_lay.cxx:887
void InsertFrame(sal_uInt16 nFrameId)
if pFrameIds==NULL all Frames will be logged.
Definition: dbg_lay.cxx:866
bool IsFlyFrame() const
Definition: frame.hxx:1188
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:182
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:472
void Width(tools::Long nNew)
Definition: swrect.hxx:187
#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:829
sal_uInt16 m_nLineCount
Definition: dbg_lay.cxx:136
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:876
static void SetRecord(PROT nNew)
Definition: dbg_lay.hxx:73
DbgAction
Definition: dbg_lay.hxx:50
std::vector< long > m_aVars
Definition: dbg_lay.cxx:133
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:1838
static SwImplProtocol * s_pImpl
Definition: dbg_lay.hxx:68
static sal_uLong lcl_GetFrameId(const SwFrame *pFrame)
Definition: dbg_lay.cxx:116
int i
static void Init()
Definition: dbg_lay.cxx:267
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:502
SwLayoutFrame * GetUpper()
Definition: frame.hxx:658
sal_uInt16 m_nMaxLines
Definition: dbg_lay.cxx:137
bool isFramePrintAreaValid() const
Definition: frame.hxx:166
bool IsRowFrame() const
Definition: frame.hxx:1200
virtual void Enter()
Definition: dbg_lay.cxx:913
bool IsEndNode() const
Definition: node.hxx:640
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:701
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:482
static OUString lcl_CellText(const SwCellFrame *pFrame)
Definition: dbg_lay.cxx:538
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:452
static OString lcl_CellInfo(const SwCellFrame *pFrame)
Definition: dbg_lay.cxx:567
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:574
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
bool IsLayoutFrame() const
Definition: frame.hxx:1148
virtual void Leave()
Definition: dbg_lay.cxx:918
SvStream & ReadChar(char &rChar)
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:445
static void Stop()
Definition: dbg_lay.cxx:281
bool IsTabFrame() const
Definition: frame.hxx:1196
void ChkStream()
Definition: dbg_lay.cxx:157
unsigned char sal_uInt8
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
void Top(const tools::Long nTop)
Definition: swrect.hxx:204
const SwModify * GetRegisteredIn() const
Definition: calbck.hxx:159
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:625
bool NewStream()
Definition: dbg_lay.cxx:302
bool IsPageFrame() const
Definition: frame.hxx:1156
static OString lcl_RowInfo(const SwRowFrame *pFrame)
Definition: dbg_lay.cxx:526
bool good() const
void FileInit()
read the file "dbg_lay.ini" in the current directory and evaluate it.
Definition: dbg_lay.cxx:424
Any result
#define SAL_WARN(area, stream)
static PROT s_nRecord
Definition: dbg_lay.hxx:67
Ends a section of nodes in the document model.
Definition: node.hxx:341
const SwTableLine * GetTabLine() const
Definition: rowfrm.hxx:69
const SwFrame * m_pFrame
Definition: dbg_lay.cxx:177
bool IsFootnoteContFrame() const
Definition: frame.hxx:1176
bool IsBodyFrame() const
Definition: frame.hxx:1184
std::unique_ptr< SvFileStream > m_pStream
Definition: dbg_lay.cxx:130
bool IsTextNode() const
Definition: node.hxx:644
void Height(tools::Long nNew)
Definition: swrect.hxx:191
bool IsFooterFrame() const
Definition: frame.hxx:1172
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
Base class of the Writer document model elements.
Definition: node.hxx:79