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