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 #include <vcl/outdev.hxx>
21 #include <SwPortionHandler.hxx>
22
23 #include "porlin.hxx"
24 #include "inftxt.hxx"
25 #include "portxt.hxx"
26 #include "pormulti.hxx"
27 #include "porglue.hxx"
28 #include <blink.hxx>
29 #if OSL_DEBUG_LEVEL > 0
30
ChkChain(SwLinePortion * pStart)31 static bool ChkChain( SwLinePortion *pStart )
32 {
33 SwLinePortion *pPor = pStart->GetNextPortion();
34 sal_uInt16 nCount = 0;
35 while( pPor )
36 {
37 ++nCount;
38 OSL_ENSURE( nCount < 200 && pPor != pStart,
39 "ChkChain(): lost in chains" );
40 if( nCount >= 200 || pPor == pStart )
41 {
42 // the lifesaver
43 pPor = pStart->GetNextPortion();
44 pStart->SetNextPortion(nullptr);
45 pPor->Truncate();
46 pStart->SetNextPortion( pPor );
47 return false;
48 }
49 pPor = pPor->GetNextPortion();
50 }
51 return true;
52 }
53 #endif
54
~SwLinePortion()55 SwLinePortion::~SwLinePortion()
56 {
57 if( pBlink )
58 pBlink->Delete( this );
59 }
60
Compress()61 SwLinePortion *SwLinePortion::Compress()
62 {
63 return GetLen() || Width() ? this : nullptr;
64 }
65
GetViewWidth(const SwTextSizeInfo &) const66 sal_uInt16 SwLinePortion::GetViewWidth( const SwTextSizeInfo & ) const
67 {
68 return 0;
69 }
70
SwLinePortion()71 SwLinePortion::SwLinePortion( ) :
72 mpNextPortion( nullptr ),
73 nLineLength( 0 ),
74 nAscent( 0 ),
75 nWhichPor( PortionType::NONE ),
76 m_bJoinBorderWithPrev(false),
77 m_bJoinBorderWithNext(false)
78 {
79 }
80
PrePaint(const SwTextPaintInfo & rInf,const SwLinePortion * pLast) const81 void SwLinePortion::PrePaint( const SwTextPaintInfo& rInf,
82 const SwLinePortion* pLast ) const
83 {
84 OSL_ENSURE( rInf.OnWin(), "SwLinePortion::PrePaint: don't prepaint on a printer");
85 OSL_ENSURE( !Width(), "SwLinePortion::PrePaint: For Width()==0 only!");
86
87 const sal_uInt16 nViewWidth = GetViewWidth( rInf );
88
89 if( ! nViewWidth )
90 return;
91
92 const sal_uInt16 nHalfView = nViewWidth / 2;
93 sal_uInt16 nLastWidth = pLast->Width();
94
95 if ( pLast->InSpaceGrp() && rInf.GetSpaceAdd() )
96 nLastWidth = nLastWidth + static_cast<sal_uInt16>(pLast->CalcSpacing( rInf.GetSpaceAdd(), rInf ));
97
98 sal_uInt16 nPos;
99 SwTextPaintInfo aInf( rInf );
100
101 const bool bBidiPor = rInf.GetTextFrame()->IsRightToLeft() !=
102 bool( ComplexTextLayoutFlags::BiDiRtl & rInf.GetOut()->GetLayoutMode() );
103
104 sal_uInt16 nDir = bBidiPor ?
105 1800 :
106 rInf.GetFont()->GetOrientation( rInf.GetTextFrame()->IsVertical() );
107
108 switch ( nDir )
109 {
110 case 0 :
111 nPos = sal_uInt16( rInf.X() );
112 if( nLastWidth > nHalfView )
113 nPos += nLastWidth - nHalfView;
114 aInf.X( nPos );
115 break;
116 case 900 :
117 nPos = sal_uInt16( rInf.Y() );
118 if( nLastWidth > nHalfView )
119 nPos -= nLastWidth + nHalfView;
120 aInf.Y( nPos );
121 break;
122 case 1800 :
123 nPos = sal_uInt16( rInf.X() );
124 if( nLastWidth > nHalfView )
125 nPos -= nLastWidth + nHalfView;
126 aInf.X( nPos );
127 break;
128 case 2700 :
129 nPos = sal_uInt16( rInf.Y() );
130 if( nLastWidth > nHalfView )
131 nPos += nLastWidth - nHalfView;
132 aInf.Y( nPos );
133 break;
134 }
135
136 SwLinePortion *pThis = const_cast<SwLinePortion*>(this);
137 pThis->Width( nViewWidth );
138 Paint( aInf );
139 pThis->Width(0);
140 }
141
CalcTextSize(const SwTextSizeInfo & rInf)142 void SwLinePortion::CalcTextSize( const SwTextSizeInfo &rInf )
143 {
144 if( GetLen() == rInf.GetLen() )
145 *static_cast<SwPosSize*>(this) = GetTextSize( rInf );
146 else
147 {
148 SwTextSizeInfo aInf( rInf );
149 aInf.SetLen( GetLen() );
150 *static_cast<SwPosSize*>(this) = GetTextSize( aInf );
151 }
152 }
153
154 // all following portions will be deleted
Truncate_()155 void SwLinePortion::Truncate_()
156 {
157 SwLinePortion *pPos = mpNextPortion;
158 do
159 {
160 OSL_ENSURE( pPos != this, "SwLinePortion::Truncate: loop" );
161 SwLinePortion *pLast = pPos;
162 pPos = pPos->GetNextPortion();
163 pLast->SetNextPortion( nullptr );
164 delete pLast;
165
166 } while( pPos );
167
168 mpNextPortion = nullptr;
169 }
170
171 // It always will be inserted after us.
Insert(SwLinePortion * pIns)172 SwLinePortion *SwLinePortion::Insert( SwLinePortion *pIns )
173 {
174 pIns->FindLastPortion()->SetNextPortion( mpNextPortion );
175 SetNextPortion( pIns );
176 #if OSL_DEBUG_LEVEL > 0
177 ChkChain( this );
178 #endif
179 return pIns;
180 }
181
FindLastPortion()182 SwLinePortion *SwLinePortion::FindLastPortion()
183 {
184 SwLinePortion *pPos = this;
185 // Find the end and link pLinPortion to the last one...
186 while( pPos->GetNextPortion() )
187 {
188 pPos = pPos->GetNextPortion();
189 }
190 return pPos;
191 }
192
Append(SwLinePortion * pIns)193 SwLinePortion *SwLinePortion::Append( SwLinePortion *pIns )
194 {
195 SwLinePortion *pPos = FindLastPortion();
196 pPos->SetNextPortion( pIns );
197 pIns->SetNextPortion( nullptr );
198 #if OSL_DEBUG_LEVEL > 0
199 ChkChain( this );
200 #endif
201 return pIns;
202 }
203
Cut(SwLinePortion * pVictim)204 SwLinePortion *SwLinePortion::Cut( SwLinePortion *pVictim )
205 {
206 SwLinePortion *pPrev = pVictim->FindPrevPortion( this );
207 OSL_ENSURE( pPrev, "SwLinePortion::Cut(): can't cut" );
208 pPrev->SetNextPortion( pVictim->GetNextPortion() );
209 pVictim->SetNextPortion(nullptr);
210 return pVictim;
211 }
212
FindPrevPortion(const SwLinePortion * pRoot)213 SwLinePortion *SwLinePortion::FindPrevPortion( const SwLinePortion *pRoot )
214 {
215 OSL_ENSURE( pRoot != this, "SwLinePortion::FindPrevPortion(): invalid root" );
216 SwLinePortion *pPos = const_cast<SwLinePortion*>(pRoot);
217 while( pPos->GetNextPortion() && pPos->GetNextPortion() != this )
218 {
219 pPos = pPos->GetNextPortion();
220 }
221 OSL_ENSURE( pPos->GetNextPortion(),
222 "SwLinePortion::FindPrevPortion: blowing in the wind");
223 return pPos;
224 }
225
GetCursorOfst(const sal_uInt16 nOfst) const226 TextFrameIndex SwLinePortion::GetCursorOfst(const sal_uInt16 nOfst) const
227 {
228 if( nOfst > ( PrtWidth() / 2 ) )
229 return GetLen();
230 else
231 return TextFrameIndex(0);
232 }
233
GetTextSize(const SwTextSizeInfo &) const234 SwPosSize SwLinePortion::GetTextSize( const SwTextSizeInfo & ) const
235 {
236 OSL_ENSURE( false, "SwLinePortion::GetTextSize: don't ask me about sizes, "
237 "I'm only a stupid SwLinePortion" );
238 return SwPosSize();
239 }
240
Format(SwTextFormatInfo & rInf)241 bool SwLinePortion::Format( SwTextFormatInfo &rInf )
242 {
243 if( rInf.X() > rInf.Width() )
244 {
245 Truncate();
246 rInf.SetUnderflow( this );
247 return true;
248 }
249
250 const SwLinePortion *pLast = rInf.GetLast();
251 Height( pLast->Height() );
252 SetAscent( pLast->GetAscent() );
253 const sal_uInt16 nNewWidth = static_cast<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() )
257 {
258 Truncate();
259 if( nNewWidth > rInf.Width() )
260 PrtWidth( nNewWidth - rInf.Width() );
261 rInf.GetLast()->FormatEOL( rInf );
262 return true;
263 }
264 return false;
265 }
266
267 // Format end of line
268
FormatEOL(SwTextFormatInfo &)269 void SwLinePortion::FormatEOL( SwTextFormatInfo & )
270 { }
271
Move(SwTextPaintInfo & rInf)272 void SwLinePortion::Move( SwTextPaintInfo &rInf )
273 {
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() );
278
279 if ( InSpaceGrp() && rInf.GetSpaceAdd() )
280 {
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 );
286 else
287 rInf.X( rInf.X() + nTmp );
288 }
289 else
290 {
291 if( InFixMargGrp() && !IsMarginPortion() )
292 {
293 rInf.IncSpaceIdx();
294 rInf.IncKanaIdx();
295 }
296 if( rInf.IsRotated() )
297 rInf.Y( rInf.Y() + ( bB2T ? -PrtWidth() : PrtWidth() ) );
298 else if ( bCounterDir )
299 rInf.X( rInf.X() - PrtWidth() );
300 else
301 rInf.X( rInf.X() + PrtWidth() );
302 }
303 if( IsMultiPortion() && static_cast<SwMultiPortion*>(this)->HasTabulator() )
304 rInf.IncSpaceIdx();
305
306 rInf.SetIdx( rInf.GetIdx() + GetLen() );
307 }
308
CalcSpacing(long,const SwTextSizeInfo &) const309 long SwLinePortion::CalcSpacing( long , const SwTextSizeInfo & ) const
310 {
311 return 0;
312 }
313
GetExpText(const SwTextSizeInfo &,OUString &) const314 bool SwLinePortion::GetExpText( const SwTextSizeInfo &, OUString & ) const
315 {
316 return false;
317 }
318
HandlePortion(SwPortionHandler & rPH) const319 void SwLinePortion::HandlePortion( SwPortionHandler& rPH ) const
320 {
321 rPH.Special( GetLen(), OUString(), GetWhichPor(), Height(), Width() );
322 }
323
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
325