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