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