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 <editeng/charscaleitem.hxx>
22 : #include <txtatr.hxx>
23 : #include <sfx2/printer.hxx>
24 : #include <svx/svdobj.hxx>
25 : #include <vcl/window.hxx>
26 : #include <vcl/svapp.hxx>
27 : #include <fmtanchr.hxx>
28 : #include <fmtfsize.hxx>
29 : #include <fmtornt.hxx>
30 : #include <fmtflcnt.hxx>
31 : #include <fmtcntnt.hxx>
32 : #include <fmtftn.hxx>
33 : #include <frmatr.hxx>
34 : #include <frmfmt.hxx>
35 : #include <fmtfld.hxx>
36 : #include <doc.hxx>
37 : #include <IDocumentSettingAccess.hxx>
38 : #include <IDocumentDeviceAccess.hxx>
39 : #include <IDocumentLayoutAccess.hxx>
40 : #include <viewsh.hxx>
41 : #include <rootfrm.hxx>
42 : #include <docary.hxx>
43 : #include <ndtxt.hxx>
44 : #include <dcontact.hxx>
45 : #include <fldbas.hxx>
46 : #include <pam.hxx>
47 : #include <itratr.hxx>
48 : #include <htmltbl.hxx>
49 : #include <swtable.hxx>
50 : #include <redlnitr.hxx>
51 : #include <fmtsrnd.hxx>
52 : #include <itrtxt.hxx>
53 : #include <breakit.hxx>
54 : #include <com/sun/star/i18n/WordType.hpp>
55 : #include <com/sun/star/i18n/ScriptType.hpp>
56 : #include <editeng/lrspitem.hxx>
57 : #include <calbck.hxx>
58 :
59 : using namespace ::com::sun::star::i18n;
60 : using namespace ::com::sun::star;
61 :
62 54472 : void SwAttrIter::Chg( SwTextAttr *pHt )
63 : {
64 : assert(pHt && pFnt && "No attribute of font available for change");
65 54472 : if( pRedln && pRedln->IsOn() )
66 290 : pRedln->ChangeTextAttr( pFnt, *pHt, true );
67 : else
68 54182 : aAttrHandler.PushAndChg( *pHt, *pFnt );
69 54472 : nChgCnt++;
70 54472 : }
71 :
72 15079 : void SwAttrIter::Rst( SwTextAttr *pHt )
73 : {
74 : assert(pHt && pFnt && "No attribute of font available for reset");
75 : // get top from stack after removing pHt
76 15079 : if( pRedln && pRedln->IsOn() )
77 316 : pRedln->ChangeTextAttr( pFnt, *pHt, false );
78 : else
79 14763 : aAttrHandler.PopAndChg( *pHt, *pFnt );
80 15079 : nChgCnt--;
81 15079 : }
82 :
83 370540 : SwAttrIter::~SwAttrIter()
84 : {
85 185270 : delete pRedln;
86 185270 : delete pFnt;
87 185270 : }
88 :
89 : /**
90 : * Returns the attribute for a position
91 : *
92 : * Only if the attribute is exactly at the position @param nPos and
93 : * does not have an EndIndex
94 : *
95 : * We need this function for attributes which should alter formatting without
96 : * changing the content of the string.
97 : * Such "degenerated" attributes are e.g.: fields which retain expanded text and
98 : * line-bound Frames.
99 : * In order to avoid ambiguities between different such attributes, we insert a
100 : * special character at the start of the string, when creating such an attribute.
101 : * The Formatter later on encounters such a special character and retrieves the
102 : * degenerate attribute via GetAttr().
103 : */
104 7081 : SwTextAttr *SwAttrIter::GetAttr( const sal_Int32 nPosition ) const
105 : {
106 7081 : return (m_pTextNode) ? m_pTextNode->GetTextAttrForCharAt(nPosition) : 0;
107 : }
108 :
109 295599 : bool SwAttrIter::SeekAndChgAttrIter( const sal_Int32 nNewPos, OutputDevice* pOut )
110 : {
111 295599 : bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos );
112 295599 : if ( pLastOut.get() != pOut )
113 : {
114 48574 : pLastOut = pOut;
115 48574 : pFnt->SetFntChg( true );
116 48574 : bChg = true;
117 : }
118 295599 : if( bChg )
119 : {
120 : // if the change counter is zero, we know the MagicNo of the wanted font
121 294446 : if ( !nChgCnt && !nPropFont )
122 179546 : pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
123 359092 : aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
124 294446 : pFnt->ChgPhysFnt( pShell, *pOut );
125 : }
126 :
127 295599 : return bChg;
128 : }
129 :
130 0 : bool SwAttrIter::IsSymbol( const sal_Int32 nNewPos )
131 : {
132 0 : Seek( nNewPos );
133 0 : if ( !nChgCnt && !nPropFont )
134 0 : pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
135 0 : aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
136 0 : return pFnt->IsSymbol( pShell );
137 : }
138 :
139 12087 : bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFont )
140 : {
141 12087 : if ( pRedln && pRedln->ExtOn() )
142 0 : pRedln->LeaveExtend( *pFnt, 0 );
143 :
144 : // reset font to its original state
145 12087 : aAttrHandler.Reset();
146 12087 : aAttrHandler.ResetFont( *pFnt );
147 :
148 12087 : nStartIndex = 0;
149 12087 : nEndIndex = 0;
150 12087 : nPos = 0;
151 12087 : nChgCnt = 0;
152 12087 : if( nPropFont )
153 0 : pFnt->SetProportion( nPropFont );
154 12087 : if( pRedln )
155 : {
156 54 : pRedln->Clear( pFnt );
157 54 : if( !bParaFont )
158 54 : nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, USHRT_MAX );
159 : else
160 0 : pRedln->Reset();
161 : }
162 :
163 12087 : if ( pHints && !bParaFont )
164 : {
165 : SwTextAttr *pTextAttr;
166 : // While we've not reached the end of the StartArray && the TextAttribute starts at position 0...
167 6716 : while ( ( nStartIndex < pHints->GetStartCount() ) &&
168 2664 : !((pTextAttr=pHints->GetStart(nStartIndex))->GetStart()) )
169 : {
170 : // open the TextAttributes
171 1332 : Chg( pTextAttr );
172 1332 : nStartIndex++;
173 : }
174 : }
175 :
176 12087 : bool bChg = pFnt->IsFntChg();
177 12087 : if ( pLastOut.get() != pOut )
178 : {
179 11754 : pLastOut = pOut;
180 11754 : pFnt->SetFntChg( true );
181 11754 : bChg = true;
182 : }
183 12087 : if( bChg )
184 : {
185 : // if the application counter is zero, we know the MagicNo of the wanted font
186 12087 : if ( !nChgCnt && !nPropFont )
187 10708 : pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
188 21416 : aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
189 12087 : pFnt->ChgPhysFnt( pShell, *pOut );
190 : }
191 12087 : return bChg;
192 : }
193 :
194 : // AMA: New AttrIter Nov 94
195 107925 : void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
196 : {
197 : SwTextAttr *pTextAttr;
198 :
199 107925 : if ( nStartIndex ) // If attributes have been opened at all ...
200 : {
201 : // Close attributes that are currently open, but stop at nNewPos+1
202 :
203 : // As long as we've not yet reached the end of EndArray and the
204 : // TextAttribute ends before or at the new position ...
205 259232 : while ( ( nEndIndex < pHints->GetEndCount() ) &&
206 134678 : (*(pTextAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
207 : {
208 : // Close the TextAttributes, whoes StartPos were before or at
209 : // the old nPos and are currently open
210 17598 : if (pTextAttr->GetStart() <= nPos) Rst( pTextAttr );
211 17598 : nEndIndex++;
212 : }
213 : }
214 : else // skip the not opended ends
215 : {
216 174678 : while ( (nEndIndex < pHints->GetEndCount()) &&
217 57906 : (*pHints->GetEnd(nEndIndex)->GetAnyEnd() <= nNewPos) )
218 : {
219 7878 : nEndIndex++;
220 : }
221 : }
222 :
223 : // As long as we've not yet reached the end of EndArray and the
224 : // TextAttribute ends before or at the new position ...
225 576157 : while ( ( nStartIndex < pHints->GetStartCount() ) &&
226 296770 : ((pTextAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos) )
227 : {
228 :
229 : // open the TextAttributes, whose ends lie behind the new position
230 63537 : if ( *pTextAttr->GetAnyEnd() > nNewPos ) Chg( pTextAttr );
231 63537 : nStartIndex++;
232 : }
233 :
234 107925 : }
235 :
236 296755 : bool SwAttrIter::Seek( const sal_Int32 nNewPos )
237 : {
238 296755 : if ( pRedln && pRedln->ExtOn() )
239 0 : pRedln->LeaveExtend( *pFnt, nNewPos );
240 :
241 296755 : if( pHints )
242 : {
243 107925 : if( !nNewPos || nNewPos < nPos )
244 : {
245 50023 : if( pRedln )
246 800 : pRedln->Clear( NULL );
247 :
248 : // reset font to its original state
249 50023 : aAttrHandler.Reset();
250 50023 : aAttrHandler.ResetFont( *pFnt );
251 :
252 50023 : if( nPropFont )
253 74 : pFnt->SetProportion( nPropFont );
254 50023 : nStartIndex = 0;
255 50023 : nEndIndex = 0;
256 50023 : nPos = 0;
257 50023 : nChgCnt = 0;
258 :
259 : // Attention!
260 : // resetting the font here makes it necessary to apply any
261 : // changes for extended input directly to the font
262 50023 : if ( pRedln && pRedln->ExtOn() )
263 : {
264 0 : pRedln->UpdateExtFont( *pFnt );
265 0 : ++nChgCnt;
266 : }
267 : }
268 107925 : SeekFwd( nNewPos );
269 : }
270 :
271 296755 : pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) );
272 :
273 296755 : if( pRedln )
274 3773 : nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos );
275 296755 : nPos = nNewPos;
276 :
277 296755 : if( nPropFont )
278 79 : pFnt->SetProportion( nPropFont );
279 :
280 296755 : return pFnt->IsFntChg();
281 : }
282 :
283 88011 : sal_Int32 SwAttrIter::GetNextAttr( ) const
284 : {
285 88011 : sal_Int32 nNext = COMPLETE_STRING;
286 88011 : if( pHints )
287 : {
288 : // are there attribute starts left?
289 48145 : for (size_t i = nStartIndex; i < pHints->GetStartCount(); ++i)
290 : {
291 39121 : SwTextAttr *const pAttr(pHints->GetStart(i));
292 39121 : if (!pAttr->IsFormatIgnoreStart())
293 : {
294 39024 : nNext = pAttr->GetStart();
295 39024 : break;
296 : }
297 : }
298 : // are there attribute ends left?
299 48341 : for (size_t i = nEndIndex; i < pHints->GetEndCount(); ++i)
300 : {
301 46069 : SwTextAttr *const pAttr(pHints->GetEnd(i));
302 46069 : if (!pAttr->IsFormatIgnoreEnd())
303 : {
304 45776 : sal_Int32 const nNextEnd = *pAttr->GetAnyEnd();
305 45776 : nNext = std::min(nNext, nNextEnd); // pick nearest one
306 45776 : break;
307 : }
308 : }
309 : }
310 88011 : if (m_pTextNode!=NULL) {
311 : // TODO: maybe use hints like FieldHints for this instead of looking at the text...
312 88011 : const sal_Int32 l = nNext<m_pTextNode->Len() ? nNext : m_pTextNode->Len();
313 88011 : sal_Int32 p=nPos;
314 88011 : const sal_Unicode* aStr = m_pTextNode->GetText().getStr();
315 39871338 : while (p<l)
316 : {
317 39695618 : sal_Unicode aChar = aStr[p];
318 39695618 : if (aChar < CH_TXT_ATR_FORMELEMENT
319 39695529 : || aChar > CH_TXT_ATR_FIELDEND)
320 : {
321 39695316 : ++p;
322 : }
323 : else
324 : {
325 : break;
326 : }
327 : }
328 88011 : if ((p<l && p>nPos) || nNext<=p)
329 45702 : nNext=p;
330 : else
331 42309 : nNext=p+1;
332 : }
333 88011 : if( pRedln )
334 769 : return pRedln->GetNextRedln( nNext );
335 87242 : return nNext;
336 : }
337 :
338 290 : class SwMinMaxArgs
339 : {
340 : public:
341 : VclPtr<OutputDevice> pOut;
342 : SwViewShell const * pSh;
343 : sal_uLong &rMin;
344 : sal_uLong &rMax;
345 : sal_uLong &rAbsMin;
346 : long nRowWidth;
347 : long nWordWidth;
348 : long nWordAdd;
349 : sal_Int32 nNoLineBreak;
350 290 : SwMinMaxArgs( OutputDevice* pOutI, SwViewShell const * pShI, sal_uLong& rMinI, sal_uLong &rMaxI, sal_uLong &rAbsI )
351 290 : : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI )
352 290 : { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = COMPLETE_STRING; }
353 28 : void Minimum( long nNew ) const { if( (long)rMin < nNew ) rMin = nNew; }
354 9 : void NewWord() { nWordAdd = nWordWidth = 0; }
355 : };
356 :
357 41 : static bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const OUString &rText,
358 : sal_Int32 nIdx, sal_Int32 nEnd )
359 : {
360 41 : bool bRet = false;
361 110 : while( nIdx < nEnd )
362 : {
363 28 : sal_Int32 nStop = nIdx;
364 28 : bool bClear = false;
365 28 : LanguageType eLang = pFnt->GetLanguage();
366 28 : if( g_pBreakIt->GetBreakIter().is() )
367 : {
368 28 : bClear = CH_BLANK == rText[ nStop ];
369 56 : Boundary aBndry( g_pBreakIt->GetBreakIter()->getWordBoundary( rText, nIdx,
370 28 : g_pBreakIt->GetLocale( eLang ),
371 56 : WordType::DICTIONARY_WORD, true ) );
372 28 : nStop = aBndry.endPos;
373 28 : if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
374 1 : rArg.NewWord();
375 28 : if( nStop == nIdx )
376 0 : ++nStop;
377 28 : if( nStop > nEnd )
378 0 : nStop = nEnd;
379 : }
380 : else
381 : {
382 0 : while( nStop < nEnd && CH_BLANK != rText[ nStop ] )
383 0 : ++nStop;
384 0 : bClear = nStop == nIdx;
385 0 : if ( bClear )
386 : {
387 0 : rArg.NewWord();
388 0 : while( nStop < nEnd && CH_BLANK == rText[ nStop ] )
389 0 : ++nStop;
390 : }
391 : }
392 :
393 28 : SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rText, nIdx, nStop - nIdx );
394 28 : long nAktWidth = pFnt->_GetTextSize( aDrawInf ).Width();
395 28 : rArg.nRowWidth += nAktWidth;
396 28 : if( bClear )
397 0 : rArg.NewWord();
398 : else
399 : {
400 28 : rArg.nWordWidth += nAktWidth;
401 28 : if( (long)rArg.rAbsMin < rArg.nWordWidth )
402 28 : rArg.rAbsMin = rArg.nWordWidth;
403 28 : rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
404 28 : bRet = true;
405 : }
406 28 : nIdx = nStop;
407 28 : }
408 41 : return bRet;
409 : }
410 :
411 0 : bool SwTextNode::IsSymbol( const sal_Int32 nBegin ) const
412 : {
413 0 : SwScriptInfo aScriptInfo;
414 0 : SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
415 0 : aIter.Seek( nBegin );
416 : return aIter.GetFnt()->IsSymbol(
417 0 : const_cast<SwViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()) );
418 : }
419 :
420 : class SwMinMaxNodeArgs
421 : {
422 : public:
423 : sal_uLong nMaxWidth; // sum of all frame widths
424 : long nMinWidth; // biggest frame
425 : long nLeftRest; // space not already covered by frames in the left margin
426 : long nRightRest; // space not already covered by frames in the right margin
427 : long nLeftDiff; // Min/Max-difference of the frame in the left margin
428 : long nRightDiff; // Min/Max-difference of the frame in the right margin
429 : sal_uLong nIndx; // index of the node
430 0 : void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
431 : };
432 :
433 3 : static void lcl_MinMaxNode( SwFrameFormat* pNd, SwMinMaxNodeArgs* pIn )
434 : {
435 3 : const SwFormatAnchor& rFormatA = pNd->GetAnchor();
436 :
437 3 : if ((FLY_AT_PARA == rFormatA.GetAnchorId()) ||
438 0 : (FLY_AT_CHAR == rFormatA.GetAnchorId()))
439 : {
440 3 : const SwPosition *pPos = rFormatA.GetContentAnchor();
441 : OSL_ENSURE(pPos && pIn, "Unexpected NULL arguments");
442 3 : if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
443 3 : return;
444 : }
445 :
446 : long nMin, nMax;
447 0 : SwHTMLTableLayout *pLayout = 0;
448 0 : const bool bIsDrawFrameFormat = pNd->Which()==RES_DRAWFRMFMT;
449 0 : if( !bIsDrawFrameFormat )
450 : {
451 : // Does the frame contain a table at the start or the end?
452 0 : const SwNodes& rNodes = pNd->GetDoc()->GetNodes();
453 0 : const SwFormatContent& rFlyContent = pNd->GetContent();
454 0 : sal_uLong nStt = rFlyContent.GetContentIdx()->GetIndex();
455 0 : SwTableNode* pTableNd = rNodes[nStt+1]->GetTableNode();
456 0 : if( !pTableNd )
457 : {
458 0 : SwNode *pNd2 = rNodes[nStt];
459 0 : pNd2 = rNodes[pNd2->EndOfSectionIndex()-1];
460 0 : if( pNd2->IsEndNode() )
461 0 : pTableNd = pNd2->StartOfSectionNode()->GetTableNode();
462 : }
463 :
464 0 : if( pTableNd )
465 0 : pLayout = pTableNd->GetTable().GetHTMLTableLayout();
466 : }
467 :
468 0 : const SwFormatHoriOrient& rOrient = pNd->GetHoriOrient();
469 0 : sal_Int16 eHoriOri = rOrient.GetHoriOrient();
470 :
471 : long nDiff;
472 0 : if( pLayout )
473 : {
474 0 : nMin = pLayout->GetMin();
475 0 : nMax = pLayout->GetMax();
476 0 : nDiff = nMax - nMin;
477 : }
478 : else
479 : {
480 0 : if( bIsDrawFrameFormat )
481 : {
482 0 : const SdrObject* pSObj = pNd->FindSdrObject();
483 0 : if( pSObj )
484 0 : nMin = pSObj->GetCurrentBoundRect().GetWidth();
485 : else
486 0 : nMin = 0;
487 :
488 : }
489 : else
490 : {
491 0 : const SwFormatFrmSize &rSz = pNd->GetFrmSize();
492 0 : nMin = rSz.GetWidth();
493 : }
494 0 : nMax = nMin;
495 0 : nDiff = 0;
496 : }
497 :
498 0 : const SvxLRSpaceItem &rLR = pNd->GetLRSpace();
499 0 : nMin += rLR.GetLeft();
500 0 : nMin += rLR.GetRight();
501 0 : nMax += rLR.GetLeft();
502 0 : nMax += rLR.GetRight();
503 :
504 0 : if( SURROUND_THROUGHT == pNd->GetSurround().GetSurround() )
505 : {
506 0 : pIn->Minimum( nMin );
507 0 : return;
508 : }
509 :
510 : // Frames, which are left- or right-aligned are only party considered
511 : // when calculating the maximum, since the border is already being considered.
512 : // Only if the frame extends into the text body, this part is being added
513 0 : switch( eHoriOri )
514 : {
515 : case text::HoriOrientation::RIGHT:
516 : {
517 0 : if( nDiff )
518 : {
519 0 : pIn->nRightRest -= pIn->nRightDiff;
520 0 : pIn->nRightDiff = nDiff;
521 : }
522 0 : if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
523 : {
524 0 : if( pIn->nRightRest > 0 )
525 0 : pIn->nRightRest = 0;
526 : }
527 0 : pIn->nRightRest -= nMin;
528 0 : break;
529 : }
530 : case text::HoriOrientation::LEFT:
531 : {
532 0 : if( nDiff )
533 : {
534 0 : pIn->nLeftRest -= pIn->nLeftDiff;
535 0 : pIn->nLeftDiff = nDiff;
536 : }
537 0 : if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
538 0 : pIn->nLeftRest < 0 )
539 0 : pIn->nLeftRest = 0;
540 0 : pIn->nLeftRest -= nMin;
541 0 : break;
542 : }
543 : default:
544 : {
545 0 : pIn->nMaxWidth += nMax;
546 0 : pIn->Minimum( nMin );
547 : }
548 : }
549 : }
550 :
551 : #define FLYINCNT_MIN_WIDTH 284
552 :
553 : /**
554 : * Changing this method very likely requires changing of GetScalingOfSelectedText
555 : */
556 290 : void SwTextNode::GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax,
557 : sal_uLong& rAbsMin, OutputDevice* pOut ) const
558 : {
559 290 : SwViewShell const * pSh = GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
560 290 : if( !pOut )
561 : {
562 290 : if( pSh )
563 0 : pOut = pSh->GetWin();
564 290 : if( !pOut )
565 290 : pOut = Application::GetDefaultDevice();
566 : }
567 :
568 290 : MapMode aOldMap( pOut->GetMapMode() );
569 290 : pOut->SetMapMode( MapMode( MAP_TWIP ) );
570 :
571 290 : rMin = 0;
572 290 : rMax = 0;
573 290 : rAbsMin = 0;
574 :
575 290 : const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
576 290 : long nLROffset = rSpace.GetTextLeft() + GetLeftMarginWithNum( true );
577 : short nFLOffs;
578 : // For enumerations a negative first line indentation is probably filled already
579 290 : if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
580 290 : nLROffset = nFLOffs;
581 :
582 : SwMinMaxNodeArgs aNodeArgs;
583 290 : aNodeArgs.nMinWidth = 0;
584 290 : aNodeArgs.nMaxWidth = 0;
585 290 : aNodeArgs.nLeftRest = nLROffset;
586 290 : aNodeArgs.nRightRest = rSpace.GetRight();
587 290 : aNodeArgs.nLeftDiff = 0;
588 290 : aNodeArgs.nRightDiff = 0;
589 290 : if( nIndex )
590 : {
591 290 : SwFrameFormats* pTmp = const_cast<SwFrameFormats*>(GetDoc()->GetSpzFrameFormats());
592 290 : if( pTmp )
593 : {
594 290 : aNodeArgs.nIndx = nIndex;
595 293 : for( SwFrameFormat *pFormat : *pTmp )
596 3 : lcl_MinMaxNode( pFormat, &aNodeArgs );
597 : }
598 : }
599 290 : if( aNodeArgs.nLeftRest < 0 )
600 0 : aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
601 290 : aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
602 290 : if( aNodeArgs.nLeftRest < 0 )
603 0 : aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
604 :
605 290 : if( aNodeArgs.nRightRest < 0 )
606 0 : aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
607 290 : aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
608 290 : if( aNodeArgs.nRightRest < 0 )
609 0 : aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
610 :
611 580 : SwScriptInfo aScriptInfo;
612 580 : SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
613 290 : sal_Int32 nIdx = 0;
614 290 : aIter.SeekAndChgAttrIter( nIdx, pOut );
615 290 : sal_Int32 nLen = m_Text.getLength();
616 290 : long nAktWidth = 0;
617 290 : long nAdd = 0;
618 580 : SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
619 613 : while( nIdx < nLen )
620 : {
621 33 : sal_Int32 nNextChg = aIter.GetNextAttr();
622 33 : sal_Int32 nStop = aScriptInfo.NextScriptChg( nIdx );
623 33 : if( nNextChg > nStop )
624 27 : nNextChg = nStop;
625 33 : SwTextAttr *pHint = NULL;
626 33 : sal_Unicode cChar = CH_BLANK;
627 33 : nStop = nIdx;
628 238 : while( nStop < nLen && nStop < nNextChg &&
629 120 : CH_TAB != ( cChar = m_Text[nStop] ) &&
630 60 : CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
631 145 : CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
632 : !pHint )
633 : {
634 96 : if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
635 60 : || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
636 44 : ++nStop;
637 : }
638 33 : if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
639 : {
640 25 : nAdd = 20;
641 : }
642 33 : nIdx = nStop;
643 33 : aIter.SeekAndChgAttrIter( nIdx, pOut );
644 33 : switch( cChar )
645 : {
646 : case CH_BREAK :
647 : {
648 0 : if( (long)rMax < aArg.nRowWidth )
649 0 : rMax = aArg.nRowWidth;
650 0 : aArg.nRowWidth = 0;
651 0 : aArg.NewWord();
652 0 : aIter.SeekAndChgAttrIter( ++nIdx, pOut );
653 : }
654 0 : break;
655 : case CH_TAB :
656 : {
657 0 : aArg.NewWord();
658 0 : aIter.SeekAndChgAttrIter( ++nIdx, pOut );
659 : }
660 0 : break;
661 : case CHAR_SOFTHYPHEN:
662 0 : ++nIdx;
663 0 : break;
664 : case CHAR_HARDBLANK:
665 : case CHAR_HARDHYPHEN:
666 : {
667 0 : OUString sTmp( cChar );
668 0 : SwDrawTextInfo aDrawInf( getIDocumentLayoutAccess()->GetCurrentViewShell(),
669 0 : *pOut, 0, sTmp, 0, 1, 0, false );
670 0 : nAktWidth = aIter.GetFnt()->_GetTextSize( aDrawInf ).Width();
671 0 : aArg.nWordWidth += nAktWidth;
672 0 : aArg.nRowWidth += nAktWidth;
673 0 : if( (long)rAbsMin < aArg.nWordWidth )
674 0 : rAbsMin = aArg.nWordWidth;
675 0 : aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
676 0 : aArg.nNoLineBreak = nIdx++;
677 : }
678 0 : break;
679 : case CH_TXTATR_BREAKWORD:
680 : case CH_TXTATR_INWORD:
681 : {
682 8 : if( !pHint )
683 0 : break;
684 8 : long nOldWidth = aArg.nWordWidth;
685 8 : long nOldAdd = aArg.nWordAdd;
686 8 : aArg.NewWord();
687 :
688 8 : switch( pHint->Which() )
689 : {
690 : case RES_TXTATR_FLYCNT :
691 : {
692 0 : SwFrameFormat *pFrameFormat = pHint->GetFlyCnt().GetFrameFormat();
693 0 : const SvxLRSpaceItem &rLR = pFrameFormat->GetLRSpace();
694 0 : if( RES_DRAWFRMFMT == pFrameFormat->Which() )
695 : {
696 0 : const SdrObject* pSObj = pFrameFormat->FindSdrObject();
697 0 : if( pSObj )
698 0 : nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
699 : else
700 0 : nAktWidth = 0;
701 : }
702 : else
703 : {
704 0 : const SwFormatFrmSize& rTmpSize = pFrameFormat->GetFrmSize();
705 0 : if( RES_FLYFRMFMT == pFrameFormat->Which()
706 0 : && rTmpSize.GetWidthPercent() )
707 : {
708 : // This is a hack for the wollowing situation: In the paragraph there's a
709 : // text frame with relative size. Then let's take 0.5 cm as minimum width
710 : // and USHRT_MAX as maximum width
711 : // It were cleaner and maybe necessary later on to iterate over the content
712 : // of the text frame and call GetMinMaxSize recursively
713 0 : nAktWidth = FLYINCNT_MIN_WIDTH; // 0.5 cm
714 0 : if( (long)rMax < USHRT_MAX )
715 0 : rMax = USHRT_MAX;
716 : }
717 : else
718 0 : nAktWidth = pFrameFormat->GetFrmSize().GetWidth();
719 : }
720 0 : nAktWidth += rLR.GetLeft();
721 0 : nAktWidth += rLR.GetRight();
722 0 : aArg.nWordAdd = nOldWidth + nOldAdd;
723 0 : aArg.nWordWidth = nAktWidth;
724 0 : aArg.nRowWidth += nAktWidth;
725 0 : if( (long)rAbsMin < aArg.nWordWidth )
726 0 : rAbsMin = aArg.nWordWidth;
727 0 : aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
728 0 : break;
729 : }
730 : case RES_TXTATR_FTN :
731 : {
732 0 : const OUString aText = pHint->GetFootnote().GetNumStr();
733 0 : if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
734 0 : aText.getLength() ) )
735 0 : nAdd = 20;
736 0 : break;
737 : }
738 :
739 : case RES_TXTATR_FIELD :
740 : case RES_TXTATR_ANNOTATION :
741 : {
742 8 : SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
743 8 : const OUString aText = pField->ExpandField(true);
744 8 : if( lcl_MinMaxString( aArg, aIter.GetFnt(), aText, 0,
745 8 : aText.getLength() ) )
746 3 : nAdd = 20;
747 8 : break;
748 : }
749 0 : default: aArg.nWordWidth = nOldWidth;
750 0 : aArg.nWordAdd = nOldAdd;
751 :
752 : }
753 8 : aIter.SeekAndChgAttrIter( ++nIdx, pOut );
754 : }
755 8 : break;
756 : }
757 : }
758 290 : if( (long)rMax < aArg.nRowWidth )
759 28 : rMax = aArg.nRowWidth;
760 :
761 290 : nLROffset += rSpace.GetRight();
762 :
763 290 : rAbsMin += nLROffset;
764 290 : rAbsMin += nAdd;
765 290 : rMin += nLROffset;
766 290 : rMin += nAdd;
767 290 : if( (long)rMin < aNodeArgs.nMinWidth )
768 0 : rMin = aNodeArgs.nMinWidth;
769 290 : if( (long)rAbsMin < aNodeArgs.nMinWidth )
770 0 : rAbsMin = aNodeArgs.nMinWidth;
771 290 : rMax += aNodeArgs.nMaxWidth;
772 290 : rMax += nLROffset;
773 290 : rMax += nAdd;
774 290 : if( rMax < rMin ) // e.g. Frames with flow through only contribute to the minimum
775 0 : rMax = rMin;
776 580 : pOut->SetMapMode( aOldMap );
777 290 : }
778 :
779 : /**
780 : * Calculates the width of the text part specified by nStt and nEnd,
781 : * the height of the line containing nStt is divided by this width,
782 : * indicating the scaling factor, if the text part is rotated.
783 : * Having CH_BREAKs in the text part, this method returns the scaling
784 : * factor for the longest of the text parts separated by the CH_BREAK
785 : *
786 : * Changing this method very likely requires changing of "GetMinMaxSize"
787 : */
788 0 : sal_uInt16 SwTextNode::GetScalingOfSelectedText( sal_Int32 nStt, sal_Int32 nEnd )
789 : const
790 : {
791 0 : SwViewShell const * pSh = GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
792 0 : OutputDevice* pOut = NULL;
793 :
794 0 : if ( pSh )
795 0 : pOut = &pSh->GetRefDev();
796 : else
797 : {
798 : // Access via StarONE, there's no need for an existing or active shell
799 0 : if ( getIDocumentSettingAccess()->get(DocumentSettingId::HTML_MODE) )
800 0 : pOut = Application::GetDefaultDevice();
801 : else
802 0 : pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
803 : }
804 :
805 : OSL_ENSURE( pOut, "GetScalingOfSelectedText without outdev" );
806 :
807 0 : MapMode aOldMap( pOut->GetMapMode() );
808 0 : pOut->SetMapMode( MapMode( MAP_TWIP ) );
809 :
810 0 : if ( nStt == nEnd )
811 : {
812 0 : if ( !g_pBreakIt->GetBreakIter().is() )
813 0 : return 100;
814 :
815 0 : SwScriptInfo aScriptInfo;
816 0 : SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
817 0 : aIter.SeekAndChgAttrIter( nStt, pOut );
818 :
819 : Boundary aBound =
820 0 : g_pBreakIt->GetBreakIter()->getWordBoundary( GetText(), nStt,
821 0 : g_pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
822 0 : WordType::DICTIONARY_WORD, true );
823 :
824 0 : if ( nStt == aBound.startPos )
825 : {
826 : // cursor is at left or right border of word
827 0 : pOut->SetMapMode( aOldMap );
828 0 : return 100;
829 : }
830 :
831 0 : nStt = aBound.startPos;
832 0 : nEnd = aBound.endPos;
833 :
834 0 : if ( nStt == nEnd )
835 : {
836 0 : pOut->SetMapMode( aOldMap );
837 0 : return 100;
838 0 : }
839 : }
840 :
841 0 : SwScriptInfo aScriptInfo;
842 0 : SwAttrIter aIter( *const_cast<SwTextNode*>(this), aScriptInfo );
843 :
844 : // We do not want scaling attributes to be considered during this
845 : // calculation. For this, we push a temporary scaling attribute with
846 : // scaling value 100 and priority flag on top of the scaling stack
847 0 : SwAttrHandler& rAH = aIter.GetAttrHandler();
848 0 : SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
849 0 : SwTextAttrEnd aAttr( aItem, nStt, nEnd );
850 0 : aAttr.SetPriorityAttr( true );
851 0 : rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
852 :
853 0 : sal_Int32 nIdx = nStt;
854 :
855 0 : sal_uLong nWidth = 0;
856 0 : sal_uLong nProWidth = 0;
857 :
858 0 : while( nIdx < nEnd )
859 : {
860 0 : aIter.SeekAndChgAttrIter( nIdx, pOut );
861 :
862 : // scan for end of portion
863 0 : const sal_Int32 nNextChg = std::max(aIter.GetNextAttr(), aScriptInfo.NextScriptChg( nIdx ));
864 :
865 0 : sal_Int32 nStop = nIdx;
866 0 : sal_Unicode cChar = CH_BLANK;
867 0 : SwTextAttr* pHint = NULL;
868 :
869 : // stop at special characters in [ nIdx, nNextChg ]
870 0 : while( nStop < nEnd && nStop < nNextChg )
871 : {
872 0 : cChar = m_Text[nStop];
873 0 : if (
874 0 : CH_TAB == cChar ||
875 0 : CH_BREAK == cChar ||
876 0 : CHAR_HARDBLANK == cChar ||
877 0 : CHAR_HARDHYPHEN == cChar ||
878 0 : CHAR_SOFTHYPHEN == cChar ||
879 : (
880 0 : (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
881 : (0 == (pHint = aIter.GetAttr(nStop)))
882 : )
883 : )
884 : {
885 0 : break;
886 : }
887 : else
888 0 : ++nStop;
889 : }
890 :
891 : // calculate text widths up to cChar
892 0 : if ( nStop > nIdx )
893 : {
894 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetText(), nIdx, nStop - nIdx );
895 0 : nProWidth += aIter.GetFnt()->_GetTextSize( aDrawInf ).Width();
896 : }
897 :
898 0 : nIdx = nStop;
899 0 : aIter.SeekAndChgAttrIter( nIdx, pOut );
900 :
901 0 : if ( cChar == CH_BREAK )
902 : {
903 0 : nWidth = std::max( nWidth, nProWidth );
904 0 : nProWidth = 0;
905 0 : nIdx++;
906 : }
907 0 : else if ( cChar == CH_TAB )
908 : {
909 : // tab receives width of one space
910 0 : OUString sTmp( CH_BLANK );
911 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
912 0 : nProWidth += aIter.GetFnt()->_GetTextSize( aDrawInf ).Width();
913 0 : nIdx++;
914 : }
915 0 : else if ( cChar == CHAR_SOFTHYPHEN )
916 0 : ++nIdx;
917 0 : else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
918 : {
919 0 : OUString sTmp( cChar );
920 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
921 0 : nProWidth += aIter.GetFnt()->_GetTextSize( aDrawInf ).Width();
922 0 : nIdx++;
923 : }
924 0 : else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || cChar == CH_TXTATR_INWORD ) )
925 : {
926 0 : switch( pHint->Which() )
927 : {
928 : case RES_TXTATR_FTN :
929 : {
930 0 : const OUString aText = pHint->GetFootnote().GetNumStr();
931 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aText, 0, aText.getLength() );
932 :
933 0 : nProWidth += aIter.GetFnt()->_GetTextSize( aDrawInf ).Width();
934 0 : break;
935 : }
936 :
937 : case RES_TXTATR_FIELD :
938 : case RES_TXTATR_ANNOTATION :
939 : {
940 0 : SwField *pField = const_cast<SwField*>(pHint->GetFormatField().GetField());
941 0 : OUString const aText = pField->ExpandField(true);
942 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aText, 0, aText.getLength() );
943 :
944 0 : nProWidth += aIter.GetFnt()->_GetTextSize( aDrawInf ).Width();
945 0 : break;
946 : }
947 :
948 : default:
949 : {
950 : // any suggestions for a default action?
951 : }
952 : } // end of switch
953 0 : nIdx++;
954 : } // end of while
955 : }
956 :
957 0 : nWidth = std::max( nWidth, nProWidth );
958 :
959 : // search for a text frame this node belongs to
960 0 : SwIterator<SwTextFrm,SwTextNode> aFrmIter( *this );
961 0 : SwTextFrm* pFrm = 0;
962 0 : for( SwTextFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() )
963 : {
964 0 : if ( pTmpFrm->GetOfst() <= nStt &&
965 0 : ( !pTmpFrm->GetFollow() ||
966 0 : pTmpFrm->GetFollow()->GetOfst() > nStt ) )
967 : {
968 0 : pFrm = pTmpFrm;
969 0 : break;
970 : }
971 : }
972 :
973 : // search for the line containing nStt
974 0 : if ( pFrm && pFrm->HasPara() )
975 : {
976 0 : SwTextInfo aInf( pFrm );
977 0 : SwTextIter aLine( pFrm, &aInf );
978 0 : aLine.CharToLine( nStt );
979 0 : pOut->SetMapMode( aOldMap );
980 : return (sal_uInt16)( nWidth ?
981 0 : ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
982 : }
983 : // no frame or no paragraph, we take the height of the character
984 : // at nStt as line height
985 :
986 0 : aIter.SeekAndChgAttrIter( nStt, pOut );
987 0 : pOut->SetMapMode( aOldMap );
988 :
989 0 : SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetText(), nStt, 1 );
990 : return (sal_uInt16)
991 0 : ( nWidth ? ((100 * aIter.GetFnt()->_GetTextSize( aDrawInf ).Height()) / nWidth ) : 0 );
992 : }
993 :
994 0 : SwTwips SwTextNode::GetWidthOfLeadingTabs() const
995 : {
996 0 : SwTwips nRet = 0;
997 :
998 0 : sal_Int32 nIdx = 0;
999 :
1000 0 : while ( nIdx < GetText().getLength() )
1001 : {
1002 0 : const sal_Unicode cCh = GetText()[nIdx];
1003 0 : if ( cCh!='\t' && cCh!=' ' )
1004 : {
1005 0 : break;
1006 : }
1007 0 : ++nIdx;
1008 : }
1009 :
1010 0 : if ( nIdx > 0 )
1011 : {
1012 0 : SwPosition aPos( *this );
1013 0 : aPos.nContent += nIdx;
1014 :
1015 : // Find the non-follow text frame:
1016 0 : SwIterator<SwTextFrm,SwTextNode> aIter( *this );
1017 0 : for( SwTextFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1018 : {
1019 : // Only consider master frames:
1020 0 : if ( !pFrm->IsFollow() )
1021 : {
1022 0 : SWRECTFN( pFrm )
1023 0 : SwRect aRect;
1024 0 : pFrm->GetCharRect( aRect, aPos );
1025 0 : nRet = pFrm->IsRightToLeft() ?
1026 0 : (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1027 0 : (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)();
1028 0 : break;
1029 : }
1030 0 : }
1031 : }
1032 :
1033 0 : return nRet;
1034 177 : }
1035 :
1036 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|