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