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