Line data Source code
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 :
21 : #include "hintids.hxx"
22 : #include "ndtxt.hxx"
23 : #include "frmfmt.hxx"
24 : #include "paratr.hxx"
25 : #include "flyfrm.hxx"
26 : #include "pam.hxx"
27 : #include "swselectionlist.hxx"
28 : #include <sortedobjs.hxx>
29 : #include <editeng/protitem.hxx>
30 : #include <editeng/adjitem.hxx>
31 : #include <editeng/lspcitem.hxx>
32 : #include <editeng/lrspitem.hxx>
33 : #include <frmatr.hxx>
34 : #include <pagedesc.hxx> // SwPageDesc
35 : #include <tgrditem.hxx>
36 : #include <IDocumentSettingAccess.hxx>
37 : #include <pagefrm.hxx>
38 :
39 : #include "itrtxt.hxx"
40 : #include "txtfrm.hxx"
41 : #include "flyfrms.hxx"
42 : #include "porglue.hxx" // SwFlyCnt
43 : #include "porfld.hxx" // SwFldPortion::IsFollow()
44 : #include "porfly.hxx" // GetFlyCrsrOfst()
45 : #include "pordrop.hxx"
46 : #include "crstate.hxx" // SwCrsrMoveState
47 : #include <pormulti.hxx> // SwMultiPortion
48 : // #i111284#
49 : #include <numrule.hxx>
50 :
51 : // Nicht reentrant !!!
52 : // wird in GetCharRect gesetzt und im UnitUp/Down ausgewertet.
53 : sal_Bool SwTxtCursor::bRightMargin = sal_False;
54 :
55 :
56 : /*************************************************************************
57 : * lcl_GetCharRectInsideField
58 : *
59 : * After calculating the position of a character during GetCharRect
60 : * this function allows to find the coordinates of a position (defined
61 : * in pCMS->pSpecialPos) inside a special portion (e.g., a field)
62 : *************************************************************************/
63 0 : static void lcl_GetCharRectInsideField( SwTxtSizeInfo& rInf, SwRect& rOrig,
64 : const SwCrsrMoveState& rCMS,
65 : const SwLinePortion& rPor )
66 : {
67 : OSL_ENSURE( rCMS.pSpecialPos, "Information about special pos missing" );
68 :
69 0 : if ( rPor.InFldGrp() && ((SwFldPortion&)rPor).GetExp().Len() )
70 : {
71 0 : const sal_uInt16 nCharOfst = rCMS.pSpecialPos->nCharOfst;
72 0 : sal_uInt16 nFldIdx = 0;
73 0 : sal_uInt16 nFldLen = 0;
74 :
75 0 : const XubString* pString = 0;
76 0 : const SwLinePortion* pPor = &rPor;
77 0 : do
78 : {
79 0 : if ( pPor->InFldGrp() )
80 : {
81 0 : pString = &((SwFldPortion*)pPor)->GetExp();
82 0 : nFldLen = pString->Len();
83 : }
84 : else
85 : {
86 0 : pString = 0;
87 0 : nFldLen = 0;
88 : }
89 :
90 0 : if ( ! pPor->GetPortion() || nFldIdx + nFldLen > nCharOfst )
91 0 : break;
92 :
93 0 : nFldIdx = nFldIdx + nFldLen;
94 0 : rOrig.Pos().X() += pPor->Width();
95 0 : pPor = pPor->GetPortion();
96 :
97 : } while ( sal_True );
98 :
99 : OSL_ENSURE( nCharOfst >= nFldIdx, "Request of position inside field failed" );
100 0 : sal_uInt16 nLen = nCharOfst - nFldIdx + 1;
101 :
102 0 : if ( pString )
103 : {
104 : // get script for field portion
105 0 : rInf.GetFont()->SetActual( SwScriptInfo::WhichFont( 0, pString, 0 ) );
106 :
107 0 : xub_StrLen nOldLen = pPor->GetLen();
108 0 : ((SwLinePortion*)pPor)->SetLen( nLen - 1 );
109 0 : const SwTwips nX1 = pPor->GetLen() ?
110 0 : pPor->GetTxtSize( rInf ).Width() :
111 0 : 0;
112 :
113 0 : SwTwips nX2 = 0;
114 0 : if ( rCMS.bRealWidth )
115 : {
116 0 : ((SwLinePortion*)pPor)->SetLen( nLen );
117 0 : nX2 = pPor->GetTxtSize( rInf ).Width();
118 : }
119 :
120 0 : ((SwLinePortion*)pPor)->SetLen( nOldLen );
121 :
122 0 : rOrig.Pos().X() += nX1;
123 : rOrig.Width( ( nX2 > nX1 ) ?
124 : ( nX2 - nX1 ) :
125 0 : 1 );
126 : }
127 : }
128 : else
129 : {
130 : // special cases: no common fields, e.g., graphic number portion,
131 : // FlyInCntPortions, Notes
132 0 : rOrig.Width( rCMS.bRealWidth && rPor.Width() ? rPor.Width() : 1 );
133 : }
134 0 : }
135 :
136 : // #i111284#
137 : namespace {
138 4150 : bool AreListLevelIndentsApplicableAndLabelAlignmentActive( const SwTxtNode& rTxtNode )
139 : {
140 4150 : bool bRet( false );
141 :
142 4150 : if ( rTxtNode.AreListLevelIndentsApplicable() )
143 : {
144 : const SwNumFmt& rNumFmt =
145 123 : rTxtNode.GetNumRule()->Get( static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()) );
146 123 : if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
147 : {
148 123 : bRet = true;
149 : }
150 : }
151 :
152 4150 : return bRet;
153 : }
154 : } // end of anonymous namespace
155 :
156 : /*************************************************************************
157 : * SwTxtMargin::CtorInitTxtMargin()
158 : *************************************************************************/
159 4150 : void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
160 : {
161 4150 : CtorInitTxtIter( pNewFrm, pNewInf );
162 :
163 4150 : pInf = pNewInf;
164 4150 : GetInfo().SetFont( GetFnt() );
165 4150 : const SwTxtNode *pNode = pFrm->GetTxtNode();
166 :
167 4150 : const SvxLRSpaceItem &rSpace = pFrm->GetTxtNode()->GetSwAttrSet().GetLRSpace();
168 : // #i95907#
169 : // #i111284#
170 : const bool bListLevelIndentsApplicableAndLabelAlignmentActive(
171 4150 : AreListLevelIndentsApplicableAndLabelAlignmentActive( *(pFrm->GetTxtNode()) ) );
172 :
173 : //
174 : // Carefully adjust the text formatting ranges.
175 : //
176 : // This whole area desperately needs some rework. There are
177 : // quite a couple of values that need to be considered:
178 : // 1. paragraph indent
179 : // 2. paragraph first line indent
180 : // 3. numbering indent
181 : // 4. numbering spacing to text
182 : // 5. paragraph border
183 : // Note: These values have already been used during calculation
184 : // of the printing area of the paragraph.
185 4150 : const int nLMWithNum = pNode->GetLeftMarginWithNum( sal_True );
186 4150 : if ( pFrm->IsRightToLeft() )
187 : {
188 : // this calculation is identical this the calculation for L2R layout - see below
189 0 : nLeft = pFrm->Frm().Left() +
190 0 : pFrm->Prt().Left() +
191 : nLMWithNum -
192 0 : pNode->GetLeftMarginWithNum( sal_False ) -
193 : // #i95907#
194 : // #i111284#
195 : // rSpace.GetLeft() +
196 : // rSpace.GetTxtLeft();
197 : ( bListLevelIndentsApplicableAndLabelAlignmentActive
198 : ? 0
199 0 : : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
200 : }
201 : else
202 : {
203 : // #i95907#
204 : // #i111284#
205 8177 : if ( bListLevelIndentsApplicableAndLabelAlignmentActive ||
206 4027 : !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
207 : {
208 : // this calculation is identical this the calculation for R2L layout - see above
209 4150 : nLeft = pFrm->Frm().Left() +
210 4150 : pFrm->Prt().Left() +
211 : nLMWithNum -
212 4150 : pNode->GetLeftMarginWithNum( sal_False ) -
213 : // #i95907#
214 : // #i111284#
215 : ( bListLevelIndentsApplicableAndLabelAlignmentActive
216 : ? 0
217 8300 : : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
218 : }
219 : else
220 : {
221 0 : nLeft = pFrm->Frm().Left() +
222 0 : Max( long( rSpace.GetTxtLeft() + nLMWithNum ),
223 0 : pFrm->Prt().Left() );
224 : }
225 : }
226 :
227 4150 : nRight = pFrm->Frm().Left() + pFrm->Prt().Left() + pFrm->Prt().Width();
228 :
229 4168 : if( nLeft >= nRight &&
230 : // #i53066# Omit adjustment of nLeft for numbered
231 : // paras inside cells inside new documents:
232 9 : ( pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ||
233 9 : !pFrm->IsInTab() ||
234 : !nLMWithNum ) )
235 : {
236 9 : nLeft = pFrm->Prt().Left() + pFrm->Frm().Left();
237 9 : if( nLeft >= nRight ) // z.B. bei grossen Absatzeinzuegen in schmalen Tabellenspalten
238 5 : nRight = nLeft + 1; // einen goennen wir uns immer
239 : }
240 :
241 4150 : if( pFrm->IsFollow() && pFrm->GetOfst() )
242 0 : nFirst = nLeft;
243 : else
244 : {
245 4150 : short nFLOfst = 0;
246 4150 : long nFirstLineOfs = 0;
247 8118 : if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) &&
248 3968 : rSpace.IsAutoFirst() )
249 : {
250 0 : nFirstLineOfs = GetFnt()->GetSize( GetFnt()->GetActual() ).Height();
251 0 : const SvxLineSpacingItem *pSpace = aLineInf.GetLineSpacing();
252 0 : if( pSpace )
253 : {
254 0 : switch( pSpace->GetLineSpaceRule() )
255 : {
256 : case SVX_LINE_SPACE_AUTO:
257 0 : break;
258 : case SVX_LINE_SPACE_MIN:
259 : {
260 0 : if( nFirstLineOfs < KSHORT( pSpace->GetLineHeight() ) )
261 0 : nFirstLineOfs = pSpace->GetLineHeight();
262 0 : break;
263 : }
264 : case SVX_LINE_SPACE_FIX:
265 0 : nFirstLineOfs = pSpace->GetLineHeight();
266 0 : break;
267 : default: OSL_FAIL( ": unknown LineSpaceRule" );
268 : }
269 0 : switch( pSpace->GetInterLineSpaceRule() )
270 : {
271 : case SVX_INTER_LINE_SPACE_OFF:
272 0 : break;
273 : case SVX_INTER_LINE_SPACE_PROP:
274 : {
275 0 : long nTmp = pSpace->GetPropLineSpace();
276 : // 50% ist das Minimum, bei 0% schalten wir auf
277 : // den Defaultwert 100% um ...
278 0 : if( nTmp < 50 )
279 0 : nTmp = nTmp ? 50 : 100;
280 :
281 0 : nTmp *= nFirstLineOfs;
282 0 : nTmp /= 100;
283 0 : if( !nTmp )
284 0 : ++nTmp;
285 0 : nFirstLineOfs = (KSHORT)nTmp;
286 0 : break;
287 : }
288 : case SVX_INTER_LINE_SPACE_FIX:
289 : {
290 0 : nFirstLineOfs += pSpace->GetInterLineSpace();
291 0 : break;
292 : }
293 : default: OSL_FAIL( ": unknown InterLineSpaceRule" );
294 : }
295 : }
296 : }
297 : else
298 4150 : nFirstLineOfs = nFLOfst;
299 :
300 : // #i95907#
301 : // #i111284#
302 8177 : if ( pFrm->IsRightToLeft() ||
303 : bListLevelIndentsApplicableAndLabelAlignmentActive ||
304 4027 : !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
305 : {
306 4150 : nFirst = nLeft + nFirstLineOfs;
307 : }
308 : else
309 : {
310 0 : nFirst = pFrm->Frm().Left() +
311 0 : Max( rSpace.GetTxtLeft() + nLMWithNum+ nFirstLineOfs,
312 0 : pFrm->Prt().Left() );
313 : }
314 :
315 : // Note: <SwTxtFrm::GetAdditionalFirstLineOffset()> returns a negative
316 : // value for the new list label postion and space mode LABEL_ALIGNMENT
317 : // and label alignment CENTER and RIGHT in L2R layout respectively
318 : // label alignment LEFT and CENTER in R2L layout
319 4150 : nFirst += pFrm->GetAdditionalFirstLineOffset();
320 :
321 4150 : if( nFirst >= nRight )
322 0 : nFirst = nRight - 1;
323 : }
324 4150 : const SvxAdjustItem& rAdjust = pFrm->GetTxtNode()->GetSwAttrSet().GetAdjust();
325 4150 : nAdjust = static_cast<sal_uInt16>(rAdjust.GetAdjust());
326 :
327 : // left is left and right is right
328 4150 : if ( pFrm->IsRightToLeft() )
329 : {
330 0 : if ( SVX_ADJUST_LEFT == nAdjust )
331 0 : nAdjust = SVX_ADJUST_RIGHT;
332 0 : else if ( SVX_ADJUST_RIGHT == nAdjust )
333 0 : nAdjust = SVX_ADJUST_LEFT;
334 : }
335 :
336 4150 : bOneBlock = rAdjust.GetOneWord() == SVX_ADJUST_BLOCK;
337 4150 : bLastBlock = rAdjust.GetLastBlock() == SVX_ADJUST_BLOCK;
338 4150 : bLastCenter = rAdjust.GetLastBlock() == SVX_ADJUST_CENTER;
339 :
340 : // #i91133#
341 4150 : mnTabLeft = pNode->GetLeftMarginForTabCalculation();
342 :
343 : #if OSL_DEBUG_LEVEL > 1
344 : static sal_Bool bOne = sal_False;
345 : static sal_Bool bLast = sal_False;
346 : static sal_Bool bCenter = sal_False;
347 : bOneBlock |= bOne;
348 : bLastBlock |= bLast;
349 : bLastCenter |= bCenter;
350 : #endif
351 4150 : DropInit();
352 4150 : }
353 :
354 : /*************************************************************************
355 : * SwTxtMargin::DropInit()
356 : *************************************************************************/
357 4150 : void SwTxtMargin::DropInit()
358 : {
359 4150 : nDropLeft = nDropLines = nDropHeight = nDropDescent = 0;
360 4150 : const SwParaPortion *pPara = GetInfo().GetParaPortion();
361 4150 : if( pPara )
362 : {
363 4150 : const SwDropPortion *pPorDrop = pPara->FindDropPortion();
364 4150 : if ( pPorDrop )
365 : {
366 0 : nDropLeft = pPorDrop->GetDropLeft();
367 0 : nDropLines = pPorDrop->GetLines();
368 0 : nDropHeight = pPorDrop->GetDropHeight();
369 0 : nDropDescent = pPorDrop->GetDropDescent();
370 : }
371 : }
372 4150 : }
373 :
374 : /*************************************************************************
375 : * SwTxtMargin::GetLineStart()
376 : *************************************************************************/
377 :
378 : // Unter Beruecksichtigung des Erstzeileneinzuges und der angebenen Breite.
379 3489 : SwTwips SwTxtMargin::GetLineStart() const
380 : {
381 3489 : SwTwips nRet = GetLeftMargin();
382 3684 : if( GetAdjust() != SVX_ADJUST_LEFT &&
383 195 : !pCurr->GetFirstPortion()->IsMarginPortion() )
384 : {
385 : // Wenn die erste Portion ein Margin ist, dann wird das
386 : // Adjustment durch die Portions ausgedrueckt.
387 73 : if( GetAdjust() == SVX_ADJUST_RIGHT )
388 6 : nRet = Right() - CurrWidth();
389 67 : else if( GetAdjust() == SVX_ADJUST_CENTER )
390 31 : nRet += (GetLineWidth() - CurrWidth()) / 2;
391 : }
392 3489 : return nRet;
393 : }
394 :
395 : /*************************************************************************
396 : * SwTxtCursor::CtorInitTxtCursor()
397 : *************************************************************************/
398 3443 : void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
399 : {
400 3443 : CtorInitTxtMargin( pNewFrm, pNewInf );
401 : // 6096: Vorsicht, die Iteratoren sind abgeleitet!
402 : // GetInfo().SetOut( GetInfo().GetWin() );
403 3443 : }
404 :
405 : /*************************************************************************
406 : * SwTxtCursor::GetEndCharRect()
407 : *************************************************************************/
408 :
409 : // 1170: Antikbug: Shift-Ende vergisst das letzte Zeichen ...
410 :
411 0 : sal_Bool SwTxtCursor::GetEndCharRect( SwRect* pOrig, const xub_StrLen nOfst,
412 : SwCrsrMoveState* pCMS, const long nMax )
413 : {
414 : // 1170: Mehrdeutigkeit von Dokumentpositionen
415 0 : bRightMargin = sal_True;
416 0 : CharCrsrToLine(nOfst);
417 :
418 : // Etwas verdreht: nOfst bezeichnet die Position hinter dem letzten
419 : // Zeichen der letzten Zeile == Position vor dem ersten Zeichen der
420 : // Zeile in der wir gerade stehen:
421 0 : if( nOfst != GetStart() || !pCurr->GetLen() )
422 : {
423 : // 8810: Masterzeile RightMargin, danach LeftMargin
424 0 : const sal_Bool bRet = GetCharRect( pOrig, nOfst, pCMS, nMax );
425 0 : bRightMargin = nOfst >= GetEnd() && nOfst < GetInfo().GetTxt().Len();
426 0 : return bRet;
427 : }
428 :
429 0 : if( !GetPrev() || !GetPrev()->GetLen() || !PrevLine() )
430 0 : return GetCharRect( pOrig, nOfst, pCMS, nMax );
431 :
432 : // Adjustierung ggf. nachholen
433 0 : GetAdjusted();
434 :
435 0 : KSHORT nX = 0;
436 0 : KSHORT nLast = 0;
437 0 : SwLinePortion *pPor = pCurr->GetFirstPortion();
438 :
439 : KSHORT nTmpHeight, nTmpAscent;
440 0 : CalcAscentAndHeight( nTmpAscent, nTmpHeight );
441 0 : KSHORT nPorHeight = nTmpHeight;
442 0 : KSHORT nPorAscent = nTmpAscent;
443 :
444 : // Die letzte Text/EndPortion der Zeile suchen
445 0 : while( pPor )
446 : {
447 0 : nX = nX + pPor->Width();
448 0 : if( pPor->InTxtGrp() || ( pPor->GetLen() && !pPor->IsFlyPortion()
449 0 : && !pPor->IsHolePortion() ) || pPor->IsBreakPortion() )
450 : {
451 0 : nLast = nX;
452 0 : nPorHeight = pPor->Height();
453 0 : nPorAscent = pPor->GetAscent();
454 : }
455 0 : pPor = pPor->GetPortion();
456 : }
457 :
458 0 : const Size aCharSize( 1, nTmpHeight );
459 0 : pOrig->Pos( GetTopLeft() );
460 0 : pOrig->SSize( aCharSize );
461 0 : pOrig->Pos().X() += nLast;
462 0 : const SwTwips nTmpRight = Right() - 1;
463 0 : if( pOrig->Left() > nTmpRight )
464 0 : pOrig->Pos().X() = nTmpRight;
465 :
466 0 : if ( pCMS && pCMS->bRealHeight )
467 : {
468 0 : if ( nTmpAscent > nPorAscent )
469 0 : pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
470 : else
471 0 : pCMS->aRealHeight.X() = 0;
472 : OSL_ENSURE( nPorHeight, "GetCharRect: Missing Portion-Height" );
473 0 : pCMS->aRealHeight.Y() = nPorHeight;
474 : }
475 :
476 0 : return sal_True;
477 : }
478 :
479 : /*************************************************************************
480 : * void SwTxtCursor::_GetCharRect(..)
481 : * internal function, called by SwTxtCursor::GetCharRect() to calculate
482 : * the relative character position in the current line.
483 : * pOrig referes to x and y coordinates, width and height of the cursor
484 : * pCMS is used for restricting the cursor, if there are different font
485 : * heights in one line ( first value = offset to y of pOrig, second
486 : * value = real height of (shortened) cursor
487 : *************************************************************************/
488 :
489 2264 : void SwTxtCursor::_GetCharRect( SwRect* pOrig, const xub_StrLen nOfst,
490 : SwCrsrMoveState* pCMS )
491 : {
492 2264 : const XubString &rText = GetInfo().GetTxt();
493 2264 : SwTxtSizeInfo aInf( GetInfo(), rText, nStart );
494 2264 : if( GetPropFont() )
495 0 : aInf.GetFont()->SetProportion( GetPropFont() );
496 : KSHORT nTmpAscent, nTmpHeight; // Zeilenhoehe
497 2264 : CalcAscentAndHeight( nTmpAscent, nTmpHeight );
498 2264 : const Size aCharSize( 1, nTmpHeight );
499 2264 : const Point aCharPos;
500 2264 : pOrig->Pos( aCharPos );
501 2264 : pOrig->SSize( aCharSize );
502 :
503 : // If we are looking for a position inside a field which covers
504 : // more than one line we may not skip any "empty portions" at the
505 : // beginning of a line
506 : const sal_Bool bInsideFirstField = pCMS && pCMS->pSpecialPos &&
507 : ( pCMS->pSpecialPos->nLineOfst ||
508 : SP_EXTEND_RANGE_BEFORE ==
509 2264 : pCMS->pSpecialPos->nExtendRange );
510 :
511 2264 : sal_Bool bWidth = pCMS && pCMS->bRealWidth;
512 2264 : if( !pCurr->GetLen() && !pCurr->Width() )
513 : {
514 174 : if ( pCMS && pCMS->bRealHeight )
515 : {
516 174 : pCMS->aRealHeight.X() = 0;
517 174 : pCMS->aRealHeight.Y() = nTmpHeight;
518 : }
519 : }
520 : else
521 : {
522 2090 : KSHORT nPorHeight = nTmpHeight;
523 2090 : KSHORT nPorAscent = nTmpAscent;
524 2090 : SwTwips nX = 0;
525 2090 : SwTwips nTmpFirst = 0;
526 2090 : SwLinePortion *pPor = pCurr->GetFirstPortion();
527 2090 : SwBidiPortion* pLastBidiPor = 0;
528 2090 : SwTwips nLastBidiPorWidth = 0;
529 2090 : std::deque<sal_uInt16>* pKanaComp = pCurr->GetpKanaComp();
530 2090 : MSHORT nSpaceIdx = 0;
531 2090 : size_t nKanaIdx = 0;
532 2090 : long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
533 :
534 2090 : sal_Bool bNoTxt = sal_True;
535 :
536 : // Zuerst werden alle Portions ohne Len am Zeilenanfang uebersprungen.
537 : // Ausnahme bilden die fiesen Spezialportions aus WhichFirstPortion:
538 : // Num, ErgoSum, FtnNum, FeldReste
539 : // 8477: aber auch die einzige Textportion einer leeren Zeile mit
540 : // Right/Center-Adjustment! Also nicht nur pPor->GetExpandPortion() ...
541 4412 : while( pPor && !pPor->GetLen() && ! bInsideFirstField )
542 : {
543 232 : nX += pPor->Width();
544 232 : if ( pPor->InSpaceGrp() && nSpaceAdd )
545 0 : nX += pPor->CalcSpacing( nSpaceAdd, aInf );
546 232 : if( bNoTxt )
547 145 : nTmpFirst = nX;
548 : // 8670: EndPortions zaehlen hier einmal als TxtPortions.
549 : // if( pPor->InTxtGrp() || pPor->IsBreakPortion() )
550 232 : if( pPor->InTxtGrp() || pPor->IsBreakPortion() || pPor->InTabGrp() )
551 : {
552 109 : bNoTxt = sal_False;
553 109 : nTmpFirst = nX;
554 : }
555 232 : if( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
556 : {
557 0 : if ( pCurr->IsSpaceAdd() )
558 : {
559 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
560 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
561 : else
562 0 : nSpaceAdd = 0;
563 : }
564 :
565 0 : if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->size() )
566 0 : ++nKanaIdx;
567 : }
568 232 : if( pPor->InFixMargGrp() )
569 : {
570 171 : if( pPor->IsMarginPortion() )
571 118 : bNoTxt = sal_False;
572 : else
573 : {
574 : // fix margin portion => next SpaceAdd, KanaComp value
575 53 : if ( pCurr->IsSpaceAdd() )
576 : {
577 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
578 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
579 : else
580 0 : nSpaceAdd = 0;
581 : }
582 :
583 53 : if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->size() )
584 0 : ++nKanaIdx;
585 : }
586 : }
587 232 : pPor = pPor->GetPortion();
588 : }
589 :
590 2090 : if( !pPor )
591 : {
592 : // Es sind nur Spezialportions unterwegs.
593 31 : nX = nTmpFirst;
594 : }
595 : else
596 : {
597 4130 : if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
598 2071 : (!pPor->InFldGrp() || pPor->GetAscent() ) )
599 : {
600 2059 : nPorHeight = pPor->Height();
601 2059 : nPorAscent = pPor->GetAscent();
602 : }
603 4264 : while( pPor && !pPor->IsBreakPortion() && ( aInf.GetIdx() < nOfst ||
604 0 : ( bWidth && ( pPor->IsKernPortion() || pPor->IsMultiPortion() ) ) ) )
605 : {
606 292 : if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
607 146 : (!pPor->InFldGrp() || pPor->GetAscent() ) )
608 : {
609 146 : nPorHeight = pPor->Height();
610 146 : nPorAscent = pPor->GetAscent();
611 : }
612 :
613 : // If we are behind the portion, we add the portion width to
614 : // nX. Special case: nOfst = aInf.GetIdx() + pPor->GetLen().
615 : // For common portions (including BidiPortions) we want to add
616 : // the portion width to nX. For MultiPortions, nExtra = 0,
617 : // therefore we go to the 'else' branch and start a recursion.
618 146 : const sal_uInt8 nExtra = pPor->IsMultiPortion() &&
619 0 : ! ((SwMultiPortion*)pPor)->IsBidi() &&
620 146 : ! bWidth ? 0 : 1;
621 146 : if ( aInf.GetIdx() + pPor->GetLen() < nOfst + nExtra )
622 : {
623 146 : if ( pPor->InSpaceGrp() && nSpaceAdd )
624 0 : nX += pPor->PrtWidth() +
625 0 : pPor->CalcSpacing( nSpaceAdd, aInf );
626 : else
627 : {
628 146 : if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
629 : {
630 : // update to current SpaceAdd, KanaComp values
631 4 : if ( pCurr->IsSpaceAdd() )
632 : {
633 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
634 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
635 : else
636 0 : nSpaceAdd = 0;
637 : }
638 :
639 4 : if ( pKanaComp &&
640 0 : ( nKanaIdx + 1 ) < pKanaComp->size()
641 : )
642 0 : ++nKanaIdx;
643 : }
644 146 : if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
645 0 : !pPor->GetPortion()->IsMarginPortion() ) )
646 146 : nX += pPor->PrtWidth();
647 : }
648 146 : if( pPor->IsMultiPortion() )
649 : {
650 0 : if ( ((SwMultiPortion*)pPor)->HasTabulator() )
651 : {
652 0 : if ( pCurr->IsSpaceAdd() )
653 : {
654 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
655 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
656 : else
657 0 : nSpaceAdd = 0;
658 : }
659 :
660 0 : if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->size() )
661 0 : ++nKanaIdx;
662 : }
663 :
664 : // if we are right behind a BidiPortion, we have to
665 : // hold a pointer to the BidiPortion in order to
666 : // find the correct cursor position, depending on the
667 : // cursor level
668 0 : if ( ((SwMultiPortion*)pPor)->IsBidi() &&
669 0 : aInf.GetIdx() + pPor->GetLen() == nOfst )
670 : {
671 0 : pLastBidiPor = (SwBidiPortion*)pPor;
672 0 : nLastBidiPorWidth = pLastBidiPor->Width() +
673 0 : pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );;
674 : }
675 : }
676 :
677 146 : aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() );
678 146 : pPor = pPor->GetPortion();
679 : }
680 : else
681 : {
682 0 : if( pPor->IsMultiPortion() )
683 : {
684 0 : nTmpAscent = AdjustBaseLine( *pCurr, pPor );
685 0 : GetInfo().SetMulti( sal_True );
686 0 : pOrig->Pos().Y() += nTmpAscent - nPorAscent;
687 :
688 0 : if( pCMS && pCMS->b2Lines )
689 : {
690 0 : sal_Bool bRecursion = sal_True;
691 0 : if ( ! pCMS->p2Lines )
692 : {
693 0 : pCMS->p2Lines = new Sw2LinesPos;
694 0 : pCMS->p2Lines->aLine = SwRect(aCharPos, aCharSize);
695 0 : bRecursion = sal_False;
696 : }
697 :
698 0 : if( ((SwMultiPortion*)pPor)->HasRotation() )
699 : {
700 0 : if( ((SwMultiPortion*)pPor)->IsRevers() )
701 0 : pCMS->p2Lines->nMultiType = MT_ROT_270;
702 : else
703 0 : pCMS->p2Lines->nMultiType = MT_ROT_90;
704 : }
705 0 : else if( ((SwMultiPortion*)pPor)->IsDouble() )
706 0 : pCMS->p2Lines->nMultiType = MT_TWOLINE;
707 0 : else if( ((SwMultiPortion*)pPor)->IsBidi() )
708 0 : pCMS->p2Lines->nMultiType = MT_BIDI;
709 : else
710 0 : pCMS->p2Lines->nMultiType = MT_RUBY;
711 :
712 0 : SwTwips nTmpWidth = pPor->Width();
713 0 : if( nSpaceAdd )
714 0 : nTmpWidth += pPor->CalcSpacing(nSpaceAdd, aInf);
715 :
716 0 : SwRect aRect( Point(aCharPos.X() + nX, pOrig->Top() ),
717 0 : Size( nTmpWidth, pPor->Height() ) );
718 :
719 0 : if ( ! bRecursion )
720 0 : pCMS->p2Lines->aPortion = aRect;
721 : else
722 0 : pCMS->p2Lines->aPortion2 = aRect;
723 : }
724 :
725 : // In a multi-portion we use GetCharRect()-function
726 : // recursively and must add the x-position
727 : // of the multi-portion.
728 0 : xub_StrLen nOldStart = nStart;
729 0 : SwTwips nOldY = nY;
730 0 : sal_uInt8 nOldProp = GetPropFont();
731 0 : nStart = aInf.GetIdx();
732 0 : SwLineLayout* pOldCurr = pCurr;
733 0 : pCurr = &((SwMultiPortion*)pPor)->GetRoot();
734 0 : if( ((SwMultiPortion*)pPor)->IsDouble() )
735 0 : SetPropFont( 50 );
736 :
737 0 : GETGRID( GetTxtFrm()->FindPageFrm() )
738 0 : const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
739 : const sal_uInt16 nRubyHeight = bHasGrid ?
740 0 : pGrid->GetRubyHeight() : 0;
741 :
742 0 : if( nStart + pCurr->GetLen() <= nOfst && GetNext() &&
743 0 : ( ! ((SwMultiPortion*)pPor)->IsRuby() ||
744 0 : ((SwMultiPortion*)pPor)->OnTop() ) )
745 : {
746 : sal_uInt16 nOffset;
747 : // in grid mode we may only add the height of the
748 : // ruby line if ruby line is on top
749 0 : if ( bHasGrid &&
750 0 : ((SwMultiPortion*)pPor)->IsRuby() &&
751 0 : ((SwMultiPortion*)pPor)->OnTop() )
752 0 : nOffset = nRubyHeight;
753 : else
754 0 : nOffset = GetLineHeight();
755 :
756 0 : pOrig->Pos().Y() += nOffset;
757 0 : Next();
758 : }
759 :
760 : sal_Bool bSpaceChg = ((SwMultiPortion*)pPor)->
761 0 : ChgSpaceAdd( pCurr, nSpaceAdd );
762 0 : Point aOldPos = pOrig->Pos();
763 :
764 : // Ok, for ruby portions in grid mode we have to
765 : // temporarily set the inner line height to the
766 : // outer line height because that value is needed
767 : // for the adjustment inside the recursion
768 0 : const sal_uInt16 nOldRubyHeight = pCurr->Height();
769 0 : const sal_uInt16 nOldRubyRealHeight = pCurr->GetRealHeight();
770 : const sal_Bool bChgHeight =
771 0 : ((SwMultiPortion*)pPor)->IsRuby() && bHasGrid;
772 :
773 0 : if ( bChgHeight )
774 : {
775 0 : pCurr->Height( pOldCurr->Height() - nRubyHeight );
776 0 : pCurr->SetRealHeight( pOldCurr->GetRealHeight() -
777 0 : nRubyHeight );
778 : }
779 :
780 0 : SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
781 0 : if ( ((SwMultiPortion*)pPor)->IsBidi() )
782 : {
783 : aLayoutModeModifier.Modify(
784 0 : ((SwBidiPortion*)pPor)->GetLevel() % 2 );
785 : }
786 :
787 0 : _GetCharRect( pOrig, nOfst, pCMS );
788 :
789 0 : if ( bChgHeight )
790 : {
791 0 : pCurr->Height( nOldRubyHeight );
792 0 : pCurr->SetRealHeight( nOldRubyRealHeight );
793 : }
794 :
795 : // if we are still in the first row of
796 : // our 2 line multiportion, we use the FirstMulti flag
797 : // to indicate this
798 0 : if ( ((SwMultiPortion*)pPor)->IsDouble() )
799 : {
800 : // the recursion may have damaged our font size
801 0 : SetPropFont( nOldProp );
802 0 : if ( !nOldProp )
803 0 : nOldProp = 100;
804 0 : GetInfo().GetFont()->SetProportion( 100 );
805 :
806 0 : if ( pCurr == &((SwMultiPortion*)pPor)->GetRoot() )
807 : {
808 0 : GetInfo().SetFirstMulti( true );
809 :
810 : // we want to treat a double line portion like a
811 : // single line portion, if there is no text in
812 : // the second line
813 0 : if ( !pCurr->GetNext() ||
814 0 : !pCurr->GetNext()->GetLen() )
815 0 : GetInfo().SetMulti( sal_False );
816 : }
817 : }
818 : // ruby portions are treated like single line portions
819 0 : else if( ((SwMultiPortion*)pPor)->IsRuby() ||
820 0 : ((SwMultiPortion*)pPor)->IsBidi() )
821 0 : GetInfo().SetMulti( sal_False );
822 :
823 : // calculate cursor values
824 0 : if( ((SwMultiPortion*)pPor)->HasRotation() )
825 : {
826 0 : GetInfo().SetMulti( sal_False );
827 0 : long nTmp = pOrig->Width();
828 0 : pOrig->Width( pOrig->Height() );
829 0 : pOrig->Height( nTmp );
830 0 : nTmp = pOrig->Left() - aOldPos.X();
831 :
832 : // if we travel into our rotated portion from
833 : // a line below, we have to take care, that the
834 : // y coord in pOrig is less than line height:
835 0 : if ( nTmp )
836 0 : nTmp--;
837 :
838 0 : pOrig->Pos().X() = nX + aOldPos.X();
839 0 : if( ((SwMultiPortion*)pPor)->IsRevers() )
840 0 : pOrig->Pos().Y() = aOldPos.Y() + nTmp;
841 : else
842 0 : pOrig->Pos().Y() = aOldPos.Y()
843 0 : + pPor->Height() - nTmp - pOrig->Height();
844 0 : if ( pCMS && pCMS->bRealHeight )
845 : {
846 0 : pCMS->aRealHeight.Y() = -pCMS->aRealHeight.Y();
847 : // result for rotated multi portion is not
848 : // correct for reverse (270 degree) portions
849 0 : if( ((SwMultiPortion*)pPor)->IsRevers() )
850 : {
851 0 : if ( SvxParaVertAlignItem::AUTOMATIC ==
852 0 : GetLineInfo().GetVertAlign() )
853 : // if vertical alignment is set to auto,
854 : // we switch from base line alignment
855 : // to centered alignment
856 0 : pCMS->aRealHeight.X() =
857 0 : ( pOrig->Width() +
858 0 : pCMS->aRealHeight.Y() ) / 2;
859 : else
860 0 : pCMS->aRealHeight.X() =
861 0 : ( pOrig->Width() -
862 0 : pCMS->aRealHeight.X() +
863 0 : pCMS->aRealHeight.Y() );
864 : }
865 : }
866 : }
867 : else
868 : {
869 0 : pOrig->Pos().Y() += aOldPos.Y();
870 0 : if ( ((SwMultiPortion*)pPor)->IsBidi() )
871 : {
872 0 : const SwTwips nPorWidth = pPor->Width() +
873 0 : pPor->CalcSpacing( nSpaceAdd, aInf );
874 0 : const SwTwips nInsideOfst = pOrig->Pos().X();
875 0 : pOrig->Pos().X() = nX + nPorWidth -
876 0 : nInsideOfst - pOrig->Width();
877 : }
878 : else
879 0 : pOrig->Pos().X() += nX;
880 :
881 0 : if( ((SwMultiPortion*)pPor)->HasBrackets() )
882 0 : pOrig->Pos().X() +=
883 0 : ((SwDoubleLinePortion*)pPor)->PreWidth();
884 : }
885 :
886 0 : if( bSpaceChg )
887 0 : SwDoubleLinePortion::ResetSpaceAdd( pCurr );
888 :
889 0 : pCurr = pOldCurr;
890 0 : nStart = nOldStart;
891 0 : nY = nOldY;
892 0 : bPrev = sal_False;
893 :
894 2264 : return;
895 : }
896 0 : if ( pPor->PrtWidth() )
897 : {
898 0 : xub_StrLen nOldLen = pPor->GetLen();
899 0 : pPor->SetLen( nOfst - aInf.GetIdx() );
900 0 : aInf.SetLen( pPor->GetLen() );
901 0 : if( nX || !pPor->InNumberGrp() )
902 : {
903 0 : SeekAndChg( aInf );
904 0 : const bool bOldOnWin = aInf.OnWin();
905 0 : aInf.SetOnWin( false ); // keine BULLETs!
906 0 : SwTwips nTmp = nX;
907 0 : aInf.SetKanaComp( pKanaComp );
908 0 : aInf.SetKanaIdx( nKanaIdx );
909 0 : nX += pPor->GetTxtSize( aInf ).Width();
910 0 : aInf.SetOnWin( bOldOnWin );
911 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
912 0 : nX += pPor->CalcSpacing( nSpaceAdd, aInf );
913 0 : if( bWidth )
914 : {
915 0 : pPor->SetLen( pPor->GetLen() + 1 );
916 0 : aInf.SetLen( pPor->GetLen() );
917 0 : aInf.SetOnWin( false ); // keine BULLETs!
918 0 : nTmp += pPor->GetTxtSize( aInf ).Width();
919 0 : aInf.SetOnWin( bOldOnWin );
920 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
921 0 : nTmp += pPor->CalcSpacing(nSpaceAdd, aInf);
922 0 : pOrig->Width( nTmp - nX );
923 : }
924 : }
925 0 : pPor->SetLen( nOldLen );
926 : }
927 0 : bWidth = sal_False;
928 0 : break;
929 : }
930 : }
931 : }
932 :
933 2090 : if( pPor )
934 : {
935 : OSL_ENSURE( !pPor->InNumberGrp() || bInsideFirstField, "Number surprise" );
936 2033 : sal_Bool bEmptyFld = sal_False;
937 2033 : if( pPor->InFldGrp() && pPor->GetLen() )
938 : {
939 12 : SwFldPortion *pTmp = (SwFldPortion*)pPor;
940 24 : while( pTmp->HasFollow() && !pTmp->GetExp().Len() )
941 : {
942 0 : KSHORT nAddX = pTmp->Width();
943 0 : SwLinePortion *pNext = pTmp->GetPortion();
944 0 : while( pNext && !pNext->InFldGrp() )
945 : {
946 : OSL_ENSURE( !pNext->GetLen(), "Where's my field follow?" );
947 0 : nAddX = nAddX + pNext->Width();
948 0 : pNext = pNext->GetPortion();
949 : }
950 0 : if( !pNext )
951 0 : break;
952 0 : pTmp = (SwFldPortion*)pNext;
953 0 : nPorHeight = pTmp->Height();
954 0 : nPorAscent = pTmp->GetAscent();
955 0 : nX += nAddX;
956 0 : bEmptyFld = sal_True;
957 : }
958 : }
959 : // 8513: Felder im Blocksatz, ueberspringen
960 4066 : while( pPor && !pPor->GetLen() && ! bInsideFirstField &&
961 0 : ( pPor->IsFlyPortion() || pPor->IsKernPortion() ||
962 0 : pPor->IsBlankPortion() || pPor->InTabGrp() ||
963 0 : ( !bEmptyFld && pPor->InFldGrp() ) ) )
964 : {
965 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
966 0 : nX += pPor->PrtWidth() +
967 0 : pPor->CalcSpacing( nSpaceAdd, aInf );
968 : else
969 : {
970 0 : if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
971 : {
972 0 : if ( pCurr->IsSpaceAdd() )
973 : {
974 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
975 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
976 : else
977 0 : nSpaceAdd = 0;
978 : }
979 :
980 0 : if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->size() )
981 0 : ++nKanaIdx;
982 : }
983 0 : if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
984 0 : !pPor->GetPortion()->IsMarginPortion() ) )
985 0 : nX += pPor->PrtWidth();
986 : }
987 0 : if( pPor->IsMultiPortion() &&
988 0 : ((SwMultiPortion*)pPor)->HasTabulator() )
989 : {
990 0 : if ( pCurr->IsSpaceAdd() )
991 : {
992 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
993 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
994 : else
995 0 : nSpaceAdd = 0;
996 : }
997 :
998 0 : if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->size() )
999 0 : ++nKanaIdx;
1000 : }
1001 0 : if( !pPor->IsFlyPortion() )
1002 : {
1003 0 : nPorHeight = pPor->Height();
1004 0 : nPorAscent = pPor->GetAscent();
1005 : }
1006 0 : pPor = pPor->GetPortion();
1007 : }
1008 :
1009 2033 : if( aInf.GetIdx() == nOfst && pPor && pPor->InHyphGrp() &&
1010 0 : pPor->GetPortion() && pPor->GetPortion()->InFixGrp() )
1011 : {
1012 : // Alle Sonderportions muessen uebersprungen werden
1013 : // Beispiel: zu-[FLY]sammen, 'u' == 19, 's' == 20; Right()
1014 : // Ohne den Ausgleich landen wir vor '-' mit dem
1015 : // Ausgleich vor 's'.
1016 0 : while( pPor && !pPor->GetLen() )
1017 : {
1018 0 : nX += pPor->Width();
1019 0 : if( !pPor->IsMarginPortion() )
1020 : {
1021 0 : nPorHeight = pPor->Height();
1022 0 : nPorAscent = pPor->GetAscent();
1023 : }
1024 0 : pPor = pPor->GetPortion();
1025 : }
1026 : }
1027 2033 : if( pPor && pCMS )
1028 : {
1029 2004 : if( pCMS->bFieldInfo && pPor->InFldGrp() && pPor->Width() )
1030 0 : pOrig->Width( pPor->Width() );
1031 2004 : if( pPor->IsDropPortion() )
1032 : {
1033 0 : nPorAscent = ((SwDropPortion*)pPor)->GetDropHeight();
1034 : // The drop height is only calculated, if we have more than
1035 : // one line. Otherwise it is 0.
1036 0 : if ( ! nPorAscent)
1037 0 : nPorAscent = pPor->Height();
1038 0 : nPorHeight = nPorAscent;
1039 : pOrig->Height( nPorHeight +
1040 0 : ((SwDropPortion*)pPor)->GetDropDescent() );
1041 0 : if( nTmpHeight < pOrig->Height() )
1042 : {
1043 0 : nTmpAscent = nPorAscent;
1044 0 : nTmpHeight = sal_uInt16( pOrig->Height() );
1045 : }
1046 : }
1047 2004 : if( bWidth && pPor->PrtWidth() && pPor->GetLen() &&
1048 0 : aInf.GetIdx() == nOfst )
1049 : {
1050 0 : if( !pPor->IsFlyPortion() && pPor->Height() &&
1051 0 : pPor->GetAscent() )
1052 : {
1053 0 : nPorHeight = pPor->Height();
1054 0 : nPorAscent = pPor->GetAscent();
1055 : }
1056 : SwTwips nTmp;
1057 0 : if( 2 > pPor->GetLen() )
1058 : {
1059 0 : nTmp = pPor->Width();
1060 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
1061 0 : nTmp += pPor->CalcSpacing( nSpaceAdd, aInf );
1062 : }
1063 : else
1064 : {
1065 0 : const bool bOldOnWin = aInf.OnWin();
1066 0 : xub_StrLen nOldLen = pPor->GetLen();
1067 0 : pPor->SetLen( 1 );
1068 0 : aInf.SetLen( pPor->GetLen() );
1069 0 : SeekAndChg( aInf );
1070 0 : aInf.SetOnWin( false ); // keine BULLETs!
1071 0 : aInf.SetKanaComp( pKanaComp );
1072 0 : aInf.SetKanaIdx( nKanaIdx );
1073 0 : nTmp = pPor->GetTxtSize( aInf ).Width();
1074 0 : aInf.SetOnWin( bOldOnWin );
1075 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
1076 0 : nTmp += pPor->CalcSpacing( nSpaceAdd, aInf );
1077 0 : pPor->SetLen( nOldLen );
1078 : }
1079 0 : pOrig->Width( nTmp );
1080 : }
1081 :
1082 : // travel inside field portion?
1083 2004 : if ( pCMS->pSpecialPos )
1084 : {
1085 : // apply attributes to font
1086 0 : Seek( nOfst );
1087 0 : lcl_GetCharRectInsideField( aInf, *pOrig, *pCMS, *pPor );
1088 : }
1089 : }
1090 : }
1091 :
1092 : // special case: We are at the beginning of a BidiPortion or
1093 : // directly behind a BidiPortion
1094 4094 : if ( pCMS &&
1095 : ( pLastBidiPor ||
1096 : ( pPor &&
1097 2004 : pPor->IsMultiPortion() &&
1098 0 : ((SwMultiPortion*)pPor)->IsBidi() ) ) )
1099 : {
1100 : // we determine if the cursor has to blink before or behind
1101 : // the bidi portion
1102 0 : if ( pLastBidiPor )
1103 : {
1104 0 : const sal_uInt8 nPortionLevel = pLastBidiPor->GetLevel();
1105 :
1106 0 : if ( pCMS->nCursorBidiLevel >= nPortionLevel )
1107 : {
1108 : // we came from inside the bidi portion, we want to blink
1109 : // behind the portion
1110 0 : pOrig->Pos().X() -= nLastBidiPorWidth;
1111 :
1112 : // Again, there is a special case: logically behind
1113 : // the portion can actually mean that the cursor is inside
1114 : // the portion. This can happen is the last portion
1115 : // inside the bidi portion is a nested bidi portion
1116 : SwLineLayout& rLineLayout =
1117 0 : ((SwMultiPortion*)pLastBidiPor)->GetRoot();
1118 :
1119 0 : const SwLinePortion *pLast = rLineLayout.FindLastPortion();
1120 0 : if ( pLast->IsMultiPortion() )
1121 : {
1122 : OSL_ENSURE( ((SwMultiPortion*)pLast)->IsBidi(),
1123 : "Non-BidiPortion inside BidiPortion" );
1124 0 : pOrig->Pos().X() += pLast->Width() +
1125 0 : pLast->CalcSpacing( nSpaceAdd, aInf );
1126 : }
1127 : }
1128 : }
1129 : else
1130 : {
1131 0 : const sal_uInt8 nPortionLevel = ((SwBidiPortion*)pPor)->GetLevel();
1132 :
1133 0 : if ( pCMS->nCursorBidiLevel >= nPortionLevel )
1134 : {
1135 : // we came from inside the bidi portion, we want to blink
1136 : // behind the portion
1137 0 : pOrig->Pos().X() += pPor->Width() +
1138 0 : pPor->CalcSpacing( nSpaceAdd, aInf );
1139 : }
1140 : }
1141 : }
1142 :
1143 2090 : pOrig->Pos().X() += nX;
1144 :
1145 2090 : if ( pCMS && pCMS->bRealHeight )
1146 : {
1147 2061 : nTmpAscent = AdjustBaseLine( *pCurr, 0, nPorHeight, nPorAscent );
1148 2061 : if ( nTmpAscent > nPorAscent )
1149 113 : pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
1150 : else
1151 1948 : pCMS->aRealHeight.X() = 0;
1152 : OSL_ENSURE( nPorHeight, "GetCharRect: Missing Portion-Height" );
1153 2061 : if ( nTmpHeight > nPorHeight )
1154 152 : pCMS->aRealHeight.Y() = nPorHeight;
1155 : else
1156 1909 : pCMS->aRealHeight.Y() = nTmpHeight;
1157 : }
1158 2264 : }
1159 : }
1160 :
1161 : /*************************************************************************
1162 : * SwTxtCursor::GetCharRect()
1163 : *************************************************************************/
1164 :
1165 2264 : sal_Bool SwTxtCursor::GetCharRect( SwRect* pOrig, const xub_StrLen nOfst,
1166 : SwCrsrMoveState* pCMS, const long nMax )
1167 : {
1168 2264 : CharCrsrToLine(nOfst);
1169 :
1170 : // Indicates that a position inside a special portion (field, number portion)
1171 : // is requested.
1172 2264 : const sal_Bool bSpecialPos = pCMS && pCMS->pSpecialPos;
1173 2264 : xub_StrLen nFindOfst = nOfst;
1174 :
1175 2264 : if ( bSpecialPos )
1176 : {
1177 0 : const sal_uInt8 nExtendRange = pCMS->pSpecialPos->nExtendRange;
1178 :
1179 : OSL_ENSURE( ! pCMS->pSpecialPos->nLineOfst || SP_EXTEND_RANGE_BEFORE != nExtendRange,
1180 : "LineOffset AND Number Portion?" );
1181 :
1182 : // portions which are behind the string
1183 0 : if ( SP_EXTEND_RANGE_BEHIND == nExtendRange )
1184 0 : ++nFindOfst;
1185 :
1186 : // skip lines for fields which cover more than one line
1187 0 : for ( sal_uInt16 i = 0; i < pCMS->pSpecialPos->nLineOfst; i++ )
1188 0 : Next();
1189 : }
1190 :
1191 : // Adjustierung ggf. nachholen
1192 2264 : GetAdjusted();
1193 :
1194 2264 : const Point aCharPos( GetTopLeft() );
1195 2264 : sal_Bool bRet = sal_True;
1196 :
1197 2264 : _GetCharRect( pOrig, nFindOfst, pCMS );
1198 :
1199 2264 : const SwTwips nTmpRight = Right() - 12;
1200 :
1201 2264 : pOrig->Pos().X() += aCharPos.X();
1202 2264 : pOrig->Pos().Y() += aCharPos.Y();
1203 :
1204 2264 : if( pCMS && pCMS->b2Lines && pCMS->p2Lines )
1205 : {
1206 0 : pCMS->p2Lines->aLine.Pos().X() += aCharPos.X();
1207 0 : pCMS->p2Lines->aLine.Pos().Y() += aCharPos.Y();
1208 0 : pCMS->p2Lines->aPortion.Pos().X() += aCharPos.X();
1209 0 : pCMS->p2Lines->aPortion.Pos().Y() += aCharPos.Y();
1210 : }
1211 :
1212 2264 : if( pOrig->Left() > nTmpRight )
1213 5 : pOrig->Pos().X() = nTmpRight;
1214 :
1215 2264 : if( nMax )
1216 : {
1217 2264 : if( pOrig->Top() + pOrig->Height() > nMax )
1218 : {
1219 13 : if( pOrig->Top() > nMax )
1220 0 : pOrig->Top( nMax );
1221 13 : pOrig->Height( nMax - pOrig->Top() );
1222 : }
1223 2264 : if ( pCMS && pCMS->bRealHeight && pCMS->aRealHeight.Y() >= 0 )
1224 : {
1225 2235 : long nTmp = pCMS->aRealHeight.X() + pOrig->Top();
1226 2235 : if( nTmp >= nMax )
1227 : {
1228 0 : pCMS->aRealHeight.X() = nMax - pOrig->Top();
1229 0 : pCMS->aRealHeight.Y() = 0;
1230 : }
1231 2235 : else if( nTmp + pCMS->aRealHeight.Y() > nMax )
1232 13 : pCMS->aRealHeight.Y() = nMax - nTmp;
1233 : }
1234 : }
1235 2264 : long nOut = pOrig->Right() - GetTxtFrm()->Frm().Right();
1236 2264 : if( nOut > 0 )
1237 : {
1238 10 : if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left()
1239 5 : + GetTxtFrm()->Prt().Width() )
1240 0 : nOut += GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left()
1241 0 : - GetTxtFrm()->Prt().Width();
1242 5 : if( nOut > 0 )
1243 5 : pOrig->Pos().X() -= nOut + 10;
1244 : }
1245 2264 : return bRet;
1246 : }
1247 :
1248 : /*************************************************************************
1249 : * SwTxtCursor::GetCrsrOfst()
1250 : *
1251 : * Return: Offset im String
1252 : *************************************************************************/
1253 0 : xub_StrLen SwTxtCursor::GetCrsrOfst( SwPosition *pPos, const Point &rPoint,
1254 : const MSHORT nChgNode, SwCrsrMoveState* pCMS ) const
1255 : {
1256 : // Adjustierung ggf. nachholen
1257 0 : GetAdjusted();
1258 :
1259 0 : const XubString &rText = GetInfo().GetTxt();
1260 0 : xub_StrLen nOffset = 0;
1261 :
1262 : // x ist der horizontale Offset innerhalb der Zeile.
1263 0 : SwTwips x = rPoint.X();
1264 0 : const SwTwips nLeftMargin = GetLineStart();
1265 0 : SwTwips nRightMargin = GetLineEnd();
1266 0 : if( nRightMargin == nLeftMargin )
1267 0 : nRightMargin += 30;
1268 :
1269 0 : const sal_Bool bLeftOver = x < nLeftMargin;
1270 0 : if( bLeftOver )
1271 0 : x = nLeftMargin;
1272 0 : const sal_Bool bRightOver = x > nRightMargin;
1273 0 : if( bRightOver )
1274 0 : x = nRightMargin;
1275 :
1276 0 : sal_Bool bRightAllowed = pCMS && ( pCMS->eState == MV_NONE );
1277 :
1278 : // Bis hierher in Dokumentkoordinaten.
1279 0 : x -= nLeftMargin;
1280 :
1281 0 : KSHORT nX = KSHORT( x );
1282 :
1283 : // Wenn es in der Zeile Attributwechsel gibt, den Abschnitt
1284 : // suchen, in dem nX liegt.
1285 0 : SwLinePortion *pPor = pCurr->GetFirstPortion();
1286 0 : xub_StrLen nCurrStart = nStart;
1287 0 : sal_Bool bHolePortion = sal_False;
1288 0 : sal_Bool bLastHyph = sal_False;
1289 :
1290 0 : std::deque<sal_uInt16> *pKanaComp = pCurr->GetpKanaComp();
1291 0 : xub_StrLen nOldIdx = GetInfo().GetIdx();
1292 0 : MSHORT nSpaceIdx = 0;
1293 0 : size_t nKanaIdx = 0;
1294 0 : long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
1295 0 : short nKanaComp = pKanaComp ? (*pKanaComp)[0] : 0;
1296 :
1297 : // nWidth ist die Breite der Zeile, oder die Breite des
1298 : // Abschnitts mit dem Fontwechsel, in dem nX liegt.
1299 :
1300 0 : KSHORT nWidth = pPor->Width();
1301 0 : if ( pCurr->IsSpaceAdd() || pKanaComp )
1302 : {
1303 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
1304 : {
1305 0 : ((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart );
1306 0 : nWidth = nWidth + sal_uInt16( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) );
1307 : }
1308 0 : if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) ||
1309 0 : ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
1310 : )
1311 : {
1312 0 : if ( pCurr->IsSpaceAdd() )
1313 : {
1314 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
1315 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
1316 : else
1317 0 : nSpaceAdd = 0;
1318 : }
1319 :
1320 0 : if( pKanaComp )
1321 : {
1322 0 : if ( nKanaIdx + 1 < pKanaComp->size() )
1323 0 : nKanaComp = (*pKanaComp)[++nKanaIdx];
1324 : else
1325 0 : nKanaComp = 0;
1326 : }
1327 : }
1328 : }
1329 :
1330 : KSHORT nWidth30;
1331 0 : if ( pPor->IsPostItsPortion() )
1332 0 : nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
1333 : else
1334 0 : nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
1335 : 30 :
1336 0 : nWidth;
1337 :
1338 0 : while( pPor->GetPortion() && nWidth30 < nX && !pPor->IsBreakPortion() )
1339 : {
1340 0 : nX = nX - nWidth;
1341 0 : nCurrStart = nCurrStart + pPor->GetLen();
1342 0 : bHolePortion = pPor->IsHolePortion();
1343 0 : pPor = pPor->GetPortion();
1344 0 : nWidth = pPor->Width();
1345 0 : if ( pCurr->IsSpaceAdd() || pKanaComp )
1346 : {
1347 0 : if ( pPor->InSpaceGrp() && nSpaceAdd )
1348 : {
1349 0 : ((SwTxtSizeInfo&)GetInfo()).SetIdx( nCurrStart );
1350 0 : nWidth = nWidth + sal_uInt16( pPor->CalcSpacing( nSpaceAdd, GetInfo() ) );
1351 : }
1352 :
1353 0 : if( ( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() ) ||
1354 0 : ( pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->HasTabulator() )
1355 : )
1356 : {
1357 0 : if ( pCurr->IsSpaceAdd() )
1358 : {
1359 0 : if ( ++nSpaceIdx < pCurr->GetLLSpaceAddCount() )
1360 0 : nSpaceAdd = pCurr->GetLLSpaceAdd( nSpaceIdx );
1361 : else
1362 0 : nSpaceAdd = 0;
1363 : }
1364 :
1365 0 : if ( pKanaComp )
1366 : {
1367 0 : if( nKanaIdx + 1 < pKanaComp->size() )
1368 0 : nKanaComp = (*pKanaComp)[++nKanaIdx];
1369 : else
1370 0 : nKanaComp = 0;
1371 : }
1372 : }
1373 : }
1374 :
1375 0 : if ( pPor->IsPostItsPortion() )
1376 0 : nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
1377 : else
1378 0 : nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
1379 : 30 :
1380 0 : nWidth;
1381 0 : if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
1382 0 : bLastHyph = pPor->InHyphGrp();
1383 : }
1384 :
1385 0 : const sal_Bool bLastPortion = (0 == pPor->GetPortion());
1386 :
1387 0 : if( nX==nWidth )
1388 : {
1389 0 : SwLinePortion *pNextPor = pPor->GetPortion();
1390 0 : while( pNextPor && pNextPor->InFldGrp() && !pNextPor->Width() )
1391 : {
1392 0 : nCurrStart = nCurrStart + pPor->GetLen();
1393 0 : pPor = pNextPor;
1394 0 : if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
1395 0 : bLastHyph = pPor->InHyphGrp();
1396 0 : pNextPor = pPor->GetPortion();
1397 : }
1398 : }
1399 :
1400 0 : ((SwTxtSizeInfo&)GetInfo()).SetIdx( nOldIdx );
1401 :
1402 0 : xub_StrLen nLength = pPor->GetLen();
1403 :
1404 0 : sal_Bool bFieldInfo = pCMS && pCMS->bFieldInfo;
1405 :
1406 0 : if( bFieldInfo && ( nWidth30 < nX || bRightOver || bLeftOver ||
1407 0 : ( pPor->InNumberGrp() && !pPor->IsFtnNumPortion() ) ||
1408 0 : ( pPor->IsMarginPortion() && nWidth > nX + 30 ) ) )
1409 0 : ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
1410 :
1411 :
1412 : // #i27615#
1413 0 : if (pCMS)
1414 : {
1415 0 : if( pCMS->bInFrontOfLabel)
1416 : {
1417 0 : if (! (2 * nX < nWidth && pPor->InNumberGrp() &&
1418 0 : !pPor->IsFtnNumPortion()))
1419 0 : pCMS->bInFrontOfLabel = sal_False;
1420 : }
1421 : }
1422 :
1423 : // 7684: Wir sind genau auf der HyphPortion angelangt und muessen dafuer
1424 : // sorgen, dass wir in dem String landen.
1425 : // 7993: Wenn die Laenge 0 ist muessen wir raus...
1426 0 : if( !nLength )
1427 : {
1428 0 : if( pCMS )
1429 : {
1430 0 : if( pPor->IsFlyPortion() && bFieldInfo )
1431 0 : ((SwCrsrMoveState*)pCMS)->bPosCorr = sal_True;
1432 :
1433 0 : if (!bRightOver && nX)
1434 : {
1435 0 : if( pPor->IsFtnNumPortion())
1436 0 : ((SwCrsrMoveState*)pCMS)->bFtnNoInfo = sal_True;
1437 0 : else if (pPor->InNumberGrp() ) // #i23726#
1438 : {
1439 0 : ((SwCrsrMoveState*)pCMS)->nInNumPostionOffset = nX;
1440 0 : ((SwCrsrMoveState*)pCMS)->bInNumPortion = sal_True;
1441 : }
1442 : }
1443 : }
1444 0 : if( !nCurrStart )
1445 0 : return 0;
1446 :
1447 : // 7849, 7816: auf pPor->GetHyphPortion kann nicht verzichtet werden!
1448 0 : if( bHolePortion || ( !bRightAllowed && bLastHyph ) ||
1449 0 : ( pPor->IsMarginPortion() && !pPor->GetPortion() &&
1450 : // 46598: In der letzten Zeile eines zentrierten Absatzes wollen
1451 : // wir auch mal hinter dem letzten Zeichen landen.
1452 0 : nCurrStart < rText.Len() ) )
1453 0 : --nCurrStart;
1454 0 : else if( pPor->InFldGrp() && ((SwFldPortion*)pPor)->IsFollow()
1455 : && nWidth > nX )
1456 : {
1457 0 : if( bFieldInfo )
1458 0 : --nCurrStart;
1459 : else
1460 : {
1461 0 : KSHORT nHeight = pPor->Height();
1462 0 : if ( !nHeight || nHeight > nWidth )
1463 0 : nHeight = nWidth;
1464 0 : if( nChgNode && nWidth - nHeight/2 > nX )
1465 0 : --nCurrStart;
1466 : }
1467 : }
1468 0 : return nCurrStart;
1469 : }
1470 0 : if ( 1 == nLength )
1471 : {
1472 0 : if ( nWidth )
1473 : {
1474 : // Sonst kommen wir nicht mehr in zeichengeb. Rahmen hinein...
1475 0 : if( !( nChgNode && pPos && pPor->IsFlyCntPortion() ) )
1476 : {
1477 0 : if ( pPor->InFldGrp() ||
1478 0 : ( pPor->IsMultiPortion() &&
1479 0 : ((SwMultiPortion*)pPor)->IsBidi() ) )
1480 : {
1481 0 : KSHORT nHeight = 0;
1482 0 : if( !bFieldInfo )
1483 : {
1484 0 : nHeight = pPor->Height();
1485 0 : if ( !nHeight || nHeight > nWidth )
1486 0 : nHeight = nWidth;
1487 : }
1488 :
1489 0 : if( nWidth - nHeight/2 <= nX &&
1490 0 : ( ! pPor->InFldGrp() ||
1491 0 : !((SwFldPortion*)pPor)->HasFollow() ) )
1492 0 : ++nCurrStart;
1493 : }
1494 0 : else if ( ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
1495 0 : !pPor->GetPortion()->IsMarginPortion() &&
1496 0 : !pPor->GetPortion()->IsHolePortion() ) )
1497 : && ( nWidth/2 < nX ) &&
1498 : ( !bFieldInfo ||
1499 0 : ( pPor->GetPortion() &&
1500 0 : pPor->GetPortion()->IsPostItsPortion() ) )
1501 : && ( bRightAllowed || !bLastHyph ))
1502 0 : ++nCurrStart;
1503 :
1504 : // if we want to get the position inside the field, we should not return
1505 0 : if ( !pCMS || !pCMS->pSpecialPos )
1506 0 : return nCurrStart;
1507 : }
1508 : }
1509 : else
1510 : {
1511 0 : if ( pPor->IsPostItsPortion() || pPor->IsBreakPortion() ||
1512 0 : pPor->InToxRefGrp() )
1513 0 : return nCurrStart;
1514 0 : if ( pPor->InFldGrp() )
1515 : {
1516 0 : if( bRightOver && !((SwFldPortion*)pPor)->HasFollow() )
1517 0 : ++nCurrStart;
1518 0 : return nCurrStart;
1519 : }
1520 : }
1521 : }
1522 :
1523 0 : if( bLastPortion && (pCurr->GetNext() || pFrm->GetFollow() ) )
1524 0 : --nLength;
1525 :
1526 0 : if( nWidth > nX ||
1527 0 : ( nWidth == nX && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsDouble() ) )
1528 : {
1529 0 : if( pPor->IsMultiPortion() )
1530 : {
1531 : // In a multi-portion we use GetCrsrOfst()-function recursively
1532 0 : SwTwips nTmpY = rPoint.Y() - pCurr->GetAscent() + pPor->GetAscent();
1533 : // if we are in the first line of a double line portion, we have
1534 : // to add a value to nTmpY for not staying in this line
1535 : // we also want to skip the first line, if we are inside ruby
1536 0 : if ( ( ((SwTxtSizeInfo*)pInf)->IsMulti() &&
1537 0 : ((SwTxtSizeInfo*)pInf)->IsFirstMulti() ) ||
1538 0 : ( ((SwMultiPortion*)pPor)->IsRuby() &&
1539 0 : ((SwMultiPortion*)pPor)->OnTop() ) )
1540 0 : nTmpY += ((SwMultiPortion*)pPor)->Height();
1541 :
1542 : // Important for cursor traveling in ruby portions:
1543 : // We have to set nTmpY to 0 in order to stay in the first row
1544 : // if the phonetic line is the second row
1545 0 : if ( ((SwMultiPortion*)pPor)->IsRuby() &&
1546 0 : ! ((SwMultiPortion*)pPor)->OnTop() )
1547 0 : nTmpY = 0;
1548 :
1549 : SwTxtCursorSave aSave( (SwTxtCursor*)this, (SwMultiPortion*)pPor,
1550 0 : nTmpY, nX, nCurrStart, nSpaceAdd );
1551 :
1552 0 : SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1553 0 : if ( ((SwMultiPortion*)pPor)->IsBidi() )
1554 : {
1555 0 : const sal_uInt8 nBidiLevel = ((SwBidiPortion*)pPor)->GetLevel();
1556 0 : aLayoutModeModifier.Modify( nBidiLevel % 2 );
1557 : }
1558 :
1559 0 : if( ((SwMultiPortion*)pPor)->HasRotation() )
1560 : {
1561 0 : nTmpY -= nY;
1562 0 : if( !((SwMultiPortion*)pPor)->IsRevers() )
1563 0 : nTmpY = pPor->Height() - nTmpY;
1564 0 : if( nTmpY < 0 )
1565 0 : nTmpY = 0;
1566 0 : nX = (KSHORT)nTmpY;
1567 : }
1568 :
1569 0 : if( ((SwMultiPortion*)pPor)->HasBrackets() )
1570 : {
1571 0 : sal_uInt16 nPreWidth = ((SwDoubleLinePortion*)pPor)->PreWidth();
1572 0 : if ( nX > nPreWidth )
1573 0 : nX = nX - nPreWidth;
1574 : else
1575 0 : nX = 0;
1576 : }
1577 :
1578 0 : return GetCrsrOfst( pPos, Point( GetLineStart() + nX, rPoint.Y() ),
1579 0 : nChgNode, pCMS );
1580 : }
1581 0 : if( pPor->InTxtGrp() )
1582 : {
1583 : sal_uInt8 nOldProp;
1584 0 : if( GetPropFont() )
1585 : {
1586 0 : ((SwFont*)GetFnt())->SetProportion( GetPropFont() );
1587 0 : nOldProp = GetFnt()->GetPropr();
1588 : }
1589 : else
1590 0 : nOldProp = 0;
1591 : {
1592 0 : SwTxtSizeInfo aSizeInf( GetInfo(), rText, nCurrStart );
1593 0 : ((SwTxtCursor*)this)->SeekAndChg( aSizeInf );
1594 0 : SwTxtSlot aDiffTxt( &aSizeInf, ((SwTxtPortion*)pPor), false, false );
1595 0 : SwFontSave aSave( aSizeInf, pPor->IsDropPortion() ?
1596 0 : ((SwDropPortion*)pPor)->GetFnt() : NULL );
1597 :
1598 0 : SwParaPortion* pPara = (SwParaPortion*)GetInfo().GetParaPortion();
1599 : OSL_ENSURE( pPara, "No paragraph!" );
1600 :
1601 : SwDrawTextInfo aDrawInf( aSizeInf.GetVsh(),
1602 0 : *aSizeInf.GetOut(),
1603 0 : &pPara->GetScriptInfo(),
1604 0 : aSizeInf.GetTxt(),
1605 0 : aSizeInf.GetIdx(),
1606 0 : pPor->GetLen() );
1607 0 : aDrawInf.SetOfst( nX );
1608 :
1609 0 : if ( nSpaceAdd )
1610 : {
1611 : xub_StrLen nCharCnt;
1612 : // #i41860# Thai justified alignemt needs some
1613 : // additional information:
1614 0 : aDrawInf.SetNumberOfBlanks( pPor->InTxtGrp() ?
1615 0 : static_cast<const SwTxtPortion*>(pPor)->GetSpaceCnt( aSizeInf, nCharCnt ) :
1616 0 : 0 );
1617 : }
1618 :
1619 0 : if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
1620 0 : aDrawInf.SetLen( STRING_LEN ); // SMARTTAGS
1621 :
1622 0 : aDrawInf.SetSpace( nSpaceAdd );
1623 0 : aDrawInf.SetFont( aSizeInf.GetFont() );
1624 0 : aDrawInf.SetFrm( pFrm );
1625 0 : aDrawInf.SetSnapToGrid( aSizeInf.SnapToGrid() );
1626 0 : aDrawInf.SetPosMatchesBounds( pCMS && pCMS->bPosMatchesBounds );
1627 :
1628 0 : if ( SW_CJK == aSizeInf.GetFont()->GetActual() &&
1629 0 : pPara->GetScriptInfo().CountCompChg() &&
1630 0 : ! pPor->InFldGrp() )
1631 0 : aDrawInf.SetKanaComp( nKanaComp );
1632 :
1633 0 : nLength = aSizeInf.GetFont()->_GetCrsrOfst( aDrawInf );
1634 :
1635 : // get position inside field portion?
1636 0 : if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
1637 : {
1638 0 : pCMS->pSpecialPos->nCharOfst = nLength;
1639 0 : nLength = 0; // SMARTTAGS
1640 : }
1641 :
1642 : // set cursor bidi level
1643 0 : if ( pCMS )
1644 : ((SwCrsrMoveState*)pCMS)->nCursorBidiLevel =
1645 0 : aDrawInf.GetCursorBidiLevel();
1646 :
1647 0 : if( bFieldInfo && nLength == pPor->GetLen() &&
1648 0 : ( ! pPor->GetPortion() ||
1649 0 : ! pPor->GetPortion()->IsPostItsPortion() ) )
1650 0 : --nLength;
1651 : }
1652 0 : if( nOldProp )
1653 0 : ((SwFont*)GetFnt())->SetProportion( nOldProp );
1654 : }
1655 : else
1656 : {
1657 0 : if( nChgNode && pPos && pPor->IsFlyCntPortion()
1658 0 : && !( (SwFlyCntPortion*)pPor )->IsDraw() )
1659 : {
1660 : // JP 24.11.94: liegt die Pos nicht im Fly, dann
1661 : // darf nicht mit STRING_LEN returnt werden!
1662 : // (BugId: 9692 + Aenderung in feshview)
1663 0 : SwFlyInCntFrm *pTmp = ( (SwFlyCntPortion*)pPor )->GetFlyFrm();
1664 0 : sal_Bool bChgNode = 1 < nChgNode;
1665 0 : if( !bChgNode )
1666 : {
1667 0 : SwFrm* pLower = pTmp->GetLower();
1668 0 : if( pLower && (pLower->IsTxtFrm() || pLower->IsLayoutFrm()) )
1669 0 : bChgNode = sal_True;
1670 : }
1671 0 : Point aTmpPoint( rPoint );
1672 :
1673 0 : if ( pFrm->IsRightToLeft() )
1674 0 : pFrm->SwitchLTRtoRTL( aTmpPoint );
1675 :
1676 0 : if ( pFrm->IsVertical() )
1677 0 : pFrm->SwitchHorizontalToVertical( aTmpPoint );
1678 :
1679 0 : if( bChgNode && pTmp->Frm().IsInside( aTmpPoint ) &&
1680 0 : !( pTmp->IsProtected() ) )
1681 : {
1682 : nLength = ((SwFlyCntPortion*)pPor)->
1683 0 : GetFlyCrsrOfst( nX, aTmpPoint, pPos, pCMS );
1684 : // Sobald der Frame gewechselt wird, muessen wir aufpassen, dass
1685 : // unser Font wieder im OutputDevice steht.
1686 : // vgl. Paint und new SwFlyCntPortion !
1687 0 : ((SwTxtSizeInfo*)pInf)->SelectFont();
1688 :
1689 : // 6776: Das pIter->GetCrsrOfst returnt
1690 : // aus einer Verschachtelung mit STRING_LEN.
1691 0 : return STRING_LEN;
1692 : }
1693 : }
1694 : else
1695 0 : nLength = pPor->GetCrsrOfst( nX );
1696 : }
1697 : }
1698 0 : nOffset = nCurrStart + nLength;
1699 :
1700 : // 7684: Wir sind vor der HyphPortion angelangt und muessen dafuer
1701 : // sorgen, dass wir in dem String landen.
1702 : // Bei Zeilenenden vor FlyFrms muessen ebenso behandelt werden.
1703 :
1704 0 : if( nOffset && pPor->GetLen() == nLength && pPor->GetPortion() &&
1705 0 : !pPor->GetPortion()->GetLen() && pPor->GetPortion()->InHyphGrp() )
1706 0 : --nOffset;
1707 :
1708 0 : return nOffset;
1709 : }
1710 :
1711 : /** Looks for text portions which are inside the given rectangle
1712 :
1713 : For a rectangular text selection every text portions which is inside the given
1714 : rectangle has to be put into the SwSelectionList as SwPaM
1715 : From these SwPaM the SwCursors will be created.
1716 :
1717 : @param rSelList
1718 : The container for the overlapped text portions
1719 :
1720 : @param rRect
1721 : A rectangle in document coordinates, text inside this rectangle has to be
1722 : selected.
1723 :
1724 : @return [ true, false ]
1725 : true if any overlapping text portion has been found and put into list
1726 : false if no portion overlaps, the list has been unchanged
1727 : */
1728 0 : bool SwTxtFrm::FillSelection( SwSelectionList& rSelList, const SwRect& rRect ) const
1729 : {
1730 0 : bool bRet = false;
1731 : // PaintArea() instead Frm() for negative indents
1732 0 : SwRect aTmpFrm( PaintArea() );
1733 0 : if( !rRect.IsOver( aTmpFrm ) )
1734 0 : return false;
1735 0 : if( rSelList.checkContext( this ) )
1736 : {
1737 0 : SwRect aRect( aTmpFrm );
1738 0 : aRect.Intersection( rRect );
1739 : // rNode without const to create SwPaMs
1740 0 : SwCntntNode &rNode = const_cast<SwCntntNode&>( *GetNode() );
1741 0 : SwNodeIndex aIdx( rNode );
1742 0 : SwPosition aPosL( aIdx, SwIndex( &rNode, 0 ) );
1743 0 : if( IsEmpty() )
1744 : {
1745 0 : SwPaM *pPam = new SwPaM( aPosL, aPosL );
1746 0 : rSelList.insertPaM( pPam );
1747 : }
1748 0 : else if( aRect.HasArea() )
1749 : {
1750 0 : xub_StrLen nOld = STRING_LEN;
1751 0 : SwPosition aPosR( aPosL );
1752 0 : Point aPoint;
1753 0 : SwTxtInfo aInf( const_cast<SwTxtFrm*>(this) );
1754 0 : SwTxtIter aLine( const_cast<SwTxtFrm*>(this), &aInf );
1755 : // We have to care for top-to-bottom layout, where right becomes top etc.
1756 0 : SWRECTFN( this )
1757 0 : SwTwips nTop = (aRect.*fnRect->fnGetTop)();
1758 0 : SwTwips nBottom = (aRect.*fnRect->fnGetBottom)();
1759 0 : SwTwips nLeft = (aRect.*fnRect->fnGetLeft)();
1760 0 : SwTwips nRight = (aRect.*fnRect->fnGetRight)();
1761 0 : SwTwips nY = aLine.Y(); // Top position of the first line
1762 0 : SwTwips nLastY = nY;
1763 0 : while( nY < nTop && aLine.Next() ) // line above rectangle
1764 : {
1765 0 : nLastY = nY;
1766 0 : nY = aLine.Y();
1767 : }
1768 0 : bool bLastLine = false;
1769 0 : if( nY < nTop && !aLine.GetNext() )
1770 : {
1771 0 : bLastLine = true;
1772 0 : nY += aLine.GetLineHeight();
1773 : }
1774 0 : do // check the lines for overlapping
1775 : {
1776 0 : if( nLastY < nTop ) // if the last line was above rectangle
1777 0 : nLastY = nTop;
1778 0 : if( nY > nBottom ) // if the current line leaves the rectangle
1779 0 : nY = nBottom;
1780 0 : if( nY >= nLastY ) // gotcha: overlapping
1781 : {
1782 0 : nLastY += nY;
1783 0 : nLastY /= 2;
1784 0 : if( bVert )
1785 : {
1786 0 : aPoint.X() = nLastY;
1787 0 : aPoint.Y() = nLeft;
1788 : }
1789 : else
1790 : {
1791 0 : aPoint.X() = nLeft;
1792 0 : aPoint.Y() = nLastY;
1793 : }
1794 : // Looking for the position of the left border of the rectangle
1795 : // in this text line
1796 0 : SwCrsrMoveState aState( MV_UPDOWN );
1797 0 : if( GetCrsrOfst( &aPosL, aPoint, &aState ) )
1798 : {
1799 0 : if( bVert )
1800 : {
1801 0 : aPoint.X() = nLastY;
1802 0 : aPoint.Y() = nRight;
1803 : }
1804 : else
1805 : {
1806 0 : aPoint.X() = nRight;
1807 0 : aPoint.Y() = nLastY;
1808 : }
1809 : // If we get a right position and if the left position
1810 : // is not the same like the left position of the line before
1811 : // which cound happen e.g. for field portions or fly frames
1812 : // a SwPaM will be inserted with these positions
1813 0 : if( GetCrsrOfst( &aPosR, aPoint, &aState ) &&
1814 0 : nOld != aPosL.nContent.GetIndex() )
1815 : {
1816 0 : SwPaM *pPam = new SwPaM( aPosL, aPosR );
1817 0 : rSelList.insertPaM( pPam );
1818 0 : nOld = aPosL.nContent.GetIndex();
1819 : }
1820 : }
1821 : }
1822 0 : if( aLine.Next() )
1823 : {
1824 0 : nLastY = nY;
1825 0 : nY = aLine.Y();
1826 : }
1827 0 : else if( !bLastLine )
1828 : {
1829 0 : bLastLine = true;
1830 0 : nLastY = nY;
1831 0 : nY += aLine.GetLineHeight();
1832 : }
1833 : else
1834 0 : break;
1835 0 : }while( nLastY < nBottom );
1836 0 : }
1837 : }
1838 0 : if( GetDrawObjs() )
1839 : {
1840 0 : const SwSortedObjs &rObjs = *GetDrawObjs();
1841 0 : for ( sal_uInt16 i = 0; i < rObjs.Count(); ++i )
1842 : {
1843 0 : const SwAnchoredObject* pAnchoredObj = rObjs[i];
1844 0 : if( !pAnchoredObj->ISA(SwFlyFrm) )
1845 0 : continue;
1846 0 : const SwFlyFrm* pFly = static_cast<const SwFlyFrm*>(pAnchoredObj);
1847 0 : if( pFly->IsFlyInCntFrm() && pFly->FillSelection( rSelList, rRect ) )
1848 0 : bRet = true;
1849 : }
1850 : }
1851 0 : return bRet;
1852 : }
1853 :
1854 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|