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