1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
23 * And here's the description:
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.
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.
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
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
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.
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
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
88 * #the following FrameIds:
90 * #no layout frames, except ColumnFrames
91 * [frmtype] !0x3FFF 0x4
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.
98 #include <dbg_lay.hxx>
100 #include <txtfrm.hxx>
101 #include <fntcache.hxx>
102 #include <tabfrm.hxx>
103 #include <rowfrm.hxx>
104 #include <cellfrm.hxx>
105 #include <layfrm.hxx>
107 #include <swtable.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>
115 PROT
SwProtocol::s_nRecord
= PROT::FileInit
;
116 SwImplProtocol
* SwProtocol::s_pImpl
= nullptr;
118 static sal_uLong
lcl_GetFrameId( const SwFrame
* pFrame
)
120 #if OSL_DEBUG_LEVEL > 1
121 static bool bFrameId
= false;
123 return pFrame
->GetFrameId();
126 return pFrame
->GetFrameId();
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
);
145 void CheckLine( OString
& rLine
);
146 static void SectFunc( OStringBuffer
& rOut
, DbgAction nAct
, void const * pParam
);
151 void Record( const SwFrame
* pFrame
, PROT nFunction
, DbgAction nAct
, void* pParam
)
154 Record_(pFrame
, nFunction
, nAct
, pParam
);
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
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().
176 class SwImplEnterLeave
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
184 SwImplEnterLeave(const SwFrame
* pF
, PROT nFunct
, DbgAction nAct
, void* pPar
)
186 , m_nFunction(nFunct
)
191 virtual ~SwImplEnterLeave() {}
192 virtual void Enter(); // message when entering
193 virtual void Leave(); // message when leaving
198 class SwSizeEnterLeave
: public SwImplEnterLeave
200 tools::Long m_nFrameHeight
;
203 SwSizeEnterLeave(const SwFrame
* pF
, PROT nFunct
, DbgAction nAct
, void* pPar
)
204 : SwImplEnterLeave(pF
, nFunct
, nAct
, pPar
)
205 , m_nFrameHeight(pF
->getFrameArea().Height())
209 virtual void Leave() override
; // resize message
212 class SwUpperEnterLeave
: public SwImplEnterLeave
214 sal_uInt16 m_nFrameId
;
217 SwUpperEnterLeave(const SwFrame
* pF
, PROT nFunct
, DbgAction nAct
, void* pPar
)
218 : SwImplEnterLeave(pF
, nFunct
, nAct
, pPar
)
223 virtual void Enter() override
; // message
224 virtual void Leave() override
; // message of FrameId from upper
227 class SwFrameChangesLeave
: public SwImplEnterLeave
232 SwFrameChangesLeave(const SwFrame
* pF
, PROT nFunct
, DbgAction nAct
, void* pPar
)
233 : SwImplEnterLeave(pF
, nFunct
, nAct
, pPar
)
234 , m_aFrame(pF
->getFrameArea())
238 virtual void Enter() override
; // no message
239 virtual void Leave() override
; // message when resizing the Frame area
244 void SwProtocol::Record( const SwFrame
* pFrame
, PROT nFunction
, DbgAction nAct
, void* pParam
)
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
251 s_nRecord
&= ~nFunction
; // Don't log this function any longer
252 s_nRecord
&= ~PROT::Init
; // Always reset PROT::Init
255 s_nRecord
|= nFunction
; // Activate logging of this function
256 s_nRecord
&= ~PROT::Init
; // Always reset PROT::Init
258 s_pImpl
->ChkStream();
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
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
269 void SwProtocol::Init()
271 s_nRecord
= PROT::FileInit
;
272 SvFileStream
aStream( "dbg_lay.go", StreamMode::READ
);
273 if( aStream
.IsOpen() )
275 s_pImpl
= new SwImplProtocol();
283 void SwProtocol::Stop()
292 s_nRecord
= PROT::FileInit
;
295 SwImplProtocol::SwImplProtocol()
298 , m_nMaxLines(USHRT_MAX
)
304 bool SwImplProtocol::NewStream()
307 m_pStream
.reset(new SvFileStream("dbg_lay.out", StreamMode::WRITE
| StreamMode::TRUNC
));
308 if (m_pStream
->GetError())
312 return nullptr != m_pStream
;
315 SwImplProtocol::~SwImplProtocol()
326 /// analyze a line in the INI file
327 void SwImplProtocol::CheckLine( OString
& rLine
)
329 rLine
= rLine
.toAsciiLowerCase(); // upper/lower case is the same
330 rLine
= rLine
.replace( '\t', ' ' );
331 if( '#' == rLine
[0] ) // comments start with '#'
333 if( '[' == rLine
[0] ) // section: FrameIds, type or function
335 std::string_view aTmp
= o3tl::getToken(rLine
, 0, ']');
336 if (aTmp
== "[frmid") // section FrameIds
339 m_pFrameIds
.reset(); // default: log all frames
341 else if (aTmp
== "[frmtype")// section types
344 m_nTypes
= FRM_ALL
; // default: log all frame types
346 else if (aTmp
== "[record")// section functions
349 SwProtocol::SetRecord( PROT::FileInit
);// default: don't log any function
351 else if (aTmp
== "[test")// section functions
353 m_nInitFile
= 4; // default:
354 m_nTestMode
= 0; // log outside of test formatting
356 else if (aTmp
== "[max")// Max number of lines
358 m_nInitFile
= 5; // default:
359 m_nMaxLines
= USHRT_MAX
;
361 else if (aTmp
== "[var")// variables
366 m_nInitFile
= 0; // oops: unknown section?
367 rLine
= rLine
.copy(aTmp
.size() + 1);
370 // spaces (or tabs) are the delimiter
371 sal_Int32 nIndex
= 0;
374 std::string_view aTok
= o3tl::getToken(rLine
, 0, ' ', nIndex
);
376 if( !aTok
.empty() && '!' == aTok
[0] )
378 bNo
= true; // remove this function/type
379 aTok
= aTok
.substr(1);
383 sal_Int64 nVal
= o3tl::toInt64(aTok
);
386 case 1: InsertFrame( sal_uInt16( nVal
) ); // add FrameId
389 SwFrameType nNew
= static_cast<SwFrameType
>(nVal
);
391 m_nTypes
&= ~nNew
; // remove type
393 m_nTypes
|= nNew
; // add type
397 PROT nOld
= SwProtocol::Record();
399 nOld
&= ~PROT(nVal
& o3tl::typed_flags
<PROT
>::mask
); // remove function
401 nOld
|= PROT(nVal
& o3tl::typed_flags
<PROT
>::mask
); // remove function
402 SwProtocol::SetRecord( nOld
);
406 sal_uInt8 nNew
= static_cast<sal_uInt8
>(nVal
);
408 m_nTestMode
&= ~nNew
; // reset test mode
410 m_nTestMode
|= nNew
; // set test mode
414 m_nMaxLines
= o3tl::narrowing
<sal_uInt16
>(nVal
);
417 m_aVars
.push_back(nVal
);
422 while ( nIndex
>= 0 );
425 /// read the file "dbg_lay.ini" in the current directory and evaluate it.
426 void SwImplProtocol::FileInit()
428 SvFileStream
aStream( "dbg_lay.ini", StreamMode::READ
);
429 if( aStream
.IsOpen() )
433 while( aStream
.good() )
436 aStream
.ReadChar( c
);
437 if( '\n' == c
|| '\r' == c
) // line ending
439 aLine
= aLine
.trim();
440 if( !aLine
.isEmpty() )
441 CheckLine( aLine
); // evaluate line
445 aLine
+= OStringChar(c
);
447 if( !aLine
.isEmpty() )
448 CheckLine( aLine
); // evaluate last line
453 /// enable indentation by two spaces during DbgAction::Start and disable it again at DbgAction::End.
454 static void lcl_Start(OStringBuffer
& rOut
, OStringBuffer
& rLay
, DbgAction nAction
)
456 if( nAction
== DbgAction::Start
)
461 else if( nAction
== DbgAction::End
)
463 if( rLay
.getLength() > 1 )
465 rLay
.remove(rLay
.getLength() - 2, rLay
.getLength());
472 /// output the ValidSize-, ValidPos- and ValidPrtArea-Flag ("Sz","Ps","PA")
473 /// of the frame; "+" stands for valid, "-" stands for invalid.
474 static void lcl_Flags(OStringBuffer
& rOut
, const SwFrame
* pFrame
)
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() ? '+' : '-');
484 static void lcl_Padded(OStringBuffer
& rOut
, const OString
& s
, size_t length
)
486 if (length
< o3tl::make_unsigned(s
.getLength()))
487 length
= s
.getLength();
489 for (size_t i
= 0; i
< length
- s
.getLength(); i
++)
495 static void lcl_Padded(OStringBuffer
& rOut
, const tools::Long n
, size_t length
= 5)
497 char sz
[RTL_STR_MAX_VALUEOFINT64
];
498 rtl_str_valueOfInt64(sz
, n
, 10);
500 lcl_Padded(rOut
, s
, length
);
503 /// output the frame as plain text.
504 static void lcl_FrameRect(OStringBuffer
& rOut
, const char* hint
, const SwRect
& rect
)
509 lcl_Padded(rOut
, rect
.Pos().X());
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());
519 static OString
lcl_TableInfo(const SwTabFrame
* pTabFrame
)
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
);
527 static OString
lcl_RowInfo(const SwRowFrame
* pFrame
)
529 // dummy, needs actual functionality...
530 if (pFrame
== nullptr)
532 const SwTableLine
* pTabLine
= pFrame
->GetTabLine();
533 if (pTabLine
== nullptr)
539 static OUString
lcl_CellText(const SwCellFrame
* pFrame
)
544 const SwStartNode
* pStartNode
= pFrame
->GetTabBox()->GetSttNd();
545 const SwEndNode
* pEndNode
= pStartNode
->EndOfSectionNode();
546 const SwNodes
& nodes
= pStartNode
->GetNodes();
548 for (SwNodeOffset i
= pStartNode
->GetIndex(); i
< nodes
.Count(); i
++)
550 SwNode
* pNode
= nodes
[i
];
552 if (pNode
->IsEndNode())
554 if (pNode
->EndOfSectionNode() == pEndNode
)
557 else if (pNode
->IsTextNode())
560 result
+= "Para:" + OUString::number(10) + " " +
561 pNode
->GetTextNode()->GetText();
565 return OUString::number(n
) + " para(s):" + result
;
568 static OString
lcl_CellInfo(const SwCellFrame
* pFrame
)
570 const OUString text
= "CellInfo: " + pFrame
->GetTabBox()->GetName() + " Text: " + lcl_CellText(pFrame
);
571 return OUStringToOString(text
, RTL_TEXTENCODING_ASCII_US
);
574 /// output the type of the frame as plain text.
575 static void lcl_FrameType( OStringBuffer
& rOut
, const SwFrame
* pFrame
)
577 if( pFrame
->IsTextFrame() )
578 rOut
.append("SwTextFrame ");
579 else if( pFrame
->IsLayoutFrame() )
581 if( pFrame
->IsPageFrame() )
582 rOut
.append("SwPageFrame ");
583 else if( pFrame
->IsColumnFrame() )
584 rOut
.append("SwColumnFrame ");
585 else if( pFrame
->IsBodyFrame() )
587 if( pFrame
->GetUpper() && pFrame
->IsColBodyFrame() )
588 rOut
.append("(Col)");
589 rOut
.append("SwBodyFrame ");
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 ");
612 rOut
.append("SwLayoutFrame ");
614 else if( pFrame
->IsNoTextFrame() )
615 rOut
.append("SwNoTextFrame");
617 rOut
.append("Not impl. ");
621 * Is only called if the PROTOCOL macro finds out,
622 * that this function should be recorded ( @see{SwProtocol::nRecord} ).
624 * In this method we also check if FrameId and frame type should be logged.
626 void SwImplProtocol::Record_( const SwFrame
* pFrame
, PROT nFunction
, DbgAction nAct
, void* pParam
)
628 sal_uInt16 nSpecial
= 0;
629 if( nSpecial
) // the possible debugger manipulations
631 sal_uInt16 nId
= sal_uInt16(lcl_GetFrameId( pFrame
));
634 case 1: InsertFrame( nId
); break;
635 case 2: DeleteFrame( nId
); break;
645 if (!m_pStream
&& !NewStream())
646 return; // still no stream
648 if (m_pFrameIds
&& !m_pFrameIds
->count(sal_uInt16(lcl_GetFrameId(pFrame
))))
649 return; // doesn't belong to the wished FrameIds
651 if (!(pFrame
->GetType() & m_nTypes
))
652 return; // the type is unwanted
654 if (1 == m_nTestMode
&& nFunction
!= PROT::TestFormat
)
655 return; // we may only log inside a test formatting
657 OStringBuffer
aOut(m_aLayer
);
658 aOut
.append(static_cast<sal_Int64
>(lcl_GetFrameId(pFrame
)));
660 lcl_FrameType( aOut
, pFrame
); // then the frame type
661 switch ( nFunction
) // and the function
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
);
668 case PROT::MoveFwd
: bTmp
= true;
671 if (nFunction
== (bTmp
? PROT::Init
: PROT::FileInit
))
672 aOut
.append("SwFlowFrame::MoveFwd");
674 aOut
.append("SwFlowFrame::MoveBwd");
675 lcl_Start(aOut
, m_aLayer
, nAct
);
678 aOut
.append(" " + OString::number(static_cast<sal_Int32
>(*static_cast<sal_uInt16
*>(pParam
))));
682 aOut
.append("SwFrame::Grow (test)");
683 lcl_Start(aOut
, m_aLayer
, nAct
);
685 case PROT::ShrinkTest
:
686 aOut
.append("SwFrame::Shrink (test)");
687 lcl_Start(aOut
, m_aLayer
, nAct
);
690 case PROT::Shrink
: bTmp
= true;
694 aOut
.append("SwFrame::Grow");
697 if (nFunction
== PROT::Shrink
)
698 aOut
.append("SwFrame::Shrink");
700 aOut
.append("SwFrame::AdjustNeighbourhood");
702 lcl_Start(aOut
, m_aLayer
, nAct
);
705 aOut
.append(" " + OString::number(static_cast<sal_Int64
>(*static_cast<tools::Long
*>(pParam
))));
708 case PROT::PrintArea
: aOut
.append("PROT::PrintArea");
709 lcl_Start(aOut
, m_aLayer
, nAct
);
711 case PROT::Size
: aOut
.append("PROT::Size");
712 lcl_Start(aOut
, m_aLayer
, nAct
);
714 aOut
.append(static_cast<sal_Int64
>(pFrame
->getFrameArea().Height()));
716 case PROT::Leaf
: aOut
.append("SwFrame::GetPrev/NextSctLeaf");
717 lcl_Start(aOut
, m_aLayer
, nAct
);
722 aOut
.append(static_cast<sal_Int64
>(lcl_GetFrameId(static_cast<SwFrame
*>(pParam
))));
725 case PROT::FileInit
: FileInit();
726 aOut
.append("Initialize");
728 case PROT::Section
: SectFunc(aOut
, nAct
, pParam
);
730 case PROT::Cut
: bTmp
= true;
734 aOut
.append("PROT::Cut from ");
736 aOut
.append("PROT::Paste to ");
737 aOut
.append(static_cast<sal_Int64
>(lcl_GetFrameId(static_cast<SwFrame
*>(pParam
))));
739 case PROT::TestFormat
:
740 aOut
.append("SwTextFrame::TestFormat");
741 lcl_Start(aOut
, m_aLayer
, nAct
);
742 if( DbgAction::Start
== nAct
)
747 case PROT::FrmChanges
:
749 SwRect
& rFrame
= *static_cast<SwRect
*>(pParam
);
750 if( pFrame
->getFrameArea().Pos() != rFrame
.Pos() )
752 aOut
.append("PosChg: ("
753 + OString::number(static_cast<sal_Int64
>(rFrame
.Left()))
755 + OString::number(static_cast<sal_Int64
>(rFrame
.Top()))
757 + OString::number(static_cast<sal_Int64
>(pFrame
->getFrameArea().Left()))
759 + OString::number(static_cast<sal_Int64
>(pFrame
->getFrameArea().Top()))
762 if( pFrame
->getFrameArea().Height() != rFrame
.Height() )
764 aOut
.append("Height: "
765 + OString::number(static_cast<sal_Int64
>(rFrame
.Height()))
767 + OString::number(static_cast<sal_Int64
>(pFrame
->getFrameArea().Height()))
770 if( pFrame
->getFrameArea().Width() != rFrame
.Width() )
772 aOut
.append("Width: "
773 + OString::number(static_cast<sal_Int64
>(rFrame
.Width()))
775 + OString::number(static_cast<sal_Int64
>(pFrame
->getFrameArea().Width()))
784 while (aOut
.getLength() < 40) aOut
.append(" ");
785 lcl_FrameRect(aOut
, "SwFrame", pFrame
->getFrameArea());
788 while (aOut
.getLength() < 90) aOut
.append(" ");
789 lcl_FrameRect(aOut
, "SwPrint", pFrame
->getFramePrintArea());
791 if (pFrame
->IsTextFrame())
794 while (aOut
.getLength() < 140) aOut
.append(" ");
795 const OUString
& text
= static_cast<const SwTextFrame
*>(pFrame
)->GetText();
796 OString o
= OUStringToOString(text
, RTL_TEXTENCODING_ASCII_US
);
799 else if (pFrame
->IsTabFrame())
801 const SwTabFrame
* pTabFrame
= static_cast<const SwTabFrame
*>(pFrame
);
802 aOut
.append(lcl_TableInfo(pTabFrame
));
804 else if (pFrame
->IsRowFrame())
806 const SwRowFrame
* pRowFrame
= static_cast<const SwRowFrame
*>(pFrame
);
807 aOut
.append(lcl_RowInfo(pRowFrame
));
810 else if (pFrame
->IsCellFrame())
812 const SwCellFrame
* pCellFrame
= static_cast<const SwCellFrame
*>(pFrame
);
813 aOut
.append(lcl_CellInfo(pCellFrame
));
816 SAL_INFO("sw.layout.debug", aOut
.getStr());
817 m_pStream
->WriteOString(aOut
);
818 (*m_pStream
) << endl
; // output
819 m_pStream
->Flush(); // to the disk, so we can read it immediately
820 if (++m_nLineCount
>= m_nMaxLines
) // max number of lines reached?
822 SAL_WARN("sw.layout.debug", "max number of lines reached");
823 SwProtocol::SetRecord( PROT::FileInit
); // => end f logging
827 /// Handle the output of the SectionFrames.
828 void SwImplProtocol::SectFunc(OStringBuffer
&rOut
, DbgAction nAct
, void const * pParam
)
833 case DbgAction::Merge
: rOut
.append("Merge Section ");
834 rOut
.append(static_cast<sal_Int64
>(lcl_GetFrameId(static_cast<SwFrame
const *>(pParam
))));
836 case DbgAction::CreateMaster
: bTmp
= true;
838 case DbgAction::CreateFollow
: rOut
.append("Create Section ");
840 rOut
.append("Master to ");
842 rOut
.append("Follow from ");
843 rOut
.append(static_cast<sal_Int64
>(lcl_GetFrameId(static_cast<SwFrame
const *>(pParam
))));
845 case DbgAction::DelMaster
: bTmp
= true;
847 case DbgAction::DelFollow
: rOut
.append("Delete Section ");
849 rOut
.append("Master to ");
851 rOut
.append("Follow from ");
852 rOut
.append(static_cast<sal_Int64
>(lcl_GetFrameId(static_cast<SwFrame
const *>(pParam
))));
859 * if pFrameIds==NULL all Frames will be logged. But as soon as pFrameIds are
860 * set, only the added FrameIds are being logged.
862 * @param nId new FrameId for logging
863 * @return TRUE if newly added, FALSE if FrameId is already under control
865 void SwImplProtocol::InsertFrame( sal_uInt16 nId
)
868 m_pFrameIds
.reset(new std::set
<sal_uInt16
>);
869 if (m_pFrameIds
->count(nId
))
871 m_pFrameIds
->insert(nId
);
874 /// Removes a FrameId from the pFrameIds array, so that it won't be logged anymore.
875 void SwImplProtocol::DeleteFrame( sal_uInt16 nId
)
879 m_pFrameIds
->erase(nId
);
883 * The task here is to find the right SwImplEnterLeave object based on the
884 * function; everything else is then done in his Ctor/Dtor.
886 SwEnterLeave::SwEnterLeave( const SwFrame
* pFrame
, PROT nFunc
, DbgAction nAct
, void* pPar
)
888 if( !SwProtocol::Record( nFunc
) )
894 case PROT::Shrink
: pImpl
.reset( new SwSizeEnterLeave( pFrame
, nFunc
, nAct
, pPar
) ); break;
896 case PROT::MoveBack
: pImpl
.reset( new SwUpperEnterLeave( pFrame
, nFunc
, nAct
, pPar
) ); break;
897 case PROT::FrmChanges
: pImpl
.reset( new SwFrameChangesLeave( pFrame
, nFunc
, nAct
, pPar
) ); break;
898 default: pImpl
.reset( new SwImplEnterLeave( pFrame
, nFunc
, nAct
, pPar
) ); break;
903 /* This is not inline because we don't want the SwImplEnterLeave definition inside
906 SwEnterLeave::~SwEnterLeave()
912 void SwImplEnterLeave::Enter()
914 SwProtocol::Record(m_pFrame
, m_nFunction
, DbgAction::Start
, m_pParam
);
917 void SwImplEnterLeave::Leave() {
918 SwProtocol::Record(m_pFrame
, m_nFunction
, DbgAction::End
, m_pParam
);
921 void SwSizeEnterLeave::Leave()
923 m_nFrameHeight
= m_pFrame
->getFrameArea().Height() - m_nFrameHeight
;
924 SwProtocol::Record(m_pFrame
, m_nFunction
, DbgAction::End
, &m_nFrameHeight
);
927 void SwUpperEnterLeave::Enter()
929 m_nFrameId
= m_pFrame
->GetUpper() ? sal_uInt16(lcl_GetFrameId(m_pFrame
->GetUpper())) : 0;
930 SwProtocol::Record(m_pFrame
, m_nFunction
, DbgAction::Start
, &m_nFrameId
);
933 void SwUpperEnterLeave::Leave()
935 m_nFrameId
= m_pFrame
->GetUpper() ? sal_uInt16(lcl_GetFrameId(m_pFrame
->GetUpper())) : 0;
936 SwProtocol::Record(m_pFrame
, m_nFunction
, DbgAction::End
, &m_nFrameId
);
939 void SwFrameChangesLeave::Enter()
943 void SwFrameChangesLeave::Leave()
945 if (m_pFrame
->getFrameArea() != m_aFrame
)
946 SwProtocol::Record(m_pFrame
, PROT::FrmChanges
, DbgAction::NONE
, &m_aFrame
);
951 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */