1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: impedit3.cxx,v $
10 * $Revision: 1.124.82.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include <eeng_pch.hxx>
35 #include <vcl/metaact.hxx>
36 #include <vcl/gdimtf.hxx>
38 #define _SVSTDARR_USHORTS
39 #include <svtools/svstdarr.hxx>
41 #ifndef _WRKWIN_HXX //autogen
42 #include <vcl/wrkwin.hxx>
45 #include <svx/adjitem.hxx>
46 #include <svx/tstpitem.hxx>
47 #include <svx/lspcitem.hxx>
49 #include <svx/flditem.hxx>
51 #include <impedit.hxx>
52 #include <svx/editeng.hxx>
53 #include <svx/editview.hxx>
54 #include <txtrange.hxx>
55 #include <svx/cscoitem.hxx>
56 #include <svx/colritem.hxx>
57 #include <svx/udlnitem.hxx>
58 #include <svx/fhgtitem.hxx>
59 #include <svx/kernitem.hxx>
60 #include <svx/lrspitem.hxx>
61 #include <svx/ulspitem.hxx>
62 #include <fontitem.hxx>
63 #include <svx/wghtitem.hxx>
64 #include <svx/postitem.hxx>
65 #include <svx/langitem.hxx>
66 #include <svx/scriptspaceitem.hxx>
67 #include <svx/charscaleitem.hxx>
68 #include <svx/numitem.hxx>
70 #include <svtools/colorcfg.hxx>
71 #include <svtools/ctloptions.hxx>
73 #include <forbiddencharacterstable.hxx>
75 #include <unotools/localedatawrapper.hxx>
77 #include <unolingu.hxx>
80 #include <vcl/svapp.hxx>
81 #include <sfx2/sfxuno.hxx>
82 #include <vcl/metric.hxx>
83 #include <com/sun/star/i18n/ScriptType.hpp>
84 #include <com/sun/star/text/CharacterCompressionType.hpp>
85 #include <vcl/pdfextoutdevdata.hxx>
86 #include <i18npool/mslangid.hxx>
88 #include <comphelper/processfactory.hxx>
90 using ::rtl::OUString
;
91 using namespace ::com::sun::star
;
92 using namespace ::com::sun::star::uno
;
93 using namespace ::com::sun::star::beans
;
94 using namespace ::com::sun::star::linguistic2
;
96 SV_DECL_VARARR_SORT( SortedPositions
, sal_uInt32
, 16, 8 )
97 SV_IMPL_VARARR_SORT( SortedPositions
, sal_uInt32
);
103 #define WRONG_SHOW_MIN 5
104 #define WRONG_SHOW_SMALL 11
105 #define WRONG_SHOW_MEDIUM 15
117 TabInfo() { bValid
= FALSE
; }
120 Point
Rotate( const Point
& rPoint
, short nOrientation
, const Point
& rOrigin
)
122 double nRealOrientation
= nOrientation
*F_PI1800
;
123 double nCos
= cos( nRealOrientation
);
124 double nSin
= sin( nRealOrientation
);
127 Point
aTranslatedPos( rPoint
);
130 aTranslatedPos
-= rOrigin
;
133 aRotatedPos
.X() = (long) ( nCos
*aTranslatedPos
.X() + nSin
*aTranslatedPos
.Y() );
134 aRotatedPos
.Y() = (long) - ( nSin
*aTranslatedPos
.X() - nCos
*aTranslatedPos
.Y() );
135 aTranslatedPos
= aRotatedPos
;
138 aTranslatedPos
+= rOrigin
;
139 return aTranslatedPos
;
142 BYTE
GetCharTypeForCompression( xub_Unicode cChar
)
146 case 0x3008: case 0x300A: case 0x300C: case 0x300E:
147 case 0x3010: case 0x3014: case 0x3016: case 0x3018:
148 case 0x301A: case 0x301D:
150 return CHAR_PUNCTUATIONRIGHT
;
152 case 0x3001: case 0x3002: case 0x3009: case 0x300B:
153 case 0x300D: case 0x300F: case 0x3011: case 0x3015:
154 case 0x3017: case 0x3019: case 0x301B: case 0x301E:
157 return CHAR_PUNCTUATIONLEFT
;
161 return ( ( 0x3040 <= cChar
) && ( 0x3100 > cChar
) ) ? CHAR_KANA
: CHAR_NORMAL
;
166 void lcl_DrawRedLines(
167 OutputDevice
* pOutDev
,
172 const sal_Int32
* pDXArray
,
175 const Point
& rOrigin
,
177 BOOL bIsRightToLeft
)
180 // Aber nur, wenn Font nicht zu klein...
181 long nHght
= pOutDev
->LogicToPixel( Size( 0, nFontHeight
) ).Height();
182 if( WRONG_SHOW_MIN
< nHght
)
185 if( WRONG_SHOW_MEDIUM
< nHght
)
186 nStyle
= WAVE_NORMAL
;
187 else if( WRONG_SHOW_SMALL
< nHght
)
192 sal_uInt16 nEnd
, nStart
= nIndex
;
193 sal_Bool bWrong
= pWrongs
->NextWrong( nStart
, nEnd
);
196 if ( nStart
>= nMaxEnd
)
199 if ( nStart
< nIndex
) // Wurde korrigiert
201 if ( nEnd
> nMaxEnd
)
204 if ( bVertical
&& ( nStyle
!= WAVE_FLAT
) )
206 // VCL doesn't know that the text is vertical, and is manipulating
207 // the positions a little bit in y direction...
208 long nOnePixel
= pOutDev
->PixelToLogic( Size( 0, 1 ) ).Height();
209 long nCorrect
= ( nStyle
== WAVE_NORMAL
) ? 2*nOnePixel
: nOnePixel
;
210 aPnt1
.Y() -= nCorrect
;
211 aPnt1
.X() -= nCorrect
;
213 if ( nStart
> nIndex
)
217 // since for RTL portions rPnt is on the visual right end of the portion
218 // (i.e. at the start of the first RTL char) we need to subtract the offset
219 // for RTL portions...
220 aPnt1
.X() += (bIsRightToLeft
? -1 : 1) * pDXArray
[ nStart
- nIndex
- 1 ];
223 aPnt1
.Y() += pDXArray
[ nStart
- nIndex
- 1 ];
226 DBG_ASSERT( nEnd
> nIndex
, "RedLine: aPnt2?" );
229 // since for RTL portions rPnt is on the visual right end of the portion
230 // (i.e. at the start of the first RTL char) we need to subtract the offset
231 // for RTL portions...
232 aPnt2
.X() += (bIsRightToLeft
? -1 : 1) * pDXArray
[ nEnd
- nIndex
- 1 ];
235 aPnt2
.Y() += pDXArray
[ nEnd
- nIndex
- 1 ];
238 aPnt1
= Rotate( aPnt1
, nOrientation
, rOrigin
);
239 aPnt2
= Rotate( aPnt2
, nOrientation
, rOrigin
);
242 pOutDev
->DrawWaveLine( aPnt1
, aPnt2
, nStyle
);
245 if ( nEnd
< nMaxEnd
)
246 bWrong
= pWrongs
->NextWrong( nStart
, nEnd
);
254 Point
lcl_ImplCalcRotatedPos( Point rPos
, Point rOrigin
, double nSin
, double nCos
)
258 Point
aTranslatedPos( rPos
);
259 aTranslatedPos
-= rOrigin
;
261 aRotatedPos
.X() = (long) ( nCos
*aTranslatedPos
.X() + nSin
*aTranslatedPos
.Y() );
262 aRotatedPos
.Y() = (long) - ( nSin
*aTranslatedPos
.X() - nCos
*aTranslatedPos
.Y() );
263 aTranslatedPos
= aRotatedPos
;
265 aTranslatedPos
+= rOrigin
;
267 return aTranslatedPos
;
270 sal_Bool
lcl_IsLigature( xub_Unicode cCh
, xub_Unicode cNextCh
) // For Kashidas from sw/source/core/text/porlay.txt
273 return ( 0x644 == cCh
&& 0x627 == cNextCh
) ||
275 ( 0x628 == cCh
&& 0x631 == cNextCh
);
278 sal_Bool
lcl_ConnectToPrev( xub_Unicode cCh
, xub_Unicode cPrevCh
) // For Kashidas from sw/source/core/text/porlay.txt
280 // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left
281 sal_Bool bRet
= 0x627 != cPrevCh
&& 0x62F != cPrevCh
&& 0x630 != cPrevCh
&&
282 0x631 != cPrevCh
&& 0x632 != cPrevCh
&& 0x648 != cPrevCh
;
284 // check for ligatures cPrevChar + cChar
286 bRet
= ! lcl_IsLigature( cPrevCh
, cCh
);
292 // ----------------------------------------------------------------------
293 // class ImpEditEngine
294 // ----------------------------------------------------------------------
295 void ImpEditEngine::UpdateViews( EditView
* pCurView
)
297 if ( !GetUpdateMode() || IsFormatting() || aInvalidRec
.IsEmpty() )
300 DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" );
302 for ( sal_uInt16 nView
= 0; nView
< aEditViews
.Count(); nView
++ )
304 EditView
* pView
= aEditViews
[nView
];
305 DBG_CHKOBJ( pView
, EditView
, 0 );
308 Rectangle
aClipRec( aInvalidRec
);
309 Rectangle
aVisArea( pView
->GetVisArea() );
310 aClipRec
.Intersection( aVisArea
);
312 if ( !aClipRec
.IsEmpty() )
314 // in Fensterkoordinaten umwandeln....
315 aClipRec
= pView
->pImpEditView
->GetWindowPos( aClipRec
);
317 if ( ( pView
== pCurView
) )
318 Paint( pView
->pImpEditView
, aClipRec
, sal_True
);
320 pView
->GetWindow()->Invalidate( aClipRec
);
326 sal_Bool bGotoCursor
= pCurView
->pImpEditView
->DoAutoScroll();
327 pCurView
->ShowCursor( bGotoCursor
);
330 aInvalidRec
= Rectangle();
334 IMPL_LINK( ImpEditEngine
, OnlineSpellHdl
, Timer
*, EMPTYARG
)
336 if ( !Application::AnyInput( INPUT_KEYBOARD
) && GetUpdateMode() && IsFormatted() )
339 aOnlineSpellTimer
.Start();
344 IMPL_LINK_INLINE_START( ImpEditEngine
, IdleFormatHdl
, Timer
*, EMPTYARG
)
346 aIdleFormatter
.ResetRestarts();
347 FormatAndUpdate( aIdleFormatter
.GetView() );
350 IMPL_LINK_INLINE_END( ImpEditEngine
, IdleFormatHdl
, Timer
*, EMPTYARG
)
352 void ImpEditEngine::CheckIdleFormatter()
354 aIdleFormatter
.ForceTimeout();
355 // Falls kein Idle, aber trotzdem nicht formatiert:
356 if ( !IsFormatted() )
360 void ImpEditEngine::FormatFullDoc()
362 for ( sal_uInt16 nPortion
= 0; nPortion
< GetParaPortions().Count(); nPortion
++ )
363 GetParaPortions()[nPortion
]->MarkSelectionInvalid( 0, GetParaPortions()[nPortion
]->GetNode()->Len() );
367 void ImpEditEngine::FormatDoc()
369 if ( !GetUpdateMode() || IsFormatting() )
372 EnterBlockNotifications();
374 bIsFormatting
= sal_True
;
376 // Dann kann ich auch den Spell-Timer starten...
377 if ( GetStatus().DoOnlineSpelling() )
378 StartOnlineSpellTimer();
381 sal_Bool bGrow
= sal_False
;
383 Font
aOldFont( GetRefDevice()->GetFont() );
385 // Hier schon, damit nicht jedesmal in CreateLines...
386 sal_Bool bMapChanged
= ImpCheckRefMapMode();
388 aInvalidRec
= Rectangle(); // leermachen
389 for ( sal_uInt16 nPara
= 0; nPara
< GetParaPortions().Count(); nPara
++ )
391 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
392 if ( pParaPortion
->MustRepaint() || ( pParaPortion
->IsInvalid() && pParaPortion
->IsVisible() ) )
394 if ( pParaPortion
->IsInvalid() )
396 sal_Bool bChangedByDerivedClass
= GetEditEnginePtr()->FormattingParagraph( nPara
);
397 if ( bChangedByDerivedClass
)
399 pParaPortion
->GetTextPortions().Reset();
400 pParaPortion
->MarkSelectionInvalid( 0, pParaPortion
->GetNode()->Len() );
403 // bei MustRepaint() sollte keine Formatierung noetig sein!
404 // 23.1.95: Evtl. ist sie durch eine andere Aktion aber doch
405 // ungueltig geworden!
406 // if ( pParaPortion->MustRepaint() || CreateLines( nPara ) )
407 if ( ( pParaPortion
->MustRepaint() && !pParaPortion
->IsInvalid() )
408 || CreateLines( nPara
, nY
) )
410 if ( !bGrow
&& GetTextRanger() )
412 // Bei einer Aenderung der Hoehe muss alles weiter unten
413 // neu formatiert werden...
414 for ( sal_uInt16 n
= nPara
+1; n
< GetParaPortions().Count(); n
++ )
416 ParaPortion
* pPP
= GetParaPortions().GetObject( n
);
417 pPP
->MarkSelectionInvalid( 0, pPP
->GetNode()->Len() );
418 pPP
->GetLines().Reset();
422 if ( IsCallParaInsertedOrDeleted() )
423 GetEditEnginePtr()->ParagraphHeightChanged( nPara
);
424 pParaPortion
->SetMustRepaint( sal_False
);
427 // InvalidRec nur einmal setzen...
428 if ( aInvalidRec
.IsEmpty() )
430 // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()...
431 long nWidth
= Max( (long)1, ( !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height() ) );
432 Range
aInvRange( GetInvalidYOffsets( pParaPortion
) );
433 aInvalidRec
= Rectangle( Point( 0, nY
+aInvRange
.Min() ),
434 Size( nWidth
, aInvRange
.Len() ) );
438 aInvalidRec
.Bottom() = nY
+ pParaPortion
->GetHeight();
443 aInvalidRec
.Bottom() = nY
+ pParaPortion
->GetHeight();
445 nY
+= pParaPortion
->GetHeight();
448 // Man kann auch durch UpdateMode An=>AUS=>AN in die Formatierung gelangen...
449 // Optimierung erst nach Vobis-Auslieferung aktivieren...
450 // if ( !aInvalidRec.IsEmpty() )
452 sal_uInt32 nNewHeight
= CalcTextHeight();
453 long nDiff
= nNewHeight
- nCurTextHeight
;
455 aStatus
.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTHEIGHTCHANGED
: EE_STAT_TEXTWIDTHCHANGED
;
456 if ( nNewHeight
< nCurTextHeight
)
458 aInvalidRec
.Bottom() = (long)Max( nNewHeight
, nCurTextHeight
);
459 if ( aInvalidRec
.IsEmpty() )
461 aInvalidRec
.Top() = 0;
462 // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt.
463 aInvalidRec
.Left() = 0;
464 aInvalidRec
.Right() = !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height();
468 nCurTextHeight
= nNewHeight
;
470 if ( aStatus
.AutoPageSize() )
474 for ( sal_uInt16 nView
= 0; nView
< aEditViews
.Count(); nView
++ )
476 EditView
* pView
= aEditViews
[nView
];
477 ImpEditView
* pImpView
= pView
->pImpEditView
;
478 if ( pImpView
->DoAutoHeight() )
480 Size
aSz( pImpView
->GetOutputArea().GetWidth(), nCurTextHeight
);
481 if ( aSz
.Height() > aMaxAutoPaperSize
.Height() )
482 aSz
.Height() = aMaxAutoPaperSize
.Height();
483 else if ( aSz
.Height() < aMinAutoPaperSize
.Height() )
484 aSz
.Height() = aMinAutoPaperSize
.Height();
485 pImpView
->ResetOutputArea( Rectangle(
486 pImpView
->GetOutputArea().TopLeft(), aSz
) );
492 if ( aStatus
.DoRestoreFont() )
493 GetRefDevice()->SetFont( aOldFont
);
494 bIsFormatting
= sal_False
;
495 bFormatted
= sal_True
;
498 GetRefDevice()->Pop();
500 CallStatusHdl(); // Falls Modified...
502 LeaveBlockNotifications();
505 sal_Bool
ImpEditEngine::ImpCheckRefMapMode()
507 sal_Bool bChange
= sal_False
;
509 if ( aStatus
.DoFormat100() )
511 MapMode
aMapMode( GetRefDevice()->GetMapMode() );
512 if ( aMapMode
.GetScaleX().GetNumerator() != aMapMode
.GetScaleX().GetDenominator() )
514 else if ( aMapMode
.GetScaleY().GetNumerator() != aMapMode
.GetScaleY().GetDenominator() )
519 Fraction
Scale1( 1, 1 );
520 aMapMode
.SetScaleX( Scale1
);
521 aMapMode
.SetScaleY( Scale1
);
522 GetRefDevice()->Push();
523 GetRefDevice()->SetMapMode( aMapMode
);
530 void ImpEditEngine::CheckAutoPageSize()
532 Size
aPrevPaperSize( GetPaperSize() );
533 if ( GetStatus().AutoPageWidth() )
534 aPaperSize
.Width() = (long) !IsVertical() ? CalcTextWidth( TRUE
) : GetTextHeight();
535 if ( GetStatus().AutoPageHeight() )
536 aPaperSize
.Height() = (long) !IsVertical() ? GetTextHeight() : CalcTextWidth( TRUE
);
538 SetValidPaperSize( aPaperSize
); //Min, Max beruecksichtigen
540 if ( aPaperSize
!= aPrevPaperSize
)
542 if ( ( !IsVertical() && ( aPaperSize
.Width() != aPrevPaperSize
.Width() ) )
543 || ( IsVertical() && ( aPaperSize
.Height() != aPrevPaperSize
.Height() ) ) )
545 // Falls davor zentriert/rechts oder Tabs...
546 aStatus
.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTWIDTHCHANGED
: EE_STAT_TEXTHEIGHTCHANGED
;
547 for ( sal_uInt16 nPara
= 0; nPara
< GetParaPortions().Count(); nPara
++ )
549 // Es brauchen nur Absaetze neu formatiert werden,
550 // die nicht linksbuendig sind.
551 // Die Hoehe kann sich hier nicht mehr aendern.
552 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
553 ContentNode
* pNode
= pParaPortion
->GetNode();
554 SvxAdjust eJustification
= GetJustification( nPara
);
555 if ( eJustification
!= SVX_ADJUST_LEFT
)
557 pParaPortion
->MarkSelectionInvalid( 0, pNode
->Len() );
558 CreateLines( nPara
, 0 ); // 0: Bei AutoPageSize kein TextRange!
563 Size aInvSize
= aPaperSize
;
564 if ( aPaperSize
.Width() < aPrevPaperSize
.Width() )
565 aInvSize
.Width() = aPrevPaperSize
.Width();
566 if ( aPaperSize
.Height() < aPrevPaperSize
.Height() )
567 aInvSize
.Height() = aPrevPaperSize
.Height();
569 Size
aSz( aInvSize
);
572 aSz
.Width() = aInvSize
.Height();
573 aSz
.Height() = aInvSize
.Width();
575 aInvalidRec
= Rectangle( Point(), aSz
);
578 for ( sal_uInt16 nView
= 0; nView
< aEditViews
.Count(); nView
++ )
580 EditView
* pView
= aEditViews
[nView
];
581 pView
->pImpEditView
->RecalcOutputArea();
586 static sal_Int32
ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight
)
588 return ( nFontHeight
* 12 ) / 10; // + 20%
591 sal_Bool
ImpEditEngine::CreateLines( USHORT nPara
, sal_uInt32 nStartPosY
)
593 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
595 // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False
596 DBG_ASSERT( pParaPortion
->GetNode(), "Portion ohne Node in CreateLines" );
597 DBG_ASSERT( pParaPortion
->IsVisible(), "Unsichtbare Absaetze nicht formatieren!" );
598 DBG_ASSERT( pParaPortion
->IsInvalid(), "CreateLines: Portion nicht invalid!" );
600 BOOL bProcessingEmptyLine
= ( pParaPortion
->GetNode()->Len() == 0 );
601 BOOL bEmptyNodeWithPolygon
= ( pParaPortion
->GetNode()->Len() == 0 ) && GetTextRanger();
603 // ---------------------------------------------------------------
604 // Schnelle Sonderbehandlung fuer leere Absaetze...
605 // ---------------------------------------------------------------
606 if ( ( pParaPortion
->GetNode()->Len() == 0 ) && !GetTextRanger() )
608 // schnelle Sonderbehandlung...
609 if ( pParaPortion
->GetTextPortions().Count() )
610 pParaPortion
->GetTextPortions().Reset();
611 if ( pParaPortion
->GetLines().Count() )
612 pParaPortion
->GetLines().Reset();
613 CreateAndInsertEmptyLine( pParaPortion
, nStartPosY
);
614 return FinishCreateLines( pParaPortion
);
617 // ---------------------------------------------------------------
618 // Initialisierung......
619 // ---------------------------------------------------------------
621 // Immer fuer 100% formatieren:
622 sal_Bool bMapChanged
= ImpCheckRefMapMode();
624 if ( pParaPortion
->GetLines().Count() == 0 )
626 EditLine
* pL
= new EditLine
;
627 pParaPortion
->GetLines().Insert( pL
, 0 );
630 // ---------------------------------------------------------------
631 // Absatzattribute holen......
632 // ---------------------------------------------------------------
633 ContentNode
* const pNode
= pParaPortion
->GetNode();
635 BOOL bRightToLeftPara
= IsRightToLeft( nPara
);
637 SvxAdjust eJustification
= GetJustification( nPara
);
638 sal_Bool bHyphenatePara
= ((const SfxBoolItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_HYPHENATE
)).GetValue();
639 sal_Int32 nSpaceBefore
= 0;
640 sal_Int32 nMinLabelWidth
= 0;
641 sal_Int32 nSpaceBeforeAndMinLabelWidth
= GetSpaceBeforeAndMinLabelWidth( pNode
, &nSpaceBefore
, &nMinLabelWidth
);
642 const SvxLRSpaceItem
& rLRItem
= GetLRSpaceItem( pNode
);
643 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&) pNode
->GetContentAttribs().GetItem( EE_PARA_SBL
);
644 const BOOL bScriptSpace
= ((const SvxScriptSpaceItem
&) pNode
->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING
)).GetValue();
646 // const sal_uInt16 nInvalidEnd = ( pParaPortion->GetInvalidDiff() > 0 )
647 // ? pParaPortion->GetInvalidPosStart() + pParaPortion->GetInvalidDiff()
649 const short nInvalidDiff
= pParaPortion
->GetInvalidDiff();
650 const sal_uInt16 nInvalidStart
= pParaPortion
->GetInvalidPosStart();
651 const sal_uInt16 nInvalidEnd
= nInvalidStart
+ Abs( nInvalidDiff
);
653 sal_Bool bQuickFormat
= sal_False
;
654 if ( !bEmptyNodeWithPolygon
&& !HasScriptType( nPara
, i18n::ScriptType::COMPLEX
) )
656 if ( ( pParaPortion
->IsSimpleInvalid() ) && ( nInvalidDiff
> 0 ) &&
657 ( pNode
->Search( CH_FEATURE
, nInvalidStart
) > nInvalidEnd
) )
659 bQuickFormat
= sal_True
;
661 else if ( ( pParaPortion
->IsSimpleInvalid() ) && ( nInvalidDiff
< 0 ) )
663 // pruefen, ob loeschen ueber Portiongrenzen erfolgte...
664 sal_uInt16 nStart
= nInvalidStart
; // DOPPELT !!!!!!!!!!!!!!!
665 sal_uInt16 nEnd
= nStart
- nInvalidDiff
; // neg.
666 bQuickFormat
= sal_True
;
668 sal_uInt16 nPortions
= pParaPortion
->GetTextPortions().Count();
669 for ( sal_uInt16 nTP
= 0; nTP
< nPortions
; nTP
++ )
671 // Es darf kein Start/Ende im geloeschten Bereich liegen.
672 TextPortion
* const pTP
= pParaPortion
->GetTextPortions()[ nTP
];
673 nPos
= nPos
+ pTP
->GetLen();
674 if ( ( nPos
> nStart
) && ( nPos
< nEnd
) )
676 bQuickFormat
= sal_False
;
683 // SW disables TEXT_LAYOUT_COMPLEX_DISABLED, so maybe I have to enable it...
685 // #114278# Saving both layout mode and language (since I'm
686 // potentially changing both)
688 GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE
|PUSH_TEXTLANGUAGE
);
690 ImplInitLayoutMode( GetRefDevice(), nPara
, 0xFFFF );
692 sal_uInt16 nRealInvalidStart
= nInvalidStart
;
694 if ( bEmptyNodeWithPolygon
)
696 TextPortion
* pDummyPortion
= new TextPortion( 0 );
697 pParaPortion
->GetTextPortions().Reset();
698 pParaPortion
->GetTextPortions().Insert( pDummyPortion
, 0 );
700 else if ( bQuickFormat
)
702 // schnellere Methode:
703 RecalcTextPortion( pParaPortion
, nInvalidStart
, nInvalidDiff
);
705 else // nRealInvalidStart kann vor InvalidStart liegen, weil Portions geloescht....
707 CreateTextPortions( pParaPortion
, nRealInvalidStart
);
711 // ---------------------------------------------------------------
712 // Zeile mit InvalidPos suchen, eine Zeile davor beginnen...
713 // Zeilen flaggen => nicht removen !
714 // ---------------------------------------------------------------
716 sal_uInt16 nLine
= pParaPortion
->GetLines().Count()-1;
717 for ( sal_uInt16 nL
= 0; nL
<= nLine
; nL
++ )
719 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nL
);
720 if ( pLine
->GetEnd() > nRealInvalidStart
) // nicht nInvalidStart!
727 // Eine Zeile davor beginnen...
728 // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern.
729 if ( nLine
&& ( !pParaPortion
->IsSimpleInvalid() || ( nInvalidEnd
< pNode
->Len() ) || ( nInvalidDiff
<= 0 ) ) )
732 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nLine
);
734 static Rectangle aZeroArea
= Rectangle( Point(), Point() );
735 Rectangle
aBulletArea( aZeroArea
);
738 aBulletArea
= GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion
) );
739 if ( aBulletArea
.Right() > 0 )
740 pParaPortion
->SetBulletX( (sal_uInt16
) GetXValue( aBulletArea
.Right() ) );
742 pParaPortion
->SetBulletX( 0 ); // Falls Bullet falsch eingestellt.
745 // ---------------------------------------------------------------
746 // Ab hier alle Zeilen durchformatieren...
747 // ---------------------------------------------------------------
748 sal_uInt16 nDelFromLine
= 0xFFFF;
749 sal_Bool bLineBreak
= sal_False
;
751 sal_uInt16 nIndex
= pLine
->GetStart();
752 EditLine
aSaveLine( *pLine
);
753 SvxFont
aTmpFont( pNode
->GetCharAttribs().GetDefFont() );
755 sal_Bool bCalcCharPositions
= sal_True
;
756 sal_Int32
* pBuf
= new sal_Int32
[ pNode
->Len() ];
758 sal_Bool bSameLineAgain
= sal_False
; // Fuer TextRanger, wenn sich die Hoehe aendert.
761 BOOL bForceOneRun
= bEmptyNodeWithPolygon
;
762 BOOL bCompressedChars
= FALSE
;
764 while ( ( nIndex
< pNode
->Len() ) || bForceOneRun
)
766 bForceOneRun
= FALSE
;
768 sal_Bool bEOL
= sal_False
;
769 sal_Bool bEOC
= sal_False
;
770 sal_uInt16 nPortionStart
= 0;
771 sal_uInt16 nPortionEnd
= 0;
773 long nStartX
= GetXValue( rLRItem
.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth
);
776 long nFI
= GetXValue( rLRItem
.GetTxtFirstLineOfst() );
779 if ( !nLine
&& ( pParaPortion
->GetBulletX() > nStartX
) )
781 // TL_NFLR nStartX += nFI; // Vielleicht reicht der LI?
782 // TL_NFLR if ( pParaPortion->GetBulletX() > nStartX )
783 nStartX
= pParaPortion
->GetBulletX();
789 nMaxLineWidth
= aStatus
.AutoPageWidth() ? aMaxAutoPaperSize
.Width() : aPaperSize
.Width();
791 nMaxLineWidth
= aStatus
.AutoPageHeight() ? aMaxAutoPaperSize
.Height() : aPaperSize
.Height();
793 nMaxLineWidth
-= GetXValue( rLRItem
.GetRight() );
794 nMaxLineWidth
-= nStartX
;
796 // Wenn PaperSize == long_max, kann ich keinen neg. Erstzeileneinzug
797 // abziehen (Overflow)
798 if ( ( nMaxLineWidth
< 0 ) && ( nStartX
< 0 ) )
799 nMaxLineWidth
= ( !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height() ) - GetXValue( rLRItem
.GetRight() );
801 // Wenn jetzt noch kleiner 0, kann es nur der rechte Rand sein.
802 if ( nMaxLineWidth
<= 0 )
805 // Problem: Da eine Zeile _vor_ der ungueltigen Position mit der
806 // Formatierung begonnen wird, werden hier leider auch die Positionen
809 // Die Zeile davor kann nur groesser werden, nicht kleiner
811 if ( bCalcCharPositions
)
812 pLine
->GetCharPosArray().Remove( 0, pLine
->GetCharPosArray().Count() );
814 sal_uInt16 nTmpPos
= nIndex
;
815 sal_uInt16 nTmpPortion
= pLine
->GetStartPortion();
817 long nXWidth
= nMaxLineWidth
;
818 if ( nXWidth
<= nTmpWidth
) // while muss 1x durchlaufen werden
819 nXWidth
= nTmpWidth
+1;
821 SvLongsPtr pTextRanges
= 0;
822 long nTextExtraYOffset
= 0;
823 long nTextXOffset
= 0;
824 long nTextLineHeight
= 0;
825 if ( GetTextRanger() )
827 GetTextRanger()->SetVertical( IsVertical() );
829 long nTextY
= nStartPosY
+ GetEditCursor( pParaPortion
, pLine
->GetStart() ).Top();
830 if ( !bSameLineAgain
)
832 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
833 aTmpFont
.SetPhysFont( GetRefDevice() );
834 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
836 if ( IsFixedCellHeight() )
837 nTextLineHeight
= ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
839 nTextLineHeight
= aTmpFont
.GetPhysTxtSize( GetRefDevice(), String() ).Height();
840 // Metriken koennen groesser sein
841 FormatterFontMetric aTempFormatterMetrics
;
842 RecalcFormatterFontMetrics( aTempFormatterMetrics
, aTmpFont
);
843 sal_uInt16 nLineHeight
= aTempFormatterMetrics
.GetHeight();
844 if ( nLineHeight
> nTextLineHeight
)
845 nTextLineHeight
= nLineHeight
;
848 nTextLineHeight
= pLine
->GetHeight();
853 long nYOff
= nTextY
+ nTextExtraYOffset
;
854 long nYDiff
= nTextLineHeight
;
857 long nMaxPolygonX
= GetTextRanger()->GetBoundRect().Right();
858 nYOff
= nMaxPolygonX
-nYOff
;
859 nYDiff
= -nTextLineHeight
;
861 pTextRanges
= GetTextRanger()->GetTextRanges( Range( nYOff
, nYOff
+ nYDiff
) );
862 DBG_ASSERT( pTextRanges
, "GetTextRanges?!" );
863 long nMaxRangeWidth
= 0;
864 // Den breitesten Bereich verwenden...
865 // Der breiteste Bereich koennte etwas verwirren, also
866 // generell den ersten. Am besten mal richtig mit Luecken.
867 // for ( sal_uInt16 n = 0; n < pTextRanges->Count(); )
868 if ( pTextRanges
->Count() )
871 long nA
= pTextRanges
->GetObject( n
++ );
872 long nB
= pTextRanges
->GetObject( n
++ );
873 DBG_ASSERT( nA
<= nB
, "TextRange verdreht?" );
875 if ( nW
> nMaxRangeWidth
)
881 nXWidth
= nMaxRangeWidth
;
883 nMaxLineWidth
= nXWidth
- nStartX
- GetXValue( rLRItem
.GetRight() );
886 // Weiter unten im Polygon versuchen.
887 // Unterhalb des Polygons die Paperbreite verwenden.
888 nTextExtraYOffset
+= Max( (long)(nTextLineHeight
/ 10), (long)1 );
889 if ( ( nTextY
+ nTextExtraYOffset
) > GetTextRanger()->GetBoundRect().Bottom() )
891 nXWidth
= !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height();
892 if ( !nXWidth
) // AutoPaperSize
893 nXWidth
= 0x7FFFFFFF;
899 // Portion suchen, die nicht mehr in Zeile passt....
900 TextPortion
* pPortion
= 0;
901 sal_Bool bBrokenLine
= sal_False
;
902 bLineBreak
= sal_False
;
903 EditCharAttrib
* pNextFeature
= pNode
->GetCharAttribs().FindFeature( pLine
->GetStart() );
904 while ( ( nTmpWidth
< nXWidth
) && !bEOL
&& ( nTmpPortion
< pParaPortion
->GetTextPortions().Count() ) )
906 nPortionStart
= nTmpPos
;
907 pPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
908 if ( pPortion
->GetKind() == PORTIONKIND_HYPHENATOR
)
910 // Portion wegschmeissen, ggf. die davor korrigieren, wenn
911 // die Hyph-Portion ein Zeichen geschluckt hat...
912 pParaPortion
->GetTextPortions().Remove( nTmpPortion
);
913 if ( nTmpPortion
&& pPortion
->GetLen() )
916 TextPortion
* pPrev
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
917 DBG_ASSERT( pPrev
->GetKind() == PORTIONKIND_TEXT
, "Portion?!" );
918 nTmpWidth
-= pPrev
->GetSize().Width();
919 nTmpPos
= nTmpPos
- pPrev
->GetLen();
920 pPrev
->SetLen( pPrev
->GetLen() + pPortion
->GetLen() );
921 pPrev
->GetSize().Width() = (-1);
924 DBG_ASSERT( nTmpPortion
< pParaPortion
->GetTextPortions().Count(), "Keine Portion mehr da!" );
925 pPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
927 DBG_ASSERT( pPortion
->GetKind() != PORTIONKIND_HYPHENATOR
, "CreateLines: Hyphenator-Portion!" );
928 DBG_ASSERT( pPortion
->GetLen() || bProcessingEmptyLine
, "Leere Portion in CreateLines ?!" );
929 if ( pNextFeature
&& ( pNextFeature
->GetStart() == nTmpPos
) )
931 sal_uInt16 nWhich
= pNextFeature
->GetItem()->Which();
936 long nOldTmpWidth
= nTmpWidth
;
939 long nCurPos
= nTmpWidth
+nStartX
;
940 // nCurPos -= rLRItem.GetTxtLeft(); // Tabs relativ zu LI
941 // Skalierung rausrechnen
942 if ( aStatus
.DoStretch() && ( nStretchX
!= 100 ) )
943 nCurPos
= nCurPos
*100/std::max(static_cast<sal_Int32
>(nStretchX
), static_cast<sal_Int32
>(1));
945 short nAllSpaceBeforeText
= static_cast< short >(rLRItem
.GetTxtLeft()/* + rLRItem.GetTxtLeft()*/ + nSpaceBeforeAndMinLabelWidth
);
946 aCurrentTab
.aTabStop
= pNode
->GetContentAttribs().FindTabStop( nCurPos
- nAllSpaceBeforeText
/*rLRItem.GetTxtLeft()*/, aEditDoc
.GetDefTab() );
947 aCurrentTab
.nTabPos
= GetXValue( (long) ( aCurrentTab
.aTabStop
.GetTabPos() + nAllSpaceBeforeText
/*rLRItem.GetTxtLeft()*/ ) );
948 aCurrentTab
.bValid
= FALSE
;
950 // Switch direction in R2L para...
951 if ( bRightToLeftPara
)
953 if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_RIGHT
)
954 aCurrentTab
.aTabStop
.GetAdjustment() = SVX_TAB_ADJUST_LEFT
;
955 else if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_LEFT
)
956 aCurrentTab
.aTabStop
.GetAdjustment() = SVX_TAB_ADJUST_RIGHT
;
959 if ( ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_RIGHT
) ||
960 ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_CENTER
) ||
961 ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL
) )
963 // Bei LEFT/DEFAULT wird dieses Tab nicht mehr betrachtet.
964 aCurrentTab
.bValid
= TRUE
;
965 aCurrentTab
.nStartPosX
= nTmpWidth
;
966 aCurrentTab
.nCharPos
= nTmpPos
;
967 aCurrentTab
.nTabPortion
= nTmpPortion
;
970 pPortion
->GetKind() = PORTIONKIND_TAB
;
971 pPortion
->SetExtraValue( aCurrentTab
.aTabStop
.GetFill() );
972 pPortion
->GetSize().Width() = aCurrentTab
.nTabPos
- (nTmpWidth
+nStartX
);
974 // #90520# Height needed...
975 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
976 pPortion
->GetSize().Height() = aTmpFont
.QuickGetTextSize( GetRefDevice(), String(), 0, 0, NULL
).Height();
978 DBG_ASSERT( pPortion
->GetSize().Width() >= 0, "Tab falsch berechnet!" );
980 nTmpWidth
= aCurrentTab
.nTabPos
-nStartX
;
982 // Wenn dies das erste Token in der Zeile ist,
983 // und nTmpWidth > aPaperSize.Width, habe ich eine
985 if ( ( nTmpWidth
>= nXWidth
) && ( nTmpPortion
== pLine
->GetStartPortion() ) )
988 // Tab passend machen
989 pPortion
->GetSize().Width() = nXWidth
-nOldTmpWidth
;
990 nTmpWidth
= nXWidth
-1;
992 bBrokenLine
= sal_True
;
994 pLine
->GetCharPosArray().Insert( pPortion
->GetSize().Width(), nTmpPos
-pLine
->GetStart() );
995 bCompressedChars
= FALSE
;
998 case EE_FEATURE_LINEBR
:
1000 DBG_ASSERT( pPortion
, "?!" );
1001 pPortion
->GetSize().Width() = 0;
1003 bLineBreak
= sal_True
;
1004 pPortion
->GetKind() = PORTIONKIND_LINEBREAK
;
1005 bCompressedChars
= FALSE
;
1006 pLine
->GetCharPosArray().Insert( pPortion
->GetSize().Width(), nTmpPos
-pLine
->GetStart() );
1009 case EE_FEATURE_FIELD
:
1011 // long nCurWidth = nTmpWidth;
1012 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
1013 sal_Unicode cChar
= 0; // later: NBS?
1014 aTmpFont
.SetPhysFont( GetRefDevice() );
1015 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
1017 String aFieldValue
= cChar
? String(cChar
) : ((EditCharAttribField
*)pNextFeature
)->GetFieldValue();
1018 if ( bCalcCharPositions
|| !pPortion
->HasValidSize() )
1020 pPortion
->GetSize() = aTmpFont
.QuickGetTextSize( GetRefDevice(), aFieldValue
, 0, aFieldValue
.Len(), 0 );
1021 // Damit kein Scrollen bei ueberlangen Feldern
1022 if ( pPortion
->GetSize().Width() > nXWidth
)
1023 pPortion
->GetSize().Width() = nXWidth
;
1025 nTmpWidth
+= pPortion
->GetSize().Width();
1026 pLine
->GetCharPosArray().Insert( pPortion
->GetSize().Width(), nTmpPos
-pLine
->GetStart() );
1027 pPortion
->GetKind() = cChar
? PORTIONKIND_TEXT
: PORTIONKIND_FIELD
;
1028 // Wenn dies das erste Token in der Zeile ist,
1029 // und nTmpWidth > aPaperSize.Width, habe ich eine
1031 if ( ( nTmpWidth
>= nXWidth
) && ( nTmpPortion
== pLine
->GetStartPortion() ) )
1033 nTmpWidth
= nXWidth
-1;
1035 bBrokenLine
= sal_True
;
1037 // Compression in Fields????
1038 // I think this could be a little bit difficult and is not very usefull
1039 bCompressedChars
= FALSE
;
1042 default: DBG_ERROR( "Was fuer ein Feature ?" );
1044 pNextFeature
= pNode
->GetCharAttribs().FindFeature( pNextFeature
->GetStart() + 1 );
1048 DBG_ASSERT( pPortion
->GetLen() || bProcessingEmptyLine
, "Empty Portion - Extra Space?!" );
1049 SeekCursor( pNode
, nTmpPos
+1, aTmpFont
);
1050 aTmpFont
.SetPhysFont( GetRefDevice() );
1051 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
1053 if ( bCalcCharPositions
|| !pPortion
->HasValidSize() )
1055 pPortion
->GetSize() = aTmpFont
.QuickGetTextSize( GetRefDevice(), *pParaPortion
->GetNode(), nTmpPos
, pPortion
->GetLen(), pBuf
);
1057 // #i9050# Do Kerning also behind portions...
1058 if ( ( aTmpFont
.GetFixKerning() > 0 ) && ( ( nTmpPos
+ pPortion
->GetLen() ) < pNode
->Len() ) )
1059 pPortion
->GetSize().Width() += aTmpFont
.GetFixKerning();
1060 if ( IsFixedCellHeight() )
1061 pPortion
->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
1063 if ( bCalcCharPositions
)
1065 sal_uInt16 nLen
= pPortion
->GetLen();
1066 // Es wird am Anfang generell das Array geplaettet
1067 // => Immer einfach schnelles insert.
1068 sal_uInt16 nPos
= nTmpPos
- pLine
->GetStart();
1069 pLine
->GetCharPosArray().Insert( pBuf
, nLen
, nPos
);
1072 // And now check for Compression:
1073 if ( pPortion
->GetLen() && GetAsianCompressionMode() )
1074 bCompressedChars
|= ImplCalcAsianCompression( pNode
, pPortion
, nTmpPos
, (sal_Int32
*)pLine
->GetCharPosArray().GetData() + (nTmpPos
-pLine
->GetStart()), 10000, FALSE
);
1076 nTmpWidth
+= pPortion
->GetSize().Width();
1078 pPortion
->SetRightToLeft( GetRightToLeft( nPara
, nTmpPos
+1 ) );
1080 USHORT _nPortionEnd
= nTmpPos
+ pPortion
->GetLen();
1081 if( bScriptSpace
&& ( _nPortionEnd
< pNode
->Len() ) && ( nTmpWidth
< nXWidth
) && IsScriptChange( EditPaM( pNode
, _nPortionEnd
) ) )
1083 BOOL bAllow
= FALSE
;
1084 USHORT nScriptTypeLeft
= GetScriptType( EditPaM( pNode
, _nPortionEnd
) );
1085 USHORT nScriptTypeRight
= GetScriptType( EditPaM( pNode
, _nPortionEnd
+1 ) );
1086 if ( ( nScriptTypeLeft
== i18n::ScriptType::ASIAN
) || ( nScriptTypeRight
== i18n::ScriptType::ASIAN
) )
1089 // No spacing within L2R/R2L nesting
1092 long nExtraSpace
= pPortion
->GetSize().Height()/5;
1093 nExtraSpace
= GetXValue( nExtraSpace
);
1094 pPortion
->GetSize().Width() += nExtraSpace
;
1095 nTmpWidth
+= nExtraSpace
;
1100 if ( aCurrentTab
.bValid
&& ( nTmpPortion
!= aCurrentTab
.nTabPortion
) )
1102 long nWidthAfterTab
= 0;
1103 for ( USHORT n
= aCurrentTab
.nTabPortion
+1; n
<= nTmpPortion
; n
++ )
1105 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( n
);
1106 nWidthAfterTab
+= pTP
->GetSize().Width();
1108 long nW
= nWidthAfterTab
; // Length before tab position
1109 if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_RIGHT
)
1111 // nW = nWidthAfterTab;
1113 else if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_CENTER
)
1115 nW
= nWidthAfterTab
/2;
1117 else if ( aCurrentTab
.aTabStop
.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL
)
1119 // nW = nWidthAfterTab;
1120 String aText
= GetSelected( EditSelection( EditPaM( pParaPortion
->GetNode(), nTmpPos
),
1121 EditPaM( pParaPortion
->GetNode(), nTmpPos
+ pPortion
->GetLen() ) ) );
1122 USHORT nDecPos
= aText
.Search( aCurrentTab
.aTabStop
.GetDecimal() );
1123 if ( nDecPos
!= STRING_NOTFOUND
)
1125 nW
-= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
)->GetSize().Width();
1126 nW
+= aTmpFont
.QuickGetTextSize( GetRefDevice(), *pParaPortion
->GetNode(), nTmpPos
, nDecPos
, NULL
).Width();
1127 aCurrentTab
.bValid
= FALSE
;
1132 DBG_ERROR( "CreateLines: Tab not handled!" );
1134 long nMaxW
= aCurrentTab
.nTabPos
- aCurrentTab
.nStartPosX
- nStartX
;
1138 aCurrentTab
.bValid
= FALSE
;
1140 TextPortion
* pTabPortion
= pParaPortion
->GetTextPortions().GetObject( aCurrentTab
.nTabPortion
);
1141 pTabPortion
->GetSize().Width() = aCurrentTab
.nTabPos
- aCurrentTab
.nStartPosX
- nW
- nStartX
;
1142 nTmpWidth
= aCurrentTab
.nStartPosX
+ pTabPortion
->GetSize().Width() + nWidthAfterTab
;
1145 nTmpPos
= nTmpPos
+ pPortion
->GetLen();
1146 nPortionEnd
= nTmpPos
;
1148 if ( aStatus
.OneCharPerLine() )
1152 DBG_ASSERT( pPortion
, "no portion!?" );
1154 aCurrentTab
.bValid
= FALSE
;
1156 // das war evtl. eine Portion zu weit:
1157 sal_Bool bFixedEnd
= sal_False
;
1158 if ( aStatus
.OneCharPerLine() )
1160 // Zustand vor Portion: ( bis auf nTmpWidth )
1161 nPortionEnd
= nTmpPos
;
1162 nTmpPos
-= pPortion
? pPortion
->GetLen() : 0;
1163 nPortionStart
= nTmpPos
;
1169 // Und jetzt genau ein Zeichen:
1172 nPortionEnd
= nTmpPortion
;
1173 // Eine Nicht-Feature-Portion muss gebrochen werden
1174 if ( pPortion
->GetLen() > 1 )
1176 DBG_ASSERT( pPortion
&& (pPortion
->GetKind() == PORTIONKIND_TEXT
), "Len>1, aber keine TextPortion?" );
1177 nTmpWidth
-= pPortion
? pPortion
->GetSize().Width() : 0;
1178 sal_uInt16 nP
= SplitTextPortion( pParaPortion
, nTmpPos
, pLine
);
1179 TextPortion
* p
= pParaPortion
->GetTextPortions().GetObject( nP
);
1180 DBG_ASSERT( p
, "Portion ?!" );
1181 nTmpWidth
+= p
->GetSize().Width();
1184 else if ( nTmpWidth
>= nXWidth
)
1186 nPortionEnd
= nTmpPos
;
1187 nTmpPos
-= pPortion
? pPortion
->GetLen() : 0;
1188 nPortionStart
= nTmpPos
;
1192 if( pPortion
) switch ( pPortion
->GetKind() )
1194 case PORTIONKIND_TEXT
:
1196 nTmpWidth
-= pPortion
->GetSize().Width();
1199 case PORTIONKIND_FIELD
:
1200 case PORTIONKIND_TAB
:
1202 nTmpWidth
-= pPortion
->GetSize().Width();
1204 bFixedEnd
= sal_True
;
1209 // Ein Feature wird nicht umgebrochen:
1210 DBG_ASSERT( ( pPortion
->GetKind() == PORTIONKIND_LINEBREAK
), "Was fuer ein Feature ?" );
1212 bFixedEnd
= sal_True
;
1220 pLine
->SetEnd( nPortionEnd
);
1221 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "Keine TextPortions?" );
1222 pLine
->SetEndPortion( (sal_uInt16
)pParaPortion
->GetTextPortions().Count() - 1 );
1225 if ( aStatus
.OneCharPerLine() )
1227 pLine
->SetEnd( nPortionEnd
);
1228 pLine
->SetEndPortion( nTmpPortion
-1 );
1230 else if ( bFixedEnd
)
1232 pLine
->SetEnd( nPortionStart
);
1233 pLine
->SetEndPortion( nTmpPortion
-1 );
1235 else if ( bLineBreak
|| bBrokenLine
)
1237 pLine
->SetEnd( nPortionStart
+1 );
1238 pLine
->SetEndPortion( nTmpPortion
-1 );
1239 bEOC
= sal_False
; // wurde oben gesetzt, vielleich mal die if's umstellen?
1243 DBG_ASSERT( pPortion
&& ((nPortionEnd
-nPortionStart
) == pPortion
->GetLen()), "Doch eine andere Portion?!" );
1244 long nRemainingWidth
= nMaxLineWidth
- nTmpWidth
;
1245 sal_Bool bCanHyphenate
= ( aTmpFont
.GetCharSet() != RTL_TEXTENCODING_SYMBOL
);
1246 if ( bCompressedChars
&& pPortion
&& ( pPortion
->GetLen() > 1 ) && pPortion
->GetExtraInfos() && pPortion
->GetExtraInfos()->bCompressed
)
1248 // I need the manipulated DXArray for determining the break postion...
1249 ImplCalcAsianCompression( pNode
, pPortion
, nPortionStart
, const_cast<sal_Int32
*>(( pLine
->GetCharPosArray().GetData() + (nPortionStart
-pLine
->GetStart()) )), 10000, TRUE
);
1252 ImpBreakLine( pParaPortion
, pLine
, pPortion
, nPortionStart
,
1253 nRemainingWidth
, bCanHyphenate
&& bHyphenatePara
);
1256 // ------------------------------------------------------------------
1257 // Zeile fertig => justieren
1258 // ------------------------------------------------------------------
1260 // CalcTextSize sollte besser durch ein kontinuierliches
1261 // Registrieren ersetzt werden !
1262 Size aTextSize
= pLine
->CalcTextSize( *pParaPortion
);
1264 if ( aTextSize
.Height() == 0 )
1266 SeekCursor( pNode
, pLine
->GetStart()+1, aTmpFont
);
1267 aTmpFont
.SetPhysFont( pRefDev
);
1268 ImplInitDigitMode( pRefDev
, 0, 0, 0, aTmpFont
.GetLanguage() );
1270 if ( IsFixedCellHeight() )
1271 aTextSize
.Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
1273 aTextSize
.Height() = aTmpFont
.GetPhysTxtSize( pRefDev
, String() ).Height();
1274 pLine
->SetHeight( (sal_uInt16
)aTextSize
.Height() );
1277 // Die Fontmetriken koennen nicht kontinuierlich berechnet werden,
1278 // wenn der Font sowieso eingestellt ist, weil ggf. ein grosser Font
1279 // erst nach dem Umbrechen ploetzlich in der naechsten Zeile landet
1280 // => Font-Metriken zu gross.
1281 FormatterFontMetric aFormatterMetrics
;
1282 sal_uInt16 nTPos
= pLine
->GetStart();
1283 for ( sal_uInt16 nP
= pLine
->GetStartPortion(); nP
<= pLine
->GetEndPortion(); nP
++ )
1285 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( nP
);
1286 // #95819# problem with hard font height attribute, when everthing but the line break has this attribute
1287 if ( pTP
->GetKind() != PORTIONKIND_LINEBREAK
)
1289 SeekCursor( pNode
, nTPos
+1, aTmpFont
);
1290 aTmpFont
.SetPhysFont( GetRefDevice() );
1291 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
1292 RecalcFormatterFontMetrics( aFormatterMetrics
, aTmpFont
);
1294 nTPos
= nTPos
+ pTP
->GetLen();
1296 sal_uInt16 nLineHeight
= aFormatterMetrics
.GetHeight();
1297 if ( nLineHeight
> pLine
->GetHeight() )
1298 pLine
->SetHeight( nLineHeight
);
1299 pLine
->SetMaxAscent( aFormatterMetrics
.nMaxAscent
);
1301 bSameLineAgain
= sal_False
;
1302 if ( GetTextRanger() && ( pLine
->GetHeight() > nTextLineHeight
) )
1304 // Nochmal mit der anderen Groesse aufsetzen!
1305 bSameLineAgain
= sal_True
;
1309 if ( !bSameLineAgain
&& !aStatus
.IsOutliner() )
1311 if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_MIN
)
1313 sal_uInt16 nMinHeight
= GetYValue( rLSItem
.GetLineHeight() );
1314 sal_uInt16 nTxtHeight
= pLine
->GetHeight();
1315 if ( nTxtHeight
< nMinHeight
)
1317 // Der Ascent muss um die Differenz angepasst werden:
1318 long nDiff
= nMinHeight
- nTxtHeight
;
1319 pLine
->SetMaxAscent( (sal_uInt16
)(pLine
->GetMaxAscent() + nDiff
) );
1320 pLine
->SetHeight( nMinHeight
, nTxtHeight
);
1323 else if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_FIX
)
1325 sal_uInt16 nFixHeight
= GetYValue( rLSItem
.GetLineHeight() );
1326 sal_uInt16 nTxtHeight
= pLine
->GetHeight();
1327 pLine
->SetMaxAscent( (sal_uInt16
)(pLine
->GetMaxAscent() + ( nFixHeight
- nTxtHeight
) ) );
1328 pLine
->SetHeight( nFixHeight
, nTxtHeight
);
1330 else if ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP
)
1332 if ( nPara
|| IsFixedCellHeight() || pLine
->GetStartPortion() ) // Nicht die aller erste Zeile
1334 // #100508# There are documents with PropLineSpace 0, why?
1335 // (cmc: re above question :-) such documents can be seen by importing a .ppt
1336 if ( rLSItem
.GetPropLineSpace() && ( rLSItem
.GetPropLineSpace() != 100 ) )
1338 sal_uInt16 nTxtHeight
= pLine
->GetHeight();
1339 sal_Int32 nH
= nTxtHeight
;
1340 nH
*= rLSItem
.GetPropLineSpace();
1342 // Der Ascent muss um die Differenz angepasst werden:
1343 long nDiff
= pLine
->GetHeight() - nH
;
1344 if ( nDiff
> pLine
->GetMaxAscent() )
1345 nDiff
= pLine
->GetMaxAscent();
1346 pLine
->SetMaxAscent( (sal_uInt16
)(pLine
->GetMaxAscent() - nDiff
) );
1347 pLine
->SetHeight( (sal_uInt16
)nH
, nTxtHeight
);
1354 // #80582# - Bullet should not influence line height
1357 // long nBulletHeight = aBulletArea.GetHeight();
1358 // if ( nBulletHeight > (long)pLine->GetHeight() )
1360 // long nDiff = nBulletHeight - (long)pLine->GetHeight();
1361 // // nDiff auf oben und unten verteilen.
1362 // pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff/2) );
1363 // pLine->SetHeight( (sal_uInt16)nBulletHeight );
1367 if ( ( !IsVertical() && aStatus
.AutoPageWidth() ) ||
1368 ( IsVertical() && aStatus
.AutoPageHeight() ) )
1370 // Wenn die Zeile in die aktuelle Papierbreite passt, muss
1371 // diese Breite fuer die Ausrichting verwendet werden.
1372 // Wenn sie nicht passt oder sie die Papierbreite aendert,
1373 // wird bei Justification != LEFT sowieso noch mal formatiert.
1374 long nMaxLineWidthFix
= ( !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height() )
1375 - GetXValue( rLRItem
.GetRight() ) - nStartX
;
1376 if ( aTextSize
.Width() < nMaxLineWidthFix
)
1377 nMaxLineWidth
= nMaxLineWidthFix
;
1380 if ( bCompressedChars
)
1382 long nRemainingWidth
= nMaxLineWidth
- aTextSize
.Width();
1383 if ( nRemainingWidth
> 0 )
1385 ImplExpandCompressedPortions( pLine
, pParaPortion
, nRemainingWidth
);
1386 aTextSize
= pLine
->CalcTextSize( *pParaPortion
);
1390 if ( pLine
->IsHangingPunctuation() )
1392 // Width from HangingPunctuation was set to 0 in ImpBreakLine,
1393 // check for rel width now, maybe create compression...
1394 long n
= nMaxLineWidth
- aTextSize
.Width();
1395 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( pLine
->GetEndPortion() );
1396 sal_uInt16 nPosInArray
= pLine
->GetEnd()-1-pLine
->GetStart();
1397 long nNewValue
= ( nPosInArray
? pLine
->GetCharPosArray()[ nPosInArray
-1 ] : 0 ) + n
;
1398 pLine
->GetCharPosArray()[ nPosInArray
] = nNewValue
;
1399 pTP
->GetSize().Width() += n
;
1402 pLine
->SetTextWidth( aTextSize
.Width() );
1403 switch ( eJustification
)
1405 case SVX_ADJUST_CENTER
:
1407 long n
= ( nMaxLineWidth
- aTextSize
.Width() ) / 2;
1408 n
+= nStartX
; // Einrueckung bleibt erhalten.
1410 pLine
->SetStartPosX( (sal_uInt16
)n
);
1412 pLine
->SetStartPosX( 0 );
1416 case SVX_ADJUST_RIGHT
:
1418 // Bei automatisch umgebrochenen Zeilen, die ein Blank
1419 // am Ende enthalten, darf das Blank nicht ausgegeben werden!
1421 long n
= nMaxLineWidth
- aTextSize
.Width();
1422 n
+= nStartX
; // Einrueckung bleibt erhalten.
1424 pLine
->SetStartPosX( (sal_uInt16
)n
);
1426 pLine
->SetStartPosX( 0 );
1429 case SVX_ADJUST_BLOCK
:
1431 long nRemainingSpace
= nMaxLineWidth
- aTextSize
.Width();
1432 pLine
->SetStartPosX( (sal_uInt16
)nStartX
);
1433 if ( !bEOC
&& ( nRemainingSpace
> 0 ) ) // nicht die letzte Zeile...
1434 ImpAdjustBlocks( pParaPortion
, pLine
, nRemainingSpace
);
1439 pLine
->SetStartPosX( (sal_uInt16
)nStartX
); // FI, LI
1444 // -----------------------------------------------------------------
1445 // pruefen, ob die Zeile neu ausgegeben werden muss...
1446 // -----------------------------------------------------------------
1447 pLine
->SetInvalid();
1449 // Wenn eine Portion umgebrochen wurde sind ggf. viel zu viele Positionen
1451 if ( bCalcCharPositions
)
1453 sal_uInt16 nLen
= pLine
->GetLen();
1454 sal_uInt16 nCount
= pLine
->GetCharPosArray().Count();
1455 if ( nCount
> nLen
)
1456 pLine
->GetCharPosArray().Remove( nLen
, nCount
-nLen
);
1459 if ( GetTextRanger() )
1462 pLine
->SetStartPosX( (sal_uInt16
) ( pLine
->GetStartPosX() + nTextXOffset
) );
1463 if ( nTextExtraYOffset
)
1465 pLine
->SetHeight( (sal_uInt16
) ( pLine
->GetHeight() + nTextExtraYOffset
), 0, pLine
->GetHeight() );
1466 pLine
->SetMaxAscent( (sal_uInt16
) ( pLine
->GetMaxAscent() + nTextExtraYOffset
) );
1470 // Fuer kleiner 0 noch ueberlegen!
1471 if ( pParaPortion
->IsSimpleInvalid() /* && ( nInvalidDiff > 0 ) */ )
1473 // Aenderung durch einfache Textaenderung...
1474 // Formatierung nicht abbrechen, da Portions evtl. wieder
1475 // gesplittet werden muessen!
1476 // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren!
1477 // Aber ggf. als Valid markieren, damit weniger Ausgabe...
1478 if ( pLine
->GetEnd() < nInvalidStart
)
1480 if ( *pLine
== aSaveLine
)
1487 sal_uInt16 nStart
= pLine
->GetStart();
1488 sal_uInt16 nEnd
= pLine
->GetEnd();
1490 if ( nStart
> nInvalidEnd
)
1492 if ( ( ( nStart
-nInvalidDiff
) == aSaveLine
.GetStart() ) &&
1493 ( ( nEnd
-nInvalidDiff
) == aSaveLine
.GetEnd() ) )
1496 if ( bCalcCharPositions
&& bQuickFormat
)
1498 bCalcCharPositions
= sal_False
;
1499 bLineBreak
= sal_False
;
1500 pParaPortion
->CorrectValuesBehindLastFormattedLine( nLine
);
1505 else if ( bCalcCharPositions
&& bQuickFormat
&& ( nEnd
> nInvalidEnd
) )
1507 // Wenn die ungueltige Zeile so endet, dass die naechste an
1508 // der 'gleichen' Textstelle wie vorher beginnt, also nicht
1509 // anders umgebrochen wird, brauche ich dort auch nicht die
1510 // textbreiten neu bestimmen:
1511 if ( nEnd
== ( aSaveLine
.GetEnd() + nInvalidDiff
) )
1513 bCalcCharPositions
= sal_False
;
1514 bLineBreak
= sal_False
;
1515 pParaPortion
->CorrectValuesBehindLastFormattedLine( nLine
);
1522 if ( !bSameLineAgain
)
1524 nIndex
= pLine
->GetEnd(); // naechste Zeile Start = letzte Zeile Ende
1525 // weil nEnd hinter das letzte Zeichen zeigt!
1527 sal_uInt16 nEndPortion
= pLine
->GetEndPortion();
1529 // Naechste Zeile oder ggf. neue Zeile....
1531 if ( nLine
< pParaPortion
->GetLines().Count()-1 )
1532 pLine
= pParaPortion
->GetLines().GetObject( ++nLine
);
1533 if ( pLine
&& ( nIndex
>= pNode
->Len() ) )
1535 nDelFromLine
= nLine
;
1540 if ( nIndex
< pNode
->Len() )
1542 pLine
= new EditLine
;
1543 pParaPortion
->GetLines().Insert( pLine
, ++nLine
);
1545 else if ( nIndex
&& bLineBreak
&& GetTextRanger() )
1547 // normaly CreateAndInsertEmptyLine would be called, but I want to use
1548 // CreateLines, so I need Polygon code only here...
1549 TextPortion
* pDummyPortion
= new TextPortion( 0 );
1550 pParaPortion
->GetTextPortions().Insert( pDummyPortion
, pParaPortion
->GetTextPortions().Count() );
1551 pLine
= new EditLine
;
1552 pParaPortion
->GetLines().Insert( pLine
, ++nLine
);
1553 bForceOneRun
= TRUE
;
1554 bProcessingEmptyLine
= TRUE
;
1560 pLine
->SetStart( nIndex
);
1561 pLine
->SetEnd( nIndex
);
1562 pLine
->SetStartPortion( nEndPortion
+1 );
1563 pLine
->SetEndPortion( nEndPortion
+1 );
1566 } // while ( Index < Len )
1568 if ( nDelFromLine
!= 0xFFFF )
1569 pParaPortion
->GetLines().DeleteFromLine( nDelFromLine
);
1571 DBG_ASSERT( pParaPortion
->GetLines().Count(), "Keine Zeile nach CreateLines!" );
1573 if ( bLineBreak
== sal_True
)
1574 CreateAndInsertEmptyLine( pParaPortion
, nStartPosY
);
1578 sal_Bool bHeightChanged
= FinishCreateLines( pParaPortion
);
1581 GetRefDevice()->Pop();
1583 GetRefDevice()->Pop();
1585 return bHeightChanged
;
1588 void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion
* pParaPortion
, sal_uInt32
)
1590 DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" );
1592 EditLine
* pTmpLine
= new EditLine
;
1593 pTmpLine
->SetStart( pParaPortion
->GetNode()->Len() );
1594 pTmpLine
->SetEnd( pParaPortion
->GetNode()->Len() );
1595 pParaPortion
->GetLines().Insert( pTmpLine
, pParaPortion
->GetLines().Count() );
1597 sal_Bool bLineBreak
= pParaPortion
->GetNode()->Len() ? sal_True
: sal_False
;
1598 sal_Int32 nSpaceBefore
= 0;
1599 sal_Int32 nSpaceBeforeAndMinLabelWidth
= GetSpaceBeforeAndMinLabelWidth( pParaPortion
->GetNode(), &nSpaceBefore
);
1600 const SvxLRSpaceItem
& rLRItem
= GetLRSpaceItem( pParaPortion
->GetNode() );
1601 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&)pParaPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
1602 short nStartX
= GetXValue( (short)(rLRItem
.GetTxtLeft() + rLRItem
.GetTxtFirstLineOfst() + nSpaceBefore
));
1604 Rectangle aBulletArea
= Rectangle( Point(), Point() );
1605 if ( bLineBreak
== sal_True
)
1607 nStartX
= (short)GetXValue( rLRItem
.GetTxtLeft() + rLRItem
.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth
);
1611 aBulletArea
= GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion
) );
1612 if ( aBulletArea
.Right() > 0 )
1613 pParaPortion
->SetBulletX( (sal_uInt16
) GetXValue( aBulletArea
.Right() ) );
1615 pParaPortion
->SetBulletX( 0 ); // Falls Bullet falsch eingestellt.
1616 if ( pParaPortion
->GetBulletX() > nStartX
)
1618 nStartX
= (short)GetXValue( rLRItem
.GetTxtLeft() + rLRItem
.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth
);
1619 if ( pParaPortion
->GetBulletX() > nStartX
)
1620 nStartX
= pParaPortion
->GetBulletX();
1625 SeekCursor( pParaPortion
->GetNode(), bLineBreak
? pParaPortion
->GetNode()->Len() : 0, aTmpFont
);
1626 aTmpFont
.SetPhysFont( pRefDev
);
1628 TextPortion
* pDummyPortion
= new TextPortion( 0 );
1629 pDummyPortion
->GetSize() = aTmpFont
.GetPhysTxtSize( pRefDev
, String() );
1630 if ( IsFixedCellHeight() )
1631 pDummyPortion
->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont
.GetHeight() );
1632 pParaPortion
->GetTextPortions().Insert( pDummyPortion
, pParaPortion
->GetTextPortions().Count() );
1633 FormatterFontMetric aFormatterMetrics
;
1634 RecalcFormatterFontMetrics( aFormatterMetrics
, aTmpFont
);
1635 pTmpLine
->SetMaxAscent( aFormatterMetrics
.nMaxAscent
);
1636 pTmpLine
->SetHeight( (sal_uInt16
) pDummyPortion
->GetSize().Height() );
1637 sal_uInt16 nLineHeight
= aFormatterMetrics
.GetHeight();
1638 if ( nLineHeight
> pTmpLine
->GetHeight() )
1639 pTmpLine
->SetHeight( nLineHeight
);
1641 if ( !aStatus
.IsOutliner() )
1643 USHORT nPara
= GetParaPortions().GetPos( pParaPortion
);
1644 SvxAdjust eJustification
= GetJustification( nPara
);
1645 long nMaxLineWidth
= !IsVertical() ? aPaperSize
.Width() : aPaperSize
.Height();
1646 nMaxLineWidth
-= GetXValue( rLRItem
.GetRight() );
1647 long nTextXOffset
= 0;
1648 if ( nMaxLineWidth
< 0 )
1650 if ( eJustification
== SVX_ADJUST_CENTER
)
1651 nStartX
= sal::static_int_cast
< short >(nMaxLineWidth
/ 2);
1652 else if ( eJustification
== SVX_ADJUST_RIGHT
)
1653 nStartX
= sal::static_int_cast
< short >(nMaxLineWidth
);
1655 nStartX
= sal::static_int_cast
< short >(nStartX
+ nTextXOffset
);
1658 pTmpLine
->SetStartPosX( nStartX
);
1660 if ( !aStatus
.IsOutliner() )
1662 if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_MIN
)
1664 sal_uInt16 nMinHeight
= rLSItem
.GetLineHeight();
1665 sal_uInt16 nTxtHeight
= pTmpLine
->GetHeight();
1666 if ( nTxtHeight
< nMinHeight
)
1668 // Der Ascent muss um die Differenz angepasst werden:
1669 long nDiff
= nMinHeight
- nTxtHeight
;
1670 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() + nDiff
) );
1671 pTmpLine
->SetHeight( nMinHeight
, nTxtHeight
);
1674 else if ( rLSItem
.GetLineSpaceRule() == SVX_LINE_SPACE_FIX
)
1676 sal_uInt16 nFixHeight
= rLSItem
.GetLineHeight();
1677 sal_uInt16 nTxtHeight
= pTmpLine
->GetHeight();
1679 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() + ( nFixHeight
- nTxtHeight
) ) );
1680 pTmpLine
->SetHeight( nFixHeight
, nTxtHeight
);
1682 else if ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP
)
1684 USHORT nPara
= GetParaPortions().GetPos( pParaPortion
);
1685 if ( nPara
|| IsFixedCellHeight() || pTmpLine
->GetStartPortion() ) // Nicht die aller erste Zeile
1687 // #100508# There are documents with PropLineSpace 0, why?
1688 // (cmc: re above question :-) such documents can be seen by importing a .ppt
1689 if ( rLSItem
.GetPropLineSpace() && ( rLSItem
.GetPropLineSpace() != 100 ) )
1691 sal_uInt16 nTxtHeight
= pTmpLine
->GetHeight();
1692 sal_Int32 nH
= nTxtHeight
;
1693 nH
*= rLSItem
.GetPropLineSpace();
1695 // Der Ascent muss um die Differenz angepasst werden:
1696 long nDiff
= pTmpLine
->GetHeight() - nH
;
1697 if ( nDiff
> pTmpLine
->GetMaxAscent() )
1698 nDiff
= pTmpLine
->GetMaxAscent();
1699 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() - nDiff
) );
1700 pTmpLine
->SetHeight( (sal_uInt16
)nH
, nTxtHeight
);
1708 long nMinHeight
= aBulletArea
.GetHeight();
1709 if ( nMinHeight
> (long)pTmpLine
->GetHeight() )
1711 long nDiff
= nMinHeight
- (long)pTmpLine
->GetHeight();
1712 // nDiff auf oben und unten verteilen.
1713 pTmpLine
->SetMaxAscent( (sal_uInt16
)(pTmpLine
->GetMaxAscent() + nDiff
/2) );
1714 pTmpLine
->SetHeight( (sal_uInt16
)nMinHeight
);
1719 // -2: Die neue ist bereits eingefuegt.
1721 EditLine
* pLastLine
= pParaPortion
->GetLines().GetObject( pParaPortion
->GetLines().Count()-2 );
1722 DBG_ASSERT( pLastLine
, "Weicher Umbruch, keine Zeile ?!" );
1723 DBG_ASSERT( pLastLine
->GetEnd() == pParaPortion
->GetNode()->Len(), "Doch anders?" );
1725 // pTmpLine->SetStart( pLastLine->GetEnd() );
1726 // pTmpLine->SetEnd( pLastLine->GetEnd() );
1727 sal_uInt16 nPos
= (sal_uInt16
) pParaPortion
->GetTextPortions().Count() - 1 ;
1728 pTmpLine
->SetStartPortion( nPos
);
1729 pTmpLine
->SetEndPortion( nPos
);
1733 sal_Bool
ImpEditEngine::FinishCreateLines( ParaPortion
* pParaPortion
)
1735 // CalcCharPositions( pParaPortion );
1736 pParaPortion
->SetValid();
1737 long nOldHeight
= pParaPortion
->GetHeight();
1738 // sal_uInt16 nPos = GetParaPortions().GetPos( pParaPortion );
1739 // DBG_ASSERT( nPos != USHRT_MAX, "FinishCreateLines: Portion nicht in Liste!" );
1740 // ParaPortion* pPrev = nPos ? GetParaPortions().GetObject( nPos-1 ) : 0;
1741 CalcHeight( pParaPortion
);
1743 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "FinishCreateLines: Keine Text-Portion?" );
1744 sal_Bool bRet
= ( pParaPortion
->GetHeight() != nOldHeight
);
1748 void ImpEditEngine::ImpBreakLine( ParaPortion
* pParaPortion
, EditLine
* pLine
, TextPortion
* pPortion
, sal_uInt16 nPortionStart
, long nRemainingWidth
, sal_Bool bCanHyphenate
)
1750 ContentNode
* const pNode
= pParaPortion
->GetNode();
1752 sal_uInt16 nBreakInLine
= nPortionStart
- pLine
->GetStart();
1753 sal_uInt16 nMax
= nBreakInLine
+ pPortion
->GetLen();
1754 while ( ( nBreakInLine
< nMax
) && ( pLine
->GetCharPosArray()[nBreakInLine
] < nRemainingWidth
) )
1757 sal_uInt16 nMaxBreakPos
= nBreakInLine
+ pLine
->GetStart();
1758 sal_uInt16 nBreakPos
= 0xFFFF;
1760 sal_Bool bCompressBlank
= sal_False
;
1761 sal_Bool bHyphenated
= sal_False
;
1762 sal_Bool bHangingPunctuation
= sal_False
;
1763 sal_Unicode cAlternateReplChar
= 0;
1764 sal_Unicode cAlternateExtraChar
= 0;
1766 if ( ( nMaxBreakPos
< ( nMax
+ pLine
->GetStart() ) ) && ( pNode
->GetChar( nMaxBreakPos
) == ' ' ) )
1768 // Break behind the blank, blank will be compressed...
1769 nBreakPos
= nMaxBreakPos
+ 1;
1770 bCompressBlank
= sal_True
;
1774 sal_uInt16 nMinBreakPos
= pLine
->GetStart();
1775 USHORT nAttrs
= pNode
->GetCharAttribs().GetAttribs().Count();
1776 for ( USHORT nAttr
= nAttrs
; nAttr
; )
1778 EditCharAttrib
* pAttr
= pNode
->GetCharAttribs().GetAttribs()[--nAttr
];
1779 if ( pAttr
->IsFeature() && ( pAttr
->GetEnd() > nMinBreakPos
) && ( pAttr
->GetEnd() <= nMaxBreakPos
) )
1781 nMinBreakPos
= pAttr
->GetEnd();
1786 lang::Locale aLocale
= GetLocale( EditPaM( pNode
, nMaxBreakPos
) );
1788 Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1789 OUString
aText( *pNode
);
1790 Reference
< XHyphenator
> xHyph
;
1791 if ( bCanHyphenate
)
1792 xHyph
= GetHyphenator();
1793 i18n::LineBreakHyphenationOptions
aHyphOptions( xHyph
, Sequence
< PropertyValue
>(), 1 );
1794 i18n::LineBreakUserOptions aUserOptions
;
1796 const i18n::ForbiddenCharacters
* pForbidden
= GetForbiddenCharsTable()->GetForbiddenCharacters( SvxLocaleToLanguage( aLocale
), TRUE
);
1797 aUserOptions
.forbiddenBeginCharacters
= pForbidden
->beginLine
;
1798 aUserOptions
.forbiddenEndCharacters
= pForbidden
->endLine
;
1799 aUserOptions
.applyForbiddenRules
= ((const SfxBoolItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_FORBIDDENRULES
)).GetValue();
1800 aUserOptions
.allowPunctuationOutsideMargin
= ((const SfxBoolItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_HANGINGPUNCTUATION
)).GetValue();
1801 aUserOptions
.allowHyphenateEnglish
= FALSE
;
1803 i18n::LineBreakResults aLBR
= _xBI
->getLineBreak( *pNode
, nMaxBreakPos
, aLocale
, nMinBreakPos
, aHyphOptions
, aUserOptions
);
1804 nBreakPos
= (USHORT
)aLBR
.breakIndex
;
1806 // BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos
1807 if ( nBreakPos
< nMinBreakPos
)
1809 nBreakPos
= nMinBreakPos
;
1811 else if ( ( nBreakPos
> nMaxBreakPos
) && !aUserOptions
.allowPunctuationOutsideMargin
)
1813 DBG_ERROR( "I18N: XBreakIterator::getLineBreak returns position > Max" );
1814 nBreakPos
= nMaxBreakPos
;
1817 // #101795# nBreakPos can never be outside the portion, even not with hangig punctuation
1818 if ( nBreakPos
> nMaxBreakPos
)
1819 nBreakPos
= nMaxBreakPos
;
1821 // BUG in I18N - the japanese dot is in the next line!
1822 // !!! Testen!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1823 if ( (nBreakPos
+ ( aUserOptions
.allowPunctuationOutsideMargin
? 0 : 1 ) ) <= nMaxBreakPos
)
1825 sal_Unicode cFirstInNextLine
= ( (nBreakPos
+1) < pNode
->Len() ) ? pNode
->GetChar( nBreakPos
) : 0;
1826 if ( cFirstInNextLine
== 12290 )
1830 bHangingPunctuation
= ( nBreakPos
> nMaxBreakPos
) ? sal_True
: sal_False
;
1831 pLine
->SetHangingPunctuation( bHangingPunctuation
);
1834 // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
1835 // die Silbentrennung jagen...
1836 // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
1837 // nBreakPos ist der Wort-Anfang
1838 // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
1839 // auf mehr als Zwei Zeilen gebrochen wird...
1840 if ( !bHangingPunctuation
&& bCanHyphenate
&& GetHyphenator().is() )
1842 i18n::Boundary aBoundary
= _xBI
->getWordBoundary( *pNode
, nBreakPos
, GetLocale( EditPaM( pNode
, nBreakPos
) ), ::com::sun::star::i18n::WordType::DICTIONARY_WORD
, sal_True
);
1843 // sal_uInt16 nWordStart = nBreakPos;
1844 // sal_uInt16 nBreakPos_OLD = nBreakPos;
1845 sal_uInt16 nWordStart
= nBreakPos
;
1846 sal_uInt16 nWordEnd
= (USHORT
) aBoundary
.endPos
;
1847 DBG_ASSERT( nWordEnd
> nWordStart
, "ImpBreakLine: Start >= End?" );
1849 USHORT nWordLen
= nWordEnd
- nWordStart
;
1850 if ( ( nWordEnd
>= nMaxBreakPos
) && ( nWordLen
> 3 ) )
1852 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
1853 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
1854 String
aWord( *pNode
, nWordStart
, nWordLen
);
1855 sal_uInt16 nMinTrail
= nWordEnd
-nMaxBreakPos
+1; //+1: Vor dem angeknacksten Buchstaben
1856 Reference
< XHyphenatedWord
> xHyphWord
;
1857 if (xHyphenator
.is())
1858 xHyphWord
= xHyphenator
->hyphenate( aWord
, aLocale
, aWord
.Len() - nMinTrail
, Sequence
< PropertyValue
>() );
1861 sal_Bool bAlternate
= xHyphWord
->isAlternativeSpelling();
1862 sal_uInt16 _nWordLen
= 1 + xHyphWord
->getHyphenPos();
1864 if ( ( _nWordLen
>= 2 ) && ( (nWordStart
+_nWordLen
) >= (pLine
->GetStart() + 2 ) ) )
1868 bHyphenated
= sal_True
;
1869 nBreakPos
= nWordStart
+ _nWordLen
;
1873 String
aAlt( xHyphWord
->getHyphenatedWord() );
1875 // Wir gehen von zwei Faellen aus, die nun
1876 // vorliegen koennen:
1877 // 1) packen wird zu pak-ken
1878 // 2) Schiffahrt wird zu Schiff-fahrt
1879 // In Fall 1 muss ein Zeichen ersetzt werden,
1880 // in Fall 2 wird ein Zeichen hinzugefuegt.
1881 // Die Identifikation wird erschwert durch Worte wie
1882 // "Schiffahrtsbrennesseln", da der Hyphenator alle
1883 // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
1884 // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
1885 // Index des AlternativWord auf aWord schliessen.
1887 // Das ganze geraffel wird durch eine Funktion am
1888 // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
1889 sal_uInt16 nAltStart
= _nWordLen
- 1;
1890 sal_uInt16 nTxtStart
= nAltStart
- (aAlt
.Len() - aWord
.Len());
1891 sal_uInt16 nTxtEnd
= nTxtStart
;
1892 sal_uInt16 nAltEnd
= nAltStart
;
1894 // Die Bereiche zwischen den nStart und nEnd ist
1895 // die Differenz zwischen Alternativ- und OriginalString.
1896 while( nTxtEnd
< aWord
.Len() && nAltEnd
< aAlt
.Len() &&
1897 aWord
.GetChar(nTxtEnd
) != aAlt
.GetChar(nAltEnd
) )
1903 // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
1904 if( nAltEnd
> nTxtEnd
&& nAltStart
== nAltEnd
&&
1905 aWord
.GetChar( nTxtEnd
) == aAlt
.GetChar(nAltEnd
) )
1912 DBG_ASSERT( ( nAltEnd
- nAltStart
) == 1, "Alternate: Falsche Annahme!" );
1914 if ( nTxtEnd
> nTxtStart
)
1915 cAlternateReplChar
= aAlt
.GetChar( nAltStart
);
1917 cAlternateExtraChar
= aAlt
.GetChar( nAltStart
);
1919 bHyphenated
= sal_True
;
1920 nBreakPos
= nWordStart
+ nTxtStart
;
1921 if ( cAlternateReplChar
)
1929 #endif // !SVX_LIGHT
1931 if ( nBreakPos
<= pLine
->GetStart() )
1933 // keine Trenner in Zeile => abhacken !
1934 nBreakPos
= nMaxBreakPos
;
1935 // MT: I18N nextCharacters !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1936 if ( nBreakPos
<= pLine
->GetStart() )
1937 nBreakPos
= pLine
->GetStart() + 1; // Sonst Endlosschleife!
1941 // die angeknackste Portion ist die End-Portion
1942 pLine
->SetEnd( nBreakPos
);
1944 sal_uInt16 nEndPortion
= SplitTextPortion( pParaPortion
, nBreakPos
, pLine
);
1946 if ( !bCompressBlank
&& !bHangingPunctuation
)
1948 // #96187# When justification is not SVX_ADJUST_LEFT, it's important to compress
1949 // the trailing space even if there is enough room for the space...
1950 // Don't check for SVX_ADJUST_LEFT, doesn't matter to compress in this case too...
1951 DBG_ASSERT( nBreakPos
> pLine
->GetStart(), "ImpBreakLines - BreakPos not expected!" );
1952 if ( pNode
->GetChar( nBreakPos
-1 ) == ' ' )
1953 bCompressBlank
= sal_True
;
1956 if ( bCompressBlank
|| bHangingPunctuation
)
1958 TextPortion
* pTP
= pParaPortion
->GetTextPortions().GetObject( nEndPortion
);
1959 DBG_ASSERT( pTP
->GetKind() == PORTIONKIND_TEXT
, "BlankRubber: Keine TextPortion!" );
1960 DBG_ASSERT( nBreakPos
> pLine
->GetStart(), "SplitTextPortion am Anfang der Zeile?" );
1961 sal_uInt16 nPosInArray
= nBreakPos
- 1 - pLine
->GetStart();
1962 pTP
->GetSize().Width() = ( nPosInArray
&& ( pTP
->GetLen() > 1 ) ) ? pLine
->GetCharPosArray()[ nPosInArray
-1 ] : 0;
1963 pLine
->GetCharPosArray()[ nPosInArray
] = pTP
->GetSize().Width();
1965 else if ( bHyphenated
)
1967 // Eine Portion fuer den Trenner einbauen...
1968 TextPortion
* pHyphPortion
= new TextPortion( 0 );
1969 pHyphPortion
->GetKind() = PORTIONKIND_HYPHENATOR
;
1970 String
aHyphText( CH_HYPH
);
1971 if ( cAlternateReplChar
)
1973 TextPortion
* pPrev
= pParaPortion
->GetTextPortions().GetObject( nEndPortion
);
1974 DBG_ASSERT( pPrev
&& pPrev
->GetLen(), "Hyphenate: Prev portion?!" );
1975 pPrev
->SetLen( pPrev
->GetLen() - 1 );
1976 pHyphPortion
->SetLen( 1 );
1977 pHyphPortion
->SetExtraValue( cAlternateReplChar
);
1978 // Breite der Portion davor korrigieren:
1979 pPrev
->GetSize().Width() =
1980 pLine
->GetCharPosArray()[ nBreakPos
-1 - pLine
->GetStart() - 1 ];
1982 else if ( cAlternateExtraChar
)
1984 pHyphPortion
->SetExtraValue( cAlternateExtraChar
);
1985 aHyphText
.Insert( cAlternateExtraChar
, 0 );
1988 // Breite der Hyph-Portion ermitteln:
1990 SeekCursor( pParaPortion
->GetNode(), nBreakPos
, aFont
);
1991 aFont
.SetPhysFont( GetRefDevice() );
1992 pHyphPortion
->GetSize().Height() = GetRefDevice()->GetTextHeight();
1993 pHyphPortion
->GetSize().Width() = GetRefDevice()->GetTextWidth( aHyphText
);
1995 pParaPortion
->GetTextPortions().Insert( pHyphPortion
, ++nEndPortion
);
1997 pLine
->SetEndPortion( nEndPortion
);
2000 void ImpEditEngine::ImpAdjustBlocks( ParaPortion
* pParaPortion
, EditLine
* pLine
, long nRemainingSpace
)
2002 DBG_ASSERT( nRemainingSpace
> 0, "AdjustBlocks: Etwas zuwenig..." );
2003 DBG_ASSERT( pLine
, "AdjustBlocks: Zeile ?!" );
2004 if ( ( nRemainingSpace
< 0 ) || pLine
->IsEmpty() )
2007 const USHORT nFirstChar
= pLine
->GetStart();
2008 const USHORT nLastChar
= pLine
->GetEnd() -1; // Last zeigt dahinter
2009 ContentNode
* pNode
= pParaPortion
->GetNode();
2011 DBG_ASSERT( nLastChar
< pNode
->Len(), "AdjustBlocks: Out of range!" );
2013 // Search blanks or Kashidas...
2014 SvUShorts aPositions
;
2016 for ( nChar
= nFirstChar
; nChar
<= nLastChar
; nChar
++ )
2018 if ( pNode
->GetChar(nChar
) == ' ' )
2020 // Don't use blank if language is arabic
2021 LanguageType eLang
= GetLanguage( EditPaM( pNode
, nChar
) );
2022 if ( MsLangId::getPrimaryLanguage( eLang
) != LANGUAGE_ARABIC_PRIMARY_ONLY
)
2023 aPositions
.Insert( nChar
, aPositions
.Count() );
2028 ImpFindKashidas( pNode
, nFirstChar
, nLastChar
, aPositions
);
2031 if ( !aPositions
.Count() )
2034 // Wenn das letzte Zeichen ein Blank ist, will ich es nicht haben!
2035 // Die Breite muss auf die Blocker davor verteilt werden...
2036 // Aber nicht, wenn es das einzige ist
2037 if ( ( pNode
->GetChar( nLastChar
) == ' ' ) && ( aPositions
.Count() > 1 ) && ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode
, nLastChar
) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY
) )
2039 aPositions
.Remove( aPositions
.Count()-1, 1 );
2040 USHORT nPortionStart
, nPortion
;
2041 nPortion
= pParaPortion
->GetTextPortions().FindPortion( nLastChar
+1, nPortionStart
);
2042 TextPortion
* pLastPortion
= pParaPortion
->GetTextPortions()[ nPortion
];
2043 long nRealWidth
= pLine
->GetCharPosArray()[nLastChar
-nFirstChar
];
2044 long nBlankWidth
= nRealWidth
;
2045 if ( nLastChar
> nPortionStart
)
2046 nBlankWidth
-= pLine
->GetCharPosArray()[nLastChar
-nFirstChar
-1];
2047 // Evtl. ist das Blank schon in ImpBreakLine abgezogen worden:
2048 if ( nRealWidth
== pLastPortion
->GetSize().Width() )
2050 // Beim letzten Zeichen muss die Portion hinter dem Blank aufhoeren
2051 // => Korrektur vereinfachen:
2052 DBG_ASSERT( ( nPortionStart
+ pLastPortion
->GetLen() ) == ( nLastChar
+1 ), "Blank doch nicht am Portion-Ende?!" );
2053 pLastPortion
->GetSize().Width() -= nBlankWidth
;
2054 nRemainingSpace
+= nBlankWidth
;
2056 pLine
->GetCharPosArray()[nLastChar
-nFirstChar
] -= nBlankWidth
;
2059 USHORT nGaps
= aPositions
.Count();
2060 const long nMore4Everyone
= nRemainingSpace
/ nGaps
;
2061 long nSomeExtraSpace
= nRemainingSpace
- nMore4Everyone
*nGaps
;
2063 DBG_ASSERT( nSomeExtraSpace
< (long)nGaps
, "AdjustBlocks: ExtraSpace zu gross" );
2064 DBG_ASSERT( nSomeExtraSpace
>= 0, "AdjustBlocks: ExtraSpace < 0 " );
2066 // Die Positionen im Array und die Portion-Breiten korrigieren:
2067 // Letztes Zeichen wird schon nicht mehr beachtet...
2068 for ( USHORT n
= 0; n
< aPositions
.Count(); n
++ )
2070 nChar
= aPositions
[n
];
2071 if ( nChar
< nLastChar
)
2073 USHORT nPortionStart
, nPortion
;
2074 nPortion
= pParaPortion
->GetTextPortions().FindPortion( nChar
, nPortionStart
);
2075 TextPortion
* pLastPortion
= pParaPortion
->GetTextPortions()[ nPortion
];
2077 // Die Breite der Portion:
2078 pLastPortion
->GetSize().Width() += nMore4Everyone
;
2079 if ( nSomeExtraSpace
)
2080 pLastPortion
->GetSize().Width()++;
2082 // Correct positions in array
2083 // Even for kashidas just change positions, VCL will then draw the kashida automaticly
2084 USHORT nPortionEnd
= nPortionStart
+ pLastPortion
->GetLen();
2085 for ( USHORT _n
= nChar
; _n
< nPortionEnd
; _n
++ )
2087 pLine
->GetCharPosArray()[_n
-nFirstChar
] += nMore4Everyone
;
2088 if ( nSomeExtraSpace
)
2089 pLine
->GetCharPosArray()[_n
-nFirstChar
]++;
2092 if ( nSomeExtraSpace
)
2097 // Now the text width contains the extra width...
2098 pLine
->SetTextWidth( pLine
->GetTextWidth() + nRemainingSpace
);
2101 void ImpEditEngine::ImpFindKashidas( ContentNode
* pNode
, USHORT nStart
, USHORT nEnd
, SvUShorts
& rArray
)
2103 // the search has to be performed on a per word base
2105 EditSelection
aWordSel( EditPaM( pNode
, nStart
) );
2106 aWordSel
= SelectWord( aWordSel
, ::com::sun::star::i18n::WordType::DICTIONARY_WORD
);
2107 if ( aWordSel
.Min().GetIndex() < nStart
)
2108 aWordSel
.Min().GetIndex() = nStart
;
2110 while ( ( aWordSel
.Min().GetNode() == pNode
) && ( aWordSel
.Min().GetIndex() < nEnd
) )
2112 USHORT nSavPos
= aWordSel
.Max().GetIndex();
2113 if ( aWordSel
.Max().GetIndex() > nEnd
)
2114 aWordSel
.Max().GetIndex() = nEnd
;
2116 String aWord
= GetSelected( aWordSel
);
2118 // restore selection for proper iteration at the end of the function
2119 aWordSel
.Max().GetIndex() = nSavPos
;
2121 xub_StrLen nIdx
= 0;
2122 xub_StrLen nKashidaPos
= STRING_LEN
;
2124 xub_Unicode cPrevCh
= 0;
2126 while ( nIdx
< aWord
.Len() )
2128 cCh
= aWord
.GetChar( nIdx
);
2131 // after user inserted kashida
2134 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
;
2139 // after a Seen or Sad
2140 if ( nIdx
+ 1 < aWord
.Len() &&
2141 ( 0x633 == cCh
|| 0x635 == cCh
) )
2143 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
;
2148 // before final form of Teh Marbuta, Hah, Dal
2150 // before final form of Alef, Lam or Kaf
2151 if ( nIdx
&& nIdx
+ 1 == aWord
.Len() &&
2152 ( 0x629 == cCh
|| 0x62D == cCh
|| 0x62F == cCh
||
2153 0x627 == cCh
|| 0x644 == cCh
|| 0x643 == cCh
) )
2155 DBG_ASSERT( 0 != cPrevCh
, "No previous character" );
2157 // check if character is connectable to previous character,
2158 if ( lcl_ConnectToPrev( cCh
, cPrevCh
) )
2160 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
- 1;
2167 if ( nIdx
&& nIdx
+ 1 < aWord
.Len() && 0x628 == cCh
)
2169 DBG_ASSERT( 0 != cPrevCh
, "No previous character" );
2171 // check if next character is Reh, Yeh or Alef Maksura
2172 xub_Unicode cNextCh
= aWord
.GetChar( nIdx
+ 1 );
2174 if ( 0x631 == cNextCh
|| 0x64A == cNextCh
||
2177 // check if character is connectable to previous character,
2178 if ( lcl_ConnectToPrev( cCh
, cPrevCh
) )
2179 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
- 1;
2184 // other connecting possibilities
2185 if ( nIdx
&& nIdx
+ 1 == aWord
.Len() &&
2186 0x60C <= cCh
&& 0x6FE >= cCh
)
2188 DBG_ASSERT( 0 != cPrevCh
, "No previous character" );
2190 // check if character is connectable to previous character,
2191 if ( lcl_ConnectToPrev( cCh
, cPrevCh
) )
2193 // only choose this position if we did not find
2195 if ( STRING_LEN
== nKashidaPos
)
2196 nKashidaPos
= aWordSel
.Min().GetIndex() + nIdx
- 1;
2201 // Do not consider Fathatan, Dammatan, Kasratan, Fatha,
2202 // Damma, Kasra, Shadda and Sukun when checking if
2203 // a character can be connected to previous character.
2204 if ( cCh
< 0x64B || cCh
> 0x652 )
2208 } // end of current word
2210 if ( STRING_LEN
!= nKashidaPos
)
2211 rArray
.Insert( nKashidaPos
, rArray
.Count() );
2213 aWordSel
= WordRight( aWordSel
.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD
);
2214 aWordSel
= SelectWord( aWordSel
, ::com::sun::star::i18n::WordType::DICTIONARY_WORD
);
2218 sal_uInt16
ImpEditEngine::SplitTextPortion( ParaPortion
* pPortion
, sal_uInt16 nPos
, EditLine
* pCurLine
)
2220 DBG_ASSERT( pPortion
, "SplitTextPortion: Welche ?" );
2222 // Die Portion bei nPos wird geplittet, wenn bei nPos nicht
2223 // sowieso ein Wechsel ist
2227 sal_uInt16 nSplitPortion
;
2228 sal_uInt16 nTmpPos
= 0;
2229 TextPortion
* pTextPortion
= 0;
2230 sal_uInt16 nPortions
= pPortion
->GetTextPortions().Count();
2231 for ( nSplitPortion
= 0; nSplitPortion
< nPortions
; nSplitPortion
++ )
2233 TextPortion
* pTP
= pPortion
->GetTextPortions().GetObject(nSplitPortion
);
2234 nTmpPos
= nTmpPos
+ pTP
->GetLen();
2235 if ( nTmpPos
>= nPos
)
2237 if ( nTmpPos
== nPos
) // dann braucht nichts geteilt werden
2239 // Skip Portions with ExtraSpace
2240 // while ( ( (nSplitPortion+1) < nPortions ) && (pPortion->GetTextPortions().GetObject(nSplitPortion+1)->GetKind() == PORTIONKIND_EXTRASPACE ) )
2243 return nSplitPortion
;
2250 DBG_ASSERT( pTextPortion
, "Position ausserhalb des Bereichs!" );
2251 DBG_ASSERT( pTextPortion
->GetKind() == PORTIONKIND_TEXT
, "SplitTextPortion: Keine TextPortion!" );
2253 sal_uInt16 nOverlapp
= nTmpPos
- nPos
;
2254 pTextPortion
->GetLen() = pTextPortion
->GetLen() - nOverlapp
;
2255 TextPortion
* pNewPortion
= new TextPortion( nOverlapp
);
2256 pPortion
->GetTextPortions().Insert( pNewPortion
, nSplitPortion
+1 );
2260 // Kein neues GetTextSize, sondern Werte aus Array verwenden:
2261 DBG_ASSERT( nPos
> pCurLine
->GetStart(), "SplitTextPortion am Anfang der Zeile?" );
2262 pTextPortion
->GetSize().Width() = pCurLine
->GetCharPosArray()[ nPos
-pCurLine
->GetStart()-1 ];
2264 if ( pTextPortion
->GetExtraInfos() && pTextPortion
->GetExtraInfos()->bCompressed
)
2266 // We need the original size from the portion
2267 USHORT nTxtPortionStart
= pPortion
->GetTextPortions().GetStartPos( nSplitPortion
);
2268 SvxFont
aTmpFont( pPortion
->GetNode()->GetCharAttribs().GetDefFont() );
2269 SeekCursor( pPortion
->GetNode(), nTxtPortionStart
+1, aTmpFont
);
2270 aTmpFont
.SetPhysFont( GetRefDevice() );
2271 GetRefDevice()->Push( PUSH_TEXTLANGUAGE
);
2272 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
2273 Size aSz
= aTmpFont
.QuickGetTextSize( GetRefDevice(), *pPortion
->GetNode(), nTxtPortionStart
, pTextPortion
->GetLen(), NULL
);
2274 GetRefDevice()->Pop();
2275 pTextPortion
->GetExtraInfos()->nOrgWidth
= aSz
.Width();
2279 pTextPortion
->GetSize().Width() = (-1);
2281 return nSplitPortion
;
2284 void ImpEditEngine::CreateTextPortions( ParaPortion
* pParaPortion
, sal_uInt16
& rStart
/* , sal_Bool bCreateBlockPortions */ )
2286 sal_uInt16 nStartPos
= rStart
;
2287 ContentNode
* pNode
= pParaPortion
->GetNode();
2288 DBG_ASSERT( pNode
->Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" );
2290 SortedPositions aPositions
;
2291 aPositions
.Insert( (sal_uInt32
) 0 );
2293 sal_uInt16 nAttr
= 0;
2294 EditCharAttrib
* pAttrib
= GetAttrib( pNode
->GetCharAttribs().GetAttribs(), nAttr
);
2297 // Start und Ende in das Array eintragen...
2298 // Die InsertMethode laesst keine doppelten Werte zu....
2299 aPositions
.Insert( pAttrib
->GetStart() );
2300 aPositions
.Insert( pAttrib
->GetEnd() );
2302 pAttrib
= GetAttrib( pNode
->GetCharAttribs().GetAttribs(), nAttr
);
2304 aPositions
.Insert( pNode
->Len() );
2306 if ( !pParaPortion
->aScriptInfos
.Count() )
2307 ((ImpEditEngine
*)this)->InitScriptTypes( GetParaPortions().GetPos( pParaPortion
) );
2309 const ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
2310 for ( USHORT nT
= 0; nT
< rTypes
.Count(); nT
++ )
2311 aPositions
.Insert( rTypes
[nT
].nStartPos
);
2313 const WritingDirectionInfos
& rWritingDirections
= pParaPortion
->aWritingDirectionInfos
;
2314 for ( USHORT nD
= 0; nD
< rWritingDirections
.Count(); nD
++ )
2315 aPositions
.Insert( rWritingDirections
[nD
].nStartPos
);
2317 if ( mpIMEInfos
&& mpIMEInfos
->nLen
&& mpIMEInfos
->pAttribs
&& ( mpIMEInfos
->aPos
.GetNode() == pNode
) )
2319 sal_uInt16 nLastAttr
= 0xFFFF;
2320 for( sal_uInt16 n
= 0; n
< mpIMEInfos
->nLen
; n
++ )
2322 if ( mpIMEInfos
->pAttribs
[n
] != nLastAttr
)
2324 aPositions
.Insert( mpIMEInfos
->aPos
.GetIndex() + n
);
2325 nLastAttr
= mpIMEInfos
->pAttribs
[n
];
2328 aPositions
.Insert( mpIMEInfos
->aPos
.GetIndex() + mpIMEInfos
->nLen
);
2332 // Leider muss die Anzahl der TextPortions mit aPositions.Count()
2333 // nicht uebereinstimmen, da evtl. Zeilenumbrueche...
2334 sal_uInt16 nPortionStart
= 0;
2335 sal_uInt16 nInvPortion
= 0;
2337 for ( nP
= 0; nP
< pParaPortion
->GetTextPortions().Count(); nP
++ )
2339 TextPortion
* pTmpPortion
= pParaPortion
->GetTextPortions().GetObject(nP
);
2340 nPortionStart
= nPortionStart
+ pTmpPortion
->GetLen();
2341 if ( nPortionStart
>= nStartPos
)
2343 nPortionStart
= nPortionStart
- pTmpPortion
->GetLen();
2344 rStart
= nPortionStart
;
2349 DBG_ASSERT( nP
< pParaPortion
->GetTextPortions().Count() || !pParaPortion
->GetTextPortions().Count(), "Nichts zum loeschen: CreateTextPortions" );
2350 if ( nInvPortion
&& ( nPortionStart
+pParaPortion
->GetTextPortions().GetObject(nInvPortion
)->GetLen() > nStartPos
) )
2352 // lieber eine davor...
2353 // Aber nur wenn es mitten in der Portion war, sonst ist es evtl.
2354 // die einzige in der Zeile davor !
2356 nPortionStart
= nPortionStart
- pParaPortion
->GetTextPortions().GetObject(nInvPortion
)->GetLen();
2358 pParaPortion
->GetTextPortions().DeleteFromPortion( nInvPortion
);
2360 // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein:
2361 aPositions
.Insert( nPortionStart
);
2367 aPositions
.Seek_Entry( nPortionStart
, &nInvPos
);
2369 DBG_ASSERT( bFound
&& ( nInvPos
< (aPositions
.Count()-1) ), "InvPos ?!" );
2370 for ( sal_uInt16 i
= nInvPos
+1; i
< aPositions
.Count(); i
++ )
2372 TextPortion
* pNew
= new TextPortion( (sal_uInt16
)aPositions
[i
] - (sal_uInt16
)aPositions
[i
-1] );
2373 pParaPortion
->GetTextPortions().Insert( pNew
, pParaPortion
->GetTextPortions().Count());
2376 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "Keine Portions?!" );
2378 DBG_ASSERT( pParaPortion
->DbgCheckTextPortions(), "Portions kaputt?" );
2382 void ImpEditEngine::RecalcTextPortion( ParaPortion
* pParaPortion
, sal_uInt16 nStartPos
, short nNewChars
)
2384 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "Keine Portions!" );
2385 DBG_ASSERT( nNewChars
, "RecalcTextPortion mit Diff == 0" );
2387 ContentNode
* const pNode
= pParaPortion
->GetNode();
2388 if ( nNewChars
> 0 )
2390 // Wenn an nStartPos ein Attribut beginnt/endet, faengt eine neue Portion
2391 // an, ansonsten wird die Portion an nStartPos erweitert.
2393 if ( pNode
->GetCharAttribs().HasBoundingAttrib( nStartPos
) || IsScriptChange( EditPaM( pNode
, nStartPos
) ) )
2395 sal_uInt16 nNewPortionPos
= 0;
2397 nNewPortionPos
= SplitTextPortion( pParaPortion
, nStartPos
) + 1;
2399 // Eine leere Portion kann hier stehen, wenn der Absatz leer war,
2400 // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist.
2401 if ( ( nNewPortionPos
< pParaPortion
->GetTextPortions().Count() ) &&
2402 !pParaPortion
->GetTextPortions()[nNewPortionPos
]->GetLen() )
2404 DBG_ASSERT( pParaPortion
->GetTextPortions()[nNewPortionPos
]->GetKind() == PORTIONKIND_TEXT
, "Leere Portion war keine TextPortion!" );
2406 pParaPortion
->GetTextPortions()[nNewPortionPos
]->GetLen();
2411 TextPortion
* pNewPortion
= new TextPortion( nNewChars
);
2412 pParaPortion
->GetTextPortions().Insert( pNewPortion
, nNewPortionPos
);
2417 sal_uInt16 nPortionStart
;
2418 const sal_uInt16 nTP
= pParaPortion
->GetTextPortions().
2419 FindPortion( nStartPos
, nPortionStart
);
2420 TextPortion
* const pTP
= pParaPortion
->GetTextPortions()[ nTP
];
2421 DBG_ASSERT( pTP
, "RecalcTextPortion: Portion nicht gefunden" );
2422 pTP
->GetLen() = pTP
->GetLen() + nNewChars
;
2423 pTP
->GetSize().Width() = (-1);
2428 // Portion schrumpfen oder ggf. entfernen.
2429 // Vor Aufruf dieser Methode muss sichergestellt sein, dass
2430 // keine Portions in dem geloeschten Bereich lagen!
2432 // Es darf keine reinragende oder im Bereich startende Portion geben,
2433 // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein
2434 sal_uInt16 nPortion
= 0;
2435 sal_uInt16 nPos
= 0;
2436 sal_uInt16 nEnd
= nStartPos
-nNewChars
;
2437 sal_uInt16 nPortions
= pParaPortion
->GetTextPortions().Count();
2438 TextPortion
* pTP
= 0;
2439 for ( nPortion
= 0; nPortion
< nPortions
; nPortion
++ )
2441 pTP
= pParaPortion
->GetTextPortions()[ nPortion
];
2442 if ( ( nPos
+pTP
->GetLen() ) > nStartPos
)
2444 DBG_ASSERT( nPos
<= nStartPos
, "Start falsch!" );
2445 DBG_ASSERT( nPos
+pTP
->GetLen() >= nEnd
, "End falsch!" );
2448 nPos
= nPos
+ pTP
->GetLen();
2450 DBG_ASSERT( pTP
, "RecalcTextPortion: Portion nicht gefunden" );
2451 if ( ( nPos
== nStartPos
) && ( (nPos
+pTP
->GetLen()) == nEnd
) )
2453 // Portion entfernen;
2454 BYTE nType
= pTP
->GetKind();
2455 pParaPortion
->GetTextPortions().Remove( nPortion
);
2457 if ( nType
== PORTIONKIND_LINEBREAK
)
2459 TextPortion
* pNext
= pParaPortion
->GetTextPortions()[ nPortion
];
2460 if ( pNext
&& !pNext
->GetLen() )
2462 // Dummy-Portion entfernen
2463 pParaPortion
->GetTextPortions().Remove( nPortion
);
2470 DBG_ASSERT( pTP
->GetLen() > (-nNewChars
), "Portion zu klein zum schrumpfen!" );
2471 pTP
->GetLen() = pTP
->GetLen() + nNewChars
;
2474 // ganz am Schluss darf keine HYPHENATOR-Portion stehen bleiben...
2475 DBG_ASSERT( pParaPortion
->GetTextPortions().Count(), "RecalcTextPortions: Keine mehr da!" );
2476 sal_uInt16 nLastPortion
= pParaPortion
->GetTextPortions().Count() - 1;
2477 pTP
= pParaPortion
->GetTextPortions().GetObject( nLastPortion
);
2478 if ( pTP
->GetKind() == PORTIONKIND_HYPHENATOR
)
2480 // Portion wegschmeissen, ggf. die davor korrigieren, wenn
2481 // die Hyph-Portion ein Zeichen geschluckt hat...
2482 pParaPortion
->GetTextPortions().Remove( nLastPortion
);
2483 if ( nLastPortion
&& pTP
->GetLen() )
2485 TextPortion
* pPrev
= pParaPortion
->GetTextPortions().GetObject( nLastPortion
- 1 );
2486 DBG_ASSERT( pPrev
->GetKind() == PORTIONKIND_TEXT
, "Portion?!" );
2487 pPrev
->SetLen( pPrev
->GetLen() + pTP
->GetLen() );
2488 pPrev
->GetSize().Width() = (-1);
2494 DBG_ASSERT( pParaPortion
->DbgCheckTextPortions(), "Portions kaputt?" );
2498 void ImpEditEngine::SetTextRanger( TextRanger
* pRanger
)
2500 if ( pTextRanger
!= pRanger
)
2503 pTextRanger
= pRanger
;
2505 for ( sal_uInt16 nPara
= 0; nPara
< GetParaPortions().Count(); nPara
++ )
2507 ParaPortion
* pParaPortion
= GetParaPortions().GetObject( nPara
);
2508 pParaPortion
->MarkSelectionInvalid( 0, pParaPortion
->GetNode()->Len() );
2509 pParaPortion
->GetLines().Reset();
2513 UpdateViews( GetActiveView() );
2514 if ( GetUpdateMode() && GetActiveView() )
2515 pActiveView
->ShowCursor( sal_False
, sal_False
);
2519 void ImpEditEngine::SetVertical( BOOL bVertical
)
2521 if ( IsVertical() != bVertical
)
2523 GetEditDoc().SetVertical( bVertical
);
2524 sal_Bool bUseCharAttribs
= ( aStatus
.GetControlWord() & EE_CNTRL_USECHARATTRIBS
) ? sal_True
: sal_False
;
2525 GetEditDoc().CreateDefFont( bUseCharAttribs
);
2526 if ( IsFormatted() )
2529 UpdateViews( GetActiveView() );
2534 void ImpEditEngine::SetFixedCellHeight( BOOL bUseFixedCellHeight
)
2536 if ( IsFixedCellHeight() != bUseFixedCellHeight
)
2538 GetEditDoc().SetFixedCellHeight( bUseFixedCellHeight
);
2539 if ( IsFormatted() )
2542 UpdateViews( GetActiveView() );
2547 void ImpEditEngine::SeekCursor( ContentNode
* pNode
, sal_uInt16 nPos
, SvxFont
& rFont
, OutputDevice
* pOut
, sal_uInt16 nIgnoreWhich
)
2549 // Es war mal geplant, SeekCursor( nStartPos, nEndPos, ... ), damit nur
2550 // ab der StartPosition neu gesucht wird.
2551 // Problem: Es mussten zwei Listen beruecksichtigt/gefuehrt werden:
2552 // OrderedByStart,OrderedByEnd.
2554 if ( nPos
> pNode
->Len() )
2555 nPos
= pNode
->Len();
2557 rFont
= pNode
->GetCharAttribs().GetDefFont();
2559 short nScriptType
= GetScriptType( EditPaM( pNode
, nPos
) );
2560 if ( ( nScriptType
== i18n::ScriptType::ASIAN
) || ( nScriptType
== i18n::ScriptType::COMPLEX
) )
2562 const SvxFontItem
& rFontItem
= (const SvxFontItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTINFO
, nScriptType
) );
2563 rFont
.SetName( rFontItem
.GetFamilyName() );
2564 rFont
.SetFamily( rFontItem
.GetFamily() );
2565 rFont
.SetPitch( rFontItem
.GetPitch() );
2566 rFont
.SetCharSet( rFontItem
.GetCharSet() );
2567 Size
aSz( rFont
.GetSize() );
2568 aSz
.Height() = ((const SvxFontHeightItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTHEIGHT
, nScriptType
) ) ).GetHeight();
2569 rFont
.SetSize( aSz
);
2570 rFont
.SetWeight( ((const SvxWeightItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_WEIGHT
, nScriptType
))).GetWeight() );
2571 rFont
.SetItalic( ((const SvxPostureItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_ITALIC
, nScriptType
))).GetPosture() );
2572 rFont
.SetLanguage( ((const SvxLanguageItem
&)pNode
->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_LANGUAGE
, nScriptType
))).GetLanguage() );
2575 sal_uInt16 nRelWidth
= ((const SvxCharScaleWidthItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH
)).GetValue();
2579 const SvxUnderlineItem
& rTextLineColor
= (const SvxUnderlineItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_UNDERLINE
);
2580 if ( rTextLineColor
.GetColor() != COL_TRANSPARENT
)
2581 pOut
->SetTextLineColor( rTextLineColor
.GetColor() );
2583 pOut
->SetTextLineColor();
2588 const SvxOverlineItem
& rOverlineColor
= (const SvxOverlineItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_OVERLINE
);
2589 if ( rOverlineColor
.GetColor() != COL_TRANSPARENT
)
2590 pOut
->SetOverlineColor( rOverlineColor
.GetColor() );
2592 pOut
->SetOverlineColor();
2595 const SvxLanguageItem
* pCJKLanguageItem
= NULL
;
2597 if ( aStatus
.UseCharAttribs() )
2599 const CharAttribArray
& rAttribs
= pNode
->GetCharAttribs().GetAttribs();
2600 sal_uInt16 nAttr
= 0;
2601 EditCharAttrib
* pAttrib
= GetAttrib( rAttribs
, nAttr
);
2602 while ( pAttrib
&& ( pAttrib
->GetStart() <= nPos
) )
2604 // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen!
2605 // Leere Attribute werden beruecksichtigt( verwendet), da diese
2606 // gerade eingestellt wurden.
2607 // 12.4.95: Doch keine Leeren Attribute verwenden:
2608 // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font
2609 // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam.
2610 if ( ( pAttrib
->Which() != nIgnoreWhich
) &&
2611 ( ( ( pAttrib
->GetStart() < nPos
) && ( pAttrib
->GetEnd() >= nPos
) )
2612 || ( !pNode
->Len() ) ) )
2614 DBG_ASSERT( ( pAttrib
->Which() >= EE_CHAR_START
) && ( pAttrib
->Which() <= EE_FEATURE_END
), "Unglueltiges Attribut in Seek() " );
2615 if ( IsScriptItemValid( pAttrib
->Which(), nScriptType
) )
2617 pAttrib
->SetFont( rFont
, pOut
);
2618 // #i1550# hard color attrib should win over text color from field
2619 if ( pAttrib
->Which() == EE_FEATURE_FIELD
)
2621 EditCharAttrib
* pColorAttr
= pNode
->GetCharAttribs().FindAttrib( EE_CHAR_COLOR
, nPos
);
2623 pColorAttr
->SetFont( rFont
, pOut
);
2626 if ( pAttrib
->Which() == EE_CHAR_FONTWIDTH
)
2627 nRelWidth
= ((const SvxCharScaleWidthItem
*)pAttrib
->GetItem())->GetValue();
2628 if ( pAttrib
->Which() == EE_CHAR_LANGUAGE_CJK
)
2629 pCJKLanguageItem
= (const SvxLanguageItem
*) pAttrib
->GetItem();
2631 pAttrib
= GetAttrib( rAttribs
, ++nAttr
);
2635 if ( !pCJKLanguageItem
)
2636 pCJKLanguageItem
= (const SvxLanguageItem
*) &pNode
->GetContentAttribs().GetItem( EE_CHAR_LANGUAGE_CJK
);
2638 rFont
.SetCJKContextLanguage( pCJKLanguageItem
->GetLanguage() );
2640 if ( rFont
.GetKerning() && IsKernAsianPunctuation() && ( nScriptType
== i18n::ScriptType::ASIAN
) )
2641 rFont
.SetKerning( rFont
.GetKerning() | KERNING_ASIAN
);
2643 if ( aStatus
.DoNotUseColors() )
2645 // Hack fuer DL,weil JOE staendig die Pooldefaults verbiegt!
2646 // const SvxColorItem& rColorItem = (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR );
2647 rFont
.SetColor( /* rColorItem.GetValue() */ COL_BLACK
);
2650 if ( aStatus
.DoStretch() || ( nRelWidth
!= 100 ) )
2652 // Fuer das aktuelle Ausgabegeraet, weil es sonst bei einem
2653 // Drucker als RefDev auf dem Bildschirm #?!@' aussieht!
2654 OutputDevice
* pDev
= pOut
? pOut
: GetRefDevice();
2655 rFont
.SetPhysFont( pDev
);
2656 FontMetric
aMetric( pDev
->GetFontMetric() );
2657 // Fuer die Hoehe nicht die Metriken nehmen, da das bei
2658 // Hoch-/Tiefgestellt schief geht.
2659 Size
aRealSz( aMetric
.GetSize().Width(), rFont
.GetSize().Height() );
2660 if ( aStatus
.DoStretch() )
2662 if ( nStretchY
!= 100 )
2664 aRealSz
.Height() *= nStretchY
;
2665 aRealSz
.Height() /= 100;
2667 if ( nStretchX
!= 100 )
2669 if ( nStretchX
== nStretchY
&&
2672 aRealSz
.Width() = 0;
2676 aRealSz
.Width() *= nStretchX
;
2677 aRealSz
.Width() /= 100;
2679 // Auch das Kerning: (long wegen Zwischenergebnis)
2680 long nKerning
= rFont
.GetFixKerning();
2682 Die Ueberlegung war: Wenn neg. Kerning, aber StretchX = 200
2683 => Nicht das Kerning verdoppelt, also die Buchstaben weiter
2685 ---------------------------
2686 Kern StretchX =>Kern
2687 ---------------------------
2688 >0 <100 < (Proportional)
2689 <0 <100 < (Proportional)
2690 >0 >100 > (Proportional)
2691 <0 >100 < (Der Betrag, also Antiprop)
2693 if ( ( nKerning
< 0 ) && ( nStretchX
> 100 ) )
2697 nKerning
/= nStretchX
;
2699 else if ( nKerning
)
2702 nKerning
*= nStretchX
;
2705 rFont
.SetFixKerning( (short)nKerning
);
2709 if ( nRelWidth
!= 100 )
2711 aRealSz
.Width() *= nRelWidth
;
2712 aRealSz
.Width() /= 100;
2714 rFont
.SetSize( aRealSz
);
2715 // Font wird nicht restauriert...
2718 if ( ( ( rFont
.GetColor() == COL_AUTO
) || ( IsForceAutoColor() ) ) && pOut
)
2720 // #i75566# Do not use AutoColor when printing OR Pdf export
2721 const bool bPrinting(OUTDEV_PRINTER
== pOut
->GetOutDevType());
2722 const bool bPDFExporting(0 != pOut
->GetPDFWriter());
2724 if ( IsAutoColorEnabled() && !bPrinting
&& !bPDFExporting
)
2726 // Never use WindowTextColor on the printer
2727 rFont
.SetColor( GetAutoColor() );
2731 if ( ( GetBackgroundColor() != COL_AUTO
) && GetBackgroundColor().IsDark() )
2732 rFont
.SetColor( COL_WHITE
);
2734 rFont
.SetColor( COL_BLACK
);
2738 if ( mpIMEInfos
&& mpIMEInfos
->pAttribs
&& ( mpIMEInfos
->aPos
.GetNode() == pNode
) &&
2739 ( nPos
> mpIMEInfos
->aPos
.GetIndex() ) && ( nPos
<= ( mpIMEInfos
->aPos
.GetIndex() + mpIMEInfos
->nLen
) ) )
2741 sal_uInt16 nAttr
= mpIMEInfos
->pAttribs
[ nPos
- mpIMEInfos
->aPos
.GetIndex() - 1 ];
2742 if ( nAttr
& EXTTEXTINPUT_ATTR_UNDERLINE
)
2743 rFont
.SetUnderline( UNDERLINE_SINGLE
);
2744 else if ( nAttr
& EXTTEXTINPUT_ATTR_BOLDUNDERLINE
)
2745 rFont
.SetUnderline( UNDERLINE_BOLD
);
2746 else if ( nAttr
& EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE
)
2747 rFont
.SetUnderline( UNDERLINE_DOTTED
);
2748 else if ( nAttr
& EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE
)
2749 rFont
.SetUnderline( UNDERLINE_DOTTED
);
2750 else if ( nAttr
& EXTTEXTINPUT_ATTR_REDTEXT
)
2751 rFont
.SetColor( Color( COL_RED
) );
2752 else if ( nAttr
& EXTTEXTINPUT_ATTR_HALFTONETEXT
)
2753 rFont
.SetColor( Color( COL_LIGHTGRAY
) );
2754 if ( nAttr
& EXTTEXTINPUT_ATTR_HIGHLIGHT
)
2756 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2757 rFont
.SetColor( rStyleSettings
.GetHighlightTextColor() );
2758 rFont
.SetFillColor( rStyleSettings
.GetHighlightColor() );
2759 rFont
.SetTransparent( FALSE
);
2761 else if ( nAttr
& EXTTEXTINPUT_ATTR_GRAYWAVELINE
)
2763 rFont
.SetUnderline( UNDERLINE_WAVE
);
2765 pOut
->SetTextLineColor( Color( COL_LIGHTGRAY
) );
2770 void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric
& rCurMetrics
, SvxFont
& rFont
)
2772 // Fuer Zeilenhoehe bei Hoch/Tief erstmal ohne Propr!
2773 sal_uInt16 nPropr
= rFont
.GetPropr();
2774 DBG_ASSERT( ( nPropr
== 100 ) || rFont
.GetEscapement(), "Propr ohne Escape?!" );
2775 if ( nPropr
!= 100 )
2777 rFont
.SetPropr( 100 );
2778 rFont
.SetPhysFont( pRefDev
);
2780 sal_uInt16 nAscent
, nDescent
;
2782 FontMetric
aMetric( pRefDev
->GetFontMetric() );
2783 nAscent
= (sal_uInt16
)aMetric
.GetAscent();
2784 if ( IsAddExtLeading() )
2785 nAscent
= sal::static_int_cast
< sal_uInt16
>(
2786 nAscent
+ aMetric
.GetExtLeading() );
2787 nDescent
= (sal_uInt16
)aMetric
.GetDescent();
2789 if ( IsFixedCellHeight() )
2791 /* creating correct proportional ascent and descent values lead to problems if different fonts are used
2792 in the same portion, it results in a bigger linespacing.
2793 sal_Int32 f = nAscent + nDescent;
2796 sal_Int32 nHeight = ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() );
2797 nAscent = (sal_Int16)(( nHeight * nAscent ) / f );
2798 nDescent = (sal_Int16)(nHeight - nAscent);
2801 nAscent
= sal::static_int_cast
< sal_uInt16
>( rFont
.GetHeight() );
2802 nDescent
= sal::static_int_cast
< sal_uInt16
>( ImplCalculateFontIndependentLineSpacing( rFont
.GetHeight() ) - nAscent
);
2806 sal_uInt16 nIntLeading
= ( aMetric
.GetIntLeading() > 0 ) ? (sal_uInt16
)aMetric
.GetIntLeading() : 0;
2807 // Fonts ohne Leading bereiten Probleme
2808 if ( ( nIntLeading
== 0 ) && ( pRefDev
->GetOutDevType() == OUTDEV_PRINTER
) )
2810 // Da schaun wir mal, was fuer eine Leading ich auf dem
2811 // Bildschirm erhalte
2812 VirtualDevice
* pVDev
= GetVirtualDevice( pRefDev
->GetMapMode(), pRefDev
->GetDrawMode() );
2813 rFont
.SetPhysFont( pVDev
);
2814 aMetric
= pVDev
->GetFontMetric();
2816 // Damit sich die Leading nicht wieder rausrechnet,
2817 // wenn die ganze Zeile den Font hat, nTmpLeading.
2819 // 4/96: Kommt bei HP Laserjet 4V auch nicht hin
2820 // => Werte komplett vom Bildschirm holen.
2821 // sal_uInt16 nTmpLeading = (sal_uInt16)aMetric.GetLeading();
2822 // nAscent += nTmpLeading;
2823 nAscent
= (sal_uInt16
)aMetric
.GetAscent();
2824 nDescent
= (sal_uInt16
)aMetric
.GetDescent();
2825 // nLeading = (sal_uInt16)aMetric.GetLeading();
2828 if ( nAscent
> rCurMetrics
.nMaxAscent
)
2829 rCurMetrics
.nMaxAscent
= nAscent
;
2830 if ( nDescent
> rCurMetrics
.nMaxDescent
)
2831 rCurMetrics
.nMaxDescent
= nDescent
;
2832 // Sonderbehandlung Hoch/Tief:
2833 if ( rFont
.GetEscapement() )
2835 // Jetzt unter Beruecksichtigung von Escape/Propr
2836 // Ascent oder Descent ggf vergroessern
2837 short nDiff
= (short)(rFont
.GetSize().Height()*rFont
.GetEscapement()/100L);
2838 if ( rFont
.GetEscapement() > 0 )
2840 nAscent
= (sal_uInt16
) (((long)nAscent
)*nPropr
/100 + nDiff
);
2841 if ( nAscent
> rCurMetrics
.nMaxAscent
)
2842 rCurMetrics
.nMaxAscent
= nAscent
;
2844 else // muss < 0 sein
2846 nDescent
= (sal_uInt16
) (((long)nDescent
)*nPropr
/100 - nDiff
);
2847 if ( nDescent
> rCurMetrics
.nMaxDescent
)
2848 rCurMetrics
.nMaxDescent
= nDescent
;
2853 void ImpEditEngine::Paint( OutputDevice
* pOutDev
, Rectangle aClipRec
, Point aStartPos
, sal_Bool bStripOnly
, short nOrientation
)
2855 if ( !GetUpdateMode() && !bStripOnly
)
2858 if ( !IsFormatted() )
2861 long nFirstVisXPos
= - pOutDev
->GetMapMode().GetOrigin().X();
2862 long nFirstVisYPos
= - pOutDev
->GetMapMode().GetOrigin().Y();
2866 Point aRedLineTmpPos
;
2867 DBG_ASSERT( GetParaPortions().Count(), "Keine ParaPortion?!" );
2868 SvxFont
aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() );
2869 Font
aOldFont( pOutDev
->GetFont() );
2870 vcl::PDFExtOutDevData
* pPDFExtOutDevData
= PTR_CAST( vcl::PDFExtOutDevData
, pOutDev
->GetExtOutDevData() );
2872 // Bei gedrehtem Text wird aStartPos als TopLeft angesehen, da andere
2873 // Informationen fehlen, und sowieso das ganze Object ungescrollt
2874 // dargestellt wird.
2875 // Das Rechteck ist unendlich gross.
2876 Point
aOrigin( aStartPos
);
2877 double nCos
= 0.0, nSin
= 0.0;
2880 double nRealOrientation
= nOrientation
*F_PI1800
;
2881 nCos
= cos( nRealOrientation
);
2882 nSin
= sin( nRealOrientation
);
2885 // #110496# Added some more optional metafile comments. This
2886 // change: factored out some duplicated code.
2887 GDIMetaFile
* pMtf
= pOutDev
->GetConnectMetaFile();
2888 const bool bMetafileValid( pMtf
!= NULL
);
2890 // Fuer OnlineSpelling:
2891 // EditPaM aCursorPos;
2892 // if( GetStatus().DoOnlineSpelling() && pActiveView )
2893 // aCurPos = pActiveView->pImpEditView->GetEditSelections().Max();
2895 // --------------------------------------------------
2896 // Ueber alle Absaetze...
2897 // --------------------------------------------------
2898 for ( sal_uInt16 n
= 0; n
< GetParaPortions().Count(); n
++ )
2900 ParaPortion
* pPortion
= GetParaPortions().GetObject( n
);
2901 DBG_ASSERT( pPortion
, "NULL-Pointer in TokenList in Paint" );
2902 // falls beim Tippen Idle-Formatierung, asynchrones Paint.
2903 // Unsichtbare Portions koennen ungueltig sein.
2904 if ( pPortion
->IsVisible() && pPortion
->IsInvalid() )
2907 if ( pPDFExtOutDevData
)
2908 pPDFExtOutDevData
->BeginStructureElement( vcl::PDFWriter::Paragraph
);
2910 long nParaHeight
= pPortion
->GetHeight();
2911 sal_uInt16 nIndex
= 0;
2912 if ( pPortion
->IsVisible() && (
2913 ( !IsVertical() && ( ( aStartPos
.Y() + nParaHeight
) > aClipRec
.Top() ) ) ||
2914 ( IsVertical() && ( ( aStartPos
.X() - nParaHeight
) < aClipRec
.Right() ) ) ) )
2917 // --------------------------------------------------
2918 // Ueber die Zeilen des Absatzes...
2919 // --------------------------------------------------
2920 sal_uInt16 nLines
= pPortion
->GetLines().Count();
2921 sal_uInt16 nLastLine
= nLines
-1;
2923 if ( !IsVertical() )
2924 aStartPos
.Y() += pPortion
->GetFirstLineOffset();
2926 aStartPos
.X() -= pPortion
->GetFirstLineOffset();
2928 Point
aParaStart( aStartPos
);
2930 const SvxLineSpacingItem
& rLSItem
= ((const SvxLineSpacingItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
));
2931 sal_uInt16 nSBL
= ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
)
2932 ? GetYValue( rLSItem
.GetInterLineSpace() ) : 0;
2933 for ( sal_uInt16 nLine
= 0; nLine
< nLines
; nLine
++ )
2935 pLine
= pPortion
->GetLines().GetObject(nLine
);
2936 DBG_ASSERT( pLine
, "NULL-Pointer im Zeileniterator in UpdateViews" );
2937 aTmpPos
= aStartPos
;
2938 if ( !IsVertical() )
2940 aTmpPos
.X() += pLine
->GetStartPosX();
2941 aTmpPos
.Y() += pLine
->GetMaxAscent();
2942 aStartPos
.Y() += pLine
->GetHeight();
2946 aTmpPos
.Y() += pLine
->GetStartPosX();
2947 aTmpPos
.X() -= pLine
->GetMaxAscent();
2948 aStartPos
.X() -= pLine
->GetHeight();
2951 if ( ( !IsVertical() && ( aStartPos
.Y() > aClipRec
.Top() ) )
2952 || ( IsVertical() && aStartPos
.X() < aClipRec
.Right() ) )
2954 // Why not just also call when stripping portions? This will give the correct values
2955 // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call
2956 // PaintBullet correctly; exactly what GetEditEnginePtr()->PaintingFirstLine
2957 // does, too. No change for not-layouting (painting).
2958 if(0 == nLine
) // && !bStripOnly)
2961 GetEditEnginePtr()->PaintingFirstLine( n
, aParaStart
, aTmpPos
.Y(), aOrigin
, nOrientation
, pOutDev
);
2964 // --------------------------------------------------
2965 // Ueber die Portions der Zeile...
2966 // --------------------------------------------------
2967 nIndex
= pLine
->GetStart();
2968 for ( sal_uInt16 y
= pLine
->GetStartPortion(); y
<= pLine
->GetEndPortion(); y
++ )
2970 DBG_ASSERT( pPortion
->GetTextPortions().Count(), "Zeile ohne Textportion im Paint!" );
2971 TextPortion
* pTextPortion
= pPortion
->GetTextPortions().GetObject( y
);
2972 DBG_ASSERT( pTextPortion
, "NULL-Pointer im Portioniterator in UpdateViews" );
2974 long nPortionXOffset
= GetPortionXOffset( pPortion
, pLine
, y
);
2975 if ( !IsVertical() )
2977 aTmpPos
.X() = aStartPos
.X() + nPortionXOffset
;
2978 if ( aTmpPos
.X() > aClipRec
.Right() )
2979 break; // Keine weitere Ausgabe in Zeile noetig
2983 aTmpPos
.Y() = aStartPos
.Y() + nPortionXOffset
;
2984 if ( aTmpPos
.Y() > aClipRec
.Bottom() )
2985 break; // Keine weitere Ausgabe in Zeile noetig
2988 // R2L replaces with obove...
2989 // New position after processing R2L text...
2990 // R2L if ( nR2LWidth && !pTextPortion->GetRightToLeft() )
2992 // R2L if ( !IsVertical() )
2993 // R2L aTmpPos.X() += nR2LWidth;
2995 // R2L aTmpPos.Y() += nR2LWidth;
2997 // R2L nR2LWidth = 0;
3000 switch ( pTextPortion
->GetKind() )
3002 case PORTIONKIND_TEXT
:
3003 case PORTIONKIND_FIELD
:
3004 case PORTIONKIND_HYPHENATOR
:
3006 SeekCursor( pPortion
->GetNode(), nIndex
+1, aTmpFont
, pOutDev
);
3008 BOOL bDrawFrame
= FALSE
;
3010 if ( ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
) && !aTmpFont
.IsTransparent() &&
3011 ( GetBackgroundColor() != COL_AUTO
) && GetBackgroundColor().IsDark() &&
3012 ( IsAutoColorEnabled() && ( pOutDev
->GetOutDevType() != OUTDEV_PRINTER
) ) )
3014 aTmpFont
.SetTransparent( TRUE
);
3015 pOutDev
->SetFillColor();
3016 pOutDev
->SetLineColor( GetAutoColor() );
3021 if ( pTextPortion
->GetKind() == PORTIONKIND_HYPHENATOR
)
3023 aTmpFont
.SetFillColor( COL_LIGHTGRAY
);
3024 aTmpFont
.SetTransparent( sal_False
);
3026 if ( pTextPortion
->GetRightToLeft() )
3028 aTmpFont
.SetFillColor( COL_LIGHTGRAY
);
3029 aTmpFont
.SetTransparent( sal_False
);
3031 else if ( GetScriptType( EditPaM( pPortion
->GetNode(), nIndex
+1 ) ) == i18n::ScriptType::COMPLEX
)
3033 aTmpFont
.SetFillColor( COL_LIGHTCYAN
);
3034 aTmpFont
.SetTransparent( sal_False
);
3037 aTmpFont
.SetPhysFont( pOutDev
);
3039 // #114278# Saving both layout mode and language (since I'm
3040 // potentially changing both)
3041 pOutDev
->Push( PUSH_TEXTLAYOUTMODE
|PUSH_TEXTLANGUAGE
);
3042 ImplInitLayoutMode( pOutDev
, n
, nIndex
);
3043 ImplInitDigitMode( pOutDev
, 0, 0, 0, aTmpFont
.GetLanguage() );
3046 USHORT nTextStart
= 0;
3047 USHORT nTextLen
= 0;
3048 const sal_Int32
* pDXArray
= 0;
3049 sal_Int32
* pTmpDXArray
= 0;
3051 if ( pTextPortion
->GetKind() == PORTIONKIND_TEXT
)
3053 aText
= *pPortion
->GetNode();
3054 nTextStart
= nIndex
;
3055 nTextLen
= pTextPortion
->GetLen();
3056 pDXArray
= pLine
->GetCharPosArray().GetData()+( nIndex
-pLine
->GetStart() );
3058 // --> FME 2005-10-18 #i55716# Paint control characters
3059 if ( aStatus
.MarkFields() )
3062 const xub_StrLen nTmpEnd
= nTextStart
+ pTextPortion
->GetLen();
3064 for ( nTmpIdx
= nTextStart
; nTmpIdx
<= nTmpEnd
; ++nTmpIdx
)
3066 const sal_Unicode cChar
= ( nTmpIdx
!= aText
.Len() && ( nTmpIdx
!= nTextStart
|| 0 == nTextStart
) ) ?
3067 aText
.GetChar( nTmpIdx
) :
3070 if ( 0x200B == cChar
|| 0x2060 == cChar
)
3072 const String
aBlank( ' ' );
3073 long nHalfBlankWidth
= aTmpFont
.QuickGetTextSize( pOutDev
, aBlank
, 0, 1, 0 ).Width() / 2;
3075 const long nAdvanceX
= ( nTmpIdx
== nTmpEnd
?
3076 pTextPortion
->GetSize().Width() :
3077 pDXArray
[ nTmpIdx
- nTextStart
] ) - nHalfBlankWidth
;
3078 const long nAdvanceY
= -pLine
->GetMaxAscent();
3080 Point
aTopLeftRectPos( aTmpPos
);
3081 if ( !IsVertical() )
3083 aTopLeftRectPos
.X() += nAdvanceX
;
3084 aTopLeftRectPos
.Y() += nAdvanceY
;
3088 aTopLeftRectPos
.Y() += nAdvanceX
;
3089 aTopLeftRectPos
.X() -= nAdvanceY
;
3092 Point
aBottomRightRectPos( aTopLeftRectPos
);
3093 if ( !IsVertical() )
3095 aBottomRightRectPos
.X() += 2 * nHalfBlankWidth
;
3096 aBottomRightRectPos
.Y() += pLine
->GetHeight();
3100 aBottomRightRectPos
.X() -= pLine
->GetHeight();
3101 aBottomRightRectPos
.Y() += 2 * nHalfBlankWidth
;
3104 pOutDev
->Push( PUSH_FILLCOLOR
);
3105 pOutDev
->Push( PUSH_LINECOLOR
);
3106 pOutDev
->SetFillColor( COL_LIGHTGRAY
);
3107 pOutDev
->SetLineColor( COL_LIGHTGRAY
);
3109 const Rectangle
aBackRect( aTopLeftRectPos
, aBottomRightRectPos
);
3110 pOutDev
->DrawRect( aBackRect
);
3115 if ( 0x200B == cChar
)
3117 const String
aSlash( '/' );
3118 const short nOldEscapement
= aTmpFont
.GetEscapement();
3119 const BYTE nOldPropr
= aTmpFont
.GetPropr();
3121 aTmpFont
.SetEscapement( -20 );
3122 aTmpFont
.SetPropr( 25 );
3123 aTmpFont
.SetPhysFont( pOutDev
);
3125 const Size aSlashSize
= aTmpFont
.QuickGetTextSize( pOutDev
, aSlash
, 0, 1, 0 );
3126 Point
aSlashPos( aTmpPos
);
3127 const long nAddX
= nHalfBlankWidth
- aSlashSize
.Width() / 2;
3128 if ( !IsVertical() )
3130 aSlashPos
.X() = aTopLeftRectPos
.X() + nAddX
;
3134 aSlashPos
.Y() = aTopLeftRectPos
.Y() + nAddX
;
3137 aTmpFont
.QuickDrawText( pOutDev
, aSlashPos
, aSlash
, 0, 1, 0 );
3139 aTmpFont
.SetEscapement( nOldEscapement
);
3140 aTmpFont
.SetPropr( nOldPropr
);
3141 aTmpFont
.SetPhysFont( pOutDev
);
3148 else if ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
)
3150 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature( nIndex
);
3151 DBG_ASSERT( pAttr
, "Feld nicht gefunden" );
3152 DBG_ASSERT( pAttr
&& pAttr
->GetItem()->ISA( SvxFieldItem
), "Feld vom falschen Typ!" );
3153 aText
= ((EditCharAttribField
*)pAttr
)->GetFieldValue();
3155 nTextLen
= aText
.Len();
3157 pTmpDXArray
= new sal_Int32
[ aText
.Len() ];
3158 pDXArray
= pTmpDXArray
;
3159 Font
_aOldFont( GetRefDevice()->GetFont() );
3160 aTmpFont
.SetPhysFont( GetRefDevice() );
3161 aTmpFont
.QuickGetTextSize( GetRefDevice(), aText
, 0, aText
.Len(), pTmpDXArray
);
3162 if ( aStatus
.DoRestoreFont() )
3163 GetRefDevice()->SetFont( _aOldFont
);
3165 // add a meta file comment if we record to a metafile
3166 if( bMetafileValid
)
3168 SvxFieldItem
* pFieldItem
= PTR_CAST( SvxFieldItem
, pAttr
->GetItem() );
3171 const SvxFieldData
* pFieldData
= pFieldItem
->GetField();
3173 pMtf
->AddAction( pFieldData
->createBeginComment() );
3178 else if ( pTextPortion
->GetKind() == PORTIONKIND_HYPHENATOR
)
3180 if ( pTextPortion
->GetExtraValue() )
3181 aText
= pTextPortion
->GetExtraValue();
3184 nTextLen
= aText
.Len();
3186 // #b6668980# crash when accessing 0 pointer in pDXArray
3187 pTmpDXArray
= new sal_Int32
[ aText
.Len() ];
3188 pDXArray
= pTmpDXArray
;
3189 Font
_aOldFont( GetRefDevice()->GetFont() );
3190 aTmpFont
.SetPhysFont( GetRefDevice() );
3191 aTmpFont
.QuickGetTextSize( GetRefDevice(), aText
, 0, aText
.Len(), pTmpDXArray
);
3192 if ( aStatus
.DoRestoreFont() )
3193 GetRefDevice()->SetFont( _aOldFont
);
3196 long nTxtWidth
= pTextPortion
->GetSize().Width();
3198 Point
aOutPos( aTmpPos
);
3199 aRedLineTmpPos
= aTmpPos
;
3200 // In RTL portions spell markup pos should be at the start of the
3201 // first chara as well. That is on the right end of the portion
3202 if (pTextPortion
->IsRightToLeft())
3203 aRedLineTmpPos
.X() += pTextPortion
->GetSize().Width();
3205 //L2R if ( pTextPortion->GetRightToLeft() )
3207 //L2R sal_uInt16 nNextPortion = y+1;
3208 //L2R while ( nNextPortion <= pLine->GetEndPortion() )
3210 //L2R TextPortion* pNextTextPortion = pPortion->GetTextPortions().GetObject( nNextPortion );
3211 //L2R if ( pNextTextPortion->GetRightToLeft() )
3213 //L2R if ( !IsVertical() )
3214 //L2R aOutPos.X() += pNextTextPortion->GetSize().Width();
3216 //L2R aOutPos.Y() += pNextTextPortion->GetSize().Width();
3220 //L2R nNextPortion++;
3225 EEngineData::WrongSpellVector aWrongSpellVector
;
3227 if(GetStatus().DoOnlineSpelling() && pTextPortion
->GetLen())
3229 WrongList
* pWrongs
= pPortion
->GetNode()->GetWrongList();
3231 if(pWrongs
&& pWrongs
->HasWrongs())
3233 sal_uInt16
nStart(nIndex
);
3235 sal_Bool
bWrong(pWrongs
->NextWrong(nStart
, nEnd
));
3236 const sal_uInt16
nMaxEnd(nIndex
+ pTextPortion
->GetLen());
3240 if(nStart
>= nMaxEnd
)
3256 aWrongSpellVector
.push_back(EEngineData::WrongSpellClass(nStart
, nEnd
));
3263 bWrong
= pWrongs
->NextWrong(nStart
, nEnd
);
3273 const SvxFieldData
* pFieldData
= 0;
3275 if(PORTIONKIND_FIELD
== pTextPortion
->GetKind())
3277 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature(nIndex
);
3278 SvxFieldItem
* pFieldItem
= PTR_CAST(SvxFieldItem
, pAttr
->GetItem());
3282 pFieldData
= pFieldItem
->GetField();
3286 // support for EOC, EOW, EOS TEXT comments. To support that,
3287 // the locale is needed. With the locale and a XBreakIterator it is
3288 // possible to re-create the text marking info on primitive level
3289 const lang::Locale
aLocale(GetLocale(EditPaM(pPortion
->GetNode(), nIndex
+ 1)));
3291 // create EOL and EOP bools
3292 const bool bEndOfLine(y
== pLine
->GetEndPortion());
3293 const bool bEndOfParagraph(bEndOfLine
&& nLine
+ 1 == nLines
);
3295 // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in
3296 // consequence, but also already set at pOutDev)
3297 const Color
aOverlineColor(pOutDev
->GetOverlineColor());
3299 // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in
3300 // consequence, but also already set at pOutDev)
3301 const Color
aTextLineColor(pOutDev
->GetTextLineColor());
3303 // Unicode code points conversion according to ctl text numeral setting
3304 ImplInitDigitMode( 0, &aText
, nTextStart
, nTextLen
, aTmpFont
.GetLanguage() );
3306 // StripPortions() data callback
3307 GetEditEnginePtr()->DrawingText( aOutPos
, aText
, nTextStart
, nTextLen
, pDXArray
,
3308 aTmpFont
, n
, nIndex
, pTextPortion
->GetRightToLeft(),
3309 aWrongSpellVector
.size() ? &aWrongSpellVector
: 0,
3311 bEndOfLine
, bEndOfParagraph
, false, // support for EOL/EOP TEXT comments
3318 short nEsc
= aTmpFont
.GetEscapement();
3321 // Bei Hoch/Tief selbst Hand anlegen:
3322 if ( aTmpFont
.GetEscapement() )
3324 long nDiff
= aTmpFont
.GetSize().Height() * aTmpFont
.GetEscapement() / 100L;
3325 if ( !IsVertical() )
3326 aOutPos
.Y() -= nDiff
;
3328 aOutPos
.X() += nDiff
;
3329 aRedLineTmpPos
= aOutPos
;
3330 aTmpFont
.SetEscapement( 0 );
3333 aOutPos
= lcl_ImplCalcRotatedPos( aOutPos
, aOrigin
, nSin
, nCos
);
3334 aTmpFont
.SetOrientation( aTmpFont
.GetOrientation()+nOrientation
);
3335 aTmpFont
.SetPhysFont( pOutDev
);
3338 // nur ausgeben, was im sichtbaren Bereich beginnt:
3339 // Wichtig, weil Bug bei einigen Grafikkarten bei transparentem Font, Ausgabe bei neg.
3340 if ( nOrientation
|| ( !IsVertical() && ( ( aTmpPos
.X() + nTxtWidth
) >= nFirstVisXPos
) )
3341 || ( IsVertical() && ( ( aTmpPos
.Y() + nTxtWidth
) >= nFirstVisYPos
) ) )
3343 if ( nEsc
&& ( ( aTmpFont
.GetUnderline() != UNDERLINE_NONE
) ) )
3345 // Das Hoch/Tief ohne Underline malen, das Underline
3346 // auf der BaseLine der Original-Fonthoehe ausgeben...
3348 // Aber nur, wenn davor auch Unterstrichen!
3349 sal_Bool bSpecialUnderline
= sal_False
;
3350 EditCharAttrib
* pPrev
= pPortion
->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT
, nIndex
);
3354 // Unterstreichung davor?
3355 if ( pPrev
->GetStart() )
3357 SeekCursor( pPortion
->GetNode(), pPrev
->GetStart(), aDummy
);
3358 if ( aDummy
.GetUnderline() != UNDERLINE_NONE
)
3359 bSpecialUnderline
= sal_True
;
3361 if ( !bSpecialUnderline
&& ( pPrev
->GetEnd() < pPortion
->GetNode()->Len() ) )
3363 SeekCursor( pPortion
->GetNode(), pPrev
->GetEnd()+1, aDummy
);
3364 if ( aDummy
.GetUnderline() != UNDERLINE_NONE
)
3365 bSpecialUnderline
= sal_True
;
3368 if ( bSpecialUnderline
)
3370 Size aSz
= aTmpFont
.GetPhysTxtSize( pOutDev
, aText
, nTextStart
, nTextLen
);
3371 BYTE nProp
= aTmpFont
.GetPropr();
3372 aTmpFont
.SetEscapement( 0 );
3373 aTmpFont
.SetPropr( 100 );
3374 aTmpFont
.SetPhysFont( pOutDev
);
3376 aBlanks
.Fill( nTextLen
, ' ' );
3377 Point
aUnderlinePos( aOutPos
);
3379 aUnderlinePos
= lcl_ImplCalcRotatedPos( aTmpPos
, aOrigin
, nSin
, nCos
);
3380 pOutDev
->DrawStretchText( aUnderlinePos
, aSz
.Width(), aBlanks
, 0, nTextLen
);
3382 aTmpFont
.SetUnderline( UNDERLINE_NONE
);
3383 if ( !nOrientation
)
3384 aTmpFont
.SetEscapement( nEsc
);
3385 aTmpFont
.SetPropr( nProp
);
3386 aTmpFont
.SetPhysFont( pOutDev
);
3389 Point
aRealOutPos( aOutPos
);
3390 if ( ( pTextPortion
->GetKind() == PORTIONKIND_TEXT
)
3391 && pTextPortion
->GetExtraInfos() && pTextPortion
->GetExtraInfos()->bCompressed
3392 && pTextPortion
->GetExtraInfos()->bFirstCharIsRightPunktuation
)
3394 aRealOutPos
.X() += pTextPortion
->GetExtraInfos()->nPortionOffsetX
;
3397 // --> FME 2005-06-17 #i37132# RTL portions with
3398 // compressed blank should not paint this blank:
3399 if ( pTextPortion
->IsRightToLeft() && nTextLen
>= 2 &&
3400 pDXArray
[ nTextLen
- 1 ] ==
3401 pDXArray
[ nTextLen
- 2 ] &&
3402 ' ' == aText
.GetChar( nTextStart
+ nTextLen
- 1 ) )
3407 aTmpFont
.QuickDrawText( pOutDev
, aRealOutPos
, aText
, nTextStart
, nTextLen
, pDXArray
);
3411 Point
aTopLeft( aTmpPos
);
3412 aTopLeft
.Y() -= pLine
->GetMaxAscent();
3414 aTopLeft
= lcl_ImplCalcRotatedPos( aTopLeft
, aOrigin
, nSin
, nCos
);
3415 Rectangle
aRect( aTopLeft
, pTextPortion
->GetSize() );
3416 pOutDev
->DrawRect( aRect
);
3421 if ( pPDFExtOutDevData
)
3423 if ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
)
3425 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature( nIndex
);
3426 SvxFieldItem
* pFieldItem
= PTR_CAST( SvxFieldItem
, pAttr
->GetItem() );
3429 const SvxFieldData
* pFieldData
= pFieldItem
->GetField();
3430 if ( pFieldData
->ISA( SvxURLField
) )
3432 Point
aTopLeft( aTmpPos
);
3433 aTopLeft
.Y() -= pLine
->GetMaxAscent();
3434 // if ( nOrientation )
3435 // aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos );
3437 Rectangle
aRect( aTopLeft
, pTextPortion
->GetSize() );
3438 vcl::PDFExtOutDevBookmarkEntry aBookmark
;
3439 aBookmark
.nLinkId
= pPDFExtOutDevData
->CreateLink( aRect
);
3440 aBookmark
.aBookmark
= ((SvxURLField
*)pFieldData
)->GetURL();
3441 std::vector
< vcl::PDFExtOutDevBookmarkEntry
>& rBookmarks
= pPDFExtOutDevData
->GetBookmarks();
3442 rBookmarks
.push_back( aBookmark
);
3456 if ( GetStatus().DoOnlineSpelling() && pPortion
->GetNode()->GetWrongList()->HasWrongs() && pTextPortion
->GetLen() )
3458 {//#105750# adjust LinePos for superscript or subscript text
3459 short _nEsc
= aTmpFont
.GetEscapement();
3462 long nShift
= ((_nEsc
*long(aTmpFont
.GetSize().Height()))/ 100L);
3464 aRedLineTmpPos
.Y() -= nShift
;
3466 aRedLineTmpPos
.X() += nShift
;
3469 Color
aOldColor( pOutDev
->GetLineColor() );
3470 pOutDev
->SetLineColor( Color( GetColorConfig().GetColorValue( svtools::SPELL
).nColor
) );
3471 lcl_DrawRedLines( pOutDev
, aTmpFont
.GetSize().Height(), aRedLineTmpPos
, nIndex
, nIndex
+ pTextPortion
->GetLen(), pDXArray
, pPortion
->GetNode()->GetWrongList(), nOrientation
, aOrigin
, IsVertical(), pTextPortion
->IsRightToLeft() );
3472 pOutDev
->SetLineColor( aOldColor
);
3474 #endif // !SVX_LIGHT
3480 delete[] pTmpDXArray
;
3482 // R2L if ( !pTextPortion->GetRightToLeft() )
3484 // R2L if ( !IsVertical() )
3485 // R2L aTmpPos.X() += nTxtWidth;
3487 // R2L aTmpPos.Y() += nTxtWidth;
3491 // R2L nR2LWidth += nTxtWidth;
3494 if ( pTextPortion
->GetKind() == PORTIONKIND_FIELD
)
3496 EditCharAttrib
* pAttr
= pPortion
->GetNode()->GetCharAttribs().FindFeature( nIndex
);
3497 DBG_ASSERT( pAttr
, "Feld nicht gefunden" );
3498 DBG_ASSERT( pAttr
&& pAttr
->GetItem()->ISA( SvxFieldItem
), "Feld vom falschen Typ!" );
3500 // add a meta file comment if we record to a metafile
3501 if( bMetafileValid
)
3503 SvxFieldItem
* pFieldItem
= PTR_CAST( SvxFieldItem
, pAttr
->GetItem() );
3507 const SvxFieldData
* pFieldData
= pFieldItem
->GetField();
3509 pMtf
->AddAction( pFieldData
->createEndComment() );
3517 // case PORTIONKIND_EXTRASPACE:
3518 case PORTIONKIND_TAB
:
3520 if ( pTextPortion
->GetExtraValue() && ( pTextPortion
->GetExtraValue() != ' ' ) )
3522 SeekCursor( pPortion
->GetNode(), nIndex
+1, aTmpFont
, pOutDev
);
3523 aTmpFont
.SetTransparent( sal_False
);
3524 aTmpFont
.SetEscapement( 0 );
3525 aTmpFont
.SetPhysFont( pOutDev
);
3526 long nCharWidth
= aTmpFont
.QuickGetTextSize( pOutDev
, pTextPortion
->GetExtraValue(), 0, 1, NULL
).Width();
3529 nChars
= pTextPortion
->GetSize().Width() / nCharWidth
;
3531 nChars
= 2; // wird durch DrawStretchText gestaucht.
3532 else if ( nChars
== 2 )
3533 nChars
= 3; // sieht besser aus
3536 aText
.Fill( (USHORT
)nChars
, pTextPortion
->GetExtraValue() );
3537 pOutDev
->DrawStretchText( aTmpPos
, pTextPortion
->GetSize().Width(), aText
);
3542 nIndex
= nIndex
+ pTextPortion
->GetLen();
3546 if ( ( nLine
!= nLastLine
) && !aStatus
.IsOutliner() )
3548 if ( !IsVertical() )
3549 aStartPos
.Y() += nSBL
;
3551 aStartPos
.X() -= nSBL
;
3554 // keine sichtbaren Aktionen mehr?
3555 if ( !IsVertical() && ( aStartPos
.Y() >= aClipRec
.Bottom() ) )
3557 else if ( IsVertical() && ( aStartPos
.X() <= aClipRec
.Left() ) )
3561 if ( !aStatus
.IsOutliner() )
3563 const SvxULSpaceItem
& rULItem
= (const SvxULSpaceItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
3564 long nUL
= GetYValue( rULItem
.GetLower() );
3565 if ( !IsVertical() )
3566 aStartPos
.Y() += nUL
;
3568 aStartPos
.X() -= nUL
;
3573 if ( !IsVertical() )
3574 aStartPos
.Y() += nParaHeight
;
3576 aStartPos
.X() -= nParaHeight
;
3579 if ( pPDFExtOutDevData
)
3580 pPDFExtOutDevData
->EndStructureElement();
3582 // keine sichtbaren Aktionen mehr?
3583 if ( !IsVertical() && ( aStartPos
.Y() > aClipRec
.Bottom() ) )
3585 if ( IsVertical() && ( aStartPos
.X() < aClipRec
.Left() ) )
3588 if ( aStatus
.DoRestoreFont() )
3589 pOutDev
->SetFont( aOldFont
);
3592 void ImpEditEngine::Paint( ImpEditView
* pView
, const Rectangle
& rRec
, sal_Bool bUseVirtDev
)
3594 DBG_ASSERT( pView
, "Keine View - Kein Paint!" );
3595 DBG_CHKOBJ( GetEditEnginePtr(), EditEngine
, 0 );
3597 if ( !GetUpdateMode() || IsInUndo() )
3600 // Schnittmenge aus Paintbereich und OutputArea.
3601 Rectangle
aClipRec( pView
->GetOutputArea() );
3602 aClipRec
.Intersection( rRec
);
3604 Window
* pOutWin
= pView
->GetWindow();
3608 Rectangle
aClipRecPixel( pOutWin
->LogicToPixel( aClipRec
) );
3609 if ( !IsVertical() )
3611 // etwas mehr, falls abgerundet!
3612 aClipRecPixel
.Right() += 1;
3613 aClipRecPixel
.Bottom() += 1;
3617 aClipRecPixel
.Left() -= 1;
3618 aClipRecPixel
.Bottom() += 1;
3621 // Wenn aClipRecPixel > XXXX, dann invalidieren ?!
3623 VirtualDevice
* pVDev
= GetVirtualDevice( pOutWin
->GetMapMode(), pOutWin
->GetDrawMode() );
3624 pVDev
->SetDigitLanguage( GetRefDevice()->GetDigitLanguage() );
3627 Color
aBackgroundColor( pView
->GetBackgroundColor() );
3628 // #i47161# Check if text is visible on background
3630 ContentNode
* pNode
= GetEditDoc().SaveGetObject( 0 );
3631 SeekCursor( pNode
, 1, aTmpFont
);
3632 Color
aFontColor( aTmpFont
.GetColor() );
3633 if( aFontColor
== COL_AUTO
)
3634 aFontColor
= GetAutoColor();
3636 // #i69346# check for reverse color of input method attribute
3637 if( mpIMEInfos
&& (mpIMEInfos
->aPos
.GetNode() == pNode
&&
3638 mpIMEInfos
->pAttribs
))
3640 sal_uInt16 nAttr
= mpIMEInfos
->pAttribs
[ 0 ];
3641 if ( nAttr
& EXTTEXTINPUT_ATTR_HIGHLIGHT
)
3643 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
3644 aFontColor
= rStyleSettings
.GetHighlightColor() ;
3648 UINT8 nColorDiff
= aFontColor
.GetColorError( aBackgroundColor
);
3649 if( nColorDiff
< 8 )
3650 aBackgroundColor
= aFontColor
.IsDark() ? COL_WHITE
: COL_BLACK
;
3651 pVDev
->SetBackground( aBackgroundColor
);
3654 sal_Bool bVDevValid
= sal_True
;
3655 Size
aOutSz( pVDev
->GetOutputSizePixel() );
3656 if ( ( aOutSz
.Width() < aClipRecPixel
.GetWidth() ) ||
3657 ( aOutSz
.Height() < aClipRecPixel
.GetHeight() ) )
3659 bVDevValid
= pVDev
->SetOutputSizePixel( aClipRecPixel
.GetSize() );
3663 // Das VirtDev kann bei einem Resize sehr gross werden =>
3664 // irgendwann mal kleiner machen!
3665 if ( ( aOutSz
.Height() > ( aClipRecPixel
.GetHeight() + RESDIFF
) ) ||
3666 ( aOutSz
.Width() > ( aClipRecPixel
.GetWidth() + RESDIFF
) ) )
3668 bVDevValid
= pVDev
->SetOutputSizePixel( aClipRecPixel
.GetSize() );
3675 DBG_ASSERT( bVDevValid
, "VDef konnte nicht vergroessert werden!" );
3678 Paint( pView
, rRec
, sal_False
/* ohne VDev */ );
3682 // PaintRect fuer VDev nicht mit alignter Groesse,
3683 // da sonst die Zeile darunter auch ausgegeben werden muss:
3684 Rectangle
aTmpRec( Point( 0, 0 ), aClipRec
.GetSize() );
3686 aClipRec
= pOutWin
->PixelToLogic( aClipRecPixel
);
3688 if ( !IsVertical() )
3690 aStartPos
= aClipRec
.TopLeft();
3691 aStartPos
= pView
->GetDocPos( aStartPos
);
3692 aStartPos
.X() *= (-1);
3693 aStartPos
.Y() *= (-1);
3697 aStartPos
= aClipRec
.TopRight();
3698 Point
aDocPos( pView
->GetDocPos( aStartPos
) );
3699 aStartPos
.X() = aClipRec
.GetSize().Width() + aDocPos
.Y();
3700 aStartPos
.Y() = -aDocPos
.X();
3703 Paint( pVDev
, aTmpRec
, aStartPos
);
3705 sal_Bool bClipRegion
= sal_False
;
3707 MapMode aOldMapMode
;
3708 if ( GetTextRanger() )
3710 // Some problems here with push/pop, why?!
3711 // pOutWin->Push( PUSH_CLIPREGION|PUSH_MAPMODE );
3712 bClipRegion
= pOutWin
->IsClipRegion();
3713 aOldRegion
= pOutWin
->GetClipRegion();
3714 // Wie bekomme ich das Polygon an die richtige Stelle????
3715 // Das Polygon bezieht sich auf die View, nicht auf das Window
3716 // => Origin umsetzen...
3717 aOldMapMode
= pOutWin
->GetMapMode();
3718 Point aOrigin
= aOldMapMode
.GetOrigin();
3719 Point aViewPos
= pView
->GetOutputArea().TopLeft();
3720 aOrigin
.Move( aViewPos
.X(), aViewPos
.Y() );
3721 aClipRec
.Move( -aViewPos
.X(), -aViewPos
.Y() );
3722 MapMode
aNewMapMode( aOldMapMode
);
3723 aNewMapMode
.SetOrigin( aOrigin
);
3724 pOutWin
->SetMapMode( aNewMapMode
);
3725 pOutWin
->SetClipRegion( Region( GetTextRanger()->GetPolyPolygon() ) );
3728 pOutWin
->DrawOutDev( aClipRec
.TopLeft(), aClipRec
.GetSize(),
3729 Point(0,0), aClipRec
.GetSize(), *pVDev
);
3731 if ( GetTextRanger() )
3735 pOutWin
->SetClipRegion( aOldRegion
);
3737 pOutWin
->SetClipRegion();
3738 pOutWin
->SetMapMode( aOldMapMode
);
3742 pView
->DrawSelection();
3747 if ( !IsVertical() )
3749 aStartPos
= pView
->GetOutputArea().TopLeft();
3750 aStartPos
.X() -= pView
->GetVisDocLeft();
3751 aStartPos
.Y() -= pView
->GetVisDocTop();
3755 aStartPos
= pView
->GetOutputArea().TopRight();
3756 aStartPos
.X() += pView
->GetVisDocTop();
3757 aStartPos
.Y() -= pView
->GetVisDocLeft();
3760 // Wenn Doc-Breite < OutputArea,Width, nicht umgebrochene Felder,
3761 // stehen die Felder sonst �ber, wenn > Zeile.
3762 // ( Oben nicht, da dort bereits Doc-Breite von Formatierung mit drin )
3763 if ( !IsVertical() && ( pView
->GetOutputArea().GetWidth() > GetPaperSize().Width() ) )
3765 long nMaxX
= pView
->GetOutputArea().Left() + GetPaperSize().Width();
3766 if ( aClipRec
.Left() > nMaxX
)
3768 if ( aClipRec
.Right() > nMaxX
)
3769 aClipRec
.Right() = nMaxX
;
3772 sal_Bool bClipRegion
= pOutWin
->IsClipRegion();
3773 Region aOldRegion
= pOutWin
->GetClipRegion();
3774 pOutWin
->IntersectClipRegion( aClipRec
);
3776 Paint( pOutWin
, aClipRec
, aStartPos
);
3779 pOutWin
->SetClipRegion( aOldRegion
);
3781 pOutWin
->SetClipRegion();
3783 pView
->DrawSelection();
3788 void ImpEditEngine::InsertContent( ContentNode
* pNode
, sal_uInt16 nPos
)
3790 DBG_ASSERT( pNode
, "NULL-Poointer in InsertContent! " );
3791 DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" );
3792 ParaPortion
* pNew
= new ParaPortion( pNode
);
3793 GetParaPortions().Insert( pNew
, nPos
);
3794 aEditDoc
.Insert( pNode
, nPos
);
3795 if ( IsCallParaInsertedOrDeleted() )
3796 GetEditEnginePtr()->ParagraphInserted( nPos
);
3799 EditPaM
ImpEditEngine::SplitContent( sal_uInt16 nNode
, sal_uInt16 nSepPos
)
3801 ContentNode
* pNode
= aEditDoc
.SaveGetObject( nNode
);
3802 DBG_ASSERT( pNode
, "Ungueltiger Node in SplitContent" );
3803 DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" );
3804 DBG_ASSERT( nSepPos
<= pNode
->Len(), "Index im Wald: SplitContent" );
3805 EditPaM
aPaM( pNode
, nSepPos
);
3806 return ImpInsertParaBreak( aPaM
);
3809 EditPaM
ImpEditEngine::ConnectContents( sal_uInt16 nLeftNode
, sal_Bool bBackward
)
3811 ContentNode
* pLeftNode
= aEditDoc
.SaveGetObject( nLeftNode
);
3812 ContentNode
* pRightNode
= aEditDoc
.SaveGetObject( nLeftNode
+1 );
3813 DBG_ASSERT( pLeftNode
, "Ungueltiger linker Node in ConnectContents" );
3814 DBG_ASSERT( pRightNode
, "Ungueltiger rechter Node in ConnectContents" );
3815 DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" );
3816 return ImpConnectParagraphs( pLeftNode
, pRightNode
, bBackward
);
3819 void ImpEditEngine::SetUpdateMode( sal_Bool bUp
, EditView
* pCurView
, sal_Bool bForceUpdate
)
3821 sal_Bool bChanged
= ( GetUpdateMode() != bUp
);
3823 // Beim Umschalten von sal_True auf sal_False waren alle Selektionen sichtbar,
3825 // Umgekehrt waren alle unsichtbar => malen
3827 // DrawAllSelections(); sieht im Outliner schlecht aus !
3828 // EditView* pView = aEditViewList.First();
3831 // DBG_CHKOBJ( pView, EditView, 0 );
3832 // pView->pImpEditView->DrawSelection();
3833 // pView = aEditViewList.Next();
3836 // Wenn !bFormatted, also z.B. nach SetText, braucht bei UpdateMode sal_True
3837 // nicht sofort formatiert werden, weil warscheinlich noch Text kommt.
3838 // Spaetestens bei einem Paint / CalcTextWidth wird formatiert.
3841 if ( bUpdate
&& ( bChanged
|| bForceUpdate
) )
3842 FormatAndUpdate( pCurView
);
3845 void ImpEditEngine::ShowParagraph( sal_uInt16 nParagraph
, sal_Bool bShow
)
3847 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3848 DBG_ASSERT( pPPortion
, "ShowParagraph: Absatz existiert nicht!" );
3849 if ( pPPortion
&& ( pPPortion
->IsVisible() != bShow
) )
3851 pPPortion
->SetVisible( bShow
);
3855 // Als deleted kenzeichnen, damit keine Selektion auf diesem
3856 // Absatz beginnt oder endet...
3857 DeletedNodeInfo
* pDelInfo
= new DeletedNodeInfo( (sal_uIntPtr
)pPPortion
->GetNode(), nParagraph
);
3858 aDeletedNodes
.Insert( pDelInfo
, aDeletedNodes
.Count() );
3860 // Dann kriege ich den unteren Bereich nicht invalidiert,
3861 // wenn UpdateMode = sal_False!
3862 // Wenn doch, dann vor SetVisible auf sal_False merken!
3863 // nCurTextHeight -= pPPortion->GetHeight();
3866 if ( bShow
&& ( pPPortion
->IsInvalid() || !pPPortion
->nHeight
) )
3868 if ( !GetTextRanger() )
3870 if ( pPPortion
->IsInvalid() )
3872 Font
aOldFont( GetRefDevice()->GetFont() );
3873 CreateLines( nParagraph
, 0 ); // 0: Kein TextRanger
3874 if ( aStatus
.DoRestoreFont() )
3875 GetRefDevice()->SetFont( aOldFont
);
3879 CalcHeight( pPPortion
);
3881 nCurTextHeight
+= pPPortion
->GetHeight();
3885 nCurTextHeight
= 0x7fffffff;
3889 pPPortion
->SetMustRepaint( sal_True
);
3890 if ( GetUpdateMode() && !IsInUndo() && !GetTextRanger() )
3892 aInvalidRec
= Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion
) ),
3893 Point( GetPaperSize().Width(), nCurTextHeight
) );
3894 UpdateViews( GetActiveView() );
3899 sal_Bool
ImpEditEngine::IsParagraphVisible( sal_uInt16 nParagraph
)
3901 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3902 DBG_ASSERT( pPPortion
, "IsParagraphVisible: Absatz existiert nicht!" );
3904 return pPPortion
->IsVisible();
3908 EditSelection
ImpEditEngine::MoveParagraphs( Range aOldPositions
, sal_uInt16 nNewPos
, EditView
* pCurView
)
3910 DBG_ASSERT( GetParaPortions().Count() != 0, "Keine Absaetze gefunden: MoveParagraphs" );
3911 if ( GetParaPortions().Count() == 0 )
3912 return EditSelection();
3913 aOldPositions
.Justify();
3915 EditSelection
aSel( ImpMoveParagraphs( aOldPositions
, nNewPos
) );
3917 if ( nNewPos
>= GetParaPortions().Count() )
3918 nNewPos
= GetParaPortions().Count() - 1;
3920 // Dort, wo der Absatz eingefuegt wurde, muss richtig gepainted werden:
3921 // Dort, wo der Absatz entfernt wurde, muss richtig gepainted werden:
3922 // ( Und dazwischen entsprechend auch...)
3923 if ( pCurView
&& ( GetUpdateMode() == sal_True
) )
3925 // in diesem Fall kann ich direkt neu malen, ohne die
3926 // Portions zu Invalidieren.
3927 sal_uInt16 nFirstPortion
= Min( (sal_uInt16
)aOldPositions
.Min(), nNewPos
);
3928 sal_uInt16 nLastPortion
= Max( (sal_uInt16
)aOldPositions
.Max(), nNewPos
);
3930 ParaPortion
* pUpperPortion
= GetParaPortions().SaveGetObject( nFirstPortion
);
3931 ParaPortion
* pLowerPortion
= GetParaPortions().SaveGetObject( nLastPortion
);
3933 aInvalidRec
= Rectangle(); // leermachen
3934 aInvalidRec
.Left() = 0;
3935 aInvalidRec
.Right() = aPaperSize
.Width();
3936 aInvalidRec
.Top() = GetParaPortions().GetYOffset( pUpperPortion
);
3937 aInvalidRec
.Bottom() = GetParaPortions().GetYOffset( pLowerPortion
) + pLowerPortion
->GetHeight();
3939 UpdateViews( pCurView
);
3943 // aber der oberen ungueltigen Position neu painten...
3944 sal_uInt16 nFirstInvPara
= Min( (sal_uInt16
)aOldPositions
.Min(), nNewPos
);
3945 InvalidateFromParagraph( nFirstInvPara
);
3950 void ImpEditEngine::InvalidateFromParagraph( sal_uInt16 nFirstInvPara
)
3952 // Es werden nicht die folgenden Absaetze invalidiert,
3953 // da ResetHeight() => Groessenanderung => alles folgende wird
3954 // sowieso neu ausgegeben.
3955 ParaPortion
* pTmpPortion
;
3956 if ( nFirstInvPara
!= 0 )
3958 pTmpPortion
= GetParaPortions().GetObject( nFirstInvPara
-1 );
3959 pTmpPortion
->MarkInvalid( pTmpPortion
->GetNode()->Len(), 0 );
3963 pTmpPortion
= GetParaPortions().GetObject( 0 );
3964 pTmpPortion
->MarkSelectionInvalid( 0, pTmpPortion
->GetNode()->Len() );
3966 pTmpPortion
->ResetHeight();
3969 IMPL_LINK_INLINE_START( ImpEditEngine
, StatusTimerHdl
, Timer
*, EMPTYARG
)
3974 IMPL_LINK_INLINE_END( ImpEditEngine
, StatusTimerHdl
, Timer
*, EMPTYARG
)
3976 void ImpEditEngine::CallStatusHdl()
3978 if ( aStatusHdlLink
.IsSet() && aStatus
.GetStatusWord() )
3980 // Der Status muss vor Call zurueckgesetzt werden,
3981 // da im Hdl evtl. weitere Fags gesetzt werden...
3982 EditStatus
aTmpStatus( aStatus
);
3984 aStatusHdlLink
.Call( &aTmpStatus
);
3985 aStatusTimer
.Stop(); // Falls von Hand gerufen...
3989 ContentNode
* ImpEditEngine::GetPrevVisNode( ContentNode
* pCurNode
)
3991 ParaPortion
* pPortion
= FindParaPortion( pCurNode
);
3992 DBG_ASSERT( pPortion
, "GetPrevVisibleNode: Keine passende Portion!" );
3993 pPortion
= GetPrevVisPortion( pPortion
);
3995 return pPortion
->GetNode();
3999 ContentNode
* ImpEditEngine::GetNextVisNode( ContentNode
* pCurNode
)
4001 ParaPortion
* pPortion
= FindParaPortion( pCurNode
);
4002 DBG_ASSERT( pPortion
, "GetNextVisibleNode: Keine passende Portion!" );
4003 pPortion
= GetNextVisPortion( pPortion
);
4005 return pPortion
->GetNode();
4009 ParaPortion
* ImpEditEngine::GetPrevVisPortion( ParaPortion
* pCurPortion
)
4011 sal_uInt16 nPara
= GetParaPortions().GetPos( pCurPortion
);
4012 DBG_ASSERT( nPara
< GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisPortion" );
4013 ParaPortion
* pPortion
= nPara
? GetParaPortions()[--nPara
] : 0;
4014 while ( pPortion
&& !pPortion
->IsVisible() )
4015 pPortion
= nPara
? GetParaPortions()[--nPara
] : 0;
4020 ParaPortion
* ImpEditEngine::GetNextVisPortion( ParaPortion
* pCurPortion
)
4022 sal_uInt16 nPara
= GetParaPortions().GetPos( pCurPortion
);
4023 DBG_ASSERT( nPara
< GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisNode" );
4024 ParaPortion
* pPortion
= GetParaPortions().SaveGetObject( ++nPara
);
4025 while ( pPortion
&& !pPortion
->IsVisible() )
4026 pPortion
= GetParaPortions().SaveGetObject( ++nPara
);
4031 EditPaM
ImpEditEngine::InsertParagraph( sal_uInt16 nPara
)
4036 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
-1 );
4038 pNode
= GetEditDoc().SaveGetObject( GetEditDoc().Count() - 1 );
4039 DBG_ASSERT( pNode
, "Kein einziger Absatz in InsertParagraph ?" );
4040 aPaM
= EditPaM( pNode
, pNode
->Len() );
4044 ContentNode
* pNode
= GetEditDoc().SaveGetObject( 0 );
4045 aPaM
= EditPaM( pNode
, 0 );
4048 return ImpInsertParaBreak( aPaM
);
4051 EditSelection
* ImpEditEngine::SelectParagraph( sal_uInt16 nPara
)
4053 EditSelection
* pSel
= 0;
4054 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
);
4055 DBG_ASSERTWARNING( pNode
, "Absatz existiert nicht: SelectParagraph" );
4057 pSel
= new EditSelection( EditPaM( pNode
, 0 ), EditPaM( pNode
, pNode
->Len() ) );
4062 void ImpEditEngine::FormatAndUpdate( EditView
* pCurView
)
4068 IdleFormatAndUpdate( pCurView
);
4072 UpdateViews( pCurView
);
4076 void ImpEditEngine::SetFlatMode( sal_Bool bFlat
)
4078 if ( bFlat
!= aStatus
.UseCharAttribs() )
4082 aStatus
.TurnOnFlags( EE_CNTRL_USECHARATTRIBS
);
4084 aStatus
.TurnOffFlags( EE_CNTRL_USECHARATTRIBS
);
4086 aEditDoc
.CreateDefFont( !bFlat
);
4089 UpdateViews( (EditView
*) 0);
4091 pActiveView
->ShowCursor();
4094 void ImpEditEngine::SetCharStretching( sal_uInt16 nX
, sal_uInt16 nY
)
4096 bool bChanged(false);
4097 if ( !IsVertical() )
4099 bChanged
= nStretchX
!=nX
|| nStretchY
!=nY
;
4105 bChanged
= nStretchX
!=nY
|| nStretchY
!=nX
;
4110 if (bChanged
&& aStatus
.DoStretch())
4113 // (potentially) need everything redrawn
4114 aInvalidRec
=Rectangle(0,0,1000000,1000000);
4115 UpdateViews( GetActiveView() );
4119 void ImpEditEngine::DoStretchChars( sal_uInt16 nX
, sal_uInt16 nY
)
4121 UndoActionStart( EDITUNDO_STRETCH
);
4122 sal_uInt16 nParas
= GetEditDoc().Count();
4123 for ( sal_uInt16 nPara
= 0; nPara
< nParas
; nPara
++ )
4125 ContentNode
* pNode
= GetEditDoc()[nPara
];
4126 SfxItemSet
aTmpSet( pNode
->GetContentAttribs().GetItems() );
4131 SvxCharScaleWidthItem
* pNewWidth
= (SvxCharScaleWidthItem
*) pNode
->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH
).Clone();
4132 sal_uInt32 nProp
= pNewWidth
->GetValue(); // sal_uInt32, kann temporaer gross werden
4135 pNewWidth
->SetValue( (sal_uInt16
)nProp
);
4136 aTmpSet
.Put( *pNewWidth
);
4140 const SvxKerningItem
& rKerningItem
=
4141 (const SvxKerningItem
&)pNode
->GetContentAttribs().GetItem( EE_CHAR_KERNING
);
4142 SvxKerningItem
* pNewKerning
= (SvxKerningItem
*)rKerningItem
.Clone();
4143 long nKerning
= pNewKerning
->GetValue();
4149 else if ( nKerning
< 0 )
4151 // Bei Negativen Werten:
4152 // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt.
4156 pNewKerning
->SetValue( (short)nKerning
);
4157 aTmpSet
.Put( *pNewKerning
);
4161 aTmpSet
.ClearItem( EE_CHAR_FONTWIDTH
);
4166 for ( int nItem
= 0; nItem
< 3; nItem
++ )
4168 USHORT nItemId
= EE_CHAR_FONTHEIGHT
;
4170 nItemId
= EE_CHAR_FONTHEIGHT_CJK
;
4171 else if ( nItem
== 2 )
4172 nItemId
= EE_CHAR_FONTHEIGHT_CTL
;
4174 const SvxFontHeightItem
& rHeightItem
=
4175 (const SvxFontHeightItem
&)pNode
->GetContentAttribs().GetItem( nItemId
);
4176 SvxFontHeightItem
* pNewHeight
= (SvxFontHeightItem
*)rHeightItem
.Clone();
4177 sal_uInt32 nHeight
= pNewHeight
->GetHeight();
4180 pNewHeight
->SetHeightValue( nHeight
);
4181 aTmpSet
.Put( *pNewHeight
);
4186 const SvxULSpaceItem
& rULSpaceItem
=
4187 (const SvxULSpaceItem
&)pNode
->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
4188 SvxULSpaceItem
* pNewUL
= (SvxULSpaceItem
*)rULSpaceItem
.Clone();
4189 sal_uInt32 nUpper
= pNewUL
->GetUpper();
4192 pNewUL
->SetUpper( (sal_uInt16
)nUpper
);
4193 sal_uInt32 nLower
= pNewUL
->GetLower();
4196 pNewUL
->SetLower( (sal_uInt16
)nLower
);
4197 aTmpSet
.Put( *pNewUL
);
4201 aTmpSet
.ClearItem( EE_CHAR_FONTHEIGHT
);
4203 SetParaAttribs( nPara
, aTmpSet
);
4206 sal_uInt16 nLastEnd
= 0; // damit nach entfernen und neu nicht nochmal
4207 CharAttribArray
& rAttribs
= pNode
->GetCharAttribs().GetAttribs();
4208 sal_uInt16 nAttribs
= rAttribs
.Count();
4209 for ( sal_uInt16 nAttr
= 0; nAttr
< nAttribs
; nAttr
++ )
4211 EditCharAttrib
* pAttr
= rAttribs
[nAttr
];
4212 if ( pAttr
->GetStart() >= nLastEnd
)
4214 sal_uInt16 nWhich
= pAttr
->Which();
4215 SfxPoolItem
* pNew
= 0;
4216 if ( nWhich
== EE_CHAR_FONTHEIGHT
)
4218 SvxFontHeightItem
* pNewHeight
= (SvxFontHeightItem
*)pAttr
->GetItem()->Clone();
4219 sal_uInt32 nHeight
= pNewHeight
->GetHeight();
4222 pNewHeight
->SetHeightValue( nHeight
);
4225 else if ( nWhich
== EE_CHAR_FONTWIDTH
)
4227 SvxCharScaleWidthItem
* pNewWidth
= (SvxCharScaleWidthItem
*)pAttr
->GetItem()->Clone();
4228 sal_uInt32 nProp
= pNewWidth
->GetValue();
4231 pNewWidth
->SetValue( (sal_uInt16
)nProp
);
4234 else if ( nWhich
== EE_CHAR_KERNING
)
4236 SvxKerningItem
* pNewKerning
= (SvxKerningItem
*)pAttr
->GetItem()->Clone();
4237 long nKerning
= pNewKerning
->GetValue();
4243 else if ( nKerning
< 0 )
4245 // Bei Negativen Werten:
4246 // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt.
4250 pNewKerning
->SetValue( (short)nKerning
);
4255 SfxItemSet
_aTmpSet( GetEmptyItemSet() );
4256 _aTmpSet
.Put( *pNew
);
4257 SetAttribs( EditSelection( EditPaM( pNode
, pAttr
->GetStart() ),
4258 EditPaM( pNode
, pAttr
->GetEnd() ) ), _aTmpSet
);
4260 nLastEnd
= pAttr
->GetEnd();
4266 UndoActionEnd( EDITUNDO_STRETCH
);
4269 const SvxNumberFormat
* ImpEditEngine::GetNumberFormat( const ContentNode
*pNode
) const
4271 const SvxNumberFormat
*pRes
= 0;
4275 // get index of paragraph
4276 USHORT nPara
= GetEditDoc().GetPos( const_cast< ContentNode
* >(pNode
) );
4277 DBG_ASSERT( nPara
< USHRT_MAX
, "node not found in array" );
4278 if (nPara
< USHRT_MAX
)
4280 // the called function may be overloaded by an OutlinerEditEng object to provide
4281 // access to the SvxNumberFormat of the Outliner.
4282 // The EditEngine implementation will just return 0.
4283 pRes
= pEditEngine
->GetNumberFormat( nPara
);
4290 sal_Int32
ImpEditEngine::GetSpaceBeforeAndMinLabelWidth(
4291 const ContentNode
*pNode
,
4292 sal_Int32
*pnSpaceBefore
, sal_Int32
*pnMinLabelWidth
) const
4294 // nSpaceBefore matches the ODF attribut text:space-before
4295 // nMinLabelWidth matches the ODF attribut text:min-label-width
4297 const SvxNumberFormat
*pNumFmt
= GetNumberFormat( pNode
);
4299 // if no number format was found we have no Outliner or the numbering level
4300 // within the Outliner is -1 which means no number format should be applied.
4301 // Thus the default values to be returned are 0.
4302 sal_Int32 nSpaceBefore
= 0;
4303 sal_Int32 nMinLabelWidth
= 0;
4307 nMinLabelWidth
= -pNumFmt
->GetFirstLineOffset();
4308 nSpaceBefore
= pNumFmt
->GetAbsLSpace() - nMinLabelWidth
;
4309 DBG_ASSERT( nMinLabelWidth
>= 0, "ImpEditEngine::GetSpaceBeforeAndMinLabelWidth: min-label-width < 0 encountered" );
4312 *pnSpaceBefore
= nSpaceBefore
;
4313 if (pnMinLabelWidth
)
4314 *pnMinLabelWidth
= nMinLabelWidth
;
4316 return nSpaceBefore
+ nMinLabelWidth
;
4319 const SvxLRSpaceItem
& ImpEditEngine::GetLRSpaceItem( ContentNode
* pNode
)
4321 return (const SvxLRSpaceItem
&)pNode
->GetContentAttribs().GetItem( aStatus
.IsOutliner() ? EE_PARA_OUTLLRSPACE
: EE_PARA_LRSPACE
);
4324 // Either sets the digit mode at the output device or
4325 // modifies the passed string according to the text numeral setting:
4326 void ImpEditEngine::ImplInitDigitMode( OutputDevice
* pOutDev
, String
* pString
, xub_StrLen nStt
, xub_StrLen nLen
, LanguageType eCurLang
)
4328 // #114278# Also setting up digit language from Svt options
4329 // (cannot reliably inherit the outdev's setting)
4331 pCTLOptions
= new SvtCTLOptions
;
4333 LanguageType eLang
= eCurLang
;
4334 const SvtCTLOptions::TextNumerals nCTLTextNumerals
= pCTLOptions
->GetCTLTextNumerals();
4336 if ( SvtCTLOptions::NUMERALS_HINDI
== nCTLTextNumerals
)
4337 eLang
= LANGUAGE_ARABIC_SAUDI_ARABIA
;
4338 else if ( SvtCTLOptions::NUMERALS_ARABIC
== nCTLTextNumerals
)
4339 eLang
= LANGUAGE_ENGLISH
;
4340 else if ( SvtCTLOptions::NUMERALS_SYSTEM
== nCTLTextNumerals
)
4341 eLang
= (LanguageType
) Application::GetSettings().GetLanguage();
4345 pOutDev
->SetDigitLanguage( eLang
);
4349 // see sallayout.cxx in vcl
4351 switch( eLang
& LANGUAGE_MASK_PRIMARY
)
4356 case LANGUAGE_ARABIC_SAUDI_ARABIA
& LANGUAGE_MASK_PRIMARY
:
4357 nOffset
= 0x0660 - '0'; // arabic-indic digits
4359 case LANGUAGE_URDU
& LANGUAGE_MASK_PRIMARY
:
4360 case LANGUAGE_PUNJABI
& LANGUAGE_MASK_PRIMARY
: //???
4361 case LANGUAGE_SINDHI
& LANGUAGE_MASK_PRIMARY
:
4362 nOffset
= 0x06F0 - '0'; // eastern arabic-indic digits
4367 const xub_StrLen nEnd
= nStt
+ nLen
;
4368 for( xub_StrLen nIdx
= nStt
; nIdx
< nEnd
; ++nIdx
)
4370 sal_Unicode nChar
= pString
->GetChar( nIdx
);
4371 if( (nChar
< '0') || ('9' < nChar
) )
4373 nChar
= (sal_Unicode
)(nChar
+ nOffset
);
4374 pString
->SetChar( nIdx
, nChar
);
4380 void ImpEditEngine::ImplInitLayoutMode( OutputDevice
* pOutDev
, USHORT nPara
, USHORT nIndex
)
4384 if ( nIndex
== 0xFFFF )
4386 bCTL
= HasScriptType( nPara
, i18n::ScriptType::COMPLEX
);
4387 bR2L
= IsRightToLeft( nPara
);
4391 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
);
4392 short nScriptType
= GetScriptType( EditPaM( pNode
, nIndex
+1 ) );
4393 bCTL
= nScriptType
== i18n::ScriptType::COMPLEX
;
4394 bR2L
= GetRightToLeft( nPara
, nIndex
+ 1); // this change was discussed in issue 37190
4395 // it also works for issue 55927
4398 ULONG nLayoutMode
= pOutDev
->GetLayoutMode();
4400 // We always use the left postion for DrawText()
4401 nLayoutMode
&= ~(TEXT_LAYOUT_BIDI_RTL
);
4403 if ( !bCTL
&& !bR2L
)
4405 // No CTL/Bidi checking neccessary
4406 nLayoutMode
|= ( TEXT_LAYOUT_COMPLEX_DISABLED
| TEXT_LAYOUT_BIDI_STRONG
);
4410 // CTL/Bidi checking neccessary
4411 // Don't use BIDI_STRONG, VCL must do some checks.
4412 nLayoutMode
&= ~( TEXT_LAYOUT_COMPLEX_DISABLED
| TEXT_LAYOUT_BIDI_STRONG
);
4415 nLayoutMode
|= TEXT_LAYOUT_BIDI_RTL
|TEXT_LAYOUT_TEXTORIGIN_LEFT
;
4418 pOutDev
->SetLayoutMode( nLayoutMode
);
4420 // #114278# Also setting up digit language from Svt options
4421 // (cannot reliably inherit the outdev's setting)
4425 pCTLOptions
= new SvtCTLOptions
;
4427 if ( SvtCTLOptions::NUMERALS_HINDI
== pCTLOptions
->GetCTLTextNumerals() )
4428 eLang
= LANGUAGE_ARABIC_SAUDI_ARABIA
;
4429 else if ( SvtCTLOptions::NUMERALS_ARABIC
== pCTLOptions
->GetCTLTextNumerals() )
4430 eLang
= LANGUAGE_ENGLISH
;
4432 eLang
= (LanguageType
) Application::GetSettings().GetLanguage();
4434 pOutDev
->SetDigitLanguage( eLang
);
4437 Reference
< i18n::XBreakIterator
> ImpEditEngine::ImplGetBreakIterator() const
4441 Reference
< lang::XMultiServiceFactory
> xMSF( ::comphelper::getProcessServiceFactory() );
4442 xBI
.set( xMSF
->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY
);
4447 Reference
< i18n::XExtendedInputSequenceChecker
> ImpEditEngine::ImplGetInputSequenceChecker() const
4451 Reference
< lang::XMultiServiceFactory
> xMSF
= ::comphelper::getProcessServiceFactory();
4452 Reference
< XInterface
> xI
= xMSF
->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) );
4455 Any x
= xI
->queryInterface( ::getCppuType((const Reference
< i18n::XExtendedInputSequenceChecker
>*)0) );
4462 Color
ImpEditEngine::GetAutoColor() const
4464 Color aColor
= const_cast<ImpEditEngine
*>(this)->GetColorConfig().GetColorValue( svtools::FONTCOLOR
).nColor
;
4466 if ( GetBackgroundColor() != COL_AUTO
)
4468 if ( GetBackgroundColor().IsDark() && aColor
.IsDark() )
4470 else if ( GetBackgroundColor().IsBright() && aColor
.IsBright() )
4478 BOOL
ImpEditEngine::ImplCalcAsianCompression( ContentNode
* pNode
, TextPortion
* pTextPortion
, USHORT nStartPos
, sal_Int32
* pDXArray
, USHORT n100thPercentFromMax
, BOOL bManipulateDXArray
)
4480 DBG_ASSERT( GetAsianCompressionMode(), "ImplCalcAsianCompression - Why?" );
4481 DBG_ASSERT( pTextPortion
->GetLen(), "ImplCalcAsianCompression - Empty Portion?" );
4483 // Percent is 1/100 Percent...
4485 if ( n100thPercentFromMax
== 10000 )
4486 pTextPortion
->SetExtraInfos( NULL
);
4488 BOOL bCompressed
= FALSE
;
4490 if ( GetScriptType( EditPaM( pNode
, nStartPos
+1 ) ) == i18n::ScriptType::ASIAN
)
4492 long nNewPortionWidth
= pTextPortion
->GetSize().Width();
4493 USHORT nPortionLen
= pTextPortion
->GetLen();
4494 for ( USHORT n
= 0; n
< nPortionLen
; n
++ )
4496 BYTE nType
= GetCharTypeForCompression( pNode
->GetChar( n
+nStartPos
) );
4498 BOOL bCompressPunctuation
= ( nType
== CHAR_PUNCTUATIONLEFT
) || ( nType
== CHAR_PUNCTUATIONRIGHT
);
4499 BOOL bCompressKana
= ( nType
== CHAR_KANA
) && ( GetAsianCompressionMode() == text::CharacterCompressionType::PUNCTUATION_AND_KANA
);
4501 // create Extra infos only if needed...
4502 if ( bCompressPunctuation
|| bCompressKana
)
4504 if ( !pTextPortion
->GetExtraInfos() )
4506 ExtraPortionInfo
* pExtraInfos
= new ExtraPortionInfo
;
4507 pTextPortion
->SetExtraInfos( pExtraInfos
);
4508 pExtraInfos
->nOrgWidth
= pTextPortion
->GetSize().Width();
4509 pExtraInfos
->nAsianCompressionTypes
= CHAR_NORMAL
;
4511 pTextPortion
->GetExtraInfos()->nMaxCompression100thPercent
= n100thPercentFromMax
;
4512 pTextPortion
->GetExtraInfos()->nAsianCompressionTypes
|= nType
;
4513 // pTextPortion->GetExtraInfos()->nCompressedChars++;
4516 if ( (n
+1) < nPortionLen
)
4518 nOldCharWidth
= pDXArray
[n
];
4522 if ( bManipulateDXArray
)
4523 nOldCharWidth
= nNewPortionWidth
- pTextPortion
->GetExtraInfos()->nPortionOffsetX
;
4525 nOldCharWidth
= pTextPortion
->GetExtraInfos()->nOrgWidth
;
4527 nOldCharWidth
-= ( n
? pDXArray
[n
-1] : 0 );
4531 if ( bCompressPunctuation
)
4533 // pTextPortion->GetExtraInfos()->nComressionWeight += 5;
4534 nCompress
= nOldCharWidth
/ 2;
4538 // pTextPortion->GetExtraInfos()->nComressionWeight += 1;
4539 nCompress
= nOldCharWidth
/ 10;
4542 if ( n100thPercentFromMax
!= 10000 )
4544 nCompress
*= n100thPercentFromMax
;
4551 nNewPortionWidth
-= nCompress
;
4552 pTextPortion
->GetExtraInfos()->bCompressed
= TRUE
;
4555 // Special handling for rightpunctuation: For the 'compression' we must
4556 // start th eoutput before the normal char position....
4557 if ( bManipulateDXArray
&& ( pTextPortion
->GetLen() > 1 ) )
4559 if ( !pTextPortion
->GetExtraInfos()->pOrgDXArray
)
4560 pTextPortion
->GetExtraInfos()->SaveOrgDXArray( pDXArray
, pTextPortion
->GetLen()-1 );
4562 if ( nType
== CHAR_PUNCTUATIONRIGHT
)
4564 // If it's the first char, I must handle it in Paint()...
4567 // -1: No entry for the last character
4568 for ( USHORT i
= n
-1; i
< (nPortionLen
-1); i
++ )
4569 pDXArray
[i
] -= nCompress
;
4573 pTextPortion
->GetExtraInfos()->bFirstCharIsRightPunktuation
= TRUE
;
4574 pTextPortion
->GetExtraInfos()->nPortionOffsetX
= -nCompress
;
4579 // -1: No entry for the last character
4580 for ( USHORT i
= n
; i
< (nPortionLen
-1); i
++ )
4581 pDXArray
[i
] -= nCompress
;
4588 if ( bCompressed
&& ( n100thPercentFromMax
== 10000 ) )
4589 pTextPortion
->GetExtraInfos()->nWidthFullCompression
= nNewPortionWidth
;
4591 pTextPortion
->GetSize().Width() = nNewPortionWidth
;
4593 if ( pTextPortion
->GetExtraInfos() && ( n100thPercentFromMax
!= 10000 ) )
4595 // Maybe rounding errors in nNewPortionWidth, assure that width not bigger than expected
4596 long nShrink
= pTextPortion
->GetExtraInfos()->nOrgWidth
- pTextPortion
->GetExtraInfos()->nWidthFullCompression
;
4597 nShrink
*= n100thPercentFromMax
;
4599 long nNewWidth
= pTextPortion
->GetExtraInfos()->nOrgWidth
- nShrink
;
4600 if ( nNewWidth
< pTextPortion
->GetSize().Width() )
4601 pTextPortion
->GetSize().Width() = nNewWidth
;
4608 void ImpEditEngine::ImplExpandCompressedPortions( EditLine
* pLine
, ParaPortion
* pParaPortion
, long nRemainingWidth
)
4610 BOOL bFoundCompressedPortion
= FALSE
;
4611 long nCompressed
= 0;
4612 // long nCompressWeight = 0;
4613 TextPortionList aCompressedPortions
;
4615 USHORT nPortion
= pLine
->GetEndPortion();
4616 TextPortion
* pTP
= pParaPortion
->GetTextPortions()[ nPortion
];
4617 while ( pTP
&& ( pTP
->GetKind() == PORTIONKIND_TEXT
) )
4619 if ( pTP
->GetExtraInfos() && pTP
->GetExtraInfos()->bCompressed
)
4621 bFoundCompressedPortion
= TRUE
;
4622 nCompressed
+= pTP
->GetExtraInfos()->nOrgWidth
- pTP
->GetSize().Width();
4623 aCompressedPortions
.Insert( pTP
, aCompressedPortions
.Count() );
4625 pTP
= ( nPortion
> pLine
->GetStartPortion() ) ? pParaPortion
->GetTextPortions()[ --nPortion
] : NULL
;
4628 if ( bFoundCompressedPortion
)
4630 long nCompressPercent
= 0;
4631 if ( nCompressed
> nRemainingWidth
)
4633 nCompressPercent
= nCompressed
- nRemainingWidth
;
4634 DBG_ASSERT( nCompressPercent
< 200000, "ImplExpandCompressedPortions - Overflow!" );
4635 nCompressPercent
*= 10000;
4636 nCompressPercent
/= nCompressed
;
4639 for ( USHORT n
= 0; n
< aCompressedPortions
.Count(); n
++ )
4641 pTP
= aCompressedPortions
[n
];
4642 pTP
->GetExtraInfos()->bCompressed
= FALSE
;
4643 pTP
->GetSize().Width() = pTP
->GetExtraInfos()->nOrgWidth
;
4644 if ( nCompressPercent
)
4646 USHORT nTxtPortion
= pParaPortion
->GetTextPortions().GetPos( pTP
);
4647 USHORT nTxtPortionStart
= pParaPortion
->GetTextPortions().GetStartPos( nTxtPortion
);
4648 DBG_ASSERT( nTxtPortionStart
>= pLine
->GetStart(), "Portion doesn't belong to the line!!!" );
4649 sal_Int32
* pDXArray
= const_cast< sal_Int32
* >( pLine
->GetCharPosArray().GetData()+( nTxtPortionStart
-pLine
->GetStart() ) );
4650 if ( pTP
->GetExtraInfos()->pOrgDXArray
)
4651 memcpy( pDXArray
, pTP
->GetExtraInfos()->pOrgDXArray
, (pTP
->GetLen()-1)*sizeof(sal_Int32
) );
4652 ImplCalcAsianCompression( pParaPortion
->GetNode(), pTP
, nTxtPortionStart
, pDXArray
, (USHORT
)nCompressPercent
, TRUE
);
4657 aCompressedPortions
.Remove( 0, aCompressedPortions
.Count() );
4660 // redesigned to work with TextMarkingVector
4661 void ImpEditEngine::ImplFillTextMarkingVector(const lang::Locale
& rLocale
, EEngineData::TextMarkingVector
& rTextMarkingVector
, const String
& rTxt
, const USHORT nIdx
, const USHORT nLen
) const
4663 // determine relevant logical text elements for the just-rendered
4664 // string of characters.
4665 Reference
< i18n::XBreakIterator
> _xBI(ImplGetBreakIterator());
4670 sal_Int32
nNextCellBreak(_xBI
->nextCharacters(rTxt
, nIdx
, rLocale
, i18n::CharacterIteratorMode::SKIPCELL
, 0, nDone
));
4671 i18n::Boundary
nNextWordBoundary(_xBI
->getWordBoundary(rTxt
, nIdx
, rLocale
, i18n::WordType::ANY_WORD
, sal_True
));
4672 sal_Int32
nNextSentenceBreak(_xBI
->endOfSentence(rTxt
, nIdx
, rLocale
));
4674 const sal_Int32
nEndPos(nIdx
+ nLen
);
4677 for(i
= nIdx
; i
< nEndPos
; i
++)
4679 // create the entries for the respective break positions
4680 if(i
== nNextCellBreak
)
4682 rTextMarkingVector
.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfCaracter
, i
- nIdx
));
4683 nNextCellBreak
= _xBI
->nextCharacters(rTxt
, i
, rLocale
, i18n::CharacterIteratorMode::SKIPCELL
, 1, nDone
);
4685 if(i
== nNextWordBoundary
.endPos
)
4687 rTextMarkingVector
.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfWord
, i
- nIdx
));
4688 nNextWordBoundary
= _xBI
->getWordBoundary(rTxt
, i
+ 1, rLocale
, i18n::WordType::ANY_WORD
, sal_True
);
4690 if(i
== nNextSentenceBreak
)
4692 rTextMarkingVector
.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfSentence
, i
- nIdx
));
4693 nNextSentenceBreak
= _xBI
->endOfSentence(rTxt
, i
+ 1, rLocale
);