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