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