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