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