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 SwTxtCursor::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( SwTxtSizeInfo& 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.InFldGrp() && !((SwFldPortion&)rPor).GetExp().isEmpty() )
64 : {
65 0 : const sal_Int32 nCharOfst = rCMS.pSpecialPos->nCharOfst;
66 0 : sal_Int32 nFldIdx = 0;
67 0 : sal_Int32 nFldLen = 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->InFldGrp() )
75 : {
76 0 : sString = ((SwFldPortion*)pPor)->GetExp();
77 0 : pString = &sString;
78 0 : nFldLen = pString->getLength();
79 : }
80 : else
81 : {
82 0 : pString = 0;
83 0 : nFldLen = 0;
84 : }
85 :
86 0 : if ( ! pPor->GetPortion() || nFldIdx + nFldLen > nCharOfst )
87 0 : break;
88 :
89 0 : nFldIdx = nFldIdx + nFldLen;
90 0 : rOrig.Pos().X() += pPor->Width();
91 0 : pPor = pPor->GetPortion();
92 :
93 : } while ( true );
94 :
95 : OSL_ENSURE( nCharOfst >= nFldIdx, "Request of position inside field failed" );
96 0 : sal_Int32 nLen = nCharOfst - nFldIdx + 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 : ((SwLinePortion*)pPor)->SetLen( nLen - 1 );
105 0 : const SwTwips nX1 = pPor->GetLen() ?
106 0 : pPor->GetTxtSize( rInf ).Width() :
107 0 : 0;
108 :
109 0 : SwTwips nX2 = 0;
110 0 : if ( rCMS.bRealWidth )
111 : {
112 0 : ((SwLinePortion*)pPor)->SetLen( nLen );
113 0 : nX2 = pPor->GetTxtSize( rInf ).Width();
114 : }
115 :
116 0 : ((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 317328 : bool AreListLevelIndentsApplicableAndLabelAlignmentActive( const SwTxtNode& rTxtNode )
135 : {
136 317328 : bool bRet( false );
137 :
138 317328 : if ( rTxtNode.GetNumRule() && rTxtNode.AreListLevelIndentsApplicable() )
139 : {
140 11568 : int nListLevel = rTxtNode.GetActualListLevel();
141 :
142 11568 : if (nListLevel < 0)
143 0 : nListLevel = 0;
144 :
145 11568 : if (nListLevel >= MAXLEVEL)
146 0 : nListLevel = MAXLEVEL - 1;
147 :
148 : const SwNumFmt& rNumFmt =
149 11568 : rTxtNode.GetNumRule()->Get( static_cast<sal_uInt16>(nListLevel) );
150 11568 : if ( rNumFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
151 : {
152 10498 : bRet = true;
153 : }
154 : }
155 :
156 317328 : return bRet;
157 : }
158 : } // end of anonymous namespace
159 :
160 317328 : void SwTxtMargin::CtorInitTxtMargin( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
161 : {
162 317328 : CtorInitTxtIter( pNewFrm, pNewInf );
163 :
164 317328 : pInf = pNewInf;
165 317328 : GetInfo().SetFont( GetFnt() );
166 317328 : const SwTxtNode *pNode = pFrm->GetTxtNode();
167 :
168 317328 : const SvxLRSpaceItem &rSpace = pFrm->GetTxtNode()->GetSwAttrSet().GetLRSpace();
169 : // #i95907#
170 : // #i111284#
171 : const bool bListLevelIndentsApplicableAndLabelAlignmentActive(
172 317328 : AreListLevelIndentsApplicableAndLabelAlignmentActive( *(pFrm->GetTxtNode()) ) );
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 317328 : const int nLMWithNum = pNode->GetLeftMarginWithNum( true );
186 317328 : if ( pFrm->IsRightToLeft() )
187 : {
188 : // this calculation is identical this the calculation for L2R layout - see below
189 776 : nLeft = pFrm->Frm().Left() +
190 776 : pFrm->Prt().Left() +
191 388 : nLMWithNum -
192 1164 : pNode->GetLeftMarginWithNum() -
193 : // #i95907#
194 : // #i111284#
195 : // rSpace.GetLeft() + rSpace.GetTxtLeft();
196 : ( bListLevelIndentsApplicableAndLabelAlignmentActive
197 : ? 0
198 776 : : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
199 : }
200 : else
201 : {
202 : // #i95907#
203 : // #i111284#
204 623382 : if ( bListLevelIndentsApplicableAndLabelAlignmentActive ||
205 306442 : !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 633546 : nLeft = pFrm->Frm().Left() +
209 633546 : pFrm->Prt().Left() +
210 316773 : nLMWithNum -
211 939821 : pNode->GetLeftMarginWithNum() -
212 : // #i95907#
213 : // #i111284#
214 : ( bListLevelIndentsApplicableAndLabelAlignmentActive
215 : ? 0
216 623048 : : ( rSpace.GetLeft() - rSpace.GetTxtLeft() ) );
217 : }
218 : else
219 : {
220 334 : nLeft = pFrm->Frm().Left() +
221 167 : std::max( long( rSpace.GetTxtLeft() + nLMWithNum ),
222 501 : pFrm->Prt().Left() );
223 : }
224 : }
225 :
226 317328 : nRight = pFrm->Frm().Left() + pFrm->Prt().Left() + pFrm->Prt().Width();
227 :
228 318092 : if( nLeft >= nRight &&
229 : // #i53066# Omit adjustment of nLeft for numbered
230 : // paras inside cells inside new documents:
231 764 : ( pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) ||
232 632 : !pFrm->IsInTab() ||
233 : !nLMWithNum ) )
234 : {
235 382 : nLeft = pFrm->Prt().Left() + pFrm->Frm().Left();
236 382 : if( nLeft >= nRight ) // e.g. with large paragraph indentations in slim table columns
237 238 : nRight = nLeft + 1; // einen goennen wir uns immer
238 : }
239 :
240 317328 : if( pFrm->IsFollow() && pFrm->GetOfst() )
241 27071 : nFirst = nLeft;
242 : else
243 : {
244 290257 : short nFLOfst = 0;
245 290257 : long nFirstLineOfs = 0;
246 566254 : if( !pNode->GetFirstLineOfsWithNum( nFLOfst ) &&
247 275997 : 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 290257 : nFirstLineOfs = nFLOfst;
298 :
299 : // #i95907#
300 : // #i111284#
301 870383 : if ( pFrm->IsRightToLeft() ||
302 569646 : bListLevelIndentsApplicableAndLabelAlignmentActive ||
303 279389 : !pNode->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) )
304 : {
305 290090 : nFirst = nLeft + nFirstLineOfs;
306 : }
307 : else
308 : {
309 334 : nFirst = pFrm->Frm().Left() +
310 167 : std::max( rSpace.GetTxtLeft() + nLMWithNum+ nFirstLineOfs,
311 501 : pFrm->Prt().Left() );
312 : }
313 :
314 : // Note: <SwTxtFrm::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 290257 : nFirst += pFrm->GetAdditionalFirstLineOffset();
319 :
320 290257 : if( nFirst >= nRight )
321 110 : nFirst = nRight - 1;
322 : }
323 317328 : const SvxAdjustItem& rAdjust = pFrm->GetTxtNode()->GetSwAttrSet().GetAdjust();
324 317328 : nAdjust = static_cast<sal_uInt16>(rAdjust.GetAdjust());
325 :
326 : // left is left and right is right
327 317328 : if ( pFrm->IsRightToLeft() )
328 : {
329 388 : if ( SVX_ADJUST_LEFT == nAdjust )
330 164 : nAdjust = SVX_ADJUST_RIGHT;
331 224 : else if ( SVX_ADJUST_RIGHT == nAdjust )
332 110 : nAdjust = SVX_ADJUST_LEFT;
333 : }
334 :
335 317328 : bOneBlock = rAdjust.GetOneWord() == SVX_ADJUST_BLOCK;
336 317328 : bLastBlock = rAdjust.GetLastBlock() == SVX_ADJUST_BLOCK;
337 317328 : bLastCenter = rAdjust.GetLastBlock() == SVX_ADJUST_CENTER;
338 :
339 : // #i91133#
340 317328 : 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 317328 : DropInit();
351 317328 : }
352 :
353 317340 : void SwTxtMargin::DropInit()
354 : {
355 317340 : nDropLeft = nDropLines = nDropHeight = nDropDescent = 0;
356 317340 : const SwParaPortion *pPara = GetInfo().GetParaPortion();
357 317340 : if( pPara )
358 : {
359 317340 : const SwDropPortion *pPorDrop = pPara->FindDropPortion();
360 317340 : if ( pPorDrop )
361 : {
362 156 : nDropLeft = pPorDrop->GetDropLeft();
363 156 : nDropLines = pPorDrop->GetLines();
364 156 : nDropHeight = pPorDrop->GetDropHeight();
365 156 : nDropDescent = pPorDrop->GetDropDescent();
366 : }
367 : }
368 317340 : }
369 :
370 : // The function is interpreting / observing / evaluating / keeping / respecting the first line indention and the specified width.
371 263993 : SwTwips SwTxtMargin::GetLineStart() const
372 : {
373 263993 : SwTwips nRet = GetLeftMargin();
374 306471 : if( GetAdjust() != SVX_ADJUST_LEFT &&
375 42478 : !pCurr->GetFirstPortion()->IsMarginPortion() )
376 : {
377 : // If the first portion is a Margin, then the
378 : // adjustment is expressed by the portions.
379 34628 : if( GetAdjust() == SVX_ADJUST_RIGHT )
380 2196 : nRet = Right() - CurrWidth();
381 32432 : else if( GetAdjust() == SVX_ADJUST_CENTER )
382 10966 : nRet += (GetLineWidth() - CurrWidth()) / 2;
383 : }
384 263993 : return nRet;
385 : }
386 :
387 237348 : void SwTxtCursor::CtorInitTxtCursor( SwTxtFrm *pNewFrm, SwTxtSizeInfo *pNewInf )
388 : {
389 237348 : CtorInitTxtMargin( pNewFrm, pNewInf );
390 : // 6096: Attention, the iterators are derived!
391 : // GetInfo().SetOut( GetInfo().GetWin() );
392 237348 : }
393 :
394 : // 1170: Ancient bug: Shift-End forgets the last character ...
395 0 : bool SwTxtCursor::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().GetTxt().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->InTxtGrp() || ( 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 SwTxtCursor::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 119033 : void SwTxtCursor::_GetCharRect( SwRect* pOrig, const sal_Int32 nOfst,
470 : SwCrsrMoveState* pCMS )
471 : {
472 119033 : const OUString aText = GetInfo().GetTxt();
473 237674 : SwTxtSizeInfo aInf( GetInfo(), &aText, nStart );
474 119033 : if( GetPropFont() )
475 50 : aInf.GetFont()->SetProportion( GetPropFont() );
476 : sal_uInt16 nTmpAscent, nTmpHeight; // Line height
477 119033 : CalcAscentAndHeight( nTmpAscent, nTmpHeight );
478 119033 : const Size aCharSize( 1, nTmpHeight );
479 119033 : const Point aCharPos;
480 119033 : pOrig->Pos( aCharPos );
481 119033 : 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 119033 : const bool bInsideFirstField = pCMS && pCMS->pSpecialPos &&
487 0 : ( pCMS->pSpecialPos->nLineOfst ||
488 0 : SP_EXTEND_RANGE_BEFORE ==
489 119033 : pCMS->pSpecialPos->nExtendRange );
490 :
491 119033 : bool bWidth = pCMS && pCMS->bRealWidth;
492 119033 : if( !pCurr->GetLen() && !pCurr->Width() )
493 : {
494 12506 : if ( pCMS && pCMS->bRealHeight )
495 : {
496 12470 : pCMS->aRealHeight.X() = 0;
497 12470 : pCMS->aRealHeight.Y() = nTmpHeight;
498 : }
499 : }
500 : else
501 : {
502 106527 : sal_uInt16 nPorHeight = nTmpHeight;
503 106527 : sal_uInt16 nPorAscent = nTmpAscent;
504 106527 : SwTwips nX = 0;
505 106527 : SwTwips nTmpFirst = 0;
506 106527 : SwLinePortion *pPor = pCurr->GetFirstPortion();
507 106527 : SwBidiPortion* pLastBidiPor = 0;
508 106527 : SwTwips nLastBidiPorWidth = 0;
509 106527 : std::deque<sal_uInt16>* pKanaComp = pCurr->GetpKanaComp();
510 106527 : sal_uInt16 nSpaceIdx = 0;
511 106527 : size_t nKanaIdx = 0;
512 106527 : long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
513 :
514 106527 : bool bNoTxt = 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, FtnNum, FeldReste
519 : // 8477: but also the only Textportion of an empty line with
520 : // Right/Center-Adjustment! So not just pPor->GetExpandPortion() ...
521 225766 : while( pPor && !pPor->GetLen() && ! bInsideFirstField )
522 : {
523 12712 : nX += pPor->Width();
524 12712 : if ( pPor->InSpaceGrp() && nSpaceAdd )
525 0 : nX += pPor->CalcSpacing( nSpaceAdd, aInf );
526 12712 : if( bNoTxt )
527 8320 : nTmpFirst = nX;
528 : // 8670: EndPortions count once as TxtPortions.
529 : // if( pPor->InTxtGrp() || pPor->IsBreakPortion() )
530 12712 : if( pPor->InTxtGrp() || pPor->IsBreakPortion() || pPor->InTabGrp() )
531 : {
532 4804 : bNoTxt = false;
533 4804 : nTmpFirst = nX;
534 : }
535 12712 : if( pPor->IsMultiPortion() && ((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 12712 : if( pPor->InFixMargGrp() )
549 : {
550 9636 : if( pPor->IsMarginPortion() )
551 6808 : bNoTxt = false;
552 : else
553 : {
554 : // fix margin portion => next SpaceAdd, KanaComp value
555 2828 : 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 2828 : if( pKanaComp && ( nKanaIdx + 1 ) < pKanaComp->size() )
564 0 : ++nKanaIdx;
565 : }
566 : }
567 12712 : pPor = pPor->GetPortion();
568 : }
569 :
570 106527 : if( !pPor )
571 : {
572 : // There's just Spezialportions.
573 1794 : nX = nTmpFirst;
574 : }
575 : else
576 : {
577 313243 : if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
578 105283 : (!pPor->InFldGrp() || pPor->GetAscent() ) )
579 : {
580 104255 : nPorHeight = pPor->Height();
581 104255 : nPorAscent = pPor->GetAscent();
582 : }
583 319965 : while( pPor && !pPor->IsBreakPortion() && ( aInf.GetIdx() < nOfst ||
584 0 : ( bWidth && ( pPor->IsKernPortion() || pPor->IsMultiPortion() ) ) ) )
585 : {
586 169747 : if( !pPor->IsMarginPortion() && !pPor->IsPostItsPortion() &&
587 58307 : (!pPor->InFldGrp() || pPor->GetAscent() ) )
588 : {
589 56173 : nPorHeight = pPor->Height();
590 56173 : 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 58585 : const sal_Int32 nExtra = pPor->IsMultiPortion() &&
599 1184 : ! ((SwMultiPortion*)pPor)->IsBidi() &&
600 58585 : ! bWidth ? 0 : 1;
601 57401 : if ( aInf.GetIdx() + pPor->GetLen() < nOfst + nExtra )
602 : {
603 53098 : if ( pPor->InSpaceGrp() && nSpaceAdd )
604 0 : nX += pPor->PrtWidth() +
605 0 : pPor->CalcSpacing( nSpaceAdd, aInf );
606 : else
607 : {
608 53098 : if( pPor->InFixMargGrp() && ! pPor->IsMarginPortion() )
609 : {
610 : // update to current SpaceAdd, KanaComp values
611 12 : 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 12 : if ( pKanaComp &&
620 0 : ( nKanaIdx + 1 ) < pKanaComp->size()
621 : )
622 0 : ++nKanaIdx;
623 : }
624 53098 : if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
625 0 : !pPor->GetPortion()->IsMarginPortion() ) )
626 53098 : nX += pPor->PrtWidth();
627 : }
628 53098 : if( pPor->IsMultiPortion() )
629 : {
630 792 : if ( ((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 792 : if ( ((SwMultiPortion*)pPor)->IsBidi() &&
649 0 : aInf.GetIdx() + pPor->GetLen() == nOfst )
650 : {
651 0 : pLastBidiPor = (SwBidiPortion*)pPor;
652 0 : nLastBidiPorWidth = pLastBidiPor->Width() +
653 0 : pLastBidiPor->CalcSpacing( nSpaceAdd, aInf );;
654 : }
655 : }
656 :
657 53098 : aInf.SetIdx( aInf.GetIdx() + pPor->GetLen() );
658 53098 : pPor = pPor->GetPortion();
659 : }
660 : else
661 : {
662 4303 : if( pPor->IsMultiPortion() )
663 : {
664 392 : nTmpAscent = AdjustBaseLine( *pCurr, pPor );
665 392 : GetInfo().SetMulti( true );
666 392 : pOrig->Pos().Y() += nTmpAscent - nPorAscent;
667 :
668 392 : if( pCMS && pCMS->b2Lines )
669 : {
670 136 : const bool bRecursion = pCMS->p2Lines;
671 136 : if ( !bRecursion )
672 : {
673 136 : pCMS->p2Lines = new Sw2LinesPos;
674 136 : pCMS->p2Lines->aLine = SwRect(aCharPos, aCharSize);
675 : }
676 :
677 136 : if( ((SwMultiPortion*)pPor)->HasRotation() )
678 : {
679 0 : if( ((SwMultiPortion*)pPor)->IsRevers() )
680 0 : pCMS->p2Lines->nMultiType = MT_ROT_270;
681 : else
682 0 : pCMS->p2Lines->nMultiType = MT_ROT_90;
683 : }
684 136 : else if( ((SwMultiPortion*)pPor)->IsDouble() )
685 30 : pCMS->p2Lines->nMultiType = MT_TWOLINE;
686 106 : else if( ((SwMultiPortion*)pPor)->IsBidi() )
687 0 : pCMS->p2Lines->nMultiType = MT_BIDI;
688 : else
689 106 : pCMS->p2Lines->nMultiType = MT_RUBY;
690 :
691 136 : SwTwips nTmpWidth = pPor->Width();
692 136 : if( nSpaceAdd )
693 0 : nTmpWidth += pPor->CalcSpacing(nSpaceAdd, aInf);
694 :
695 136 : SwRect aRect( Point(aCharPos.X() + nX, pOrig->Top() ),
696 272 : Size( nTmpWidth, pPor->Height() ) );
697 :
698 136 : if ( ! bRecursion )
699 136 : 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 392 : sal_Int32 nOldStart = nStart;
708 392 : SwTwips nOldY = nY;
709 392 : sal_uInt8 nOldProp = GetPropFont();
710 392 : nStart = aInf.GetIdx();
711 392 : SwLineLayout* pOldCurr = pCurr;
712 392 : pCurr = &((SwMultiPortion*)pPor)->GetRoot();
713 392 : if( ((SwMultiPortion*)pPor)->IsDouble() )
714 50 : SetPropFont( 50 );
715 :
716 : SwTextGridItem const*const pGrid(
717 392 : GetGridItem(GetTxtFrm()->FindPageFrm()));
718 392 : const bool bHasGrid = pGrid && GetInfo().SnapToGrid();
719 : const sal_uInt16 nRubyHeight = bHasGrid ?
720 392 : pGrid->GetRubyHeight() : 0;
721 :
722 1028 : if( nStart + pCurr->GetLen() <= nOfst && GetNext() &&
723 734 : ( ! ((SwMultiPortion*)pPor)->IsRuby() ||
724 342 : ((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 244 : if ( bHasGrid &&
730 244 : ((SwMultiPortion*)pPor)->IsRuby() &&
731 0 : ((SwMultiPortion*)pPor)->OnTop() )
732 0 : nOffset = nRubyHeight;
733 : else
734 244 : nOffset = GetLineHeight();
735 :
736 244 : pOrig->Pos().Y() += nOffset;
737 244 : Next();
738 : }
739 :
740 : const bool bSpaceChg = ((SwMultiPortion*)pPor)->
741 392 : ChgSpaceAdd( pCurr, nSpaceAdd );
742 392 : 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 392 : const sal_uInt16 nOldRubyHeight = pCurr->Height();
749 392 : const sal_uInt16 nOldRubyRealHeight = pCurr->GetRealHeight();
750 : const bool bChgHeight =
751 392 : ((SwMultiPortion*)pPor)->IsRuby() && bHasGrid;
752 :
753 392 : if ( bChgHeight )
754 : {
755 0 : pCurr->Height( pOldCurr->Height() - nRubyHeight );
756 0 : pCurr->SetRealHeight( pOldCurr->GetRealHeight() -
757 0 : nRubyHeight );
758 : }
759 :
760 392 : SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
761 392 : if ( ((SwMultiPortion*)pPor)->IsBidi() )
762 : {
763 : aLayoutModeModifier.Modify(
764 0 : ((SwBidiPortion*)pPor)->GetLevel() % 2 );
765 : }
766 :
767 392 : _GetCharRect( pOrig, nOfst, pCMS );
768 :
769 392 : 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 392 : if ( ((SwMultiPortion*)pPor)->IsDouble() )
779 : {
780 : // the recursion may have damaged our font size
781 50 : SetPropFont( nOldProp );
782 50 : if ( !nOldProp )
783 50 : nOldProp = 100;
784 50 : GetInfo().GetFont()->SetProportion( 100 );
785 :
786 50 : if ( pCurr == &((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 342 : else if( ((SwMultiPortion*)pPor)->IsRuby() ||
800 0 : ((SwMultiPortion*)pPor)->IsBidi() )
801 342 : GetInfo().SetMulti( false );
802 :
803 : // calculate cursor values
804 392 : if( ((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( ((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( ((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 392 : pOrig->Pos().Y() += aOldPos.Y();
850 392 : if ( ((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 392 : pOrig->Pos().X() += nX;
860 :
861 392 : if( ((SwMultiPortion*)pPor)->HasBrackets() )
862 40 : pOrig->Pos().X() +=
863 80 : ((SwDoubleLinePortion*)pPor)->PreWidth();
864 : }
865 :
866 392 : if( bSpaceChg )
867 0 : SwDoubleLinePortion::ResetSpaceAdd( pCurr );
868 :
869 392 : pCurr = pOldCurr;
870 392 : nStart = nOldStart;
871 392 : nY = nOldY;
872 392 : bPrev = false;
873 :
874 119425 : return;
875 : }
876 3911 : if ( pPor->PrtWidth() )
877 : {
878 3907 : sal_Int32 nOldLen = pPor->GetLen();
879 3907 : pPor->SetLen( nOfst - aInf.GetIdx() );
880 3907 : aInf.SetLen( pPor->GetLen() );
881 3907 : if( nX || !pPor->InNumberGrp() )
882 : {
883 3907 : SeekAndChg( aInf );
884 3907 : const bool bOldOnWin = aInf.OnWin();
885 3907 : aInf.SetOnWin( false ); // keine BULLETs!
886 3907 : SwTwips nTmp = nX;
887 3907 : aInf.SetKanaComp( pKanaComp );
888 3907 : aInf.SetKanaIdx( nKanaIdx );
889 3907 : nX += pPor->GetTxtSize( aInf ).Width();
890 3907 : aInf.SetOnWin( bOldOnWin );
891 3907 : if ( pPor->InSpaceGrp() && nSpaceAdd )
892 0 : nX += pPor->CalcSpacing( nSpaceAdd, aInf );
893 3907 : 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->GetTxtSize( 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 3907 : pPor->SetLen( nOldLen );
906 :
907 : // Shift the cursor with the right border width
908 : // Note: nX remains positive because GetTxtSize() also include the width of the right border
909 3907 : if( aInf.GetIdx() < nOfst && nOfst < aInf.GetIdx() + pPor->GetLen() )
910 : {
911 : // Find the current drop portion part and use its right border
912 3907 : 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 3907 : else if( GetInfo().GetFont()->GetRightBorder() && !pPor->GetJoinBorderWithNext())
928 : {
929 0 : nX -= GetInfo().GetFont()->GetRightBorderSpace();
930 : }
931 : }
932 : }
933 3911 : bWidth = false;
934 3911 : break;
935 : }
936 : }
937 : }
938 :
939 106135 : if( pPor )
940 : {
941 : OSL_ENSURE( !pPor->InNumberGrp() || bInsideFirstField, "Number surprise" );
942 61971 : bool bEmptyFld = false;
943 61971 : if( pPor->InFldGrp() && pPor->GetLen() )
944 : {
945 436 : SwFldPortion *pTmp = (SwFldPortion*)pPor;
946 872 : 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->InFldGrp() )
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 = (SwFldPortion*)pNext;
959 0 : nPorHeight = pTmp->Height();
960 0 : nPorAscent = pTmp->GetAscent();
961 0 : nX += nAddX;
962 0 : bEmptyFld = true;
963 : }
964 : }
965 : // 8513: Fields in justified text, skipped
966 123978 : while( pPor && !pPor->GetLen() && ! bInsideFirstField &&
967 36 : ( pPor->IsFlyPortion() || pPor->IsKernPortion() ||
968 36 : pPor->IsBlankPortion() || pPor->InTabGrp() ||
969 24 : ( !bEmptyFld && pPor->InFldGrp() ) ) )
970 : {
971 12 : if ( pPor->InSpaceGrp() && nSpaceAdd )
972 0 : nX += pPor->PrtWidth() +
973 0 : pPor->CalcSpacing( nSpaceAdd, aInf );
974 : else
975 : {
976 12 : 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 12 : if ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
990 0 : !pPor->GetPortion()->IsMarginPortion() ) )
991 12 : nX += pPor->PrtWidth();
992 : }
993 12 : if( pPor->IsMultiPortion() &&
994 0 : ((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 12 : if( !pPor->IsFlyPortion() )
1008 : {
1009 12 : nPorHeight = pPor->Height();
1010 12 : nPorAscent = pPor->GetAscent();
1011 : }
1012 12 : pPor = pPor->GetPortion();
1013 : }
1014 :
1015 182002 : if( aInf.GetIdx() == nOfst && pPor && pPor->InHyphGrp() &&
1016 61971 : 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 61971 : if( pPor && pCMS )
1034 : {
1035 57634 : if( pCMS->bFieldInfo && pPor->InFldGrp() && pPor->Width() )
1036 0 : pOrig->Width( pPor->Width() );
1037 57634 : if( pPor->IsDropPortion() )
1038 : {
1039 128 : nPorAscent = ((SwDropPortion*)pPor)->GetDropHeight();
1040 : // The drop height is only calculated, if we have more than
1041 : // one line. Otherwise it is 0.
1042 128 : if ( ! nPorAscent)
1043 128 : nPorAscent = pPor->Height();
1044 128 : nPorHeight = nPorAscent;
1045 256 : pOrig->Height( nPorHeight +
1046 256 : ((SwDropPortion*)pPor)->GetDropDescent() );
1047 128 : if( nTmpHeight < pOrig->Height() )
1048 : {
1049 0 : nTmpAscent = nPorAscent;
1050 0 : nTmpHeight = sal_uInt16( pOrig->Height() );
1051 : }
1052 : }
1053 57634 : 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->GetTxtSize( 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 57634 : 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 106333 : if ( pCMS &&
1101 101804 : ( pLastBidiPor ||
1102 57634 : ( pPor &&
1103 58134 : pPor->IsMultiPortion() &&
1104 500 : ((SwMultiPortion*)pPor)->IsBidi() ) ) )
1105 : {
1106 : // we determine if the cursor has to blink before or behind
1107 : // the bidi portion
1108 198 : 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 : ((SwMultiPortion*)pLastBidiPor)->GetRoot();
1124 :
1125 0 : const SwLinePortion *pLast = rLineLayout.FindLastPortion();
1126 0 : if ( pLast->IsMultiPortion() )
1127 : {
1128 : OSL_ENSURE( ((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 198 : const sal_uInt8 nPortionLevel = ((SwBidiPortion*)pPor)->GetLevel();
1138 :
1139 198 : 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 106135 : pOrig->Pos().X() += nX;
1150 :
1151 106135 : if ( pCMS && pCMS->bRealHeight )
1152 : {
1153 98946 : nTmpAscent = AdjustBaseLine( *pCurr, 0, nPorHeight, nPorAscent );
1154 98946 : if ( nTmpAscent > nPorAscent )
1155 1846 : pCMS->aRealHeight.X() = nTmpAscent - nPorAscent;
1156 : else
1157 97100 : pCMS->aRealHeight.X() = 0;
1158 : OSL_ENSURE( nPorHeight, "GetCharRect: Missing Portion-Height" );
1159 98946 : if ( nTmpHeight > nPorHeight )
1160 2662 : pCMS->aRealHeight.Y() = nPorHeight;
1161 : else
1162 96284 : pCMS->aRealHeight.Y() = nTmpHeight;
1163 : }
1164 118641 : }
1165 : }
1166 :
1167 118641 : bool SwTxtCursor::GetCharRect( SwRect* pOrig, const sal_Int32 nOfst,
1168 : SwCrsrMoveState* pCMS, const long nMax )
1169 : {
1170 118641 : CharCrsrToLine(nOfst);
1171 :
1172 : // Indicates that a position inside a special portion (field, number portion)
1173 : // is requested.
1174 118641 : const bool bSpecialPos = pCMS && pCMS->pSpecialPos;
1175 118641 : sal_Int32 nFindOfst = nOfst;
1176 :
1177 118641 : if ( bSpecialPos )
1178 : {
1179 0 : const sal_uInt8 nExtendRange = pCMS->pSpecialPos->nExtendRange;
1180 :
1181 : OSL_ENSURE( ! pCMS->pSpecialPos->nLineOfst || SP_EXTEND_RANGE_BEFORE != nExtendRange,
1182 : "LineOffset AND Number Portion?" );
1183 :
1184 : // portions which are behind the string
1185 0 : if ( SP_EXTEND_RANGE_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 118641 : GetAdjusted();
1195 :
1196 118641 : const Point aCharPos( GetTopLeft() );
1197 118641 : bool bRet = true;
1198 :
1199 118641 : _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 118641 : const SwTwips nTmpRight = Right() - 12;
1204 :
1205 118641 : pOrig->Pos().X() += aCharPos.X();
1206 118641 : pOrig->Pos().Y() += aCharPos.Y();
1207 :
1208 118641 : if( pCMS && pCMS->b2Lines && pCMS->p2Lines )
1209 : {
1210 136 : pCMS->p2Lines->aLine.Pos().X() += aCharPos.X();
1211 136 : pCMS->p2Lines->aLine.Pos().Y() += aCharPos.Y();
1212 136 : pCMS->p2Lines->aPortion.Pos().X() += aCharPos.X();
1213 136 : pCMS->p2Lines->aPortion.Pos().Y() += aCharPos.Y();
1214 : }
1215 :
1216 118641 : const bool bTabOverMargin = GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::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 118641 : if( pOrig->Left() > nTmpRight && !bTabOverMargin)
1219 12 : pOrig->Pos().X() = nTmpRight;
1220 :
1221 118641 : if( nMax )
1222 : {
1223 115474 : if( pOrig->Top() + pOrig->Height() > nMax )
1224 : {
1225 790 : if( pOrig->Top() > nMax )
1226 0 : pOrig->Top( nMax );
1227 790 : pOrig->Height( nMax - pOrig->Top() );
1228 : }
1229 115474 : if ( pCMS && pCMS->bRealHeight && pCMS->aRealHeight.Y() >= 0 )
1230 : {
1231 111416 : long nTmp = pCMS->aRealHeight.X() + pOrig->Top();
1232 111416 : if( nTmp >= nMax )
1233 : {
1234 0 : pCMS->aRealHeight.X() = nMax - pOrig->Top();
1235 0 : pCMS->aRealHeight.Y() = 0;
1236 : }
1237 111416 : else if( nTmp + pCMS->aRealHeight.Y() > nMax )
1238 848 : pCMS->aRealHeight.Y() = nMax - nTmp;
1239 : }
1240 : }
1241 118641 : long nOut = pOrig->Right() - GetTxtFrm()->Frm().Right();
1242 118641 : if( nOut > 0 )
1243 : {
1244 540 : if( GetTxtFrm()->Frm().Width() < GetTxtFrm()->Prt().Left()
1245 270 : + GetTxtFrm()->Prt().Width() )
1246 0 : nOut += GetTxtFrm()->Frm().Width() - GetTxtFrm()->Prt().Left()
1247 0 : - GetTxtFrm()->Prt().Width();
1248 270 : if( nOut > 0 )
1249 270 : pOrig->Pos().X() -= nOut + 10;
1250 : }
1251 :
1252 118641 : return bRet;
1253 : }
1254 :
1255 : // Return: Offset in String
1256 234 : sal_Int32 SwTxtCursor::GetCrsrOfst( SwPosition *pPos, const Point &rPoint,
1257 : bool nChgNode, SwCrsrMoveState* pCMS ) const
1258 : {
1259 : // If necessary, as catch up, do the adjustment
1260 234 : GetAdjusted();
1261 :
1262 234 : const OUString &rText = GetInfo().GetTxt();
1263 234 : sal_Int32 nOffset = 0;
1264 :
1265 : // x is the horizontal offset within the line.
1266 234 : SwTwips x = rPoint.X();
1267 234 : const SwTwips nLeftMargin = GetLineStart();
1268 234 : SwTwips nRightMargin = GetLineEnd();
1269 234 : if( nRightMargin == nLeftMargin )
1270 2 : nRightMargin += 30;
1271 :
1272 234 : const bool bLeftOver = x < nLeftMargin;
1273 234 : if( bLeftOver )
1274 4 : x = nLeftMargin;
1275 234 : const bool bRightOver = x > nRightMargin;
1276 234 : if( bRightOver )
1277 166 : x = nRightMargin;
1278 :
1279 234 : const bool bRightAllowed = pCMS && ( pCMS->eState == MV_NONE );
1280 :
1281 : // Until here everything in document coordinates.
1282 234 : x -= nLeftMargin;
1283 :
1284 234 : 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 234 : SwLinePortion *pPor = pCurr->GetFirstPortion();
1289 234 : sal_Int32 nCurrStart = nStart;
1290 234 : bool bHolePortion = false;
1291 234 : bool bLastHyph = false;
1292 :
1293 234 : std::deque<sal_uInt16> *pKanaComp = pCurr->GetpKanaComp();
1294 234 : sal_Int32 nOldIdx = GetInfo().GetIdx();
1295 234 : sal_uInt16 nSpaceIdx = 0;
1296 234 : size_t nKanaIdx = 0;
1297 234 : long nSpaceAdd = pCurr->IsSpaceAdd() ? pCurr->GetLLSpaceAdd( 0 ) : 0;
1298 234 : 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 234 : sal_uInt16 nWidth = pPor->Width();
1304 234 : 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 : sal_uInt16 nWidth30;
1334 234 : if ( pPor->IsPostItsPortion() )
1335 0 : nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
1336 : else
1337 2 : nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
1338 : 30 :
1339 468 : nWidth;
1340 :
1341 480 : while( pPor->GetPortion() && nWidth30 < nX && !pPor->IsBreakPortion() )
1342 : {
1343 12 : nX = nX - nWidth;
1344 12 : nCurrStart = nCurrStart + pPor->GetLen();
1345 12 : bHolePortion = pPor->IsHolePortion();
1346 12 : pPor = pPor->GetPortion();
1347 12 : nWidth = pPor->Width();
1348 12 : 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 12 : if ( pPor->IsPostItsPortion() )
1379 0 : nWidth30 = 30 + pPor->GetViewWidth( GetInfo() ) / 2;
1380 : else
1381 0 : nWidth30 = ! nWidth && pPor->GetLen() && pPor->InToxRefOrFldGrp() ?
1382 : 30 :
1383 24 : nWidth;
1384 12 : if( !pPor->IsFlyPortion() && !pPor->IsMarginPortion() )
1385 12 : bLastHyph = pPor->InHyphGrp();
1386 : }
1387 :
1388 234 : const bool bLastPortion = (0 == pPor->GetPortion());
1389 :
1390 234 : if( nX==nWidth )
1391 : {
1392 164 : SwLinePortion *pNextPor = pPor->GetPortion();
1393 328 : 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 234 : ((SwTxtSizeInfo&)GetInfo()).SetIdx( nOldIdx );
1404 :
1405 234 : sal_Int32 nLength = pPor->GetLen();
1406 :
1407 234 : const bool bFieldInfo = pCMS && pCMS->bFieldInfo;
1408 :
1409 236 : if( bFieldInfo && ( nWidth30 < nX || bRightOver || bLeftOver ||
1410 0 : ( pPor->InNumberGrp() && !pPor->IsFtnNumPortion() ) ||
1411 0 : ( pPor->IsMarginPortion() && nWidth > nX + 30 ) ) )
1412 2 : ((SwCrsrMoveState*)pCMS)->bPosCorr = true;
1413 :
1414 : // #i27615#
1415 234 : if (pCMS)
1416 : {
1417 234 : if( pCMS->bInFrontOfLabel)
1418 : {
1419 0 : if (! (2 * nX < nWidth && pPor->InNumberGrp() &&
1420 0 : !pPor->IsFtnNumPortion()))
1421 0 : pCMS->bInFrontOfLabel = false;
1422 : }
1423 : }
1424 :
1425 : // 7684: We are exactly ended up at ther 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 234 : if( !nLength )
1429 : {
1430 4 : if( pCMS )
1431 : {
1432 4 : if( pPor->IsFlyPortion() && bFieldInfo )
1433 0 : ((SwCrsrMoveState*)pCMS)->bPosCorr = true;
1434 :
1435 4 : if (!bRightOver && nX)
1436 : {
1437 2 : if( pPor->IsFtnNumPortion())
1438 0 : ((SwCrsrMoveState*)pCMS)->bFtnNoInfo = true;
1439 2 : else if (pPor->InNumberGrp() ) // #i23726#
1440 : {
1441 0 : ((SwCrsrMoveState*)pCMS)->nInNumPostionOffset = nX;
1442 0 : ((SwCrsrMoveState*)pCMS)->bInNumPortion = true;
1443 : }
1444 : }
1445 : }
1446 4 : if( !nCurrStart )
1447 4 : 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->InFldGrp() && ((SwFldPortion*)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 230 : if ( 1 == nLength )
1473 : {
1474 224 : if ( nWidth )
1475 : {
1476 : // Else we may not enter the character-supplying frame...
1477 224 : if( !( nChgNode && pPos && pPor->IsFlyCntPortion() ) )
1478 : {
1479 16 : if ( pPor->InFldGrp() ||
1480 4 : ( pPor->IsMultiPortion() &&
1481 0 : ((SwMultiPortion*)pPor)->IsBidi() ) )
1482 : {
1483 4 : sal_uInt16 nHeight = 0;
1484 4 : if( !bFieldInfo )
1485 : {
1486 2 : nHeight = pPor->Height();
1487 2 : if ( !nHeight || nHeight > nWidth )
1488 2 : nHeight = nWidth;
1489 : }
1490 :
1491 4 : if( nWidth - nHeight/2 <= nX &&
1492 0 : ( ! pPor->InFldGrp() ||
1493 0 : !((SwFldPortion*)pPor)->HasFollow() ) )
1494 0 : ++nCurrStart;
1495 : }
1496 8 : else if ( ( !pPor->IsFlyPortion() || ( pPor->GetPortion() &&
1497 0 : !pPor->GetPortion()->IsMarginPortion() &&
1498 0 : !pPor->GetPortion()->IsHolePortion() ) )
1499 8 : && ( nWidth/2 < nX ) &&
1500 4 : ( !bFieldInfo ||
1501 0 : ( pPor->GetPortion() &&
1502 0 : pPor->GetPortion()->IsPostItsPortion() ) )
1503 8 : && ( bRightAllowed || !bLastHyph ))
1504 4 : ++nCurrStart;
1505 :
1506 : // if we want to get the position inside the field, we should not return
1507 8 : if ( !pCMS || !pCMS->pSpecialPos )
1508 6 : return nCurrStart;
1509 : }
1510 : }
1511 : else
1512 : {
1513 0 : if ( pPor->IsPostItsPortion() || pPor->IsBreakPortion() ||
1514 0 : pPor->InToxRefGrp() )
1515 0 : return nCurrStart;
1516 0 : if ( pPor->InFldGrp() )
1517 : {
1518 0 : if( bRightOver && !((SwFldPortion*)pPor)->HasFollow() )
1519 0 : ++nCurrStart;
1520 0 : return nCurrStart;
1521 : }
1522 : }
1523 : }
1524 :
1525 : // Skip space at the end of the line
1526 440 : if( bLastPortion && (pCurr->GetNext() || pFrm->GetFollow() )
1527 224 : && rText[nCurrStart + nLength - 1] == ' ' )
1528 0 : --nLength;
1529 :
1530 448 : if( nWidth > nX ||
1531 320 : ( nWidth == nX && pPor->IsMultiPortion() && ((SwMultiPortion*)pPor)->IsDouble() ) )
1532 : {
1533 64 : 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 ( ( ((SwTxtSizeInfo*)pInf)->IsMulti() &&
1541 0 : ((SwTxtSizeInfo*)pInf)->IsFirstMulti() ) ||
1542 0 : ( ((SwMultiPortion*)pPor)->IsRuby() &&
1543 0 : ((SwMultiPortion*)pPor)->OnTop() ) )
1544 0 : nTmpY += ((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 ( ((SwMultiPortion*)pPor)->IsRuby() &&
1550 0 : ! ((SwMultiPortion*)pPor)->OnTop() )
1551 0 : nTmpY = 0;
1552 :
1553 : SwTxtCursorSave aSave( (SwTxtCursor*)this, (SwMultiPortion*)pPor,
1554 0 : nTmpY, nX, nCurrStart, nSpaceAdd );
1555 :
1556 0 : SwLayoutModeModifier aLayoutModeModifier( *GetInfo().GetOut() );
1557 0 : if ( ((SwMultiPortion*)pPor)->IsBidi() )
1558 : {
1559 0 : const sal_uInt8 nBidiLevel = ((SwBidiPortion*)pPor)->GetLevel();
1560 0 : aLayoutModeModifier.Modify( nBidiLevel % 2 );
1561 : }
1562 :
1563 0 : if( ((SwMultiPortion*)pPor)->HasRotation() )
1564 : {
1565 0 : nTmpY -= nY;
1566 0 : if( !((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( ((SwMultiPortion*)pPor)->HasBrackets() )
1574 : {
1575 0 : const sal_uInt16 nPreWidth = ((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 64 : if( pPor->InTxtGrp() )
1586 : {
1587 : sal_uInt8 nOldProp;
1588 6 : if( GetPropFont() )
1589 : {
1590 0 : ((SwFont*)GetFnt())->SetProportion( GetPropFont() );
1591 0 : nOldProp = GetFnt()->GetPropr();
1592 : }
1593 : else
1594 6 : nOldProp = 0;
1595 : {
1596 6 : SwTxtSizeInfo aSizeInf( GetInfo(), &rText, nCurrStart );
1597 6 : ((SwTxtCursor*)this)->SeekAndChg( aSizeInf );
1598 12 : SwTxtSlot aDiffTxt( &aSizeInf, ((SwTxtPortion*)pPor), false, false );
1599 6 : SwFontSave aSave( aSizeInf, pPor->IsDropPortion() ?
1600 12 : ((SwDropPortion*)pPor)->GetFnt() : NULL );
1601 :
1602 6 : SwParaPortion* pPara = (SwParaPortion*)GetInfo().GetParaPortion();
1603 : OSL_ENSURE( pPara, "No paragraph!" );
1604 :
1605 6 : SwDrawTextInfo aDrawInf( aSizeInf.GetVsh(),
1606 6 : *aSizeInf.GetOut(),
1607 6 : &pPara->GetScriptInfo(),
1608 6 : aSizeInf.GetTxt(),
1609 : aSizeInf.GetIdx(),
1610 18 : pPor->GetLen() );
1611 :
1612 : // Drop portion works like a multi portion, just its parts are not portions
1613 6 : 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 6 : else if( GetInfo().GetFont()->GetLeftBorder() && !pPor->GetJoinBorderWithPrev() )
1638 : {
1639 0 : nX = std::max(0, nX - GetInfo().GetFont()->GetLeftBorderSpace());
1640 : }
1641 :
1642 6 : aDrawInf.SetOfst( nX );
1643 :
1644 6 : if ( nSpaceAdd )
1645 : {
1646 0 : sal_Int32 nCharCnt = 0;
1647 : // #i41860# Thai justified alignemt needs some
1648 : // additional information:
1649 0 : aDrawInf.SetNumberOfBlanks( pPor->InTxtGrp() ?
1650 : static_cast<const SwTxtPortion*>(pPor)->GetSpaceCnt( aSizeInf, nCharCnt ) :
1651 0 : 0 );
1652 : }
1653 :
1654 6 : if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
1655 2 : aDrawInf.SetLen( COMPLETE_STRING );
1656 :
1657 6 : aDrawInf.SetSpace( nSpaceAdd );
1658 6 : aDrawInf.SetFont( aSizeInf.GetFont() );
1659 6 : aDrawInf.SetFrm( pFrm );
1660 6 : aDrawInf.SetSnapToGrid( aSizeInf.SnapToGrid() );
1661 6 : aDrawInf.SetPosMatchesBounds( pCMS && pCMS->bPosMatchesBounds );
1662 :
1663 12 : if ( SW_CJK == aSizeInf.GetFont()->GetActual() &&
1664 6 : pPara->GetScriptInfo().CountCompChg() &&
1665 0 : ! pPor->InFldGrp() )
1666 0 : aDrawInf.SetKanaComp( nKanaComp );
1667 :
1668 6 : nLength = aSizeInf.GetFont()->_GetCrsrOfst( aDrawInf );
1669 :
1670 : // get position inside field portion?
1671 6 : if ( pPor->InFldGrp() && pCMS && pCMS->pSpecialPos )
1672 : {
1673 2 : pCMS->pSpecialPos->nCharOfst = nLength;
1674 2 : nLength = 0;
1675 : }
1676 :
1677 : // set cursor bidi level
1678 6 : if ( pCMS )
1679 : ((SwCrsrMoveState*)pCMS)->nCursorBidiLevel =
1680 6 : aDrawInf.GetCursorBidiLevel();
1681 :
1682 6 : if( bFieldInfo && nLength == pPor->GetLen() &&
1683 0 : ( ! pPor->GetPortion() ||
1684 0 : ! pPor->GetPortion()->IsPostItsPortion() ) )
1685 6 : --nLength;
1686 : }
1687 6 : if( nOldProp )
1688 0 : ((SwFont*)GetFnt())->SetProportion( nOldProp );
1689 : }
1690 : else
1691 : {
1692 116 : if( nChgNode && pPos && pPor->IsFlyCntPortion()
1693 116 : && !( (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 = ( (SwFlyCntPortion*)pPor )->GetFlyFrm();
1699 0 : SwFrm* pLower = pTmp->GetLower();
1700 : bool bChgNode = pLower
1701 0 : && (pLower->IsTxtFrm() || 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 = ((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 : ((SwTxtSizeInfo*)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 58 : nLength = pPor->GetCrsrOfst( nX );
1727 : }
1728 : }
1729 224 : 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 440 : if( nOffset && pPor->GetLen() == nLength && pPor->GetPortion() &&
1735 224 : !pPor->GetPortion()->GetLen() && pPor->GetPortion()->InHyphGrp() )
1736 0 : --nOffset;
1737 :
1738 224 : 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 SwTxtFrm::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 : SwCntntNode &rNode = const_cast<SwCntntNode&>( *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 : SwTxtInfo aInf( const_cast<SwTxtFrm*>(this) );
1784 0 : SwTxtIter aLine( const_cast<SwTxtFrm*>(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 270 : }
1883 :
1884 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|