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 <o3tl/string_view.hxx>
110 #include <rtl/strbuf.hxx>
111 #include <sal/log.hxx>
112 #include <tools/stream.hxx>
113 
116 
117 static sal_uLong lcl_GetFrameId( const SwFrame* pFrame )
118 {
119 #if OSL_DEBUG_LEVEL > 1
120  static bool bFrameId = false;
121  if( bFrameId )
122  return pFrame->GetFrameId();
123 #endif
124  if( pFrame )
125  return pFrame->GetFrameId();
126  return 0;
127 }
128 
130 {
131  std::unique_ptr<SvFileStream> m_pStream; // output stream
132  std::unique_ptr<std::set<sal_uInt16>>
133  m_pFrameIds; // which FrameIds shall be logged ( NULL == all)
134  std::vector<tools::Long> m_aVars; // variables
135  OStringBuffer m_aLayer; // indentation of output (" " per start/end)
136  SwFrameType m_nTypes; // which types shall be logged
137  sal_uInt16 m_nLineCount; // printed lines
138  sal_uInt16 m_nMaxLines; // max lines to be printed
139  sal_uInt8 m_nInitFile; // range (FrameId,FrameType,Record) during reading of the INI file
140  sal_uInt8
141  m_nTestMode; // special for test formatting, logging may only be done in test formatting.
142  void Record_( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam );
143  bool NewStream();
144  void CheckLine( OString& rLine );
145  static void SectFunc( OStringBuffer& rOut, DbgAction nAct, void const * pParam );
146 public:
147  SwImplProtocol();
148  ~SwImplProtocol();
149  // logging
150  void Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
151  {
152  if (m_pStream)
153  Record_(pFrame, nFunction, nAct, pParam);
154  }
155  void InsertFrame( sal_uInt16 nFrameId ); // take FrameId for logging
156  void DeleteFrame( sal_uInt16 nFrameId ); // remove FrameId; don't log him anymore
157  void FileInit(); // read the INI file
158  void ChkStream() {
159  if (!m_pStream)
160  NewStream();
161  }
162 };
163 
164 /* Through the PROTOCOL_ENTER macro a SwEnterLeave object gets created. If the
165  * current function should be logged as SwImplEnterLeace object gets created.
166  * The funny thing here is, that the Ctor of the Impl object is automatically
167  * called at the beginning of the function and the Dtor is automatically called
168  * when leaving the function. In the base implementation the Ctor calls only
169  * PROTOCOL(..) with DbgAction::Start and in the Dtor a PROTOCOL(..) with DbgAction::End.
170  * It's possible to derive from this class, for example to be able to document
171  * frame resize while leaving a function. To do this, one only needs to add the
172  * desired SwImplEnterLeave class in SwEnterLeave::Ctor().
173  */
174 
176 {
177 protected:
178  const SwFrame* m_pFrame; // the frame
179  PROT m_nFunction; // the function
180  DbgAction m_nAction; // the action if needed
181  void* m_pParam; // further parameter
182 public:
183  SwImplEnterLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
184  : m_pFrame(pF)
185  , m_nFunction(nFunct)
186  , m_nAction(nAct)
187  , m_pParam(pPar)
188  {
189  }
190  virtual ~SwImplEnterLeave() {}
191  virtual void Enter(); // message when entering
192  virtual void Leave(); // message when leaving
193 };
194 
195 namespace {
196 
197 class SwSizeEnterLeave : public SwImplEnterLeave
198 {
199  tools::Long m_nFrameHeight;
200 
201 public:
202  SwSizeEnterLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
203  : SwImplEnterLeave(pF, nFunct, nAct, pPar)
204  , m_nFrameHeight(pF->getFrameArea().Height())
205  {
206  }
207 
208  virtual void Leave() override; // resize message
209 };
210 
211 class SwUpperEnterLeave : public SwImplEnterLeave
212 {
213  sal_uInt16 m_nFrameId;
214 
215 public:
216  SwUpperEnterLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
217  : SwImplEnterLeave(pF, nFunct, nAct, pPar)
218  , m_nFrameId(0)
219  {
220  }
221 
222  virtual void Enter() override; // message
223  virtual void Leave() override; // message of FrameId from upper
224 };
225 
226 class SwFrameChangesLeave : public SwImplEnterLeave
227 {
228  SwRect m_aFrame;
229 
230 public:
231  SwFrameChangesLeave(const SwFrame* pF, PROT nFunct, DbgAction nAct, void* pPar)
232  : SwImplEnterLeave(pF, nFunct, nAct, pPar)
233  , m_aFrame(pF->getFrameArea())
234  {
235  }
236 
237  virtual void Enter() override; // no message
238  virtual void Leave() override; // message when resizing the Frame area
239 };
240 
241 }
242 
243 void SwProtocol::Record( const SwFrame* pFrame, PROT nFunction, DbgAction nAct, void* pParam )
244 {
245  if( Start() )
246  { // We reach this point if SwProtocol::nRecord is binary OR'd with PROT::Init(0x1) using the debugger
247  bool bFinit = false; // This gives the possibility to stop logging of this action in the debugger
248  if( bFinit )
249  {
250  s_nRecord &= ~nFunction; // Don't log this function any longer
251  s_nRecord &= ~PROT::Init; // Always reset PROT::Init
252  return;
253  }
254  s_nRecord |= nFunction; // Activate logging of this function
255  s_nRecord &= ~PROT::Init; // Always reset PROT::Init
256  if( s_pImpl )
257  s_pImpl->ChkStream();
258  }
259  if( !s_pImpl ) // Create Impl object if needed
260  s_pImpl = new SwImplProtocol();
261  s_pImpl->Record( pFrame, nFunction, nAct, pParam ); // ...and start logging
262 }
263 
264 // The following function gets called when pulling in the writer DLL through
265 // TextInit(..) and gives the possibility to release functions
266 // and/or FrameIds to the debugger
267 
269 {
271  SvFileStream aStream( "dbg_lay.go", StreamMode::READ );
272  if( aStream.IsOpen() )
273  {
274  s_pImpl = new SwImplProtocol();
275  s_pImpl->FileInit();
276  }
277  aStream.Close();
278 }
279 
280 // End of logging
281 
283 {
284  if( s_pImpl )
285  {
286  delete s_pImpl;
287  s_pImpl = nullptr;
288  if( pFntCache )
289  pFntCache->Flush();
290  }
292 }
293 
295  : m_nTypes(FRM_ALL)
296  , m_nLineCount(0)
297  , m_nMaxLines(USHRT_MAX)
298  , m_nTestMode(0)
299 {
300  NewStream();
301 }
302 
304 {
305  m_nLineCount = 0;
306  m_pStream.reset(new SvFileStream("dbg_lay.out", StreamMode::WRITE | StreamMode::TRUNC));
307  if (m_pStream->GetError())
308  {
309  m_pStream.reset();
310  }
311  return nullptr != m_pStream;
312 }
313 
315 {
316  if (m_pStream)
317  {
318  m_pStream->Close();
319  m_pStream.reset();
320  }
321  m_pFrameIds.reset();
322  m_aVars.clear();
323 }
324 
326 void SwImplProtocol::CheckLine( OString& rLine )
327 {
328  rLine = rLine.toAsciiLowerCase(); // upper/lower case is the same
329  rLine = rLine.replace( '\t', ' ' );
330  if( '#' == rLine[0] ) // comments start with '#'
331  return;
332  if( '[' == rLine[0] ) // section: FrameIds, type or function
333  {
334  std::string_view aTmp = o3tl::getToken(rLine, 0, ']');
335  if (aTmp == "[frmid") // section FrameIds
336  {
337  m_nInitFile = 1;
338  m_pFrameIds.reset(); // default: log all frames
339  }
340  else if (aTmp == "[frmtype")// section types
341  {
342  m_nInitFile = 2;
343  m_nTypes = FRM_ALL; // default: log all frame types
344  }
345  else if (aTmp == "[record")// section functions
346  {
347  m_nInitFile = 3;
348  SwProtocol::SetRecord( PROT::FileInit );// default: don't log any function
349  }
350  else if (aTmp == "[test")// section functions
351  {
352  m_nInitFile = 4; // default:
353  m_nTestMode = 0; // log outside of test formatting
354  }
355  else if (aTmp == "[max")// Max number of lines
356  {
357  m_nInitFile = 5; // default:
358  m_nMaxLines = USHRT_MAX;
359  }
360  else if (aTmp == "[var")// variables
361  {
362  m_nInitFile = 6;
363  }
364  else
365  m_nInitFile = 0; // oops: unknown section?
366  rLine = rLine.copy(aTmp.size() + 1);
367  }
368 
369  // spaces (or tabs) are the delimiter
370  sal_Int32 nIndex = 0;
371  do
372  {
373  std::string_view aTok = o3tl::getToken(rLine, 0, ' ', nIndex );
374  bool bNo = false;
375  if( !aTok.empty() && '!' == aTok[0] )
376  {
377  bNo = true; // remove this function/type
378  aTok = aTok.substr(1);
379  }
380  if( !aTok.empty() )
381  {
382  sal_Int64 nVal = o3tl::toInt64(aTok);
383  switch (m_nInitFile)
384  {
385  case 1: InsertFrame( sal_uInt16( nVal ) ); // add FrameId
386  break;
387  case 2: {
388  SwFrameType nNew = static_cast<SwFrameType>(nVal);
389  if( bNo )
390  m_nTypes &= ~nNew; // remove type
391  else
392  m_nTypes |= nNew; // add type
393  }
394  break;
395  case 3: {
396  PROT nOld = SwProtocol::Record();
397  if( bNo )
398  nOld &= ~PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
399  else
400  nOld |= PROT(nVal & o3tl::typed_flags<PROT>::mask); // remove function
401  SwProtocol::SetRecord( nOld );
402  }
403  break;
404  case 4: {
405  sal_uInt8 nNew = static_cast<sal_uInt8>(nVal);
406  if( bNo )
407  m_nTestMode &= ~nNew; // reset test mode
408  else
409  m_nTestMode |= nNew; // set test mode
410  }
411  break;
412  case 5:
413  m_nMaxLines = o3tl::narrowing<sal_uInt16>(nVal);
414  break;
415  case 6:
416  m_aVars.push_back(nVal);
417  break;
418  }
419  }
420  }
421  while ( nIndex >= 0 );
422 }
423 
426 {
427  SvFileStream aStream( "dbg_lay.ini", StreamMode::READ );
428  if( aStream.IsOpen() )
429  {
430  OString aLine;
431  m_nInitFile = 0;
432  while( aStream.good() )
433  {
434  char c;
435  aStream.ReadChar( c );
436  if( '\n' == c || '\r' == c ) // line ending
437  {
438  aLine = aLine.trim();
439  if( !aLine.isEmpty() )
440  CheckLine( aLine ); // evaluate line
441  aLine.clear();
442  }
443  else
444  aLine += OStringChar(c);
445  }
446  if( !aLine.isEmpty() )
447  CheckLine( aLine ); // evaluate last line
448  }
449  aStream.Close();
450 }
451 
453 static void lcl_Start(OStringBuffer& rOut, OStringBuffer& rLay, DbgAction nAction)
454 {
455  if( nAction == DbgAction::Start )
456  {
457  rLay.append(" ");
458  rOut.append(" On");
459  }
460  else if( nAction == DbgAction::End )
461  {
462  if( rLay.getLength() > 1 )
463  {
464  rLay.remove(rLay.getLength() - 2, rLay.getLength());
465  rOut.remove(0, 2);
466  }
467  rOut.append(" Off");
468  }
469 }
470 
473 static void lcl_Flags(OStringBuffer& rOut, const SwFrame* pFrame)
474 {
475  rOut.append(" ValidSize");
476  rOut.append(pFrame->isFrameAreaSizeValid() ? '+' : '-');
477  rOut.append(" ValidPos");
478  rOut.append(pFrame->isFrameAreaPositionValid() ? '+' : '-');
479  rOut.append(" ValidPrtArea");
480  rOut.append(pFrame->isFramePrintAreaValid() ? '+' : '-');
481 }
482 
483 static void lcl_Padded(OStringBuffer& rOut, const OString& s, size_t length)
484 {
485  if (sal_Int32(length) < s.getLength())
486  length = s.getLength();
487  rOut.append(s);
488  for (size_t i = 0; i < length - s.getLength(); i++)
489  {
490  rOut.append(" ");
491  }
492 }
493 
494 static void lcl_Padded(OStringBuffer& rOut, const tools::Long n, size_t length = 5)
495 {
496  char sz[RTL_STR_MAX_VALUEOFINT64];
497  rtl_str_valueOfInt64(sz, n, 10);
498  OString s(sz);
499  lcl_Padded(rOut, s, length);
500 }
501 
503 static void lcl_FrameRect(OStringBuffer& rOut, const char* hint, const SwRect& rect)
504 {
505  rOut.append("[");
506  rOut.append(hint);
507  rOut.append(":X:");
508  lcl_Padded(rOut, rect.Pos().X());
509  rOut.append(", Y:");
510  lcl_Padded(rOut, rect.Pos().Y());
511  rOut.append(", Width:");
512  lcl_Padded(rOut, rect.SSize().Width());
513  rOut.append(", Height:");
514  lcl_Padded(rOut, rect.SSize().Height());
515  rOut.append("] ");
516 }
517 
518 static OString lcl_TableInfo(const SwTabFrame* pTabFrame)
519 {
520  const SwTable* pTable = pTabFrame->GetTable();
521  const SwFormat* pFormat = static_cast<const SwFormat*>(pTable->GetRegisteredIn());
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 (SwNodeOffset 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:136
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:692
Starts a section of nodes in the document model.
Definition: node.hxx:313
void Record(const SwFrame *pFrame, PROT nFunction, DbgAction nAct, void *pParam)
Definition: dbg_lay.cxx:150
Base class of the Writer layout elements.
Definition: frame.hxx:314
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:159
sal_Int32 nIndex
sal_uInt8 m_nTestMode
Definition: dbg_lay.cxx:141
bool IsRootFrame() const
Definition: frame.hxx:1174
sal_Int64 toInt64(std::u16string_view str, sal_Int16 radix=10)
virtual ~SwImplEnterLeave()
Definition: dbg_lay.cxx:190
const OUString & GetText() const
Definition: ndtxt.hxx:218
const SwTable * GetTable() const
Definition: tabfrm.hxx:158
void Left(const tools::Long nLeft)
Definition: swrect.hxx:197
SwFrameType GetType() const
Definition: frame.hxx:519
sal_uIntPtr sal_uLong
long Long
const SwRect & getFramePrintArea() const
Definition: frame.hxx:180
std::unique_ptr< std::set< sal_uInt16 > > m_pFrameIds
Definition: dbg_lay.cxx:133
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:46
sal_Int64 n
sal_uInt8 m_nInitFile
Definition: dbg_lay.cxx:139
sal_Int16 nId
OStringBuffer m_aLayer
Definition: dbg_lay.cxx:135
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
PROT
Definition: dbg_lay.hxx:26
SwTableLine is one table row in the document model.
Definition: swtable.hxx:357
void Pos(const Point &rNew)
Definition: swrect.hxx:171
static PROT Record()
Definition: dbg_lay.hxx:72
bool IsCellFrame() const
Definition: frame.hxx:1226
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
DbgAction m_nAction
Definition: dbg_lay.cxx:180
void CheckLine(OString &rLine)
analyze a line in the INI file
Definition: dbg_lay.cxx:326
static bool Start()
Definition: dbg_lay.hxx:69
static OString lcl_TableInfo(const SwTabFrame *pTabFrame)
Definition: dbg_lay.cxx:518
bool IsFootnoteFrame() const
Definition: frame.hxx:1202
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:1210
const SwTableBox * GetTabBox() const
Definition: cellfrm.hxx:52
const SwRect & getFrameArea() const
Definition: frame.hxx:179
SwImplEnterLeave(const SwFrame *pF, PROT nFunct, DbgAction nAct, void *pPar)
Definition: dbg_lay.cxx:183
const OUString & GetName() const
Definition: format.hxx:131
bool IsTextFrame() const
Definition: frame.hxx:1234
void Flush()
Definition: fntcache.cxx:92
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:473
void Width(tools::Long nNew)
Definition: swrect.hxx:189
#define FRM_ALL
Definition: frame.hxx:102
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:137
bool IsSctFrame() const
Definition: frame.hxx:1214
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
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
Base class for various Writer styles.
Definition: format.hxx:46
exports com.sun.star. text
bool IsColumnFrame() const
Definition: frame.hxx:1182
OUString GetName() const
Definition: swtable.cxx:1998
static SwImplProtocol * s_pImpl
Definition: dbg_lay.hxx:68
static sal_uLong lcl_GetFrameId(const SwFrame *pFrame)
Definition: dbg_lay.cxx:117
int i
static void Init()
Definition: dbg_lay.cxx:268
SwFrameType
Definition: frame.hxx:74
static void lcl_FrameRect(OStringBuffer &rOut, const char *hint, const SwRect &rect)
output the frame as plain text.
Definition: dbg_lay.cxx:503
SwNodeOffset GetIndex() const
Definition: node.hxx:292
SwLayoutFrame * GetUpper()
Definition: frame.hxx:678
sal_uInt16 m_nMaxLines
Definition: dbg_lay.cxx:138
bool isFramePrintAreaValid() const
Definition: frame.hxx:168
bool IsRowFrame() const
Definition: frame.hxx:1222
virtual void Enter()
Definition: dbg_lay.cxx:913
bool IsEndNode() const
Definition: node.hxx:642
std::vector< tools::Long > m_aVars
Definition: dbg_lay.cxx:134
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:703
bool isFrameAreaPositionValid() const
Definition: frame.hxx:166
void SSize(const Size &rNew)
Definition: swrect.hxx:180
bool isFrameAreaSizeValid() const
Definition: frame.hxx:167
SwFntCache * pFntCache
Definition: fntcache.cxx:64
static void lcl_Padded(OStringBuffer &rOut, const OString &s, size_t length)
Definition: dbg_lay.cxx:483
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:453
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:112
static void lcl_FrameType(OStringBuffer &rOut, const SwFrame *pFrame)
output the type of the frame as plain text.
Definition: dbg_lay.cxx:574
bool IsLayoutFrame() const
Definition: frame.hxx:1170
virtual void Leave()
Definition: dbg_lay.cxx:918
SvStream & ReadChar(char &rChar)
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:471
static void Stop()
Definition: dbg_lay.cxx:282
bool IsTabFrame() const
Definition: frame.hxx:1218
void ChkStream()
Definition: dbg_lay.cxx:158
unsigned char sal_uInt8
SvStream & endl(SvStream &rStr)
#define SAL_INFO(area, stream)
bool IsNoTextFrame() const
Definition: frame.hxx:1238
void Top(const tools::Long nTop)
Definition: swrect.hxx:206
const SwModify * GetRegisteredIn() const
Definition: calbck.hxx:164
bool IsColBodyFrame() const
These SwFrame inlines are here, so that frame.hxx does not need to include layfrm.hxx.
Definition: layfrm.hxx:210
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:303
bool IsPageFrame() const
Definition: frame.hxx:1178
static OString lcl_RowInfo(const SwRowFrame *pFrame)
Definition: dbg_lay.cxx:526
bool good() const
SwNodeOffset Count() const
Definition: ndarr.hxx:141
void FileInit()
read the file "dbg_lay.ini" in the current directory and evaluate it.
Definition: dbg_lay.cxx:425
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:343
const SwTableLine * GetTabLine() const
Definition: rowfrm.hxx:70
const SwFrame * m_pFrame
Definition: dbg_lay.cxx:178
bool IsFootnoteContFrame() const
Definition: frame.hxx:1198
bool IsBodyFrame() const
Definition: frame.hxx:1206
std::unique_ptr< SvFileStream > m_pStream
Definition: dbg_lay.cxx:131
bool IsTextNode() const
Definition: node.hxx:646
void Height(tools::Long nNew)
Definition: swrect.hxx:193
bool IsFooterFrame() const
Definition: frame.hxx:1194
std::unique_ptr< SwImplEnterLeave > pImpl
Definition: dbg_lay.hxx:82
sal_uInt32 GetFrameId() const
Definition: frame.hxx:174
SwCellFrame is one table cell in the document layout.
Definition: cellfrm.hxx:30
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
bool IsOpen() const
bool IsHeaderFrame() const
Definition: frame.hxx:1190
Base class of the Writer document model elements.
Definition: node.hxx:81