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 .
20 #include <vcl/outdev.hxx>
21 #include <SwPortionHandler.hxx>
25 #include "pormulti.hxx"
26 #if OSL_DEBUG_LEVEL > 0
28 static bool ChkChain( SwLinePortion
*pStart
)
30 SwLinePortion
*pPor
= pStart
->GetNextPortion();
31 sal_uInt16 nCount
= 0;
35 OSL_ENSURE( nCount
< 200 && pPor
!= pStart
,
36 "ChkChain(): lost in chains" );
37 if( nCount
>= 200 || pPor
== pStart
)
40 pPor
= pStart
->GetNextPortion();
41 pStart
->SetNextPortion(nullptr);
43 pStart
->SetNextPortion( pPor
);
46 pPor
= pPor
->GetNextPortion();
52 SwLinePortion::~SwLinePortion()
56 SwLinePortion
*SwLinePortion::Compress()
58 return GetLen() || Width() ? this : nullptr;
61 sal_uInt16
SwLinePortion::GetViewWidth( const SwTextSizeInfo
& ) const
66 SwLinePortion::SwLinePortion( ) :
67 mpNextPortion( nullptr ),
70 mnHangingBaseline( 0 ),
71 mnWhichPor( PortionType::NONE
),
72 m_bJoinBorderWithPrev(false),
73 m_bJoinBorderWithNext(false)
77 void SwLinePortion::PrePaint( const SwTextPaintInfo
& rInf
,
78 const SwLinePortion
* pLast
) const
80 OSL_ENSURE( rInf
.OnWin(), "SwLinePortion::PrePaint: don't prepaint on a printer");
81 OSL_ENSURE( !Width(), "SwLinePortion::PrePaint: For Width()==0 only!");
83 const sal_uInt16 nViewWidth
= GetViewWidth( rInf
);
88 const sal_uInt16 nHalfView
= nViewWidth
/ 2;
89 sal_uInt16 nLastWidth
= pLast
->Width();
91 if ( pLast
->InSpaceGrp() && rInf
.GetSpaceAdd() )
92 nLastWidth
= nLastWidth
+ o3tl::narrowing
<sal_uInt16
>(pLast
->CalcSpacing( rInf
.GetSpaceAdd(), rInf
));
95 SwTextPaintInfo
aInf( rInf
);
97 const bool bBidiPor
= rInf
.GetTextFrame()->IsRightToLeft() !=
98 bool( vcl::text::ComplexTextLayoutFlags::BiDiRtl
& rInf
.GetOut()->GetLayoutMode() );
100 Degree10 nDir
= bBidiPor
?
102 rInf
.GetFont()->GetOrientation( rInf
.GetTextFrame()->IsVertical() );
104 // pLast == this *only* for the 1st portion in the line so nLastWidth is 0;
105 // allow this too, will paint outside the frame but might look better...
106 if (nLastWidth
> nHalfView
|| pLast
== this)
111 nPos
= sal_uInt16( rInf
.X() );
112 nPos
+= nLastWidth
- nHalfView
;
116 nPos
= sal_uInt16( rInf
.Y() );
117 nPos
-= nLastWidth
- nHalfView
;
121 nPos
= sal_uInt16( rInf
.X() );
122 nPos
-= nLastWidth
- nHalfView
;
126 nPos
= sal_uInt16( rInf
.Y() );
127 nPos
+= nLastWidth
- nHalfView
;
133 SwLinePortion
*pThis
= const_cast<SwLinePortion
*>(this);
134 pThis
->Width( nViewWidth
);
139 void SwLinePortion::CalcTextSize( const SwTextSizeInfo
&rInf
)
141 if( GetLen() == rInf
.GetLen() )
142 *static_cast<SwPosSize
*>(this) = GetTextSize( rInf
);
145 SwTextSizeInfo
aInf( rInf
);
146 aInf
.SetLen( GetLen() );
147 *static_cast<SwPosSize
*>(this) = GetTextSize( aInf
);
151 // all following portions will be deleted
152 void SwLinePortion::Truncate_()
154 SwLinePortion
*pPos
= mpNextPortion
;
157 OSL_ENSURE( pPos
!= this, "SwLinePortion::Truncate: loop" );
158 SwLinePortion
*pLast
= pPos
;
159 pPos
= pPos
->GetNextPortion();
160 pLast
->SetNextPortion( nullptr );
165 mpNextPortion
= nullptr;
168 // It always will be inserted after us.
169 SwLinePortion
*SwLinePortion::Insert( SwLinePortion
*pIns
)
171 pIns
->FindLastPortion()->SetNextPortion( mpNextPortion
);
172 SetNextPortion( pIns
);
173 #if OSL_DEBUG_LEVEL > 0
179 SwLinePortion
*SwLinePortion::FindLastPortion()
181 SwLinePortion
*pPos
= this;
182 // Find the end and link pLinPortion to the last one...
183 while( pPos
->GetNextPortion() )
185 pPos
= pPos
->GetNextPortion();
190 SwLinePortion
*SwLinePortion::Append( SwLinePortion
*pIns
)
192 SwLinePortion
*pPos
= FindLastPortion();
193 pPos
->SetNextPortion( pIns
);
194 pIns
->SetNextPortion( nullptr );
195 #if OSL_DEBUG_LEVEL > 0
201 SwLinePortion
*SwLinePortion::Cut( SwLinePortion
*pVictim
)
203 SwLinePortion
*pPrev
= pVictim
->FindPrevPortion( this );
204 OSL_ENSURE( pPrev
, "SwLinePortion::Cut(): can't cut" );
205 // note: if pVictim is a follow then clearing pPrev's m_bHasFollow here is
206 // tricky because it could be that the HookChar inserted a tab portion
207 // between 2 field portions
208 pPrev
->SetNextPortion( pVictim
->GetNextPortion() );
209 pVictim
->SetNextPortion(nullptr);
213 SwLinePortion
*SwLinePortion::FindPrevPortion( const SwLinePortion
*pRoot
)
215 OSL_ENSURE( pRoot
!= this, "SwLinePortion::FindPrevPortion(): invalid root" );
216 SwLinePortion
*pPos
= const_cast<SwLinePortion
*>(pRoot
);
217 while( pPos
->GetNextPortion() && pPos
->GetNextPortion() != this )
219 pPos
= pPos
->GetNextPortion();
221 OSL_ENSURE( pPos
->GetNextPortion(),
222 "SwLinePortion::FindPrevPortion: blowing in the wind");
226 TextFrameIndex
SwLinePortion::GetModelPositionForViewPoint(const sal_uInt16 nOfst
) const
228 if( nOfst
> ( PrtWidth() / 2 ) )
231 return TextFrameIndex(0);
234 SwPosSize
SwLinePortion::GetTextSize( const SwTextSizeInfo
& ) const
236 OSL_ENSURE( false, "SwLinePortion::GetTextSize: don't ask me about sizes, "
237 "I'm only a stupid SwLinePortion" );
241 bool SwLinePortion::Format( SwTextFormatInfo
&rInf
)
243 if( rInf
.X() > rInf
.Width() )
246 rInf
.SetUnderflow( this );
250 const SwLinePortion
*pLast
= rInf
.GetLast();
251 Height( pLast
->Height() );
252 SetAscent( pLast
->GetAscent() );
253 const sal_uInt16 nNewWidth
= o3tl::narrowing
<sal_uInt16
>(rInf
.X() + PrtWidth());
254 // Only portions with true width can return true
255 // Notes for example never set bFull==true
256 if( rInf
.Width() <= nNewWidth
&& PrtWidth() && ! IsKernPortion() )
259 if( nNewWidth
> rInf
.Width() )
260 PrtWidth( nNewWidth
- rInf
.Width() );
261 rInf
.GetLast()->FormatEOL( rInf
);
267 // Format end of line
269 void SwLinePortion::FormatEOL( SwTextFormatInfo
& )
272 void SwLinePortion::Move( SwTextPaintInfo
&rInf
)
274 bool bB2T
= rInf
.GetDirection() == DIR_BOTTOM2TOP
;
275 const bool bFrameDir
= rInf
.GetTextFrame()->IsRightToLeft();
276 bool bCounterDir
= ( ! bFrameDir
&& DIR_RIGHT2LEFT
== rInf
.GetDirection() ) ||
277 ( bFrameDir
&& DIR_LEFT2RIGHT
== rInf
.GetDirection() );
279 if ( InSpaceGrp() && rInf
.GetSpaceAdd() )
281 SwTwips nTmp
= PrtWidth() + CalcSpacing( rInf
.GetSpaceAdd(), rInf
);
282 if( rInf
.IsRotated() )
283 rInf
.Y( rInf
.Y() + ( bB2T
? -nTmp
: nTmp
) );
284 else if ( bCounterDir
)
285 rInf
.X( rInf
.X() - nTmp
);
287 rInf
.X( rInf
.X() + nTmp
);
291 if( InFixMargGrp() && !IsMarginPortion() )
296 if( rInf
.IsRotated() )
297 rInf
.Y( rInf
.Y() + ( bB2T
? -PrtWidth() : PrtWidth() ) );
298 else if ( bCounterDir
)
299 rInf
.X( rInf
.X() - PrtWidth() );
301 rInf
.X( rInf
.X() + PrtWidth() );
303 if( IsMultiPortion() && static_cast<SwMultiPortion
*>(this)->HasTabulator() )
306 rInf
.SetIdx( rInf
.GetIdx() + GetLen() );
309 tools::Long
SwLinePortion::CalcSpacing( tools::Long
, const SwTextSizeInfo
& ) const
314 bool SwLinePortion::GetExpText( const SwTextSizeInfo
&, OUString
& ) const
319 void SwLinePortion::HandlePortion( SwPortionHandler
& rPH
) const
321 rPH
.Special( GetLen(), OUString(), GetWhichPor() );
324 void SwLinePortion::dumpAsXml(xmlTextWriterPtr pWriter
, const OUString
& rText
, TextFrameIndex
& nOffset
) const
326 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwLinePortion"));
327 dumpAsXmlAttributes(pWriter
, rText
, nOffset
);
330 (void)xmlTextWriterEndElement(pWriter
);
333 void SwLinePortion::dumpAsXmlAttributes(xmlTextWriterPtr pWriter
, std::u16string_view rText
, TextFrameIndex nOffset
) const
335 (void)xmlTextWriterWriteFormatAttribute(pWriter
, BAD_CAST("ptr"), "%p", this);
336 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("symbol"), BAD_CAST(typeid(*this).name()));
337 (void)xmlTextWriterWriteAttribute(
338 pWriter
, BAD_CAST("width"),
339 BAD_CAST(OString::number(Width()).getStr()));
340 (void)xmlTextWriterWriteAttribute(
341 pWriter
, BAD_CAST("height"),
342 BAD_CAST(OString::number(Height()).getStr()));
343 (void)xmlTextWriterWriteAttribute(
344 pWriter
, BAD_CAST("length"),
345 BAD_CAST(OString::number(static_cast<sal_Int32
>(mnLineLength
)).getStr()));
346 (void)xmlTextWriterWriteAttribute(
347 pWriter
, BAD_CAST("type"),
348 BAD_CAST(sw::PortionTypeToString(GetWhichPor())));
349 OUString
aText( rText
.substr(sal_Int32(nOffset
), sal_Int32(GetLen())) );
350 for (int i
= 0; i
< 32; ++i
)
351 aText
= aText
.replace(i
, '*');
352 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("portion"),
353 BAD_CAST(aText
.toUtf8().getStr()));
356 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */